Skip to content

Commit 46d6ebb

Browse files
committed
ndk/media: Add bindings for AMediaCodecCryptoInfo
1 parent 2d269e1 commit 46d6ebb

File tree

2 files changed

+145
-0
lines changed

2 files changed

+145
-0
lines changed

ndk/src/media/media_codec_crypto.rs

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
//! Bindings for [`AMediaCodecCryptoInfo`]
2+
//!
3+
//! [`AMediaCodecCryptoInfo`]: https://developer.android.com/ndk/reference/group/media#amediacodeccryptoinfo
4+
5+
use std::{mem::MaybeUninit, ptr::NonNull};
6+
7+
use crate::media_error::{MediaError, Result};
8+
9+
/// A native [`AMediaCodecCryptoInfo *`]
10+
///
11+
/// [`AMediaCodecCryptoInfo *`]: https://developer.android.com/ndk/reference/group/media#amediacodeccryptoinfo
12+
#[derive(Debug)]
13+
#[doc(alias = "AMediaCodecCryptoInfo")]
14+
pub struct MediaCodecCryptoInfo {
15+
inner: NonNull<ffi::AMediaCodecCryptoInfo>,
16+
}
17+
18+
impl MediaCodecCryptoInfo {
19+
/// Create a [`MediaCodecCryptoInfo`] from scratch. Use this if you need to use custom crypto
20+
/// info, rather than one obtained from [`super::media_extractor::MediaExtractor`].
21+
///
22+
/// [`MediaCodecCryptoInfo`] describes the structure of an (at least partially) encrypted input
23+
/// sample.
24+
///
25+
/// A buffer's data is considered to be partitioned into "subsamples", each subsample starts
26+
/// with a (potentially empty) run of plain, unencrypted bytes followed by a (also potentially
27+
/// empty) run of encrypted bytes.
28+
///
29+
/// [`numBytesOfClearData`] can be null to indicate that all data is encrypted. This information
30+
/// encapsulates per-sample metadata as outlined in ISO/IEC FDIS 23001-7:2011 "Common encryption
31+
/// in ISO base media file format files".
32+
#[doc(alias = "AMediaCodecCryptoInfo_new")]
33+
pub fn new(
34+
num_sub_samples: i32,
35+
key: &[u8; 16],
36+
iv: &[u8; 16],
37+
mode: ffi::cryptoinfo_mode_t,
38+
) -> Self {
39+
let mut clear_bytes = 0;
40+
let mut encrypted_bytes = 0;
41+
Self {
42+
// TODO: Mut?
43+
inner: NonNull::new(unsafe {
44+
ffi::AMediaCodecCryptoInfo_new(
45+
num_sub_samples,
46+
key.as_ptr().cast_mut(),
47+
iv.as_ptr().cast_mut(),
48+
mode,
49+
&mut clear_bytes,
50+
&mut encrypted_bytes,
51+
)
52+
})
53+
.unwrap(),
54+
}
55+
}
56+
57+
/// Assumes ownership of `ptr`
58+
///
59+
/// # Safety
60+
/// `ptr` must be a valid pointer to an Android [`ffi::AMediaCodecCryptoInfo`].
61+
pub unsafe fn from_ptr(ptr: NonNull<ffi::AMediaCodecCryptoInfo>) -> Self {
62+
Self { inner: ptr }
63+
}
64+
65+
pub fn as_ptr(&self) -> *mut ffi::AMediaCodecCryptoInfo {
66+
self.inner.as_ptr()
67+
}
68+
69+
/// Set the crypto pattern on an AMediaCryptoInfo object.
70+
#[doc(alias = "AMediaCodecCryptoInfo_setPattern")]
71+
pub fn set_pattern(&self, pattern: &ffi::cryptoinfo_pattern_t) {
72+
unsafe {
73+
ffi::AMediaCodecCryptoInfo_setPattern(
74+
self.inner.as_ptr(),
75+
<*const _>::cast_mut(pattern),
76+
)
77+
}
78+
}
79+
80+
/// The number of subsamples that make up the buffer's contents.
81+
#[doc(alias = "AMediaCodecCryptoInfo_getNumSubSamples")]
82+
pub fn num_sub_samples(&self) -> usize {
83+
unsafe { ffi::AMediaCodecCryptoInfo_getNumSubSamples(self.inner.as_ptr()) }
84+
}
85+
86+
/// A 16-byte opaque key.
87+
#[doc(alias = "AMediaCodecCryptoInfo_getKey")]
88+
pub fn key(&self) -> Result<[u8; 16]> {
89+
let mut key = [0u8; 16];
90+
let status =
91+
unsafe { ffi::AMediaCodecCryptoInfo_getKey(self.inner.as_ptr(), key.as_mut_ptr()) };
92+
MediaError::from_status(status).map(|()| key)
93+
}
94+
95+
/// A 16-byte initialization vector.
96+
#[doc(alias = "AMediaCodecCryptoInfo_getIV")]
97+
pub fn iv(&self) -> Result<[u8; 16]> {
98+
let mut iv = [0u8; 16];
99+
let status =
100+
unsafe { ffi::AMediaCodecCryptoInfo_getIV(self.inner.as_ptr(), iv.as_mut_ptr()) };
101+
MediaError::from_status(status).map(|()| iv)
102+
}
103+
104+
/// The type of encryption that has been applied,
105+
/// one of AMEDIACODECRYPTOINFO_MODE_CLEAR or AMEDIACODECRYPTOINFO_MODE_AES_CTR.
106+
#[doc(alias = "AMediaCodecCryptoInfo_getMode")]
107+
pub fn mode(&self) -> ffi::cryptoinfo_mode_t {
108+
unsafe { ffi::AMediaCodecCryptoInfo_getMode(self.inner.as_ptr()) }
109+
}
110+
111+
/// The number of leading unencrypted bytes in each subsample.
112+
#[doc(alias = "AMediaCodecCryptoInfo_getClearBytes")]
113+
pub fn clear_bytes(&self) -> Result<usize> {
114+
let mut clear_bytes = MaybeUninit::uninit();
115+
116+
let status = unsafe {
117+
ffi::AMediaCodecCryptoInfo_getClearBytes(self.inner.as_ptr(), clear_bytes.as_mut_ptr())
118+
};
119+
MediaError::from_status(status).map(|()| unsafe { clear_bytes.assume_init() })
120+
}
121+
122+
/// The number of trailing encrypted bytes in each subsample.
123+
#[doc(alias = "AMediaCodecCryptoInfo_getEncryptedBytes")]
124+
pub fn encrypted_bytes(&self) -> Result<usize> {
125+
let mut encrypted_bytes = MaybeUninit::uninit();
126+
let status = unsafe {
127+
ffi::AMediaCodecCryptoInfo_getEncryptedBytes(
128+
self.inner.as_ptr(),
129+
encrypted_bytes.as_mut_ptr(),
130+
)
131+
};
132+
MediaError::from_status(status).map(|()| unsafe { encrypted_bytes.assume_init() })
133+
}
134+
}
135+
136+
impl Drop for MediaCodecCryptoInfo {
137+
/// Delete a [`MediaCodecCryptoInfo`] created previously with [`MediaCodecCryptoInfo::new()`], or
138+
/// obtained from [`super::media_extractor::MediaExtractor`].
139+
#[doc(alias = "AMediaCodecCryptoInfo_delete")]
140+
fn drop(&mut self) {
141+
let status = unsafe { ffi::AMediaCodecCryptoInfo_delete(self.inner.as_ptr()) };
142+
MediaError::from_status(status).unwrap()
143+
}
144+
}

ndk/src/media/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@
55

66
pub mod image_reader;
77
pub mod media_codec;
8+
pub mod media_codec_crypto;
89
pub mod media_format;

0 commit comments

Comments
 (0)