diff options
author | Kostya Shishkov <kostya.shishkov@gmail.com> | 2023-06-18 15:28:45 +0200 |
---|---|---|
committer | Kostya Shishkov <kostya.shishkov@gmail.com> | 2023-06-18 15:28:45 +0200 |
commit | 4e72c04a50ab02f6be479799d5b48161f043ebd2 (patch) | |
tree | b9d489214299145514c7fedead4f57e41ae86f26 /videoplayer/src/videodec.rs | |
parent | 0b064d417951df4685eba8cc70a3d1df66334662 (diff) | |
download | nihav-player-4e72c04a50ab02f6be479799d5b48161f043ebd2.tar.gz |
try to improve state handling in decoding threads
Diffstat (limited to 'videoplayer/src/videodec.rs')
-rw-r--r-- | videoplayer/src/videodec.rs | 47 |
1 files changed, 26 insertions, 21 deletions
diff --git a/videoplayer/src/videodec.rs b/videoplayer/src/videodec.rs index ac60466..1a34aad 100644 --- a/videoplayer/src/videodec.rs +++ b/videoplayer/src/videodec.rs @@ -1,5 +1,4 @@ use std::thread::JoinHandle; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::{Receiver, SyncSender, TrySendError}; use std::thread; @@ -10,11 +9,9 @@ use nihav_core::formats::*; use nihav_core::codecs::*; use nihav_core::scale::*; -use super::{DecoderStuff, DecoderType, DispQueue, FrameRecord, PktSendEvent, FRAME_QUEUE_LEN}; +use super::{DecoderStuff, DecoderType, DecoderState, DecodingState, DispQueue, FrameRecord, PktSendEvent, FRAME_QUEUE_LEN}; -static SKIP_VDECODING: AtomicBool = AtomicBool::new(false); -static VIDEO_END: AtomicBool = AtomicBool::new(false); -static GET_FRAMES_END: AtomicBool = AtomicBool::new(false); +static VDEC_STATE: DecoderState = DecoderState::new(); pub const FRAME_QUEUE_SIZE: usize = 25; @@ -69,7 +66,7 @@ impl VideoDecoder { let mut opic = if let ColorModel::YUV(_) = self.ifmt.get_format().get_model() { self.yuv_pool.prealloc_video(self.oinfo_yuv, 2).unwrap(); while self.yuv_pool.get_free().is_none() { - if SKIP_VDECODING.load(Ordering::Relaxed) { + if VDEC_STATE.is_flushing() { return None; } std::thread::yield_now(); @@ -78,7 +75,7 @@ impl VideoDecoder { } else { self.rgb_pool.prealloc_video(self.oinfo_rgb, 0).unwrap(); while self.rgb_pool.get_free().is_none() { - if SKIP_VDECODING.load(Ordering::Relaxed) { + if VDEC_STATE.is_flushing() { return None; } std::thread::yield_now(); @@ -225,13 +222,13 @@ impl VideoDecoder { fn start_video_decoding(width: usize, height: usize, tb_num: u32, tb_den: u32, video_dec: DecoderStuff, vprecv: Receiver<PktSendEvent>, vfsend: SyncSender<(NABufferType, u64)>) -> JoinHandle<()> { std::thread::Builder::new().name("vdecoder".to_string()).spawn(move ||{ - SKIP_VDECODING.store(false, Ordering::Relaxed); + VDEC_STATE.set_state(DecodingState::Waiting); let mut vdec = VideoDecoder::new(width, height, tb_num, tb_den, video_dec); let mut skip_mode = FrameSkipMode::None; loop { match vprecv.recv() { Ok(PktSendEvent::Packet(pkt)) => { - if !SKIP_VDECODING.load(Ordering::Relaxed) { + if !VDEC_STATE.is_flushing() { if let Some((buf, time)) = vdec.next_frame(&pkt) { vfsend.send((buf, time)).unwrap(); } @@ -244,11 +241,11 @@ fn start_video_decoding(width: usize, height: usize, tb_num: u32, tb_den: u32, v while let Some((buf, time)) = vdec.more_frames(false) { vfsend.send((buf, time)).unwrap(); } - GET_FRAMES_END.store(true, Ordering::Relaxed); + VDEC_STATE.set_state(DecodingState::Waiting); }, Ok(PktSendEvent::Flush) => { vdec.flush(); - SKIP_VDECODING.store(false, Ordering::Relaxed); + VDEC_STATE.set_state(DecodingState::Waiting); }, Ok(PktSendEvent::End) => { while vdec.yuv_pool.get_free().is_some() && vdec.rgb_pool.get_free().is_some() { @@ -258,11 +255,11 @@ fn start_video_decoding(width: usize, height: usize, tb_num: u32, tb_den: u32, v } vfsend.send(ret.unwrap()).unwrap(); } - VIDEO_END.store(true, Ordering::Relaxed); + VDEC_STATE.set_state(DecodingState::End); break; }, Ok(PktSendEvent::ImmediateEnd) => { - VIDEO_END.store(true, Ordering::Relaxed); + VDEC_STATE.set_state(DecodingState::End); break; }, Ok(PktSendEvent::HurryUp) => { @@ -335,7 +332,7 @@ impl VideoControl { let (vpsend, vprecv) = std::sync::mpsc::sync_channel::<PktSendEvent>(0); let (vfsend, vfrecv) = std::sync::mpsc::sync_channel::<FrameRecord>(FRAME_QUEUE_SIZE - 1); - VIDEO_END.store(false, Ordering::Relaxed); + VDEC_STATE.set_state(DecodingState::Normal); let vthread = if let Some(video_dec) = video_dec { start_video_decoding(width, height, tb_num, tb_den, video_dec, vprecv, vfsend) @@ -351,6 +348,7 @@ impl VideoControl { _ => {}, }; } + VDEC_STATE.set_state(DecodingState::End); }).unwrap() }; @@ -364,7 +362,7 @@ impl VideoControl { } pub fn flush(&mut self) { self.vqueue.clear(); - SKIP_VDECODING.store(true, Ordering::Release); + VDEC_STATE.set_state(DecodingState::Flush); for _ in 0..8 { let _ = self.vfrecv.try_recv(); } @@ -401,15 +399,22 @@ impl VideoControl { true } pub fn is_video_end(&self) -> bool { - VIDEO_END.load(Ordering::Relaxed) + matches!(VDEC_STATE.get_state(), DecodingState::End | DecodingState::Error) } - pub fn wait_for_frames(&mut self) { - GET_FRAMES_END.store(false, Ordering::Relaxed); + pub fn wait_for_frames(&mut self) -> Result<(), ()> { + VDEC_STATE.set_state(DecodingState::Prefetch); self.try_send_event(PktSendEvent::GetFrames); while !self.try_send_queued() { } - while !GET_FRAMES_END.load(Ordering::Relaxed) { - thread::yield_now(); + loop { + match VDEC_STATE.get_state() { + DecodingState::Waiting => { + VDEC_STATE.set_state(DecodingState::Normal); + return Ok(()); + }, + DecodingState::Prefetch => thread::yield_now(), + _ => return Err(()), + }; } } @@ -451,7 +456,7 @@ impl VideoControl { } pub fn finish(self) { - SKIP_VDECODING.store(true, Ordering::Release); + VDEC_STATE.set_state(DecodingState::Flush); for _ in 0..8 { let _ = self.vfrecv.try_recv(); } |