use crate::error::AllocFrameError;
use ffmpeg_sys_next::AVMediaType::{
AVMEDIA_TYPE_ATTACHMENT, AVMEDIA_TYPE_AUDIO, AVMEDIA_TYPE_DATA, AVMEDIA_TYPE_SUBTITLE,
AVMEDIA_TYPE_VIDEO,
};
use ffmpeg_sys_next::{
av_freep, avcodec_free_context, avformat_close_input, avformat_free_context, avio_closep,
avio_context_free, AVCodecContext, AVCodecParameters, AVFormatContext, AVIOContext,
AVMediaType, AVRational, AVStream, AVFMT_NOFILE,
};
use std::ffi::c_void;
use std::ptr::null_mut;
use ffmpeg_context::{InputOpaque, OutputOpaque};
pub mod ffmpeg_context;
pub mod ffmpeg_context_builder;
pub mod input;
pub mod output;
pub mod filter_complex;
pub(super) mod decoder_stream;
pub(super) mod demuxer;
pub(super) mod encoder_stream;
pub(super) mod filter_graph;
pub(super) mod input_filter;
pub(super) mod muxer;
pub(super) mod obj_pool;
pub(super) mod output_filter;
pub mod null_output;
pub(crate) struct CodecContext {
inner: *mut AVCodecContext,
}
unsafe impl Send for CodecContext {}
unsafe impl Sync for CodecContext {}
impl CodecContext {
pub(crate) fn new(avcodec_context: *mut AVCodecContext) -> Self {
Self {
inner: avcodec_context,
}
}
pub(crate) fn replace(&mut self, avcodec_context: *mut AVCodecContext) -> *mut AVCodecContext {
let mut tmp = self.inner;
if !tmp.is_null() {
unsafe {
avcodec_free_context(&mut tmp);
}
}
self.inner = avcodec_context;
tmp
}
pub(crate) fn null() -> Self {
Self { inner: null_mut() }
}
pub(crate) fn as_mut_ptr(&self) -> *mut AVCodecContext {
self.inner
}
pub(crate) fn as_ptr(&self) -> *const AVCodecContext {
self.inner as *const AVCodecContext
}
}
impl Drop for CodecContext {
fn drop(&mut self) {
unsafe {
avcodec_free_context(&mut self.inner);
}
}
}
#[derive(Copy, Clone)]
pub(crate) struct Stream {
pub(crate) inner: *mut AVStream,
}
unsafe impl Send for Stream {}
unsafe impl Sync for Stream {}
pub(crate) struct FrameBox {
pub(crate) frame: ffmpeg_next::Frame,
pub(crate) frame_data: FrameData,
}
unsafe impl Send for FrameBox {}
unsafe impl Sync for FrameBox {}
pub fn frame_alloc() -> crate::error::Result<ffmpeg_next::Frame> {
unsafe {
let frame = ffmpeg_next::Frame::empty();
if frame.as_ptr().is_null() {
return Err(AllocFrameError::OutOfMemory.into());
}
Ok(frame)
}
}
pub fn null_frame() -> ffmpeg_next::Frame {
unsafe { ffmpeg_next::Frame::wrap(null_mut()) }
}
#[derive(Clone)]
pub(crate) struct FrameData {
pub(crate) framerate: Option<AVRational>,
pub(crate) bits_per_raw_sample: i32,
pub(crate) input_stream_width: i32,
pub(crate) input_stream_height: i32,
pub(crate) subtitle_header_size: i32,
pub(crate) subtitle_header: *mut u8,
pub(crate) fg_input_index: usize,
}
unsafe impl Send for FrameData {}
unsafe impl Sync for FrameData {}
pub(crate) struct PacketBox {
pub(crate) packet: ffmpeg_next::Packet,
pub(crate) packet_data: PacketData,
}
unsafe impl Send for PacketBox {}
unsafe impl Sync for PacketBox {}
#[derive(Clone)]
pub(crate) struct PacketData {
pub(crate) dts_est: i64,
pub(crate) codec_type: AVMediaType,
pub(crate) output_stream_index: i32,
pub(crate) is_copy: bool,
pub(crate) codecpar: *mut AVCodecParameters,
}
unsafe impl Send for PacketData {}
unsafe impl Sync for PacketData {}
pub(crate) struct AVFormatContextBox {
pub(crate) fmt_ctx: *mut AVFormatContext,
pub(crate) is_input: bool,
pub(crate) is_set_callback: bool,
}
unsafe impl Send for AVFormatContextBox {}
unsafe impl Sync for AVFormatContextBox {}
impl AVFormatContextBox {
pub(crate) fn new(
fmt_ctx: *mut AVFormatContext,
is_input: bool,
is_set_callback: bool,
) -> Self {
Self {
fmt_ctx,
is_input,
is_set_callback,
}
}
}
impl Drop for AVFormatContextBox {
fn drop(&mut self) {
if self.fmt_ctx.is_null() {
return;
}
if self.is_input {
in_fmt_ctx_free(self.fmt_ctx, self.is_set_callback)
} else {
out_fmt_ctx_free(self.fmt_ctx, self.is_set_callback)
}
}
}
pub(crate) fn out_fmt_ctx_free(out_fmt_ctx: *mut AVFormatContext, is_set_write_callback: bool) {
if out_fmt_ctx.is_null() {
return;
}
unsafe {
if is_set_write_callback {
free_output_opaque((*out_fmt_ctx).pb);
} else if (*out_fmt_ctx).flags & AVFMT_NOFILE == 0 {
let mut pb = (*out_fmt_ctx).pb;
if !pb.is_null() {
avio_closep(&mut pb);
}
}
avformat_free_context(out_fmt_ctx);
}
}
unsafe fn free_output_opaque(mut avio_ctx: *mut AVIOContext) {
if avio_ctx.is_null() {
return;
}
if !(*avio_ctx).buffer.is_null() {
av_freep(&mut (*avio_ctx).buffer as *mut _ as *mut c_void);
}
let opaque_ptr = (*avio_ctx).opaque as *mut OutputOpaque;
if !opaque_ptr.is_null() {
let _ = Box::from_raw(opaque_ptr);
}
avio_context_free(&mut avio_ctx);
}
pub(crate) fn in_fmt_ctx_free(mut in_fmt_ctx: *mut AVFormatContext, is_set_read_callback: bool) {
if in_fmt_ctx.is_null() {
return;
}
if is_set_read_callback {
unsafe {
free_input_opaque((*in_fmt_ctx).pb);
}
}
unsafe {
avformat_close_input(&mut in_fmt_ctx);
}
}
unsafe fn free_input_opaque(mut avio_ctx: *mut AVIOContext) {
if !avio_ctx.is_null() {
let opaque_ptr = (*avio_ctx).opaque as *mut InputOpaque;
if !opaque_ptr.is_null() {
let _ = Box::from_raw(opaque_ptr);
}
av_freep(&mut (*avio_ctx).buffer as *mut _ as *mut c_void);
avio_context_free(&mut avio_ctx);
}
}
#[allow(dead_code)]
pub(crate) fn type_to_linklabel(media_type: AVMediaType, index: usize) -> Option<String> {
match media_type {
AVMediaType::AVMEDIA_TYPE_UNKNOWN => None,
AVMEDIA_TYPE_VIDEO => Some(format!("{index}:v")),
AVMEDIA_TYPE_AUDIO => Some(format!("{index}:a")),
AVMEDIA_TYPE_DATA => Some(format!("{index}:d")),
AVMEDIA_TYPE_SUBTITLE => Some(format!("{index}:s")),
AVMEDIA_TYPE_ATTACHMENT => Some(format!("{index}:t")),
AVMediaType::AVMEDIA_TYPE_NB => None,
}
}