Skip to main content

flowly_flv/parser/tag/
video.rs

1use flowly::Fourcc;
2
3use crate::{
4    error::Error,
5    parser::{FlvParser, Parser},
6    reader::FlvReader,
7    tag::video::{
8        AvMultitrackType, AvcPacketType, CodecID, PacketExData, VideoFrameType, VideoPacketType,
9        VideoTag, VideoTagBody, VideoTagHeader,
10        mpeg4_avc::{Mpeg4AvcNALUSeq, Mpeg4AvcRecord},
11    },
12};
13
14impl<E> Parser<E, VideoTagHeader> for FlvParser {
15    type Error = Error<E>;
16
17    fn parse(&mut self, reader: &mut impl FlvReader) -> Result<VideoTagHeader, Self::Error> {
18        let header = reader.read_u8()?;
19        let frame_type = VideoFrameType::from(header & 0x70 >> 4);
20        let enhanced = (header >> 7) & 1 > 0;
21
22        let mut fourcc = Fourcc::default();
23        let mut multitrack = false;
24        let mut has_body = true;
25        let mut multitrack_type = AvMultitrackType::OneTrack;
26        let mut _video_command = None;
27        let mut pkt_type = VideoPacketType::from(header & 0x0F);
28
29        if enhanced {
30            while let VideoPacketType::ModEx = pkt_type {
31                let ex_data: PacketExData = self.parse(reader)?;
32
33                pkt_type = ex_data.pkt_type;
34            }
35
36            if pkt_type != VideoPacketType::Metadata && frame_type == VideoFrameType::Command {
37                _video_command = Some(reader.read_u8()?);
38
39                //   ExVideoTagBody has no payload if we got here.
40                //   Set boolean to not try to process the video body.
41                has_body = false;
42            } else if pkt_type == VideoPacketType::Multitrack {
43                multitrack = true;
44                // Fetch VideoPacketType for all video tracks in the video message.
45                // This fetch MUST not result in a VideoPacketType.Multitrack
46                multitrack_type = AvMultitrackType::from(reader.read_u8()?);
47
48                if multitrack_type != AvMultitrackType::ManyTracksManyCodecs {
49                    fourcc = Fourcc::from(reader.read_u32()?);
50                }
51            } else {
52                fourcc = Fourcc::from(reader.read_u32()?);
53            }
54        } else {
55            fourcc = match CodecID::from(header & 0x0F) {
56                CodecID::SorensonH263 => Fourcc::from_static("M263"),
57                CodecID::Screen1 => Fourcc::from_static("SCR1"),
58                CodecID::VP6 => Fourcc::from_static("VP06"),
59                CodecID::VP6Alpha => Fourcc::from_static("VP6a"),
60                CodecID::Screen2 => Fourcc::from_static("SCR2"),
61                CodecID::AVC => Fourcc::VIDEO_AVC,
62                CodecID::RealH263 => Fourcc::from_static("H263"),
63                CodecID::Hevc => Fourcc::VIDEO_HEVC,
64                CodecID::Unknown(_) => Fourcc::default(),
65            };
66        }
67
68        Ok(VideoTagHeader {
69            pkt_type,
70            multitrack,
71            has_body,
72            multitrack_type,
73            fourcc,
74            frame_type,
75            enhanced,
76        })
77    }
78}
79
80impl<E> Parser<E, VideoTag> for FlvParser {
81    type Error = Error<E>;
82
83    fn parse(&mut self, reader: &mut impl FlvReader) -> Result<VideoTag, Self::Error> {
84        let mut header: VideoTagHeader = self.parse(reader)?;
85        let mut track_id = 0;
86        let mut pts_offset = 0;
87        let mut param_count = 0;
88        let mut nalus = Vec::new();
89
90        if header.enhanced {
91            if header.multitrack_type == AvMultitrackType::ManyTracksManyCodecs {
92                // Each track has a codec assigned to it. Fetch the FOURCC for the next track.
93                header.fourcc = Fourcc::from(reader.read_u32()?)
94            }
95
96            // Track Ordering:
97            //
98            // For identifying the highest priority (a.k.a., default track)
99            // or highest quality track, it is RECOMMENDED to use trackId
100            // set to zero. For tracks of lesser priority or quality, use
101            // multiple instances of trackId with ascending numerical values.
102            // The concept of priority or quality can have multiple
103            // interpretations, including but not limited to bitrate,
104            // resolution, default angle, and language. This recommendation
105            // serves as a guideline intended to standardize track numbering
106            // across various applications.
107            track_id = reader.read_u8()?;
108
109            if header.multitrack_type != AvMultitrackType::OneTrack {
110                // The `sizeOfVideoTrack` specifies the size in bytes of the
111                // current track that is being processed. This size starts
112                // counting immediately after the position where the `sizeOfVideoTrack`
113                // value is located. You can use this value as an offset to locate the
114                // next video track in a multitrack system. The data pointer is
115                // positioned immediately after this field. Depending on the MultiTrack
116                // type, the offset points to either a `fourCc` or a `trackId.`
117                let _size_of_video_track = reader.read_u24()?;
118            }
119
120            match header.pkt_type {
121                VideoPacketType::SequenceStart => {
122                    // if self.mpeg4_avc_parser.is_none() {
123                    //     self.mpeg4_avc_parser = Some(Default::default());
124                    // }
125
126                    // let x: Mpeg4AvcRecord =
127                    //     self.mpeg4_avc_parser.as_mut().unwrap().parse(reader)?;
128
129                    // params = Some([x.sps, x.pps].concat());
130                }
131                VideoPacketType::CodedFrames => {
132                    match header.fourcc {
133                        Fourcc::VIDEO_AVC => {
134                            // See ISO/IEC 14496-12:2015, 8.6.1 for the description of the composition
135                            // time offset. The offset in an FLV file is always in milliseconds
136                            pts_offset = reader.read_i24()? as i32;
137
138                            // let x: Mpeg4AvcNALUSeq =
139                            //     self.mpeg4_avc_parser.as_mut().unwrap().parse(reader)?;
140
141                            // nalus = x.nalus;
142                            nalus = vec![reader.read_to_end()?];
143                        }
144                        Fourcc::VIDEO_HEVC => {
145                            // body contains a configuration record to start the sequence.
146                            // See ISO/IEC 14496-15:2022, 8.3.3.2 for the description of
147                            // HEVCDecoderConfigurationRecord
148                            pts_offset = reader.read_i24()? as i32;
149                            // let x: Mpeg4AvcNALUSeq =
150                            //     self.mpeg4_avc_parser.as_mut().unwrap().parse(reader)?;
151
152                            // nalus = x.nalus;
153                            nalus = vec![reader.read_to_end()?];
154                        }
155                        _ => {
156                            nalus = vec![reader.read_to_end()?];
157                        }
158                    }
159                }
160                VideoPacketType::SequenceEnd => {}
161                VideoPacketType::CodedFramesX => {
162                    nalus = vec![reader.read_to_end()?];
163                }
164                VideoPacketType::Metadata => {}
165                VideoPacketType::MPEG2TSSequenceStart => {}
166                VideoPacketType::Multitrack => {}
167                VideoPacketType::ModEx => {}
168                VideoPacketType::Unknown(_) => {}
169            }
170        } else {
171            match header.fourcc {
172                Fourcc::VIDEO_AVC | Fourcc::VIDEO_HEVC => {
173                    if self.mpeg4_avc_parser.is_none() {
174                        self.mpeg4_avc_parser = Some(Default::default());
175                    }
176
177                    let packet_type = AvcPacketType::from(reader.read_u8()?);
178                    pts_offset = reader.read_i24()? as i32;
179
180                    match packet_type {
181                        AvcPacketType::SequenceHeader => {
182                            let mut x: Mpeg4AvcRecord =
183                                self.mpeg4_avc_parser.as_mut().unwrap().parse(reader)?;
184
185                            param_count += x.sps.len() as u32;
186                            nalus.extend(x.sps.drain(..));
187
188                            param_count += x.pps.len() as u32;
189                            nalus.extend(x.pps.drain(..));
190                        }
191                        AvcPacketType::NALU => {
192                            let x: Mpeg4AvcNALUSeq =
193                                self.mpeg4_avc_parser.as_mut().unwrap().parse(reader)?;
194
195                            nalus = x.nalus;
196                        }
197                        _ => {}
198                    }
199                }
200                _ => {
201                    nalus.push(reader.read_to_end()?);
202                }
203            }
204        }
205
206        Ok(VideoTag {
207            header,
208            track_id,
209            body: VideoTagBody {
210                pts_offset,
211                param_count,
212                nalus,
213            },
214        })
215    }
216}