armovie: zero-terminated string is not exactly an error
[nihav.git] / nihav-codec-support / src / test / dec_video.rs
1 //! Routines for testing decoders.
2 use std::fs::File;
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;
10 use super::md5::MD5;
11 use crate::imgwrite::write_pnm;
12 pub use super::ExpectedTestResult;
13
14 const OUTPUT_PREFIX: &str = "assets/test_out/";
15
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)
22 }*/
23
24 /// Tests decoding of provided file and optionally outputs video frames as PNM (PPM for RGB video, PGM for YUV).
25 ///
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.
33 ///
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();
44
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()) {
52 let mut dec = (df)();
53 let mut dsupp = Box::new(NADecoderSupport::new());
54 dec.init(&mut dsupp, info).unwrap();
55 decs.push(Some((dsupp, dec)));
56 } else {
57 decs.push(None);
58 }
59 } else {
60 decs.push(None);
61 }
62 }
63
64 loop {
65 let pktres = dmx.get_frame();
66 if let Err(e) = pktres {
67 if e == DemuxerError::EOF { break; }
68 panic!("error");
69 }
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; }
75 }
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();
81 }
82 }
83 }
84 }
85
86 /// Tests audio decoder with the content in the provided file and optionally outputs decoded audio.
87 ///
88 /// The syntax is very similar to [`test_file_decoding`] except that it is intended for testing audio codecs.
89 ///
90 /// Since the function is intended for tests, it will panic instead of returning an error.
91 ///
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();
100
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 {
107 if info.is_audio() {
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)));
112 } else {
113 decs.push(None);
114 }
115 } else {
116 decs.push(None);
117 }
118 }
119
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;
127
128 loop {
129 let pktres = dmx.get_frame();
130 if let Err(e) = pktres {
131 if e == DemuxerError::EOF { break; }
132 panic!("error");
133 }
134 let pkt = pktres.unwrap();
135 if limit.is_some() && pkt.get_pts().is_some() && pkt.get_pts().unwrap() > limit.unwrap() {
136 break;
137 }
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() {
142 if !wrote_header {
143 wwr.write_header(frm.get_info().as_ref().get_properties().get_audio_info().unwrap()).unwrap();
144 wrote_header = true;
145 }
146 wwr.write_frame(frm.get_buffer()).unwrap();
147 }
148 }
149 }
150 } else {
151 loop {
152 let pktres = dmx.get_frame();
153 if let Err(e) = pktres {
154 if e == DemuxerError::EOF { break; }
155 panic!("error");
156 }
157 let pkt = pktres.unwrap();
158 if limit.is_some() && pkt.get_pts().is_some() && pkt.get_pts().unwrap() > limit.unwrap() {
159 break;
160 }
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();
164 }
165 }
166 }
167 }
168
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());
173 },
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);
181 }
182 },
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);
192 }
193 },
194 NABufferType::VideoPacked(ref vb) => {
195 md5.update_hash(vb.get_data());
196 },
197 NABufferType::AudioU8(ref ab) => {
198 md5.update_hash(ab.get_data());
199 },
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);
207 }
208 },
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);
218 }
219 },
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);
230 }
231 },
232 NABufferType::AudioPacked(ref ab) => {
233 md5.update_hash(ab.get_data());
234 },
235 NABufferType::Data(ref db) => {
236 md5.update_hash(db.as_ref());
237 },
238 NABufferType::None => {},
239 };
240 }
241
242 /// Tests decoder for requested codec in provided file.
243 ///
244 /// This functions tries to decode a stream corresponding to `dec_name` codec in input file and validate the results against expected ones.
245 ///
246 /// Since the function is intended for tests, it will panic instead of returning an error.
247 ///
248 /// # Examples
249 ///
250 /// Test RealVideo 4 decoder in test stream:
251 /// ```no_run
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;
256 ///
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]));
261 /// ```
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();
270
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)));
284 found = true;
285 } else {
286 decs.push(None);
287 }
288 } else {
289 decs.push(None);
290 }
291 }
292
293 let mut md5 = MD5::new();
294 let mut frameiter = if let ExpectedTestResult::MD5Frames(ref vec) = test {
295 Some(vec.iter())
296 } else {
297 None
298 };
299 loop {
300 let pktres = dmx.get_frame();
301 if let Err(e) = pktres {
302 if e == DemuxerError::EOF { break; }
303 panic!("error");
304 }
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() {
309 break;
310 }
311 let frm = dec.decode(dsupp, &pkt).unwrap();
312 match &test {
313 ExpectedTestResult::Decodes => {},
314 ExpectedTestResult::MD5(_) => { frame_checksum(&mut md5, frm); },
315 ExpectedTestResult::MD5Frames(_) => {
316 md5 = MD5::new();
317 frame_checksum(&mut md5, frm);
318 md5.finish();
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);
327 }
328 },
329 ExpectedTestResult::GenerateMD5Frames => {
330 md5 = MD5::new();
331 frame_checksum(&mut md5, frm);
332 md5.finish();
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]);
336 },
337 };
338 }
339 }
340 if let ExpectedTestResult::MD5(ref ref_hash) = test {
341 md5.finish();
342 let mut hash = [0u32; 4];
343 md5.get_hash(&mut hash);
344 println!("full hash {}", md5);
345 assert_eq!(&hash, ref_hash);
346 }
347 if let ExpectedTestResult::GenerateMD5Frames = test {
348 panic!("generated hashes");
349 }
350 }
351
352 /// Tests decoder for requested codec in provided file with raw streams.
353 ///
354 /// This functions tries to decode a stream corresponding to `dec_name` codec in input file and validate the results against expected ones.
355 ///
356 /// Since the function is intended for tests, it will panic instead of returning an error.
357 ///
358 /// # Examples
359 ///
360 /// Test FLAC decoder in test stream:
361 /// ```no_run
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;
366 ///
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]));
372 /// ```
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();
381
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)));
398 found = true;
399 } else {
400 decs.push(None);
401 }
402 } else {
403 decs.push(None);
404 }
405 }
406
407 let mut md5 = MD5::new();
408 let mut frameiter = if let ExpectedTestResult::MD5Frames(ref vec) = test {
409 Some(vec.iter())
410 } else {
411 None
412 };
413 loop {
414 let datares = dmx.get_data();
415 if let Err(e) = datares {
416 if e == DemuxerError::EOF { break; }
417 panic!("error");
418 }
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() {
425 break;
426 }
427 let frm = dec.decode(dsupp, &pkt).unwrap();
428 match &test {
429 ExpectedTestResult::Decodes => {},
430 ExpectedTestResult::MD5(_) => { frame_checksum(&mut md5, frm); },
431 ExpectedTestResult::MD5Frames(_) => {
432 md5 = MD5::new();
433 frame_checksum(&mut md5, frm);
434 md5.finish();
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);
443 }
444 },
445 ExpectedTestResult::GenerateMD5Frames => {
446 md5 = MD5::new();
447 frame_checksum(&mut md5, frm);
448 md5.finish();
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]);
452 },
453 };
454 }
455 }
456 }
457 if let ExpectedTestResult::MD5(ref ref_hash) = test {
458 md5.finish();
459 let mut hash = [0u32; 4];
460 md5.get_hash(&mut hash);
461 println!("full hash {}", md5);
462 assert_eq!(&hash, ref_hash);
463 }
464 if let ExpectedTestResult::GenerateMD5Frames = test {
465 panic!("generated hashes");
466 }
467 }
468
469 const THREADS: usize = 3;
470
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) {
475 assert!(lts < cts);
476 }
477 *last_ts = frm_dts;
478 match test {
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);
484 loc_md5.finish();
485 if let Some(ref mut iter) = frameiter {
486 let ret = iter.next();
487 if ret.is_none() {
488 return true;
489 }
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);
495 }
496 },
497 ExpectedTestResult::GenerateMD5Frames => {
498 let mut loc_md5 = MD5::new();
499 frame_checksum(&mut loc_md5, frm);
500 loc_md5.finish();
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]);
504 },
505 };
506 false
507 }
508
509 /// Tests multi-threaded decoder for requested codec in provided file.
510 ///
511 /// The syntax is very similar to [`test_file_decoding`] except that it tests multi-threaded decoders instead.
512 ///
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);
522 break;
523 }
524 }
525 }
526
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");
532
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)));
546 found = true;
547 } else {
548 decs.push(None);
549 }
550 } else {
551 decs.push(None);
552 }
553 }
554
555 let mut md5 = MD5::new();
556 let mut frameiter = if let ExpectedTestResult::MD5Frames(ref vec) = test {
557 Some(vec.iter())
558 } else {
559 None
560 };
561 let mut reord = MTFrameReorderer::new();
562 let mut last_ts = None;
563 'dec_loop: loop {
564 let pktres = dmx.get_frame();
565 if let Err(e) = pktres {
566 if e == DemuxerError::EOF { break; }
567 panic!("error");
568 }
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() {
573 break;
574 }
575 let queue_id = reord.register_frame();
576 match dec.queue_pkt(dsupp, &pkt, queue_id) {
577 Ok(true) => {},
578 Ok(false) => {
579 while !dec.can_take_input() || dec.has_output() {
580 match dec.get_frame() {
581 (Ok(frm), id) => {
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) {
585 break 'dec_loop;
586 }
587 }
588 },
589 (Err(err), id) => {
590 reord.drop_frame(id);
591 panic!("frame {} decoding error {:?}", id, err);
592 },
593 };
594 }
595 match dec.queue_pkt(dsupp, &pkt, queue_id) {
596 Ok(true) => {},
597 Ok(false) => panic!("still can't queue frame!"),
598 Err(err) => panic!("queueing error {:?}", err),
599 };
600 },
601 Err(err) => panic!("queueing error {:?}", err),
602 };
603
604 }
605 }
606 'tail_loop: for (_, ref mut dec) in decs.iter_mut().flatten() {
607 loop {
608 match dec.get_frame() {
609 (Ok(frm), id) => {
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) {
613 break 'tail_loop;
614 }
615 }
616 },
617 (Err(DecoderError::NoFrame), _) => break,
618 (Err(err), id) => panic!("frame {} decoding error {:?}", id, err),
619 };
620 }
621 while let Some(nfrm) = reord.get_last_frames() {
622 if check_frame(nfrm, &test, &mut md5, &mut frameiter, &mut last_ts) {
623 break;
624 }
625 }
626 }
627 if let ExpectedTestResult::MD5(ref ref_hash) = test {
628 md5.finish();
629 let mut hash = [0u32; 4];
630 md5.get_hash(&mut hash);
631 println!("full hash {}", md5);
632 assert_eq!(&hash, ref_hash);
633 }
634 if let ExpectedTestResult::GenerateMD5Frames = test {
635 panic!("generated hashes");
636 }
637 }
638
639 /// Tests decoding of provided file by outputting video frames as PNM (PPM for RGB video, PGM for YUV).
640 ///
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.
647 ///
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();
656
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 {
663 if info.is_video() {
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)));
668 break;
669 } else {
670 decs.push(None);
671 }
672 } else {
673 decs.push(None);
674 }
675 }
676
677 loop {
678 let pktres = dmx.get_frame();
679 if let Err(e) = pktres {
680 if e == DemuxerError::EOF { break; }
681 panic!("error");
682 }
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; }
689 }
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();
695 }
696 }
697 }
698 }