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/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"