]> git.nihav.org Git - nihav-encoder.git/blame_incremental - src/main.rs
use u32::MAX instead of deprecated std::u32::MAX
[nihav-encoder.git] / src / main.rs
... / ...
CommitLineData
1extern crate nihav_core;
2extern crate nihav_codec_support;
3extern crate nihav_registry;
4extern crate nihav_allstuff;
5
6use std::fs::File;
7use std::io::Write;
8use nihav_core::frame::*;
9use nihav_core::options::*;
10use nihav_core::codecs::*;
11use nihav_core::demuxers::*;
12use nihav_core::muxers::*;
13use nihav_core::reorder::*;
14use nihav_registry::detect;
15use nihav_registry::register;
16use std::env;
17use std::time::{Duration, Instant};
18
19macro_rules! parse_and_apply_options {
20 ($obj: expr, $in_opts: expr, $name: expr) => {
21 let mut opts = Vec::with_capacity($in_opts.len());
22 let opt_def = $obj.get_supported_options();
23 for opt in $in_opts.iter() {
24 let mut found = false;
25 for opt_def in opt_def.iter() {
26 let mut matches = opt.name == opt_def.name;
27 if !matches && opt.name.starts_with("no") {
28 let (_, name) = opt.name.split_at(2);
29 matches = name == opt_def.name;
30 }
31 if matches {
32 let arg = if let Some(ref strval) = opt.value { Some(strval) } else { None };
33 let ret = opt_def.parse(&opt.name, arg);
34 if let Ok((val, _)) = ret {
35 opts.push(val);
36 } else {
37 println!("invalid option {} for {}", opt.name, $name);
38 }
39 found = true;
40 }
41 }
42 if !found {
43 println!(" ignoring option '{}' for {}", opt.name, $name);
44 }
45 }
46 $obj.set_options(opts.as_slice());
47 }
48}
49
50mod demux;
51use crate::demux::FullRegister;
52mod null;
53mod acvt;
54mod imgseq;
55mod transcoder;
56use crate::transcoder::*;
57
58
59fn format_time(ms: u64) -> String {
60 let s = ms / 1000;
61 let ds = (ms % 1000) / 100;
62 let (min, s) = (s / 60, s % 60);
63 let (h, min) = (min / 60, min % 60);
64 if h == 0 {
65 if min == 0 {
66 format!("{}.{}", s, ds)
67 } else {
68 format!("{}:{:02}.{}", min, s, ds)
69 }
70 } else {
71 format!("{}:{:02}:{:02}.{}", h, min, s, ds)
72 }
73}
74
75fn print_options(name: &str, options: &[NAOptionDefinition]) {
76 if options.is_empty() {
77 println!("No custom options.");
78 } else {
79 println!("Options for '{}'", name);
80 for opt in options.iter() {
81 println!(" {}", opt);
82 }
83 }
84}
85
86macro_rules! next_arg {
87 ($args: expr, $arg_idx: expr) => {
88 if $arg_idx + 1 >= $args.len() {
89 println!("codec name is required");
90 }
91 $arg_idx += 1;
92 }
93}
94
95macro_rules! parse_id {
96 ($val: expr, $stype: expr, $maxval: expr) => {
97 if $val.is_empty() {
98 0
99 } else if let Ok(val) = $val.parse::<usize>() {
100 if val < $maxval {
101 val
102 } else {
103 println!("{} number should be below {}", $stype, $maxval);
104 return;
105 }
106 } else {
107 println!("invalid {} number '{}'", $stype, $val);
108 return;
109 }
110 }
111}
112
113fn retrieve_packets(transcoder: &mut Transcoder, mux: &mut Muxer, vdata_size: &mut usize, adata_size: &mut usize, end: bool) -> bool {
114 while let Some(pkt) = transcoder.queue.get_packet() {
115 if transcoder.end != NATimePoint::None && !pkt.ts.less_than(transcoder.end) {
116 return false;
117 }
118 let pkt_size = pkt.get_buffer().len();
119 match pkt.get_stream().get_media_type() {
120 StreamType::Video => { *vdata_size += pkt_size; },
121 StreamType::Audio => { *adata_size += pkt_size; },
122 _ => {},
123 };
124 if mux.mux_frame(pkt).is_err() {
125 println!("error muxing packet");
126 return false;
127 }
128 }
129 if end {
130 while let Some(pkt) = transcoder.queue.get_last_packet() {
131 if transcoder.end != NATimePoint::None && !pkt.ts.less_than(transcoder.end) {
132 return false;
133 }
134 let pkt_size = pkt.get_buffer().len();
135 match pkt.get_stream().get_media_type() {
136 StreamType::Video => { *vdata_size += pkt_size; },
137 StreamType::Audio => { *adata_size += pkt_size; },
138 _ => {},
139 };
140 if mux.mux_frame(pkt).is_err() {
141 println!("error muxing packet");
142 return false;
143 }
144 }
145 }
146 true
147}
148
149#[allow(clippy::single_match)]
150fn main() {
151 let args: Vec<_> = env::args().collect();
152
153 if args.len() == 1 {
154 println!("usage: nihav-encoder [options] --input inputfile --output outputfile");
155 println!(" use nihav-encoder --help to list all available options");
156 return;
157 }
158 if args.len() == 2 && (args[1] == "--help" || args[1] == "-h") {
159 println!("usage: nihav-encoder [options] --input inputfile --output outputfile");
160 println!(" query options:");
161 println!(" --list-{{decoders,encoders,demuxers,muxers}} - lists all available decoders/encoders/demuxers/muxers");
162 println!(" --query-{{decoder,encoder,demuxer,muxer}}-options name - lists all options recognized by that decoder/encoder/demuxer/muxer");
163 println!(" processing options:");
164 println!(" --verbose - show time for the currently processed input");
165 println!(" --input inputfile - set input file");
166 println!(" --input-format fmt - force input format");
167 println!(" --demuxer-options options - set input demuxer options");
168 println!(" --scale-options options - set scaler options");
169 println!(" --output outputfile - set output file");
170 println!(" --output-format fmt - force output format");
171 println!(" --muxer-options options - set output muxer options");
172 println!(" --no-audio - do not decode audio streams");
173 println!(" --no-video - do not decode video streams");
174 println!(" --start starttime - start decoding from given position");
175 println!(" --end endtime - end decoding at given position");
176 println!(" --istreamX options - set options for input stream X");
177 println!(" --ostreamX options - set options for output stream X");
178 println!();
179 println!(" (de)muxer and stream options are passed as comma-separated list e.g. --ostream0 width=320,height=240,flip");
180 return;
181 }
182
183 let full_reg = FullRegister::new();
184
185 let mut transcoder = Transcoder::new();
186
187 let mut arg_idx = 1;
188 let mut printed_info = false;
189 let mut force_sync = false;
190 let mut profile_name = "".to_string();
191 let mut custom_profile = false;
192 while arg_idx < args.len() {
193 match args[arg_idx].as_str() {
194 "--list-decoders" => {
195 if full_reg.dec_reg.iter().len() > 0 {
196 println!("Registered decoders:");
197 for dec in full_reg.dec_reg.iter() {
198 let cdesc = register::get_codec_description(dec.name);
199 let full_name = if let Some(cd) = cdesc { cd.get_full_name() } else { "???" };
200 println!(" {} ({})", dec.name, full_name);
201 }
202 } else {
203 println!("No registered decoders.");
204 }
205 printed_info = true;
206 },
207 "--list-encoders" => {
208 if full_reg.enc_reg.iter().len() > 0 {
209 println!("Registered encoders:");
210 for enc in full_reg.enc_reg.iter() {
211 let cdesc = register::get_codec_description(enc.name);
212 let full_name = if let Some(cd) = cdesc { cd.get_full_name() } else { "???" };
213 println!(" {} ({})", enc.name, full_name);
214 }
215 } else {
216 println!("No registered encoders.");
217 }
218 printed_info = true;
219 },
220 "--list-demuxers" => {
221 print!("Registered demuxers:");
222 for dmx in full_reg.dmx_reg.iter() {
223 print!(" {}", dmx.get_name());
224 }
225 println!();
226 printed_info = true;
227 },
228 "--list-muxers" => {
229 print!("Registered muxers:");
230 for mux in full_reg.mux_reg.iter() {
231 print!(" {}", mux.get_name());
232 }
233 println!();
234 printed_info = true;
235 },
236 "--query-decoder-options" => {
237 next_arg!(args, arg_idx);
238 let cname = args[arg_idx].as_str();
239 if let Some(decfunc) = full_reg.dec_reg.find_decoder(cname) {
240 let dec = (decfunc)();
241 let opts = dec.get_supported_options();
242 print_options(cname, opts);
243 } else {
244 println!("codec {} is not found", cname);
245 }
246 printed_info = true;
247 },
248 "--query-demuxer-options" => {
249 next_arg!(args, arg_idx);
250 let dname = args[arg_idx].as_str();
251 let mut mr = MemoryReader::new_read(&[]);
252 let mut br = ByteReader::new(&mut mr);
253 if let Some(dmx_creator) = full_reg.dmx_reg.find_demuxer(dname) {
254 let dmx = dmx_creator.new_demuxer(&mut br);
255 let opts = dmx.get_supported_options();
256 print_options(dname, opts);
257 } else {
258 println!("demuxer {} is not found", dname);
259 }
260 printed_info = true;
261 },
262 "--query-encoder-options" => {
263 next_arg!(args, arg_idx);
264 let cname = args[arg_idx].as_str();
265 if let Some(encfunc) = full_reg.enc_reg.find_encoder(cname) {
266 let enc = (encfunc)();
267 let opts = enc.get_supported_options();
268 print_options(cname, opts);
269 } else {
270 println!("codec {} is not found", cname);
271 }
272 printed_info = true;
273 },
274 "--query-muxer-options" => {
275 next_arg!(args, arg_idx);
276 let name = args[arg_idx].as_str();
277 let mut data = [];
278 let mut mw = MemoryWriter::new_write(&mut data);
279 let mut bw = ByteWriter::new(&mut mw);
280 if let Some(mux_creator) = full_reg.mux_reg.find_muxer(name) {
281 let mux = mux_creator.new_muxer(&mut bw);
282 let opts = mux.get_supported_options();
283 print_options(name, opts);
284 } else {
285 println!("muxer {} is not found", name);
286 }
287 printed_info = true;
288 },
289 "--output" | "-o" => {
290 next_arg!(args, arg_idx);
291 transcoder.output_name = args[arg_idx].clone();
292 },
293 "--output-format" => {
294 next_arg!(args, arg_idx);
295 transcoder.output_fmt = Some(args[arg_idx].clone());
296 },
297 "--scale-options" => {
298 next_arg!(args, arg_idx);
299 if !transcoder.parse_scale_options(&args[arg_idx]) {
300 println!("invalid scale option syntax");
301 return;
302 }
303 },
304 "--no-video" | "-vn" => {
305 transcoder.no_video = true;
306 },
307 "--no-audio" | "-an" => {
308 transcoder.no_audio = true;
309 },
310 "--start" => {
311 next_arg!(args, arg_idx);
312 let ret = args[arg_idx].parse::<NATimePoint>();
313 if let Ok(val) = ret {
314 transcoder.start = val;
315 } else {
316 println!("invalid start time");
317 return;
318 }
319 },
320 "--end" => {
321 next_arg!(args, arg_idx);
322 let ret = args[arg_idx].parse::<NATimePoint>();
323 if let Ok(val) = ret {
324 transcoder.end = val;
325 } else {
326 println!("invalid end time");
327 return;
328 }
329 },
330 "--sync" => {
331 force_sync = true;
332 },
333 "--muxer-options" => {
334 next_arg!(args, arg_idx);
335 if !transcoder.parse_muxer_options(&args[arg_idx], &full_reg.mux_reg) {
336 println!("invalid muxer option syntax");
337 return;
338 }
339 },
340 "--calc-len" => {
341 transcoder.calc_len = true;
342 },
343 "--print-profiles" => {
344 println!("Supported profiles:");
345 for (name, profiles) in PROFILES.iter() {
346 print!(" profiles for format '{name}': ");
347 for profile in profiles.iter() {
348 print!(" {}", profile.name);
349 }
350 println!();
351 }
352 printed_info = true;
353 },
354 "--profile" => {
355 next_arg!(args, arg_idx);
356 profile_name = args[arg_idx].to_string();
357 },
358 "--verbose" | "-v" => transcoder.verbose = 1,
359 "-vv" => transcoder.verbose = 2,
360 "-v-" => transcoder.verbose = 0,
361 _ => {
362 if args[arg_idx].starts_with("--istream") {
363 let opt0 = &args[arg_idx];
364 next_arg!(args, arg_idx);
365 if !transcoder.parse_istream_options(opt0, &args[arg_idx]) {
366 println!("invalid input stream option syntax");
367 return;
368 }
369 } else if args[arg_idx].starts_with("--ostream") {
370 let opt0 = &args[arg_idx];
371 next_arg!(args, arg_idx);
372 if !transcoder.parse_ostream_options(opt0, &args[arg_idx], &full_reg.enc_reg) {
373 println!("invalid output stream option syntax");
374 return;
375 }
376 custom_profile = true;
377 } else if args[arg_idx].starts_with("--iformat") {
378 let id = parse_id!(&args[arg_idx][9..], "input format", transcoder.input_fmt.len());
379 next_arg!(args, arg_idx);
380 transcoder.input_fmt[id] = Some(args[arg_idx].clone());
381 } else if args[arg_idx].starts_with("--input-format") {
382 let id = parse_id!(&args[arg_idx][14..], "input format", transcoder.input_fmt.len());
383 next_arg!(args, arg_idx);
384 transcoder.input_fmt[id] = Some(args[arg_idx].clone());
385 } else if args[arg_idx].starts_with("--input") { // should be after --input-format
386 let id = parse_id!(&args[arg_idx][7..], "input", transcoder.input_name.len());
387 next_arg!(args, arg_idx);
388 transcoder.input_name[id] = Some(args[arg_idx].clone());
389 } else if args[arg_idx].starts_with("-i") {
390 let id = parse_id!(&args[arg_idx][2..], "input", transcoder.input_name.len());
391 next_arg!(args, arg_idx);
392 transcoder.input_name[id] = Some(args[arg_idx].clone());
393 } else if args[arg_idx].starts_with("--demuxer-options") {
394 let id = parse_id!(&args[arg_idx][17..], "input options", transcoder.demux_opts.len());
395 next_arg!(args, arg_idx);
396 if !transcoder.parse_demuxer_options(&args[arg_idx], &full_reg.dmx_reg, id) {
397 println!("invalid demuxer option syntax");
398 return;
399 }
400 } else if args[arg_idx].starts_with("--") {
401 println!("unknown option '{}'", args[arg_idx]);
402 } else {
403 println!("unrecognized argument '{}'", args[arg_idx]);
404 }
405 },
406 };
407 arg_idx += 1;
408 }
409
410 if printed_info {
411 return;
412 }
413
414 if transcoder.input_name.iter().flatten().count() == 0 {
415 println!("no input name(s) provided");
416 return;
417 }
418 if transcoder.output_name.is_empty() {
419 println!("no output name provided");
420 return;
421 }
422
423 let mut demuxers = Vec::with_capacity(1);
424 if !transcoder.create_demuxers(&mut demuxers, &full_reg, true) {
425 return;
426 }
427
428 let duration = demuxers.iter().fold(0u64, |mindur, (dmx, _)| {
429 let dur = dmx.get_duration();
430 if mindur == 0 {
431 dur
432 } else if dur > 0 {
433 mindur.min(dur)
434 } else {
435 mindur
436 }
437 });
438 let duration_string = if duration != 0 { format_time(duration) } else { String::new() };
439
440 let mut ism = StreamManager::new();
441 let mut is_offset = Vec::with_capacity(demuxers.len());
442 let mut start = 0;
443 let mut nstreams = 0;
444 for (dmx, _) in demuxers.iter() {
445 is_offset.push(nstreams);
446 let sm = dmx.get_stream_manager();
447 let max_id = sm.iter().fold(0u32, |id, strm| id.max(strm.id));
448 for stream in sm.iter() {
449 let mut newstream = (*stream).clone();
450 if transcoder.global_tb == (0, 0) && newstream.get_media_type() == StreamType::Video {
451 transcoder.global_tb = newstream.get_timebase();
452 }
453 newstream.id += start;
454 ism.add_stream(newstream);
455 }
456 start += max_id + 1;
457 nstreams += sm.get_num_streams();
458 }
459
460 for (&is_off, (dmx, _)) in is_offset.iter().zip(demuxers.iter_mut()) {
461 for i in 0..dmx.get_num_streams() {
462 let s = dmx.get_stream(i).unwrap();
463 let info = s.get_info();
464 let decfunc = full_reg.dec_reg.find_decoder(info.get_name());
465 let str_id = (s.get_num() + is_off) as u32;
466 if let Some(create_dec) = decfunc {
467 let mut decoder = (create_dec)();
468 let mut dsupp = Box::new(NADecoderSupport::new());
469 let ret = decoder.init(&mut dsupp, info.clone());
470 if ret.is_err() {
471 println!("Error initialising decoder '{}' for stream {}", info.get_name(), str_id);
472 return;
473 }
474 transcoder.apply_decoder_options(decoder.as_mut(), str_id);
475 let desc = register::get_codec_description(info.get_name());
476 let has_b = if let Some(desc) = desc {
477 desc.has_reorder()
478 } else {
479 println!("No codec description found, using B-frame reorderer.");
480 true
481 };
482 let reorderer: Box<dyn FrameReorderer> = if has_b { Box::new(IPBReorderer::new()) } else { Box::new(NoReorderer::new()) };
483 transcoder.decoders.push(Some(DecodeContext{ dsupp, decoder, reorderer }));
484 } else {
485 println!("No decoder for stream {} ({}) is found", str_id, info.get_name());
486 transcoder.decoders.push(None);
487 }
488 }
489 if transcoder.start != NATimePoint::None {
490 let ret = dmx.seek(transcoder.start);
491 if ret.is_err() {
492 println!(" failed to seek to {} error {:?}", transcoder.start, ret.err().unwrap());
493 }
494 }
495 }
496
497 let output_fmt = if let Some(ref fmtname) = transcoder.output_fmt {
498 fmtname
499 } else if transcoder.output_name.as_str() == "/dev/null" {
500 "null"
501 } else if let Some(fmtname) = detect::detect_format_by_name(transcoder.output_name.as_str()) {
502 fmtname
503 } else {
504 println!("Cannot guess muxer for output");
505 return;
506 };
507 let ret = full_reg.mux_reg.find_muxer(output_fmt);
508 let ofmt = output_fmt.to_string();
509
510 if ret.is_none() {
511 println!("cannot find muxer '{}'", output_fmt);
512 return;
513 }
514 let mux_creator = ret.unwrap();
515
516 if custom_profile && !profile_name.is_empty() {
517 println!("profile setting is incompatible with custom --ostream options");
518 return;
519 }
520 if !profile_name.is_empty() {
521 if let Some(profiles) = PROFILES.iter().find(|(fmt, _)| fmt == &output_fmt) {
522 if let Some(ref_profile) = profiles.1.iter().find(|p| p.name == profile_name) {
523 transcoder.profile = Some(ref_profile.profile);
524 } else {
525 println!("profile '{profile_name}' is not defined for output format '{output_fmt}'");
526 }
527 } else {
528 println!("no profiles for output format '{output_fmt}'");
529 }
530 }
531
532 let mux_quirks = mux_creator.get_quirks();
533 if mux_quirks.is_fixed_duration() {
534 transcoder.calc_len = true;
535 }
536 transcoder.fixed_rate = mux_quirks.is_fixed_rate();
537 transcoder.queue.set_sync(force_sync || !mux_quirks.is_unsync());
538
539 if transcoder.calc_len {
540 let mut sids = Vec::new();
541 transcoder.nframes.clear();
542 for (dmx, _) in demuxers.iter_mut() {
543 let sstart = transcoder.nframes.len();
544 let sm = dmx.get_stream_manager();
545 sids.clear();
546 for stream in sm.iter() {
547 transcoder.nframes.push(0);
548 sids.push(stream.get_id());
549 }
550
551 while let Ok(pkt) = dmx.get_frame() {
552 let stream = pkt.get_stream();
553 let pos = sstart + sids.iter().position(|&x| x == stream.get_id()).unwrap();
554 transcoder.nframes[pos] += 1;
555 }
556 }
557 // this is necessary since not all demuxers allow to seek even back to the start
558 demuxers.clear();
559 if !transcoder.create_demuxers(&mut demuxers, &full_reg, false) {
560 println!("failed to re-create demuxer(s)");
561 return;
562 }
563 }
564
565 let mux_caps = mux_creator.get_capabilities();
566 let mut out_sm = StreamManager::new();
567 if !transcoder.negotiate_stream_map(&ism, mux_caps, &mut out_sm, &full_reg.enc_reg) {
568 println!("cannot determine stream map");
569 return;
570 }
571
572 let ret = File::create(transcoder.output_name.as_str());
573 if ret.is_err() {
574 println!("cannot open output file");
575 return;
576 }
577 let mut fw = FileWriter::new_write(ret.unwrap());
578 let mut bw = ByteWriter::new(&mut fw);
579 let ret = create_muxer(mux_creator, out_sm, &mut bw);
580 if let Err(err) = ret {
581 println!("cannot create muxer instance {:?}", err);
582 return;
583 }
584 let mut mux = ret.unwrap();
585 parse_and_apply_options!(mux, &transcoder.mux_opts, "output");
586
587 println!("Output {} muxer {}", transcoder.output_name, ofmt);
588 for ostr in mux.get_streams() {
589 let mut is_copy = false;
590 let stream_id = ostr.get_num() as u32;
591 for omode in transcoder.encoders.iter() {
592 if let OutputMode::Copy(sno) = omode {
593 if sno == &stream_id {
594 is_copy = true;
595 break;
596 }
597 }
598 }
599 println!(" #{}: {} {}{}", ostr.get_num(), ostr, ostr.get_info().get_name(), if is_copy { " (copy)" } else { "" });
600 }
601
602 transcoder.queue.reserve_streams(mux.get_num_streams());
603
604 let mut time = Instant::now();
605 let show_interval = Duration::from_millis(100);
606 let mut adata_size = 0;
607 let mut vdata_size = 0;
608 let mut cur_dmx = 0;
609 let mut last_known_time = None;
610 'main_loop: loop {
611 let mut pktres = Err(DemuxerError::EOF);
612 let mut src_dmx = 0;
613 loop {
614 if !demuxers.iter().any(|(_, eof)| !eof) {
615 break;
616 }
617 let mut got_res = false;
618 if !demuxers[cur_dmx].1 {
619 pktres = demuxers[cur_dmx].0.get_frame();
620 got_res = true;
621 src_dmx = cur_dmx;
622 }
623 cur_dmx += 1;
624 if cur_dmx >= demuxers.len() {
625 cur_dmx = 0;
626 }
627 if got_res {
628 break;
629 }
630 }
631
632 if let Err(DemuxerError::EOF) = pktres { break; }
633 if pktres.is_err() {
634 println!("demuxing error");
635 break;
636 }
637 let mut pkt = pktres.unwrap();
638 if transcoder.start != NATimePoint::None && pkt.ts.less_than(transcoder.start) { continue; }
639 let src_id = pkt.get_stream().get_num() + is_offset[src_dmx];
640 let ts = pkt.ts;
641 let newstream = ism.get_stream(src_id).unwrap();
642 pkt.reassign(newstream, ts);
643
644 if transcoder.verbose > 0 && time.elapsed() >= show_interval {
645 if let Some(pts) = pkt.get_pts() {
646 let cur_time = format_time(NATimeInfo::ts_to_time(pts, 1000, pkt.ts.tb_num, pkt.ts.tb_den));
647 print!(" {}", cur_time);
648 last_known_time = Some(cur_time);
649 } else if let Some(ref time) = last_known_time {
650 print!(" {time}");
651 } else {
652 print!(" ???");
653 }
654 if !duration_string.is_empty() {
655 print!(" / {}", duration_string);
656 }
657 if transcoder.verbose > 1 {
658 print!(" data sizes V: {} A: {}", vdata_size, adata_size);
659 }
660 print!("\r");
661 std::io::stdout().flush().unwrap();
662 time = Instant::now();
663 }
664 match transcoder.encoders[src_id] {
665 OutputMode::Drop => {},
666 OutputMode::Copy(dst_id) => {
667 let dstr = mux.get_stream(dst_id as usize).unwrap();
668 pkt.reassign(dstr, pkt.get_time_information());
669 if transcoder.end != NATimePoint::None && !pkt.ts.less_than(transcoder.end) { break 'main_loop; }
670 let pkt_size = pkt.get_buffer().len();
671 match pkt.get_stream().get_media_type() {
672 StreamType::Video => { vdata_size += pkt_size; },
673 StreamType::Audio => { adata_size += pkt_size; },
674 _ => {},
675 };
676 transcoder.queue.queue_packet(pkt);
677 },
678 OutputMode::Encode(dst_id, ref mut encoder) => {
679 if let Some(ref mut dec_ctx) = transcoder.decoders[src_id] {
680 let ret = dec_ctx.decoder.decode(&mut dec_ctx.dsupp, &pkt);
681 if let (true, Err(DecoderError::MissingReference)) = (transcoder.start != NATimePoint::None, &ret) {
682 continue;
683 }
684 if ret.is_err() {
685 println!("error decoding stream {}", src_id);
686 break;
687 }
688 let frm = ret.unwrap();
689 dec_ctx.reorderer.add_frame(frm);
690 while let Some(frm) = dec_ctx.reorderer.get_frame() {
691 match encoder.encode_frame(dst_id, frm, &transcoder.scale_opts, &mut transcoder.queue) {
692 Ok(true) => {},
693 Ok(false) => break,
694 Err(err) => {
695 println!("encoder error {err:?}");
696 break 'main_loop;
697 }
698 }
699 }
700 } else {
701 println!("no decoder for stream {}", src_id);
702 break;
703 }
704 },
705 };
706
707 if !retrieve_packets(&mut transcoder, &mut mux, &mut vdata_size, &mut adata_size, false) {
708 break;
709 }
710 }
711 'reord_flush_loop: for stream in ism.iter() {
712 let src_id = stream.get_num();
713 if let OutputMode::Encode(dst_id, ref mut encoder) = transcoder.encoders[src_id] {
714 if let Some(ref mut dec_ctx) = transcoder.decoders[src_id] {
715 while let Some(frm) = dec_ctx.reorderer.get_last_frames() {
716 match encoder.encode_frame(dst_id, frm, &transcoder.scale_opts, &mut transcoder.queue) {
717 Ok(true) => {},
718 Ok(false) => break,
719 Err(err) => {
720 println!("encoder error {err:?}");
721 break 'reord_flush_loop;
722 }
723 }
724 }
725 }
726 }
727 }
728 /*'flush_loop:*/ for enc in transcoder.encoders.iter_mut() {
729 match enc {
730 OutputMode::Encode(str_id, ref mut encoder) => {
731 let ret = encoder.flush(&mut transcoder.queue);
732 if ret.is_err() {
733 println!("error flushing encoder for stream {}", str_id);
734 break;
735 }
736 },
737 _ => {},
738 };
739 }
740
741 retrieve_packets(&mut transcoder, &mut mux, &mut vdata_size, &mut adata_size, true);
742
743 if transcoder.verbose > 0 {
744 println!();
745 }
746
747 let ret = mux.end();
748 if ret.is_err() {
749 println!("error at finalising muxing");
750 }
751}
752
753struct ProfileDef {
754 name: &'static str,
755 profile: EncodingProfile,
756}
757
758const PROFILES: &[(&str, &[ProfileDef])] = &[
759 ("avi",
760 &[
761 ProfileDef {
762 name: "cinepak",
763 profile: EncodingProfile {
764 vname: "cinepak",
765 voptions: &[],
766 aname: "pcm",
767 aoptions: &[],
768 }
769 },
770 ProfileDef {
771 name: "lossless",
772 profile: EncodingProfile {
773 vname: "zmbv",
774 voptions: &[("range", Some("4")), ("compr_level", Some("fast"))],
775 aname: "pcm",
776 aoptions: &[],
777 }
778 },
779 ProfileDef {
780 name: "ms-lossy",
781 profile: EncodingProfile {
782 vname: "msvideo1",
783 voptions: &[],
784 aname: "ms-adpcm",
785 aoptions: &[],
786 }
787 },
788 ProfileDef {
789 name: "raw",
790 profile: EncodingProfile {
791 vname: "rawvideo-ms",
792 voptions: &[],
793 aname: "pcm",
794 aoptions: &[],
795 }
796 },
797 ]),
798];