ignore empty frames
[nihav-player.git] / sndplay / src / main.rs
index 377c2d1b11bb7b134f3a1b9e1bd5ad287a61d175..275826ff9f7db9d425b5efc9a3c37a12179ba3ef 100644 (file)
@@ -2,11 +2,10 @@ extern crate libc;
 extern crate sdl2_sys;
 extern crate nihav_core;
 extern crate nihav_registry;
-extern crate nihav_allstuff;
 
 use std::fs::File;
 use std::io::prelude::*;
-use std::io::{BufReader, SeekFrom};
+use std::io::BufReader;
 use std::sync::mpsc;
 use std::time::Duration;
 use std::thread;
@@ -16,16 +15,16 @@ use nihav_core::frame::*;
 use nihav_core::codecs::*;
 use nihav_core::demuxers::*;
 use nihav_core::soundcvt::*;
-use nihav_registry::detect;
-use nihav_allstuff::*;
 
+mod allreg;
 mod command;
 use command::*;
+mod demux;
+use demux::*;
 
 struct Player {
     ended:      bool,
-    dmx_reg:    RegisteredDemuxers,
-    dec_reg:    RegisteredDecoders,
+    full_reg:   allreg::FullRegister,
     paused:     bool,
     mute:       bool,
     volume:     u8,
@@ -86,8 +85,14 @@ impl AudioDevice {
     }
 }
 
+impl Drop for AudioDevice {
+    fn drop(&mut self) {
+        unsafe { sdl2_sys::SDL_CloseAudioDevice(self.device_id); }
+    }
+}
+
 struct Decoder<'a> {
-    demuxer:    Demuxer<'a>,
+    demuxer:    DemuxerObject<'a>,
     decoder:    Box<dyn NADecoder>,
     dsupp:      Box<NADecoderSupport>,
     buf:        &'a mut Vec<i16>,
@@ -102,7 +107,7 @@ struct Decoder<'a> {
 
 fn output_vol_i16(device: &AudioDevice, tmp: &mut Vec<i16>, src: &[i16], mute: bool, volume: u8) {
     if !mute {
-        tmp.truncate(0);
+        tmp.clear();
         tmp.reserve(src.len());
         let vol = i32::from(volume);
         for &sample in src.iter() {
@@ -110,7 +115,7 @@ fn output_vol_i16(device: &AudioDevice, tmp: &mut Vec<i16>, src: &[i16], mute: b
             tmp.push(nsamp.min(32767).max(-32768) as i16);
         }
     } else {
-        tmp.truncate(0);
+        tmp.clear();
         tmp.resize(src.len(), 0);
     }
     device.queue(&tmp);
@@ -118,7 +123,7 @@ fn output_vol_i16(device: &AudioDevice, tmp: &mut Vec<i16>, src: &[i16], mute: b
 
 fn output_vol_u8(device: &AudioDevice, tmp: &mut Vec<i16>, src: &[u8], mute: bool, volume: u8) {
     if !mute {
-        tmp.truncate(0);
+        tmp.clear();
         tmp.reserve(src.len());
         let vol = i32::from(volume);
         for sample in src.chunks_exact(2) {
@@ -127,7 +132,7 @@ fn output_vol_u8(device: &AudioDevice, tmp: &mut Vec<i16>, src: &[u8], mute: boo
             tmp.push(nsamp.min(32767).max(-32768) as i16);
         }
     } else {
-        tmp.truncate(0);
+        tmp.clear();
         tmp.resize(src.len() / 2, 0);
     }
     device.queue(&tmp);
@@ -142,9 +147,15 @@ impl<'a> Decoder<'a> {
                         match self.decoder.decode(&mut self.dsupp, &pkt) {
                             Ok(frm) => {
                                 let buf = frm.get_buffer();
+                                if let NABufferType::None = buf {
+                                    return false;
+                                }
                                 if let Some(pts) = frm.ts.get_pts() {
                                     self.samplepos = NATimeInfo::ts_to_time(pts, u64::from(self.arate), frm.ts.tb_num, frm.ts.tb_den);
                                 }
+                                if buf.get_audio_length() == 0 {
+                                    return false;
+                                }
                                 let out_buf = convert_audio_frame(&buf, &self.dst_info, &self.dst_chmap).unwrap();
                                 match out_buf {
                                     NABufferType::AudioI16(abuf) => {
@@ -193,19 +204,21 @@ fn format_time(ms: u64) -> String {
     let s = ms / 1000;
     let ds = (ms % 1000) / 100;
     let (min, s) = (s / 60, s % 60);
-    if min == 0 {
-        format!("{}.{}", s, ds)
+    let (h, min) = (min / 60, min % 60);
+    if h == 0 {
+        if min == 0 {
+            format!("{}.{}", s, ds)
+        } else {
+            format!("{}:{:02}.{}", min, s, ds)
+        }
     } else {
-        format!("{}:{:02}.{}", min, s, ds)
+        format!("{}:{:02}:{:02}.{}", h, min, s, ds)
     }
 }
 
 impl Player {
     fn new() -> Self {
-        let mut dmx_reg = RegisteredDemuxers::new();
-        nihav_register_all_demuxers(&mut dmx_reg);
-        let mut dec_reg = RegisteredDecoders::new();
-        nihav_register_all_decoders(&mut dec_reg);
+        let full_reg = allreg::FullRegister::new();
 
         unsafe {
             if sdl2_sys::SDL_Init(sdl2_sys::SDL_INIT_AUDIO) != 0 {
@@ -216,48 +229,44 @@ impl Player {
         Self {
             ended:  false,
             paused: false,
-            dmx_reg, dec_reg,
+            full_reg,
             volume: 100,
             mute:   false,
             debug:  false,
             buf:    Vec::new(),
         }
     }
-    fn play_file(&mut self, name: &str, cmd_receiver: &mpsc::Receiver<Command>) {
+    fn play_file(&mut self, name: &str, cmd_receiver: &mpsc::Receiver<Command>, start_time: NATimePoint) {
         let ret = File::open(name);
         if ret.is_err() {
             println!("error opening {}", name);
             return;
         }
-        let mut file = ret.unwrap();
+        let file = ret.unwrap();
+        let file = BufReader::new(file);
 
-        let mut fr = FileReader::new_read(&mut file);
+        let mut fr = FileReader::new_read(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);
+        if br.peek_byte().is_err() {
+            println!("Cannot read {}", name);
             return;
         }
-        let (dmx_name, _) = res.unwrap();
-        drop(br);
-        drop(fr);
-        let dmx_fact = self.dmx_reg.find_demuxer(dmx_name);
-        if dmx_fact.is_none() {
-            println!("no demuxer for format {}", dmx_name);
-            return;
-        }
-        let dmx_fact = dmx_fact.unwrap();
+        let (is_raw, start, end) = detect_tags(&mut br);
 
-        file.seek(SeekFrom::Start(0)).unwrap();
-        let mut file = BufReader::new(file);
-        let mut fr = FileReader::new_read(&mut file);
-        let mut br = ByteReader::new(&mut fr);
-        let res = create_demuxer(dmx_fact, &mut br);
-        if res.is_err() {
-            println!("cannot create demuxer");
+        let mut nfr: Box<dyn ByteIO>;
+        if start != 0 || end.is_some() {
+            //println!(" limiting range to {:X}-{:X}", start, end.unwrap_or(0));
+            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 dmx = DemuxerObject::create(&mut br, &self.full_reg, name, is_raw);
+        if dmx.is_none() {
+            println!("No demuxer found!");
             return;
         }
-        let dmx = res.unwrap();
 
         let mut ainfo = None;
         let mut dec: Option<(Box<NADecoderSupport>, Box<dyn NADecoder>)> = None;
@@ -267,7 +276,7 @@ impl Player {
             let s = dmx.get_stream(i).unwrap();
             let info = s.get_info();
             if info.is_audio() {
-                let decfunc = self.dec_reg.find_decoder(info.get_name());
+                let decfunc = self.full_reg.dec_reg.find_decoder(info.get_name());
                 if decfunc.is_none() {
                     println!("no decoder for {}", info.get_name());
                     continue;
@@ -298,7 +307,7 @@ impl Player {
         let ch    = ainfo.channels;
 
         println!("Playing {} [{}Hz {}ch]", name, arate, ch);
-        let ret = AudioDevice::open(arate, ch.max(2));
+        let ret = AudioDevice::open(arate, ch.min(2));
         if ret.is_none() {
             println!("cannot open output");
             return;
@@ -326,6 +335,10 @@ impl Player {
         let mut refill_limit = arate * u32::from(dspec.channels);
         let underfill_limit = (arate * u32::from(dspec.channels) / 4).max(block_limit);
 
+        if start_time != NATimePoint::None {
+            let _ret = decoder.demuxer.seek(start_time);
+        }
+
         let mut eof = decoder.refill(&device);
         while !eof && device.size() < refill_limit {
             eof = decoder.refill(&device);
@@ -466,8 +479,18 @@ impl Player {
                     Command::Debug => {
                         self.debug = !self.debug;
                     },
-                    Command::PauseDisplay  => { no_display = true; },
-                    Command::ResumeDisplay => { no_display = false; },
+                    Command::PauseDisplay  => {
+                        no_display = true;
+                        if !self.paused {
+                            device.pause();
+                        }
+                    },
+                    Command::ResumeDisplay => {
+                        no_display = false;
+                        if !self.paused {
+                            device.resume();
+                        }
+                    },
                 };
                 if !no_display {
                     print!("\r{:60}\r", ' ');
@@ -508,11 +531,29 @@ fn main() {
         return;
     }
 
-    for arg in args[1..].iter() {
-        player.play_file(arg, &cmd_receiver);
-        if player.ended {
-            break;
-        }
+    let mut aiter = args[1..].iter();
+    let mut start_time = NATimePoint::None;
+    while let Some(arg) = aiter.next() {
+        match arg.as_str() {
+            "-start" => {
+                if let Some(arg) = aiter.next() {
+                    if let Ok(val) = arg.parse() {
+                        start_time = val;
+                    } else {
+                        println!("invalid time");
+                    }
+                } else {
+                    println!("argument is required");
+                }
+            },
+            _ => {
+                player.play_file(arg, &cmd_receiver, start_time);
+                if player.ended {
+                    break;
+                }
+                start_time = NATimePoint::None;
+            },
+        };
     }
     cmd_state.restore();