|
| 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 | +} |
0 commit comments