scuffle_flv/file.rs
1//! FLV file processing
2
3use byteorder::{BigEndian, ReadBytesExt};
4use bytes::{Buf, Bytes};
5
6use super::header::FlvHeader;
7use super::tag::FlvTag;
8use crate::error::FlvError;
9
10/// An FLV file is a combination of a [`FlvHeader`] followed by the
11/// FLV File Body (which is a series of [`FlvTag`]s)
12///
13/// The FLV File Body is defined by:
14/// - Legacy FLV spec, Annex E.3
15#[derive(Debug, Clone, PartialEq)]
16pub struct FlvFile<'a> {
17 /// The header of the FLV file.
18 pub header: FlvHeader,
19 /// The tags in the FLV file.
20 pub tags: Vec<FlvTag<'a>>,
21}
22
23impl FlvFile<'_> {
24 /// Demux an FLV file from a reader.
25 ///
26 /// The reader needs to be a [`std::io::Cursor`] with a [`Bytes`] buffer because we
27 /// take advantage of zero-copy reading.
28 pub fn demux(reader: &mut std::io::Cursor<Bytes>) -> Result<Self, FlvError> {
29 let header = FlvHeader::demux(reader)?;
30
31 let mut tags = Vec::new();
32 while reader.has_remaining() {
33 // We don't care about the previous tag size, its only really used for seeking
34 // backwards.
35 reader.read_u32::<BigEndian>()?;
36
37 // If there is no more data, we can stop reading.
38 if !reader.has_remaining() {
39 break;
40 }
41
42 // Demux the tag from the reader.
43 let tag = FlvTag::demux(reader)?;
44 tags.push(tag);
45 }
46
47 Ok(FlvFile { header, tags })
48 }
49}