New API to support submitting encrypted buffers to the decoder.

Change-Id: I69dd60e43078c4211c6123cf6e0ce90e676bf873
related-to-bug: 6275919
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index 5cbfbfe..ece3c09 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -296,15 +296,28 @@
                     if (sampleFlags & NuMediaExtractor::SAMPLE_FLAG_ENCRYPTED) {
                         CHECK(decryptInputBuffers);
 
-                        bufferFlags |= MediaCodec::BUFFER_FLAG_ENCRYPTED;
-                    }
+                        CryptoPlugin::SubSample ss;
+                        ss.mNumBytesOfClearData = 0;
+                        ss.mNumBytesOfEncryptedData = buffer->size();
 
-                    err = state->mCodec->queueInputBuffer(
-                            index,
-                            0 /* offset */,
-                            buffer->size(),
-                            timeUs,
-                            bufferFlags);
+                        err = state->mCodec->queueSecureInputBuffer(
+                                index,
+                                0 /* offset */,
+                                &ss,
+                                1 /* numSubSamples */,
+                                NULL /* key */,
+                                NULL /* iv */,
+                                CryptoPlugin::kMode_AES_WV,
+                                timeUs,
+                                bufferFlags);
+                    } else {
+                        err = state->mCodec->queueInputBuffer(
+                                index,
+                                0 /* offset */,
+                                buffer->size(),
+                                timeUs,
+                                bufferFlags);
+                    }
 
                     CHECK_EQ(err, (status_t)OK);
 
diff --git a/include/media/stagefright/MediaCodec.h b/include/media/stagefright/MediaCodec.h
index 0b0d511..107699e 100644
--- a/include/media/stagefright/MediaCodec.h
+++ b/include/media/stagefright/MediaCodec.h
@@ -19,6 +19,7 @@
 #define MEDIA_CODEC_H_
 
 #include <gui/ISurfaceTexture.h>
+#include <media/hardware/CryptoAPI.h>
 #include <media/stagefright/foundation/AHandler.h>
 #include <utils/Vector.h>
 
@@ -40,7 +41,6 @@
         BUFFER_FLAG_SYNCFRAME   = 1,
         BUFFER_FLAG_CODECCONFIG = 2,
         BUFFER_FLAG_EOS         = 4,
-        BUFFER_FLAG_ENCRYPTED   = 8,
     };
 
     static sp<MediaCodec> CreateByType(
@@ -74,6 +74,17 @@
             int64_t presentationTimeUs,
             uint32_t flags);
 
+    status_t queueSecureInputBuffer(
+            size_t index,
+            size_t offset,
+            const CryptoPlugin::SubSample *subSamples,
+            size_t numSubSamples,
+            const uint8_t key[16],
+            const uint8_t iv[16],
+            CryptoPlugin::Mode mode,
+            int64_t presentationTimeUs,
+            uint32_t flags);
+
     status_t dequeueInputBuffer(size_t *index, int64_t timeoutUs = 0ll);
 
     status_t dequeueOutputBuffer(
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index 1fe6bed..e6bea1f 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -97,6 +97,17 @@
         data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
         data.writeInt32(secure);
         data.writeInt32(mode);
+
+        static const uint8_t kDummy[16] = { 0 };
+
+        if (key == NULL) {
+            key = kDummy;
+        }
+
+        if (iv == NULL) {
+            iv = kDummy;
+        }
+
         data.write(key, 16);
         data.write(iv, 16);
 
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index ced8368..a382f1c 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -191,6 +191,31 @@
     return PostAndAwaitResponse(msg, &response);
 }
 
+status_t MediaCodec::queueSecureInputBuffer(
+        size_t index,
+        size_t offset,
+        const CryptoPlugin::SubSample *subSamples,
+        size_t numSubSamples,
+        const uint8_t key[16],
+        const uint8_t iv[16],
+        CryptoPlugin::Mode mode,
+        int64_t presentationTimeUs,
+        uint32_t flags) {
+    sp<AMessage> msg = new AMessage(kWhatQueueInputBuffer, id());
+    msg->setSize("index", index);
+    msg->setSize("offset", offset);
+    msg->setPointer("subSamples", (void *)subSamples);
+    msg->setSize("numSubSamples", numSubSamples);
+    msg->setPointer("key", (void *)key);
+    msg->setPointer("iv", (void *)iv);
+    msg->setInt32("mode", mode);
+    msg->setInt64("timeUs", presentationTimeUs);
+    msg->setInt32("flags", flags);
+
+    sp<AMessage> response;
+    return PostAndAwaitResponse(msg, &response);
+}
+
 status_t MediaCodec::dequeueInputBuffer(size_t *index, int64_t timeoutUs) {
     sp<AMessage> msg = new AMessage(kWhatDequeueInputBuffer, id());
     msg->setInt64("timeoutUs", timeoutUs);
@@ -1149,10 +1174,51 @@
     uint32_t flags;
     CHECK(msg->findSize("index", &index));
     CHECK(msg->findSize("offset", &offset));
-    CHECK(msg->findSize("size", &size));
     CHECK(msg->findInt64("timeUs", &timeUs));
     CHECK(msg->findInt32("flags", (int32_t *)&flags));
 
+    const CryptoPlugin::SubSample *subSamples;
+    size_t numSubSamples;
+    const uint8_t *key;
+    const uint8_t *iv;
+    CryptoPlugin::Mode mode = CryptoPlugin::kMode_Unencrypted;
+
+    // We allow the simpler queueInputBuffer API to be used even in
+    // secure mode, by fabricating a single unencrypted subSample.
+    CryptoPlugin::SubSample ss;
+
+    if (msg->findSize("size", &size)) {
+        if (mCrypto != NULL) {
+            ss.mNumBytesOfClearData = size;
+            ss.mNumBytesOfEncryptedData = 0;
+
+            subSamples = &ss;
+            numSubSamples = 1;
+            key = NULL;
+            iv = NULL;
+        }
+    } else {
+        if (mCrypto == NULL) {
+            return -EINVAL;
+        }
+
+        CHECK(msg->findPointer("subSamples", (void **)&subSamples));
+        CHECK(msg->findSize("numSubSamples", &numSubSamples));
+        CHECK(msg->findPointer("key", (void **)&key));
+        CHECK(msg->findPointer("iv", (void **)&iv));
+
+        int32_t tmp;
+        CHECK(msg->findInt32("mode", &tmp));
+
+        mode = (CryptoPlugin::Mode)tmp;
+
+        size = 0;
+        for (size_t i = 0; i < numSubSamples; ++i) {
+            size += subSamples[i].mNumBytesOfClearData;
+            size += subSamples[i].mNumBytesOfEncryptedData;
+        }
+    }
+
     if (index >= mPortBuffers[kPortIndexInput].size()) {
         return -ERANGE;
     }
@@ -1187,29 +1253,14 @@
             return -ERANGE;
         }
 
-        uint8_t key[16];
-        uint8_t iv[16];
-
-        CryptoPlugin::Mode mode;
-        CryptoPlugin::SubSample ss;
-        if (flags & BUFFER_FLAG_ENCRYPTED) {
-            mode = CryptoPlugin::kMode_AES_WV;
-            ss.mNumBytesOfClearData = 0;
-            ss.mNumBytesOfEncryptedData = size;
-        } else {
-            mode = CryptoPlugin::kMode_Unencrypted;
-            ss.mNumBytesOfClearData = size;
-            ss.mNumBytesOfEncryptedData = 0;
-        }
-
         status_t err = mCrypto->decrypt(
                 (mFlags & kFlagIsSecure) != 0,
                 key,
                 iv,
                 mode,
                 info->mEncryptedData->base() + offset,
-                &ss,
-                1 /* numSubSamples */,
+                subSamples,
+                numSubSamples,
                 info->mData->base());
 
         if (err != OK) {
@@ -1217,8 +1268,6 @@
         }
 
         info->mData->setRange(0, size);
-    } else if (flags & BUFFER_FLAG_ENCRYPTED) {
-        return -EINVAL;
     }
 
     reply->setBuffer("buffer", info->mData);