Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ndk: Rework media error types #399

Merged
merged 1 commit into from
Jun 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ndk/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
- **Breaking:** Upgrade to [`ndk-sys 0.5.0`](../ndk-sys/CHANGELOG.md#050-TODO). (#370)
- **Breaking:** Upgrade `bitflags` crate from `1` to `2`. (#394)
- **Breaking:** Upgrade `num_enum` crate from `0.5.1` to `0.6`. (#398)
- **Breaking:** Renamed and moved "`media`" error types and helpers to a new `media_error` module. (#399)

# 0.7.0 (2022-07-24)

Expand Down
1 change: 1 addition & 0 deletions ndk/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub mod hardware_buffer_format;
pub mod input_queue;
pub mod looper;
pub mod media;
pub mod media_error;
pub mod native_activity;
pub mod native_window;
pub mod surface_texture;
Expand Down
15 changes: 6 additions & 9 deletions ndk/src/media/image_reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
//! [`AImage`]: https://developer.android.com/ndk/reference/group/media#aimage
#![cfg(feature = "api-level-24")]

use super::NdkMediaError;
use super::{construct, construct_never_null, error::MediaErrorResult, Result};
use crate::media_error::{construct, construct_never_null, MediaError, MediaStatus, Result};
use crate::native_window::NativeWindow;
use num_enum::{IntoPrimitive, TryFromPrimitive};
use std::{
Expand Down Expand Up @@ -140,7 +139,7 @@ impl ImageReader {
onImageAvailable: Some(on_image_available),
};
let status = unsafe { ffi::AImageReader_setImageListener(self.as_ptr(), &mut listener) };
NdkMediaError::from_status(status)
MediaError::from_status(status)
}

#[cfg(feature = "api-level-26")]
Expand Down Expand Up @@ -168,7 +167,7 @@ impl ImageReader {
};
let status =
unsafe { ffi::AImageReader_setBufferRemovedListener(self.as_ptr(), &mut listener) };
NdkMediaError::from_status(status)
MediaError::from_status(status)
}

pub fn get_window(&self) -> Result<NativeWindow> {
Expand Down Expand Up @@ -202,9 +201,7 @@ impl ImageReader {

match res {
Ok(inner) => Ok(Some(Image { inner })),
Err(NdkMediaError::ErrorResult(MediaErrorResult::ImgreaderNoBufferAvailable)) => {
Ok(None)
}
Err(MediaError::MediaStatus(MediaStatus::ImgreaderNoBufferAvailable)) => Ok(None),
Err(e) => Err(e),
}
}
Expand Down Expand Up @@ -232,7 +229,7 @@ impl ImageReader {
ffi::AImageReader_acquireLatestImage(self.as_ptr(), res)
});

if let Err(NdkMediaError::ErrorResult(MediaErrorResult::ImgreaderNoBufferAvailable)) = res {
if let Err(MediaError::MediaStatus(MediaStatus::ImgreaderNoBufferAvailable)) = res {
return Ok(None);
}

Expand Down Expand Up @@ -291,7 +288,7 @@ impl Image {
)
};

NdkMediaError::from_status(status).map(|()| unsafe {
MediaError::from_status(status).map(|()| unsafe {
std::slice::from_raw_parts(result_ptr.assume_init(), result_len.assume_init() as _)
})
}
Expand Down
38 changes: 19 additions & 19 deletions ndk/src/media/media_codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//! [`AMediaFormat`]: https://developer.android.com/ndk/reference/group/media#amediaformat
//! [`AMediaCodec`]: https://developer.android.com/ndk/reference/group/media#amediacodec

use super::{NdkMediaError, Result};
use crate::media_error::{MediaError, Result};
use crate::native_window::NativeWindow;
use std::{
convert::TryInto,
Expand Down Expand Up @@ -206,7 +206,7 @@ impl MediaFormat {
impl Drop for MediaFormat {
fn drop(&mut self) {
let status = unsafe { ffi::AMediaFormat_delete(self.as_ptr()) };
NdkMediaError::from_status(status).unwrap();
MediaError::from_status(status).unwrap();
}
}

Expand Down Expand Up @@ -267,12 +267,12 @@ impl MediaCodec {
},
)
};
NdkMediaError::from_status(status)
MediaError::from_status(status)
}

#[cfg(feature = "api-level-26")]
pub fn create_input_surface(&self) -> Result<NativeWindow> {
use super::construct_never_null;
use crate::media_error::construct_never_null;
unsafe {
let ptr = construct_never_null(|res| {
ffi::AMediaCodec_createInputSurface(self.as_ptr(), res)
Expand All @@ -283,7 +283,7 @@ impl MediaCodec {

#[cfg(feature = "api-level-26")]
pub fn create_persistent_input_surface() -> Result<NativeWindow> {
use super::construct_never_null;
use crate::media_error::construct_never_null;
unsafe {
let ptr =
construct_never_null(|res| ffi::AMediaCodec_createPersistentInputSurface(res))?;
Expand Down Expand Up @@ -311,7 +311,7 @@ impl MediaCodec {
index: result as usize,
}))
} else {
NdkMediaError::from_status(ffi::media_status_t(result as _)).map(|()| None)
MediaError::from_status(ffi::media_status_t(result as _)).map(|()| None)
}
}

Expand Down Expand Up @@ -339,13 +339,13 @@ impl MediaCodec {
info,
}))
} else {
NdkMediaError::from_status(ffi::media_status_t(result as _)).map(|()| None)
MediaError::from_status(ffi::media_status_t(result as _)).map(|()| None)
}
}

pub fn flush(&self) -> Result<()> {
let status = unsafe { ffi::AMediaCodec_flush(self.as_ptr()) };
NdkMediaError::from_status(status)
MediaError::from_status(status)
}

#[cfg(feature = "api-level-28")]
Expand All @@ -363,7 +363,7 @@ impl MediaCodec {

#[cfg(feature = "api-level-28")]
pub fn name(&self) -> Result<String> {
use super::construct;
use crate::media_error::construct;
unsafe {
let name_ptr = construct(|name| ffi::AMediaCodec_getName(self.as_ptr(), name))?;
let name = CStr::from_ptr(name_ptr).to_str().unwrap().to_owned();
Expand Down Expand Up @@ -391,13 +391,13 @@ impl MediaCodec {
flags,
)
};
NdkMediaError::from_status(status)
MediaError::from_status(status)
}

pub fn release_output_buffer(&self, buffer: OutputBuffer, render: bool) -> Result<()> {
let status =
unsafe { ffi::AMediaCodec_releaseOutputBuffer(self.as_ptr(), buffer.index, render) };
NdkMediaError::from_status(status)
MediaError::from_status(status)
}

pub fn release_output_buffer_at_time(
Expand All @@ -408,49 +408,49 @@ impl MediaCodec {
let status = unsafe {
ffi::AMediaCodec_releaseOutputBufferAtTime(self.as_ptr(), buffer.index, timestamp_ns)
};
NdkMediaError::from_status(status)
MediaError::from_status(status)
}

#[cfg(feature = "api-level-26")]
pub fn set_input_surface(&self, surface: &NativeWindow) -> Result<()> {
let status =
unsafe { ffi::AMediaCodec_setInputSurface(self.as_ptr(), surface.ptr().as_ptr()) };
NdkMediaError::from_status(status)
MediaError::from_status(status)
}

pub fn set_output_surface(&self, surface: &NativeWindow) -> Result<()> {
let status =
unsafe { ffi::AMediaCodec_setOutputSurface(self.as_ptr(), surface.ptr().as_ptr()) };
NdkMediaError::from_status(status)
MediaError::from_status(status)
}

#[cfg(feature = "api-level-26")]
pub fn set_parameters(&self, params: MediaFormat) -> Result<()> {
let status = unsafe { ffi::AMediaCodec_setParameters(self.as_ptr(), params.as_ptr()) };
NdkMediaError::from_status(status)
MediaError::from_status(status)
}

#[cfg(feature = "api-level-26")]
pub fn set_signal_end_of_input_stream(&self) -> Result<()> {
let status = unsafe { ffi::AMediaCodec_signalEndOfInputStream(self.as_ptr()) };
NdkMediaError::from_status(status)
MediaError::from_status(status)
}

pub fn start(&self) -> Result<()> {
let status = unsafe { ffi::AMediaCodec_start(self.as_ptr()) };
NdkMediaError::from_status(status)
MediaError::from_status(status)
}

pub fn stop(&self) -> Result<()> {
let status = unsafe { ffi::AMediaCodec_stop(self.as_ptr()) };
NdkMediaError::from_status(status)
MediaError::from_status(status)
}
}

impl Drop for MediaCodec {
fn drop(&mut self) {
let status = unsafe { ffi::AMediaCodec_delete(self.as_ptr()) };
NdkMediaError::from_status(status).unwrap();
MediaError::from_status(status).unwrap();
}
}

Expand Down
24 changes: 0 additions & 24 deletions ndk/src/media/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,5 @@
//! See also [the NDK docs](https://developer.android.com/ndk/reference/group/media)
#![cfg(feature = "media")]

mod error;
pub mod image_reader;
pub mod media_codec;

pub use error::NdkMediaError;
use std::{mem::MaybeUninit, ptr::NonNull};

pub type Result<T, E = NdkMediaError> = std::result::Result<T, E>;

fn construct<T>(with_ptr: impl FnOnce(*mut T) -> ffi::media_status_t) -> Result<T> {
let mut result = MaybeUninit::uninit();
let status = with_ptr(result.as_mut_ptr());
NdkMediaError::from_status(status).map(|()| unsafe { result.assume_init() })
}

fn construct_never_null<T>(
with_ptr: impl FnOnce(*mut *mut T) -> ffi::media_status_t,
) -> Result<NonNull<T>> {
let result = construct(with_ptr)?;
let non_null = if cfg!(debug_assertions) {
NonNull::new(result).expect("result should never be null")
} else {
unsafe { NonNull::new_unchecked(result) }
};
Ok(non_null)
}
63 changes: 50 additions & 13 deletions ndk/src/media/error.rs → ndk/src/media_error.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,22 @@
use super::Result;
//! Bindings for NDK media status codes.
//!
//! Also used outside of `libmediandk.so` in `libmidi.so` for example.

#![cfg(feature = "media")]
// The cfg(feature) bounds for some pub(crate) fn uses are non-trivial and will become even more
// complex going forward. Allow them to be unused when compiling with certain feature combinations.
#![allow(dead_code)]
MarijnS95 marked this conversation as resolved.
Show resolved Hide resolved

use std::{mem::MaybeUninit, ptr::NonNull};

use thiserror::Error;

pub type Result<T, E = MediaError> = std::result::Result<T, E>;

/// Media Status codes for [`media_status_t`](https://developer.android.com/ndk/reference/group/media#group___media_1ga009a49041fe39f7bdc6d8b5cddbe760c)
#[repr(i32)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum MediaErrorResult {
pub enum MediaStatus {
CodecErrorInsufficientResource = ffi::media_status_t::AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE.0,
CodecErrorReclaimed = ffi::media_status_t::AMEDIACODEC_ERROR_RECLAIMED.0,
ErrorUnknown = ffi::media_status_t::AMEDIA_ERROR_UNKNOWN.0,
Expand Down Expand Up @@ -33,18 +46,20 @@ pub enum MediaErrorResult {
ImgreaderImageNotLocked = ffi::media_status_t::AMEDIA_IMGREADER_IMAGE_NOT_LOCKED.0,
}

/// Media Status codes in [`MediaStatus`] or raw [`ffi::media_status_t`] if unknown.
#[derive(Debug, Error)]
pub enum NdkMediaError {
#[error("error Media result ({0:?})")]
ErrorResult(MediaErrorResult),
#[error("unknown Media error result ({0:?})")]
UnknownResult(ffi::media_status_t),
pub enum MediaError {
#[error("Media Status {0:?}")]
MediaStatus(MediaStatus),
#[error("Unknown Media Status {0:?}")]
UnknownStatus(ffi::media_status_t),
}

impl NdkMediaError {
impl MediaError {
/// Returns [`Ok`] on [`ffi::media_status_t::AMEDIA_OK`], [`Err`] otherwise.
pub(crate) fn from_status(status: ffi::media_status_t) -> Result<()> {
use MediaErrorResult::*;
let result = match status {
use MediaStatus::*;
Err(Self::MediaStatus(match status {
ffi::media_status_t::AMEDIA_OK => return Ok(()),
ffi::media_status_t::AMEDIACODEC_ERROR_INSUFFICIENT_RESOURCE => {
CodecErrorInsufficientResource
Expand Down Expand Up @@ -75,8 +90,30 @@ impl NdkMediaError {
ffi::media_status_t::AMEDIA_IMGREADER_CANNOT_LOCK_IMAGE => ImgreaderCannotLockImage,
ffi::media_status_t::AMEDIA_IMGREADER_CANNOT_UNLOCK_IMAGE => ImgreaderCannotUnlockImage,
ffi::media_status_t::AMEDIA_IMGREADER_IMAGE_NOT_LOCKED => ImgreaderImageNotLocked,
_ => return Err(NdkMediaError::UnknownResult(status)),
};
Err(NdkMediaError::ErrorResult(result))
_ => return Err(MediaError::UnknownStatus(status)),
}))
}
}

/// Calls the `with_ptr` construction function with a pointer to uninitialized stack memory,
/// expecting `with_ptr` to initialize it or otherwise return an error code.
pub(crate) fn construct<T>(with_ptr: impl FnOnce(*mut T) -> ffi::media_status_t) -> Result<T> {
let mut result = MaybeUninit::uninit();
let status = with_ptr(result.as_mut_ptr());
MediaError::from_status(status).map(|()| unsafe { result.assume_init() })
}

/// Calls the `with_ptr` construction function with a pointer to a pointer, and expects `with_ptr`
/// to initialize the second pointer to a valid address. That address is returned in the form of a
/// [`NonNull`] object.
pub(crate) fn construct_never_null<T>(
with_ptr: impl FnOnce(*mut *mut T) -> ffi::media_status_t,
) -> Result<NonNull<T>> {
let result = construct(with_ptr)?;
let non_null = if cfg!(debug_assertions) {
NonNull::new(result).expect("result should never be null")
} else {
unsafe { NonNull::new_unchecked(result) }
};
Ok(non_null)
}