]> git.nihav.org Git - nihav-encoder.git/blobdiff - src/main.rs
duplicate last frame when the encoder does not support skip frames
[nihav-encoder.git] / src / main.rs
index 409c677a5c4f2e81179e1ccd9e4480df7746e4c2..1e77521d4d6fce2e438dba03ef05d3c2c42122d6 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,8 @@ use std::time::{Duration, Instant};
 mod demux;
 use crate::demux::*;
 mod null;
+mod acvt;
+use crate::acvt::*;
 
 fn format_time(ms: u64) -> String {
     let s = ms / 1000;
@@ -50,6 +51,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 +103,7 @@ struct OutputStreamOptions {
 
 enum OutputConvert {
     Video(NAScale, NABufferType),
-    Audio(NAAudioInfo, NAChannelMap),
+    Audio(AudioConverter),
     None,
 }
 
@@ -358,7 +391,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 {
@@ -517,8 +550,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 +629,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,
@@ -708,10 +743,16 @@ fn encode_frame(dst_id: u32, encoder: &mut Box<dyn NAEncoder>, cvt: &mut OutputC
     let buf = frm.get_buffer();
     let cbuf = if let NABufferType::None = buf {
         if (encoder.get_capabilities() & ENC_CAPS_SKIPFRAME) == 0 {
-            println!("encoder does not support skip frames, skipping");
-            return true;
+            match cvt {
+                OutputConvert::Video(_, ref mut dbuf) => dbuf.clone(),
+                _ => {
+                    println!("encoder does not support skip frames, skipping");
+                    return true;
+                },
+            }
+        } else {
+            buf
         }
-        buf
     } else {
         match cvt {
             OutputConvert::None => buf,
@@ -734,13 +775,12 @@ 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;
             },
         }
     };
@@ -1170,6 +1210,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) {
@@ -1186,6 +1227,19 @@ println!("stream {} - {} {}", i, s, info.get_name());
                             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;