1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
#[cfg(test)]
mod ivf_writer_test;
use crate::io::ivf_reader::IVFFileHeader;
use crate::io::Writer;
use anyhow::Result;
use byteorder::{LittleEndian, WriteBytesExt};
use bytes::{Bytes, BytesMut};
use rtp::packetizer::Depacketizer;
use std::io::{Seek, SeekFrom, Write};
pub struct IVFWriter<W: Write + Seek> {
writer: W,
count: u64,
seen_key_frame: bool,
current_frame: Option<BytesMut>,
}
impl<W: Write + Seek> IVFWriter<W> {
pub fn new(writer: W, header: &IVFFileHeader) -> Result<Self> {
let mut w = IVFWriter {
writer,
count: 0,
seen_key_frame: false,
current_frame: None,
};
w.write_header(header)?;
Ok(w)
}
fn write_header(&mut self, header: &IVFFileHeader) -> Result<()> {
self.writer.write_all(&header.signature)?;
self.writer.write_u16::<LittleEndian>(header.version)?;
self.writer.write_u16::<LittleEndian>(header.header_size)?;
self.writer.write_all(&header.four_cc)?;
self.writer.write_u16::<LittleEndian>(header.width)?;
self.writer.write_u16::<LittleEndian>(header.height)?;
self.writer
.write_u32::<LittleEndian>(header.timebase_denominator)?;
self.writer
.write_u32::<LittleEndian>(header.timebase_numerator)?;
self.writer.write_u32::<LittleEndian>(header.num_frames)?;
self.writer.write_u32::<LittleEndian>(header.unused)?;
Ok(())
}
}
impl<W: Write + Seek> Writer for IVFWriter<W> {
fn write_rtp(&mut self, packet: &rtp::packet::Packet) -> Result<()> {
let mut vp8packet = rtp::codecs::vp8::Vp8Packet::default();
vp8packet.depacketize(&packet.payload)?;
let is_key_frame = vp8packet.payload[0] & 0x01;
if (!self.seen_key_frame && is_key_frame == 1)
|| (self.current_frame.is_none() && vp8packet.s != 1)
{
return Ok(());
}
self.seen_key_frame = true;
let frame_length = if let Some(current_frame) = &mut self.current_frame {
current_frame.extend(vp8packet.payload);
current_frame.len()
} else {
let mut current_frame = BytesMut::new();
current_frame.extend(vp8packet.payload);
let frame_length = current_frame.len();
self.current_frame = Some(current_frame);
frame_length
};
if !packet.header.marker {
return Ok(());
} else if let Some(current_frame) = &self.current_frame {
if current_frame.is_empty() {
return Ok(());
}
} else {
return Ok(());
}
self.writer.write_u32::<LittleEndian>(frame_length as u32)?;
self.writer.write_u64::<LittleEndian>(self.count)?;
self.count += 1;
let frame_content = if let Some(current_frame) = self.current_frame.take() {
current_frame.freeze()
} else {
Bytes::new()
};
self.writer.write_all(&frame_content)?;
Ok(())
}
fn close(&mut self) -> Result<()> {
self.writer.seek(SeekFrom::Start(24))?;
self.writer.write_u32::<LittleEndian>(self.count as u32)?;
self.writer.flush()?;
Ok(())
}
}