use anyhow::{Result, bail};
use std::collections::VecDeque;
use std::os::raw::c_int;
use std::ptr;
use std::sync::{Arc, Mutex};
use crate::frame::ColorSpace;
use super::NvdecError;
use super::ffi::{
CUcontext, CUvideodecoder,
FnCuCtxPopCurrent, FnCuCtxPushCurrent,
FnCuMemcpy2D,
FnCuvidCreateDecoder, FnCuvidDecodePicture, FnCuvidGetDecoderCaps,
FnCuvidMapVideoFrame, FnCuvidUnmapVideoFrame,
};
#[derive(Clone)]
pub struct DecodedFrame {
pub nv12: Vec<u8>,
pub width: u32,
pub height: u32,
pub bit_depth_minus8: u8,
pub color_space: ColorSpace,
pub timestamp: u64,
}
pub struct FrameCollector {
pub frames: VecDeque<DecodedFrame>,
}
pub struct CallbackState {
pub cuvid_create_decoder: FnCuvidCreateDecoder,
pub cuvid_get_decoder_caps: FnCuvidGetDecoderCaps,
pub cuvid_decode_picture: FnCuvidDecodePicture,
pub cuvid_map_video_frame: FnCuvidMapVideoFrame,
pub cuvid_unmap_video_frame: FnCuvidUnmapVideoFrame,
pub cu_memcpy2d: FnCuMemcpy2D,
pub decoder: Option<CUvideodecoder>,
pub collector: Arc<Mutex<FrameCollector>>,
pub width: u32,
pub height: u32,
pub codec_type: c_int,
pub bit_depth_luma_minus8: u8,
pub color_space: ColorSpace,
pub vui_colour_primaries: u8,
pub vui_transfer_characteristics: u8,
pub vui_matrix_coefficients: u8,
pub vui_full_range_flag: bool,
pub error: Option<String>,
pub typed_error: Option<NvdecError>,
}
unsafe impl Send for CallbackState {}
impl CallbackState {
pub fn set_error(&mut self, msg: impl Into<String>) {
if self.error.is_none() {
self.error = Some(msg.into());
}
}
pub fn set_typed_error(&mut self, err: NvdecError) {
if self.typed_error.is_none() {
self.typed_error = Some(err.clone());
}
self.set_error(err.to_string());
}
}
pub struct CtxScope {
pub pop: FnCuCtxPopCurrent,
}
impl CtxScope {
pub unsafe fn push(
ctx: CUcontext,
push: FnCuCtxPushCurrent,
pop: FnCuCtxPopCurrent,
) -> Result<Self> {
unsafe {
if push(ctx) != 0 {
bail!("cuCtxPushCurrent failed");
}
Ok(Self { pop })
}
}
}
impl Drop for CtxScope {
fn drop(&mut self) {
let mut popped: CUcontext = ptr::null_mut();
unsafe {
(self.pop)(&mut popped);
}
}
}