use super::{AVBufferRef, AVDictionary, AVFrame};
use crate::{
error::Result,
ffi,
shared::{PointerUpgrade, RetUpgrade},
};
pub use ffi::AVHWDeviceType;
use std::{
ffi::CStr,
ops::{Deref, DerefMut},
os::raw::c_int,
ptr::{self, NonNull},
};
#[derive(Clone)]
#[repr(transparent)]
pub struct AVHWDeviceContext {
buffer_ref: AVBufferRef,
}
impl AVHWDeviceContext {
pub fn alloc(r#type: AVHWDeviceType) -> Self {
let buffer_ref = unsafe { ffi::av_hwdevice_ctx_alloc(r#type) };
let buffer_ref = buffer_ref.upgrade().unwrap();
Self {
buffer_ref: unsafe { AVBufferRef::from_raw(buffer_ref) },
}
}
pub fn init(&mut self) -> Result<()> {
unsafe { ffi::av_hwdevice_ctx_init(self.buffer_ref.as_mut_ptr()) }.upgrade()?;
Ok(())
}
pub fn create(
r#type: AVHWDeviceType,
device: Option<&CStr>,
opts: Option<&AVDictionary>,
flags: c_int,
) -> Result<Self> {
let mut ptr = ptr::null_mut();
let opts = opts.map(|opts| opts.as_ptr()).unwrap_or_else(ptr::null);
let device = device
.map(|device| device.as_ptr())
.unwrap_or_else(ptr::null);
unsafe { ffi::av_hwdevice_ctx_create(&mut ptr, r#type, device, opts as *mut _, flags) }
.upgrade()?;
let ptr = ptr.upgrade().unwrap();
let buffer_ref = unsafe { AVBufferRef::from_raw(ptr) };
Ok(Self { buffer_ref })
}
pub fn create_derived(&self, r#type: AVHWDeviceType) -> Result<Self> {
let mut ptr = ptr::null_mut();
unsafe {
ffi::av_hwdevice_ctx_create_derived(&mut ptr, r#type, self.as_ptr() as *mut _, 0)
}
.upgrade()?;
let ptr = ptr.upgrade().unwrap();
Ok(Self {
buffer_ref: unsafe { AVBufferRef::from_raw(ptr) },
})
}
pub fn create_derived_opts(
&self,
r#type: AVHWDeviceType,
options: Option<&AVDictionary>,
) -> Result<Self> {
let mut ptr = ptr::null_mut();
let options = options.map(|opts| opts.as_ptr()).unwrap_or_else(ptr::null);
unsafe {
ffi::av_hwdevice_ctx_create_derived_opts(
&mut ptr,
r#type,
self.as_ptr() as *mut _,
options as *mut _,
0,
)
}
.upgrade()?;
let ptr = ptr.upgrade().unwrap();
Ok(Self {
buffer_ref: unsafe { AVBufferRef::from_raw(ptr) },
})
}
pub fn hwframe_ctx_alloc(&self) -> AVHWFramesContext {
let buffer_ref = unsafe {
ffi::av_hwframe_ctx_alloc(self.as_ptr() as *mut _)
.upgrade()
.unwrap()
};
AVHWFramesContext {
buffer_ref: unsafe { AVBufferRef::from_raw(buffer_ref) },
}
}
pub fn into_inner(self) -> AVBufferRef {
self.buffer_ref
}
}
impl Deref for AVHWDeviceContext {
type Target = AVBufferRef;
fn deref(&self) -> &Self::Target {
&self.buffer_ref
}
}
impl DerefMut for AVHWDeviceContext {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.buffer_ref
}
}
#[derive(Clone)]
#[repr(transparent)]
pub struct AVHWFramesContext {
buffer_ref: AVBufferRef,
}
wrap_ref_pure!((AVHWFramesContext, AVHWFramesContextRef): ffi::AVBufferRef);
wrap_mut_pure!((AVHWFramesContext, AVHWFramesContextMut): ffi::AVBufferRef);
impl AVHWFramesContext {
pub fn init(&mut self) -> Result<()> {
unsafe { ffi::av_hwframe_ctx_init(self.buffer_ref.as_mut_ptr()) }.upgrade()?;
Ok(())
}
pub fn data(&mut self) -> &mut ffi::AVHWFramesContext {
unsafe { &mut *(self.buffer_ref.data as *mut ffi::AVHWFramesContext) }
}
pub fn get_buffer(&mut self, frame: &mut AVFrame) -> Result<()> {
unsafe { ffi::av_hwframe_get_buffer(self.buffer_ref.as_mut_ptr(), frame.as_mut_ptr(), 0) }
.upgrade()?;
Ok(())
}
pub unsafe fn from_raw(raw: NonNull<ffi::AVBufferRef>) -> Self {
Self {
buffer_ref: unsafe { AVBufferRef::from_raw(raw) },
}
}
pub fn into_inner(self) -> AVBufferRef {
self.buffer_ref
}
}
impl Deref for AVHWFramesContext {
type Target = AVBufferRef;
fn deref(&self) -> &Self::Target {
&self.buffer_ref
}
}
impl DerefMut for AVHWFramesContext {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.buffer_ref
}
}
pub fn hwdevice_find_type_by_name(name: &CStr) -> AVHWDeviceType {
unsafe { ffi::av_hwdevice_find_type_by_name(name.as_ptr()) }
}
pub fn hwdevice_get_type_name(r#type: AVHWDeviceType) -> Option<&'static CStr> {
unsafe {
ffi::av_hwdevice_get_type_name(r#type)
.upgrade()
.map(|x| CStr::from_ptr(x.as_ptr()))
}
}
pub fn hwdevice_iterate_types() -> AVHWDeviceTypeIter {
AVHWDeviceTypeIter::new()
}
pub struct AVHWDeviceTypeIter {
prev: AVHWDeviceType,
}
impl AVHWDeviceTypeIter {
fn new() -> Self {
Self {
prev: ffi::AV_HWDEVICE_TYPE_NONE,
}
}
}
impl Iterator for AVHWDeviceTypeIter {
type Item = AVHWDeviceType;
fn next(&mut self) -> Option<Self::Item> {
let next = unsafe { ffi::av_hwdevice_iterate_types(self.prev) };
if next == ffi::AV_HWDEVICE_TYPE_NONE {
None
} else {
self.prev = next;
Some(next)
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hw_device_iterate_types() {
let mut iter = hwdevice_iterate_types();
while let Some(device_type) = iter.next() {
dbg!(hwdevice_get_type_name(device_type).unwrap());
assert_ne!(device_type, ffi::AV_HWDEVICE_TYPE_NONE);
}
}
}