1 //! Routines for testing decoders.
3 use nihav_core::frame::*;
4 use nihav_core::codecs::*;
5 use nihav_core::demuxers::*;
6 //use nihav_core::io::byteio::*;
7 //use nihav_core::scale::*;
8 use nihav_core::reorder::MTFrameReorderer;
9 use super::wavwriter::WavWriter;
11 use crate::imgwrite::write_pnm;
12 pub use super::ExpectedTestResult;
14 const OUTPUT_PREFIX: &str = "assets/test_out/";
16 /*fn open_wav_out(pfx: &str, strno: usize) -> WavWriter {
17 let name = format!("assets/{}out{:02}.wav", pfx, strno);
18 let mut file = File::create(name).unwrap();
19 let mut fw = FileWriter::new_write(&mut file);
20 let mut wr = ByteWriter::new(&mut fw);
21 WavWriter::new(&mut wr)
24 /// Tests decoding of provided file and optionally outputs video frames as PNM (PPM for RGB video, PGM for YUV).
26 /// This function expects the following arguments:
27 /// * `demuxer` - container format name (used to find proper demuxer for it)
28 /// * `name` - input file name
29 /// * `limit` - optional PTS value after which decoding is stopped
30 /// * `decode_video`/`decode_audio` - flags for enabling video/audio decoding
31 /// * `video_pfx` - prefix for video frames written as pictures (if enabled then output picture names should look like `<crate_name>/assets/test_out/PFXout00_000000.ppm`
32 /// * `dmx_reg` and `dec_reg` - registered demuxers and decoders that should contain demuxer and decoder(s) needed to decode the provided file.
34 /// Since the function is intended for tests, it will panic instead of returning an error.
35 pub fn test_file_decoding(demuxer: &str, name: &str, limit: Option<u64>,
36 decode_video: bool, decode_audio: bool,
37 video_pfx: Option<&str>,
38 dmx_reg: &RegisteredDemuxers, dec_reg: &RegisteredDecoders) {
39 let dmx_f = dmx_reg.find_demuxer(demuxer).unwrap();
40 let mut file = File::open(name).unwrap();
41 let mut fr = FileReader::new_read(&mut file);
42 let mut br = ByteReader::new(&mut fr);
43 let mut dmx = create_demuxer(dmx_f, &mut br).unwrap();
45 let mut decs: Vec<Option<(Box<NADecoderSupport>, Box<dyn NADecoder>)>> = Vec::new();
46 for i in 0..dmx.get_num_streams() {
47 let s = dmx.get_stream(i).unwrap();
48 let info = s.get_info();
49 let decfunc = dec_reg.find_decoder(info.get_name());
50 if let Some(df) = decfunc {
51 if (decode_video && info.is_video()) || (decode_audio && info.is_audio()) {
53 let mut dsupp = Box::new(NADecoderSupport::new());
54 dec.init(&mut dsupp, info).unwrap();
55 decs.push(Some((dsupp, dec)));
65 let pktres = dmx.get_frame();
66 if let Err(e) = pktres {
67 if e == DemuxerError::EOF { break; }
70 let pkt = pktres.unwrap();
71 let streamno = pkt.get_stream().get_id() as usize;
72 if let Some((ref mut dsupp, ref mut dec)) = decs[streamno] {
73 if let (Some(lim), Some(ppts)) = (limit, pkt.get_pts()) {
74 if ppts > lim { break; }
76 let frm = dec.decode(dsupp, &pkt).unwrap();
77 if pkt.get_stream().get_info().is_video() && video_pfx.is_some() && frm.get_frame_type() != FrameType::Skip {
78 let pts = if let Some(fpts) = frm.get_pts() { fpts } else { pkt.get_pts().unwrap() };
79 let pfx = OUTPUT_PREFIX.to_owned() + video_pfx.unwrap_or("") + "out";
80 write_pnm(pfx.as_str(), streamno, pts, frm).unwrap();
86 /// Tests audio decoder with the content in the provided file and optionally outputs decoded audio.
88 /// The syntax is very similar to [`test_file_decoding`] except that it is intended for testing audio codecs.
90 /// Since the function is intended for tests, it will panic instead of returning an error.
92 /// [`test_file_decoding`]: ./fn.test_file_decoding.html
93 pub fn test_decode_audio(demuxer: &str, name: &str, limit: Option<u64>, audio_pfx: Option<&str>,
94 dmx_reg: &RegisteredDemuxers, dec_reg: &RegisteredDecoders) {
95 let dmx_f = dmx_reg.find_demuxer(demuxer).unwrap();
96 let mut file = File::open(name).unwrap();
97 let mut fr = FileReader::new_read(&mut file);
98 let mut br = ByteReader::new(&mut fr);
99 let mut dmx = create_demuxer(dmx_f, &mut br).unwrap();
101 let mut decs: Vec<Option<(Box<NADecoderSupport>, Box<dyn NADecoder>)>> = Vec::new();
102 for i in 0..dmx.get_num_streams() {
103 let s = dmx.get_stream(i).unwrap();
104 let info = s.get_info();
105 let decfunc = dec_reg.find_decoder(info.get_name());
106 if let Some(df) = decfunc {
108 let mut dec = (df)();
109 let mut dsupp = Box::new(NADecoderSupport::new());
110 dec.init(&mut dsupp, info).unwrap();
111 decs.push(Some((dsupp, dec)));
120 if let Some(audio_pfx) = audio_pfx {
121 let name = format!("{}/{}out.wav", OUTPUT_PREFIX, audio_pfx);
122 let file = File::create(name).unwrap();
123 let mut fw = FileWriter::new_write(file);
124 let mut wr = ByteWriter::new(&mut fw);
125 let mut wwr = WavWriter::new(&mut wr);
126 let mut wrote_header = false;
129 let pktres = dmx.get_frame();
130 if let Err(e) = pktres {
131 if e == DemuxerError::EOF { break; }
134 let pkt = pktres.unwrap();
135 if limit.is_some() && pkt.get_pts().is_some() && pkt.get_pts().unwrap() > limit.unwrap() {
138 let streamno = pkt.get_stream().get_id() as usize;
139 if let Some((ref mut dsupp, ref mut dec)) = decs[streamno] {
140 let frm = dec.decode(dsupp, &pkt).unwrap();
141 if frm.get_info().is_audio() {
143 wwr.write_header(frm.get_info().as_ref().get_properties().get_audio_info().unwrap()).unwrap();
146 wwr.write_frame(frm.get_buffer()).unwrap();
152 let pktres = dmx.get_frame();
153 if let Err(e) = pktres {
154 if e == DemuxerError::EOF { break; }
157 let pkt = pktres.unwrap();
158 if limit.is_some() && pkt.get_pts().is_some() && pkt.get_pts().unwrap() > limit.unwrap() {
161 let streamno = pkt.get_stream().get_id() as usize;
162 if let Some((ref mut dsupp, ref mut dec)) = decs[streamno] {
163 let _ = dec.decode(dsupp, &pkt).unwrap();
169 fn frame_checksum(md5: &mut MD5, frm: NAFrameRef) {
170 match frm.get_buffer() {
171 NABufferType::Video(ref vb) => {
172 md5.update_hash(vb.get_data());
174 NABufferType::Video16(ref vb) => {
175 let mut samp = [0u8; 2];
176 let data = vb.get_data();
177 for el in data.iter() {
178 samp[0] = (*el >> 8) as u8;
179 samp[1] = (*el >> 0) as u8;
180 md5.update_hash(&samp);
183 NABufferType::Video32(ref vb) => {
184 let mut samp = [0u8; 4];
185 let data = vb.get_data();
186 for el in data.iter() {
187 samp[0] = (*el >> 24) as u8;
188 samp[1] = (*el >> 16) as u8;
189 samp[2] = (*el >> 8) as u8;
190 samp[3] = (*el >> 0) as u8;
191 md5.update_hash(&samp);
194 NABufferType::VideoPacked(ref vb) => {
195 md5.update_hash(vb.get_data());
197 NABufferType::AudioU8(ref ab) => {
198 md5.update_hash(ab.get_data());
200 NABufferType::AudioI16(ref ab) => {
201 let mut samp = [0u8; 2];
202 let data = ab.get_data();
203 for el in data.iter() {
204 samp[0] = (*el >> 8) as u8;
205 samp[1] = (*el >> 0) as u8;
206 md5.update_hash(&samp);
209 NABufferType::AudioI32(ref ab) => {
210 let mut samp = [0u8; 4];
211 let data = ab.get_data();
212 for el in data.iter() {
213 samp[0] = (*el >> 24) as u8;
214 samp[1] = (*el >> 16) as u8;
215 samp[2] = (*el >> 8) as u8;
216 samp[3] = (*el >> 0) as u8;
217 md5.update_hash(&samp);
220 NABufferType::AudioF32(ref ab) => {
221 let mut samp = [0u8; 4];
222 let data = ab.get_data();
223 for el in data.iter() {
224 let bits = el.to_bits();
225 samp[0] = (bits >> 24) as u8;
226 samp[1] = (bits >> 16) as u8;
227 samp[2] = (bits >> 8) as u8;
228 samp[3] = (bits >> 0) as u8;
229 md5.update_hash(&samp);
232 NABufferType::AudioPacked(ref ab) => {
233 md5.update_hash(ab.get_data());
235 NABufferType::Data(ref db) => {
236 md5.update_hash(db.as_ref());
238 NABufferType::None => {},
242 /// Tests decoder for requested codec in provided file.
244 /// This functions tries to decode a stream corresponding to `dec_name` codec in input file and validate the results against expected ones.
246 /// Since the function is intended for tests, it will panic instead of returning an error.
250 /// Test RealVideo 4 decoder in test stream:
252 /// use nihav_codec_support::test::ExpectedTestResult;
253 /// use nihav_codec_support::test::dec_video::test_decoding;
254 /// use nihav_core::codecs::RegisteredDecoders;
255 /// use nihav_core::demuxers::RegisteredDemuxers;
257 /// let mut dmx_reg = RegisteredDemuxers::new();
258 /// let mut dec_reg = RegisteredDecoders::new();
259 /// // ... register RealMedia demuxers and RealVideo decoders ...
260 /// test_decoding("realmedia", "rv40", "assets/test_file.rmvb", None, &dmx_reg, &dec_reg, ExpectedTestResult::MD5([0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f]));
262 pub fn test_decoding(demuxer: &str, dec_name: &str, filename: &str, limit: Option<u64>,
263 dmx_reg: &RegisteredDemuxers, dec_reg: &RegisteredDecoders,
264 test: ExpectedTestResult) {
265 let dmx_f = dmx_reg.find_demuxer(demuxer).unwrap();
266 let mut file = File::open(filename).unwrap();
267 let mut fr = FileReader::new_read(&mut file);
268 let mut br = ByteReader::new(&mut fr);
269 let mut dmx = create_demuxer(dmx_f, &mut br).unwrap();
271 let mut decs: Vec<Option<(Box<NADecoderSupport>, Box<dyn NADecoder>)>> = Vec::new();
272 let mut found = false;
273 for i in 0..dmx.get_num_streams() {
274 let s = dmx.get_stream(i).unwrap();
275 let info = s.get_info();
276 println!("stream {} codec {} / {}", i, info.get_name(), dec_name);
277 if !found && (info.get_name() == dec_name) {
278 let decfunc = dec_reg.find_decoder(info.get_name());
279 if let Some(df) = decfunc {
280 let mut dec = (df)();
281 let mut dsupp = Box::new(NADecoderSupport::new());
282 dec.init(&mut dsupp, info).unwrap();
283 decs.push(Some((dsupp, dec)));
293 let mut md5 = MD5::new();
294 let mut frameiter = if let ExpectedTestResult::MD5Frames(ref vec) = test {
300 let pktres = dmx.get_frame();
301 if let Err(e) = pktres {
302 if e == DemuxerError::EOF { break; }
305 let pkt = pktres.unwrap();
306 let streamno = pkt.get_stream().get_id() as usize;
307 if let Some((ref mut dsupp, ref mut dec)) = decs[streamno] {
308 if limit.is_some() && pkt.get_pts().is_some() && pkt.get_pts().unwrap() > limit.unwrap() {
311 let frm = dec.decode(dsupp, &pkt).unwrap();
313 ExpectedTestResult::Decodes => {},
314 ExpectedTestResult::MD5(_) => { frame_checksum(&mut md5, frm); },
315 ExpectedTestResult::MD5Frames(_) => {
317 frame_checksum(&mut md5, frm);
319 if let Some(ref mut iter) = frameiter {
320 let ret = iter.next();
321 if ret.is_none() { break; }
322 let ref_hash = ret.unwrap();
323 let mut hash = [0u32; 4];
324 md5.get_hash(&mut hash);
325 println!("frame pts {:?} hash {}", pkt.get_pts(), md5);
326 assert_eq!(&hash, ref_hash);
329 ExpectedTestResult::GenerateMD5Frames => {
331 frame_checksum(&mut md5, frm);
333 let mut hash = [0u32; 4];
334 md5.get_hash(&mut hash);
335 println!("frame pts {:?} hash [0x{:08x}, 0x{:08x}, 0x{:08x}, 0x{:08x}],", pkt.get_pts(), hash[0], hash[1], hash[2], hash[3]);
340 if let ExpectedTestResult::MD5(ref ref_hash) = test {
342 let mut hash = [0u32; 4];
343 md5.get_hash(&mut hash);
344 println!("full hash {}", md5);
345 assert_eq!(&hash, ref_hash);
347 if let ExpectedTestResult::GenerateMD5Frames = test {
348 panic!("generated hashes");
352 /// Tests decoder for requested codec in provided file with raw streams.
354 /// This functions tries to decode a stream corresponding to `dec_name` codec in input file and validate the results against expected ones.
356 /// Since the function is intended for tests, it will panic instead of returning an error.
360 /// Test FLAC decoder in test stream:
362 /// use nihav_codec_support::test::ExpectedTestResult;
363 /// use nihav_codec_support::test::dec_video::test_decoding_raw;
364 /// use nihav_core::codecs::RegisteredDecoders;
365 /// use nihav_core::demuxers::RegisteredDemuxers;
367 /// let mut dmx_reg = RegisteredRawDemuxers::new();
368 /// let mut pkt_reg = RegisteredPacketisers::new();
369 /// let mut dec_reg = RegisteredDecoders::new();
370 /// // ... register FLAC demuxer, packetiser and decoders ...
371 /// test_decoding_raw("flac", "flac", "assets/test_file.flac", None, &dmx_reg, &pkt_reg, &dec_reg, ExpectedTestResult::MD5([0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f]));
373 pub fn test_decoding_raw(demuxer: &str, dec_name: &str, filename: &str, limit: Option<u64>,
374 dmx_reg: &RegisteredRawDemuxers, pkt_reg: &RegisteredPacketisers,
375 dec_reg: &RegisteredDecoders, test: ExpectedTestResult) {
376 let dmx_f = dmx_reg.find_demuxer(demuxer).unwrap();
377 let mut file = File::open(filename).unwrap();
378 let mut fr = FileReader::new_read(&mut file);
379 let mut br = ByteReader::new(&mut fr);
380 let mut dmx = create_raw_demuxer(dmx_f, &mut br).unwrap();
382 let mut decs: Vec<Option<(Box<dyn NAPacketiser>, Box<NADecoderSupport>, Box<dyn NADecoder>)>> = Vec::new();
383 let mut found = false;
384 for i in 0..dmx.get_num_streams() {
385 let s = dmx.get_stream(i).unwrap();
386 let info = s.get_info();
387 println!("stream {} codec {} / {}", i, info.get_name(), dec_name);
388 if !found && (info.get_name() == dec_name) {
389 let decfunc = dec_reg.find_decoder(info.get_name());
390 let pktfunc = pkt_reg.find_packetiser(info.get_name());
391 if let (Some(df), Some(pf)) = (decfunc, pktfunc) {
392 let mut pkt = (pf)();
393 pkt.attach_stream(s);
394 let mut dec = (df)();
395 let mut dsupp = Box::new(NADecoderSupport::new());
396 dec.init(&mut dsupp, info).unwrap();
397 decs.push(Some((pkt, dsupp, dec)));
407 let mut md5 = MD5::new();
408 let mut frameiter = if let ExpectedTestResult::MD5Frames(ref vec) = test {
414 let datares = dmx.get_data();
415 if let Err(e) = datares {
416 if e == DemuxerError::EOF { break; }
419 let data = datares.unwrap();
420 let streamno = data.get_stream().get_id() as usize;
421 if let Some((ref mut pktr, ref mut dsupp, ref mut dec)) = decs[streamno] {
422 pktr.add_data(&data.get_buffer());
423 while let Ok(Some(pkt)) = pktr.get_packet(data.get_stream()) {
424 if limit.is_some() && pkt.get_pts().is_some() && pkt.get_pts().unwrap() > limit.unwrap() {
427 let frm = dec.decode(dsupp, &pkt).unwrap();
429 ExpectedTestResult::Decodes => {},
430 ExpectedTestResult::MD5(_) => { frame_checksum(&mut md5, frm); },
431 ExpectedTestResult::MD5Frames(_) => {
433 frame_checksum(&mut md5, frm);
435 if let Some(ref mut iter) = frameiter {
436 let ret = iter.next();
437 if ret.is_none() { break; }
438 let ref_hash = ret.unwrap();
439 let mut hash = [0u32; 4];
440 md5.get_hash(&mut hash);
441 println!("frame pts {:?} hash {}", pkt.get_pts(), md5);
442 assert_eq!(&hash, ref_hash);
445 ExpectedTestResult::GenerateMD5Frames => {
447 frame_checksum(&mut md5, frm);
449 let mut hash = [0u32; 4];
450 md5.get_hash(&mut hash);
451 println!("frame pts {:?} hash [0x{:08x}, 0x{:08x}, 0x{:08x}, 0x{:08x}],", pkt.get_pts(), hash[0], hash[1], hash[2], hash[3]);
457 if let ExpectedTestResult::MD5(ref ref_hash) = test {
459 let mut hash = [0u32; 4];
460 md5.get_hash(&mut hash);
461 println!("full hash {}", md5);
462 assert_eq!(&hash, ref_hash);
464 if let ExpectedTestResult::GenerateMD5Frames = test {
465 panic!("generated hashes");
469 const THREADS: usize = 3;
471 fn check_frame(frm: NAFrameRef, test: &ExpectedTestResult, glbl_md5: &mut MD5, frameiter: &mut Option<std::slice::Iter<[u32; 4]>>, last_ts: &mut Option<u64>) -> bool {
472 let frm_pts = frm.get_pts();
473 let frm_dts = frm.get_dts();
474 if let (Some(lts), Some(cts)) = (*last_ts, frm_dts) {
479 ExpectedTestResult::Decodes => {},
480 ExpectedTestResult::MD5(_) => { frame_checksum(glbl_md5, frm); },
481 ExpectedTestResult::MD5Frames(_) => {
482 let mut loc_md5 = MD5::new();
483 frame_checksum(&mut loc_md5, frm);
485 if let Some(ref mut iter) = frameiter {
486 let ret = iter.next();
490 let ref_hash = ret.unwrap();
491 let mut hash = [0u32; 4];
492 loc_md5.get_hash(&mut hash);
493 println!("frame pts {:?} dts {:?} hash {}", frm_pts, frm_dts, loc_md5);
494 assert_eq!(&hash, ref_hash);
497 ExpectedTestResult::GenerateMD5Frames => {
498 let mut loc_md5 = MD5::new();
499 frame_checksum(&mut loc_md5, frm);
501 let mut hash = [0u32; 4];
502 loc_md5.get_hash(&mut hash);
503 println!("frame pts {:?} dts {:?} hash [0x{:08x}, 0x{:08x}, 0x{:08x}, 0x{:08x}],", frm_pts, frm_dts, hash[0], hash[1], hash[2], hash[3]);
509 /// Tests multi-threaded decoder for requested codec in provided file.
511 /// The syntax is very similar to [`test_file_decoding`] except that it tests multi-threaded decoders instead.
513 /// [`test_file_decoding`]: ./fn.test_file_decoding.html
514 pub fn test_mt_decoding(demuxer: &str, dec_name: &str, filename: &str, limit: Option<u64>,
515 dmx_reg: &RegisteredDemuxers, dec_reg: &RegisteredMTDecoders,
516 test: ExpectedTestResult) {
517 let mut dec_threads = THREADS;
518 for (key, value) in std::env::vars_os() {
519 if key == "MT_THREADS" {
520 if let Some(val) = value.to_str() {
521 dec_threads = val.parse::<usize>().unwrap_or(THREADS);
527 let dmx_f = dmx_reg.find_demuxer(demuxer).expect("demuxer is not found");
528 let mut file = File::open(filename).expect("input file should be present");
529 let mut fr = FileReader::new_read(&mut file);
530 let mut br = ByteReader::new(&mut fr);
531 let mut dmx = create_demuxer(dmx_f, &mut br).expect("demuxer can't be created");
533 let mut decs: Vec<Option<(Box<NADecoderSupport>, Box<dyn NADecoderMT>)>> = Vec::new();
534 let mut found = false;
535 for i in 0..dmx.get_num_streams() {
536 let s = dmx.get_stream(i).unwrap();
537 let info = s.get_info();
538 println!("stream {} codec {} / {}", i, info.get_name(), dec_name);
539 if !found && (info.get_name() == dec_name) {
540 let decfunc = dec_reg.find_decoder(info.get_name());
541 if let Some(df) = decfunc {
542 let mut dec = (df)();
543 let mut dsupp = Box::new(NADecoderSupport::new());
544 dec.init(&mut dsupp, info, dec_threads).unwrap();
545 decs.push(Some((dsupp, dec)));
555 let mut md5 = MD5::new();
556 let mut frameiter = if let ExpectedTestResult::MD5Frames(ref vec) = test {
561 let mut reord = MTFrameReorderer::new();
562 let mut last_ts = None;
564 let pktres = dmx.get_frame();
565 if let Err(e) = pktres {
566 if e == DemuxerError::EOF { break; }
569 let pkt = pktres.expect("packet");
570 let streamno = pkt.get_stream().get_id() as usize;
571 if let Some((ref mut dsupp, ref mut dec)) = decs[streamno] {
572 if limit.is_some() && pkt.get_pts().is_some() && pkt.get_pts().unwrap() > limit.unwrap() {
575 let queue_id = reord.register_frame();
576 match dec.queue_pkt(dsupp, &pkt, queue_id) {
579 while !dec.can_take_input() || dec.has_output() {
580 match dec.get_frame() {
582 reord.add_frame(frm, id);
583 while let Some(nfrm) = reord.get_frame() {
584 if check_frame(nfrm, &test, &mut md5, &mut frameiter, &mut last_ts) {
590 reord.drop_frame(id);
591 panic!("frame {} decoding error {:?}", id, err);
595 match dec.queue_pkt(dsupp, &pkt, queue_id) {
597 Ok(false) => panic!("still can't queue frame!"),
598 Err(err) => panic!("queueing error {:?}", err),
601 Err(err) => panic!("queueing error {:?}", err),
606 'tail_loop: for (_, ref mut dec) in decs.iter_mut().flatten() {
608 match dec.get_frame() {
610 reord.add_frame(frm, id);
611 while let Some(nfrm) = reord.get_frame() {
612 if check_frame(nfrm, &test, &mut md5, &mut frameiter, &mut last_ts) {
617 (Err(DecoderError::NoFrame), _) => break,
618 (Err(err), id) => panic!("frame {} decoding error {:?}", id, err),
621 while let Some(nfrm) = reord.get_last_frames() {
622 if check_frame(nfrm, &test, &mut md5, &mut frameiter, &mut last_ts) {
627 if let ExpectedTestResult::MD5(ref ref_hash) = test {
629 let mut hash = [0u32; 4];
630 md5.get_hash(&mut hash);
631 println!("full hash {}", md5);
632 assert_eq!(&hash, ref_hash);
634 if let ExpectedTestResult::GenerateMD5Frames = test {
635 panic!("generated hashes");
639 /// Tests decoding of provided file by outputting video frames as PNM (PPM for RGB video, PGM for YUV).
641 /// This function expects the following arguments:
642 /// * `demuxer` - container format name (used to find proper demuxer for it)
643 /// * `name` - input file name
644 /// * `video_pfx` - prefix for video frames written as pictures (output picture names should look like `<crate_name>/assets/test_out/PFXout00_000000.ppm`
645 /// * `limit` - optional PTS value after which decoding is stopped
646 /// * `dmx_reg` and `dec_reg` - registered demuxers and decoders that should contain demuxer and decoder(s) needed to decode the provided file.
648 /// Since the function is intended for tests, it will panic instead of returning an error.
649 pub fn test_decode_images(demuxer: &str, name: &str, video_pfx: &str, limit: Option<u64>,
650 dmx_reg: &RegisteredDemuxers, dec_reg: &RegisteredDecoders) {
651 let dmx_f = dmx_reg.find_demuxer(demuxer).unwrap();
652 let mut file = File::open(name).unwrap();
653 let mut fr = FileReader::new_read(&mut file);
654 let mut br = ByteReader::new(&mut fr);
655 let mut dmx = create_demuxer(dmx_f, &mut br).unwrap();
657 let mut decs: Vec<Option<(Box<NADecoderSupport>, Box<dyn NADecoder>)>> = Vec::new();
658 for i in 0..dmx.get_num_streams() {
659 let s = dmx.get_stream(i).unwrap();
660 let info = s.get_info();
661 let decfunc = dec_reg.find_decoder(info.get_name());
662 if let Some(df) = decfunc {
664 let mut dec = (df)();
665 let mut dsupp = Box::new(NADecoderSupport::new());
666 dec.init(&mut dsupp, info).unwrap();
667 decs.push(Some((dsupp, dec)));
678 let pktres = dmx.get_frame();
679 if let Err(e) = pktres {
680 if e == DemuxerError::EOF { break; }
683 let pkt = pktres.unwrap();
684 let streamno = pkt.get_stream().get_id() as usize;
685 if streamno >= decs.len() { continue; }
686 if let Some((ref mut dsupp, ref mut dec)) = decs[streamno] {
687 if let (Some(lim), Some(ppts)) = (limit, pkt.get_pts()) {
688 if ppts > lim { break; }
690 let frm = dec.decode(dsupp, &pkt).unwrap();
691 if frm.get_frame_type() != FrameType::Skip {
692 let pts = if let Some(fpts) = frm.get_pts() { fpts } else { pkt.get_pts().unwrap() };
693 let pfx = OUTPUT_PREFIX.to_owned() + video_pfx + "out";
694 write_pnm(pfx.as_str(), streamno, pts, frm).unwrap();