Skip to main content

flowly_flv/tag/
video.rs

1use bytes::Bytes;
2use flowly::Fourcc;
3
4pub mod mpeg4_avc;
5
6/// The tag data part of `video` FLV tag, including `tag data header` and `tag data body`.
7#[derive(Clone, Debug, PartialEq)]
8pub struct VideoTag {
9    /// The header part of `video` FLV tag.
10    pub header: VideoTagHeader, // 8 bits.
11
12    /// The body part of `video` FLV tag.
13    pub body: VideoTagBody,
14
15    /// Track ID
16    pub track_id: u8,
17}
18
19#[derive(Clone, Debug, PartialEq)]
20pub struct VideoTagBody {
21    pub pts_offset: i32,
22    pub param_count: u32,
23    pub nalus: Vec<Bytes>,
24}
25
26#[derive(Copy, Clone, Debug, Eq, PartialEq)]
27#[repr(u8)]
28pub enum VideoPacketType {
29    SequenceStart = 0,
30    CodedFrames = 1,
31    SequenceEnd = 2,
32
33    /// CompositionTime Offset is implicitly set to zero. This optimization
34    /// avoids transmitting an SI24 composition time value of zero over the wire.
35    /// See the ExVideoTagBody section below for corresponding pseudocode.
36    CodedFramesX = 3,
37
38    /// ExVideoTagBody does not contain video data. Instead, it contains
39    /// an AMF-encoded metadata. Refer to the Metadata Frame section for
40    /// an illustration of its usage. For example, the metadata might include
41    /// HDR information. This also enables future possibilities for expressing
42    /// additional metadata meant for subsequent video sequences.
43    ///
44    /// If VideoPacketType.Metadata is present, the FrameType flags
45    /// at the top of this table should be ignored.
46    Metadata = 4,
47
48    /// Carriage of bitstream in MPEG-2 TS format
49    ///
50    /// PacketTypeSequenceStart and PacketTypeMPEG2TSSequenceStart are mutually exclusive
51    MPEG2TSSequenceStart = 5,
52
53    /// Turns on video multitrack mode
54    Multitrack = 6,
55
56    /// ModEx is a special signal within the VideoPacketType enum that                 
57    /// serves to both modify and extend the behavior of the current packet.           
58    /// When this signal is encountered, it indicates the presence of                  
59    /// additional modifiers or extensions, requiring further processing to            
60    /// adjust or augment the packet's functionality. ModEx can be used to             
61    /// introduce new capabilities or modify existing ones, such as                    
62    /// enabling support for high-precision timestamps or other advanced               
63    /// features that enhance the base packet structure.
64    ModEx = 7,
65
66    Unknown(u8),
67}
68
69impl From<u8> for VideoPacketType {
70    fn from(value: u8) -> Self {
71        match value {
72            0 => VideoPacketType::SequenceStart,
73            1 => VideoPacketType::CodedFrames,
74            2 => VideoPacketType::SequenceEnd,
75            3 => VideoPacketType::CodedFramesX,
76            4 => VideoPacketType::Metadata,
77            5 => VideoPacketType::MPEG2TSSequenceStart,
78            6 => VideoPacketType::Multitrack,
79            7 => VideoPacketType::ModEx,
80            _ => unreachable!(),
81        }
82    }
83}
84
85#[derive(Debug, Clone, Copy, PartialEq, Eq)]
86#[repr(u8)]
87pub enum VideoPacketModExType {
88    TimestampOffsetNano = 0,
89    Unknown(u8),
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
93#[repr(u8)]
94pub enum AvMultitrackType {
95    OneTrack = 0,
96    ManyTracks = 1,
97    ManyTracksManyCodecs = 2,
98    Unknown(u8),
99}
100
101impl From<u8> for AvMultitrackType {
102    fn from(value: u8) -> Self {
103        match value {
104            0 => AvMultitrackType::OneTrack,
105            1 => AvMultitrackType::ManyTracks,
106            2 => AvMultitrackType::ManyTracksManyCodecs,
107            t => AvMultitrackType::Unknown(t),
108        }
109    }
110}
111
112/// The `tag data header` part of `video` FLV tag data.
113#[derive(Clone, Debug, Eq, PartialEq)]
114pub struct VideoTagHeader {
115    pub frame_type: VideoFrameType,
116    pub pkt_type: VideoPacketType,
117    pub multitrack: bool,
118    pub fourcc: Fourcc,
119    pub has_body: bool,
120    pub multitrack_type: AvMultitrackType,
121    pub(crate) enhanced: bool,
122}
123
124impl From<u8> for VideoPacketModExType {
125    fn from(value: u8) -> Self {
126        match value {
127            0 => Self::TimestampOffsetNano,
128            v => Self::Unknown(v),
129        }
130    }
131}
132
133#[derive(Debug, Clone, PartialEq, Eq)]
134pub struct PacketExData {
135    pub pkt_type: VideoPacketType,
136    pub ex_type: VideoPacketModExType,
137    pub dts_offset_ns: u32,
138    pub ex_data: Bytes,
139}
140
141#[derive(Copy, Clone, Debug, Eq, PartialEq)]
142#[repr(u8)]
143pub enum VideoCommand {
144    StartSeek = 0,
145    EndSeek = 1,
146    Unknown(u8), // 0x03..0xff = reserved
147}
148
149/// The type of video frame.
150#[derive(Copy, Clone, Debug, Eq, PartialEq)]
151pub enum VideoFrameType {
152    /// 1, Key frame.
153    Key,
154
155    /// 2, Inter frame.
156    Inter,
157
158    /// 3, DisposableInter frame.
159    DisposableInter,
160
161    /// 4, Generated frame.
162    Generated,
163
164    /// 5, Command frame.
165    Command,
166
167    /// Unknown frame.
168    Unknown(u8),
169}
170
171impl From<u8> for VideoFrameType {
172    fn from(value: u8) -> Self {
173        match value {
174            1 => VideoFrameType::Key,
175            2 => VideoFrameType::Inter,
176            3 => VideoFrameType::DisposableInter,
177            4 => VideoFrameType::Generated,
178            5 => VideoFrameType::Command,
179            t => VideoFrameType::Unknown(t),
180        }
181    }
182}
183
184/// The code identifier of video.
185#[allow(clippy::upper_case_acronyms)]
186#[derive(Copy, Clone, Debug, Eq, PartialEq)]
187#[repr(u8)]
188pub enum CodecID {
189    /// 2, SorensonH263
190    SorensonH263,
191
192    /// 3, Screen1
193    Screen1,
194
195    /// 4, VP6
196    VP6,
197
198    /// 5, VP6Alpha
199    VP6Alpha,
200
201    /// 6, Screen2
202    Screen2,
203
204    /// 7, MPEG-4 Part 10 AVC / H.264
205    AVC,
206
207    /// 8, REAL H263
208    RealH263,
209
210    // 12, HEVC experimental non-standart codec
211    Hevc,
212
213    /// Unknown codec ID.
214    Unknown(u8),
215}
216
217impl From<u8> for CodecID {
218    fn from(value: u8) -> Self {
219        match value {
220            2 => CodecID::SorensonH263,
221            3 => CodecID::Screen1,
222            4 => CodecID::VP6,
223            5 => CodecID::VP6Alpha,
224            6 => CodecID::Screen2,
225            7 => CodecID::AVC,
226            8 => CodecID::RealH263,
227            12 => CodecID::Hevc,
228            c => CodecID::Unknown(c),
229        }
230    }
231}
232
233/// The type of AVC packet.
234#[allow(clippy::upper_case_acronyms)]
235#[derive(Copy, Clone, Debug, Eq, PartialEq)]
236#[repr(u8)]
237pub enum AvcPacketType {
238    /// 0, SequenceHeader.
239    SequenceHeader,
240
241    /// 1. NALU.
242    NALU,
243
244    /// 2, EndOfSequence.
245    EndOfSequence,
246
247    /// Unknown
248    Unknown(u8),
249}
250
251impl From<u8> for AvcPacketType {
252    fn from(value: u8) -> Self {
253        match value {
254            0 => AvcPacketType::SequenceHeader,
255            1 => AvcPacketType::NALU,
256            2 => AvcPacketType::EndOfSequence,
257            t => AvcPacketType::Unknown(t),
258        }
259    }
260}