scuffle_flv/
header.rs

1//! FLV header processing
2
3use std::io;
4
5use byteorder::{BigEndian, ReadBytesExt};
6use bytes::Bytes;
7use scuffle_bytes_util::BytesCursorExt;
8
9use crate::error::FlvError;
10
11/// The FLV header
12/// Whenever a FLV file is read these are the first 9 bytes of the file.
13///
14/// Defined by:
15/// - video_file_format_spec_v10.pdf (Chapter 1 - The FLV Header - Page 8)
16/// - video_file_format_spec_v10_1.pdf (Annex E.2 - The FLV Header)
17#[derive(Debug, Clone, PartialEq)]
18pub struct FlvHeader {
19    /// The version of the FLV file.
20    pub version: u8,
21    /// Whether the FLV file contains audio tags.
22    pub is_audio_present: bool,
23    /// Whether the FLV file contains video tags.
24    pub is_video_present: bool,
25    /// The extra data in the FLV header.
26    ///
27    /// Since the header provides a data offset, this is the remaining bytes after the DataOffset field
28    /// to the end of the header.
29    pub extra: Bytes,
30}
31
32impl FlvHeader {
33    /// Demux the FLV header from the given reader.
34    /// The reader will be returned in the position of the start of the data
35    /// offset.
36    pub fn demux(reader: &mut io::Cursor<Bytes>) -> Result<Self, FlvError> {
37        let start = reader.position() as usize;
38
39        let signature = reader.read_u24::<BigEndian>()?;
40
41        // 0 byte at the beginning because we are only reading 3 bytes not 4.
42        if signature != u32::from_be_bytes([0, b'F', b'L', b'V']) {
43            return Err(FlvError::InvalidSignature(signature));
44        }
45
46        let version = reader.read_u8()?;
47        let flags = reader.read_u8()?;
48        let is_audio_present = (flags & 0b00000100) != 0;
49        let is_video_present = (flags & 0b00000001) != 0;
50
51        let data_offset = reader.read_u32::<BigEndian>()?;
52        let end = reader.position() as usize;
53        let size = end - start;
54
55        let remaining = (data_offset as usize)
56            .checked_sub(size)
57            .ok_or(FlvError::InvalidDataOffset(data_offset))?;
58
59        let extra = reader.extract_bytes(remaining)?;
60
61        Ok(FlvHeader {
62            version,
63            is_audio_present,
64            is_video_present,
65            extra,
66        })
67    }
68}