diff options
author | Marco Nelissen <marcone@google.com> | 2014-05-09 15:10:23 -0700 |
---|---|---|
committer | Marco Nelissen <marcone@google.com> | 2014-05-13 15:03:04 -0700 |
commit | 050eb3280d7305b84f723d515be2dc9606dc39d1 (patch) | |
tree | 110716a883abc7e41f3507f86973224dc4bc0adb | |
parent | 021cf9634ab09c0753a40b7c9ef4ba603be5c3da (diff) | |
download | frameworks_av-050eb3280d7305b84f723d515be2dc9606dc39d1.zip frameworks_av-050eb3280d7305b84f723d515be2dc9606dc39d1.tar.gz frameworks_av-050eb3280d7305b84f723d515be2dc9606dc39d1.tar.bz2 |
Some crypto stuff, error codes
Add crypto/drm related functions, define some media errors
instead of using magic numbers in the code.
Change-Id: I5924cba0bfcdb3623073c9182a646b70f4ead5a5
-rw-r--r-- | include/ndk/NdkMediaCodec.h | 47 | ||||
-rw-r--r-- | include/ndk/NdkMediaCrypto.h | 55 | ||||
-rw-r--r-- | include/ndk/NdkMediaError.h | 48 | ||||
-rw-r--r-- | include/ndk/NdkMediaExtractor.h | 29 | ||||
-rw-r--r-- | media/ndk/Android.mk | 2 | ||||
-rw-r--r-- | media/ndk/NdkMediaCodec.cpp | 137 | ||||
-rw-r--r-- | media/ndk/NdkMediaCrypto.cpp | 117 | ||||
-rw-r--r-- | media/ndk/NdkMediaCryptoPriv.h | 41 | ||||
-rw-r--r-- | media/ndk/NdkMediaExtractor.cpp | 148 |
9 files changed, 612 insertions, 12 deletions
diff --git a/include/ndk/NdkMediaCodec.h b/include/ndk/NdkMediaCodec.h index c35c6b3..5233fe3 100644 --- a/include/ndk/NdkMediaCodec.h +++ b/include/ndk/NdkMediaCodec.h @@ -29,6 +29,7 @@ #include <android/native_window.h> +#include "NdkMediaCrypto.h" #include "NdkMediaFormat.h" #ifdef __cplusplus @@ -46,6 +47,7 @@ struct AMediaCodecBufferInfo { uint32_t flags; }; typedef struct AMediaCodecBufferInfo AMediaCodecBufferInfo; +typedef struct AMediaCodecCryptoInfo AMediaCodecCryptoInfo; enum { AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM = 4, @@ -81,8 +83,12 @@ int AMediaCodec_delete(AMediaCodec*); /** * Configure the codec. For decoding you would typically get the format from an extractor. */ -int AMediaCodec_configure(AMediaCodec*, const AMediaFormat* format, - ANativeWindow* surface, uint32_t flags); // TODO: other args +int AMediaCodec_configure( + AMediaCodec*, + const AMediaFormat* format, + ANativeWindow* surface, + AMediaCrypto *crypto, + uint32_t flags); /** * Start the codec. A codec must be configured before it can be started, and must be started @@ -127,6 +133,12 @@ int AMediaCodec_queueInputBuffer(AMediaCodec*, size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags); /** + * Send the specified buffer to the codec for processing. + */ +int AMediaCodec_queueSecureInputBuffer(AMediaCodec*, + size_t idx, off_t offset, AMediaCodecCryptoInfo*, uint64_t time, uint32_t flags); + +/** * Get the index of the next available buffer of processed data. */ ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec*, AMediaCodecBufferInfo *info, int64_t timeoutUs); @@ -138,7 +150,6 @@ AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec*); int AMediaCodec_releaseOutputBuffer(AMediaCodec*, size_t idx, bool render); - typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata); /** @@ -150,6 +161,36 @@ typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata); int AMediaCodec_setNotificationCallback(AMediaCodec*, OnCodecEvent callback, void *userdata); +enum { + AMEDIACODECRYPTOINFO_MODE_CLEAR = 0, + AMEDIACODECRYPTOINFO_MODE_AES_CTR = 1 +}; + +/** + * create an AMediaCodecCryptoInfo from scratch. Use this if you need to use custom + * crypto info, rather than one obtained from AMediaExtractor. + */ +AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( + int numsubsamples, + uint8_t key[16], + uint8_t iv[16], + uint32_t mode, + size_t *clearbytes, + size_t *encryptedbytes); + +/** + * delete an AMediaCodecCryptoInfo create previously with AMediaCodecCryptoInfo_new, or + * obtained from AMediaExtractor + */ +int AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo*); + +size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo*); +int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo*, uint8_t *dst); +int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo*, uint8_t *dst); +uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo*); +int AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo*, size_t *dst); +int AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo*, size_t *dst); + #ifdef __cplusplus } // extern "C" #endif diff --git a/include/ndk/NdkMediaCrypto.h b/include/ndk/NdkMediaCrypto.h new file mode 100644 index 0000000..0bcba9f --- /dev/null +++ b/include/ndk/NdkMediaCrypto.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/* + * This file defines an NDK API. + * Do not remove methods. + * Do not change method signatures. + * Do not change the value of constants. + * Do not change the size of any of the classes defined in here. + * Do not reference types that are not part of the NDK. + * Do not #include files that aren't part of the NDK. + */ + +#ifndef _NDK_MEDIA_CRYPTO_H +#define _NDK_MEDIA_CRYPTO_H + +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +struct AMediaCrypto; +typedef struct AMediaCrypto AMediaCrypto; + +typedef uint8_t AMediaUUID[16]; + +bool AMediaCrypto_isCryptoSchemeSupport(const AMediaUUID uuid); + +bool AMediaCrypto_requiresSecureDecoderComponent(const char *mime); + +AMediaCrypto* AMediaCrypto_new(const AMediaUUID uuid, const void *initData, size_t initDataSize); + +void AMediaCrypto_delete(AMediaCrypto* crypto); + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _NDK_MEDIA_CRYPTO_H diff --git a/include/ndk/NdkMediaError.h b/include/ndk/NdkMediaError.h new file mode 100644 index 0000000..b89a10e --- /dev/null +++ b/include/ndk/NdkMediaError.h @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/* + * This file defines an NDK API. + * Do not remove methods. + * Do not change method signatures. + * Do not change the value of constants. + * Do not change the size of any of the classes defined in here. + * Do not reference types that are not part of the NDK. + * Do not #include files that aren't part of the NDK. + */ + +#ifndef _NDK_MEDIA_ERROR_H +#define _NDK_MEDIA_ERROR_H + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + AMEDIAERROR_BASE = -10000, + + AMEDIAERROR_GENERIC = AMEDIAERROR_BASE, + AMEDIAERROR_MALFORMED = AMEDIAERROR_BASE - 1, + AMEDIAERROR_UNSUPPORTED = AMEDIAERROR_BASE - 2 +}; + + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // _NDK_MEDIA_ERROR_H diff --git a/include/ndk/NdkMediaExtractor.h b/include/ndk/NdkMediaExtractor.h index a7c32c4..9e50ec0 100644 --- a/include/ndk/NdkMediaExtractor.h +++ b/include/ndk/NdkMediaExtractor.h @@ -30,7 +30,9 @@ #include <sys/types.h> +#include "NdkMediaCodec.h" #include "NdkMediaFormat.h" +#include "NdkMediaCrypto.h" #ifdef __cplusplus extern "C" { @@ -112,6 +114,33 @@ int64_t AMediaExtractor_getSampletime(AMediaExtractor*); */ bool AMediaExtractor_advance(AMediaExtractor*); + +/** + * mapping of crypto scheme uuid to the scheme specific data for that scheme + */ +typedef struct PsshEntry { + AMediaUUID uuid; + size_t datalen; + void *data; +} PsshEntry; + +/** + * list of crypto schemes and their data + */ +typedef struct PsshInfo { + size_t numentries; + PsshEntry entries[0]; +} PsshInfo; + +/** + * Get the PSSH info if present. + */ +PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor*); + + +AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *); + + enum { AMEDIAEXTRACTOR_SAMPLE_FLAG_SYNC = 1, AMEDIAEXTRACTOR_SAMPLE_FLAG_ENCRYPTED = 2, diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk index b8dd19e..03f26a0 100644 --- a/media/ndk/Android.mk +++ b/media/ndk/Android.mk @@ -22,6 +22,7 @@ include $(CLEAR_VARS) LOCAL_SRC_FILES:= \ NdkMediaCodec.cpp \ + NdkMediaCrypto.cpp \ NdkMediaExtractor.cpp \ NdkMediaFormat.cpp \ NdkMediaMuxer.cpp \ @@ -34,6 +35,7 @@ LOCAL_C_INCLUDES := \ frameworks/av/include/ndk LOCAL_SHARED_LIBRARIES := \ + libbinder \ libmedia \ libstagefright \ libstagefright_foundation \ diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index 1789f75..1f62fa2 100644 --- a/media/ndk/NdkMediaCodec.cpp +++ b/media/ndk/NdkMediaCodec.cpp @@ -18,13 +18,14 @@ #define LOG_TAG "NdkMediaCodec" #include "NdkMediaCodec.h" +#include "NdkMediaError.h" +#include "NdkMediaCryptoPriv.h" #include "NdkMediaFormatPriv.h" #include <utils/Log.h> #include <utils/StrongPointer.h> #include <gui/Surface.h> -#include <media/ICrypto.h> #include <media/stagefright/foundation/ALooper.h> #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/foundation/ABuffer.h> @@ -42,7 +43,7 @@ static int translate_error(status_t err) { return AMEDIACODEC_INFO_TRY_AGAIN_LATER; } ALOGE("sf error code: %d", err); - return -1000; + return AMEDIAERROR_GENERIC; } enum { @@ -187,7 +188,11 @@ int AMediaCodec_delete(AMediaCodec *mData) { } int AMediaCodec_configure( - AMediaCodec *mData, const AMediaFormat* format, ANativeWindow* window, uint32_t flags) { + AMediaCodec *mData, + const AMediaFormat* format, + ANativeWindow* window, + AMediaCrypto *crypto, + uint32_t flags) { sp<AMessage> nativeFormat; AMediaFormat_getFormat(format, &nativeFormat); ALOGV("configure with format: %s", nativeFormat->debugString(0).c_str()); @@ -196,7 +201,8 @@ int AMediaCodec_configure( surface = (Surface*) window; } - return translate_error(mData->mCodec->configure(nativeFormat, surface, NULL, flags)); + return translate_error(mData->mCodec->configure(nativeFormat, surface, + crypto ? crypto->mCrypto : NULL, flags)); } int AMediaCodec_start(AMediaCodec *mData) { @@ -326,6 +332,129 @@ int AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callbac return OK; } +typedef struct AMediaCodecCryptoInfo { + int numsubsamples; + uint8_t key[16]; + uint8_t iv[16]; + uint32_t mode; + size_t *clearbytes; + size_t *encryptedbytes; +} AMediaCodecCryptoInfo; + +int AMediaCodec_queueSecureInputBuffer( + AMediaCodec* codec, + size_t idx, + off_t offset, + AMediaCodecCryptoInfo* crypto, + uint64_t time, + uint32_t flags) { + + CryptoPlugin::SubSample *subSamples = new CryptoPlugin::SubSample[crypto->numsubsamples]; + for (int i = 0; i < crypto->numsubsamples; i++) { + subSamples[i].mNumBytesOfClearData = crypto->clearbytes[i]; + subSamples[i].mNumBytesOfEncryptedData = crypto->encryptedbytes[i]; + } + + AString errormsg; + status_t err = codec->mCodec->queueSecureInputBuffer(idx, + offset, + subSamples, + crypto->numsubsamples, + crypto->key, + crypto->iv, + (CryptoPlugin::Mode) crypto->mode, + time, + flags, + &errormsg); + if (err != 0) { + ALOGE("queSecureInputBuffer: %s", errormsg.c_str()); + } + delete subSamples; + return translate_error(err); +} + + + +AMediaCodecCryptoInfo *AMediaCodecCryptoInfo_new( + int numsubsamples, + uint8_t key[16], + uint8_t iv[16], + uint32_t mode, + size_t *clearbytes, + size_t *encryptedbytes) { + + // size needed to store all the crypto data + size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2; + AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize); + if (!ret) { + ALOGE("couldn't allocate %d bytes", cryptosize); + return NULL; + } + ret->numsubsamples = numsubsamples; + memcpy(ret->key, key, 16); + memcpy(ret->iv, iv, 16); + ret->mode = mode; + + // clearbytes and encryptedbytes point at the actual data, which follows + ret->clearbytes = (size_t*) ((&ret->encryptedbytes) + sizeof(ret->encryptedbytes)); + ret->encryptedbytes = (size_t*) (ret->clearbytes + (sizeof(size_t) * numsubsamples)); + + size_t *dst = ret->clearbytes; + memcpy(dst, clearbytes, numsubsamples * sizeof(size_t)); + dst += numsubsamples * sizeof(size_t); + memcpy(dst, encryptedbytes, numsubsamples * sizeof(size_t)); + + return ret; +} + + +int AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) { + free(info); + return OK; +} + +size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) { + return ci->numsubsamples; +} + +int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) { + if (!dst || !ci) { + return AMEDIAERROR_UNSUPPORTED; + } + memcpy(dst, ci->key, 16); + return OK; +} + +int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) { + if (!dst || !ci) { + return AMEDIAERROR_UNSUPPORTED; + } + memcpy(dst, ci->iv, 16); + return OK; +} + +uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) { + if (!ci) { + return AMEDIAERROR_UNSUPPORTED; + } + return ci->mode; +} + +int AMediaCodecCryptoInfo_getClearBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { + if (!dst || !ci) { + return AMEDIAERROR_UNSUPPORTED; + } + memcpy(dst, ci->clearbytes, sizeof(size_t) * ci->numsubsamples); + return OK; +} + +int AMediaCodecCryptoInfo_getEncryptedBytes(AMediaCodecCryptoInfo* ci, size_t *dst) { + if (!dst || !ci) { + return AMEDIAERROR_UNSUPPORTED; + } + memcpy(dst, ci->encryptedbytes, sizeof(size_t) * ci->numsubsamples); + return OK; +} } // extern "C" diff --git a/media/ndk/NdkMediaCrypto.cpp b/media/ndk/NdkMediaCrypto.cpp new file mode 100644 index 0000000..25dfe6a --- /dev/null +++ b/media/ndk/NdkMediaCrypto.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_NDEBUG 0 +#define LOG_TAG "NdkMediaCrypto" + + +#include "NdkMediaCrypto.h" +#include "NdkMediaCodec.h" +#include "NdkMediaFormatPriv.h" + + +#include <utils/Log.h> +#include <utils/StrongPointer.h> +#include <binder/IServiceManager.h> +#include <media/ICrypto.h> +#include <media/IMediaPlayerService.h> +#include <android_runtime/AndroidRuntime.h> +#include <android_util_Binder.h> + +#include <jni.h> + +using namespace android; + +static int translate_error(status_t err) { + if (err == OK) { + return OK; + } + ALOGE("sf error code: %d", err); + return -1000; +} + + +static sp<ICrypto> makeCrypto() { + sp<IServiceManager> sm = defaultServiceManager(); + + sp<IBinder> binder = + sm->getService(String16("media.player")); + + sp<IMediaPlayerService> service = + interface_cast<IMediaPlayerService>(binder); + + if (service == NULL) { + return NULL; + } + + sp<ICrypto> crypto = service->makeCrypto(); + + if (crypto == NULL || (crypto->initCheck() != OK && crypto->initCheck() != NO_INIT)) { + return NULL; + } + + return crypto; +} + +struct AMediaCrypto { + sp<ICrypto> mCrypto; +}; + + +extern "C" { + + +bool AMediaCrypto_isCryptoSchemeSupport(const AMediaUUID uuid) { + sp<ICrypto> crypto = makeCrypto(); + if (crypto == NULL) { + return false; + } + return crypto->isCryptoSchemeSupported(uuid); +} + +bool AMediaCrypto_requiresSecureDecoderComponent(const char *mime) { + sp<ICrypto> crypto = makeCrypto(); + if (crypto == NULL) { + return false; + } + return crypto->requiresSecureDecoderComponent(mime); +} + +AMediaCrypto* AMediaCrypto_new(const AMediaUUID uuid, const void *data, size_t datasize) { + + sp<ICrypto> tmp = makeCrypto(); + if (tmp == NULL) { + return NULL; + } + + if (tmp->createPlugin(uuid, data, datasize) != 0) { + return NULL; + } + + AMediaCrypto *crypto = new AMediaCrypto(); + crypto->mCrypto = tmp; + + return crypto; +} + +void AMediaCrypto_delete(AMediaCrypto* crypto) { + delete crypto; +} + + + +} // extern "C" + diff --git a/media/ndk/NdkMediaCryptoPriv.h b/media/ndk/NdkMediaCryptoPriv.h new file mode 100644 index 0000000..14ea928 --- /dev/null +++ b/media/ndk/NdkMediaCryptoPriv.h @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/* + * This file defines an NDK API. + * Do not remove methods. + * Do not change method signatures. + * Do not change the value of constants. + * Do not change the size of any of the classes defined in here. + * Do not reference types that are not part of the NDK. + * Do not #include files that aren't part of the NDK. + */ + +#ifndef _NDK_MEDIA_CRYPTO_PRIV_H +#define _NDK_MEDIA_CRYPTO_PRIV_H + +#include <sys/types.h> +#include <utils/StrongPointer.h> +#include <media/ICrypto.h> + +using namespace android; + +struct AMediaCrypto { + sp<ICrypto> mCrypto; +}; + +#endif // _NDK_MEDIA_CRYPTO_PRIV_H diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp index 681633a..0a66988 100644 --- a/media/ndk/NdkMediaExtractor.cpp +++ b/media/ndk/NdkMediaExtractor.cpp @@ -18,12 +18,14 @@ #define LOG_TAG "NdkMediaExtractor" +#include "NdkMediaError.h" #include "NdkMediaExtractor.h" #include "NdkMediaFormatPriv.h" #include <utils/Log.h> #include <utils/StrongPointer.h> +#include <media/hardware/CryptoAPI.h> #include <media/stagefright/foundation/ABuffer.h> #include <media/stagefright/foundation/AMessage.h> #include <media/stagefright/MetaData.h> @@ -41,11 +43,12 @@ static int translate_error(status_t err) { return OK; } ALOGE("sf error code: %d", err); - return -1000; + return AMEDIAERROR_GENERIC; } struct AMediaExtractor { sp<NuMediaExtractor> mImpl; + sp<ABuffer> mPsshBuf; }; @@ -79,14 +82,14 @@ int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) if (env == NULL) { ALOGE("setDataSource(path) must be called from Java thread"); env->ExceptionClear(); - return -1; + return AMEDIAERROR_UNSUPPORTED; } jclass mediahttpclass = env->FindClass("android/media/MediaHTTPService"); if (mediahttpclass == NULL) { ALOGE("can't find MediaHttpService"); env->ExceptionClear(); - return -1; + return AMEDIAERROR_UNSUPPORTED; } jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass, @@ -94,7 +97,7 @@ int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) if (mediaHttpCreateMethod == NULL) { ALOGE("can't find method"); env->ExceptionClear(); - return -1; + return AMEDIAERROR_UNSUPPORTED; } jstring jloc = env->NewStringUTF(location); @@ -110,7 +113,7 @@ int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) mData->mImpl->setDataSource(httpService, location, NULL); env->ExceptionClear(); - return 0; + return OK; } int AMediaExtractor_getTrackCount(AMediaExtractor *mData) { @@ -184,6 +187,141 @@ int64_t AMediaExtractor_getSampletime(AMediaExtractor *mData) { return time; } +PsshInfo* AMediaExtractor_getPsshInfo(AMediaExtractor *ex) { + + if (ex->mPsshBuf != NULL) { + return (PsshInfo*) ex->mPsshBuf->data(); + } + + sp<AMessage> format; + ex->mImpl->getFileFormat(&format); + sp<ABuffer> buffer; + if(!format->findBuffer("pssh", &buffer)) { + return NULL; + } + + // the format of the buffer is 1 or more of: + // { + // 16 byte uuid + // 4 byte data length N + // N bytes of data + // } + + // Determine the number of entries in the source data. + // Since we got the data from stagefright, we trust it is valid and properly formatted. + const uint8_t* data = buffer->data(); + size_t len = buffer->size(); + size_t numentries = 0; + while (len > 0) { + numentries++; + + // skip uuid + data += 16; + len -= 16; + + // get data length + uint32_t datalen = *((uint32_t*)data); + data += 4; + len -= 4; + + // skip the data + data += datalen; + len -= datalen; + } + + // there are <numentries> in the buffer, we need + // (source buffer size) + 4 + (4 * numentries) bytes for the PsshInfo structure + size_t newsize = buffer->size() + 4 + (4 * numentries); + ex->mPsshBuf = new ABuffer(newsize); + ex->mPsshBuf->setRange(0, newsize); + + // copy data + const uint8_t* src = buffer->data(); + uint8_t* dst = ex->mPsshBuf->data(); + uint8_t* dstdata = dst + 4 + numentries * sizeof(PsshEntry); + *((uint32_t*)dst) = numentries; + dst += 4; + for (size_t i = 0; i < numentries; i++) { + // copy uuid + memcpy(dst, src, 16); + src += 16; + dst += 16; + + // get/copy data length + uint32_t datalen = *((uint32_t*)src); + memcpy(dst, src, 4); + src += 4; + dst += 4; + + // the next entry in the destination is a pointer to the actual data, which we store + // after the array of PsshEntry + memcpy(dst, &dstdata, sizeof(dstdata)); + dst += 4; + + // copy the actual data + memcpy(dstdata, src, datalen); + dstdata += datalen; + src += datalen; + } + + return (PsshInfo*) ex->mPsshBuf->data(); +} + +AMediaCodecCryptoInfo *AMediaExtractor_getSampleCryptoInfo(AMediaExtractor *ex) { + sp<MetaData> meta; + if(ex->mImpl->getSampleMeta(&meta) != 0) { + return NULL; + } + + uint32_t type; + const void *crypteddata; + size_t cryptedsize; + if (!meta->findData(kKeyEncryptedSizes, &type, &crypteddata, &cryptedsize)) { + return NULL; + } + size_t numSubSamples = cryptedsize / sizeof(size_t); + + const void *cleardata; + size_t clearsize; + if (meta->findData(kKeyPlainSizes, &type, &cleardata, &clearsize)) { + if (clearsize != cryptedsize) { + // The two must be of the same length. + return NULL; + } + } + + const void *key; + size_t keysize; + if (meta->findData(kKeyCryptoIV, &type, &key, &keysize)) { + if (keysize != 16) { + // IVs must be 16 bytes in length. + return NULL; + } + } + + const void *iv; + size_t ivsize; + if (meta->findData(kKeyCryptoIV, &type, &iv, &ivsize)) { + if (ivsize != 16) { + // IVs must be 16 bytes in length. + return NULL; + } + } + + int32_t mode; + if (!meta->findInt32(kKeyCryptoMode, &mode)) { + mode = CryptoPlugin::kMode_AES_CTR; + } + + return AMediaCodecCryptoInfo_new( + numSubSamples, + (uint8_t*) key, + (uint8_t*) iv, + mode, + (size_t*) cleardata, + (size_t*) crypteddata); +} + } // extern "C" |