use crate::av::dictionary::Dictionary; use crate::av::stream::Stream; use crate::av::{verify_response, Rational}; use crate::av_err2str; use ffmpeg_sys_next::AVPixelFormat::AV_PIX_FMT_NONE; use ffmpeg_sys_next::{ av_free, av_get_channel_layout_string, av_get_pix_fmt_name, av_get_sample_fmt_name, av_malloc, avcodec_flush_buffers, avcodec_open2, AVCodecContext, AVCodecID, AVColorPrimaries, AVColorRange, AVColorTransferCharacteristic, AVPixelFormat, AVRational, AVSampleFormat, AVERROR, AVERROR_EOF, EAGAIN, }; use num_rational::Ratio; use std::ffi::CStr; use std::os::raw::c_int; use std::ptr::null_mut; pub trait XCoder: Sized { fn from_name(name: &str) -> Option; fn as_mut_ptr(&self) -> *mut AVCodecContext; #[inline] fn as_ptr(&self) -> *const AVCodecContext { self.as_mut_ptr() } fn name(&self) -> String { unsafe { if let Some(x) = (*(*self.as_ptr()).av_class).item_name { CStr::from_ptr(x(self.as_mut_ptr().cast())) .to_str() .unwrap_or("") .to_string() } else { String::new() } } } fn configure(&self, stream: &Stream) -> Result<(), String>; fn open(&self) -> Result<(), String> { let ctx = self.as_mut_ptr(); let resp = unsafe { avcodec_open2(ctx, (*ctx).codec, null_mut()) }; if resp < 0 { return Err(format!( "Failed configuring coder from stream (code {}: {})", resp, av_err2str(resp) )); } Ok(()) } #[inline] fn codec(&self) -> AVCodecID { unsafe { (*(*self.as_ptr()).codec).id } } #[inline] fn time_base(&self) -> Ratio { unsafe { (*self.as_ptr()).time_base.to_num() } } #[inline] fn set_time_base(&self, ratio: R) { unsafe { (*self.as_mut_ptr()).time_base = ratio.to_av() } } #[inline] fn pixel_format(&self) -> AVPixelFormat { unsafe { (*self.as_ptr()).pix_fmt } } #[inline] fn pixel_format_name(&self) -> String { unsafe { CStr::from_ptr(av_get_pix_fmt_name(self.pixel_format())) .to_str() .unwrap() .to_string() } } #[inline] fn set_pixel_format(&self, pixel_format: AVPixelFormat) { unsafe { (*self.as_mut_ptr()).pix_fmt = pixel_format } } #[inline] fn width(&self) -> c_int { unsafe { (*self.as_ptr()).width } } #[inline] fn set_width(&self, width: c_int) { unsafe { (*self.as_mut_ptr()).width = width } } #[inline] fn height(&self) -> c_int { unsafe { (*self.as_ptr()).height } } #[inline] fn set_height(&self, height: c_int) { unsafe { (*self.as_mut_ptr()).height = height } } #[inline] fn bit_rate(&self) -> i64 { unsafe { (*self.as_mut_ptr()).bit_rate } } #[inline] fn set_bit_rate(&self, bit_rate: i64) { unsafe { (*self.as_mut_ptr()).bit_rate = bit_rate; } } #[inline] fn sample_aspect_ratio(&self) -> AVRational { unsafe { (*self.as_ptr()).sample_aspect_ratio } } #[inline] fn color_range(&self) -> AVColorRange { unsafe { (*self.as_ptr()).color_range } } #[inline] fn set_color_range(&self, color_range: AVColorRange) { unsafe { (*self.as_mut_ptr()).color_range = color_range } } #[inline] fn color_primaries(&self) -> AVColorPrimaries { unsafe { (*self.as_ptr()).color_primaries } } #[inline] fn set_color_primaries(&self, color_primaries: AVColorPrimaries) { unsafe { (*self.as_mut_ptr()).color_primaries = color_primaries } } #[inline] fn color_trc(&self) -> AVColorTransferCharacteristic { unsafe { (*self.as_ptr()).color_trc } } #[inline] fn set_color_trc(&self, color_trc: AVColorTransferCharacteristic) { unsafe { (*self.as_mut_ptr()).color_trc = color_trc } } #[inline] fn channels(&self) -> i32 { unsafe { (*self.as_ptr()).channels } } #[inline] fn set_channels(&self, channels: i32) { unsafe { (*self.as_mut_ptr()).channels = channels } } #[inline] fn channel_layout(&self) -> u64 { unsafe { (*self.as_ptr()).channel_layout } } #[inline] fn set_channel_layout(&self, channel_layout: u64) { unsafe { (*self.as_mut_ptr()).channel_layout = channel_layout } } fn channel_layout_name(&self) -> String { unsafe { let str = av_malloc(1024).cast(); av_get_channel_layout_string(str, 1024, self.channels(), self.channel_layout()); let string = CStr::from_ptr(str).to_str().unwrap().to_string(); av_free(str.cast()); string } } #[inline] fn sample_format(&self) -> AVSampleFormat { unsafe { (*self.as_ptr()).sample_fmt } } #[inline] fn sample_format_name(&self) -> String { unsafe { CStr::from_ptr(av_get_sample_fmt_name(self.sample_format())) .to_str() .unwrap() .to_string() } } #[inline] fn set_sample_format(&self, sample_format: AVSampleFormat) { unsafe { (*self.as_mut_ptr()).sample_fmt = sample_format } } #[inline] fn frame_size(&self) -> i32 { unsafe { (*self.as_ptr()).frame_size } } #[inline] fn set_frame_size(&self, frame_size: i32) { unsafe { (*self.as_mut_ptr()).frame_size = frame_size } } #[inline] fn sample_rate(&self) -> i32 { unsafe { (*self.as_ptr()).sample_rate } } #[inline] fn set_sample_rate(&self, sample_rate: i32) { unsafe { (*self.as_mut_ptr()).sample_rate = sample_rate } } #[inline] fn extra_data(&self) -> Vec { unsafe { let extra_data_size = (*self.as_ptr()).extradata_size as usize; let mut extra_data = vec![0u8; extra_data_size]; (*self.as_ptr()) .extradata .copy_to(extra_data.as_mut_ptr(), extra_data_size); extra_data } } #[inline] fn set_extra_data(&self, extra_data: Vec) { unsafe { let new_extra_data: *mut u8 = av_malloc(extra_data.len()).cast(); (*self.as_mut_ptr()).extradata = new_extra_data; (*self.as_mut_ptr()).extradata_size = extra_data.len() as i32; } } fn flush(&self) { unsafe { avcodec_flush_buffers(self.as_mut_ptr()); } } fn set_private_data(&self, key: &str, value: &str) { unsafe { Dictionary { ptr: (*self.as_ptr()).priv_data.cast(), owned: false, } .set(key, value) } } fn pixel_formats(&self) -> Vec { let mut pixel_formats = vec![]; unsafe { let mut current = (*(*self.as_ptr()).codec).pix_fmts; while *current != AV_PIX_FMT_NONE { pixel_formats.push(*current); current = current.add(1); } } pixel_formats } fn sample_formats(&self) -> Vec { let mut sample_formats = vec![]; unsafe { let mut current = (*(*self.as_ptr()).codec).sample_fmts; while *current != AVSampleFormat::AV_SAMPLE_FMT_NONE { sample_formats.push(*current); current = current.add(1); } } sample_formats } } pub(crate) fn process_return(error: &str, resp: i32) -> Result { if resp == AVERROR(EAGAIN) || resp == AVERROR_EOF { Ok(false) } else { verify_response(error, resp).and(Ok(true)) } }