use anyhow::{bail, Result};
use std::ffi::c_void;
use std::os::raw::c_uint;
use std::ptr;
use super::constants::{
CUcontext, FnCuCtxDestroy, FnCuCtxPopCurrent, FnCuCtxPushCurrent, FnNvEncDestroyBitstreamBuffer,
FnNvEncDestroyEncoder, FnNvEncDestroyInputBuffer, FnNvEncEncodePicture, FnNvEncLockBitstream,
FnNvEncLockInputBuffer, FnNvEncUnlockBitstream, FnNvEncUnlockInputBuffer, RING_SIZE,
};
pub(super) struct EncodeSession {
pub(super) encoder: *mut c_void,
pub(super) input_buffers: [*mut c_void; RING_SIZE],
pub(super) bitstream_buffers: [*mut c_void; RING_SIZE],
pub(super) cuda_ctx: CUcontext,
pub(super) width: u32,
pub(super) height: u32,
pub(super) buffer_format: c_uint,
pub(super) fn_destroy_input_buffer: FnNvEncDestroyInputBuffer,
pub(super) fn_destroy_bitstream_buffer: FnNvEncDestroyBitstreamBuffer,
pub(super) fn_lock_input_buffer: FnNvEncLockInputBuffer,
pub(super) fn_unlock_input_buffer: FnNvEncUnlockInputBuffer,
pub(super) fn_encode_picture: FnNvEncEncodePicture,
pub(super) fn_lock_bitstream: FnNvEncLockBitstream,
pub(super) fn_unlock_bitstream: FnNvEncUnlockBitstream,
pub(super) fn_destroy_encoder: FnNvEncDestroyEncoder,
pub(super) fn_cu_ctx_destroy: FnCuCtxDestroy,
pub(super) fn_cu_ctx_push: FnCuCtxPushCurrent,
pub(super) fn_cu_ctx_pop: FnCuCtxPopCurrent,
}
unsafe impl Send for EncodeSession {}
impl EncodeSession {
pub(super) unsafe fn ctx_scope(&self) -> Result<CtxScope> {
unsafe { CtxScope::push(self.cuda_ctx, self.fn_cu_ctx_push, self.fn_cu_ctx_pop) }
}
}
impl Drop for EncodeSession {
fn drop(&mut self) {
unsafe {
let _scope =
CtxScope::push(self.cuda_ctx, self.fn_cu_ctx_push, self.fn_cu_ctx_pop).ok();
for i in (0..RING_SIZE).rev() {
if !self.input_buffers[i].is_null() {
(self.fn_destroy_input_buffer)(self.encoder, self.input_buffers[i]);
}
if !self.bitstream_buffers[i].is_null() {
(self.fn_destroy_bitstream_buffer)(self.encoder, self.bitstream_buffers[i]);
}
}
if !self.encoder.is_null() {
(self.fn_destroy_encoder)(self.encoder);
}
drop(_scope);
if !self.cuda_ctx.is_null() {
(self.fn_cu_ctx_destroy)(self.cuda_ctx);
}
}
}
}
pub(super) struct CtxScope {
pop: FnCuCtxPopCurrent,
}
impl CtxScope {
pub(super) 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);
}
}
}