diff options
Diffstat (limited to 'media/ndk/NdkMediaCodec.cpp')
-rw-r--r-- | media/ndk/NdkMediaCodec.cpp | 256 |
1 files changed, 239 insertions, 17 deletions
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp index 9592af8..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,29 +43,97 @@ 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 { + kWhatActivityNotify, + kWhatRequestActivityNotifications, + kWhatStopActivityNotifications, +}; + class CodecHandler: public AHandler { +private: + AMediaCodec* mCodec; public: - CodecHandler(sp<android::MediaCodec>); + CodecHandler(AMediaCodec *codec); virtual void onMessageReceived(const sp<AMessage> &msg); }; -CodecHandler::CodecHandler(sp<android::MediaCodec>) { +struct AMediaCodec { + sp<android::MediaCodec> mCodec; + sp<ALooper> mLooper; + sp<CodecHandler> mHandler; + sp<AMessage> mActivityNotification; + int32_t mGeneration; + bool mRequestedActivityNotification; + OnCodecEvent mCallback; + void *mCallbackUserData; +}; +CodecHandler::CodecHandler(AMediaCodec *codec) { + mCodec = codec; } void CodecHandler::onMessageReceived(const sp<AMessage> &msg) { - ALOGI("handler got message %d", msg->what()); + + switch (msg->what()) { + case kWhatRequestActivityNotifications: + { + if (mCodec->mRequestedActivityNotification) { + break; + } + + mCodec->mCodec->requestActivityNotification(mCodec->mActivityNotification); + mCodec->mRequestedActivityNotification = true; + break; + } + + case kWhatActivityNotify: + { + { + int32_t generation; + msg->findInt32("generation", &generation); + + if (generation != mCodec->mGeneration) { + // stale + break; + } + + mCodec->mRequestedActivityNotification = false; + } + + if (mCodec->mCallback) { + mCodec->mCallback(mCodec, mCodec->mCallbackUserData); + } + break; + } + + case kWhatStopActivityNotifications: + { + uint32_t replyID; + msg->senderAwaitsResponse(&replyID); + + mCodec->mGeneration++; + mCodec->mRequestedActivityNotification = false; + + sp<AMessage> response = new AMessage; + response->postReply(replyID); + break; + } + + default: + ALOGE("shouldn't be here"); + break; + } + } -struct AMediaCodec { - sp<android::MediaCodec> mCodec; - sp<ALooper> mLooper; - sp<CodecHandler> mHandler; -}; + +static void requestActivityNotification(AMediaCodec *codec) { + (new AMessage(kWhatRequestActivityNotifications, codec->mHandler->id()))->post(); +} extern "C" { @@ -76,14 +145,17 @@ static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool false, // runOnCallingThread true, // canCallJava XXX PRIORITY_FOREGROUND); - ALOGV("looper start: %d", ret); if (name_is_type) { mData->mCodec = android::MediaCodec::CreateByType(mData->mLooper, name, encoder); } else { mData->mCodec = android::MediaCodec::CreateByComponentName(mData->mLooper, name); } - mData->mHandler = new CodecHandler(mData->mCodec); + mData->mHandler = new CodecHandler(mData); mData->mLooper->registerHandler(mData->mHandler); + mData->mGeneration = 1; + mData->mRequestedActivityNotification = false; + mData->mCallback = NULL; + return mData; } @@ -116,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()); @@ -125,15 +201,30 @@ 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) { - return translate_error(mData->mCodec->start()); + status_t ret = mData->mCodec->start(); + if (ret != OK) { + return translate_error(ret); + } + mData->mActivityNotification = new AMessage(kWhatActivityNotify, mData->mHandler->id()); + mData->mActivityNotification->setInt32("generation", mData->mGeneration); + requestActivityNotification(mData); + return OK; } int AMediaCodec_stop(AMediaCodec *mData) { - return translate_error(mData->mCodec->stop()); + int ret = translate_error(mData->mCodec->stop()); + + sp<AMessage> msg = new AMessage(kWhatStopActivityNotifications, mData->mHandler->id()); + sp<AMessage> response; + msg->postAndAwaitResponse(&response); + mData->mActivityNotification.clear(); + + return ret; } int AMediaCodec_flush(AMediaCodec *mData) { @@ -143,6 +234,7 @@ int AMediaCodec_flush(AMediaCodec *mData) { ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) { size_t idx; status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs); + requestActivityNotification(mData); if (ret == OK) { return idx; } @@ -200,7 +292,7 @@ ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData, int64_t presentationTimeUs; status_t ret = mData->mCodec->dequeueOutputBuffer(&idx, &offset, &size, &presentationTimeUs, &flags, timeoutUs); - + requestActivityNotification(mData); switch (ret) { case OK: info->offset = offset; @@ -234,5 +326,135 @@ int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) } } +int AMediaCodec_setNotificationCallback(AMediaCodec *mData, OnCodecEvent callback, void *userdata) { + mData->mCallback = callback; + mData->mCallbackUserData = userdata; + 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" |