X-Git-Url: https://git.nihav.org/?p=nihav-tool.git;a=blobdiff_plain;f=src%2Fmain.rs;h=76e720ef3e46ed304522f592c918f07ef88e6c92;hp=2517b53fd51c5d28eafe33cf8b6a094f0529b4c9;hb=fabefb1bbbe0989b89e588a9409679cf3096d2d8;hpb=019f9f9c8f115c0b7e3a18f1ad81a47546aa0793 diff --git a/src/main.rs b/src/main.rs dissimilarity index 79% index 2517b53..76e720e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,148 +1,280 @@ -extern crate nihav; - -use std::io::prelude::*; -use std::io::SeekFrom; -use std::fs::File; -use std::path::Path; -use nihav::io::byteio::{FileReader, ByteReader}; -use nihav::frame::*; -use nihav::codecs::*; -use nihav::demuxers::*; -use nihav::detect; -use std::env; - -fn write_pgmyuv(pfx: &str, strno: usize, num: u64, frmref: NAFrameRef) { - let frm = frmref.borrow(); - if let NABufferType::None = frm.get_buffer() { return; } - let name = format!("{}out{:02}_{:04}.pgm", pfx, strno, num); - let mut ofile = File::create(name).unwrap(); - let buf = frm.get_buffer().get_vbuf().unwrap(); - let (w, h) = buf.get_dimensions(0); - let (w2, h2) = buf.get_dimensions(1); - let tot_h = h + h2; - let hdr = format!("P5\n{} {}\n255\n", w, tot_h); - ofile.write_all(hdr.as_bytes()).unwrap(); - let dta = buf.get_data(); - let ls = buf.get_stride(0); - let mut idx = 0; - let mut idx2 = w; - let mut pad: Vec = Vec::with_capacity((w - w2 * 2) / 2); - pad.resize((w - w2 * 2) / 2, 0xFF); - for _ in 0..h { - let line = &dta[idx..idx2]; - ofile.write_all(line).unwrap(); - idx += ls; - idx2 += ls; - } - let mut base1 = buf.get_offset(1); - let stride1 = buf.get_stride(1); - let mut base2 = buf.get_offset(2); - let stride2 = buf.get_stride(2); - for _ in 0..h2 { - let bend1 = base1 + w2; - let line = &dta[base1..bend1]; - ofile.write_all(line).unwrap(); - ofile.write_all(pad.as_slice()).unwrap(); - - let bend2 = base2 + w2; - let line = &dta[base2..bend2]; - ofile.write_all(line).unwrap(); - ofile.write_all(pad.as_slice()).unwrap(); - - base1 += stride1; - base2 += stride2; - } -} - -fn write_palppm(pfx: &str, strno: usize, num: u64, frmref: NAFrameRef) { - let frm = frmref.borrow(); - let name = format!("{}out{:02}_{:04}.ppm", pfx, strno, num); - let mut ofile = File::create(name).unwrap(); - let buf = frm.get_buffer().get_vbuf().unwrap(); - let (w, h) = buf.get_dimensions(0); - let paloff = buf.get_offset(1); - let hdr = format!("P6\n{} {}\n255\n", w, h); - ofile.write_all(hdr.as_bytes()).unwrap(); - let dta = buf.get_data(); - let ls = buf.get_stride(0); - let mut idx = 0; - let mut line: Vec = Vec::with_capacity(w * 3); - line.resize(w * 3, 0); - for _ in 0..h { - let src = &dta[idx..(idx+w)]; - for x in 0..w { - let pix = src[x] as usize; - line[x * 3 + 0] = dta[paloff + pix * 3 + 2]; - line[x * 3 + 1] = dta[paloff + pix * 3 + 1]; - line[x * 3 + 2] = dta[paloff + pix * 3 + 0]; - } - ofile.write_all(line.as_slice()).unwrap(); - idx += ls; - } -} - -fn main() { - let args: Vec<_> = env::args().collect(); - - if args.len() == 1 { return; } - let lastpts = if args.len() > 2 { - Some(u64::from_str_radix(args[2].as_str(), 10).unwrap()) - } else { None }; - - let name = args[1].as_str(); - let path = Path::new(name); - let mut file = File::open(path).unwrap(); - let dmx_fact; - let mut fr = FileReader::new_read(&mut file); - let mut br = ByteReader::new(&mut fr); - let res = detect::detect_format(name, &mut br); - if res.is_none() { - println!("cannot detect format for {}", name); - return; - } - let (dmx_name, _) = res.unwrap(); -println!("trying demuxer {}", dmx_name); - dmx_fact = find_demuxer(dmx_name).unwrap(); - br.seek(SeekFrom::Start(0)).unwrap(); - let mut dmx = dmx_fact.new_demuxer(&mut br); - dmx.open().unwrap(); - - let mut decs: Vec>> = Vec::new(); - for i in 0..dmx.get_num_streams() { - let s = dmx.get_stream(i).unwrap(); - let info = s.get_info(); - let decfunc = find_decoder(info.get_name()); - if !info.is_video() { - decs.push(None); - } else if let Some(df) = decfunc { - let mut dec = (df)(); - dec.init(info).unwrap(); - decs.push(Some(dec)); - } else { -panic!("decoder {} not found", info.get_name()); - } - } - - loop { - let pktres = dmx.get_frame(); - if let Err(e) = pktres { - if e == DemuxerError::EOF { break; } - } - let pkt = pktres.unwrap(); - let streamno = pkt.get_stream().get_id() as usize; - if let Some(ref mut dec) = decs[streamno] { - let frm = dec.decode(&pkt).unwrap(); - if pkt.get_stream().get_info().is_video() { - if frm.borrow().get_frame_type() != FrameType::Skip { - if frm.borrow().get_buffer().get_vbuf().unwrap().get_info().get_format().is_paletted() { - write_palppm("", streamno, pkt.get_pts().unwrap(), frm); - } else { - write_pgmyuv("", streamno, pkt.get_pts().unwrap(), frm); - } - } - } - } - if pkt.get_pts() != None && pkt.get_pts() == lastpts { break; } - } -//panic!("end"); -} +extern crate nihav_core; +extern crate nihav_codec_support; +extern crate nihav_registry; +extern crate nihav_allstuff; + +use std::io::{SeekFrom, Write}; +use std::fs::File; +use std::path::Path; +use nihav_core::io::byteio::{FileReader, ByteReader}; +use nihav_core::frame::*; +use nihav_core::codecs::*; +use nihav_core::demuxers::*; +use nihav_codec_support::imgwrite::*; +use nihav_registry::detect; +use nihav_allstuff::*; +use std::env; + +mod wavwriter; +use crate::wavwriter::WavWriter; + +#[derive(Clone,Copy,PartialEq)] +enum NumberMode { + Counter, + PktPTS, + FrmPTS, +} + +struct FrameOutput { + prefix: String, + streamno: usize, + frameno: u64, + nmode: NumberMode, +} + +impl FrameOutput { + fn output_frame(&mut self, pkt: &NAPacket, frm: NAFrameRef) { + if frm.get_frame_type() != FrameType::Skip { + let pts = match self.nmode { + NumberMode::Counter => { self.frameno }, + NumberMode::PktPTS => { pkt.get_pts().unwrap() }, + NumberMode::FrmPTS => { if let Some(pt) = frm.get_pts() { pt } else { pkt.get_pts().unwrap() } }, + }; + if let Err(_) = write_pnm(&self.prefix, self.streamno, pts, frm) { + println!("error writing output picture"); + } + } + self.frameno += 1; + } +} + +struct AudioOutput { + wwr: WavWriter<'static>, + wrote_header: bool, +} + +impl AudioOutput { + fn new(name: &str) -> Self { Self { wwr: WavWriter::new(name), wrote_header: false } } + fn output_frame(&mut self, _pkt: &NAPacket, frm: NAFrameRef) { + if !self.wrote_header { + self.wwr.write_header(frm.get_info().as_ref().get_properties().get_audio_info().unwrap()).unwrap(); + self.wrote_header = true; + } + self.wwr.write_frame(frm.get_buffer()).unwrap(); + } +} + +enum Outputter { + Video(FrameOutput), + Audio(AudioOutput), + None, +} + +fn main() { + let args: Vec<_> = env::args().collect(); + + if args.len() == 1 { + println!("usage: nihav-tool [-noout] [-vn] [-an] input [lastpts]"); + return; + } + let mut lastpts = NATimePoint::None; + let mut cur_arg: usize = 1; + let mut noout = false; + let mut decode_video = true; + let mut decode_audio = true; + let mut nmode = NumberMode::FrmPTS; + let mut smode = FrameSkipMode::None; + let mut seek_time = NATimePoint::None; + let mut vpfx: Option = None; + let mut apfx: Option<&str> = None; + let mut ignore_errors = false; + let mut dump_frames = false; + + while (cur_arg < args.len()) && args[cur_arg].starts_with('-') { + match args[cur_arg].as_str() { + "--" => { break; }, + "-noout" => { noout = true; }, + "-an" => { decode_audio = false; }, + "-vn" => { decode_video = false; }, + "-nm=count" => { nmode = NumberMode::Counter; }, + "-nm=pktpts" => { nmode = NumberMode::PktPTS; }, + "-nm=frmpts" => { nmode = NumberMode::FrmPTS; }, + "-skip=key" => { smode = FrameSkipMode::KeyframesOnly; }, + "-skip=intra" => { smode = FrameSkipMode::IntraOnly; }, + "-seek" => { + cur_arg += 1; + if cur_arg == args.len() { + println!("seek time missing"); + return; + } + let ret = args[cur_arg].parse::(); + if ret.is_err() { + println!("wrong seek time"); + return; + } + seek_time = ret.unwrap(); + }, + "-apfx" => { + cur_arg += 1; + if cur_arg == args.len() { + println!("name missing"); + return; + } + apfx = Some(&args[cur_arg]); + }, + "-vpfx" => { + cur_arg += 1; + if cur_arg == args.len() { + println!("name missing"); + return; + } + vpfx = Some(args[cur_arg].clone()); + }, + "-ignerr" => { ignore_errors = true; }, + "-dumpfrm" => { dump_frames = true; }, + _ => { println!("unknown option {}", args[cur_arg]); return; }, + } + cur_arg += 1; + } + let name = args[cur_arg].as_str(); + cur_arg += 1; + if cur_arg < args.len() { + let ret = args[cur_arg].parse::(); + if ret.is_err() { + println!("cannot parse end time"); + return; + } + lastpts = ret.unwrap(); + } + + let path = Path::new(name); + let mut file = File::open(path).unwrap(); + let dmx_fact; + let mut fr = FileReader::new_read(&mut file); + let mut br = ByteReader::new(&mut fr); + let res = detect::detect_format(name, &mut br); + if res.is_none() { + println!("cannot detect format for {}", name); + return; + } + let (dmx_name, _) = res.unwrap(); +println!("trying demuxer {} on {}", dmx_name, name); + + let mut dmx_reg = RegisteredDemuxers::new(); + nihav_register_all_demuxers(&mut dmx_reg); + let mut dec_reg = RegisteredDecoders::new(); + nihav_register_all_codecs(&mut dec_reg); + + dmx_fact = dmx_reg.find_demuxer(dmx_name).unwrap(); + br.seek(SeekFrom::Start(0)).unwrap(); + let mut dmx = create_demuxer(dmx_fact, &mut br).unwrap(); + + if seek_time != NATimePoint::None { + let ret = dmx.seek(seek_time); + if ret.is_err() { +println!(" seek error {:?}", ret.err().unwrap()); + } + } + + let mut decs: Vec, Box)>> = Vec::new(); + let mut sids: Vec = Vec::new(); + let mut writers: Vec = Vec::new(); + let dec_opts = [NAOption{name: FRAME_SKIP_OPTION, value: NAValue::String(smode.to_string())}]; + for i in 0..dmx.get_num_streams() { + let s = dmx.get_stream(i).unwrap(); + let info = s.get_info(); + let decfunc = dec_reg.find_decoder(info.get_name()); +println!("stream {} - {} {}", i, s, info.get_name()); + let str_id = s.get_id(); + let mut has_out = false; + sids.push(str_id); + if info.is_video() { + if decode_video { + if decfunc.is_none() { + println!("no video decoder found!"); + return; + } + let mut dec = (decfunc.unwrap())(); + let mut dsupp = Box::new(NADecoderSupport::new()); + dec.init(&mut dsupp, info).unwrap(); + dec.set_options(&dec_opts); + decs.push(Some((dsupp, dec))); + if !noout { + writers.push(Outputter::Video(FrameOutput{prefix: if let Some(ref str) = vpfx { str.clone() } else { "out".to_string() }, streamno: i, frameno: 1, nmode})); + has_out = true; + } + } else { + decs.push(None); + } + } else if info.is_audio() { + if decode_audio { + if decfunc.is_none() { + println!("no audio decoder found!"); + return; + } + let mut dec = (decfunc.unwrap())(); + let mut dsupp = Box::new(NADecoderSupport::new()); + dec.init(&mut dsupp, info).unwrap(); + decs.push(Some((dsupp, dec))); + if !noout { + let name = if let Some(apfx) = apfx { + format!("{}{:02}.wav", apfx, i) + } else { + format!("out{:02}.wav", i) + }; + writers.push(Outputter::Audio(AudioOutput::new(&name))); + has_out = true; + } + } else { + decs.push(None); + } + } else { + decs.push(None); + } + if !has_out { + writers.push(Outputter::None); + } + } + + let mut frmnum = 0; + loop { + let pktres = dmx.get_frame(); + if let Err(e) = pktres { + if e == DemuxerError::EOF { break; } + } + let pkt = pktres.unwrap(); + let streamno = pkt.get_stream().get_id(); + let sr = sids.iter().position(|x| *x == streamno); + let idx = sr.unwrap(); + if dump_frames { + let name = format!("out{:02}_{:08}.frm", streamno, pkt.get_pts().unwrap_or(frmnum)); + let mut ofile = File::create(name).unwrap(); + ofile.write(pkt.get_buffer().as_slice()).unwrap(); + frmnum += 1; + } + if let Some((ref mut dsupp, ref mut dec)) = decs[idx] { + match dec.decode(dsupp, &pkt) { + Ok(frm) => { + if !noout { + match writers[idx] { + Outputter::Video(ref mut wr) => { wr.output_frame(&pkt, frm); }, + Outputter::Audio(ref mut wr) => { wr.output_frame(&pkt, frm); }, + _ => {}, + }; + } + }, + Err(DecoderError::MissingReference) if seek_time != NATimePoint::None => { + println!("ignoring missing ref"); + }, + Err(reason) => { + println!("error decoding frame {:?}", reason); + if !ignore_errors { + break; + } + }, + }; + if pkt.get_pts() != None && lastpts != NATimePoint::None && !pkt.ts.less_than(lastpts) { break; } + } + } +//panic!("end"); +}