use nihav_allstuff::*;
use crate::null::*;
use crate::imgseq::*;
+use crate::{SBBox, SelfBorrow};
pub struct FullRegister {
pub dmx_reg: RegisteredDemuxers,
}
}
+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()
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);
}
}
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));
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));
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
}
}
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,
}
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()) {
}
},
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()) {
}
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),
}
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,
}
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::*;
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 {
#[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>,
}
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);
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;
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();
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)
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);
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));
} 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() };
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();
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();
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)
2 => NAChannelMap::from_ms_mapping(0x3),
_ => {
println!("can't generate default channel map for {} channels", dainfo.channels);
- return false;
+ return RegisterResult::Failed;
},
};
//todo channelmap
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;
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
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);
}
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);
}
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);
}
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;
}
}
}
}
+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();
}
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();
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]) {
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 {
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() {
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());
+ }
}
}
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;
}
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");
}
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));
},
};
}
- '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] {