From 6a9886814acc6059073e04a264ae3b45b9cd127a Mon Sep 17 00:00:00 2001 From: Marijn Suijten Date: Tue, 24 Oct 2023 16:53:02 +0200 Subject: [PATCH] ndk/media: Move `MediaFormat` to its own module (#442) This type is used outside of `media_codec`, for example in the `media_extractor` bindings. --- ndk/CHANGELOG.md | 2 + ndk/src/media/media_codec.rs | 215 ++-------------------------------- ndk/src/media/media_format.rs | 210 +++++++++++++++++++++++++++++++++ ndk/src/media/mod.rs | 1 + 4 files changed, 222 insertions(+), 206 deletions(-) create mode 100644 ndk/src/media/media_format.rs diff --git a/ndk/CHANGELOG.md b/ndk/CHANGELOG.md index 1292ad57..8fdf6d03 100644 --- a/ndk/CHANGELOG.md +++ b/ndk/CHANGELOG.md @@ -1,5 +1,7 @@ # Unreleased +- Move `MediaFormat` from `media::media_codec` to its own `media::media_format` module. (#442) + # 0.8.0 (2023-10-15) - event: Add `tool_type` getter for `Pointer`. (#323) diff --git a/ndk/src/media/media_codec.rs b/ndk/src/media/media_codec.rs index 4847a614..68b64123 100644 --- a/ndk/src/media/media_codec.rs +++ b/ndk/src/media/media_codec.rs @@ -1,14 +1,15 @@ -//! Bindings for [`AMediaFormat`] and [`AMediaCodec`] +//! Bindings for [`AMediaCodec`] //! -//! [`AMediaFormat`]: https://developer.android.com/ndk/reference/group/media#amediaformat //! [`AMediaCodec`]: https://developer.android.com/ndk/reference/group/media#amediacodec +#[deprecated = "MediaFormat should be referenced directly from the media_format module"] +pub use super::media_format::MediaFormat; use crate::media_error::{MediaError, Result}; use crate::native_window::NativeWindow; use crate::utils::abort_on_panic; use std::{ ffi::{c_char, c_void, CStr, CString}, - fmt::Display, + fmt, mem::MaybeUninit, pin::Pin, ptr::{self, NonNull}, @@ -22,204 +23,6 @@ pub enum MediaCodecDirection { Encoder, } -/// A native [`AMediaFormat *`] -/// -/// [`AMediaFormat *`]: https://developer.android.com/ndk/reference/group/media#amediaformat -#[derive(Debug)] -pub struct MediaFormat { - inner: NonNull, -} - -impl Display for MediaFormat { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let c_str = unsafe { CStr::from_ptr(ffi::AMediaFormat_toString(self.as_ptr())) }; - f.write_str(c_str.to_str().unwrap()) - } -} - -impl Default for MediaFormat { - fn default() -> Self { - Self::new() - } -} - -impl MediaFormat { - /// Assumes ownership of `ptr` - /// - /// # Safety - /// `ptr` must be a valid pointer to an Android [`ffi::AMediaFormat`]. - pub unsafe fn from_ptr(ptr: NonNull) -> Self { - Self { inner: ptr } - } - - fn as_ptr(&self) -> *mut ffi::AMediaFormat { - self.inner.as_ptr() - } - - pub fn new() -> Self { - Self { - inner: NonNull::new(unsafe { ffi::AMediaFormat_new() }).unwrap(), - } - } - - pub fn i32(&self, key: &str) -> Option { - let name = CString::new(key).unwrap(); - let mut out = 0; - if unsafe { ffi::AMediaFormat_getInt32(self.as_ptr(), name.as_ptr(), &mut out) } { - Some(out) - } else { - None - } - } - - pub fn i64(&self, key: &str) -> Option { - let name = CString::new(key).unwrap(); - let mut out = 0; - if unsafe { ffi::AMediaFormat_getInt64(self.as_ptr(), name.as_ptr(), &mut out) } { - Some(out) - } else { - None - } - } - - pub fn f32(&self, key: &str) -> Option { - let name = CString::new(key).unwrap(); - let mut out = 0.0; - if unsafe { ffi::AMediaFormat_getFloat(self.as_ptr(), name.as_ptr(), &mut out) } { - Some(out) - } else { - None - } - } - - pub fn usize(&self, key: &str) -> Option { - let name = CString::new(key).unwrap(); - let mut out = 0; - if unsafe { ffi::AMediaFormat_getSize(self.as_ptr(), name.as_ptr(), &mut out) } { - Some(out) - } else { - None - } - } - - pub fn buffer(&self, key: &str) -> Option<&[u8]> { - let name = CString::new(key).unwrap(); - let mut out_buffer = ptr::null_mut(); - let mut out_size = 0; - unsafe { - ffi::AMediaFormat_getBuffer( - self.as_ptr(), - name.as_ptr(), - &mut out_buffer, - &mut out_size, - ) - } - .then(|| unsafe { slice::from_raw_parts(out_buffer.cast(), out_size) }) - } - - pub fn str(&self, key: &str) -> Option<&str> { - let name = CString::new(key).unwrap(); - let mut out = ptr::null(); - unsafe { ffi::AMediaFormat_getString(self.as_ptr(), name.as_ptr(), &mut out) } - .then(|| unsafe { CStr::from_ptr(out) }.to_str().unwrap()) - } - - pub fn set_i32(&self, key: &str, value: i32) { - let name = CString::new(key).unwrap(); - unsafe { ffi::AMediaFormat_setInt32(self.as_ptr(), name.as_ptr(), value) }; - } - - pub fn set_i64(&self, key: &str, value: i64) { - let name = CString::new(key).unwrap(); - unsafe { ffi::AMediaFormat_setInt64(self.as_ptr(), name.as_ptr(), value) }; - } - - pub fn set_f32(&self, key: &str, value: f32) { - let name = CString::new(key).unwrap(); - unsafe { ffi::AMediaFormat_setFloat(self.as_ptr(), name.as_ptr(), value) }; - } - - pub fn set_str(&self, key: &str, value: &str) { - let name = CString::new(key).unwrap(); - let c_string = CString::new(value).unwrap(); - unsafe { ffi::AMediaFormat_setString(self.as_ptr(), name.as_ptr(), c_string.as_ptr()) }; - } - - pub fn set_buffer(&self, key: &str, value: &[u8]) { - let name = CString::new(key).unwrap(); - unsafe { - ffi::AMediaFormat_setBuffer( - self.as_ptr(), - name.as_ptr(), - value.as_ptr().cast(), - value.len(), - ) - }; - } - - #[cfg(feature = "api-level-28")] - pub fn f64(&self, key: &str) -> Option { - let name = CString::new(key).unwrap(); - let mut out = 0.0; - if unsafe { ffi::AMediaFormat_getDouble(self.as_ptr(), name.as_ptr(), &mut out) } { - Some(out) - } else { - None - } - } - - /// Returns (left, top, right, bottom) - #[cfg(feature = "api-level-28")] - pub fn rect(&self, key: &str) -> Option<(i32, i32, i32, i32)> { - let name = CString::new(key).unwrap(); - let mut left = 0; - let mut top = 0; - let mut right = 0; - let mut bottom = 0; - if unsafe { - ffi::AMediaFormat_getRect( - self.as_ptr(), - name.as_ptr(), - &mut left, - &mut top, - &mut right, - &mut bottom, - ) - } { - Some((left, top, right, bottom)) - } else { - None - } - } - - #[cfg(feature = "api-level-28")] - pub fn set_f64(&self, key: &str, value: f64) { - let name = CString::new(key).unwrap(); - unsafe { ffi::AMediaFormat_setDouble(self.as_ptr(), name.as_ptr(), value) }; - } - - #[cfg(feature = "api-level-28")] - pub fn set_rect(&self, key: &str, left: i32, top: i32, right: i32, bottom: i32) { - let name = CString::new(key).unwrap(); - unsafe { - ffi::AMediaFormat_setRect(self.as_ptr(), name.as_ptr(), left, top, right, bottom) - }; - } - - #[cfg(feature = "api-level-28")] - pub fn set_usize(&self, key: &str, value: usize) { - let name = CString::new(key).unwrap(); - unsafe { ffi::AMediaFormat_setSize(self.as_ptr(), name.as_ptr(), value) }; - } -} - -impl Drop for MediaFormat { - fn drop(&mut self) { - let status = unsafe { ffi::AMediaFormat_delete(self.as_ptr()) }; - MediaError::from_status(status).unwrap(); - } -} - /// A native [`AMediaCodec *`] /// /// [`AMediaCodec *`]: https://developer.android.com/ndk/reference/group/media#amediacodec @@ -256,8 +59,8 @@ pub struct AsyncNotifyCallback { pub on_error: Option, } -impl std::fmt::Debug for AsyncNotifyCallback { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Debug for AsyncNotifyCallback { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("AsyncNotifyCallback") .field( "on_input_available", @@ -600,13 +403,13 @@ impl MediaCodec { pub fn input_format(&self) -> MediaFormat { let inner = NonNull::new(unsafe { ffi::AMediaCodec_getInputFormat(self.as_ptr()) }) .expect("AMediaCodec_getInputFormat returned NULL"); - MediaFormat { inner } + unsafe { MediaFormat::from_ptr(inner) } } pub fn output_format(&self) -> MediaFormat { let inner = NonNull::new(unsafe { ffi::AMediaCodec_getOutputFormat(self.as_ptr()) }) .expect("AMediaCodec_getOutputFormat returned NULL"); - MediaFormat { inner } + unsafe { MediaFormat::from_ptr(inner) } } #[cfg(feature = "api-level-28")] @@ -774,7 +577,7 @@ impl OutputBuffer<'_> { ffi::AMediaCodec_getBufferFormat(self.codec.as_ptr(), self.index) }) .expect("AMediaCodec_getBufferFormat returned NULL"); - MediaFormat { inner } + unsafe { MediaFormat::from_ptr(inner) } } pub fn info(&self) -> &BufferInfo { diff --git a/ndk/src/media/media_format.rs b/ndk/src/media/media_format.rs new file mode 100644 index 00000000..45e79870 --- /dev/null +++ b/ndk/src/media/media_format.rs @@ -0,0 +1,210 @@ +//! Bindings for [`AMediaFormat`] +//! +//! [`AMediaFormat`]: https://developer.android.com/ndk/reference/group/media#amediaformat + +use std::{ + ffi::{CStr, CString}, + fmt, + ptr::{self, NonNull}, + slice, +}; + +use crate::media_error::MediaError; + +/// A native [`AMediaFormat *`] +/// +/// [`AMediaFormat *`]: https://developer.android.com/ndk/reference/group/media#amediaformat +#[derive(Debug)] +pub struct MediaFormat { + inner: NonNull, +} + +impl fmt::Display for MediaFormat { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let c_str = unsafe { CStr::from_ptr(ffi::AMediaFormat_toString(self.as_ptr())) }; + f.write_str(c_str.to_str().unwrap()) + } +} + +impl Default for MediaFormat { + fn default() -> Self { + Self::new() + } +} + +impl MediaFormat { + /// Assumes ownership of `ptr` + /// + /// # Safety + /// `ptr` must be a valid pointer to an Android [`ffi::AMediaFormat`]. + pub unsafe fn from_ptr(ptr: NonNull) -> Self { + Self { inner: ptr } + } + + pub fn as_ptr(&self) -> *mut ffi::AMediaFormat { + self.inner.as_ptr() + } + + pub fn new() -> Self { + Self { + inner: NonNull::new(unsafe { ffi::AMediaFormat_new() }).unwrap(), + } + } + + pub fn i32(&self, key: &str) -> Option { + let name = CString::new(key).unwrap(); + let mut out = 0; + if unsafe { ffi::AMediaFormat_getInt32(self.as_ptr(), name.as_ptr(), &mut out) } { + Some(out) + } else { + None + } + } + + pub fn i64(&self, key: &str) -> Option { + let name = CString::new(key).unwrap(); + let mut out = 0; + if unsafe { ffi::AMediaFormat_getInt64(self.as_ptr(), name.as_ptr(), &mut out) } { + Some(out) + } else { + None + } + } + + pub fn f32(&self, key: &str) -> Option { + let name = CString::new(key).unwrap(); + let mut out = 0.0; + if unsafe { ffi::AMediaFormat_getFloat(self.as_ptr(), name.as_ptr(), &mut out) } { + Some(out) + } else { + None + } + } + + pub fn usize(&self, key: &str) -> Option { + let name = CString::new(key).unwrap(); + let mut out = 0; + if unsafe { ffi::AMediaFormat_getSize(self.as_ptr(), name.as_ptr(), &mut out) } { + Some(out) + } else { + None + } + } + + pub fn buffer(&self, key: &str) -> Option<&[u8]> { + let name = CString::new(key).unwrap(); + let mut out_buffer = ptr::null_mut(); + let mut out_size = 0; + unsafe { + ffi::AMediaFormat_getBuffer( + self.as_ptr(), + name.as_ptr(), + &mut out_buffer, + &mut out_size, + ) + } + .then(|| unsafe { slice::from_raw_parts(out_buffer.cast(), out_size) }) + } + + pub fn str(&self, key: &str) -> Option<&str> { + let name = CString::new(key).unwrap(); + let mut out = ptr::null(); + unsafe { ffi::AMediaFormat_getString(self.as_ptr(), name.as_ptr(), &mut out) } + .then(|| unsafe { CStr::from_ptr(out) }.to_str().unwrap()) + } + + pub fn set_i32(&self, key: &str, value: i32) { + let name = CString::new(key).unwrap(); + unsafe { ffi::AMediaFormat_setInt32(self.as_ptr(), name.as_ptr(), value) }; + } + + pub fn set_i64(&self, key: &str, value: i64) { + let name = CString::new(key).unwrap(); + unsafe { ffi::AMediaFormat_setInt64(self.as_ptr(), name.as_ptr(), value) }; + } + + pub fn set_f32(&self, key: &str, value: f32) { + let name = CString::new(key).unwrap(); + unsafe { ffi::AMediaFormat_setFloat(self.as_ptr(), name.as_ptr(), value) }; + } + + pub fn set_str(&self, key: &str, value: &str) { + let name = CString::new(key).unwrap(); + let c_string = CString::new(value).unwrap(); + unsafe { ffi::AMediaFormat_setString(self.as_ptr(), name.as_ptr(), c_string.as_ptr()) }; + } + + pub fn set_buffer(&self, key: &str, value: &[u8]) { + let name = CString::new(key).unwrap(); + unsafe { + ffi::AMediaFormat_setBuffer( + self.as_ptr(), + name.as_ptr(), + value.as_ptr().cast(), + value.len(), + ) + }; + } + + #[cfg(feature = "api-level-28")] + pub fn f64(&self, key: &str) -> Option { + let name = CString::new(key).unwrap(); + let mut out = 0.0; + if unsafe { ffi::AMediaFormat_getDouble(self.as_ptr(), name.as_ptr(), &mut out) } { + Some(out) + } else { + None + } + } + + /// Returns (left, top, right, bottom) + #[cfg(feature = "api-level-28")] + pub fn rect(&self, key: &str) -> Option<(i32, i32, i32, i32)> { + let name = CString::new(key).unwrap(); + let mut left = 0; + let mut top = 0; + let mut right = 0; + let mut bottom = 0; + if unsafe { + ffi::AMediaFormat_getRect( + self.as_ptr(), + name.as_ptr(), + &mut left, + &mut top, + &mut right, + &mut bottom, + ) + } { + Some((left, top, right, bottom)) + } else { + None + } + } + + #[cfg(feature = "api-level-28")] + pub fn set_f64(&self, key: &str, value: f64) { + let name = CString::new(key).unwrap(); + unsafe { ffi::AMediaFormat_setDouble(self.as_ptr(), name.as_ptr(), value) }; + } + + #[cfg(feature = "api-level-28")] + pub fn set_rect(&self, key: &str, left: i32, top: i32, right: i32, bottom: i32) { + let name = CString::new(key).unwrap(); + unsafe { + ffi::AMediaFormat_setRect(self.as_ptr(), name.as_ptr(), left, top, right, bottom) + }; + } + + #[cfg(feature = "api-level-28")] + pub fn set_usize(&self, key: &str, value: usize) { + let name = CString::new(key).unwrap(); + unsafe { ffi::AMediaFormat_setSize(self.as_ptr(), name.as_ptr(), value) }; + } +} + +impl Drop for MediaFormat { + fn drop(&mut self) { + let status = unsafe { ffi::AMediaFormat_delete(self.as_ptr()) }; + MediaError::from_status(status).unwrap(); + } +} diff --git a/ndk/src/media/mod.rs b/ndk/src/media/mod.rs index 3e27b46e..1689a6e3 100644 --- a/ndk/src/media/mod.rs +++ b/ndk/src/media/mod.rs @@ -5,3 +5,4 @@ pub mod image_reader; pub mod media_codec; +pub mod media_format;