#![allow(unsafe_code)]
#![allow(clippy::ptr_as_ptr)]
#![allow(clippy::doc_markdown)]
use std::path::Path;
use ff_format::NetworkOptions;
use ff_sys::{AVCodecContext, AVFormatContext, AVFrame, AVPacket};
use crate::error::DecodeError;
use crate::network::{map_network_error, sanitize_url};
pub(crate) struct AvFormatContextGuard(*mut AVFormatContext);
impl AvFormatContextGuard {
pub(crate) unsafe fn new(path: &Path) -> Result<Self, DecodeError> {
let format_ctx = unsafe {
ff_sys::avformat::open_input(path).map_err(|e| DecodeError::Ffmpeg {
code: e,
message: format!("Failed to open file: {}", ff_sys::av_error_string(e)),
})?
};
Ok(Self(format_ctx))
}
pub(crate) unsafe fn new_image_sequence(
path: &Path,
framerate: u32,
) -> Result<Self, DecodeError> {
let format_ctx = unsafe {
ff_sys::avformat::open_input_image_sequence(path, framerate).map_err(|e| {
DecodeError::Ffmpeg {
code: e,
message: format!(
"Failed to open image sequence: {}",
ff_sys::av_error_string(e)
),
}
})?
};
Ok(Self(format_ctx))
}
pub(crate) unsafe fn new_url(url: &str, network: &NetworkOptions) -> Result<Self, DecodeError> {
let format_ctx = unsafe {
ff_sys::avformat::open_input_url(url, network.connect_timeout, network.read_timeout)
.map_err(|e| map_network_error(e, sanitize_url(url)))?
};
Ok(Self(format_ctx))
}
pub(crate) const fn as_ptr(&self) -> *mut AVFormatContext {
self.0
}
pub(crate) fn into_raw(self) -> *mut AVFormatContext {
let ptr = self.0;
std::mem::forget(self);
ptr
}
}
impl Drop for AvFormatContextGuard {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe {
ff_sys::avformat::close_input(&mut (self.0 as *mut _));
}
}
}
}
pub(crate) struct AvCodecContextGuard(*mut AVCodecContext);
impl AvCodecContextGuard {
pub(crate) unsafe fn new(codec: *const ff_sys::AVCodec) -> Result<Self, DecodeError> {
let codec_ctx = unsafe {
ff_sys::avcodec::alloc_context3(codec).map_err(|e| DecodeError::Ffmpeg {
code: e,
message: format!("Failed to allocate codec context: {e}"),
})?
};
Ok(Self(codec_ctx))
}
pub(crate) const fn as_ptr(&self) -> *mut AVCodecContext {
self.0
}
pub(crate) fn into_raw(self) -> *mut AVCodecContext {
let ptr = self.0;
std::mem::forget(self);
ptr
}
}
impl Drop for AvCodecContextGuard {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe {
ff_sys::avcodec::free_context(&mut (self.0 as *mut _));
}
}
}
}
pub(crate) struct AvPacketGuard(*mut AVPacket);
impl AvPacketGuard {
pub(crate) unsafe fn new() -> Result<Self, DecodeError> {
let packet = unsafe { ff_sys::av_packet_alloc() };
if packet.is_null() {
return Err(DecodeError::Ffmpeg {
code: 0,
message: "Failed to allocate packet".to_string(),
});
}
Ok(Self(packet))
}
pub(crate) fn into_raw(self) -> *mut AVPacket {
let ptr = self.0;
std::mem::forget(self);
ptr
}
}
impl Drop for AvPacketGuard {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe {
ff_sys::av_packet_free(&mut (self.0 as *mut _));
}
}
}
}
pub(crate) struct AvFrameGuard(*mut AVFrame);
impl AvFrameGuard {
pub(crate) unsafe fn new() -> Result<Self, DecodeError> {
let frame = unsafe { ff_sys::av_frame_alloc() };
if frame.is_null() {
return Err(DecodeError::Ffmpeg {
code: 0,
message: "Failed to allocate frame".to_string(),
});
}
Ok(Self(frame))
}
pub(crate) const fn as_ptr(&self) -> *mut AVFrame {
self.0
}
pub(crate) fn into_raw(self) -> *mut AVFrame {
let ptr = self.0;
std::mem::forget(self);
ptr
}
}
impl Drop for AvFrameGuard {
fn drop(&mut self) {
if !self.0.is_null() {
unsafe {
ff_sys::av_frame_free(&mut (self.0 as *mut _));
}
}
}
}