]> git.nihav.org Git - nihav-encoder.git/commitdiff
allow encoder to work with multiple inputs
authorKostya Shishkov <kostya.shishkov@gmail.com>
Sat, 19 Aug 2023 16:02:09 +0000 (18:02 +0200)
committerKostya Shishkov <kostya.shishkov@gmail.com>
Sat, 19 Aug 2023 16:02:09 +0000 (18:02 +0200)
src/demux.rs
src/main.rs

index 61ddbaf08646d747fb052a6a61cbcd0e9f61cfe1..9f6739de3bd4559184ad2ff22adc81e147c193b2 100644 (file)
@@ -7,6 +7,7 @@ use nihav_core::io::byteio::ByteReader;
 use nihav_allstuff::*;
 use crate::null::*;
 use crate::imgseq::*;
+use crate::{SBBox, SelfBorrow};
 
 pub struct FullRegister {
     pub dmx_reg:    RegisteredDemuxers,
@@ -53,16 +54,19 @@ impl<'a> RawStreamCtx<'a> {
     }
 }
 
+type ReaderBox<'a> = SBBox<Box<dyn ByteIO>, ByteReader<'a>>;
+
 pub enum DemuxerObject<'a> {
     None,
-    Normal(Demuxer<'a>),
-    Raw(RawDemuxer<'a>, Vec<Option<Box<dyn NAPacketiser + Send>>>, bool),
-    RawStream(RawStreamCtx<'a>),
+    Normal(SBBox<ReaderBox<'a>, Demuxer<'a>>),
+    Raw(SBBox<ReaderBox<'a>, RawDemuxer<'a>>, Vec<Option<Box<dyn NAPacketiser + Send>>>, bool),
+    RawStream(SBBox<ReaderBox<'a>, RawStreamCtx<'a>>),
     ImageSequence(ImgSeqDemuxer),
 }
 
 impl<'a> DemuxerObject<'a> {
-    pub fn create(br: &'a mut ByteReader<'a>, reg: &FullRegister, name: &str, ifmt: &Option<String>, is_raw: bool) -> DemuxerObject<'a> {
+    pub fn create(mut brb: ReaderBox<'a>, reg: &FullRegister, name: &str, ifmt: &Option<String>, is_raw: bool) -> DemuxerObject<'a> {
+        let br = brb.get_object_mut();
         if !is_raw {
             let dmx_name = if let Some(ref dname) = ifmt {
                     dname.as_str()
@@ -76,7 +80,12 @@ impl<'a> DemuxerObject<'a> {
                 println!("trying demuxer {} on {}", dmx_name, name);
                 if let Some(dmx_fact) = reg.dmx_reg.find_demuxer(dmx_name) {
                     br.seek(SeekFrom::Start(0)).unwrap();
-                    let dmx = create_demuxer(dmx_fact, br).unwrap();
+
+                    let dmx = SelfBorrow::new(brb, |br_| {
+                            unsafe {
+                                create_demuxer(dmx_fact, br_.as_mut().unwrap().get_object_mut()).unwrap()
+                            }
+                        });
                     return DemuxerObject::Normal(dmx);
                 }
             }
@@ -87,9 +96,13 @@ impl<'a> DemuxerObject<'a> {
                 println!("trying raw demuxer {} on {}", dmx_name, name);
                 if let Some(rdmx_fact) = reg.rdmx_reg.find_demuxer(dmx_name) {
                     br.seek(SeekFrom::Start(0)).unwrap();
-                    let dmx = create_raw_demuxer(rdmx_fact, br).unwrap();
+                    let dmx = SelfBorrow::new(brb, |br_| {
+                            unsafe {
+                                create_raw_demuxer(rdmx_fact, br_.as_mut().unwrap().get_object_mut()).unwrap()
+                            }
+                        });
                     let mut pkts = Vec::new();
-                    for stream in dmx.get_streams() {
+                    for stream in dmx.get_object().get_streams() {
                         if let Some(pcreate) = reg.pkt_reg.find_packetiser(stream.get_info().get_name()) {
                             let packetiser = (pcreate)();
                             pkts.push(Some(packetiser));
@@ -104,9 +117,13 @@ impl<'a> DemuxerObject<'a> {
                 if rdmx.check_format(br) {
                     println!("detected {} as {}", name, rdmx.get_name());
                     br.seek(SeekFrom::Start(0)).unwrap();
-                    let dmx = create_raw_demuxer(*rdmx, br).unwrap();
+                    let dmx = SelfBorrow::new(brb, |br_| {
+                            unsafe {
+                                create_raw_demuxer(*rdmx, br_.as_mut().unwrap().get_object_mut()).unwrap()
+                            }
+                        });
                     let mut pkts = Vec::new();
-                    for stream in dmx.get_streams() {
+                    for stream in dmx.get_object().get_streams() {
                         if let Some(pcreate) = reg.pkt_reg.find_packetiser(stream.get_info().get_name()) {
                             let packetiser = (pcreate)();
                             pkts.push(Some(packetiser));
@@ -134,11 +151,16 @@ impl<'a> DemuxerObject<'a> {
         if !pname.is_empty() {
             println!("found raw stream of type {} for {}", pname, name);
             let pcreate = reg.pkt_reg.find_packetiser(pname).unwrap();
-            let mut packetiser = (pcreate)();
-            packetiser.add_data(&buf[..size]);
-            let stream = packetiser.parse_stream(0).unwrap();
-            packetiser.reset();
-            DemuxerObject::RawStream(RawStreamCtx::new(stream, packetiser, br))
+            let rctx = SelfBorrow::new(brb, |br_| {
+                    unsafe {
+                        let mut packetiser = (pcreate)();
+                        packetiser.add_data(&buf[..size]);
+                        let stream = packetiser.parse_stream(0).unwrap();
+                        packetiser.reset();
+                        RawStreamCtx::new(stream, packetiser, br_.as_mut().unwrap().get_object_mut())
+                    }
+                });
+            DemuxerObject::RawStream(rctx)
         } else {
             DemuxerObject::None
         }
@@ -151,10 +173,10 @@ impl<'a> DemuxerObject<'a> {
     }
     pub fn get_duration(&self) -> u64 {
         match *self {
-            DemuxerObject::Normal(ref dmx) => dmx.get_duration(),
-            DemuxerObject::Raw(ref dmx, _, _) => dmx.get_duration(),
+            DemuxerObject::Normal(ref dmx) => dmx.get_object().get_duration(),
+            DemuxerObject::Raw(ref dmx, _, _) => dmx.get_object().get_duration(),
             DemuxerObject::RawStream(ref ctx) => {
-                NATimeInfo::ts_to_time(ctx.stream.duration, 1000, ctx.stream.tb_num, ctx.stream.tb_den)
+                NATimeInfo::ts_to_time(ctx.get_object().stream.duration, 1000, ctx.get_object().stream.tb_num, ctx.get_object().stream.tb_den)
             },
             _ => 0,
         }
@@ -162,43 +184,44 @@ impl<'a> DemuxerObject<'a> {
     pub fn get_num_streams(&self) -> usize {
         match *self {
             DemuxerObject::None => 0,
-            DemuxerObject::Normal(ref dmx) => dmx.get_num_streams(),
-            DemuxerObject::Raw(ref dmx, _, _) => dmx.get_num_streams(),
+            DemuxerObject::Normal(ref dmx) => dmx.get_object().get_num_streams(),
+            DemuxerObject::Raw(ref dmx, _, _) => dmx.get_object().get_num_streams(),
             DemuxerObject::RawStream(_) => 1,
             DemuxerObject::ImageSequence(_) => 1,
         }
     }
     pub fn get_stream(&self, idx: usize) -> Option<NAStreamRef> {
         match *self {
-            DemuxerObject::Normal(ref dmx) => dmx.get_stream(idx),
-            DemuxerObject::Raw(ref dmx, _, _) => dmx.get_stream(idx),
-            DemuxerObject::RawStream(ref ctx) if idx == 0 => Some(ctx.stream.clone()),
+            DemuxerObject::Normal(ref dmx) => dmx.get_object().get_stream(idx),
+            DemuxerObject::Raw(ref dmx, _, _) => dmx.get_object().get_stream(idx),
+            DemuxerObject::RawStream(ref ctx) if idx == 0 => Some(ctx.get_object().stream.clone()),
             DemuxerObject::ImageSequence(ref ctx) if idx == 0 => Some(ctx.stream.clone()),
             _ => None,
         }
     }
-    pub fn get_streams(&self) -> StreamIter {
+    /*pub fn get_streams(&self) -> StreamIter {
         match *self {
-            DemuxerObject::Normal(ref dmx) => dmx.get_streams(),
-            DemuxerObject::Raw(ref dmx, _, _) => dmx.get_streams(),
-            DemuxerObject::RawStream(ref ctx) => ctx.sm.iter(),
+            DemuxerObject::Normal(ref dmx) => dmx.get_object().get_streams(),
+            DemuxerObject::Raw(ref dmx, _, _) => dmx.get_object().get_streams(),
+            DemuxerObject::RawStream(ref ctx) => ctx.get_object().sm.iter(),
             DemuxerObject::ImageSequence(ref ctx) => ctx.sm.iter(),
             _ => unreachable!(),
         }
-    }
+    }*/
     pub fn get_stream_manager(&self) -> &StreamManager {
         match *self {
-            DemuxerObject::Normal(ref dmx) => dmx.get_stream_manager(),
-            DemuxerObject::Raw(ref dmx, _, _) => dmx.get_stream_manager(),
-            DemuxerObject::RawStream(ref ctx) => &ctx.sm,
+            DemuxerObject::Normal(ref dmx) => dmx.get_object().get_stream_manager(),
+            DemuxerObject::Raw(ref dmx, _, _) => dmx.get_object().get_stream_manager(),
+            DemuxerObject::RawStream(ref ctx) => &ctx.get_object().sm,
             DemuxerObject::ImageSequence(ref ctx) => &ctx.sm,
             _ => unreachable!(),
         }
     }
     pub fn get_frame(&mut self) -> DemuxerResult<NAPacket> {
         match *self {
-            DemuxerObject::Normal(ref mut dmx) => dmx.get_frame(),
+            DemuxerObject::Normal(ref mut dmx) => dmx.get_object_mut().get_frame(),
             DemuxerObject::Raw(ref mut dmx, ref mut packetisers, ref mut eof) => {
+                let dmx = dmx.get_object_mut();
                 loop {
                     let mut has_some = false;
                     for (stream, p) in dmx.get_streams().zip(packetisers.iter_mut()) {
@@ -237,6 +260,7 @@ impl<'a> DemuxerObject<'a> {
                 }
             },
             DemuxerObject::RawStream(ref mut ctx) => {
+                let ctx = ctx.get_object_mut();
                 let mut buf = [0; 65536];
                 loop {
                     match ctx.packetiser.get_packet(ctx.stream.clone()) {
@@ -277,8 +301,8 @@ impl<'a> DemuxerObject<'a> {
     }
     pub fn seek(&mut self, seek_time: NATimePoint) -> DemuxerResult<()> {
         match *self {
-            DemuxerObject::Normal(ref mut dmx) => dmx.seek(seek_time),
-            DemuxerObject::Raw(ref mut dmx, _, _) => dmx.seek(seek_time),
+            DemuxerObject::Normal(ref mut dmx) => dmx.get_object_mut().seek(seek_time),
+            DemuxerObject::Raw(ref mut dmx, _, _) => dmx.get_object_mut().seek(seek_time),
             DemuxerObject::ImageSequence(ref mut ctx) => ctx.seek(seek_time),
             _ => Err(DemuxerError::NotImplemented),
         }
@@ -288,24 +312,24 @@ impl<'a> DemuxerObject<'a> {
 impl<'a> NAOptionHandler for DemuxerObject<'a> {
     fn get_supported_options(&self) -> &[NAOptionDefinition] {
         match *self {
-            DemuxerObject::Normal(ref dmx) => dmx.get_supported_options(),
-            DemuxerObject::Raw(ref dmx, _, _) => dmx.get_supported_options(),
+            DemuxerObject::Normal(ref dmx) => dmx.get_object().get_supported_options(),
+            DemuxerObject::Raw(ref dmx, _, _) => dmx.get_object().get_supported_options(),
             DemuxerObject::ImageSequence(ref ctx) => ctx.get_supported_options(),
             _ => &[],
         }
     }
     fn set_options(&mut self, options: &[NAOption]) {
         match *self {
-            DemuxerObject::Normal(ref mut dmx) => dmx.set_options(options),
-            DemuxerObject::Raw(ref mut dmx, _, _) => dmx.set_options(options),
+            DemuxerObject::Normal(ref mut dmx) => dmx.get_object_mut().set_options(options),
+            DemuxerObject::Raw(ref mut dmx, _, _) => dmx.get_object_mut().set_options(options),
             DemuxerObject::ImageSequence(ref mut ctx) => ctx.set_options(options),
             _ => {},
         }
     }
     fn query_option_value(&self, name: &str) -> Option<NAValue> {
         match *self {
-            DemuxerObject::Normal(ref dmx) => dmx.query_option_value(name),
-            DemuxerObject::Raw(ref dmx, _, _) => dmx.query_option_value(name),
+            DemuxerObject::Normal(ref dmx) => dmx.get_object().query_option_value(name),
+            DemuxerObject::Raw(ref dmx, _, _) => dmx.get_object().query_option_value(name),
             DemuxerObject::ImageSequence(ref ctx) => ctx.query_option_value(name),
             _ => None,
         }
index 97be1e2ea36367b6b833a1b61f5134cc5a5619da..9694836feedb8bccc0f7868bc118c2a6d394b3eb 100644 (file)
@@ -5,6 +5,7 @@ extern crate nihav_allstuff;
 
 use std::fs::File;
 use std::io::{BufReader, Write};
+use std::pin::Pin;
 use nihav_core::io::byteio::{FileReader, ByteReader};
 use nihav_core::frame::*;
 use nihav_core::options::*;
@@ -26,6 +27,54 @@ use crate::acvt::*;
 mod imgseq;
 use crate::imgseq::*;
 
+#[derive(Clone,Copy,Default,PartialEq)]
+enum RegisterResult {
+    #[default]
+    Ok,
+    Ignored,
+    Failed,
+}
+
+pub struct SelfBorrow<T, U> {
+    bval: T,
+    dst:  Option<U>,
+}
+
+impl<T: Unpin, U: Unpin> SelfBorrow<T, U> {
+    pub fn new<F>(src: T, create: F) -> Pin<Box<Self>>
+            where F: Fn(*mut T) -> U {
+        let mut obj = Box::pin(Self{
+            bval: src,
+            dst: None,
+        });
+        let ptr = &mut obj.bval as *mut T;
+        obj.dst = Some(create(ptr));
+        obj
+    }
+    fn get_object(&self) -> &U {
+        if let Some(ref dst) = self.dst {
+            dst
+        } else {
+            unreachable!()
+        }
+    }
+    fn get_object_mut(&mut self) -> &mut U {
+        if let Some(ref mut dst) = self.dst {
+            dst
+        } else {
+            unreachable!()
+        }
+    }
+}
+
+impl<T, U> Drop for SelfBorrow<T, U> {
+    fn drop(&mut self) {
+        self.dst = None;
+    }
+}
+
+pub type SBBox<T, U> = Pin<Box<SelfBorrow<T, U>>>;
+
 const SND_NO_FORMAT: NASoniton = NASoniton { bits: 0, be: false, packed: false, planar: false, float: false, signed: false };
 
 fn format_time(ms: u64) -> String {
@@ -121,11 +170,11 @@ enum OutputMode {
 #[derive(Default)]
 #[allow(clippy::type_complexity)]
 struct Transcoder {
-    input_name:     String,
-    input_fmt:      Option<String>,
+    input_name:     [Option<String>; 16],
+    input_fmt:      [Option<String>; 16],
     output_name:    String,
     output_fmt:     Option<String>,
-    demux_opts:     Vec<OptionArgs>,
+    demux_opts:     [Vec<OptionArgs>; 16],
     mux_opts:       Vec<OptionArgs>,
     istr_opts:      Vec<InputStreamOptions>,
     ostr_opts:      Vec<OutputStreamOptions>,
@@ -420,20 +469,20 @@ impl Transcoder {
         }
         true
     }
-    fn parse_demuxer_options(&mut self, opts: &str, dmx_reg: &RegisteredDemuxers) -> bool {
+    fn parse_demuxer_options(&mut self, opts: &str, dmx_reg: &RegisteredDemuxers, input_no: usize) -> bool {
         for opt in opts.split(',') {
             let oval: Vec<_> = opt.split('=').collect();
             if oval.len() == 1 {
-                self.demux_opts.push(OptionArgs{ name: oval[0].to_string(), value: None });
+                self.demux_opts[input_no].push(OptionArgs{ name: oval[0].to_string(), value: None });
             } else if oval.len() == 2 {
                 if oval[0] == "format" {
                     if dmx_reg.find_demuxer(oval[1]).is_some() {
-                        self.input_fmt = Some(oval[1].to_string());
+                        self.input_fmt[input_no] = Some(oval[1].to_string());
                     } else {
                         println!("unknown demuxer format '{}'", oval[1]);
                     }
                 } else {
-                    self.demux_opts.push(OptionArgs{ name: oval[0].to_string(), value: Some(oval[1].to_string()) });
+                    self.demux_opts[input_no].push(OptionArgs{ name: oval[0].to_string(), value: Some(oval[1].to_string()) });
                 }
             } else {
                 println!("unrecognized option '{}'", opt);
@@ -484,25 +533,25 @@ impl Transcoder {
             parse_and_apply_options!(dec, &self.istr_opts[str_idx].dec_opts, name);
         }
     }
-    fn register_output_stream(&mut self, cname: &str, istr: NAStreamRef, out_sm: &mut StreamManager, enc_reg: &RegisteredEncoders) -> bool {
+    fn register_output_stream(&mut self, cname: &str, istr: NAStreamRef, out_sm: &mut StreamManager, enc_reg: &RegisteredEncoders) -> RegisterResult {
         let out_id = out_sm.get_num_streams() 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;
+                return RegisterResult::Ignored;
             }
         }
 
         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);
+                out_sm.add_stream((*istr).clone());
                 self.encoders.push(OutputMode::Copy(out_id));
             } else if cname == "any" || oopts.enc_name.as_str() == cname {
                 let enc_create = enc_reg.find_encoder(oopts.enc_name.as_str());
                 if enc_create.is_none() {
                     println!("encoder '{}' not found", oopts.enc_name.as_str());
-                    return false;
+                    return RegisterResult::Failed;
                 }
                 let mut encoder = (enc_create.unwrap())();
                 let forced_out = oopts.enc_params.format != NACodecTypeInfo::None;
@@ -543,7 +592,7 @@ impl Transcoder {
                 let ret_eparams = encoder.negotiate_format(&oopts.enc_params);
                 if ret_eparams.is_err() {
                     println!("cannot negotiate encoding parameters");
-                    return false;
+                    return RegisterResult::Failed;
                 }
                 let ret_eparams = ret_eparams.unwrap();
 
@@ -557,13 +606,13 @@ impl Transcoder {
                                 let ret = NAScale::new_with_options(ofmt, ofmt, &self.scale_opts);
                                 if ret.is_err() {
                                     println!("cannot create scaler");
-                                    return false;
+                                    return RegisterResult::Failed;
                                 }
                                 let scaler = ret.unwrap();
                                 let ret = alloc_video_buffer(*dvinfo, 4);
                                 if ret.is_err() {
                                     println!("cannot create scaler buffer");
-                                    return false;
+                                    return RegisterResult::Failed;
                                 }
                                 let cvt_buf = ret.unwrap();
                                 OutputConvert::Video(scaler, cvt_buf)
@@ -578,7 +627,7 @@ impl Transcoder {
                                         2 => NAChannelMap::from_ms_mapping(0x3),
                                         _ => {
 println!("can't generate default channel map for {} channels", dainfo.channels);
-                                            return false;
+                                            return RegisterResult::Failed;
                                         },
                                     };
                                 let acvt = AudioConverter::new(sainfo, dainfo, dchmap);
@@ -591,7 +640,7 @@ println!("can't generate default channel map for {} channels", dainfo.channels);
                 let ret = encoder.init(out_id, ret_eparams);
                 if ret.is_err() {
                     println!("error initialising encoder");
-                    return false;
+                    return RegisterResult::Failed;
                 }
                 out_sm.add_stream_ref(ret.unwrap());
 
@@ -601,10 +650,10 @@ println!("can't generate default channel map for {} channels", dainfo.channels);
                 self.encoders.push(OutputMode::Encode(out_id, encoder, cvt));
             } else {
 println!("encoder {} is not supported by output (expected {})", istr.id, istr.get_info().get_name());
-                return false;
+                return RegisterResult::Failed;
             }
         } else if cname == "any" || istr.get_info().get_name() == cname {
-            out_sm.add_stream_ref(istr);
+            out_sm.add_stream((*istr).clone());
             self.encoders.push(OutputMode::Copy(out_id));
         } else {
             let mut oopts = OutputStreamOptions {id: out_id, enc_name: cname.to_owned(), enc_params: EncodeParameters::default(), enc_opts: Vec::new() };
@@ -612,7 +661,7 @@ println!("encoder {} is not supported by output (expected {})", istr.id, istr.ge
             let enc_create = enc_reg.find_encoder(cname);
             if enc_create.is_none() {
                 println!("encoder '{}' not found", oopts.enc_name.as_str());
-                return false;
+                return RegisterResult::Failed;
             }
             let mut encoder = (enc_create.unwrap())();
             oopts.enc_params.format = istr.get_info().get_properties();
@@ -621,7 +670,7 @@ println!("encoder {} is not supported by output (expected {})", istr.id, istr.ge
             let ret_eparams = encoder.negotiate_format(&oopts.enc_params);
             if ret_eparams.is_err() {
                 println!("cannot negotiate encoding parameters");
-                return false;
+                return RegisterResult::Failed;
             }
             let ret_eparams = ret_eparams.unwrap();
 
@@ -635,13 +684,13 @@ println!("encoder {} is not supported by output (expected {})", istr.id, istr.ge
                             let ret = NAScale::new_with_options(ofmt, ofmt, &self.scale_opts);
                             if ret.is_err() {
                                 println!("cannot create scaler");
-                                return false;
+                                return RegisterResult::Failed;
                             }
                             let scaler = ret.unwrap();
                             let ret = alloc_video_buffer(*dvinfo, 4);
                             if ret.is_err() {
                                 println!("cannot create scaler buffer");
-                                return false;
+                                return RegisterResult::Failed;
                             }
                             let cvt_buf = ret.unwrap();
                             OutputConvert::Video(scaler, cvt_buf)
@@ -656,7 +705,7 @@ println!("encoder {} is not supported by output (expected {})", istr.id, istr.ge
                                     2 => NAChannelMap::from_ms_mapping(0x3),
                                     _ => {
 println!("can't generate default channel map for {} channels", dainfo.channels);
-                                        return false;
+                                        return RegisterResult::Failed;
                                     },
                                 };
 //todo channelmap
@@ -669,13 +718,13 @@ println!("can't generate default channel map for {} channels", dainfo.channels);
             let ret = encoder.init(out_id, ret_eparams);
             if ret.is_err() {
                 println!("error initialising encoder");
-                return false;
+                return RegisterResult::Failed;
             }
             out_sm.add_stream_ref(ret.unwrap());
             self.encoders.push(OutputMode::Encode(out_id, encoder, cvt));
             self.ostr_opts.push(oopts);
         }
-        true
+        RegisterResult::Ok
     }
     fn map_single(&mut self, cname: &str, ctype: StreamType, src_sm: &StreamManager, out_sm: &mut StreamManager, enc_reg: &RegisteredEncoders) -> bool {
         let mut found_stream = false;
@@ -683,10 +732,11 @@ println!("can't generate default channel map for {} channels", dainfo.channels);
             if istr.get_media_type() != ctype || found_stream {
                 self.encoders.push(OutputMode::Drop);
             } else {
-                if !self.register_output_stream(cname, istr, out_sm, enc_reg) {
-                    return false;
-                }
-                found_stream = true;
+                match self.register_output_stream(cname, istr, out_sm, enc_reg) {
+                    RegisterResult::Ok     => found_stream = true,
+                    RegisterResult::Failed => return false,
+                    RegisterResult::Ignored => {},
+                };
             }
         }
         found_stream
@@ -706,15 +756,17 @@ println!("can't generate default channel map for {} channels", dainfo.channels);
                 let mut found_aud = false;
                 for istr in src_sm.iter() {
                     if istr.get_media_type() == StreamType::Video && !found_vid && !self.no_video {
-                        if !self.register_output_stream(vname, istr, out_sm, enc_reg) {
-                            return false;
-                        }
-                        found_vid = true;
+                        match self.register_output_stream(vname, istr, out_sm, enc_reg) {
+                            RegisterResult::Ok     => found_vid = true,
+                            RegisterResult::Failed => return false,
+                            RegisterResult::Ignored => {},
+                        };
                     } else if istr.get_media_type() == StreamType::Audio && !found_aud && !self.no_audio {
-                        if !self.register_output_stream(aname, istr, out_sm, enc_reg) {
-                            return false;
-                        }
-                        found_aud = true;
+                        match self.register_output_stream(aname, istr, out_sm, enc_reg) {
+                            RegisterResult::Ok     => found_aud = true,
+                            RegisterResult::Failed => return false,
+                            RegisterResult::Ignored => {},
+                        };
                     } else {
                         self.encoders.push(OutputMode::Drop);
                     }
@@ -727,10 +779,11 @@ println!("can't generate default channel map for {} channels", dainfo.channels);
                 let mut found_vid = false;
                 for istr in src_sm.iter() {
                     if istr.get_media_type() == StreamType::Video && !found_vid {
-                        if !self.register_output_stream("any", istr, out_sm, enc_reg) {
-                            return false;
-                        }
-                        found_vid = true;
+                        match self.register_output_stream("any", istr, out_sm, enc_reg) {
+                            RegisterResult::Ok     => found_vid = true,
+                            RegisterResult::Failed => return false,
+                            RegisterResult::Ignored => {},
+                        };
                     } else {
                         self.encoders.push(OutputMode::Drop);
                     }
@@ -743,10 +796,11 @@ println!("can't generate default channel map for {} channels", dainfo.channels);
                 let mut found_aud = false;
                 for istr in src_sm.iter() {
                     if istr.get_media_type() == StreamType::Audio && !found_aud {
-                        if !self.register_output_stream("any", istr, out_sm, enc_reg) {
-                            return false;
-                        }
-                        found_aud = true;
+                        match self.register_output_stream("any", istr, out_sm, enc_reg) {
+                            RegisterResult::Ok     => found_aud = true,
+                            RegisterResult::Failed => return false,
+                            RegisterResult::Ignored => {},
+                        };
                     } else {
                         self.encoders.push(OutputMode::Drop);
                     }
@@ -760,7 +814,7 @@ println!("can't generate default channel map for {} channels", dainfo.channels);
                         self.encoders.push(OutputMode::Drop);
                         continue;
                     }
-                    if !self.register_output_stream("any", istr, out_sm, enc_reg) {
+                    if self.register_output_stream("any", istr, out_sm, enc_reg) == RegisterResult::Failed {
                         return false;
                     }
                 }
@@ -829,6 +883,24 @@ macro_rules! next_arg {
     }
 }
 
+macro_rules! parse_id {
+    ($val: expr, $stype: expr, $maxval: expr) => {
+        if $val.is_empty() {
+            0
+        } else if let Ok(val) = $val.parse::<usize>() {
+            if val < $maxval {
+                val
+            } else {
+                println!("{} number should be below {}", $stype, $maxval);
+                return;
+            }
+        } else {
+            println!("invalid {} number '{}'", $stype, $val);
+            return;
+        }
+    }
+}
+
 #[allow(clippy::single_match)]
 fn main() {
     let args: Vec<_> = env::args().collect();
@@ -966,14 +1038,6 @@ fn main() {
                 }
                 printed_info = true;
             },
-            "--input" | "-i" => {
-                next_arg!(args, arg_idx);
-                transcoder.input_name = args[arg_idx].clone();
-            },
-            "--input-format" => {
-                next_arg!(args, arg_idx);
-                transcoder.input_fmt = Some(args[arg_idx].clone());
-            },
             "--output" | "-o" => {
                 next_arg!(args, arg_idx);
                 transcoder.output_name = args[arg_idx].clone();
@@ -982,13 +1046,6 @@ fn main() {
                 next_arg!(args, arg_idx);
                 transcoder.output_fmt = Some(args[arg_idx].clone());
             },
-            "--demuxer-options" => {
-                next_arg!(args, arg_idx);
-                if !transcoder.parse_demuxer_options(&args[arg_idx], &full_reg.dmx_reg) {
-                    println!("invalid demuxer option syntax");
-                    return;
-                }
-            },
             "--scale-options" => {
                 next_arg!(args, arg_idx);
                 if !transcoder.parse_scale_options(&args[arg_idx]) {
@@ -1047,6 +1104,25 @@ fn main() {
                         println!("invalid output stream option syntax");
                         return;
                     }
+                } else if args[arg_idx].starts_with("--input-format") {
+                    let id = parse_id!(&args[arg_idx][14..], "input format", transcoder.input_fmt.len());
+                    next_arg!(args, arg_idx);
+                    transcoder.input_fmt[id] = Some(args[arg_idx].clone());
+                } else if args[arg_idx].starts_with("--input") { // should be after --input-format
+                    let id = parse_id!(&args[arg_idx][7..], "input", transcoder.input_name.len());
+                    next_arg!(args, arg_idx);
+                    transcoder.input_name[id] = Some(args[arg_idx].clone());
+                } else if args[arg_idx].starts_with("-i") {
+                    let id = parse_id!(&args[arg_idx][2..], "input", transcoder.input_name.len());
+                    next_arg!(args, arg_idx);
+                    transcoder.input_name[id] = Some(args[arg_idx].clone());
+                } else if args[arg_idx].starts_with("--demuxer-options") {
+                    let id = parse_id!(&args[arg_idx][17..], "input options", transcoder.demux_opts.len());
+                    next_arg!(args, arg_idx);
+                    if !transcoder.parse_demuxer_options(&args[arg_idx], &full_reg.dmx_reg, id) {
+                        println!("invalid demuxer option syntax");
+                        return;
+                    }
                 } else if args[arg_idx].starts_with("--") {
                     println!("unknown option");
                 } else {
@@ -1061,8 +1137,8 @@ fn main() {
         return;
     }
 
-    if transcoder.input_name.is_empty() {
-        println!("no input name provided");
+    if transcoder.input_name.iter().flatten().count() == 0 {
+        println!("no input name(s) provided");
         return;
     }
     if transcoder.output_name.is_empty() {
@@ -1070,90 +1146,137 @@ fn main() {
         return;
     }
 
-    if let Some("imgseq") = transcoder.input_fmt.as_deref() {
-        let mut isdc = ImgSeqDemuxerCreator::new(transcoder.input_name.as_str());
-        parse_and_apply_options!(isdc, &transcoder.demux_opts, "input");
-        let isd = if let Ok(ctx) = isdc.open() {
-                ctx
-            } else {
-                println!("failed to create image sequence demuxer!");
-                return;
-            };
-        let mut dmx = DemuxerObject::create_imgseq(isd);
-        transcode(transcoder, full_reg, &mut dmx);
-        return;
-    }
-
-    let res = File::open(transcoder.input_name.as_str());
-    if res.is_err() {
-        println!("error opening input");
-        return;
-    }
-    let file = res.unwrap();
-    let file = BufReader::new(file);
-    let mut fr = FileReader::new_read(file);
-    let mut br = ByteReader::new(&mut fr);
-    let (is_raw, start, end) = if transcoder.input_fmt.is_none() {
-            detect_tags(&mut br)
-        } else {
-            (false, 0, None)
-        };
+    let mut demuxers = Vec::with_capacity(1);
+    let mut isn_start = 0;
+    for (i, (iname, ifmt)) in transcoder.input_name.iter().zip(
+            transcoder.input_fmt.iter()).enumerate() {
+        match (iname, ifmt.as_ref().map(|s| s.as_str())) {
+            (Some(name), Some("imgseq")) => {
+                println!("trying image sequence {}", name);
+                let mut isdc = ImgSeqDemuxerCreator::new(name.as_str());
+                parse_and_apply_options!(isdc, &transcoder.demux_opts[i], "input");
+                let isd = if let Ok(ctx) = isdc.open() {
+                        ctx
+                    } else {
+                        println!("failed to create image sequence demuxer!");
+                        return;
+                    };
+                let dmx = DemuxerObject::create_imgseq(isd);
+                for i in 0..dmx.get_num_streams() {
+                    let s = dmx.get_stream(i).unwrap();
+                    let info = s.get_info();
+                    println!(" stream {}({}) - {} {}", i, i + isn_start, s, info.get_name());
+                }
+                isn_start += dmx.get_num_streams();
+                demuxers.push((dmx, false))
+            },
+            (Some(name), _) => {
+                let res = File::open(name);
+                if res.is_err() {
+                    println!("error opening input");
+                    return;
+                }
+                let file = res.unwrap();
+                let file = BufReader::new(file);
+                let mut fr = FileReader::new_read(file);
+                let mut br = ByteReader::new(&mut fr);
+                let (is_raw, start, end) = if ifmt.is_none() {
+                        detect_tags(&mut br)
+                    } else {
+                        (false, 0, None)
+                    };
 
-    let mut nfr: Box<dyn ByteIO>;
-    if start != 0 || end.is_some() {
-        let file = fr.finish();
-        nfr = Box::new(BoundedFileReader::new_read(file, start, end).unwrap());
-    } else {
-        nfr = Box::new(fr);
-    }
-    let mut br = ByteReader::new(nfr.as_mut());
+                let nfr: Box<dyn ByteIO> = if start != 0 || end.is_some() {
+                        let file = fr.finish();
+                        Box::new(BoundedFileReader::new_read(file, start, end).unwrap())
+                    } else {
+                        Box::new(fr)
+                    };
+                let sb = SelfBorrow::new(nfr, |rd| {
+                        unsafe {
+                            ByteReader::new(rd.as_mut().unwrap().as_mut())
+                        }
+                    });
 
-    let mut dmx = DemuxerObject::create(&mut br, &full_reg, transcoder.input_name.as_str(), &transcoder.input_fmt, is_raw);
-    if dmx.is_none() {
-        println!("cannot find demuxer for '{}'", transcoder.input_name.as_str());
-        return;
+                let mut dmx = DemuxerObject::create(sb, &full_reg, name, ifmt, is_raw);
+                if dmx.is_none() {
+                    println!("cannot find demuxer for '{}'", name);
+                    return;
+                }
+                parse_and_apply_options!(dmx, &transcoder.demux_opts[i], "input");
+                for i in 0..dmx.get_num_streams() {
+                    let s = dmx.get_stream(i).unwrap();
+                    let info = s.get_info();
+                    println!(" stream {}({}) - {} {}", i, i + isn_start, s, info.get_name());
+                }
+                isn_start += dmx.get_num_streams();
+                demuxers.push((dmx, false));
+            },
+            _ => {},
+        };
     }
-    parse_and_apply_options!(dmx, &transcoder.demux_opts, "input");
-    transcode(transcoder, full_reg, &mut dmx);
-}
 
-fn transcode(mut transcoder: Transcoder, full_reg: FullRegister, dmx: &mut DemuxerObject) {
-    let duration = dmx.get_duration();
+    let duration = demuxers.iter().fold(0u64, |mindur, (dmx, _)| {
+            let dur = dmx.get_duration();
+            if dur > 0 {
+                mindur.min(dur)
+            } else {
+                mindur
+            }
+        });
     let duration_string = if duration != 0 { format_time(duration) } else { String::new() };
 
-    for i in 0..dmx.get_num_streams() {
-        let s = dmx.get_stream(i).unwrap();
-        let info = s.get_info();
-        let decfunc = full_reg.dec_reg.find_decoder(info.get_name());
-println!("stream {} - {} {}", i, s, info.get_name());
-        let str_id = s.get_num() as u32;
-        if let Some(create_dec) = decfunc {
-            let mut dec = (create_dec)();
-            let mut dsupp = Box::new(NADecoderSupport::new());
-            let ret = dec.init(&mut dsupp, info.clone());
-            if ret.is_err() {
-                println!("Error initialising decoder '{}' for stream {}", info.get_name(), str_id);
-                return;
-            }
-            transcoder.apply_decoder_options(dec.as_mut(), str_id);
-            let desc = register::get_codec_description(info.get_name());
-            let has_b = if let Some(desc) = desc {
-                    desc.has_reorder()
-                } else {
-                    println!("No codec description found, using B-frame reorderer.");
-                    true
-                };
-            let reord: Box<dyn FrameReorderer> = if has_b { Box::new(IPBReorderer::new()) } else { Box::new(NoReorderer::new()) };
-            transcoder.decoders.push(Some((dsupp, dec, reord)));
-        } else {
-            println!("No decoder for stream {} ({}) is found", str_id, info.get_name());
-            transcoder.decoders.push(None);
+    let mut ism = StreamManager::new();
+    let mut is_offset = Vec::with_capacity(demuxers.len());
+    let mut start = 0;
+    let mut nstreams = 0;
+    for (dmx, _) in demuxers.iter() {
+        is_offset.push(nstreams);
+        let sm = dmx.get_stream_manager();
+        let max_id = sm.iter().fold(0u32, |id, strm| id.max(strm.id));
+        for stream in sm.iter() {
+            let mut newstream = (*stream).clone();
+            newstream.id += start;
+            ism.add_stream(newstream);
         }
+        start += max_id + 1;
+        nstreams += sm.get_num_streams();
     }
-    if transcoder.start != NATimePoint::None {
-        let ret = dmx.seek(transcoder.start);
-        if ret.is_err() {
-            println!(" failed to seek to {} error {:?}", transcoder.start, ret.err().unwrap());
+
+    for (&is_off, (dmx, _)) in is_offset.iter().zip(demuxers.iter_mut()) {
+        for i in 0..dmx.get_num_streams() {
+            let s = dmx.get_stream(i).unwrap();
+            let info = s.get_info();
+            let decfunc = full_reg.dec_reg.find_decoder(info.get_name());
+            let str_id = (s.get_num() + is_off) as u32;
+            if let Some(create_dec) = decfunc {
+                let mut dec = (create_dec)();
+                let mut dsupp = Box::new(NADecoderSupport::new());
+                let ret = dec.init(&mut dsupp, info.clone());
+                if ret.is_err() {
+                    println!("Error initialising decoder '{}' for stream {}", info.get_name(), str_id);
+                    return;
+                }
+                transcoder.apply_decoder_options(dec.as_mut(), str_id);
+                let desc = register::get_codec_description(info.get_name());
+                let has_b = if let Some(desc) = desc {
+                        desc.has_reorder()
+                    } else {
+                        println!("No codec description found, using B-frame reorderer.");
+                        true
+                    };
+                let reord: Box<dyn FrameReorderer> = if has_b { Box::new(IPBReorderer::new()) } else { Box::new(NoReorderer::new()) };
+                transcoder.decoders.push(Some((dsupp, dec, reord)));
+            } else {
+                println!("No decoder for stream {} ({}) is found", str_id, info.get_name());
+                transcoder.decoders.push(None);
+            }
+        }
+        if transcoder.start != NATimePoint::None {
+            let ret = dmx.seek(transcoder.start);
+            if ret.is_err() {
+                println!(" failed to seek to {} error {:?}", transcoder.start, ret.err().unwrap());
+            }
         }
     }
 
@@ -1177,7 +1300,7 @@ println!("stream {} - {} {}", i, s, info.get_name());
 
     let mux_caps = mux_creator.get_capabilities();
     let mut out_sm = StreamManager::new();
-    if !transcoder.negotiate_stream_map(dmx.get_stream_manager(), mux_caps, &mut out_sm, &full_reg.enc_reg) {
+    if !transcoder.negotiate_stream_map(&ism, mux_caps, &mut out_sm, &full_reg.enc_reg) {
         println!("cannot determine stream map");
         return;
     }
@@ -1206,8 +1329,29 @@ println!("stream {} - {} {}", i, s, info.get_name());
     let show_interval = Duration::from_millis(100);
     let mut adata_size = 0;
     let mut vdata_size = 0;
+    let mut cur_dmx = 0;
     'main_loop: loop {
-        let pktres = dmx.get_frame();
+        let mut pktres = Err(DemuxerError::EOF);
+        let mut src_dmx = 0;
+        loop {
+            if !demuxers.iter().any(|(_, eof)| !eof) {
+                break;
+            }
+            let mut got_res = false;
+            if !demuxers[cur_dmx].1 {
+                pktres = demuxers[cur_dmx].0.get_frame();
+                got_res = true;
+                src_dmx = cur_dmx;
+            }
+            cur_dmx += 1;
+            if cur_dmx >= demuxers.len() {
+                cur_dmx = 0;
+            }
+            if got_res {
+                break;
+            }
+        }
+
         if let Err(DemuxerError::EOF) = pktres { break; }
         if pktres.is_err() {
             println!("demuxing error");
@@ -1215,7 +1359,11 @@ 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();
+        let src_id = pkt.get_stream().get_num() + is_offset[src_dmx];
+        let ts = pkt.ts;
+        let newstream = ism.get_stream(src_id).unwrap();
+        pkt.reassign(newstream, ts);
+
         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));
@@ -1298,7 +1446,7 @@ println!("stream {} - {} {}", i, s, info.get_name());
             },
         };
     }
-    'reord_flush_loop: for stream in dmx.get_streams() {
+    'reord_flush_loop: for stream in ism.iter() {
         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] {