rmmux: improve the audio packet timestamp handling
[nihav.git] / nihav-realmedia / src / muxers / rmvb / mod.rs
CommitLineData
9dc1fb4b
KS
1use nihav_core::muxers::*;
2mod audiostream;
3use audiostream::*;
4mod videostream;
5use videostream::*;
6
7trait RMWriterHelper {
8 fn write_chunk(&mut self, id: &[u8], size: u32, version: u16) -> MuxerResult<()>;
9 fn write_string(&mut self, data: &[u8]) -> MuxerResult<()>;
10 fn patch_value(&mut self, val: u32, off: u64) -> MuxerResult<()>;
11}
12
13impl<'a> RMWriterHelper for ByteWriter<'a> {
14 fn write_chunk(&mut self, id: &[u8], size: u32, version: u16) -> MuxerResult<()> {
15 self.write_buf(id)?;
16 self.write_u32be(size)?;
17 self.write_u16be(version)?;
18 Ok(())
19 }
20 fn write_string(&mut self, data: &[u8]) -> MuxerResult<()> {
21 validate!(data.len() < 256);
22 self.write_byte(data.len() as u8)?;
23 self.write_buf(data)?;
24 Ok(())
25 }
26 fn patch_value(&mut self, val: u32, off: u64) -> MuxerResult<()> {
27 let cur_pos = self.tell();
28 self.seek(SeekFrom::Start(off))?;
29 self.write_u32be(val)?;
30 self.seek(SeekFrom::Start(cur_pos))?;
31 Ok(())
32 }
33}
34
35pub trait RMStreamWriter {
36 fn write_header(&mut self, bw: &mut ByteWriter, astream: &NAStream) -> MuxerResult<()>;
c5963b17
KS
37 fn queue_packet(&mut self, pkt: NAPacket, ms: u32) -> bool;
38 fn get_packet(&mut self) -> Option<(Vec<u8>, u32, bool)>;
9dc1fb4b
KS
39 fn flush(&mut self);
40 fn finish(&mut self, bw: &mut ByteWriter) -> MuxerResult<()>;
41}
42
43#[derive(Clone,Copy)]
44struct IndexEntry {
45 time: u32,
46 pos: u64,
47 pkt_no: u32,
48}
49
50struct RMStream {
51 packetiser: Box<dyn RMStreamWriter>,
52 stream_id: u16,
53 mdpr_pos: u64,
54 npkts: usize,
55 data_size: usize,
56 max_pkt_size: usize,
57 time: u32,
58 cur_time: u32,
59 keyframe: bool,
60 audio: bool,
61 index: Vec<IndexEntry>,
62}
63
64impl RMStream {
65 fn new(strno: usize, stream: &NAStream) -> MuxerResult<Self> {
66 let packetiser = match stream.get_media_type() {
67 StreamType::Video => create_video_stream(stream)?,
68 StreamType::Audio => create_audio_stream(stream)?,
69 _ => Box::new(DummyStreamWriter{}),
70 };
71 Ok(Self{
72 packetiser,
73 stream_id: strno as u16,
74 mdpr_pos: 0,
75 npkts: 0,
76 data_size: 0,
77 max_pkt_size: 0,
78 time: 0,
79 cur_time: 0,
80 keyframe: false,
81 audio: false,
82 index: Vec::new(),
83 })
84 }
85 fn write_mdpr(&mut self, bw: &mut ByteWriter, strm: &NAStream) -> MuxerResult<()> {
86 self.mdpr_pos = bw.tell();
87
88 bw.write_chunk(b"MDPR", 0, 0)?;
89 bw.write_u16be(self.stream_id as u16)?;
90 bw.write_u32be(0)?; //max br
91 bw.write_u32be(0)?; //avg br
92 bw.write_u32be(0)?; //max ps
93 bw.write_u32be(0)?; //avg ps
94 bw.write_u32be(0)?; //num packets
95 bw.write_u32be(0)?; //duration
96 bw.write_u32be(0)?; //preroll
97
98 match strm.get_media_type() {
99 StreamType::Video => {
100 bw.write_string(b"The Video Stream")?;
101 bw.write_string(b"video/x-pn-realvideo")?;
102 },
103 StreamType::Audio => {
104 bw.write_string(b"The Audio Stream")?;
105 bw.write_string(b"audio/x-pn-realaudio")?;
106 self.audio = true;
107 },
108 _ => {
109 bw.write_string(b"some other stream")?;
110 bw.write_string(b"data")?;
111 },
112 };
113 bw.write_u32be(0)?; //extradata size
114 let edata_start = bw.tell();
115 self.packetiser.write_header(bw, strm)?;
116 let edata_end = bw.tell();
117 bw.patch_value((edata_end - edata_start) as u32, edata_start - 4)?;
118
119 patch_size(bw, self.mdpr_pos)?;
120
121 Ok(())
122 }
123 fn write_packet(&mut self, bw: &mut ByteWriter, pkt: NAPacket, pkt_no: &mut u32) -> MuxerResult<()> {
124 if let Some(pts) = pkt.get_pts() {
125 let (tb_num, tb_den) = pkt.get_stream().get_timebase();
126 let ms = NATimeInfo::ts_to_time(pts, 1000, tb_num, tb_den) as u32;
127 self.time = self.time.max(ms);
128 self.cur_time = ms;
129 }
c5963b17
KS
130 self.keyframe = pkt.keyframe || self.audio;
131 self.packetiser.queue_packet(pkt, self.cur_time);
9dc1fb4b
KS
132 self.write_packets(bw, pkt_no)
133 }
134 fn write_packets(&mut self, bw: &mut ByteWriter, pkt_no: &mut u32) -> MuxerResult<()> {
c5963b17 135 while let Some((data, ts, first)) = self.packetiser.get_packet() {
9dc1fb4b
KS
136 validate!(data.len() < 65000);
137 if self.keyframe && first {
c5963b17 138 self.index.push(IndexEntry{ time: ts, pos: bw.tell(), pkt_no: *pkt_no });
9dc1fb4b
KS
139 }
140 let is_keyframe = self.keyframe && (!self.audio || first);
141 bw.write_u16be(0)?; //version;
142 bw.write_u16be((data.len() + 12) as u16)?;
143 bw.write_u16be(self.stream_id)?;
c5963b17 144 bw.write_u32be(ts)?;
9dc1fb4b
KS
145 bw.write_byte(0)?; //packet group
146 bw.write_byte(if is_keyframe { 0x2 } else { 0x0 })?;
147 bw.write_buf(&data)?;
148
149 self.npkts += 1;
150 self.data_size += data.len();
151
152 *pkt_no += 1;
153 }
154 Ok(())
155 }
156 fn finish(&mut self, bw: &mut ByteWriter, pkt_no: &mut u32) -> MuxerResult<()> {
157 self.packetiser.flush();
158 self.write_packets(bw, pkt_no)?;
159
160 let pos = bw.tell();
161 bw.seek(SeekFrom::Start(self.mdpr_pos + 12))?;
162 bw.write_u32be(if self.time > 0 { (self.data_size * 1000 / (self.time as usize)) as u32 } else { 0 })?;
163 bw.write_u32be(if self.time > 0 { (self.data_size * 1000 / (self.time as usize)) as u32 } else { 0 })?;
164 bw.write_u32be(self.max_pkt_size as u32)?;
165 bw.write_u32be(if self.npkts > 0 { (self.data_size / self.npkts) as u32 } else { 0 })?;
166 bw.seek(SeekFrom::Current(8))?;
167 bw.write_u32be(self.time)?;
168
169 bw.seek(SeekFrom::Start(pos))?;
170 Ok(())
171 }
172}
173
174struct RMMuxer<'a> {
175 bw: &'a mut ByteWriter<'a>,
176 streams: Vec<RMStream>,
177 data_pos: u64,
178 num_chunks: u32,
179 cur_packet: u32,
180}
181
182impl<'a> RMMuxer<'a> {
183 fn new(bw: &'a mut ByteWriter<'a>) -> Self {
184 Self {
185 bw,
186 streams: Vec::new(),
187 data_pos: 0,
188 num_chunks: 0,
189 cur_packet: 0,
190 }
191 }
192 fn write_index(&mut self) -> MuxerResult<()> {
193 let mut indx_pos = 0x38;
194
195 for stream in self.streams.iter() {
196 let cur_pos = self.bw.tell();
197 self.bw.patch_value(cur_pos as u32, indx_pos)?;
198 indx_pos = cur_pos + 16;
199
200 let idx_size = 10 + 10 + stream.index.len() * 14;
201 self.bw.write_chunk(b"INDX", idx_size as u32, 0)?;
202 self.bw.write_u32be(stream.index.len() as u32)?;
203 self.bw.write_u16be(stream.stream_id)?;
204 self.bw.write_u32be(0)?; // next index position
205 for entry in stream.index.iter() {
206 self.bw.write_u16be(0)?; // version
207 self.bw.write_u32be(entry.time)?;
208 self.bw.write_u32be(entry.pos as u32)?;
209 self.bw.write_u32be(entry.pkt_no)?;
210 }
211
212 self.num_chunks += 1;
213 }
214
215 Ok(())
216 }
217 fn update_prop(&mut self) -> MuxerResult<()> {
218 let mut data_size = 0;
219 let mut npkts = 0;
220 let mut max_pkt_size = 0;
221 let mut time = 0;
222
223 for stream in self.streams.iter() {
224 data_size += stream.data_size;
225 time = time.max(stream.time);
226 npkts += stream.npkts;
227 max_pkt_size = max_pkt_size.max(stream.max_pkt_size);
228 }
229
230 if npkts > 0 && time > 0 {
231 let cur_pos = self.bw.tell();
232
233 let bitrate = (data_size * 1000 / (time as usize)) as u32;
234 self.bw.seek(SeekFrom::Start(28))?;
235 self.bw.write_u32be(bitrate)?;
236 self.bw.write_u32be(bitrate)?;
237 self.bw.write_u32be(max_pkt_size as u32)?;
238 self.bw.write_u32be((data_size / npkts) as u32)?;
239 self.bw.write_u32be(npkts as u32)?;
240 self.bw.write_u32be(time)?;
241
242 self.bw.seek(SeekFrom::Start(cur_pos))?;
243 }
244
245 self.bw.patch_value(self.data_pos as u32, 0x3C)?;
246
247 Ok(())
248 }
249}
250
251fn patch_size(bw: &mut ByteWriter, pos: u64) -> MuxerResult<()> {
252 let end = bw.tell();
253 bw.patch_value((end - pos) as u32, pos + 4)
254}
255
256impl<'a> MuxCore<'a> for RMMuxer<'a> {
257 fn create(&mut self, strmgr: &StreamManager) -> MuxerResult<()> {
258 if strmgr.get_num_streams() == 0 {
259 return Err(MuxerError::InvalidArgument);
260 }
261 if strmgr.get_num_streams() > 100 {
262 return Err(MuxerError::UnsupportedFormat);
263 }
264
265 self.bw.write_chunk(b".RMF", 18, 0)?;
266 self.bw.write_u32be(0)?; // container version
267 self.bw.write_u32be(0)?; // number of chunks
268
269 self.num_chunks = 1;
270 let prop_start = self.bw.tell();
271 self.bw.write_chunk(b"PROP", 0, 0)?;
272 self.bw.write_u32be(0)?; //max br
273 self.bw.write_u32be(0)?; //avg br
274 self.bw.write_u32be(0)?; //max ps
275 self.bw.write_u32be(0)?; //avg ps
276 self.bw.write_u32be(0)?; //num packets
277 self.bw.write_u32be(0)?; //duration
278 self.bw.write_u32be(0)?; //preroll
279 self.bw.write_u32be(0)?; //index offset
280 self.bw.write_u32be(0)?; //data offset
281 self.bw.write_u16be(strmgr.get_num_streams() as u16)?;
282 self.bw.write_u16be(0)?; // flags
283 patch_size(self.bw, prop_start)?;
284
285 self.streams.clear();
286 for (strno, strm) in strmgr.iter().enumerate() {
287 let mut swriter = RMStream::new(strno, &strm)?;
288 swriter.write_mdpr(self.bw, &strm)?;
289 self.streams.push(swriter);
290 self.num_chunks += 1;
291 }
292
293 self.data_pos = self.bw.tell();
294 self.bw.write_chunk(b"DATA", 0, 0)?;
295 self.bw.write_u32be(0)?; //num packets
296 self.bw.write_u32be(0)?; //next data chunk
297 self.num_chunks += 1;
298
299 Ok(())
300 }
301 fn mux_frame(&mut self, _strmgr: &StreamManager, pkt: NAPacket) -> MuxerResult<()> {
302 if self.data_pos == 0 {
303 return Err(MuxerError::NotCreated);
304 }
305 let stream = pkt.get_stream();
306 let str_num = stream.get_num();
307 if str_num > self.streams.len() {
308 return Err(MuxerError::UnsupportedFormat);
309 }
310 self.streams[str_num].write_packet(self.bw, pkt, &mut self.cur_packet)?;
311
312 Ok(())
313 }
314 fn flush(&mut self) -> MuxerResult<()> {
315 Ok(())
316 }
317 fn end(&mut self) -> MuxerResult<()> {
318 if self.data_pos == 0 {
319 return Err(MuxerError::NotCreated);
320 }
321 let mut tot_npkts = 0;
322 for stream in self.streams.iter_mut() {
323 stream.finish(self.bw, &mut self.cur_packet)?;
324 tot_npkts += stream.npkts;
325 }
326
327 let data_size = self.bw.tell() - self.data_pos;
328 self.bw.patch_value(data_size as u32, self.data_pos + 4)?;
329 self.bw.patch_value(tot_npkts as u32, self.data_pos + 10)?;
330
331 self.write_index()?;
332 self.update_prop()?;
333
334 self.bw.patch_value(self.num_chunks, 14)?;
335 Ok(())
336 }
337}
338
339impl<'a> NAOptionHandler for RMMuxer<'a> {
340 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
341 fn set_options(&mut self, _options: &[NAOption]) { }
342 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
343}
344
345pub struct RealMediaMuxerCreator {}
346
347impl MuxerCreator for RealMediaMuxerCreator {
348 fn new_muxer<'a>(&self, bw: &'a mut ByteWriter<'a>) -> Box<dyn MuxCore<'a> + 'a> {
349 Box::new(RMMuxer::new(bw))
350 }
351 fn get_name(&self) -> &'static str { "realmedia" }
352 fn get_capabilities(&self) -> MuxerCapabilities { MuxerCapabilities::Universal }
353}
354
355struct RAMuxer<'a> {
356 bw: &'a mut ByteWriter<'a>,
357 sw: Option<Box<dyn RMStreamWriter>>,
358}
359
360impl<'a> RAMuxer<'a> {
361 fn new(bw: &'a mut ByteWriter<'a>) -> Self {
362 Self {
363 bw,
364 sw: None,
365 }
366 }
367}
368
369impl<'a> MuxCore<'a> for RAMuxer<'a> {
370 fn create(&mut self, strmgr: &StreamManager) -> MuxerResult<()> {
371 if strmgr.get_num_streams() != 1 {
372 return Err(MuxerError::InvalidArgument);
373 }
374 let astream = strmgr.get_stream(0).unwrap();
375 if astream.get_media_type() != StreamType::Audio {
376 return Err(MuxerError::InvalidArgument);
377 }
378 self.sw = Some(create_audio_stream(&astream)?);
379 if let Some(ref mut sw) = self.sw {
380 sw.write_header(self.bw, &astream)?;
381 }
382 Ok(())
383 }
384 fn mux_frame(&mut self, _strmgr: &StreamManager, pkt: NAPacket) -> MuxerResult<()> {
385 if let Some(ref mut sw) = self.sw {
c5963b17
KS
386 sw.queue_packet(pkt, 0);
387 while let Some((data, _, _)) = sw.get_packet() {
9dc1fb4b
KS
388 self.bw.write_buf(&data)?;
389 }
390 Ok(())
391 } else {
392 Err(MuxerError::NotCreated)
393 }
394 }
395 fn flush(&mut self) -> MuxerResult<()> {
396 Ok(())
397 }
398 fn end(&mut self) -> MuxerResult<()> {
399 if let Some(ref mut sw) = self.sw {
400 sw.finish(&mut self.bw)?;
401 }
402 Ok(())
403 }
404}
405
406impl<'a> NAOptionHandler for RAMuxer<'a> {
407 fn get_supported_options(&self) -> &[NAOptionDefinition] { &[] }
408 fn set_options(&mut self, _options: &[NAOption]) { }
409 fn query_option_value(&self, _name: &str) -> Option<NAValue> { None }
410}
411
412pub struct RealAudioMuxerCreator {}
413
414impl MuxerCreator for RealAudioMuxerCreator {
415 fn new_muxer<'a>(&self, bw: &'a mut ByteWriter<'a>) -> Box<dyn MuxCore<'a> + 'a> {
416 Box::new(RAMuxer::new(bw))
417 }
418 fn get_name(&self) -> &'static str { "realaudio" }
419 fn get_capabilities(&self) -> MuxerCapabilities { MuxerCapabilities::SingleAudio("any") }
420}
421
422#[cfg(test)]
423mod test {
424 use nihav_core::codecs::*;
425 use nihav_core::demuxers::*;
426 use nihav_core::muxers::*;
427 use nihav_codec_support::test::enc_video::*;
428 use crate::*;
429
430 #[test]
431 fn test_rm_muxer() {
432 let mut dmx_reg = RegisteredDemuxers::new();
433 realmedia_register_all_demuxers(&mut dmx_reg);
434 // sample from a private collection
435 let dec_config = DecoderTestParams {
436 demuxer: "realmedia",
437 in_name: "assets/RV/rv30_weighted_mc.rm",
438 limit: None,
439 stream_type: StreamType::None,
440 dmx_reg, dec_reg: RegisteredDecoders::new(),
441 };
442 let mut mux_reg = RegisteredMuxers::new();
443 realmedia_register_all_muxers(&mut mux_reg);
444 /*let enc_config = EncoderTestParams {
445 muxer: "realmedia",
446 enc_name: "",
447 out_name: "muxed.rm",
448 mux_reg, enc_reg: RegisteredEncoders::new(),
449 };
450 test_remuxing(&dec_config, &enc_config);*/
451 test_remuxing_md5(&dec_config, "realmedia", &mux_reg,
452 [0x26422839, 0xa2d7bdd1, 0xd6ea2a78, 0x1b58033a]);
453 }
454
455 #[test]
456 fn test_ra_muxer_v3() {
457 let mut dmx_reg = RegisteredDemuxers::new();
458 realmedia_register_all_demuxers(&mut dmx_reg);
459 //test sample: https://samples.mplayerhq.hu/real/RA/14_4/drummers.14.ra
460 let dec_config = DecoderTestParams {
461 demuxer: "realaudio",
462 in_name: "assets/RV/drummers.14.ra",
463 limit: None,
464 stream_type: StreamType::None,
465 dmx_reg, dec_reg: RegisteredDecoders::new(),
466 };
467 let mut mux_reg = RegisteredMuxers::new();
468 realmedia_register_all_muxers(&mut mux_reg);
469 /*let enc_config = EncoderTestParams {
470 muxer: "realaudio",
471 enc_name: "",
472 out_name: "v3.ra",
473 mux_reg, enc_reg: RegisteredEncoders::new(),
474 };
475 test_remuxing(&dec_config, &enc_config);*/
476 test_remuxing_md5(&dec_config, "realaudio", &mux_reg,
477 [0x8101a484, 0xf5d80805, 0x24577596, 0x9b27262f]);
478 }
479 #[test]
480 fn test_ra_muxer_v4() {
481 let mut dmx_reg = RegisteredDemuxers::new();
482 realmedia_register_all_demuxers(&mut dmx_reg);
483 //test sample: https://samples.mplayerhq.hu/real//RA/ra_with_comment_field/diemusik.ra
484 let dec_config = DecoderTestParams {
485 demuxer: "realaudio",
486 in_name: "assets/RV/diemusik.ra",
487 limit: None,
488 stream_type: StreamType::None,
489 dmx_reg, dec_reg: RegisteredDecoders::new(),
490 };
491 let mut mux_reg = RegisteredMuxers::new();
492 realmedia_register_all_muxers(&mut mux_reg);
493 /*let enc_config = EncoderTestParams {
494 muxer: "realaudio",
495 enc_name: "",
496 out_name: "v4.ra",
497 mux_reg, enc_reg: RegisteredEncoders::new(),
498 };
499 test_remuxing(&dec_config, &enc_config);*/
500 test_remuxing_md5(&dec_config, "realaudio", &mux_reg,
501 [0x33665ec3, 0x69b68ea2, 0x08d4b138, 0x318e305f]);
502 }
503 #[test]
504 fn test_ra_muxer_sipro() {
505 let mut dmx_reg = RegisteredDemuxers::new();
506 realmedia_register_all_demuxers(&mut dmx_reg);
507 //test sample: https://samples.mplayerhq.hu/real/AC-sipr/autahi-vox.rm
508 let dec_config = DecoderTestParams {
509 demuxer: "realmedia",
510 in_name: "assets/RV/autahi-vox.rm",
511 limit: None,
512 stream_type: StreamType::None,
513 dmx_reg, dec_reg: RegisteredDecoders::new(),
514 };
515 let mut mux_reg = RegisteredMuxers::new();
516 realmedia_register_all_muxers(&mut mux_reg);
517 /*let enc_config = EncoderTestParams {
518 muxer: "realaudio",
519 enc_name: "",
520 out_name: "v4-sipro.ra",
521 mux_reg, enc_reg: RegisteredEncoders::new(),
522 };
523 test_remuxing(&dec_config, &enc_config);*/
524 test_remuxing_md5(&dec_config, "realaudio", &mux_reg,
525 [0x08bd496d, 0x5f35d7ae, 0xe9c93c50, 0x9e803f76]);
526 }
527 #[test]
528 fn test_ra_muxer_v5() {
529 let mut dmx_reg = RegisteredDemuxers::new();
530 realmedia_register_all_demuxers(&mut dmx_reg);
531 //test sample: https://samples.mplayerhq.hu/real/AC-cook/cook_5.1/multichannel.rma
532 let dec_config = DecoderTestParams {
533 demuxer: "realmedia",
534 in_name: "assets/RV/multichannel.rma",
535 limit: None,
536 stream_type: StreamType::None,
537 dmx_reg, dec_reg: RegisteredDecoders::new(),
538 };
539 let mut mux_reg = RegisteredMuxers::new();
540 realmedia_register_all_muxers(&mut mux_reg);
541 /*let enc_config = EncoderTestParams {
542 muxer: "realaudio",
543 enc_name: "",
544 out_name: "v5.ra",
545 mux_reg, enc_reg: RegisteredEncoders::new(),
546 };
547 test_remuxing(&dec_config, &enc_config);*/
548 test_remuxing_md5(&dec_config, "realaudio", &mux_reg,
549 [0x52f42c49, 0x90ac79a7, 0x275a465f, 0x7a6f3659]);
550 }
551 #[test]
552 fn test_rm_muxer_aac() {
553 let mut dmx_reg = RegisteredDemuxers::new();
554 realmedia_register_all_demuxers(&mut dmx_reg);
555 //sample from a private collection
556 let dec_config = DecoderTestParams {
557 demuxer: "realmedia",
558 in_name: "assets/RV/rv40_weighted_mc_2.rmvb",
559 limit: None,
560 stream_type: StreamType::None,
561 dmx_reg, dec_reg: RegisteredDecoders::new(),
562 };
563 let mut mux_reg = RegisteredMuxers::new();
564 realmedia_register_all_muxers(&mut mux_reg);
565 /*let enc_config = EncoderTestParams {
566 muxer: "realmedia",
567 enc_name: "",
568 out_name: "aac.ram",
569 mux_reg, enc_reg: RegisteredEncoders::new(),
570 };
571 test_remuxing(&dec_config, &enc_config);*/
572 test_remuxing_md5(&dec_config, "realmedia", &mux_reg,
c5963b17 573 [0xcfa1a27b, 0x78314fa7, 0xeb90c31c, 0x7eafeaa8]);
9dc1fb4b
KS
574 }
575 #[test]
576 fn test_rm_muxer_ralf() {
577 let mut dmx_reg = RegisteredDemuxers::new();
578 realmedia_register_all_demuxers(&mut dmx_reg);
579 //sample from a private collection
580 let dec_config = DecoderTestParams {
581 demuxer: "realmedia",
582 in_name: "assets/RV/rv40_ralf.rmvb",
583 limit: None,
584 stream_type: StreamType::None,
585 dmx_reg, dec_reg: RegisteredDecoders::new(),
586 };
587 let mut mux_reg = RegisteredMuxers::new();
588 realmedia_register_all_muxers(&mut mux_reg);
589 /*let enc_config = EncoderTestParams {
590 muxer: "realmedia",
591 enc_name: "",
592 out_name: "ralf.ram",
593 mux_reg, enc_reg: RegisteredEncoders::new(),
594 };
595 test_remuxing(&dec_config, &enc_config);*/
596 test_remuxing_md5(&dec_config, "realmedia", &mux_reg,
597 [0xa0c336d1, 0x76221455, 0x75252067, 0x6189d4af]);
598 }
599}