]> git.nihav.org Git - nihav-encoder.git/blobdiff - src/main.rs
fix clippy warnings
[nihav-encoder.git] / src / main.rs
index fdab8438f8ecbcc8776eb5eb3775e64e6f5ddd19..e033dfd1040cd3d7b5eb965b351e1c8d926ce309 100644 (file)
@@ -13,7 +13,6 @@ use nihav_core::demuxers::*;
 use nihav_core::muxers::*;
 use nihav_core::reorder::*;
 use nihav_core::scale::*;
-use nihav_core::soundcvt::*;
 use nihav_registry::detect;
 use nihav_registry::register;
 use std::env;
@@ -22,6 +21,10 @@ use std::time::{Duration, Instant};
 mod demux;
 use crate::demux::*;
 mod null;
+mod acvt;
+use crate::acvt::*;
+
+const SND_NO_FORMAT: NASoniton = NASoniton { bits: 0, be: false, packed: false, planar: false, float: false, signed: false };
 
 fn format_time(ms: u64) -> String {
     let s = ms / 1000;
@@ -50,6 +53,38 @@ fn print_options(name: &str, options: &[NAOptionDefinition]) {
     }
 }
 
+fn parse_bitrate(strval: &str) -> Result<u32, ()> {
+    let mut val = 0;
+    let mut has_suffix = false;
+    for ch in strval.chars() {
+        match ch {
+            _ if has_suffix => return Err(()),
+            '0'..='9' => {
+                if val >= std::u32::MAX / 100 {
+                    return Err(());
+                }
+                val = val * 10 + ch.to_digit(10).unwrap_or(0);
+            },
+            'k' | 'K' => {
+                if val >= std::u32::MAX / 1000 {
+                    return Err(());
+                }
+                val *= 1000;
+                has_suffix = true;
+            },
+            'm' | 'M' => {
+                if val >= std::u32::MAX / 1000000 {
+                    return Err(());
+                }
+                val *= 1000000;
+                has_suffix = true;
+            },
+            _ => return Err(()),
+        };
+    }
+    Ok(val)
+}
+
 struct OptionArgs {
     name:   String,
     value:  Option<String>,
@@ -70,7 +105,7 @@ struct OutputStreamOptions {
 
 enum OutputConvert {
     Video(NAScale, NABufferType),
-    Audio(NAAudioInfo, NAChannelMap),
+    Audio(AudioConverter),
     None,
 }
 
@@ -99,7 +134,7 @@ struct Transcoder {
     no_audio:       bool,
     start:          NATimePoint,
     end:            NATimePoint,
-    verbose:        bool,
+    verbose:        u8,
 }
 
 macro_rules! parse_and_apply_options {
@@ -115,7 +150,7 @@ macro_rules! parse_and_apply_options {
                     matches = name == opt_def.name;
                 }
                 if matches {
-                    let arg = if let Some(ref str) = opt.value { Some(str) } else { None };
+                    let arg = if let Some(ref strval) = opt.value { Some(strval) } else { None };
                     let ret = opt_def.parse(&opt.name, arg);
                     if let Ok((val, _)) = ret {
                         opts.push(val);
@@ -141,7 +176,7 @@ impl Transcoder {
         if ret.is_err() { return false; }
         let streamno = ret.unwrap();
 
-        let sidx = if let Some(idx) = self.istr_opts.iter().position(|str| str.id == streamno) {
+        let sidx = if let Some(idx) = self.istr_opts.iter().position(|el| el.id == streamno) {
                 idx
             } else {
                 self.istr_opts.push(InputStreamOptions {id: streamno, drop: false, dec_opts: Vec::new() });
@@ -172,7 +207,7 @@ impl Transcoder {
         if ret.is_err() { return false; }
         let streamno = ret.unwrap();
 
-        let sidx = if let Some(idx) = self.ostr_opts.iter().position(|str| str.id == streamno) {
+        let sidx = if let Some(idx) = self.ostr_opts.iter().position(|el| el.id == streamno) {
                 idx
             } else {
                 self.ostr_opts.push(OutputStreamOptions {id: streamno, enc_name: String::new(), enc_params: EncodeParameters::default(), enc_opts: Vec::new() });
@@ -283,7 +318,7 @@ impl Transcoder {
                     },
                     "srate" => {
                         if ostr.enc_params.format == NACodecTypeInfo::None {
-                            ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_S16_FORMAT, 0));
+                            ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_NO_FORMAT, 0));
                         }
                         if let NACodecTypeInfo::Audio(ref mut ainfo) = ostr.enc_params.format {
                             let ret = oval[1].parse::<u32>();
@@ -298,7 +333,7 @@ impl Transcoder {
                     },
                     "channels" => {
                         if ostr.enc_params.format == NACodecTypeInfo::None {
-                            ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_S16_FORMAT, 0));
+                            ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_NO_FORMAT, 0));
                         }
                         if let NACodecTypeInfo::Audio(ref mut ainfo) = ostr.enc_params.format {
                             let ret = oval[1].parse::<u8>();
@@ -313,7 +348,7 @@ impl Transcoder {
                     },
                     "block_len" => {
                         if ostr.enc_params.format == NACodecTypeInfo::None {
-                            ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_S16_FORMAT, 0));
+                            ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_NO_FORMAT, 0));
                         }
                         if let NACodecTypeInfo::Audio(ref mut ainfo) = ostr.enc_params.format {
                             let ret = oval[1].parse::<usize>();
@@ -328,7 +363,7 @@ impl Transcoder {
                     },
                     "sfmt" => {
                         if ostr.enc_params.format == NACodecTypeInfo::None {
-                            ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_S16_FORMAT, 0));
+                            ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_NO_FORMAT, 0));
                         }
                         if let NACodecTypeInfo::Audio(ref mut ainfo) = ostr.enc_params.format {
                             let ret = oval[1].parse::<NASoniton>();
@@ -344,7 +379,7 @@ impl Transcoder {
 // todo channel map negotiation
                     /*"chmap" => {
                         if ostr.enc_params.format == NACodecTypeInfo::None {
-                            ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_S16_FORMAT, 0));
+                            ostr.enc_params.format = NACodecTypeInfo::Audio(NAAudioInfo::new(0, 0, SND_NO_FORMAT, 0));
                         }
                         if let NACodecTypeInfo::Audio(ref mut ainfo) = ostr.enc_params.format {
                             let ret = oval[1].parse::<NAChannelMap>();
@@ -358,7 +393,7 @@ impl Transcoder {
                         }
                     },*/
                     "bitrate" => {
-                        let ret = oval[1].parse::<u32>();
+                        let ret = parse_bitrate(oval[1]);
                         if let Ok(val) = ret {
                             ostr.enc_params.bitrate = val;
                         } else {
@@ -440,7 +475,7 @@ impl Transcoder {
         true
     }
     fn apply_decoder_options(&self, dec: &mut dyn NADecoder, str_id: u32) {
-        if let Some(str_idx) = self.istr_opts.iter().position(|str| str.id == str_id) {
+        if let Some(str_idx) = self.istr_opts.iter().position(|el| el.id == str_id) {
             let dec_opts = dec.get_supported_options();
             if dec_opts.is_empty() { return; }
             let name = format!("input stream {}", str_id);
@@ -449,14 +484,14 @@ impl Transcoder {
     }
     fn register_output_stream(&mut self, cname: &str, istr: NAStreamRef, out_sm: &mut StreamManager, enc_reg: &RegisteredEncoders) -> bool {
         let out_id = out_sm.get_num_streams() as u32;
-        if let Some(str_idx) = self.istr_opts.iter().position(|str| str.id == (istr.get_num() as u32)) {
+        if let Some(str_idx) = self.istr_opts.iter().position(|el| el.id == (istr.get_num() as u32)) {
             if self.istr_opts[str_idx].drop {
                 self.encoders.push(OutputMode::Drop);
                 return true;
             }
         }
 
-        if let Some(str_idx) = self.ostr_opts.iter().position(|str| str.id == out_id) {
+        if let Some(str_idx) = self.ostr_opts.iter().position(|el| el.id == out_id) {
             let oopts = &mut self.ostr_opts[str_idx];
             if oopts.enc_name.as_str() == "copy" && (cname == "any" || istr.get_info().get_name() == cname) {
                 out_sm.add_stream_ref(istr);
@@ -469,8 +504,35 @@ impl Transcoder {
                 }
                 let mut encoder = (enc_create.unwrap())();
                 let forced_out = oopts.enc_params.format != NACodecTypeInfo::None;
+                let iformat = istr.get_info().get_properties();
                 if oopts.enc_params.format == NACodecTypeInfo::None {
                     oopts.enc_params.format = istr.get_info().get_properties();
+                } else {
+                    match (&iformat, &mut oopts.enc_params.format) {
+                        (NACodecTypeInfo::Video(svinfo), NACodecTypeInfo::Video(ref mut dvinfo)) => {
+                            if dvinfo.width == 0 {
+                                dvinfo.width = svinfo.width;
+                            }
+                            if dvinfo.height == 0 {
+                                dvinfo.height = svinfo.height;
+                            }
+                        },
+                        (NACodecTypeInfo::Audio(sainfo), NACodecTypeInfo::Audio(ref mut dainfo)) => {
+                            if dainfo.sample_rate == 0 {
+                                dainfo.sample_rate = sainfo.sample_rate;
+                            }
+                            if dainfo.format == SND_NO_FORMAT {
+                                dainfo.format = sainfo.format;
+                            }
+                            if dainfo.channels == 0 {
+                                dainfo.channels = sainfo.channels;
+                            }
+                            if dainfo.block_len == 0 {
+                                dainfo.block_len = sainfo.block_len;
+                            }
+                        },
+                        _ => {},
+                    };
                 }
                 if oopts.enc_params.tb_num == 0 {
                     oopts.enc_params.tb_num = istr.tb_num;
@@ -484,7 +546,7 @@ impl Transcoder {
                 let ret_eparams = ret_eparams.unwrap();
 
 //todo check for params mismatch
-                let cvt = match (&oopts.enc_params.format, &ret_eparams.format) {
+                let cvt = match (&iformat, &ret_eparams.format) {
                         (NACodecTypeInfo::Video(svinfo), NACodecTypeInfo::Video(dvinfo)) => {
                             if svinfo == dvinfo && !forced_out {
                                 OutputConvert::None
@@ -517,8 +579,9 @@ println!("can't generate default channel map for {} channels", dainfo.channels);
                                             return false;
                                         },
                                     };
+                                let acvt = AudioConverter::new(sainfo, dainfo, dchmap);
 //todo channelmap
-                                OutputConvert::Audio(*dainfo, dchmap)
+                                OutputConvert::Audio(acvt)
                             }
                         },
                         _ => OutputConvert::None,
@@ -595,7 +658,8 @@ println!("can't generate default channel map for {} channels", dainfo.channels);
                                     },
                                 };
 //todo channelmap
-                            OutputConvert::Audio(*dainfo, dchmap)
+                            let acvt = AudioConverter::new(sainfo, dainfo, dchmap);
+                            OutputConvert::Audio(acvt)
                         }
                     },
                     _ => OutputConvert::None,
@@ -706,7 +770,20 @@ println!("can't generate default channel map for {} channels", dainfo.channels);
 
 fn encode_frame(dst_id: u32, encoder: &mut Box<dyn NAEncoder>, cvt: &mut OutputConvert, frm: NAFrameRef, scale_opts: &[(String, String)]) -> bool {
     let buf = frm.get_buffer();
-    let cbuf = match cvt {
+    let cbuf = if let NABufferType::None = buf {
+        if (encoder.get_capabilities() & ENC_CAPS_SKIPFRAME) == 0 {
+            match cvt {
+                OutputConvert::Video(_, ref mut dbuf) => dbuf.clone(),
+                _ => {
+                    println!("encoder does not support skip frames, skipping");
+                    return true;
+                },
+            }
+        } else {
+            buf
+        }
+    } else {
+        match cvt {
             OutputConvert::None => buf,
             OutputConvert::Video(ref mut scaler, ref mut dbuf) => {
                 let cur_ifmt = get_scale_fmt_from_pic(&buf);
@@ -727,15 +804,15 @@ fn encode_frame(dst_id: u32, encoder: &mut Box<dyn NAEncoder>, cvt: &mut OutputC
                 }
                 dbuf.clone()
             },
-            OutputConvert::Audio(ref dinfo, ref dchmap) => {
-                let ret = convert_audio_frame(&buf, dinfo, dchmap);
-                if ret.is_err() {
+            OutputConvert::Audio(ref mut acvt) => {
+                if !acvt.queue_frame(buf, frm.get_time_information()) {
                     println!("error converting audio for stream {}", dst_id);
                     return false;
                 }
-                ret.unwrap()
+                return true;
             },
-        };
+        }
+    };
     let cfrm = NAFrame::new(frm.get_time_information(), frm.frame_type, frm.key, frm.get_info(), cbuf);
     encoder.encode(&cfrm).unwrap();
     true
@@ -765,6 +842,7 @@ fn main() {
         println!("  --list-{{decoders,encoders,demuxers,muxers}} - lists all available decoders/encoders/demuxers/muxers");
         println!("  --query-{{decoder,encoder,demuxer,muxer}}-options name - lists all options recognized by that decoder/encoder/demuxer/muxer");
         println!(" processing options:");
+        println!("  --verbose                   - show time for the currently processed input");
         println!("  --input inputfile           - set input file");
         println!("  --input-format fmt          - force input format");
         println!("  --demuxer-options options   - set input demuxer options");
@@ -949,7 +1027,9 @@ fn main() {
                     return;
                 }
             },
-            "--verbose" | "-v" => transcoder.verbose = true,
+            "--verbose" | "-v" => transcoder.verbose = 1,
+            "-vv" => transcoder.verbose = 2,
+            "-v-" => transcoder.verbose = 0,
             _ => {
                 if args[arg_idx].starts_with("--istream") {
                     let opt0 = &args[arg_idx];
@@ -1057,10 +1137,12 @@ println!("stream {} - {} {}", i, s, info.get_name());
         }
     }
 
-    let output_fmt = if let Some(ref str) = transcoder.output_fmt {
-            str
-        } else if let Some(str) = detect::detect_format_by_name(transcoder.output_name.as_str()) {
-            str
+    let output_fmt = if let Some(ref fmtname) = transcoder.output_fmt {
+            fmtname
+        } else if transcoder.output_name.as_str() == "/dev/null" {
+            "null"
+        } else if let Some(fmtname) = detect::detect_format_by_name(transcoder.output_name.as_str()) {
+            fmtname
         } else {
             println!("Cannot guess muxer for output");
             return;
@@ -1102,6 +1184,8 @@ println!("stream {} - {} {}", i, s, info.get_name());
 
     let mut time = Instant::now();
     let show_interval = Duration::from_millis(100);
+    let mut adata_size = 0;
+    let mut vdata_size = 0;
     'main_loop: loop {
         let pktres = dmx.get_frame();
         if let Err(DemuxerError::EOF) = pktres { break; }
@@ -1112,7 +1196,7 @@ println!("stream {} - {} {}", i, s, info.get_name());
         let mut pkt = pktres.unwrap();
         if transcoder.start != NATimePoint::None && pkt.ts.less_than(transcoder.start) { continue; }
         let src_id = pkt.get_stream().get_num();
-        if transcoder.verbose && time.elapsed() >= show_interval {
+        if transcoder.verbose > 0 && time.elapsed() >= show_interval {
             if let Some(pts) = pkt.get_pts() {
                  let cur_time = format_time(NATimeInfo::ts_to_time(pts, 1000, pkt.ts.tb_num, pkt.ts.tb_den));
                 print!(" {}", cur_time);
@@ -1122,6 +1206,9 @@ println!("stream {} - {} {}", i, s, info.get_name());
             if !duration_string.is_empty() {
                 print!(" / {}", duration_string);
             }
+            if transcoder.verbose > 1 {
+                print!(" data sizes V: {} A: {}", vdata_size, adata_size);
+            }
             print!("\r");
             std::io::stdout().flush().unwrap();
             time = Instant::now();
@@ -1132,6 +1219,12 @@ println!("stream {} - {} {}", i, s, info.get_name());
                 let dstr = mux.get_stream(dst_id as usize).unwrap();
                 pkt.reassign(dstr, pkt.get_time_information());
                 if transcoder.end != NATimePoint::None && !pkt.ts.less_than(transcoder.end) { break 'main_loop; }
+                let pkt_size = pkt.get_buffer().len();
+                match pkt.get_stream().get_media_type() {
+                    StreamType::Video => { vdata_size += pkt_size; },
+                    StreamType::Audio => { adata_size += pkt_size; },
+                    _ => {},
+                };
                 if mux.mux_frame(pkt).is_err() {
                     println!("error muxing packet");
                     break;
@@ -1148,6 +1241,7 @@ println!("stream {} - {} {}", i, s, info.get_name());
                         break;
                     }
                     let frm = ret.unwrap();
+                    let tinfo = frm.get_info();
                     reorderer.add_frame(frm);
                     while let Some(frm) = reorderer.get_frame() {
                         if !encode_frame(dst_id, encoder, cvt, frm, &transcoder.scale_opts) {
@@ -1155,9 +1249,28 @@ println!("stream {} - {} {}", i, s, info.get_name());
                         }
                         while let Ok(Some(pkt)) = encoder.get_packet() {
                             if transcoder.end != NATimePoint::None && !pkt.ts.less_than(transcoder.end) { break 'main_loop; }
+                            let pkt_size = pkt.get_buffer().len();
+                            match pkt.get_stream().get_media_type() {
+                                StreamType::Video => { vdata_size += pkt_size; },
+                                StreamType::Audio => { adata_size += pkt_size; },
+                                _ => {},
+                            };
                             mux.mux_frame(pkt).unwrap();
                         }
                     }
+                    if let OutputConvert::Audio(ref mut acvt) = cvt {
+                        while let Some(ofrm) = acvt.get_frame(tinfo.clone()) {
+                            if encoder.encode(&ofrm).is_err() {
+                                break;
+                            }
+                            while let Ok(Some(pkt)) = encoder.get_packet() {
+                                if transcoder.end != NATimePoint::None && !pkt.ts.less_than(transcoder.end) { break 'main_loop; }
+                                let pkt_size = pkt.get_buffer().len();
+                                adata_size += pkt_size;
+                                mux.mux_frame(pkt).unwrap();
+                            }
+                        }
+                    }
                 } else {
                     println!("no decoder for stream {}", src_id);
                     break;
@@ -1165,8 +1278,8 @@ println!("stream {} - {} {}", i, s, info.get_name());
             },
         };
     }
-    'reord_flush_loop: for str in dmx.get_streams() {
-        let src_id = str.get_num();
+    'reord_flush_loop: for stream in dmx.get_streams() {
+        let src_id = stream.get_num();
         if let OutputMode::Encode(dst_id, ref mut encoder, ref mut cvt) = transcoder.encoders[src_id] {
             if let Some((_, _, ref mut reorderer)) = transcoder.decoders[src_id] {
                 while let Some(frm) = reorderer.get_last_frames() {
@@ -1200,7 +1313,7 @@ println!("stream {} - {} {}", i, s, info.get_name());
             _ => {},
         };
     }
-    if transcoder.verbose {
+    if transcoder.verbose > 0 {
         println!();
     }