Skip to content

Commit a83a63d

Browse files
authored
feature(media/ogg_writer): add packet segments to page (#499)
* feature(media/ogg_writer): add packet segments to page * fix(media/ogg_writer): handle payload sizes that are multiples of 255
1 parent 3d5ded8 commit a83a63d

File tree

2 files changed

+177
-3
lines changed

2 files changed

+177
-3
lines changed

media/src/io/ogg_writer/mod.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,10 @@ impl<W: Write + Seek> OggWriter<W> {
127127
) -> Result<()> {
128128
self.last_payload_size = payload.len();
129129
self.last_payload = payload.clone();
130+
let n_segments = (self.last_payload_size + 255 - 1) / 255;
130131

131-
let mut page = Vec::with_capacity(PAGE_HEADER_SIZE + 1 + self.last_payload_size);
132+
let mut page =
133+
Vec::with_capacity(PAGE_HEADER_SIZE + 1 + self.last_payload_size + n_segments);
132134
{
133135
let mut header_writer = BufWriter::new(&mut page);
134136
header_writer.write_all(PAGE_HEADER_SIGNATURE)?; // page headers starts with 'OggS'//0-3
@@ -138,8 +140,16 @@ impl<W: Write + Seek> OggWriter<W> {
138140
header_writer.write_u32::<LittleEndian>(self.serial)?; // Bitstream serial number//14-17
139141
header_writer.write_u32::<LittleEndian>(page_index)?; // Page sequence number//18-21
140142
header_writer.write_u32::<LittleEndian>(0)?; //Checksum reserve //22-25
141-
header_writer.write_u8(1)?; // Number of segments in page, giving always 1 segment //26
142-
header_writer.write_u8(self.last_payload_size as u8)?; // Segment Table inserting at 27th position since page header length is 27
143+
header_writer.write_u8(n_segments as u8)?; // Number of segments in page //26
144+
145+
// Filling the segment table with the lacing values.
146+
// First (n_segments - 1) values will always be 255.
147+
for _ in 0..n_segments - 1 {
148+
header_writer.write_u8(255)?;
149+
}
150+
// The last value will be the remainder.
151+
header_writer.write_u8((self.last_payload_size - (n_segments * 255 - 255)) as u8)?;
152+
143153
header_writer.write_all(payload)?; // inserting at 28th since Segment Table(1) + header length(27)
144154
}
145155

media/src/io/ogg_writer/ogg_writer_test.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,167 @@ fn test_ogg_writer_add_packet_and_close() -> Result<()> {
6363

6464
Ok(())
6565
}
66+
67+
#[test]
68+
fn test_ogg_writer_add_packet() -> Result<()> {
69+
let raw_pkt = Bytes::from_iter(std::iter::repeat(0x45).take(235));
70+
71+
let mut valid_packet = rtp::packet::Packet {
72+
header: rtp::header::Header {
73+
marker: true,
74+
extension: true,
75+
extension_profile: 1,
76+
version: 2,
77+
payload_type: 111,
78+
sequence_number: 27023,
79+
timestamp: 3653407706,
80+
ssrc: 476325762,
81+
csrc: vec![],
82+
padding: false,
83+
extensions: vec![],
84+
extensions_padding: 0,
85+
},
86+
payload: raw_pkt,
87+
};
88+
valid_packet
89+
.header
90+
.set_extension(0, Bytes::from_static(&[0xFF, 0xFF, 0xFF, 0xFF]))?;
91+
92+
let buffer = Cursor::new(Vec::<u8>::new());
93+
let mut writer = OggWriter::new(buffer, 48000, 2)?;
94+
let result = writer.write_rtp(&valid_packet);
95+
96+
assert!(
97+
result.is_ok(),
98+
"OggWriter should be able to write an Opus packet smaller than 255 bytes"
99+
);
100+
assert!(
101+
writer.writer.into_inner()[126..128] == [1, 235],
102+
"OggWriter should be able to write an Opus packet smaller than 255 bytes"
103+
);
104+
105+
Ok(())
106+
}
107+
108+
#[test]
109+
fn test_ogg_writer_add_packet_of_255() -> Result<()> {
110+
let raw_pkt = Bytes::from_iter(std::iter::repeat(0x45).take(255));
111+
112+
let mut valid_packet = rtp::packet::Packet {
113+
header: rtp::header::Header {
114+
marker: true,
115+
extension: true,
116+
extension_profile: 1,
117+
version: 2,
118+
payload_type: 111,
119+
sequence_number: 27023,
120+
timestamp: 3653407706,
121+
ssrc: 476325762,
122+
csrc: vec![],
123+
padding: false,
124+
extensions: vec![],
125+
extensions_padding: 0,
126+
},
127+
payload: raw_pkt,
128+
};
129+
valid_packet
130+
.header
131+
.set_extension(0, Bytes::from_static(&[0xFF, 0xFF, 0xFF, 0xFF]))?;
132+
133+
let buffer = Cursor::new(Vec::<u8>::new());
134+
let mut writer = OggWriter::new(buffer, 48000, 2)?;
135+
let result = writer.write_rtp(&valid_packet);
136+
137+
assert!(
138+
result.is_ok(),
139+
"OggWriter should be able to write an Opus packet of exactly 255"
140+
);
141+
assert!(
142+
writer.writer.into_inner()[126..128] == [1, 255],
143+
"OggWriter should be able to write an Opus packet of exactly 255"
144+
);
145+
146+
Ok(())
147+
}
148+
149+
#[test]
150+
fn test_ogg_writer_add_large_packet() -> Result<()> {
151+
let raw_pkt = Bytes::from_iter(std::iter::repeat(0x45).take(1000));
152+
153+
let mut valid_packet = rtp::packet::Packet {
154+
header: rtp::header::Header {
155+
marker: true,
156+
extension: true,
157+
extension_profile: 1,
158+
version: 2,
159+
payload_type: 111,
160+
sequence_number: 27023,
161+
timestamp: 3653407706,
162+
ssrc: 476325762,
163+
csrc: vec![],
164+
padding: false,
165+
extensions: vec![],
166+
extensions_padding: 0,
167+
},
168+
payload: raw_pkt,
169+
};
170+
valid_packet
171+
.header
172+
.set_extension(0, Bytes::from_static(&[0xFF, 0xFF, 0xFF, 0xFF]))?;
173+
174+
let buffer = Cursor::new(Vec::<u8>::new());
175+
let mut writer = OggWriter::new(buffer, 48000, 2)?;
176+
let result = writer.write_rtp(&valid_packet);
177+
178+
assert!(
179+
result.is_ok(),
180+
"OggWriter should be able to write a large (> 255 bytes) Opus packet"
181+
);
182+
assert!(
183+
writer.writer.into_inner()[126..131] == [4, 255, 255, 255, 235],
184+
"OggWriter should be able to write multiple segments per page, for 1000 bytes, 4 segments of 255, 255, 255 and 235 long"
185+
);
186+
187+
Ok(())
188+
}
189+
190+
#[test]
191+
fn test_ogg_writer_add_large_packet_with_multiple_of_255() -> Result<()> {
192+
let raw_pkt = Bytes::from_iter(std::iter::repeat(0x45).take(255 * 4));
193+
194+
let mut valid_packet = rtp::packet::Packet {
195+
header: rtp::header::Header {
196+
marker: true,
197+
extension: true,
198+
extension_profile: 1,
199+
version: 2,
200+
payload_type: 111,
201+
sequence_number: 27023,
202+
timestamp: 3653407706,
203+
ssrc: 476325762,
204+
csrc: vec![],
205+
padding: false,
206+
extensions: vec![],
207+
extensions_padding: 0,
208+
},
209+
payload: raw_pkt,
210+
};
211+
valid_packet
212+
.header
213+
.set_extension(0, Bytes::from_static(&[0xFF, 0xFF, 0xFF, 0xFF]))?;
214+
215+
let buffer = Cursor::new(Vec::<u8>::new());
216+
let mut writer = OggWriter::new(buffer, 48000, 2)?;
217+
let result = writer.write_rtp(&valid_packet);
218+
219+
assert!(
220+
result.is_ok(),
221+
"OggWriter should be able to write a large (> 255 bytes) Opus packet"
222+
);
223+
assert!(
224+
writer.writer.into_inner()[126..131] == [4, 255, 255, 255, 255],
225+
"OggWriter should be able to write multiple segments per page, for 1020 bytes, 4 segments of 255 each"
226+
);
227+
228+
Ok(())
229+
}

0 commit comments

Comments
 (0)