diff --git a/src/device/input.rs b/src/device/input.rs index 032f31b..d523ca3 100644 --- a/src/device/input.rs +++ b/src/device/input.rs @@ -3,50 +3,60 @@ use std::ptr; use crate::ffi::*; use crate::format; -pub struct AudioIter(*mut AVInputFormat); +pub struct AudioIter(*const AVInputFormat); impl Iterator for AudioIter { type Item = format::Input; fn next(&mut self) -> Option<::Item> { unsafe { - let ptr = av_input_audio_device_next(self.0) as *mut AVInputFormat; + let inner = self.0; - if ptr.is_null() && !self.0.is_null() { - None - } else { + // Pre-5.0 FFmpeg uses a non-const pointer here + #[cfg(not(feature = "ffmpeg_5_0"))] + let inner = inner as *mut _; + + let ptr = av_input_audio_device_next(inner); + + if let Some(input) = format::Input::from_raw(ptr) { self.0 = ptr; - - Some(format::Input::wrap(ptr)) + Some(input) + } else { + None } } } } pub fn audio() -> AudioIter { - AudioIter(ptr::null_mut()) + AudioIter(ptr::null()) } -pub struct VideoIter(*mut AVInputFormat); +pub struct VideoIter(*const AVInputFormat); impl Iterator for VideoIter { type Item = format::Input; fn next(&mut self) -> Option<::Item> { unsafe { - let ptr = av_input_video_device_next(self.0) as *mut AVInputFormat; + let inner = self.0; - if ptr.is_null() && !self.0.is_null() { - None - } else { + // Pre-5.0 FFmpeg uses a non-const pointer here + #[cfg(not(feature = "ffmpeg_5_0"))] + let inner = inner as *mut _; + + let ptr = av_input_video_device_next(inner); + + if let Some(input) = format::Input::from_raw(ptr) { self.0 = ptr; - - Some(format::Input::wrap(ptr)) + Some(input) + } else { + None } } } } pub fn video() -> VideoIter { - VideoIter(ptr::null_mut()) + VideoIter(ptr::null()) } diff --git a/src/device/output.rs b/src/device/output.rs index d68180b..8268eff 100644 --- a/src/device/output.rs +++ b/src/device/output.rs @@ -3,21 +3,26 @@ use std::ptr; use crate::ffi::*; use crate::format; -pub struct AudioIter(*mut AVOutputFormat); +pub struct AudioIter(*const AVOutputFormat); impl Iterator for AudioIter { type Item = format::Output; fn next(&mut self) -> Option<::Item> { unsafe { - let ptr = av_output_audio_device_next(self.0) as *mut AVOutputFormat; + let inner = self.0; - if ptr.is_null() && !self.0.is_null() { - None + // Pre-5.0 FFmpeg uses a non-const pointer here + #[cfg(not(feature = "ffmpeg_5_0"))] + let inner = inner as *mut _; + + let ptr = av_output_audio_device_next(inner); + + if let Some(output) = format::Output::from_raw(ptr) { + self.0 = ptr; + Some(output) } else { - self.0 = ptr as *mut AVOutputFormat; - - Some(format::Output::wrap(ptr)) + None } } } @@ -27,21 +32,26 @@ pub fn audio() -> AudioIter { AudioIter(ptr::null_mut()) } -pub struct VideoIter(*mut AVOutputFormat); +pub struct VideoIter(*const AVOutputFormat); impl Iterator for VideoIter { type Item = format::Output; fn next(&mut self) -> Option<::Item> { unsafe { - let ptr = av_output_video_device_next(self.0) as *mut AVOutputFormat; + let inner = self.0; - if ptr.is_null() && !self.0.is_null() { - None + // Pre-5.0 FFmpeg uses a non-const pointer here + #[cfg(not(feature = "ffmpeg_5_0"))] + let inner = inner as *mut _; + + let ptr = av_output_video_device_next(inner); + + if let Some(output) = format::Output::from_raw(ptr) { + self.0 = ptr; + Some(output) } else { - self.0 = ptr as *mut AVOutputFormat; - - Some(format::Output::wrap(ptr)) + None } } } diff --git a/src/format/context/input.rs b/src/format/context/input.rs index d03d360..277ab45 100644 --- a/src/format/context/input.rs +++ b/src/format/context/input.rs @@ -36,7 +36,7 @@ impl Input { impl Input { pub fn format(&self) -> format::Input { - unsafe { format::Input::wrap((*self.as_ptr()).iformat as *mut AVInputFormat) } + unsafe { format::Input::from_raw((*self.as_ptr()).iformat).expect("iformat is non-null") } } #[cfg(not(feature = "ffmpeg_5_0"))] diff --git a/src/format/context/output.rs b/src/format/context/output.rs index 0443fce..0856003 100644 --- a/src/format/context/output.rs +++ b/src/format/context/output.rs @@ -35,7 +35,7 @@ impl Output { impl Output { pub fn format(&self) -> format::Output { - unsafe { format::Output::wrap((*self.as_ptr()).oformat as *mut AVOutputFormat) } + unsafe { format::Output::from_raw((*self.as_ptr()).oformat).expect("oformat is non-null") } } pub fn write_header(&mut self) -> Result<(), Error> { diff --git a/src/format/format/input.rs b/src/format/format/input.rs index b646b96..58bf05a 100644 --- a/src/format/format/input.rs +++ b/src/format/format/input.rs @@ -1,34 +1,37 @@ +use std::ptr::NonNull; + use crate::ffi::*; use crate::utils; +use super::Flags; + +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Input { - ptr: *mut AVInputFormat, + ptr: NonNull, } impl Input { - pub unsafe fn wrap(ptr: *mut AVInputFormat) -> Self { - Input { ptr } + pub unsafe fn from_raw(ptr: *const AVInputFormat) -> Option { + NonNull::new(ptr as *mut _).map(|ptr| Self { ptr }) } - pub unsafe fn as_ptr(&self) -> *const AVInputFormat { - self.ptr as *const _ + pub fn as_ptr(self) -> *const AVInputFormat { + self.ptr.as_ptr() } - pub unsafe fn as_mut_ptr(&mut self) -> *mut AVInputFormat { - self.ptr - } -} - -impl Input { - pub fn name(&self) -> &str { + pub fn name(self) -> &'static str { unsafe { utils::str_from_c_ptr((*self.as_ptr()).name) } } - pub fn description(&self) -> &str { + pub fn description(self) -> &'static str { unsafe { utils::optional_str_from_c_ptr((*self.as_ptr()).long_name).unwrap_or("") } } - pub fn extensions(&self) -> Vec<&str> { + pub fn flags(self) -> Flags { + unsafe { Flags::from_bits_truncate((*self.as_ptr()).flags) } + } + + pub fn extensions(self) -> Vec<&'static str> { unsafe { let ptr = (*self.as_ptr()).extensions; @@ -40,7 +43,7 @@ impl Input { } } - pub fn mime_types(&self) -> Vec<&str> { + pub fn mime_types(self) -> Vec<&'static str> { unsafe { let ptr = (*self.as_ptr()).mime_type; diff --git a/src/format/format/iter.rs b/src/format/format/iter.rs index 884375c..ae26443 100644 --- a/src/format/format/iter.rs +++ b/src/format/format/iter.rs @@ -26,11 +26,7 @@ impl Iterator for DemuxerIter { fn next(&mut self) -> Option { unsafe { let next = av_demuxer_iterate(&mut self.ptr); - if next.is_null() { - None - } else { - Some(Input::wrap(next as _)) - } + Input::from_raw(next) } } } @@ -57,11 +53,7 @@ impl Iterator for MuxerIter { fn next(&mut self) -> Option { unsafe { let next = av_muxer_iterate(&mut self.ptr); - if next.is_null() { - None - } else { - Some(Output::wrap(next as _)) - } + Output::from_raw(next) } } } diff --git a/src/format/format/output.rs b/src/format/format/output.rs index 4bffbe6..e874fc6 100644 --- a/src/format/format/output.rs +++ b/src/format/format/output.rs @@ -1,40 +1,39 @@ use std::path::Path; use std::ffi::CString; -use std::ptr; +use std::ptr::{self, NonNull}; use super::Flags; use crate::ffi::*; use crate::{codec, media, utils}; +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Output { - ptr: *mut AVOutputFormat, + ptr: NonNull, } impl Output { - pub unsafe fn wrap(ptr: *mut AVOutputFormat) -> Self { - Output { ptr } + pub unsafe fn from_raw(ptr: *const AVOutputFormat) -> Option { + NonNull::new(ptr as *mut _).map(|ptr| Self { ptr }) } - pub unsafe fn as_ptr(&self) -> *const AVOutputFormat { - self.ptr as *const _ + pub fn as_ptr(self) -> *const AVOutputFormat { + self.ptr.as_ptr() } - pub unsafe fn as_mut_ptr(&mut self) -> *mut AVOutputFormat { - self.ptr - } -} - -impl Output { - pub fn name(&self) -> &str { + pub fn name(self) -> &'static str { unsafe { utils::str_from_c_ptr((*self.as_ptr()).name) } } - pub fn description(&self) -> &str { + pub fn description(self) -> &'static str { unsafe { utils::optional_str_from_c_ptr((*self.as_ptr()).long_name).unwrap_or("") } } - pub fn extensions(&self) -> Vec<&str> { + pub fn flags(self) -> Flags { + unsafe { Flags::from_bits_truncate((*self.as_ptr()).flags) } + } + + pub fn extensions(self) -> Vec<&'static str> { unsafe { let ptr = (*self.as_ptr()).extensions; @@ -46,7 +45,7 @@ impl Output { } } - pub fn mime_types(&self) -> Vec<&str> { + pub fn mime_types(self) -> Vec<&'static str> { unsafe { let ptr = (*self.as_ptr()).mime_type; @@ -58,9 +57,9 @@ impl Output { } } - pub fn codec>(&self, path: &P, kind: media::Type) -> codec::Id { + pub fn codec>(self, path: &P, kind: media::Type) -> codec::Id { // XXX: use to_cstring when stable - let path = CString::new(path.as_ref().as_os_str().to_str().unwrap()).unwrap(); + let path = CString::new(path.as_ref().to_str().unwrap()).unwrap(); unsafe { codec::Id::from(av_guess_codec( @@ -72,8 +71,4 @@ impl Output { )) } } - - pub fn flags(&self) -> Flags { - unsafe { Flags::from_bits_truncate((*self.as_ptr()).flags) } - } } diff --git a/src/format/mod.rs b/src/format/mod.rs index 4a83d05..c6913ba 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -23,27 +23,6 @@ use crate::ffi::*; use crate::utils; use crate::{Dictionary, Error}; -#[cfg(not(feature = "ffmpeg_5_0"))] -pub fn register_all() { - unsafe { - av_register_all(); - } -} - -#[cfg(not(feature = "ffmpeg_5_0"))] -pub fn register_input(mut format: Input) { - unsafe { - av_register_input_format(format.as_mut_ptr()); - } -} - -#[cfg(not(feature = "ffmpeg_5_0"))] -pub fn register_output(mut format: Output) { - unsafe { - av_register_output_format(format.as_mut_ptr()); - } -} - pub fn version() -> u32 { unsafe { avformat_version() } } diff --git a/src/lib.rs b/src/lib.rs index 7e1f041..c612651 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -83,11 +83,6 @@ fn init_error() { util::error::register_all(); } -#[cfg(all(feature = "format", not(feature = "ffmpeg_5_0")))] -fn init_format() { - format::register_all(); -} - #[cfg(not(feature = "format"))] fn init_format() {} @@ -109,8 +104,6 @@ fn init_filter() {} pub fn init() -> Result<(), Error> { init_error(); - #[cfg(not(feature = "ffmpeg_5_0"))] - init_format(); init_device(); #[cfg(not(feature = "ffmpeg_5_0"))] init_filter();