make video player use multi-threaded decoders if possible
[nihav-player.git] / videoplayer / src / main.rs
index 25ddcabe245f7141ac0dced820b9f9a99e808984..dcd4d0a3538fa51e2a15372f506c11cfbf032137 100644 (file)
@@ -44,16 +44,22 @@ macro_rules! debug_log {
 
 pub enum PktSendEvent {
     Packet(NAPacket),
+    GetFrames,
     Flush,
     End,
     ImmediateEnd,
     HurryUp,
 }
 
+pub enum DecoderType {
+    Audio(Box<dyn NADecoder + Send>),
+    Video(Box<dyn NADecoder + Send>, Box<dyn FrameReorderer + Send>),
+    VideoMT(Box<dyn NADecoderMT + Send>, MTFrameReorderer),
+}
+
 pub struct DecoderStuff {
     pub dsupp:  Box<NADecoderSupport>,
-    pub dec:    Box<dyn NADecoder + Send>,
-    pub reord:  Box<dyn FrameReorderer + Send>,
+    pub dec:    DecoderType,
 }
 
 fn format_time(ms: u64) -> String {
@@ -221,6 +227,9 @@ struct Player {
     video_str:      u32,
     audio_str:      u32,
 
+    vthreads:       usize,
+    use_mt:         bool,
+
     paused:         bool,
     mute:           bool,
     volume:         usize,
@@ -254,6 +263,9 @@ impl Player {
             video_str:      0,
             audio_str:      0,
 
+            vthreads:       3,
+            use_mt:         true,
+
             paused:         false,
             mute:           false,
             volume:         100,
@@ -341,6 +353,7 @@ impl Player {
                 self.vcontrol.fill(disp_queue);
                 std::thread::sleep(Duration::from_millis(10));
             }
+            self.vcontrol.wait_for_frames();
             self.vcontrol.fill(disp_queue);
         }
         debug_log!(self; {format!(" prefilling done, frames {}-{} audio {}", disp_queue.start, disp_queue.end, self.acontrol.get_fill())});
@@ -444,6 +457,10 @@ impl Player {
         nihav_register_all_demuxers(&mut dmx_reg);
         let mut dec_reg = RegisteredDecoders::new();
         nihav_register_all_decoders(&mut dec_reg);
+        let mut mtdec_reg = RegisteredMTDecoders::new();
+        if self.use_mt {
+            nihav_register_all_mt_decoders(&mut mtdec_reg);
+        }
 
         let ret = dmx_reg.find_demuxer(dmx_name);
         if ret.is_none() {
@@ -484,11 +501,32 @@ impl Player {
             let s = dmx.get_stream(i).unwrap();
             let info = s.get_info();
             let decfunc = dec_reg.find_decoder(info.get_name());
+            let decfunc_mt = mtdec_reg.find_decoder(info.get_name());
             println!("stream {} - {} {}", i, s, info.get_name());
             debug_log!(self; {format!(" stream {} - {} {}", i, s, info.get_name())});
             let str_id = s.get_id();
             if info.is_video() {
                 if video_dec.is_none() && self.play_video {
+                    if let Some(decfunc) = decfunc_mt {
+                        let mut dec = (decfunc)();
+                        let mut dsupp = Box::new(NADecoderSupport::new());
+                        let props = info.get_properties().get_video_info().unwrap();
+                        if props.get_width() != 0 {
+                            width  = props.get_width();
+                            height = props.get_height();
+                        }
+                        if dec.init(&mut dsupp, info.clone(), self.vthreads).is_ok() {
+                            video_dec = Some(DecoderStuff{ dsupp, dec: DecoderType::VideoMT(dec, MTFrameReorderer::new()) });
+                            self.video_str = str_id;
+                            let (tbn, tbd) = s.get_timebase();
+                            tb_num = tbn;
+                            tb_den = tbd;
+                            self.has_video = true;
+                            continue;
+                        } else {
+                            println!("failed to create multi-threaded decoder, falling back");
+                        }
+                    }
                     if let Some(decfunc) = decfunc {
                         let mut dec = (decfunc)();
                         let mut dsupp = Box::new(NADecoderSupport::new());
@@ -509,7 +547,7 @@ impl Player {
                         dsupp.pool_u16 = NAVideoBufferPool::new(reorder_depth);
                         dsupp.pool_u32 = NAVideoBufferPool::new(reorder_depth);
                         dec.init(&mut dsupp, info).unwrap();
-                        video_dec = Some(DecoderStuff{ dsupp, dec, reord });
+                        video_dec = Some(DecoderStuff{ dsupp, dec: DecoderType::Video(dec, reord) });
                         self.video_str = str_id;
                         let (tbn, tbd) = s.get_timebase();
                         tb_num = tbn;
@@ -526,8 +564,7 @@ impl Player {
                         let mut dsupp = Box::new(NADecoderSupport::new());
                         ainfo = info.get_properties().get_audio_info();
                         dec.init(&mut dsupp, info).unwrap();
-                        let reord = Box::new(NoReorderer::new());
-                        audio_dec = Some(DecoderStuff{ dsupp, dec, reord });
+                        audio_dec = Some(DecoderStuff{ dsupp, dec: DecoderType::Audio(dec) });
                         self.audio_str = str_id;
                         self.has_audio = true;
                     } else {
@@ -725,6 +762,21 @@ fn main() {
             "-nodebug" => {
                 player.debug = false;
             },
+            "-mt" => {
+                player.use_mt = true;
+            },
+            "-nomt" => {
+                player.use_mt = false;
+            },
+            "-threads" => {
+                if let Some(arg) = aiter.next() {
+                    if let Ok(val) = arg.parse::<usize>() {
+                        player.vthreads = val.max(1);
+                    } else {
+                        println!("wrong number of threads");
+                    }
+                }
+            },
             _ => {
                 player.play(arg, seek_time);
                 if player.end { break; }