webrtc_media/io/ivf_reader/
mod.rs1#[cfg(test)]
2mod ivf_reader_test;
3
4use std::io::Read;
5
6use byteorder::{LittleEndian, ReadBytesExt};
7use bytes::BytesMut;
8
9use crate::error::{Error, Result};
10use crate::io::ResetFn;
11
12pub const IVF_FILE_HEADER_SIGNATURE: &[u8] = b"DKIF";
13pub const IVF_FILE_HEADER_SIZE: usize = 32;
14pub const IVF_FRAME_HEADER_SIZE: usize = 12;
15
16#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
19pub struct IVFFileHeader {
20 pub signature: [u8; 4], pub version: u16, pub header_size: u16, pub four_cc: [u8; 4], pub width: u16, pub height: u16, pub timebase_denominator: u32, pub timebase_numerator: u32, pub num_frames: u32, pub unused: u32, }
31
32#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
35pub struct IVFFrameHeader {
36 pub frame_size: u32, pub timestamp: u64, }
39
40pub struct IVFReader<R: Read> {
42 reader: R,
43 bytes_read: usize,
44}
45
46impl<R: Read> IVFReader<R> {
47 pub fn new(reader: R) -> Result<(IVFReader<R>, IVFFileHeader)> {
50 let mut r = IVFReader {
51 reader,
52 bytes_read: 0,
53 };
54
55 let header = r.parse_file_header()?;
56
57 Ok((r, header))
58 }
59
60 pub fn reset_reader(&mut self, mut reset: ResetFn<R>) {
64 self.reader = reset(self.bytes_read);
65 }
66
67 pub fn parse_next_frame(&mut self) -> Result<(BytesMut, IVFFrameHeader)> {
71 let frame_size = self.reader.read_u32::<LittleEndian>()?;
72 let timestamp = self.reader.read_u64::<LittleEndian>()?;
73 let header = IVFFrameHeader {
74 frame_size,
75 timestamp,
76 };
77
78 let mut payload = BytesMut::with_capacity(header.frame_size as usize);
79 payload.resize(header.frame_size as usize, 0);
80 self.reader.read_exact(&mut payload)?;
81
82 self.bytes_read += IVF_FRAME_HEADER_SIZE + header.frame_size as usize;
83
84 Ok((payload, header))
85 }
86
87 fn parse_file_header(&mut self) -> Result<IVFFileHeader> {
90 let mut signature = [0u8; 4];
91 let mut four_cc = [0u8; 4];
92
93 self.reader.read_exact(&mut signature)?;
94 let version = self.reader.read_u16::<LittleEndian>()?;
95 let header_size = self.reader.read_u16::<LittleEndian>()?;
96 self.reader.read_exact(&mut four_cc)?;
97 let width = self.reader.read_u16::<LittleEndian>()?;
98 let height = self.reader.read_u16::<LittleEndian>()?;
99 let timebase_denominator = self.reader.read_u32::<LittleEndian>()?;
100 let timebase_numerator = self.reader.read_u32::<LittleEndian>()?;
101 let num_frames = self.reader.read_u32::<LittleEndian>()?;
102 let unused = self.reader.read_u32::<LittleEndian>()?;
103
104 let header = IVFFileHeader {
105 signature,
106 version,
107 header_size,
108 four_cc,
109 width,
110 height,
111 timebase_denominator,
112 timebase_numerator,
113 num_frames,
114 unused,
115 };
116
117 if header.signature != IVF_FILE_HEADER_SIGNATURE {
118 return Err(Error::ErrSignatureMismatch);
119 } else if header.version != 0 {
120 return Err(Error::ErrUnknownIVFVersion);
121 }
122
123 self.bytes_read += IVF_FILE_HEADER_SIZE;
124
125 Ok(header)
126 }
127}