X-Git-Url: https://git.nihav.org/?a=blobdiff_plain;f=videoplayer%2Fsrc%2Fvideodec.rs;h=b8867f1ad46f947d972ca267e0cb74c407688266;hb=HEAD;hp=ac60466be8fa4827f78b964bcf40f14cb5d1a814;hpb=37f130a74415deaf920b04209e1c334a8876c381;p=nihav-player.git diff --git a/videoplayer/src/videodec.rs b/videoplayer/src/videodec.rs index ac60466..295cfc7 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; @@ -51,39 +48,39 @@ impl VideoDecoder { rgb_pool: NAVideoBufferPool::new(FRAME_QUEUE_SIZE), tb_num, tb_den, dec, ofmt_yuv, ofmt_rgb, oinfo_yuv, oinfo_rgb, - scaler: NAScale::new(ofmt_rgb, ofmt_rgb).unwrap(), + scaler: NAScale::new(ofmt_rgb, ofmt_rgb).expect("creating scaler failed"), ifmt: NAVideoInfo { width: 0, height: 0, flipped: false, format: SDL_RGB_FMT, bits: 24 }, } } fn convert_buf(&mut self, bt: NABufferType, ts: u64) -> Option { - let vinfo = bt.get_video_info().unwrap(); + let vinfo = bt.get_video_info().expect("this should be a video buffer"); if self.ifmt.get_width() != vinfo.get_width() || self.ifmt.get_height() != vinfo.get_height() || self.ifmt.get_format() != vinfo.get_format() { self.ifmt = vinfo; let sc_ifmt = ScaleInfo { width: self.ifmt.get_width(), height: self.ifmt.get_height(), fmt: self.ifmt.get_format() }; - let do_yuv = if let ColorModel::YUV(_) = self.ifmt.get_format().get_model() { true } else { false }; + let do_yuv = self.ifmt.get_format().get_model().is_yuv(); let ofmt = if do_yuv { self.ofmt_yuv } else { self.ofmt_rgb }; - self.scaler = NAScale::new(sc_ifmt, ofmt).unwrap(); + self.scaler = NAScale::new(sc_ifmt, ofmt).expect("scaling should not fail"); } let mut opic = if let ColorModel::YUV(_) = self.ifmt.get_format().get_model() { - self.yuv_pool.prealloc_video(self.oinfo_yuv, 2).unwrap(); + self.yuv_pool.prealloc_video(self.oinfo_yuv, 2).expect("video frame pool allocation failure"); 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(); } - NABufferType::Video(self.yuv_pool.get_free().unwrap()) + NABufferType::Video(self.yuv_pool.get_free().expect("video frame pool should have a free frame")) } else { - self.rgb_pool.prealloc_video(self.oinfo_rgb, 0).unwrap(); + self.rgb_pool.prealloc_video(self.oinfo_rgb, 0).expect("video frame pool allocation failure"); 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(); } - NABufferType::VideoPacked(self.rgb_pool.get_free().unwrap()) + NABufferType::VideoPacked(self.rgb_pool.get_free().expect("video frame pool should have a free frame")) }; let ret = self.scaler.convert(&bt, &mut opic); if ret.is_err() { println!(" scaler error {:?}", ret.err()); return None; } @@ -106,7 +103,7 @@ impl VideoDecoder { }, DecoderType::VideoMT(ref mut vdec, ref mut reord) => { let queue_id = reord.register_frame(); - match vdec.queue_pkt(&mut self.dec.dsupp, &pkt, queue_id) { + match vdec.queue_pkt(&mut self.dec.dsupp, pkt, queue_id) { Ok(true) => {}, Ok(false) => { while !vdec.can_take_input() || vdec.has_output() { @@ -116,17 +113,22 @@ impl VideoDecoder { }, (Err(err), id) => { reord.drop_frame(id); - panic!("frame {} decoding error {:?}", id, err); + if err != DecoderError::MissingReference { + println!("frame {} decoding error {:?}", id, err); + } }, }; } - match vdec.queue_pkt(&mut self.dec.dsupp, &pkt, queue_id) { + match vdec.queue_pkt(&mut self.dec.dsupp, pkt, queue_id) { Ok(true) => {}, - Ok(false) => panic!("still can't queue frame!"), - Err(err) => panic!("queueing error {:?}", err), + Ok(false) => { + println!("still can't queue frame!"); + VDEC_STATE.set_state(DecodingState::Error); + }, + Err(err) => println!("queueing error {:?}", err), }; }, - Err(err) => panic!("queueing error {:?}", err), + Err(err) => println!("queueing error {:?}", err), }; while let Some(frm) = reord.get_frame() { let bt = frm.get_buffer(); @@ -135,6 +137,16 @@ impl VideoDecoder { return self.convert_buf(bt, ts); } }, + #[cfg(feature="hwaccel")] + DecoderType::VideoHW(ref mut vdec) => { + let _ = vdec.queue_pkt(pkt); + while let Some(frm) = vdec.get_frame() { + let bt = frm.get_buffer(); + if let NABufferType::None = bt { continue; } + let ts = frm.get_dts().unwrap_or_else(|| frm.get_pts().unwrap_or(0)); + return self.convert_buf(bt, ts); + } + }, _ => panic!("not a video decoder!"), }; None @@ -159,7 +171,9 @@ impl VideoDecoder { }, (Err(err), id) => { reord.drop_frame(id); - panic!("frame {} decoding error {:?}", id, err); + if err != DecoderError::MissingReference { + println!("frame {} decoding error {:?}", id, err); + } }, }; } @@ -171,7 +185,9 @@ impl VideoDecoder { (Err(DecoderError::NoFrame), _) => {}, (Err(err), id) => { reord.drop_frame(id); - panic!("frame {} decoding error {:?}", id, err); + if err != DecoderError::MissingReference { + println!("frame {} decoding error {:?}", id, err); + } }, }; } @@ -182,6 +198,15 @@ impl VideoDecoder { return self.convert_buf(bt, ts); } }, + #[cfg(feature="hwaccel")] + DecoderType::VideoHW(ref mut vdec) => { + while let Some(frm) = vdec.get_frame() { + let bt = frm.get_buffer(); + if let NABufferType::None = bt { continue; } + let ts = frm.get_dts().unwrap_or_else(|| frm.get_pts().unwrap_or(0)); + return self.convert_buf(bt, ts); + } + }, _ => {}, }; None @@ -204,6 +229,15 @@ impl VideoDecoder { return self.convert_buf(bt, ts); } }, + #[cfg(feature="hwaccel")] + DecoderType::VideoHW(ref mut dec) => { + while let Some(frm) = dec.get_last_frames() { + let bt = frm.get_buffer(); + if let NABufferType::None = bt { continue; } + let ts = frm.get_dts().unwrap_or_else(|| frm.get_pts().unwrap_or(0)); + return self.convert_buf(bt, ts); + } + }, _ => {}, }; None @@ -218,6 +252,10 @@ impl VideoDecoder { dec.flush(); reord.flush(); }, + #[cfg(feature="hwaccel")] + DecoderType::VideoHW(ref mut dec) => { + dec.flush(); + }, _ => {}, }; } @@ -225,49 +263,50 @@ impl VideoDecoder { fn start_video_decoding(width: usize, height: usize, tb_num: u32, tb_den: u32, video_dec: DecoderStuff, vprecv: Receiver, 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(); + vfsend.send((buf, time)).expect("video frame should be sent"); } while let Some((buf, time)) = vdec.more_frames(true) { - vfsend.send((buf, time)).unwrap(); + vfsend.send((buf, time)).expect("video frame should be sent"); } } }, Ok(PktSendEvent::GetFrames) => { while let Some((buf, time)) = vdec.more_frames(false) { - vfsend.send((buf, time)).unwrap(); + vfsend.send((buf, time)).expect("video frame should be sent"); } - 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() { - let ret = vdec.last_frame(); - if ret.is_none() { + if let Some(frm) = vdec.last_frame() { + vfsend.send(frm).expect("video frame should be sent"); + } else { break; } - 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) => { skip_mode = skip_mode.advance(); if let DecoderType::Video(ref mut dec, ref mut _reord) = vdec.dec.dec { + println!("setting hurry up mode to {}", skip_mode.to_string()); dec.set_options(&[NAOption{ name: FRAME_SKIP_OPTION, value: NAValue::String(skip_mode.to_string()), @@ -318,7 +357,7 @@ fn output_yuv(yuv_texture: &mut Texture, buf: &NAVideoBuffer, width: usize, for (dline, sline) in buffer[coff..].chunks_exact_mut(pitch / 2).take(height/2).zip(usrc.chunks(usstride)) { dline[..csize].copy_from_slice(&sline[..csize]); } - }).unwrap(); + }).expect("surface should be locked"); } @@ -335,7 +374,7 @@ impl VideoControl { let (vpsend, vprecv) = std::sync::mpsc::sync_channel::(0); let (vfsend, vfrecv) = std::sync::mpsc::sync_channel::(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 +390,7 @@ impl VideoControl { _ => {}, }; } + VDEC_STATE.set_state(DecodingState::End); }).unwrap() }; @@ -364,7 +404,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(); } @@ -376,7 +416,7 @@ impl VideoControl { self.vqueue.len() >= size } pub fn try_send_video(&mut self, evt: PktSendEvent) -> bool { - if self.vqueue.len() > 0 { + if !self.vqueue.is_empty() { self.vqueue.push(evt); false } else { @@ -401,15 +441,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(()), + }; } } @@ -419,7 +466,7 @@ impl VideoControl { while !disp_queue.is_full() { let is_empty = disp_queue.is_empty(); if let Ok((pic, time)) = self.vfrecv.try_recv() { - let buf = pic.get_vbuf().unwrap(); + let buf = pic.get_vbuf().expect("video frame should be of u8 type"); self.do_yuv = buf.get_info().get_format().get_model().is_yuv(); let idx = disp_queue.end; disp_queue.move_end(); @@ -430,10 +477,10 @@ impl VideoControl { frm.rgb_tex.with_lock(None, |buffer: &mut [u8], pitch: usize| { let csize = sstride.min(pitch); for (dst, src) in buffer.chunks_mut(pitch).zip(src.chunks(sstride)) { - (&mut dst[..csize]).copy_from_slice(&src[..csize]); + dst[..csize].copy_from_slice(&src[..csize]); } true - }).unwrap(); + }).expect("surface should be locked"); } else { output_yuv(&mut frm.yuv_tex, &buf, disp_queue.width, disp_queue.height); } @@ -451,7 +498,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(); }