summaryrefslogtreecommitdiffstats
path: root/media/ndk
diff options
context:
space:
mode:
authorMarco Nelissen <marcone@google.com>2014-05-09 15:10:23 -0700
committerMarco Nelissen <marcone@google.com>2014-05-13 15:03:04 -0700
commit050eb3280d7305b84f723d515be2dc9606dc39d1 (patch)
tree110716a883abc7e41f3507f86973224dc4bc0adb /media/ndk
parent021cf9634ab09c0753a40b7c9ef4ba603be5c3da (diff)
downloadframeworks_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
Diffstat (limited to 'media/ndk')
-rw-r--r--media/ndk/Android.mk2
-rw-r--r--media/ndk/NdkMediaCodec.cpp137
-rw-r--r--media/ndk/NdkMediaCrypto.cpp117
-rw-r--r--media/ndk/NdkMediaCryptoPriv.h41
-rw-r--r--media/ndk/NdkMediaExtractor.cpp148
5 files changed, 436 insertions, 9 deletions
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"