]>
Commit | Line | Data |
---|---|---|
6dc69f51 KS |
1 | extern crate nihav_core; |
2 | extern crate nihav_codec_support; | |
3 | extern crate nihav_registry; | |
4 | extern crate nihav_allstuff; | |
5 | ||
6 | use std::fs::File; | |
5ec8115f | 7 | use std::io::{BufReader, Write}; |
4a835a2a | 8 | use std::pin::Pin; |
6dc69f51 KS |
9 | use nihav_core::io::byteio::{FileReader, ByteReader}; |
10 | use nihav_core::frame::*; | |
11 | use nihav_core::options::*; | |
12 | use nihav_core::codecs::*; | |
13 | use nihav_core::demuxers::*; | |
14 | use nihav_core::muxers::*; | |
d9fe2b71 | 15 | use nihav_core::reorder::*; |
6dc69f51 | 16 | use nihav_core::scale::*; |
6dc69f51 | 17 | use nihav_registry::detect; |
e6cb09af | 18 | use nihav_registry::register; |
6dc69f51 | 19 | use std::env; |
5ec8115f | 20 | use std::time::{Duration, Instant}; |
6dc69f51 | 21 | |
91a15e39 KS |
22 | mod demux; |
23 | use crate::demux::*; | |
93521506 | 24 | mod null; |
b0481c9e KS |
25 | mod acvt; |
26 | use crate::acvt::*; | |
90683bc3 KS |
27 | mod imgseq; |
28 | use crate::imgseq::*; | |
93521506 | 29 | |
4a835a2a KS |
30 | #[derive(Clone,Copy,Default,PartialEq)] |
31 | enum RegisterResult { | |
32 | #[default] | |
33 | Ok, | |
34 | Ignored, | |
35 | Failed, | |
36 | } | |
37 | ||
38 | pub struct SelfBorrow<T, U> { | |
39 | bval: T, | |
40 | dst: Option<U>, | |
41 | } | |
42 | ||
43 | impl<T: Unpin, U: Unpin> SelfBorrow<T, U> { | |
44 | pub fn new<F>(src: T, create: F) -> Pin<Box<Self>> | |
45 | where F: Fn(*mut T) -> U { | |
46 | let mut obj = Box::pin(Self{ | |
47 | bval: src, | |
48 | dst: None, | |
49 | }); | |
50 | let ptr = &mut obj.bval as *mut T; | |
51 | obj.dst = Some(create(ptr)); | |
52 | obj | |
53 | } | |
54 | fn get_object(&self) -> &U { | |
55 | if let Some(ref dst) = self.dst { | |
56 | dst | |
57 | } else { | |
58 | unreachable!() | |
59 | } | |
60 | } | |
61 | fn get_object_mut(&mut self) -> &mut U { | |
62 | if let Some(ref mut dst) = self.dst { | |
63 | dst | |
64 | } else { | |
65 | unreachable!() | |
66 | } | |
67 | } | |
68 | } | |
69 | ||
70 | impl<T, U> Drop for SelfBorrow<T, U> { | |
71 | fn drop(&mut self) { | |
72 | self.dst = None; | |
73 | } | |
74 | } | |
75 | ||
76 | pub type SBBox<T, U> = Pin<Box<SelfBorrow<T, U>>>; | |
77 | ||
6f6ba7bf KS |
78 | const SND_NO_FORMAT: NASoniton = NASoniton { bits: 0, be: false, packed: false, planar: false, float: false, signed: false }; |
79 | ||
5ec8115f KS |
80 | fn format_time(ms: u64) -> String { |
81 | let s = ms / 1000; | |
82 | let ds = (ms % 1000) / 100; | |
83 | let (min, s) = (s / 60, s % 60); | |
84 | let (h, min) = (min / 60, min % 60); | |
85 | if h == 0 { | |
86 | if min == 0 { | |
87 | format!("{}.{}", s, ds) | |
88 | } else { | |
89 | format!("{}:{:02}.{}", min, s, ds) | |
90 | } | |
91 | } else { | |
92 | format!("{}:{:02}:{:02}.{}", h, min, s, ds) | |
93 | } | |
94 | } | |
95 | ||
6dc69f51 KS |
96 | fn print_options(name: &str, options: &[NAOptionDefinition]) { |
97 | if options.is_empty() { | |
98 | println!("No custom options."); | |
99 | } else { | |
100 | println!("Options for '{}'", name); | |
101 | for opt in options.iter() { | |
102 | println!(" {}", opt); | |
103 | } | |
104 | } | |
105 | } | |
106 | ||
30611a63 KS |
107 | fn parse_bitrate(strval: &str) -> Result<u32, ()> { |
108 | let mut val = 0; | |
109 | let mut has_suffix = false; | |
110 | for ch in strval.chars() { | |
111 | match ch { | |
112 | _ if has_suffix => return Err(()), | |
113 | '0'..='9' => { | |
114 | if val >= std::u32::MAX / 100 { | |
115 | return Err(()); | |
116 | } | |
117 | val = val * 10 + ch.to_digit(10).unwrap_or(0); | |
118 | }, | |
119 | 'k' | 'K' => { | |
120 | if val >= std::u32::MAX / 1000 { | |
121 | return Err(()); | |
122 | } | |
123 | val *= 1000; | |
124 | has_suffix = true; | |
125 | }, | |
126 | 'm' | 'M' => { | |
127 | if val >= std::u32::MAX / 1000000 { | |
128 | return Err(()); | |
129 | } | |
130 | val *= 1000000; | |
131 | has_suffix = true; | |
132 | }, | |
133 | _ => return Err(()), | |
134 | }; | |
135 | } | |
136 | Ok(val) | |
137 | } | |
138 | ||
6dc69f51 KS |
139 | struct OptionArgs { |
140 | name: String, | |
141 | value: Option<String>, | |
142 | } | |
143 | ||
144 | struct InputStreamOptions { | |
145 | id: u32, | |
146 | drop: bool, | |
147 | dec_opts: Vec<OptionArgs>, | |
148 | } | |
149 | ||
150 | struct OutputStreamOptions { | |
151 | id: u32, | |
152 | enc_params: EncodeParameters, | |
153 | enc_name: String, | |
154 | enc_opts: Vec<OptionArgs>, | |
155 | } | |
156 | ||
157 | enum OutputConvert { | |
158 | Video(NAScale, NABufferType), | |
b0481c9e | 159 | Audio(AudioConverter), |
6dc69f51 KS |
160 | None, |
161 | } | |
162 | ||
86c54d88 | 163 | #[allow(clippy::large_enum_variant)] |
6dc69f51 KS |
164 | enum OutputMode { |
165 | Drop, | |
166 | Copy(u32), | |
167 | Encode(u32, Box<dyn NAEncoder>, OutputConvert), | |
168 | } | |
169 | ||
170 | #[derive(Default)] | |
86c54d88 | 171 | #[allow(clippy::type_complexity)] |
6dc69f51 | 172 | struct Transcoder { |
4a835a2a KS |
173 | input_name: [Option<String>; 16], |
174 | input_fmt: [Option<String>; 16], | |
6dc69f51 KS |
175 | output_name: String, |
176 | output_fmt: Option<String>, | |
4a835a2a | 177 | demux_opts: [Vec<OptionArgs>; 16], |
6dc69f51 KS |
178 | mux_opts: Vec<OptionArgs>, |
179 | istr_opts: Vec<InputStreamOptions>, | |
180 | ostr_opts: Vec<OutputStreamOptions>, | |
df37d3b1 | 181 | scale_opts: Vec<(String, String)>, |
d9fe2b71 | 182 | decoders: Vec<Option<(Box<NADecoderSupport>, Box<dyn NADecoder>, Box<dyn FrameReorderer>)>>, |
6dc69f51 KS |
183 | encoders: Vec<OutputMode>, |
184 | no_video: bool, | |
185 | no_audio: bool, | |
951916e8 KS |
186 | start: NATimePoint, |
187 | end: NATimePoint, | |
908ba48c | 188 | verbose: u8, |
79eb70eb KS |
189 | |
190 | calc_len: bool, | |
191 | nframes: Vec<usize>, | |
e47b2114 | 192 | global_tb: (u32, u32), |
6dc69f51 KS |
193 | } |
194 | ||
195 | macro_rules! parse_and_apply_options { | |
196 | ($obj: expr, $in_opts: expr, $name: expr) => { | |
197 | let mut opts = Vec::with_capacity($in_opts.len()); | |
198 | let opt_def = $obj.get_supported_options(); | |
199 | for opt in $in_opts.iter() { | |
200 | let mut found = false; | |
201 | for opt_def in opt_def.iter() { | |
3e2a4e88 KS |
202 | let mut matches = opt.name == opt_def.name; |
203 | if !matches && opt.name.starts_with("no") { | |
204 | let (_, name) = opt.name.split_at(2); | |
205 | matches = name == opt_def.name; | |
206 | } | |
207 | if matches { | |
fd03a232 | 208 | let arg = if let Some(ref strval) = opt.value { Some(strval) } else { None }; |
6dc69f51 | 209 | let ret = opt_def.parse(&opt.name, arg); |
86c54d88 | 210 | if let Ok((val, _)) = ret { |
6dc69f51 | 211 | opts.push(val); |
86c54d88 KS |
212 | } else { |
213 | println!("invalid option {} for {}", opt.name, $name); | |
6dc69f51 KS |
214 | } |
215 | found = true; | |
216 | } | |
217 | } | |
218 | if !found { | |
219 | println!(" ignoring option '{}' for {}", opt.name, $name); | |
220 | } | |
221 | } | |
222 | $obj.set_options(opts.as_slice()); | |
223 | } | |
224 | } | |
225 | ||
226 | impl Transcoder { | |
227 | fn new() -> Self { Self::default() } | |
228 | fn parse_istream_options(&mut self, opt0: &str, opt1: &str) -> bool { | |
229 | let (_, strno) = opt0.split_at(9); | |
230 | let ret = strno.parse::<u32>(); | |
231 | if ret.is_err() { return false; } | |
232 | let streamno = ret.unwrap(); | |
233 | ||
fd03a232 | 234 | let sidx = if let Some(idx) = self.istr_opts.iter().position(|el| el.id == streamno) { |
6dc69f51 KS |
235 | idx |
236 | } else { | |
237 | self.istr_opts.push(InputStreamOptions {id: streamno, drop: false, dec_opts: Vec::new() }); | |
238 | self.istr_opts.len() - 1 | |
239 | }; | |
240 | let istr = &mut self.istr_opts[sidx]; | |
830c03a1 | 241 | |
6dc69f51 KS |
242 | for opt in opt1.split(',') { |
243 | let oval: Vec<_> = opt.split('=').collect(); | |
244 | if oval.len() == 1 { | |
245 | match oval[0] { | |
246 | "drop" => { istr.drop = true; }, | |
247 | _ => { | |
248 | istr.dec_opts.push(OptionArgs{ name: oval[0].to_string(), value: None }); | |
249 | }, | |
250 | }; | |
251 | } else if oval.len() == 2 { | |
252 | istr.dec_opts.push(OptionArgs{ name: oval[0].to_string(), value: Some(oval[1].to_string()) }); | |
253 | } else { | |
254 | println!("unrecognized option '{}'", opt); | |
255 | } | |
256 | } | |
257 | true | |
258 | } | |
259 | fn parse_ostream_options(&mut self, opt0: &str, opt1: &str, enc_reg: &RegisteredEncoders) -> bool { | |
260 | let (_, strno) = opt0.split_at(9); | |
261 | let ret = strno.parse::<u32>(); | |
262 | if ret.is_err() { return false; } | |
263 | let streamno = ret.unwrap(); | |
264 | ||
fd03a232 | 265 | let sidx = if let Some(idx) = self.ostr_opts.iter().position(|el| el.id == streamno) { |
6dc69f51 KS |
266 | idx |
267 | } else { | |
268 | self.ostr_opts.push(OutputStreamOptions {id: streamno, enc_name: String::new(), enc_params: EncodeParameters::default(), enc_opts: Vec::new() }); | |
269 | self.ostr_opts.len() - 1 | |
270 | }; | |
271 | let ostr = &mut self.ostr_opts[sidx]; | |
830c03a1 | 272 | |
6dc69f51 KS |
273 | for opt in opt1.split(',') { |
274 | let oval: Vec<_> = opt.split('=').collect(); | |
275 | if oval.len() == 1 { | |
276 | match oval[0] { | |
277 | "flip" => { | |
278 | if ostr.enc_params.format == NACodecTypeInfo::None { | |
279 | ostr.enc_params.format = NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, false, YUV420_FORMAT)); | |
280 | } | |
281 | if let NACodecTypeInfo::Video(ref mut vinfo) = ostr.enc_params.format { | |
282 | vinfo.flipped = true; | |
283 | } else { | |
284 | println!("video option for audio stream"); | |
285 | } | |
286 | }, | |
287 | "noflip" => { | |
288 | if ostr.enc_params.format == NACodecTypeInfo::None { | |
289 | ostr.enc_params.format = NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, false, YUV420_FORMAT)); | |
290 | } | |
291 | if let NACodecTypeInfo::Video(ref mut vinfo) = ostr.enc_params.format { | |
292 | vinfo.flipped = false; | |
293 | } else { | |
294 | println!("video option for audio stream"); | |
295 | } | |
296 | }, | |
297 | _ => { | |
298 | ostr.enc_opts.push(OptionArgs{ name: oval[0].to_string(), value: None }); | |
299 | }, | |
300 | }; | |
301 | } else if oval.len() == 2 { | |
302 | //todo parse encoder options, store, init later | |
303 | match oval[0] { | |
ca3b31d7 KS |
304 | "timebase" => { |
305 | let mut parts = oval[1].split('/'); | |
306 | let num = parts.next().unwrap(); | |
307 | let den = parts.next(); | |
308 | if let Some(den) = den { | |
309 | let rnum = num.parse::<u32>(); | |
310 | let rden = den.parse::<u32>(); | |
311 | if let (Ok(num), Ok(den)) = (rnum, rden) { | |
312 | ostr.enc_params.tb_num = num; | |
313 | ostr.enc_params.tb_den = den; | |
314 | } else { | |
315 | println!("invalid timebase value"); | |
316 | } | |
317 | } else { | |
318 | println!("invalid timebase format (should be num/den)"); | |
319 | } | |
320 | }, | |
6dc69f51 KS |
321 | "encoder" => { |
322 | if enc_reg.find_encoder(oval[1]).is_some() { | |
323 | ostr.enc_name = oval[1].to_string(); | |
324 | } else { | |
325 | println!("unknown encoder '{}'", oval[1]); | |
c0052668 | 326 | ostr.enc_name = oval[1].to_string(); |
6dc69f51 KS |
327 | } |
328 | }, | |
329 | "width" => { | |
330 | if ostr.enc_params.format == NACodecTypeInfo::None { | |
331 | ostr.enc_params.format = NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, false, YUV420_FORMAT)); | |
332 | } | |
333 | if let NACodecTypeInfo::Video(ref mut vinfo) = ostr.enc_params.format { | |
334 | let ret = oval[1].parse::<usize>(); | |
335 | if let Ok(val) = ret { | |
336 | vinfo.width = val; | |
337 | } else { | |
338 | println!("invalid width"); | |
339 | } | |
340 | } else { | |
341 | println!("video option for audio stream"); | |
342 | } | |
343 | }, | |
344 | "height" => { | |
345 | if ostr.enc_params.format == NACodecTypeInfo::None { | |
346 | ostr.enc_params.format = NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, false, YUV420_FORMAT)); | |
347 | } | |
348 | if let NACodecTypeInfo::Video(ref mut vinfo) = ostr.enc_params.format { | |
349 | let ret = oval[1].parse::<usize>(); | |
350 | if let Ok(val) = ret { | |
351 | vinfo.height = val; | |
352 | } else { | |
353 | println!("invalid height"); | |
354 | } | |
355 | } else { | |
356 | println!("video option for audio stream"); | |
357 | } | |
358 | }, | |
e176bfee KS |
359 | "pixfmt" => { |
360 | if ostr.enc_params.format == NACodecTypeInfo::None { | |
361 | ostr.enc_params.format = NACodecTypeInfo::Video(NAVideoInfo::new(0, 0, false, YUV420_FORMAT)); | |
362 | } | |
363 | if let NACodecTypeInfo::Video(ref mut vinfo) = ostr.enc_params.format { | |
364 | let ret = oval[1].parse::<NAPixelFormaton>(); | |
365 | if let Ok(val) = ret { | |
366 | vinfo.format = val; | |
367 | } else { | |
368 | println!("invalid pixel format"); | |
369 | } | |
370 | } else { | |
371 | println!("video option for audio stream"); | |
372 | } | |
373 | }, | |
6dc69f51 KS |
374 | "srate" => { |
375 | if ostr.enc_params.format == NACodecTypeInfo::None { | |
6f6ba7bf | 376 | ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_NO_FORMAT, 0)); |
6dc69f51 KS |
377 | } |
378 | if let NACodecTypeInfo::Audio(ref mut ainfo) = ostr.enc_params.format { | |
379 | let ret = oval[1].parse::<u32>(); | |
380 | if let Ok(val) = ret { | |
381 | ainfo.sample_rate = val; | |
382 | } else { | |
383 | println!("invalid sampling rate"); | |
384 | } | |
385 | } else { | |
386 | println!("audio option for video stream"); | |
387 | } | |
388 | }, | |
389 | "channels" => { | |
390 | if ostr.enc_params.format == NACodecTypeInfo::None { | |
6f6ba7bf | 391 | ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_NO_FORMAT, 0)); |
6dc69f51 KS |
392 | } |
393 | if let NACodecTypeInfo::Audio(ref mut ainfo) = ostr.enc_params.format { | |
394 | let ret = oval[1].parse::<u8>(); | |
395 | if let Ok(val) = ret { | |
396 | ainfo.channels = val; | |
397 | } else { | |
398 | println!("invalid number of channels"); | |
399 | } | |
400 | } else { | |
401 | println!("audio option for video stream"); | |
402 | } | |
403 | }, | |
404 | "block_len" => { | |
405 | if ostr.enc_params.format == NACodecTypeInfo::None { | |
6f6ba7bf | 406 | ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_NO_FORMAT, 0)); |
6dc69f51 KS |
407 | } |
408 | if let NACodecTypeInfo::Audio(ref mut ainfo) = ostr.enc_params.format { | |
409 | let ret = oval[1].parse::<usize>(); | |
410 | if let Ok(val) = ret { | |
411 | ainfo.block_len = val; | |
412 | } else { | |
413 | println!("invalid block_length"); | |
414 | } | |
415 | } else { | |
416 | println!("audio option for video stream"); | |
417 | } | |
418 | }, | |
e176bfee KS |
419 | "sfmt" => { |
420 | if ostr.enc_params.format == NACodecTypeInfo::None { | |
6f6ba7bf | 421 | ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_NO_FORMAT, 0)); |
e176bfee KS |
422 | } |
423 | if let NACodecTypeInfo::Audio(ref mut ainfo) = ostr.enc_params.format { | |
424 | let ret = oval[1].parse::<NASoniton>(); | |
425 | if let Ok(val) = ret { | |
426 | ainfo.format = val; | |
427 | } else { | |
428 | println!("invalid audio format"); | |
429 | } | |
430 | } else { | |
431 | println!("audio option for video stream"); | |
432 | } | |
433 | }, | |
434 | // todo channel map negotiation | |
435 | /*"chmap" => { | |
436 | if ostr.enc_params.format == NACodecTypeInfo::None { | |
6f6ba7bf | 437 | ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_NO_FORMAT, 0)); |
e176bfee KS |
438 | } |
439 | if let NACodecTypeInfo::Audio(ref mut ainfo) = ostr.enc_params.format { | |
440 | let ret = oval[1].parse::<NAChannelMap>(); | |
441 | if let Ok(val) = ret { | |
442 | ainfo.chmap = val; | |
443 | } else { | |
444 | println!("invalid channel map"); | |
445 | } | |
446 | } else { | |
447 | println!("audio option for video stream"); | |
448 | } | |
449 | },*/ | |
6dc69f51 | 450 | "bitrate" => { |
30611a63 | 451 | let ret = parse_bitrate(oval[1]); |
6dc69f51 KS |
452 | if let Ok(val) = ret { |
453 | ostr.enc_params.bitrate = val; | |
454 | } else { | |
455 | println!("invalid bitrate value"); | |
456 | } | |
457 | }, | |
458 | "quality" => { | |
459 | let ret = oval[1].parse::<u8>(); | |
460 | if let Ok(val) = ret { | |
461 | ostr.enc_params.quality = val; | |
462 | } else { | |
463 | println!("invalid quality value"); | |
464 | } | |
465 | }, | |
466 | _ => { | |
467 | ostr.enc_opts.push(OptionArgs{ name: oval[0].to_string(), value: Some(oval[1].to_string()) }); | |
468 | }, | |
469 | } | |
470 | } else { | |
471 | println!("unrecognized option '{}'", opt); | |
472 | } | |
473 | } | |
474 | true | |
475 | } | |
4a835a2a | 476 | fn parse_demuxer_options(&mut self, opts: &str, dmx_reg: &RegisteredDemuxers, input_no: usize) -> bool { |
6dc69f51 KS |
477 | for opt in opts.split(',') { |
478 | let oval: Vec<_> = opt.split('=').collect(); | |
479 | if oval.len() == 1 { | |
4a835a2a | 480 | self.demux_opts[input_no].push(OptionArgs{ name: oval[0].to_string(), value: None }); |
6dc69f51 KS |
481 | } else if oval.len() == 2 { |
482 | if oval[0] == "format" { | |
483 | if dmx_reg.find_demuxer(oval[1]).is_some() { | |
4a835a2a | 484 | self.input_fmt[input_no] = Some(oval[1].to_string()); |
6dc69f51 KS |
485 | } else { |
486 | println!("unknown demuxer format '{}'", oval[1]); | |
487 | } | |
488 | } else { | |
4a835a2a | 489 | self.demux_opts[input_no].push(OptionArgs{ name: oval[0].to_string(), value: Some(oval[1].to_string()) }); |
6dc69f51 KS |
490 | } |
491 | } else { | |
492 | println!("unrecognized option '{}'", opt); | |
493 | } | |
494 | } | |
495 | true | |
496 | } | |
497 | fn parse_muxer_options(&mut self, opts: &str, mux_reg: &RegisteredMuxers) -> bool { | |
498 | for opt in opts.split(',') { | |
499 | let oval: Vec<_> = opt.split('=').collect(); | |
500 | if oval.len() == 1 { | |
501 | self.mux_opts.push(OptionArgs{ name: oval[0].to_string(), value: None }); | |
502 | } else if oval.len() == 2 { | |
503 | if oval[0] == "format" { | |
504 | if mux_reg.find_muxer(oval[1]).is_some() { | |
505 | self.output_fmt = Some(oval[1].to_string()); | |
506 | } else { | |
507 | println!("unknown muxer format '{}'", oval[1]); | |
508 | } | |
509 | } else { | |
510 | self.mux_opts.push(OptionArgs{ name: oval[0].to_string(), value: Some(oval[1].to_string()) }); | |
511 | } | |
512 | } else { | |
513 | println!("unrecognized option '{}'", opt); | |
514 | } | |
515 | } | |
516 | true | |
517 | } | |
df37d3b1 KS |
518 | fn parse_scale_options(&mut self, opts: &str) -> bool { |
519 | for opt in opts.split(',') { | |
520 | let oval: Vec<_> = opt.split('=').collect(); | |
521 | if oval.len() == 1 { | |
522 | self.scale_opts.push((oval[0].to_string(), "".to_string())); | |
523 | } else if oval.len() == 2 { | |
524 | self.scale_opts.push((oval[0].to_string(), oval[1].to_string())); | |
525 | } else { | |
526 | println!("unrecognized option '{}'", opt); | |
527 | return false; | |
528 | } | |
529 | } | |
530 | true | |
531 | } | |
73f889bf | 532 | fn apply_decoder_options(&self, dec: &mut dyn NADecoder, str_id: u32) { |
fd03a232 | 533 | if let Some(str_idx) = self.istr_opts.iter().position(|el| el.id == str_id) { |
6dc69f51 KS |
534 | let dec_opts = dec.get_supported_options(); |
535 | if dec_opts.is_empty() { return; } | |
536 | let name = format!("input stream {}", str_id); | |
537 | parse_and_apply_options!(dec, &self.istr_opts[str_idx].dec_opts, name); | |
538 | } | |
539 | } | |
79eb70eb | 540 | fn register_output_stream(&mut self, cname: &str, istr: NAStreamRef, iidx: usize, out_sm: &mut StreamManager, enc_reg: &RegisteredEncoders) -> RegisterResult { |
6dc69f51 | 541 | let out_id = out_sm.get_num_streams() as u32; |
fd03a232 | 542 | if let Some(str_idx) = self.istr_opts.iter().position(|el| el.id == (istr.get_num() as u32)) { |
6dc69f51 KS |
543 | if self.istr_opts[str_idx].drop { |
544 | self.encoders.push(OutputMode::Drop); | |
4a835a2a | 545 | return RegisterResult::Ignored; |
6dc69f51 KS |
546 | } |
547 | } | |
548 | ||
fd03a232 | 549 | if let Some(str_idx) = self.ostr_opts.iter().position(|el| el.id == out_id) { |
6dc69f51 | 550 | let oopts = &mut self.ostr_opts[str_idx]; |
a7b5f008 | 551 | if oopts.enc_name.as_str() == "copy" && (cname == "any" || istr.get_info().get_name() == cname) { |
4a835a2a | 552 | out_sm.add_stream((*istr).clone()); |
6dc69f51 KS |
553 | self.encoders.push(OutputMode::Copy(out_id)); |
554 | } else if cname == "any" || oopts.enc_name.as_str() == cname { | |
555 | let enc_create = enc_reg.find_encoder(oopts.enc_name.as_str()); | |
556 | if enc_create.is_none() { | |
557 | println!("encoder '{}' not found", oopts.enc_name.as_str()); | |
4a835a2a | 558 | return RegisterResult::Failed; |
6dc69f51 KS |
559 | } |
560 | let mut encoder = (enc_create.unwrap())(); | |
eb563e3d | 561 | let forced_out = oopts.enc_params.format != NACodecTypeInfo::None; |
6f6ba7bf | 562 | let iformat = istr.get_info().get_properties(); |
6dc69f51 KS |
563 | if oopts.enc_params.format == NACodecTypeInfo::None { |
564 | oopts.enc_params.format = istr.get_info().get_properties(); | |
6f6ba7bf KS |
565 | } else { |
566 | match (&iformat, &mut oopts.enc_params.format) { | |
567 | (NACodecTypeInfo::Video(svinfo), NACodecTypeInfo::Video(ref mut dvinfo)) => { | |
568 | if dvinfo.width == 0 { | |
569 | dvinfo.width = svinfo.width; | |
570 | } | |
571 | if dvinfo.height == 0 { | |
572 | dvinfo.height = svinfo.height; | |
573 | } | |
574 | }, | |
575 | (NACodecTypeInfo::Audio(sainfo), NACodecTypeInfo::Audio(ref mut dainfo)) => { | |
576 | if dainfo.sample_rate == 0 { | |
577 | dainfo.sample_rate = sainfo.sample_rate; | |
578 | } | |
579 | if dainfo.format == SND_NO_FORMAT { | |
580 | dainfo.format = sainfo.format; | |
581 | } | |
582 | if dainfo.channels == 0 { | |
583 | dainfo.channels = sainfo.channels; | |
584 | } | |
585 | if dainfo.block_len == 0 { | |
586 | dainfo.block_len = sainfo.block_len; | |
587 | } | |
588 | }, | |
589 | _ => {}, | |
590 | }; | |
6dc69f51 | 591 | } |
e47b2114 KS |
592 | if self.global_tb != (0, 0) { |
593 | oopts.enc_params.tb_num = self.global_tb.0; | |
594 | oopts.enc_params.tb_den = self.global_tb.1; | |
595 | } | |
6dc69f51 KS |
596 | if oopts.enc_params.tb_num == 0 { |
597 | oopts.enc_params.tb_num = istr.tb_num; | |
598 | oopts.enc_params.tb_den = istr.tb_den; | |
599 | } | |
600 | let ret_eparams = encoder.negotiate_format(&oopts.enc_params); | |
601 | if ret_eparams.is_err() { | |
602 | println!("cannot negotiate encoding parameters"); | |
4a835a2a | 603 | return RegisterResult::Failed; |
6dc69f51 KS |
604 | } |
605 | let ret_eparams = ret_eparams.unwrap(); | |
606 | ||
607 | //todo check for params mismatch | |
6f6ba7bf | 608 | let cvt = match (&iformat, &ret_eparams.format) { |
6dc69f51 | 609 | (NACodecTypeInfo::Video(svinfo), NACodecTypeInfo::Video(dvinfo)) => { |
eb563e3d | 610 | if svinfo == dvinfo && !forced_out { |
6dc69f51 KS |
611 | OutputConvert::None |
612 | } else { | |
613 | let ofmt = ScaleInfo { fmt: dvinfo.format, width: dvinfo.width, height: dvinfo.height }; | |
df37d3b1 | 614 | let ret = NAScale::new_with_options(ofmt, ofmt, &self.scale_opts); |
6dc69f51 KS |
615 | if ret.is_err() { |
616 | println!("cannot create scaler"); | |
4a835a2a | 617 | return RegisterResult::Failed; |
6dc69f51 KS |
618 | } |
619 | let scaler = ret.unwrap(); | |
620 | let ret = alloc_video_buffer(*dvinfo, 4); | |
621 | if ret.is_err() { | |
622 | println!("cannot create scaler buffer"); | |
4a835a2a | 623 | return RegisterResult::Failed; |
6dc69f51 KS |
624 | } |
625 | let cvt_buf = ret.unwrap(); | |
626 | OutputConvert::Video(scaler, cvt_buf) | |
627 | } | |
628 | }, | |
629 | (NACodecTypeInfo::Audio(sainfo), NACodecTypeInfo::Audio(dainfo)) => { | |
82d53f6e KS |
630 | let icodec = istr.get_info().get_name(); |
631 | if (sainfo == dainfo) && (icodec != "pcm" || oopts.enc_name.as_str() == "pcm") { | |
6dc69f51 KS |
632 | OutputConvert::None |
633 | } else { | |
634 | let dchmap = match dainfo.channels { | |
635 | 1 => NAChannelMap::from_ms_mapping(0x4), | |
636 | 2 => NAChannelMap::from_ms_mapping(0x3), | |
637 | _ => { | |
638 | println!("can't generate default channel map for {} channels", dainfo.channels); | |
4a835a2a | 639 | return RegisterResult::Failed; |
6dc69f51 KS |
640 | }, |
641 | }; | |
b0481c9e | 642 | let acvt = AudioConverter::new(sainfo, dainfo, dchmap); |
6dc69f51 | 643 | //todo channelmap |
b0481c9e | 644 | OutputConvert::Audio(acvt) |
6dc69f51 KS |
645 | } |
646 | }, | |
647 | _ => OutputConvert::None, | |
648 | }; | |
720f1a09 KS |
649 | let name = format!("output stream {}", out_id); |
650 | parse_and_apply_options!(encoder, &oopts.enc_opts, name); | |
651 | ||
79eb70eb KS |
652 | if self.calc_len && self.nframes.len() > iidx { |
653 | encoder.set_options(&[NAOption{name: "nframes", value: NAValue::Int(self.nframes[iidx] as i64)}]); | |
654 | } | |
655 | ||
6dc69f51 KS |
656 | let ret = encoder.init(out_id, ret_eparams); |
657 | if ret.is_err() { | |
658 | println!("error initialising encoder"); | |
4a835a2a | 659 | return RegisterResult::Failed; |
6dc69f51 KS |
660 | } |
661 | out_sm.add_stream_ref(ret.unwrap()); | |
662 | ||
6dc69f51 KS |
663 | parse_and_apply_options!(encoder, &oopts.enc_opts, name); |
664 | ||
665 | self.encoders.push(OutputMode::Encode(out_id, encoder, cvt)); | |
666 | } else { | |
667 | println!("encoder {} is not supported by output (expected {})", istr.id, istr.get_info().get_name()); | |
4a835a2a | 668 | return RegisterResult::Failed; |
6dc69f51 | 669 | } |
86c54d88 | 670 | } else if cname == "any" || istr.get_info().get_name() == cname { |
4a835a2a | 671 | out_sm.add_stream((*istr).clone()); |
86c54d88 | 672 | self.encoders.push(OutputMode::Copy(out_id)); |
6dc69f51 | 673 | } else { |
00b4c46f KS |
674 | let mut oopts = OutputStreamOptions {id: out_id, enc_name: cname.to_owned(), enc_params: EncodeParameters::default(), enc_opts: Vec::new() }; |
675 | ||
676 | let enc_create = enc_reg.find_encoder(cname); | |
677 | if enc_create.is_none() { | |
678 | println!("encoder '{}' not found", oopts.enc_name.as_str()); | |
4a835a2a | 679 | return RegisterResult::Failed; |
00b4c46f KS |
680 | } |
681 | let mut encoder = (enc_create.unwrap())(); | |
682 | oopts.enc_params.format = istr.get_info().get_properties(); | |
e47b2114 KS |
683 | if self.global_tb != (0, 0) { |
684 | oopts.enc_params.tb_num = self.global_tb.0; | |
685 | oopts.enc_params.tb_den = self.global_tb.1; | |
686 | } else { | |
687 | oopts.enc_params.tb_num = istr.tb_num; | |
688 | oopts.enc_params.tb_den = istr.tb_den; | |
689 | } | |
00b4c46f KS |
690 | let ret_eparams = encoder.negotiate_format(&oopts.enc_params); |
691 | if ret_eparams.is_err() { | |
692 | println!("cannot negotiate encoding parameters"); | |
4a835a2a | 693 | return RegisterResult::Failed; |
00b4c46f KS |
694 | } |
695 | let ret_eparams = ret_eparams.unwrap(); | |
696 | ||
697 | //todo check for params mismatch | |
698 | let cvt = match (&oopts.enc_params.format, &ret_eparams.format) { | |
699 | (NACodecTypeInfo::Video(svinfo), NACodecTypeInfo::Video(dvinfo)) => { | |
700 | if svinfo == dvinfo { | |
701 | OutputConvert::None | |
702 | } else { | |
703 | let ofmt = ScaleInfo { fmt: dvinfo.format, width: dvinfo.width, height: dvinfo.height }; | |
704 | let ret = NAScale::new_with_options(ofmt, ofmt, &self.scale_opts); | |
705 | if ret.is_err() { | |
706 | println!("cannot create scaler"); | |
4a835a2a | 707 | return RegisterResult::Failed; |
00b4c46f KS |
708 | } |
709 | let scaler = ret.unwrap(); | |
710 | let ret = alloc_video_buffer(*dvinfo, 4); | |
711 | if ret.is_err() { | |
712 | println!("cannot create scaler buffer"); | |
4a835a2a | 713 | return RegisterResult::Failed; |
00b4c46f KS |
714 | } |
715 | let cvt_buf = ret.unwrap(); | |
716 | OutputConvert::Video(scaler, cvt_buf) | |
717 | } | |
718 | }, | |
719 | (NACodecTypeInfo::Audio(sainfo), NACodecTypeInfo::Audio(dainfo)) => { | |
720 | if sainfo == dainfo { | |
721 | OutputConvert::None | |
722 | } else { | |
723 | let dchmap = match dainfo.channels { | |
724 | 1 => NAChannelMap::from_ms_mapping(0x4), | |
725 | 2 => NAChannelMap::from_ms_mapping(0x3), | |
726 | _ => { | |
727 | println!("can't generate default channel map for {} channels", dainfo.channels); | |
4a835a2a | 728 | return RegisterResult::Failed; |
00b4c46f KS |
729 | }, |
730 | }; | |
731 | //todo channelmap | |
b0481c9e KS |
732 | let acvt = AudioConverter::new(sainfo, dainfo, dchmap); |
733 | OutputConvert::Audio(acvt) | |
00b4c46f KS |
734 | } |
735 | }, | |
736 | _ => OutputConvert::None, | |
737 | }; | |
738 | let ret = encoder.init(out_id, ret_eparams); | |
739 | if ret.is_err() { | |
740 | println!("error initialising encoder"); | |
4a835a2a | 741 | return RegisterResult::Failed; |
00b4c46f KS |
742 | } |
743 | out_sm.add_stream_ref(ret.unwrap()); | |
744 | self.encoders.push(OutputMode::Encode(out_id, encoder, cvt)); | |
745 | self.ostr_opts.push(oopts); | |
6dc69f51 | 746 | } |
4a835a2a | 747 | RegisterResult::Ok |
6dc69f51 KS |
748 | } |
749 | fn map_single(&mut self, cname: &str, ctype: StreamType, src_sm: &StreamManager, out_sm: &mut StreamManager, enc_reg: &RegisteredEncoders) -> bool { | |
750 | let mut found_stream = false; | |
79eb70eb | 751 | for (iidx, istr) in src_sm.iter().enumerate() { |
6dc69f51 KS |
752 | if istr.get_media_type() != ctype || found_stream { |
753 | self.encoders.push(OutputMode::Drop); | |
754 | } else { | |
79eb70eb | 755 | match self.register_output_stream(cname, istr, iidx, out_sm, enc_reg) { |
4a835a2a KS |
756 | RegisterResult::Ok => found_stream = true, |
757 | RegisterResult::Failed => return false, | |
758 | RegisterResult::Ignored => {}, | |
759 | }; | |
6dc69f51 KS |
760 | } |
761 | } | |
762 | found_stream | |
763 | } | |
764 | fn negotiate_stream_map(&mut self, src_sm: &StreamManager, mux_caps: MuxerCapabilities, out_sm: &mut StreamManager, enc_reg: &RegisteredEncoders) -> bool { | |
765 | match mux_caps { | |
766 | MuxerCapabilities::SingleVideo(cname) => { | |
767 | if self.no_video { return false; } | |
768 | self.map_single(cname, StreamType::Video, src_sm, out_sm, enc_reg) | |
769 | }, | |
770 | MuxerCapabilities::SingleAudio(cname) => { | |
771 | if self.no_audio { return false; } | |
772 | self.map_single(cname, StreamType::Audio, src_sm, out_sm, enc_reg) | |
773 | }, | |
774 | MuxerCapabilities::SingleVideoAndAudio(vname, aname) => { | |
775 | let mut found_vid = false; | |
776 | let mut found_aud = false; | |
79eb70eb | 777 | for (iidx, istr) in src_sm.iter().enumerate() { |
6dc69f51 | 778 | if istr.get_media_type() == StreamType::Video && !found_vid && !self.no_video { |
79eb70eb | 779 | match self.register_output_stream(vname, istr, iidx, out_sm, enc_reg) { |
4a835a2a KS |
780 | RegisterResult::Ok => found_vid = true, |
781 | RegisterResult::Failed => return false, | |
782 | RegisterResult::Ignored => {}, | |
783 | }; | |
6dc69f51 | 784 | } else if istr.get_media_type() == StreamType::Audio && !found_aud && !self.no_audio { |
79eb70eb | 785 | match self.register_output_stream(aname, istr, iidx, out_sm, enc_reg) { |
4a835a2a KS |
786 | RegisterResult::Ok => found_aud = true, |
787 | RegisterResult::Failed => return false, | |
788 | RegisterResult::Ignored => {}, | |
789 | }; | |
6dc69f51 KS |
790 | } else { |
791 | self.encoders.push(OutputMode::Drop); | |
792 | } | |
793 | } | |
794 | found_vid | found_aud | |
795 | }, | |
796 | MuxerCapabilities::OnlyVideo => { | |
797 | if self.no_video { return false; } | |
798 | ||
799 | let mut found_vid = false; | |
79eb70eb | 800 | for (iidx, istr) in src_sm.iter().enumerate() { |
429e677e | 801 | if istr.get_media_type() == StreamType::Video { |
79eb70eb | 802 | match self.register_output_stream("any", istr, iidx, out_sm, enc_reg) { |
4a835a2a KS |
803 | RegisterResult::Ok => found_vid = true, |
804 | RegisterResult::Failed => return false, | |
805 | RegisterResult::Ignored => {}, | |
806 | }; | |
6dc69f51 KS |
807 | } else { |
808 | self.encoders.push(OutputMode::Drop); | |
809 | } | |
810 | } | |
811 | found_vid | |
812 | }, | |
813 | MuxerCapabilities::OnlyAudio => { | |
814 | if self.no_audio { return false; } | |
815 | ||
816 | let mut found_aud = false; | |
79eb70eb | 817 | for (iidx, istr) in src_sm.iter().enumerate() { |
429e677e | 818 | if istr.get_media_type() == StreamType::Audio { |
79eb70eb | 819 | match self.register_output_stream("any", istr, iidx, out_sm, enc_reg) { |
4a835a2a KS |
820 | RegisterResult::Ok => found_aud = true, |
821 | RegisterResult::Failed => return false, | |
822 | RegisterResult::Ignored => {}, | |
823 | }; | |
6dc69f51 KS |
824 | } else { |
825 | self.encoders.push(OutputMode::Drop); | |
826 | } | |
827 | } | |
828 | found_aud | |
829 | }, | |
830 | MuxerCapabilities::Universal => { | |
79eb70eb | 831 | for (iidx, istr) in src_sm.iter().enumerate() { |
6dc69f51 KS |
832 | if (istr.get_media_type() == StreamType::Video && self.no_video) || |
833 | (istr.get_media_type() == StreamType::Audio && self.no_audio) { | |
834 | self.encoders.push(OutputMode::Drop); | |
835 | continue; | |
836 | } | |
79eb70eb | 837 | if self.register_output_stream("any", istr, iidx, out_sm, enc_reg) == RegisterResult::Failed { |
6dc69f51 KS |
838 | return false; |
839 | } | |
840 | } | |
841 | true | |
842 | }, | |
843 | } | |
844 | } | |
79eb70eb KS |
845 | fn create_demuxers(&mut self, demuxers: &mut Vec<(DemuxerObject, bool)>, full_reg: &FullRegister, print_info: bool) -> bool { |
846 | let mut isn_start = 0; | |
847 | for (i, (iname, ifmt)) in self.input_name.iter().zip( | |
848 | self.input_fmt.iter()).enumerate() { | |
849 | match (iname, ifmt.as_ref().map(|s| s.as_str())) { | |
850 | (Some(name), Some("imgseq")) => { | |
851 | println!("trying image sequence {}", name); | |
852 | let mut isdc = ImgSeqDemuxerCreator::new(name.as_str()); | |
853 | parse_and_apply_options!(isdc, &self.demux_opts[i], "input"); | |
854 | let isd = if let Ok(ctx) = isdc.open() { | |
855 | ctx | |
856 | } else { | |
857 | println!("failed to create image sequence demuxer!"); | |
858 | return false; | |
859 | }; | |
860 | let dmx = DemuxerObject::create_imgseq(isd); | |
861 | if print_info { | |
862 | for i in 0..dmx.get_num_streams() { | |
863 | let s = dmx.get_stream(i).unwrap(); | |
864 | let info = s.get_info(); | |
865 | println!(" stream {}({}) - {} {}", i, i + isn_start, s, info.get_name()); | |
866 | } | |
867 | } | |
868 | isn_start += dmx.get_num_streams(); | |
869 | demuxers.push((dmx, false)) | |
870 | }, | |
871 | (Some(name), _) => { | |
872 | let res = File::open(name); | |
873 | if res.is_err() { | |
874 | println!("error opening input"); | |
875 | return false; | |
876 | } | |
877 | let file = res.unwrap(); | |
878 | let file = BufReader::new(file); | |
879 | let mut fr = FileReader::new_read(file); | |
880 | let mut br = ByteReader::new(&mut fr); | |
881 | let (is_raw, start, end) = if ifmt.is_none() { | |
882 | detect_tags(&mut br) | |
883 | } else { | |
884 | (false, 0, None) | |
885 | }; | |
886 | ||
887 | let nfr: Box<dyn ByteIO> = if start != 0 || end.is_some() { | |
888 | let file = fr.finish(); | |
889 | Box::new(BoundedFileReader::new_read(file, start, end).unwrap()) | |
890 | } else { | |
891 | Box::new(fr) | |
892 | }; | |
893 | let sb = SelfBorrow::new(nfr, |rd| { | |
894 | unsafe { | |
895 | ByteReader::new(rd.as_mut().unwrap().as_mut()) | |
896 | } | |
897 | }); | |
898 | ||
899 | let mut dmx = DemuxerObject::create(sb, full_reg, name, ifmt, is_raw, print_info); | |
900 | if dmx.is_none() { | |
901 | println!("cannot find demuxer for '{}'", name); | |
902 | return false; | |
903 | } | |
904 | parse_and_apply_options!(dmx, &self.demux_opts[i], "input"); | |
905 | if print_info { | |
906 | for i in 0..dmx.get_num_streams() { | |
907 | let s = dmx.get_stream(i).unwrap(); | |
908 | let info = s.get_info(); | |
909 | println!(" stream {}({}) - {} {}", i, i + isn_start, s, info.get_name()); | |
910 | } | |
911 | } | |
912 | isn_start += dmx.get_num_streams(); | |
913 | demuxers.push((dmx, false)); | |
914 | }, | |
915 | _ => {}, | |
916 | }; | |
917 | } | |
918 | true | |
919 | } | |
6dc69f51 KS |
920 | } |
921 | ||
df37d3b1 | 922 | fn encode_frame(dst_id: u32, encoder: &mut Box<dyn NAEncoder>, cvt: &mut OutputConvert, frm: NAFrameRef, scale_opts: &[(String, String)]) -> bool { |
d9fe2b71 | 923 | let buf = frm.get_buffer(); |
637e4d45 | 924 | let cbuf = if let NABufferType::None = buf { |
343a59ec | 925 | if (encoder.get_capabilities() & ENC_CAPS_SKIPFRAME) == 0 { |
b76448d9 KS |
926 | match cvt { |
927 | OutputConvert::Video(_, ref mut dbuf) => dbuf.clone(), | |
928 | _ => { | |
929 | println!("encoder does not support skip frames, skipping"); | |
930 | return true; | |
931 | }, | |
932 | } | |
933 | } else { | |
934 | buf | |
343a59ec | 935 | } |
637e4d45 KS |
936 | } else { |
937 | match cvt { | |
d9fe2b71 KS |
938 | OutputConvert::None => buf, |
939 | OutputConvert::Video(ref mut scaler, ref mut dbuf) => { | |
940 | let cur_ifmt = get_scale_fmt_from_pic(&buf); | |
941 | let last_ifmt = scaler.get_in_fmt(); | |
942 | if cur_ifmt != last_ifmt { | |
943 | let ofmt = scaler.get_out_fmt(); | |
df37d3b1 | 944 | let ret = NAScale::new_with_options(cur_ifmt, ofmt, scale_opts); |
d9fe2b71 KS |
945 | if ret.is_err() { |
946 | println!("error re-initialising scaler for {} -> {}", cur_ifmt, ofmt); | |
947 | return false; | |
948 | } | |
949 | *scaler = ret.unwrap(); | |
950 | } | |
951 | let ret = scaler.convert(&buf, dbuf); | |
952 | if ret.is_err() { | |
953 | println!("error converting frame for encoding"); | |
954 | return false; | |
955 | } | |
956 | dbuf.clone() | |
957 | }, | |
b0481c9e KS |
958 | OutputConvert::Audio(ref mut acvt) => { |
959 | if !acvt.queue_frame(buf, frm.get_time_information()) { | |
d9fe2b71 KS |
960 | println!("error converting audio for stream {}", dst_id); |
961 | return false; | |
962 | } | |
b0481c9e | 963 | return true; |
d9fe2b71 | 964 | }, |
637e4d45 KS |
965 | } |
966 | }; | |
d9fe2b71 KS |
967 | let cfrm = NAFrame::new(frm.get_time_information(), frm.frame_type, frm.key, frm.get_info(), cbuf); |
968 | encoder.encode(&cfrm).unwrap(); | |
969 | true | |
970 | } | |
971 | ||
6dc69f51 KS |
972 | macro_rules! next_arg { |
973 | ($args: expr, $arg_idx: expr) => { | |
974 | if $arg_idx + 1 >= $args.len() { | |
975 | println!("codec name is required"); | |
976 | } | |
977 | $arg_idx += 1; | |
978 | } | |
979 | } | |
980 | ||
4a835a2a KS |
981 | macro_rules! parse_id { |
982 | ($val: expr, $stype: expr, $maxval: expr) => { | |
983 | if $val.is_empty() { | |
984 | 0 | |
985 | } else if let Ok(val) = $val.parse::<usize>() { | |
986 | if val < $maxval { | |
987 | val | |
988 | } else { | |
989 | println!("{} number should be below {}", $stype, $maxval); | |
990 | return; | |
991 | } | |
992 | } else { | |
993 | println!("invalid {} number '{}'", $stype, $val); | |
994 | return; | |
995 | } | |
996 | } | |
997 | } | |
998 | ||
86c54d88 | 999 | #[allow(clippy::single_match)] |
6dc69f51 KS |
1000 | fn main() { |
1001 | let args: Vec<_> = env::args().collect(); | |
1002 | ||
1003 | if args.len() == 1 { | |
071d353e KS |
1004 | println!("usage: nihav-encoder [options] --input inputfile --output outputfile"); |
1005 | println!(" use nihav-encoder --help to list all available options"); | |
1006 | return; | |
1007 | } | |
1008 | if args.len() == 2 && (args[1] == "--help" || args[1] == "-h") { | |
1009 | println!("usage: nihav-encoder [options] --input inputfile --output outputfile"); | |
1010 | println!(" query options:"); | |
1011 | println!(" --list-{{decoders,encoders,demuxers,muxers}} - lists all available decoders/encoders/demuxers/muxers"); | |
1012 | println!(" --query-{{decoder,encoder,demuxer,muxer}}-options name - lists all options recognized by that decoder/encoder/demuxer/muxer"); | |
1013 | println!(" processing options:"); | |
3e82df4a | 1014 | println!(" --verbose - show time for the currently processed input"); |
071d353e KS |
1015 | println!(" --input inputfile - set input file"); |
1016 | println!(" --input-format fmt - force input format"); | |
1017 | println!(" --demuxer-options options - set input demuxer options"); | |
df37d3b1 | 1018 | println!(" --scale-options options - set scaler options"); |
071d353e KS |
1019 | println!(" --output outputfile - set output file"); |
1020 | println!(" --output-format fmt - force output format"); | |
1021 | println!(" --muxer-options options - set output muxer options"); | |
1022 | println!(" --no-audio - do not decode audio streams"); | |
1023 | println!(" --no-video - do not decode video streams"); | |
1024 | println!(" --start starttime - start decoding from given position"); | |
1025 | println!(" --end endtime - end decoding at given position"); | |
1026 | println!(" --istreamX options - set options for input stream X"); | |
1027 | println!(" --ostreamX options - set options for output stream X"); | |
1028 | println!(); | |
1029 | println!(" (de)muxer and stream options are passed as comma-separated list e.g. --ostream0 width=320,height=240,flip"); | |
6dc69f51 KS |
1030 | return; |
1031 | } | |
1032 | ||
91a15e39 | 1033 | let full_reg = FullRegister::new(); |
6dc69f51 KS |
1034 | |
1035 | let mut transcoder = Transcoder::new(); | |
e47b2114 | 1036 | let mut use_video_tb = false; |
6dc69f51 KS |
1037 | |
1038 | let mut arg_idx = 1; | |
5a8a7cdb | 1039 | let mut printed_info = false; |
6dc69f51 KS |
1040 | while arg_idx < args.len() { |
1041 | match args[arg_idx].as_str() { | |
e6cb09af | 1042 | "--list-decoders" => { |
91a15e39 | 1043 | if full_reg.dec_reg.iter().len() > 0 { |
e6cb09af | 1044 | println!("Registered decoders:"); |
91a15e39 | 1045 | for dec in full_reg.dec_reg.iter() { |
e6cb09af KS |
1046 | let cdesc = register::get_codec_description(dec.name); |
1047 | let full_name = if let Some(cd) = cdesc { cd.get_full_name() } else { "???" }; | |
1048 | println!(" {} ({})", dec.name, full_name); | |
1049 | } | |
1050 | } else { | |
1051 | println!("No registered decoders."); | |
1052 | } | |
5a8a7cdb | 1053 | printed_info = true; |
e6cb09af KS |
1054 | }, |
1055 | "--list-encoders" => { | |
91a15e39 | 1056 | if full_reg.enc_reg.iter().len() > 0 { |
e6cb09af | 1057 | println!("Registered encoders:"); |
91a15e39 | 1058 | for enc in full_reg.enc_reg.iter() { |
e6cb09af KS |
1059 | let cdesc = register::get_codec_description(enc.name); |
1060 | let full_name = if let Some(cd) = cdesc { cd.get_full_name() } else { "???" }; | |
1061 | println!(" {} ({})", enc.name, full_name); | |
1062 | } | |
1063 | } else { | |
1064 | println!("No registered encoders."); | |
1065 | } | |
5a8a7cdb | 1066 | printed_info = true; |
e6cb09af KS |
1067 | }, |
1068 | "--list-demuxers" => { | |
1069 | print!("Registered demuxers:"); | |
91a15e39 | 1070 | for dmx in full_reg.dmx_reg.iter() { |
e6cb09af KS |
1071 | print!(" {}", dmx.get_name()); |
1072 | } | |
1073 | println!(); | |
5a8a7cdb | 1074 | printed_info = true; |
e6cb09af KS |
1075 | }, |
1076 | "--list-muxers" => { | |
1077 | print!("Registered muxers:"); | |
91a15e39 | 1078 | for mux in full_reg.mux_reg.iter() { |
e6cb09af KS |
1079 | print!(" {}", mux.get_name()); |
1080 | } | |
1081 | println!(); | |
5a8a7cdb | 1082 | printed_info = true; |
e6cb09af | 1083 | }, |
6dc69f51 KS |
1084 | "--query-decoder-options" => { |
1085 | next_arg!(args, arg_idx); | |
1086 | let cname = args[arg_idx].as_str(); | |
91a15e39 | 1087 | if let Some(decfunc) = full_reg.dec_reg.find_decoder(cname) { |
6dc69f51 KS |
1088 | let dec = (decfunc)(); |
1089 | let opts = dec.get_supported_options(); | |
1090 | print_options(cname, opts); | |
1091 | } else { | |
1092 | println!("codec {} is not found", cname); | |
1093 | } | |
5a8a7cdb | 1094 | printed_info = true; |
6dc69f51 KS |
1095 | }, |
1096 | "--query-demuxer-options" => { | |
1097 | next_arg!(args, arg_idx); | |
1098 | let dname = args[arg_idx].as_str(); | |
1099 | let mut mr = MemoryReader::new_read(&[]); | |
1100 | let mut br = ByteReader::new(&mut mr); | |
91a15e39 | 1101 | if let Some(dmx_creator) = full_reg.dmx_reg.find_demuxer(dname) { |
6dc69f51 KS |
1102 | let dmx = dmx_creator.new_demuxer(&mut br); |
1103 | let opts = dmx.get_supported_options(); | |
1104 | print_options(dname, opts); | |
1105 | } else { | |
1106 | println!("demuxer {} is not found", dname); | |
1107 | } | |
5a8a7cdb | 1108 | printed_info = true; |
6dc69f51 KS |
1109 | }, |
1110 | "--query-encoder-options" => { | |
1111 | next_arg!(args, arg_idx); | |
1112 | let cname = args[arg_idx].as_str(); | |
91a15e39 | 1113 | if let Some(encfunc) = full_reg.enc_reg.find_encoder(cname) { |
6dc69f51 KS |
1114 | let enc = (encfunc)(); |
1115 | let opts = enc.get_supported_options(); | |
1116 | print_options(cname, opts); | |
1117 | } else { | |
1118 | println!("codec {} is not found", cname); | |
1119 | } | |
5a8a7cdb | 1120 | printed_info = true; |
6dc69f51 KS |
1121 | }, |
1122 | "--query-muxer-options" => { | |
1123 | next_arg!(args, arg_idx); | |
1124 | let name = args[arg_idx].as_str(); | |
1125 | let mut data = []; | |
1126 | let mut mw = MemoryWriter::new_write(&mut data); | |
1127 | let mut bw = ByteWriter::new(&mut mw); | |
91a15e39 | 1128 | if let Some(mux_creator) = full_reg.mux_reg.find_muxer(name) { |
6dc69f51 KS |
1129 | let mux = mux_creator.new_muxer(&mut bw); |
1130 | let opts = mux.get_supported_options(); | |
1131 | print_options(name, opts); | |
1132 | } else { | |
1133 | println!("muxer {} is not found", name); | |
1134 | } | |
5a8a7cdb | 1135 | printed_info = true; |
6dc69f51 | 1136 | }, |
4b5c61e2 | 1137 | "--output" | "-o" => { |
6dc69f51 KS |
1138 | next_arg!(args, arg_idx); |
1139 | transcoder.output_name = args[arg_idx].clone(); | |
1140 | }, | |
1141 | "--output-format" => { | |
1142 | next_arg!(args, arg_idx); | |
1143 | transcoder.output_fmt = Some(args[arg_idx].clone()); | |
1144 | }, | |
df37d3b1 KS |
1145 | "--scale-options" => { |
1146 | next_arg!(args, arg_idx); | |
1147 | if !transcoder.parse_scale_options(&args[arg_idx]) { | |
1148 | println!("invalid scale option syntax"); | |
1149 | return; | |
1150 | } | |
1151 | }, | |
4b5c61e2 | 1152 | "--no-video" | "-vn" => { |
6dc69f51 KS |
1153 | transcoder.no_video = true; |
1154 | }, | |
4b5c61e2 | 1155 | "--no-audio" | "-an" => { |
6dc69f51 KS |
1156 | transcoder.no_audio = true; |
1157 | }, | |
951916e8 KS |
1158 | "--start" => { |
1159 | next_arg!(args, arg_idx); | |
1160 | let ret = args[arg_idx].parse::<NATimePoint>(); | |
1161 | if let Ok(val) = ret { | |
1162 | transcoder.start = val; | |
1163 | } else { | |
1164 | println!("invalid start time"); | |
1165 | return; | |
1166 | } | |
1167 | }, | |
1168 | "--end" => { | |
1169 | next_arg!(args, arg_idx); | |
1170 | let ret = args[arg_idx].parse::<NATimePoint>(); | |
1171 | if let Ok(val) = ret { | |
1172 | transcoder.end = val; | |
1173 | } else { | |
b0c51548 | 1174 | println!("invalid end time"); |
951916e8 KS |
1175 | return; |
1176 | } | |
1177 | }, | |
6dc69f51 KS |
1178 | "--muxer-options" => { |
1179 | next_arg!(args, arg_idx); | |
91a15e39 | 1180 | if !transcoder.parse_muxer_options(&args[arg_idx], &full_reg.mux_reg) { |
6dc69f51 KS |
1181 | println!("invalid muxer option syntax"); |
1182 | return; | |
1183 | } | |
1184 | }, | |
79eb70eb KS |
1185 | "--calc-len" => { |
1186 | transcoder.calc_len = true; | |
1187 | }, | |
e47b2114 KS |
1188 | "--use-video-tb" => { |
1189 | use_video_tb = true; | |
1190 | }, | |
908ba48c KS |
1191 | "--verbose" | "-v" => transcoder.verbose = 1, |
1192 | "-vv" => transcoder.verbose = 2, | |
1193 | "-v-" => transcoder.verbose = 0, | |
6dc69f51 KS |
1194 | _ => { |
1195 | if args[arg_idx].starts_with("--istream") { | |
1196 | let opt0 = &args[arg_idx]; | |
1197 | next_arg!(args, arg_idx); | |
1198 | if !transcoder.parse_istream_options(opt0, &args[arg_idx]) { | |
1199 | println!("invalid input stream option syntax"); | |
1200 | return; | |
1201 | } | |
1202 | } else if args[arg_idx].starts_with("--ostream") { | |
1203 | let opt0 = &args[arg_idx]; | |
1204 | next_arg!(args, arg_idx); | |
91a15e39 | 1205 | if !transcoder.parse_ostream_options(opt0, &args[arg_idx], &full_reg.enc_reg) { |
6dc69f51 KS |
1206 | println!("invalid output stream option syntax"); |
1207 | return; | |
1208 | } | |
5d3b4c0a KS |
1209 | } else if args[arg_idx].starts_with("--iformat") { |
1210 | let id = parse_id!(&args[arg_idx][9..], "input format", transcoder.input_fmt.len()); | |
1211 | next_arg!(args, arg_idx); | |
1212 | transcoder.input_fmt[id] = Some(args[arg_idx].clone()); | |
4a835a2a KS |
1213 | } else if args[arg_idx].starts_with("--input-format") { |
1214 | let id = parse_id!(&args[arg_idx][14..], "input format", transcoder.input_fmt.len()); | |
1215 | next_arg!(args, arg_idx); | |
1216 | transcoder.input_fmt[id] = Some(args[arg_idx].clone()); | |
1217 | } else if args[arg_idx].starts_with("--input") { // should be after --input-format | |
1218 | let id = parse_id!(&args[arg_idx][7..], "input", transcoder.input_name.len()); | |
1219 | next_arg!(args, arg_idx); | |
1220 | transcoder.input_name[id] = Some(args[arg_idx].clone()); | |
1221 | } else if args[arg_idx].starts_with("-i") { | |
1222 | let id = parse_id!(&args[arg_idx][2..], "input", transcoder.input_name.len()); | |
1223 | next_arg!(args, arg_idx); | |
1224 | transcoder.input_name[id] = Some(args[arg_idx].clone()); | |
1225 | } else if args[arg_idx].starts_with("--demuxer-options") { | |
1226 | let id = parse_id!(&args[arg_idx][17..], "input options", transcoder.demux_opts.len()); | |
1227 | next_arg!(args, arg_idx); | |
1228 | if !transcoder.parse_demuxer_options(&args[arg_idx], &full_reg.dmx_reg, id) { | |
1229 | println!("invalid demuxer option syntax"); | |
1230 | return; | |
1231 | } | |
6dc69f51 | 1232 | } else if args[arg_idx].starts_with("--") { |
bafd0754 | 1233 | println!("unknown option '{}'", args[arg_idx]); |
6dc69f51 | 1234 | } else { |
bafd0754 | 1235 | println!("unrecognized argument '{}'", args[arg_idx]); |
6dc69f51 KS |
1236 | } |
1237 | }, | |
1238 | }; | |
1239 | arg_idx += 1; | |
1240 | } | |
1241 | ||
5a8a7cdb KS |
1242 | if printed_info { |
1243 | return; | |
1244 | } | |
1245 | ||
4a835a2a KS |
1246 | if transcoder.input_name.iter().flatten().count() == 0 { |
1247 | println!("no input name(s) provided"); | |
6dc69f51 KS |
1248 | return; |
1249 | } | |
86c54d88 | 1250 | if transcoder.output_name.is_empty() { |
6dc69f51 KS |
1251 | println!("no output name provided"); |
1252 | return; | |
1253 | } | |
1254 | ||
4a835a2a | 1255 | let mut demuxers = Vec::with_capacity(1); |
79eb70eb KS |
1256 | if !transcoder.create_demuxers(&mut demuxers, &full_reg, true) { |
1257 | return; | |
6dc69f51 | 1258 | } |
90683bc3 | 1259 | |
4a835a2a KS |
1260 | let duration = demuxers.iter().fold(0u64, |mindur, (dmx, _)| { |
1261 | let dur = dmx.get_duration(); | |
1262 | if dur > 0 { | |
1263 | mindur.min(dur) | |
1264 | } else { | |
1265 | mindur | |
1266 | } | |
1267 | }); | |
5ec8115f KS |
1268 | let duration_string = if duration != 0 { format_time(duration) } else { String::new() }; |
1269 | ||
4a835a2a KS |
1270 | let mut ism = StreamManager::new(); |
1271 | let mut is_offset = Vec::with_capacity(demuxers.len()); | |
1272 | let mut start = 0; | |
1273 | let mut nstreams = 0; | |
1274 | for (dmx, _) in demuxers.iter() { | |
1275 | is_offset.push(nstreams); | |
1276 | let sm = dmx.get_stream_manager(); | |
1277 | let max_id = sm.iter().fold(0u32, |id, strm| id.max(strm.id)); | |
1278 | for stream in sm.iter() { | |
1279 | let mut newstream = (*stream).clone(); | |
e47b2114 KS |
1280 | if use_video_tb && transcoder.global_tb == (0, 0) && newstream.get_media_type() == StreamType::Video { |
1281 | transcoder.global_tb = newstream.get_timebase(); | |
1282 | } | |
4a835a2a KS |
1283 | newstream.id += start; |
1284 | ism.add_stream(newstream); | |
6dc69f51 | 1285 | } |
4a835a2a KS |
1286 | start += max_id + 1; |
1287 | nstreams += sm.get_num_streams(); | |
6dc69f51 | 1288 | } |
4a835a2a KS |
1289 | |
1290 | for (&is_off, (dmx, _)) in is_offset.iter().zip(demuxers.iter_mut()) { | |
1291 | for i in 0..dmx.get_num_streams() { | |
1292 | let s = dmx.get_stream(i).unwrap(); | |
1293 | let info = s.get_info(); | |
1294 | let decfunc = full_reg.dec_reg.find_decoder(info.get_name()); | |
1295 | let str_id = (s.get_num() + is_off) as u32; | |
1296 | if let Some(create_dec) = decfunc { | |
1297 | let mut dec = (create_dec)(); | |
1298 | let mut dsupp = Box::new(NADecoderSupport::new()); | |
1299 | let ret = dec.init(&mut dsupp, info.clone()); | |
1300 | if ret.is_err() { | |
1301 | println!("Error initialising decoder '{}' for stream {}", info.get_name(), str_id); | |
1302 | return; | |
1303 | } | |
1304 | transcoder.apply_decoder_options(dec.as_mut(), str_id); | |
1305 | let desc = register::get_codec_description(info.get_name()); | |
1306 | let has_b = if let Some(desc) = desc { | |
1307 | desc.has_reorder() | |
1308 | } else { | |
1309 | println!("No codec description found, using B-frame reorderer."); | |
1310 | true | |
1311 | }; | |
1312 | let reord: Box<dyn FrameReorderer> = if has_b { Box::new(IPBReorderer::new()) } else { Box::new(NoReorderer::new()) }; | |
1313 | transcoder.decoders.push(Some((dsupp, dec, reord))); | |
1314 | } else { | |
1315 | println!("No decoder for stream {} ({}) is found", str_id, info.get_name()); | |
1316 | transcoder.decoders.push(None); | |
1317 | } | |
1318 | } | |
1319 | if transcoder.start != NATimePoint::None { | |
1320 | let ret = dmx.seek(transcoder.start); | |
1321 | if ret.is_err() { | |
1322 | println!(" failed to seek to {} error {:?}", transcoder.start, ret.err().unwrap()); | |
1323 | } | |
951916e8 KS |
1324 | } |
1325 | } | |
6dc69f51 | 1326 | |
fd03a232 KS |
1327 | let output_fmt = if let Some(ref fmtname) = transcoder.output_fmt { |
1328 | fmtname | |
c23d0c3a KS |
1329 | } else if transcoder.output_name.as_str() == "/dev/null" { |
1330 | "null" | |
fd03a232 KS |
1331 | } else if let Some(fmtname) = detect::detect_format_by_name(transcoder.output_name.as_str()) { |
1332 | fmtname | |
6dc69f51 | 1333 | } else { |
86c54d88 KS |
1334 | println!("Cannot guess muxer for output"); |
1335 | return; | |
6dc69f51 | 1336 | }; |
91a15e39 | 1337 | let ret = full_reg.mux_reg.find_muxer(output_fmt); |
6dc69f51 KS |
1338 | let ofmt = output_fmt.to_string(); |
1339 | ||
1340 | if ret.is_none() { | |
1341 | println!("cannot find muxer '{}'", output_fmt); | |
becae00f | 1342 | return; |
6dc69f51 KS |
1343 | } |
1344 | let mux_creator = ret.unwrap(); | |
1345 | ||
79eb70eb KS |
1346 | if transcoder.calc_len { |
1347 | let mut sids = Vec::new(); | |
1348 | transcoder.nframes.clear(); | |
1349 | for (dmx, _) in demuxers.iter_mut() { | |
1350 | let sstart = transcoder.nframes.len(); | |
1351 | let sm = dmx.get_stream_manager(); | |
1352 | sids.clear(); | |
1353 | for stream in sm.iter() { | |
1354 | transcoder.nframes.push(0); | |
1355 | sids.push(stream.get_id()); | |
1356 | } | |
1357 | ||
1358 | while let Ok(pkt) = dmx.get_frame() { | |
1359 | let stream = pkt.get_stream(); | |
1360 | let pos = sstart + sids.iter().position(|&x| x == stream.get_id()).unwrap(); | |
1361 | transcoder.nframes[pos] += 1; | |
1362 | } | |
1363 | } | |
1364 | // this is necessary since not all demuxers allow to seek even back to the start | |
1365 | demuxers.clear(); | |
1366 | if !transcoder.create_demuxers(&mut demuxers, &full_reg, false) { | |
1367 | println!("failed to re-create demuxer(s)"); | |
1368 | return; | |
1369 | } | |
1370 | } | |
1371 | ||
6dc69f51 KS |
1372 | let mux_caps = mux_creator.get_capabilities(); |
1373 | let mut out_sm = StreamManager::new(); | |
4a835a2a | 1374 | if !transcoder.negotiate_stream_map(&ism, mux_caps, &mut out_sm, &full_reg.enc_reg) { |
6dc69f51 KS |
1375 | println!("cannot determine stream map"); |
1376 | return; | |
1377 | } | |
1378 | ||
1379 | let ret = File::create(transcoder.output_name.as_str()); | |
1380 | if ret.is_err() { | |
1381 | println!("cannot open output file"); | |
1382 | return; | |
1383 | } | |
1384 | let mut fw = FileWriter::new_write(ret.unwrap()); | |
1385 | let mut bw = ByteWriter::new(&mut fw); | |
1386 | let ret = create_muxer(mux_creator, out_sm, &mut bw); | |
1387 | if let Err(err) = ret { | |
1388 | println!("cannot create muxer instance {:?}", err); | |
1389 | return; | |
1390 | } | |
1391 | let mut mux = ret.unwrap(); | |
1392 | parse_and_apply_options!(mux, &transcoder.mux_opts, "output"); | |
1393 | ||
1394 | println!("Output {} muxer {}", transcoder.output_name, ofmt); | |
1395 | for ostr in mux.get_streams() { | |
1396 | println!(" #{}: {} {}", ostr.get_num(), ostr, ostr.get_info().get_name()); | |
1397 | } | |
1398 | ||
5ec8115f KS |
1399 | let mut time = Instant::now(); |
1400 | let show_interval = Duration::from_millis(100); | |
908ba48c KS |
1401 | let mut adata_size = 0; |
1402 | let mut vdata_size = 0; | |
4a835a2a | 1403 | let mut cur_dmx = 0; |
951916e8 | 1404 | 'main_loop: loop { |
4a835a2a KS |
1405 | let mut pktres = Err(DemuxerError::EOF); |
1406 | let mut src_dmx = 0; | |
1407 | loop { | |
1408 | if !demuxers.iter().any(|(_, eof)| !eof) { | |
1409 | break; | |
1410 | } | |
1411 | let mut got_res = false; | |
1412 | if !demuxers[cur_dmx].1 { | |
1413 | pktres = demuxers[cur_dmx].0.get_frame(); | |
1414 | got_res = true; | |
1415 | src_dmx = cur_dmx; | |
1416 | } | |
1417 | cur_dmx += 1; | |
1418 | if cur_dmx >= demuxers.len() { | |
1419 | cur_dmx = 0; | |
1420 | } | |
1421 | if got_res { | |
1422 | break; | |
1423 | } | |
1424 | } | |
1425 | ||
6dc69f51 KS |
1426 | if let Err(DemuxerError::EOF) = pktres { break; } |
1427 | if pktres.is_err() { | |
1428 | println!("demuxing error"); | |
1429 | break; | |
1430 | } | |
1431 | let mut pkt = pktres.unwrap(); | |
f88b8fb4 | 1432 | if transcoder.start != NATimePoint::None && pkt.ts.less_than(transcoder.start) { continue; } |
4a835a2a KS |
1433 | let src_id = pkt.get_stream().get_num() + is_offset[src_dmx]; |
1434 | let ts = pkt.ts; | |
1435 | let newstream = ism.get_stream(src_id).unwrap(); | |
1436 | pkt.reassign(newstream, ts); | |
1437 | ||
908ba48c | 1438 | if transcoder.verbose > 0 && time.elapsed() >= show_interval { |
5ec8115f KS |
1439 | if let Some(pts) = pkt.get_pts() { |
1440 | let cur_time = format_time(NATimeInfo::ts_to_time(pts, 1000, pkt.ts.tb_num, pkt.ts.tb_den)); | |
1441 | print!(" {}", cur_time); | |
1442 | } else { | |
1443 | print!(" ???"); | |
1444 | } | |
1445 | if !duration_string.is_empty() { | |
1446 | print!(" / {}", duration_string); | |
1447 | } | |
908ba48c KS |
1448 | if transcoder.verbose > 1 { |
1449 | print!(" data sizes V: {} A: {}", vdata_size, adata_size); | |
1450 | } | |
5ec8115f KS |
1451 | print!("\r"); |
1452 | std::io::stdout().flush().unwrap(); | |
1453 | time = Instant::now(); | |
1454 | } | |
6dc69f51 KS |
1455 | match transcoder.encoders[src_id] { |
1456 | OutputMode::Drop => {}, | |
1457 | OutputMode::Copy(dst_id) => { | |
1458 | let dstr = mux.get_stream(dst_id as usize).unwrap(); | |
1459 | pkt.reassign(dstr, pkt.get_time_information()); | |
951916e8 | 1460 | if transcoder.end != NATimePoint::None && !pkt.ts.less_than(transcoder.end) { break 'main_loop; } |
908ba48c KS |
1461 | let pkt_size = pkt.get_buffer().len(); |
1462 | match pkt.get_stream().get_media_type() { | |
1463 | StreamType::Video => { vdata_size += pkt_size; }, | |
1464 | StreamType::Audio => { adata_size += pkt_size; }, | |
1465 | _ => {}, | |
1466 | }; | |
6dc69f51 KS |
1467 | if mux.mux_frame(pkt).is_err() { |
1468 | println!("error muxing packet"); | |
1469 | break; | |
1470 | } | |
1471 | }, | |
1472 | OutputMode::Encode(dst_id, ref mut encoder, ref mut cvt) => { | |
d9fe2b71 | 1473 | if let Some((ref mut dsupp, ref mut decoder, ref mut reorderer)) = transcoder.decoders[src_id] { |
6dc69f51 | 1474 | let ret = decoder.decode(dsupp, &pkt); |
f88b8fb4 KS |
1475 | if let (true, Err(DecoderError::MissingReference)) = (transcoder.start != NATimePoint::None, &ret) { |
1476 | continue; | |
1477 | } | |
6dc69f51 KS |
1478 | if ret.is_err() { |
1479 | println!("error decoding stream {}", src_id); | |
1480 | break; | |
1481 | } | |
1482 | let frm = ret.unwrap(); | |
b0481c9e | 1483 | let tinfo = frm.get_info(); |
d9fe2b71 KS |
1484 | reorderer.add_frame(frm); |
1485 | while let Some(frm) = reorderer.get_frame() { | |
df37d3b1 | 1486 | if !encode_frame(dst_id, encoder, cvt, frm, &transcoder.scale_opts) { |
d9fe2b71 KS |
1487 | break; |
1488 | } | |
1489 | while let Ok(Some(pkt)) = encoder.get_packet() { | |
1490 | if transcoder.end != NATimePoint::None && !pkt.ts.less_than(transcoder.end) { break 'main_loop; } | |
908ba48c KS |
1491 | let pkt_size = pkt.get_buffer().len(); |
1492 | match pkt.get_stream().get_media_type() { | |
1493 | StreamType::Video => { vdata_size += pkt_size; }, | |
1494 | StreamType::Audio => { adata_size += pkt_size; }, | |
1495 | _ => {}, | |
1496 | }; | |
d9fe2b71 KS |
1497 | mux.mux_frame(pkt).unwrap(); |
1498 | } | |
6dc69f51 | 1499 | } |
b0481c9e KS |
1500 | if let OutputConvert::Audio(ref mut acvt) = cvt { |
1501 | while let Some(ofrm) = acvt.get_frame(tinfo.clone()) { | |
1502 | if encoder.encode(&ofrm).is_err() { | |
1503 | break; | |
1504 | } | |
1505 | while let Ok(Some(pkt)) = encoder.get_packet() { | |
1506 | if transcoder.end != NATimePoint::None && !pkt.ts.less_than(transcoder.end) { break 'main_loop; } | |
1507 | let pkt_size = pkt.get_buffer().len(); | |
1508 | adata_size += pkt_size; | |
1509 | mux.mux_frame(pkt).unwrap(); | |
1510 | } | |
1511 | } | |
1512 | } | |
6dc69f51 KS |
1513 | } else { |
1514 | println!("no decoder for stream {}", src_id); | |
1515 | break; | |
1516 | } | |
1517 | }, | |
1518 | }; | |
1519 | } | |
4a835a2a | 1520 | 'reord_flush_loop: for stream in ism.iter() { |
fd03a232 | 1521 | let src_id = stream.get_num(); |
d9fe2b71 KS |
1522 | if let OutputMode::Encode(dst_id, ref mut encoder, ref mut cvt) = transcoder.encoders[src_id] { |
1523 | if let Some((_, _, ref mut reorderer)) = transcoder.decoders[src_id] { | |
1524 | while let Some(frm) = reorderer.get_last_frames() { | |
df37d3b1 | 1525 | if !encode_frame(dst_id, encoder, cvt, frm, &transcoder.scale_opts) { |
d9fe2b71 KS |
1526 | break; |
1527 | } | |
1528 | while let Ok(Some(pkt)) = encoder.get_packet() { | |
1529 | if transcoder.end != NATimePoint::None && !pkt.ts.less_than(transcoder.end) { break 'reord_flush_loop; } | |
1530 | mux.mux_frame(pkt).unwrap(); | |
1531 | } | |
1532 | } | |
1533 | } | |
1534 | } | |
1535 | } | |
6dc69f51 KS |
1536 | 'flush_loop: for enc in transcoder.encoders.iter_mut() { |
1537 | match enc { | |
1538 | OutputMode::Encode(str_id, ref mut encoder, _) => { | |
1539 | let ret = encoder.flush(); | |
1540 | if ret.is_err() { | |
1541 | println!("error flushing encoder for stream {}", str_id); | |
1542 | break; | |
1543 | } else { | |
1544 | while let Ok(Some(pkt)) = encoder.get_packet() { | |
1545 | if mux.mux_frame(pkt).is_err() { | |
1546 | println!("error muxing packet"); | |
1547 | break 'flush_loop; | |
1548 | } | |
1549 | } | |
1550 | } | |
1551 | }, | |
1552 | _ => {}, | |
1553 | }; | |
1554 | } | |
908ba48c | 1555 | if transcoder.verbose > 0 { |
5ec8115f KS |
1556 | println!(); |
1557 | } | |
6dc69f51 KS |
1558 | |
1559 | let ret = mux.end(); | |
1560 | if ret.is_err() { | |
1561 | println!("error at finalising muxing"); | |
1562 | } | |
1563 | } |