summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/ndk/Android.mk6
-rw-r--r--media/ndk/NdkMediaCodec.cpp161
-rw-r--r--media/ndk/NdkMediaCrypto.cpp121
-rw-r--r--media/ndk/NdkMediaCryptoPriv.h41
-rw-r--r--media/ndk/NdkMediaDrm.cpp627
-rw-r--r--media/ndk/NdkMediaExtractor.cpp163
-rw-r--r--media/ndk/NdkMediaFormat.cpp62
-rw-r--r--media/ndk/NdkMediaMuxer.cpp8
8 files changed, 1155 insertions, 34 deletions
diff --git a/media/ndk/Android.mk b/media/ndk/Android.mk
index b8dd19e..8f795cd 100644
--- a/media/ndk/Android.mk
+++ b/media/ndk/Android.mk
@@ -22,9 +22,11 @@ include $(CLEAR_VARS)
LOCAL_SRC_FILES:= \
NdkMediaCodec.cpp \
+ NdkMediaCrypto.cpp \
NdkMediaExtractor.cpp \
NdkMediaFormat.cpp \
NdkMediaMuxer.cpp \
+ NdkMediaDrm.cpp \
LOCAL_MODULE:= libmediandk
@@ -33,13 +35,17 @@ LOCAL_C_INCLUDES := \
frameworks/base/core/jni \
frameworks/av/include/ndk
+LOCAL_CFLAGS += -fvisibility=hidden -D EXPORT='__attribute__ ((visibility ("default")))'
+
LOCAL_SHARED_LIBRARIES := \
+ libbinder \
libmedia \
libstagefright \
libstagefright_foundation \
liblog \
libutils \
libandroid_runtime \
+ libbinder \
include $(BUILD_SHARED_LIBRARY)
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 1789f75..a7c06d5 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 {
@@ -158,19 +159,22 @@ static AMediaCodec * createAMediaCodec(const char *name, bool name_is_type, bool
return mData;
}
-
+EXPORT
AMediaCodec* AMediaCodec_createCodecByName(const char *name) {
return createAMediaCodec(name, false, false);
}
+EXPORT
AMediaCodec* AMediaCodec_createDecoderByType(const char *mime_type) {
return createAMediaCodec(mime_type, true, false);
}
+EXPORT
AMediaCodec* AMediaCodec_createEncoderByType(const char *name) {
return createAMediaCodec(name, true, true);
}
+EXPORT
int AMediaCodec_delete(AMediaCodec *mData) {
if (mData->mCodec != NULL) {
mData->mCodec->release();
@@ -186,8 +190,13 @@ int AMediaCodec_delete(AMediaCodec *mData) {
return OK;
}
+EXPORT
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,9 +205,11 @@ 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));
}
+EXPORT
int AMediaCodec_start(AMediaCodec *mData) {
status_t ret = mData->mCodec->start();
if (ret != OK) {
@@ -210,6 +221,7 @@ int AMediaCodec_start(AMediaCodec *mData) {
return OK;
}
+EXPORT
int AMediaCodec_stop(AMediaCodec *mData) {
int ret = translate_error(mData->mCodec->stop());
@@ -221,10 +233,12 @@ int AMediaCodec_stop(AMediaCodec *mData) {
return ret;
}
+EXPORT
int AMediaCodec_flush(AMediaCodec *mData) {
return translate_error(mData->mCodec->flush());
}
+EXPORT
ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
size_t idx;
status_t ret = mData->mCodec->dequeueInputBuffer(&idx, timeoutUs);
@@ -235,6 +249,7 @@ ssize_t AMediaCodec_dequeueInputBuffer(AMediaCodec *mData, int64_t timeoutUs) {
return translate_error(ret);
}
+EXPORT
uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
android::Vector<android::sp<android::ABuffer> > abufs;
if (mData->mCodec->getInputBuffers(&abufs) == 0) {
@@ -252,6 +267,7 @@ uint8_t* AMediaCodec_getInputBuffer(AMediaCodec *mData, size_t idx, size_t *out_
return NULL;
}
+EXPORT
uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out_size) {
android::Vector<android::sp<android::ABuffer> > abufs;
if (mData->mCodec->getOutputBuffers(&abufs) == 0) {
@@ -269,6 +285,7 @@ uint8_t* AMediaCodec_getOutputBuffer(AMediaCodec *mData, size_t idx, size_t *out
return NULL;
}
+EXPORT
int AMediaCodec_queueInputBuffer(AMediaCodec *mData,
size_t idx, off_t offset, size_t size, uint64_t time, uint32_t flags) {
@@ -277,6 +294,7 @@ int AMediaCodec_queueInputBuffer(AMediaCodec *mData,
return translate_error(ret);
}
+EXPORT
ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData,
AMediaCodecBufferInfo *info, int64_t timeoutUs) {
size_t idx;
@@ -306,12 +324,14 @@ ssize_t AMediaCodec_dequeueOutputBuffer(AMediaCodec *mData,
return translate_error(ret);
}
+EXPORT
AMediaFormat* AMediaCodec_getOutputFormat(AMediaCodec *mData) {
sp<AMessage> format;
mData->mCodec->getOutputFormat(&format);
return AMediaFormat_fromMsg(&format);
}
+EXPORT
int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render) {
if (render) {
return translate_error(mData->mCodec->renderOutputBufferAndRelease(idx));
@@ -320,12 +340,143 @@ int AMediaCodec_releaseOutputBuffer(AMediaCodec *mData, size_t idx, bool render)
}
}
+EXPORT
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;
+
+EXPORT
+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);
+}
+
+
+
+EXPORT
+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 + 1); // point immediately after the struct
+ ret->encryptedbytes = ret->clearbytes + numsubsamples; // point after the clear sizes
+
+ memcpy(ret->clearbytes, clearbytes, numsubsamples * sizeof(size_t));
+ memcpy(ret->encryptedbytes, encryptedbytes, numsubsamples * sizeof(size_t));
+
+ return ret;
+}
+
+
+EXPORT
+int AMediaCodecCryptoInfo_delete(AMediaCodecCryptoInfo* info) {
+ free(info);
+ return OK;
+}
+
+EXPORT
+size_t AMediaCodecCryptoInfo_getNumSubSamples(AMediaCodecCryptoInfo* ci) {
+ return ci->numsubsamples;
+}
+
+EXPORT
+int AMediaCodecCryptoInfo_getKey(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
+ if (!dst || !ci) {
+ return AMEDIAERROR_UNSUPPORTED;
+ }
+ memcpy(dst, ci->key, 16);
+ return OK;
+}
+
+EXPORT
+int AMediaCodecCryptoInfo_getIV(AMediaCodecCryptoInfo* ci, uint8_t *dst) {
+ if (!dst || !ci) {
+ return AMEDIAERROR_UNSUPPORTED;
+ }
+ memcpy(dst, ci->iv, 16);
+ return OK;
+}
+
+EXPORT
+uint32_t AMediaCodecCryptoInfo_getMode(AMediaCodecCryptoInfo* ci) {
+ if (!ci) {
+ return AMEDIAERROR_UNSUPPORTED;
+ }
+ return ci->mode;
+}
+
+EXPORT
+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;
+}
+
+EXPORT
+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..c686273
--- /dev/null
+++ b/media/ndk/NdkMediaCrypto.cpp
@@ -0,0 +1,121 @@
+/*
+ * 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" {
+
+
+EXPORT
+bool AMediaCrypto_isCryptoSchemeSupported(const AMediaUUID uuid) {
+ sp<ICrypto> crypto = makeCrypto();
+ if (crypto == NULL) {
+ return false;
+ }
+ return crypto->isCryptoSchemeSupported(uuid);
+}
+
+EXPORT
+bool AMediaCrypto_requiresSecureDecoderComponent(const char *mime) {
+ sp<ICrypto> crypto = makeCrypto();
+ if (crypto == NULL) {
+ return false;
+ }
+ return crypto->requiresSecureDecoderComponent(mime);
+}
+
+EXPORT
+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;
+}
+
+EXPORT
+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/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
new file mode 100644
index 0000000..5e50418
--- /dev/null
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -0,0 +1,627 @@
+/*
+ * 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 "NdkMediaDrm"
+
+#include "NdkMediaDrm.h"
+
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+#include <gui/Surface.h>
+
+#include <media/IDrm.h>
+#include <media/IDrmClient.h>
+#include <media/stagefright/MediaErrors.h>
+#include <binder/IServiceManager.h>
+#include <media/IMediaPlayerService.h>
+#include <ndk/NdkMediaCrypto.h>
+
+
+using namespace android;
+
+typedef Vector<uint8_t> idvec_t;
+
+struct AMediaDrm {
+ sp<IDrm> mDrm;
+ sp<IDrmClient> mDrmClient;
+ AMediaDrmEventListener mListener;
+ List<idvec_t> mIds;
+ KeyedVector<String8, String8> mQueryResults;
+ Vector<uint8_t> mKeyRequest;
+ Vector<uint8_t> mProvisionRequest;
+ String8 mProvisionUrl;
+ String8 mPropertyString;
+ Vector<uint8_t> mPropertyByteArray;
+ List<Vector<uint8_t> > mSecureStops;
+};
+
+extern "C" {
+
+static mediadrm_status_t translateStatus(status_t status) {
+ mediadrm_status_t result = MEDIADRM_UNKNOWN_ERROR;
+ switch (status) {
+ case OK:
+ result = MEDIADRM_OK;
+ break;
+ case android::ERROR_DRM_NOT_PROVISIONED:
+ result = MEDIADRM_NOT_PROVISIONED_ERROR;
+ break;
+ case android::ERROR_DRM_RESOURCE_BUSY:
+ result = MEDIADRM_RESOURCE_BUSY_ERROR;
+ break;
+ case android::ERROR_DRM_DEVICE_REVOKED:
+ result = MEDIADRM_DEVICE_REVOKED_ERROR;
+ break;
+ case android::ERROR_DRM_CANNOT_HANDLE:
+ result = MEDIADRM_INVALID_PARAMETER_ERROR;
+ break;
+ case android::ERROR_DRM_TAMPER_DETECTED:
+ result = MEDIADRM_TAMPER_DETECTED_ERROR;
+ break;
+ case android::ERROR_DRM_SESSION_NOT_OPENED:
+ result = MEDIADRM_SESSION_NOT_OPENED_ERROR;
+ break;
+ case android::ERROR_DRM_NO_LICENSE:
+ result = MEDIADRM_NEED_KEY_ERROR;
+ break;
+ case android::ERROR_DRM_LICENSE_EXPIRED:
+ result = MEDIADRM_LICENSE_EXPIRED_ERROR;
+ break;
+ default:
+ result = MEDIADRM_UNKNOWN_ERROR;
+ break;
+ }
+ return result;
+}
+
+static sp<IDrm> CreateDrm() {
+ 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<IDrm> drm = service->makeDrm();
+
+ if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
+ return NULL;
+ }
+
+ return drm;
+}
+
+
+static sp<IDrm> CreateDrmFromUUID(const AMediaUUID uuid) {
+ sp<IDrm> drm = CreateDrm();
+
+ if (drm == NULL) {
+ return NULL;
+ }
+
+ status_t err = drm->createPlugin(uuid);
+
+ if (err != OK) {
+ return NULL;
+ }
+
+ return drm;
+}
+
+EXPORT
+bool AMediaDrm_isCryptoSchemeSupported(const AMediaUUID uuid, const char *mimeType) {
+ sp<IDrm> drm = CreateDrm();
+
+ if (drm == NULL) {
+ return false;
+ }
+
+ String8 mimeStr = mimeType ? String8(mimeType) : String8("");
+ return drm->isCryptoSchemeSupported(uuid, mimeStr);
+}
+
+EXPORT
+AMediaDrm* AMediaDrm_createByUUID(const AMediaUUID uuid) {
+ AMediaDrm *mObj = new AMediaDrm();
+ mObj->mDrm = CreateDrmFromUUID(uuid);
+ return mObj;
+}
+
+EXPORT
+void AMediaDrm_release(AMediaDrm *mObj) {
+ if (mObj->mDrm != NULL) {
+ mObj->mDrm->setListener(NULL);
+ mObj->mDrm->destroyPlugin();
+ mObj->mDrm.clear();
+ }
+ delete mObj;
+}
+
+#if 0
+void AMediaDrm_setOnEventListener(AMediaDrm *mObj, AMediaDrmEventListener listener) {
+ mObj->mListener = listener;
+}
+#endif
+
+
+static bool findId(AMediaDrm *mObj, const AMediaDrmByteArray &id, List<idvec_t>::iterator &iter) {
+ iter = mObj->mIds.begin();
+ while (iter != mObj->mIds.end()) {
+ if (iter->array() == id.ptr && iter->size() == id.length) {
+ return true;
+ }
+ }
+ return false;
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_openSession(AMediaDrm *mObj, AMediaDrmSessionId &sessionId) {
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+ Vector<uint8_t> session;
+ status_t status = mObj->mDrm->openSession(session);
+ if (status == OK) {
+ mObj->mIds.push_front(session);
+ List<idvec_t>::iterator iter = mObj->mIds.begin();
+ sessionId.ptr = iter->array();
+ sessionId.length = iter->size();
+ }
+ return MEDIADRM_OK;
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_closeSession(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId) {
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+
+ List<idvec_t>::iterator iter;
+ if (!findId(mObj, sessionId, iter)) {
+ return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+ }
+ mObj->mDrm->closeSession(*iter);
+ mObj->mIds.erase(iter);
+ return MEDIADRM_OK;
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_getKeyRequest(AMediaDrm *mObj, const AMediaDrmScope &scope,
+ const uint8_t *init, size_t initSize, const char *mimeType, AMediaDrmKeyType keyType,
+ const AMediaDrmKeyValue *optionalParameters, size_t numOptionalParameters,
+ const uint8_t *&keyRequest, size_t &keyRequestSize) {
+
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+ if (!mimeType) {
+ return MEDIADRM_INVALID_PARAMETER_ERROR;
+ }
+
+ List<idvec_t>::iterator iter;
+ if (!findId(mObj, scope, iter)) {
+ return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+ }
+
+ Vector<uint8_t> mdInit;
+ mdInit.appendArray(init, initSize);
+ DrmPlugin::KeyType mdKeyType;
+ switch (keyType) {
+ case KEY_TYPE_STREAMING:
+ mdKeyType = DrmPlugin::kKeyType_Streaming;
+ break;
+ case KEY_TYPE_OFFLINE:
+ mdKeyType = DrmPlugin::kKeyType_Offline;
+ break;
+ case KEY_TYPE_RELEASE:
+ mdKeyType = DrmPlugin::kKeyType_Release;
+ break;
+ default:
+ return MEDIADRM_INVALID_PARAMETER_ERROR;
+ }
+ KeyedVector<String8, String8> mdOptionalParameters;
+ for (size_t i = 0; i < numOptionalParameters; i++) {
+ mdOptionalParameters.add(String8(optionalParameters[i].mKey),
+ String8(optionalParameters[i].mValue));
+ }
+ String8 defaultUrl;
+ status_t status = mObj->mDrm->getKeyRequest(*iter, mdInit, String8(mimeType),
+ mdKeyType, mdOptionalParameters, mObj->mKeyRequest, defaultUrl);
+ if (status != OK) {
+ return translateStatus(status);
+ } else {
+ keyRequest = mObj->mKeyRequest.array();
+ keyRequestSize = mObj->mKeyRequest.size();
+ }
+ return MEDIADRM_OK;
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_provideKeyResponse(AMediaDrm *mObj, const AMediaDrmScope &scope,
+ const uint8_t *response, size_t responseSize, AMediaDrmKeySetId &keySetId) {
+
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+ if (!response || !responseSize) {
+ return MEDIADRM_INVALID_PARAMETER_ERROR;
+ }
+
+ List<idvec_t>::iterator iter;
+ if (!findId(mObj, scope, iter)) {
+ return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+ }
+ Vector<uint8_t> mdResponse;
+ mdResponse.appendArray(response, responseSize);
+
+ Vector<uint8_t> mdKeySetId;
+ status_t status = mObj->mDrm->provideKeyResponse(*iter, mdResponse, mdKeySetId);
+ if (status == OK) {
+ mObj->mIds.push_front(mdKeySetId);
+ List<idvec_t>::iterator iter = mObj->mIds.begin();
+ keySetId.ptr = iter->array();
+ keySetId.length = iter->size();
+ } else {
+ keySetId.ptr = NULL;
+ keySetId.length = 0;
+ }
+ return MEDIADRM_OK;
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_restoreKeys(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+ const AMediaDrmKeySetId &keySetId) {
+
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+ List<idvec_t>::iterator iter;
+ if (!findId(mObj, sessionId, iter)) {
+ return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+ }
+ Vector<uint8_t> keySet;
+ keySet.appendArray(keySetId.ptr, keySetId.length);
+ return translateStatus(mObj->mDrm->restoreKeys(*iter, keySet));
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_removeKeys(AMediaDrm *mObj, const AMediaDrmSessionId &keySetId) {
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+ List<idvec_t>::iterator iter;
+ status_t status;
+ if (!findId(mObj, keySetId, iter)) {
+ Vector<uint8_t> keySet;
+ keySet.appendArray(keySetId.ptr, keySetId.length);
+ status = mObj->mDrm->removeKeys(keySet);
+ } else {
+ status = mObj->mDrm->removeKeys(*iter);
+ mObj->mIds.erase(iter);
+ }
+ return translateStatus(status);
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_queryKeyStatus(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+ AMediaDrmKeyValue *keyValuePairs, size_t &numPairs) {
+
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+ List<idvec_t>::iterator iter;
+ if (!findId(mObj, sessionId, iter)) {
+ return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+ }
+
+ status_t status = mObj->mDrm->queryKeyStatus(*iter, mObj->mQueryResults);
+ if (status != OK) {
+ numPairs = 0;
+ return translateStatus(status);
+ }
+
+ if (mObj->mQueryResults.size() > numPairs) {
+ numPairs = mObj->mQueryResults.size();
+ return MEDIADRM_SHORT_BUFFER;
+ }
+
+ for (size_t i = 0; i < mObj->mQueryResults.size(); i++) {
+ keyValuePairs[i].mKey = mObj->mQueryResults.keyAt(i).string();
+ keyValuePairs[i].mValue = mObj->mQueryResults.keyAt(i).string();
+ }
+ numPairs = mObj->mQueryResults.size();
+ return MEDIADRM_OK;
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_getProvisionRequest(AMediaDrm *mObj, const uint8_t *&provisionRequest,
+ size_t &provisionRequestSize, const char *&serverUrl) {
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+ if (!provisionRequestSize || !serverUrl) {
+ return MEDIADRM_INVALID_PARAMETER_ERROR;
+ }
+
+ status_t status = mObj->mDrm->getProvisionRequest(String8(""), String8(""),
+ mObj->mProvisionRequest, mObj->mProvisionUrl);
+ if (status != OK) {
+ return translateStatus(status);
+ } else {
+ provisionRequest = mObj->mProvisionRequest.array();
+ provisionRequestSize = mObj->mProvisionRequest.size();
+ serverUrl = mObj->mProvisionUrl.string();
+ }
+ return MEDIADRM_OK;
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_provideProvisionResponse(AMediaDrm *mObj,
+ const uint8_t *response, size_t responseSize) {
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+ if (!response || !responseSize) {
+ return MEDIADRM_INVALID_PARAMETER_ERROR;
+ }
+
+ Vector<uint8_t> mdResponse;
+ mdResponse.appendArray(response, responseSize);
+
+ Vector<uint8_t> unused;
+ return translateStatus(mObj->mDrm->provideProvisionResponse(mdResponse, unused, unused));
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_getSecureStops(AMediaDrm *mObj,
+ AMediaDrmSecureStop *secureStops, size_t &numSecureStops) {
+
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+ status_t status = mObj->mDrm->getSecureStops(mObj->mSecureStops);
+ if (status != OK) {
+ numSecureStops = 0;
+ return translateStatus(status);
+ }
+ if (numSecureStops < mObj->mSecureStops.size()) {
+ return MEDIADRM_SHORT_BUFFER;
+ }
+ List<Vector<uint8_t> >::iterator iter = mObj->mSecureStops.begin();
+ size_t i = 0;
+ while (iter != mObj->mSecureStops.end()) {
+ secureStops[i].ptr = iter->array();
+ secureStops[i].length = iter->size();
+ ++iter;
+ ++i;
+ }
+ numSecureStops = mObj->mSecureStops.size();
+ return MEDIADRM_OK;
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_releaseSecureStops(AMediaDrm *mObj,
+ const AMediaDrmSecureStop &ssRelease) {
+
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+
+ Vector<uint8_t> release;
+ release.appendArray(ssRelease.ptr, ssRelease.length);
+ return translateStatus(mObj->mDrm->releaseSecureStops(release));
+}
+
+
+EXPORT
+mediadrm_status_t AMediaDrm_getPropertyString(AMediaDrm *mObj, const char *propertyName,
+ const char *&propertyValue) {
+
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+
+ status_t status = mObj->mDrm->getPropertyString(String8(propertyName),
+ mObj->mPropertyString);
+
+ if (status == OK) {
+ propertyValue = mObj->mPropertyString.string();
+ } else {
+ propertyValue = NULL;
+ }
+ return translateStatus(status);
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_getPropertyByteArray(AMediaDrm *mObj,
+ const char *propertyName, AMediaDrmByteArray &propertyValue) {
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+
+ status_t status = mObj->mDrm->getPropertyByteArray(String8(propertyName),
+ mObj->mPropertyByteArray);
+
+ if (status == OK) {
+ propertyValue.ptr = mObj->mPropertyByteArray.array();
+ propertyValue.length = mObj->mPropertyByteArray.size();
+ } else {
+ propertyValue.ptr = NULL;
+ propertyValue.length = 0;
+ }
+ return translateStatus(status);
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_setPropertyString(AMediaDrm *mObj,
+ const char *propertyName, const char *value) {
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+
+ return translateStatus(mObj->mDrm->setPropertyString(String8(propertyName),
+ String8(value)));
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_setPropertyByteArray(AMediaDrm *mObj,
+ const char *propertyName, const uint8_t *value, size_t valueSize) {
+
+ Vector<uint8_t> byteArray;
+ byteArray.appendArray(value, valueSize);
+
+ return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
+ byteArray));
+}
+
+
+static mediadrm_status_t encrypt_decrypt_common(AMediaDrm *mObj,
+ const AMediaDrmSessionId &sessionId,
+ const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
+ const uint8_t *input, uint8_t *output, size_t dataSize, bool encrypt) {
+
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+ List<idvec_t>::iterator iter;
+ if (!findId(mObj, sessionId, iter)) {
+ return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+ }
+
+ status_t status = mObj->mDrm->setCipherAlgorithm(*iter, String8(cipherAlgorithm));
+ if (status != OK) {
+ return translateStatus(status);
+ }
+
+ Vector<uint8_t> keyIdVec;
+ const size_t kKeyIdSize = 16;
+ keyIdVec.appendArray(keyId, kKeyIdSize);
+
+ Vector<uint8_t> inputVec;
+ inputVec.appendArray(input, dataSize);
+
+ Vector<uint8_t> ivVec;
+ const size_t kIvSize = 16;
+ ivVec.appendArray(iv, kIvSize);
+
+ Vector<uint8_t> outputVec;
+ if (encrypt) {
+ status_t status = mObj->mDrm->encrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
+ } else {
+ status_t status = mObj->mDrm->decrypt(*iter, keyIdVec, inputVec, ivVec, outputVec);
+ }
+ if (status == OK) {
+ memcpy(output, outputVec.array(), outputVec.size());
+ }
+ return translateStatus(status);
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_encrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+ const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
+ const uint8_t *input, uint8_t *output, size_t dataSize) {
+ return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv,
+ input, output, dataSize, true);
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_decrypt(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+ const char *cipherAlgorithm, uint8_t *keyId, uint8_t *iv,
+ const uint8_t *input, uint8_t *output, size_t dataSize) {
+ return encrypt_decrypt_common(mObj, sessionId, cipherAlgorithm, keyId, iv,
+ input, output, dataSize, false);
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_sign(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+ const char *macAlgorithm, uint8_t *keyId, uint8_t *message, size_t messageSize,
+ uint8_t *signature, size_t *signatureSize) {
+
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+ List<idvec_t>::iterator iter;
+ if (!findId(mObj, sessionId, iter)) {
+ return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+ }
+
+ status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
+ if (status != OK) {
+ return translateStatus(status);
+ }
+
+ Vector<uint8_t> keyIdVec;
+ const size_t kKeyIdSize = 16;
+ keyIdVec.appendArray(keyId, kKeyIdSize);
+
+ Vector<uint8_t> messageVec;
+ messageVec.appendArray(message, messageSize);
+
+ Vector<uint8_t> signatureVec;
+ status = mObj->mDrm->sign(*iter, keyIdVec, messageVec, signatureVec);
+ if (signatureVec.size() > *signatureSize) {
+ return MEDIADRM_SHORT_BUFFER;
+ }
+ if (status == OK) {
+ memcpy(signature, signatureVec.array(), signatureVec.size());
+ }
+ return translateStatus(status);
+}
+
+EXPORT
+mediadrm_status_t AMediaDrm_verify(AMediaDrm *mObj, const AMediaDrmSessionId &sessionId,
+ const char *macAlgorithm, uint8_t *keyId, const uint8_t *message, size_t messageSize,
+ const uint8_t *signature, size_t signatureSize) {
+
+ if (!mObj || mObj->mDrm == NULL) {
+ return MEDIADRM_INVALID_OBJECT_ERROR;
+ }
+ List<idvec_t>::iterator iter;
+ if (!findId(mObj, sessionId, iter)) {
+ return MEDIADRM_SESSION_NOT_OPENED_ERROR;
+ }
+
+ status_t status = mObj->mDrm->setMacAlgorithm(*iter, String8(macAlgorithm));
+ if (status != OK) {
+ return translateStatus(status);
+ }
+
+ Vector<uint8_t> keyIdVec;
+ const size_t kKeyIdSize = 16;
+ keyIdVec.appendArray(keyId, kKeyIdSize);
+
+ Vector<uint8_t> messageVec;
+ messageVec.appendArray(message, messageSize);
+
+ Vector<uint8_t> signatureVec;
+ signatureVec.appendArray(signature, signatureSize);
+
+ bool match;
+ status = mObj->mDrm->verify(*iter, keyIdVec, messageVec, signatureVec, match);
+ if (status == OK) {
+ return match ? MEDIADRM_OK : MEDIADRM_VERIFY_FAILED;
+ }
+ return translateStatus(status);
+}
+
+} // extern "C"
+
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index 681633a..e23adf3 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,16 +43,18 @@ 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;
};
extern "C" {
+EXPORT
AMediaExtractor* AMediaExtractor_new() {
ALOGV("ctor");
AMediaExtractor *mData = new AMediaExtractor();
@@ -58,18 +62,21 @@ AMediaExtractor* AMediaExtractor_new() {
return mData;
}
+EXPORT
int AMediaExtractor_delete(AMediaExtractor *mData) {
ALOGV("dtor");
delete mData;
return OK;
}
+EXPORT
int AMediaExtractor_setDataSourceFd(AMediaExtractor *mData, int fd, off64_t offset, off64_t length) {
ALOGV("setDataSource(%d, %lld, %lld)", fd, offset, length);
mData->mImpl->setDataSource(fd, offset, length);
return 0;
}
+EXPORT
int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) {
ALOGV("setDataSource(%s)", location);
// TODO: add header support
@@ -79,14 +86,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 +101,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,34 +117,40 @@ int AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location)
mData->mImpl->setDataSource(httpService, location, NULL);
env->ExceptionClear();
- return 0;
+ return OK;
}
+EXPORT
int AMediaExtractor_getTrackCount(AMediaExtractor *mData) {
return mData->mImpl->countTracks();
}
+EXPORT
AMediaFormat* AMediaExtractor_getTrackFormat(AMediaExtractor *mData, size_t idx) {
sp<AMessage> format;
mData->mImpl->getTrackFormat(idx, &format);
return AMediaFormat_fromMsg(&format);
}
+EXPORT
int AMediaExtractor_selectTrack(AMediaExtractor *mData, size_t idx) {
ALOGV("selectTrack(%z)", idx);
return translate_error(mData->mImpl->selectTrack(idx));
}
+EXPORT
int AMediaExtractor_unselectTrack(AMediaExtractor *mData, size_t idx) {
ALOGV("unselectTrack(%z)", idx);
return translate_error(mData->mImpl->unselectTrack(idx));
}
+EXPORT
bool AMediaExtractor_advance(AMediaExtractor *mData) {
//ALOGV("advance");
return mData->mImpl->advance();
}
+EXPORT
int AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size_t capacity) {
//ALOGV("readSampleData");
sp<ABuffer> tmp = new ABuffer(buffer, capacity);
@@ -147,6 +160,7 @@ int AMediaExtractor_readSampleData(AMediaExtractor *mData, uint8_t *buffer, size
return -1;
}
+EXPORT
int AMediaExtractor_getSampleFlags(AMediaExtractor *mData) {
int sampleFlags = 0;
sp<MetaData> meta;
@@ -168,6 +182,7 @@ int AMediaExtractor_getSampleFlags(AMediaExtractor *mData) {
return sampleFlags;
}
+EXPORT
int AMediaExtractor_getSampleTrackIndex(AMediaExtractor *mData) {
size_t idx;
if (mData->mImpl->getSampleTrackIndex(&idx) != OK) {
@@ -176,6 +191,7 @@ int AMediaExtractor_getSampleTrackIndex(AMediaExtractor *mData) {
return idx;
}
+EXPORT
int64_t AMediaExtractor_getSampletime(AMediaExtractor *mData) {
int64_t time;
if (mData->mImpl->getSampleTime(&time) != OK) {
@@ -184,6 +200,143 @@ int64_t AMediaExtractor_getSampletime(AMediaExtractor *mData) {
return time;
}
+EXPORT
+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();
+}
+
+EXPORT
+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"
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index c08814f..e1d8c95 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -56,12 +56,14 @@ void AMediaFormat_getFormat(const AMediaFormat* mData, void* dest) {
/*
* public function follow
*/
+EXPORT
AMediaFormat *AMediaFormat_new() {
ALOGV("ctor");
sp<AMessage> msg = new AMessage();
return AMediaFormat_fromMsg(&msg);
}
+EXPORT
int AMediaFormat_delete(AMediaFormat *mData) {
ALOGV("dtor");
delete mData;
@@ -69,6 +71,7 @@ int AMediaFormat_delete(AMediaFormat *mData) {
}
+EXPORT
const char* AMediaFormat_toString(AMediaFormat *mData) {
sp<AMessage> f = mData->mFormat;
String8 ret;
@@ -141,22 +144,27 @@ const char* AMediaFormat_toString(AMediaFormat *mData) {
return mData->mDebug.string();
}
+EXPORT
bool AMediaFormat_getInt32(AMediaFormat* format, const char *name, int32_t *out) {
return format->mFormat->findInt32(name, out);
}
+EXPORT
bool AMediaFormat_getInt64(AMediaFormat* format, const char *name, int64_t *out) {
return format->mFormat->findInt64(name, out);
}
+EXPORT
bool AMediaFormat_getFloat(AMediaFormat* format, const char *name, float *out) {
return format->mFormat->findFloat(name, out);
}
+EXPORT
bool AMediaFormat_getSize(AMediaFormat* format, const char *name, size_t *out) {
return format->mFormat->findSize(name, out);
}
+EXPORT
bool AMediaFormat_getBuffer(AMediaFormat* format, const char *name, void** data, size_t *outsize) {
sp<ABuffer> buf;
if (format->mFormat->findBuffer(name, &buf)) {
@@ -167,6 +175,7 @@ bool AMediaFormat_getBuffer(AMediaFormat* format, const char *name, void** data,
return false;
}
+EXPORT
bool AMediaFormat_getString(AMediaFormat* mData, const char *name, const char **out) {
for (size_t i = 0; i < mData->mStringCache.size(); i++) {
@@ -186,23 +195,28 @@ bool AMediaFormat_getString(AMediaFormat* mData, const char *name, const char **
return false;
}
+EXPORT
void AMediaFormat_setInt32(AMediaFormat* format, const char *name, int32_t value) {
format->mFormat->setInt32(name, value);
}
+EXPORT
void AMediaFormat_setInt64(AMediaFormat* format, const char *name, int64_t value) {
format->mFormat->setInt64(name, value);
}
+EXPORT
void AMediaFormat_setFloat(AMediaFormat* format, const char* name, float value) {
format->mFormat->setFloat(name, value);
}
+EXPORT
void AMediaFormat_setString(AMediaFormat* format, const char* name, const char* value) {
// AMessage::setString() makes a copy of the string
format->mFormat->setString(name, value, strlen(value));
}
+EXPORT
void AMediaFormat_setBuffer(AMediaFormat* format, const char* name, void* data, size_t size) {
// the ABuffer(void*, size_t) constructor doesn't take ownership of the data, so create
// a new buffer and copy the data into it
@@ -214,30 +228,30 @@ void AMediaFormat_setBuffer(AMediaFormat* format, const char* name, void* data,
}
-const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile";
-const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate";
-const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count";
-const char* AMEDIAFORMAT_KEY_CHANNEL_MASK = "channel-mask";
-const char* AMEDIAFORMAT_KEY_COLOR_FORMAT = "color-format";
-const char* AMEDIAFORMAT_KEY_DURATION = "durationUs";
-const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
-const char* AMEDIAFORMAT_KEY_FRAME_RATE = "frame-rate";
-const char* AMEDIAFORMAT_KEY_HEIGHT = "height";
-const char* AMEDIAFORMAT_KEY_IS_ADTS = "is-adts";
-const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT = "is-autoselect";
-const char* AMEDIAFORMAT_KEY_IS_DEFAULT = "is-default";
-const char* AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
-const char* AMEDIAFORMAT_KEY_I_FRAME_INTERVAL = "i-frame-interval";
-const char* AMEDIAFORMAT_KEY_LANGUAGE = "language";
-const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height";
-const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
-const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";
-const char* AMEDIAFORMAT_KEY_MIME = "mime";
-const char* AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
-const char* AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after";
-const char* AMEDIAFORMAT_KEY_SAMPLE_RATE = "sample-rate";
-const char* AMEDIAFORMAT_KEY_WIDTH = "width";
-const char* AMEDIAFORMAT_KEY_STRIDE = "stride";
+EXPORT const char* AMEDIAFORMAT_KEY_AAC_PROFILE = "aac-profile";
+EXPORT const char* AMEDIAFORMAT_KEY_BIT_RATE = "bitrate";
+EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_COUNT = "channel-count";
+EXPORT const char* AMEDIAFORMAT_KEY_CHANNEL_MASK = "channel-mask";
+EXPORT const char* AMEDIAFORMAT_KEY_COLOR_FORMAT = "color-format";
+EXPORT const char* AMEDIAFORMAT_KEY_DURATION = "durationUs";
+EXPORT const char* AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL = "flac-compression-level";
+EXPORT const char* AMEDIAFORMAT_KEY_FRAME_RATE = "frame-rate";
+EXPORT const char* AMEDIAFORMAT_KEY_HEIGHT = "height";
+EXPORT const char* AMEDIAFORMAT_KEY_IS_ADTS = "is-adts";
+EXPORT const char* AMEDIAFORMAT_KEY_IS_AUTOSELECT = "is-autoselect";
+EXPORT const char* AMEDIAFORMAT_KEY_IS_DEFAULT = "is-default";
+EXPORT const char* AMEDIAFORMAT_KEY_IS_FORCED_SUBTITLE = "is-forced-subtitle";
+EXPORT const char* AMEDIAFORMAT_KEY_I_FRAME_INTERVAL = "i-frame-interval";
+EXPORT const char* AMEDIAFORMAT_KEY_LANGUAGE = "language";
+EXPORT const char* AMEDIAFORMAT_KEY_MAX_HEIGHT = "max-height";
+EXPORT const char* AMEDIAFORMAT_KEY_MAX_INPUT_SIZE = "max-input-size";
+EXPORT const char* AMEDIAFORMAT_KEY_MAX_WIDTH = "max-width";
+EXPORT const char* AMEDIAFORMAT_KEY_MIME = "mime";
+EXPORT const char* AMEDIAFORMAT_KEY_PUSH_BLANK_BUFFERS_ON_STOP = "push-blank-buffers-on-shutdown";
+EXPORT const char* AMEDIAFORMAT_KEY_REPEAT_PREVIOUS_FRAME_AFTER = "repeat-previous-frame-after";
+EXPORT const char* AMEDIAFORMAT_KEY_SAMPLE_RATE = "sample-rate";
+EXPORT const char* AMEDIAFORMAT_KEY_WIDTH = "width";
+EXPORT const char* AMEDIAFORMAT_KEY_STRIDE = "stride";
} // extern "C"
diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp
index 98129cb..aa78740 100644
--- a/media/ndk/NdkMediaMuxer.cpp
+++ b/media/ndk/NdkMediaMuxer.cpp
@@ -52,6 +52,7 @@ struct AMediaMuxer {
extern "C" {
+EXPORT
AMediaMuxer* AMediaMuxer_new(int fd, OutputFormat format) {
ALOGV("ctor");
AMediaMuxer *mData = new AMediaMuxer();
@@ -59,34 +60,41 @@ AMediaMuxer* AMediaMuxer_new(int fd, OutputFormat format) {
return mData;
}
+EXPORT
int AMediaMuxer_delete(AMediaMuxer *muxer) {
ALOGV("dtor");
delete muxer;
return OK;
}
+EXPORT
int AMediaMuxer_setLocation(AMediaMuxer *muxer, float latitude, float longtitude) {
return translate_error(muxer->mImpl->setLocation(latitude * 10000, longtitude * 10000));
}
+EXPORT
int AMediaMuxer_setOrientationHint(AMediaMuxer *muxer, int degrees) {
return translate_error(muxer->mImpl->setOrientationHint(degrees));
}
+EXPORT
ssize_t AMediaMuxer_addTrack(AMediaMuxer *muxer, const AMediaFormat *format) {
sp<AMessage> msg;
AMediaFormat_getFormat(format, &msg);
return translate_error(muxer->mImpl->addTrack(msg));
}
+EXPORT
int AMediaMuxer_start(AMediaMuxer *muxer) {
return translate_error(muxer->mImpl->start());
}
+EXPORT
int AMediaMuxer_stop(AMediaMuxer *muxer) {
return translate_error(muxer->mImpl->stop());
}
+EXPORT
int AMediaMuxer_writeSampleData(AMediaMuxer *muxer,
size_t trackIdx, const uint8_t *data, const AMediaCodecBufferInfo &info) {
sp<ABuffer> buf = new ABuffer((void*)(data + info.offset), info.size);