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
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 @@
     uint32_t flags;
 };
 typedef struct AMediaCodecBufferInfo AMediaCodecBufferInfo;
+typedef struct AMediaCodecCryptoInfo AMediaCodecCryptoInfo;
 
 enum {
     AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM = 4,
@@ -81,8 +83,12 @@
 /**
  * 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 @@
         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 @@
 int AMediaCodec_releaseOutputBuffer(AMediaCodec*, size_t idx, bool render);
 
 
-
 typedef void (*OnCodecEvent)(AMediaCodec *codec, void *userdata);
 
 /**
@@ -150,6 +161,36 @@
 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 @@
  */
 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 @@
 
 LOCAL_SRC_FILES:=                                       \
                   NdkMediaCodec.cpp                     \
+                  NdkMediaCrypto.cpp                    \
                   NdkMediaExtractor.cpp                 \
                   NdkMediaFormat.cpp                    \
                   NdkMediaMuxer.cpp                     \
@@ -34,6 +35,7 @@
     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 @@
         return AMEDIACODEC_INFO_TRY_AGAIN_LATER;
     }
     ALOGE("sf error code: %d", err);
-    return -1000;
+    return AMEDIAERROR_GENERIC;
 }
 
 enum {
@@ -187,7 +188,11 @@
 }
 
 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 @@
         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 @@
     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 @@
         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 @@
     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 @@
     if (mediaHttpCreateMethod == NULL) {
         ALOGE("can't find method");
         env->ExceptionClear();
-        return -1;
+        return AMEDIAERROR_UNSUPPORTED;
     }
 
     jstring jloc = env->NewStringUTF(location);
@@ -110,7 +113,7 @@
 
     mData->mImpl->setDataSource(httpService, location, NULL);
     env->ExceptionClear();
-    return 0;
+    return OK;
 }
 
 int AMediaExtractor_getTrackCount(AMediaExtractor *mData) {
@@ -184,6 +187,141 @@
     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"