OSDN Git Service

Support a "secure input buffer" mode for use by Widevine DRM in OMXCodec.
authorAndreas Huber <andih@google.com>
Wed, 29 Jun 2011 22:53:28 +0000 (15:53 -0700)
committerAndreas Huber <andih@google.com>
Fri, 1 Jul 2011 16:28:51 +0000 (09:28 -0700)
Change-Id: Ie03b285265099dbac9b12f3f41d9ad758d0b50ad

include/media/stagefright/MediaSource.h
include/media/stagefright/MetaData.h
include/media/stagefright/OMXCodec.h
media/libstagefright/OMXCodec.cpp

index a31395e..37dbcd8 100644 (file)
@@ -22,6 +22,7 @@
 
 #include <media/stagefright/MediaErrors.h>
 #include <utils/RefBase.h>
+#include <utils/Vector.h>
 
 namespace android {
 
@@ -99,6 +100,15 @@ struct MediaSource : public RefBase {
         return ERROR_UNSUPPORTED;
     }
 
+    // The consumer of this media source requests that the given buffers
+    // are to be returned exclusively in response to read calls.
+    // This will be called after a successful start() and before the
+    // first read() call.
+    // Callee assumes ownership of the buffers if no error is returned.
+    virtual status_t setBuffers(const Vector<MediaBuffer *> &buffers) {
+        return ERROR_UNSUPPORTED;
+    }
+
 protected:
     virtual ~MediaSource();
 
index 99b72ad..57f678c 100644 (file)
@@ -121,6 +121,8 @@ enum {
 
     // To store the timed text format data
     kKeyTextFormatData    = 'text',  // raw data
+
+    kKeyRequiresSecureBuffers = 'secu',  // bool (int32_t)
 };
 
 enum {
index 92331a1..7f3c497 100644 (file)
@@ -53,6 +53,9 @@ struct OMXCodec : public MediaSource,
 
         // Enable GRALLOC_USAGE_PROTECTED for output buffers from native window
         kEnableGrallocUsageProtected = 128,
+
+        // Secure decoding mode
+        kUseSecureInputBuffers = 256,
     };
     static sp<MediaSource> Create(
             const sp<IOMX> &omx,
@@ -164,6 +167,10 @@ private:
     bool mOMXLivesLocally;
     IOMX::node_id mNode;
     uint32_t mQuirks;
+
+    // Flags specified in the creation of the codec.
+    uint32_t mFlags;
+
     bool mIsEncoder;
     char *mMIME;
     char *mComponentName;
@@ -205,15 +212,12 @@ private:
     List<size_t> mFilledBuffers;
     Condition mBufferFilled;
 
-    bool mIsMetaDataStoredInVideoBuffers;
-    bool mOnlySubmitOneBufferAtOneTime;
-    bool mEnableGrallocUsageProtected;
-
     // Used to record the decoding time for an output picture from
     // a video encoder.
     List<int64_t> mDecodingTimeList;
 
-    OMXCodec(const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
+    OMXCodec(const sp<IOMX> &omx, IOMX::node_id node,
+             uint32_t quirks, uint32_t flags,
              bool isEncoder, const char *mime, const char *componentName,
              const sp<MediaSource> &source,
              const sp<ANativeWindow> &nativeWindow);
@@ -287,6 +291,10 @@ private:
     void drainInputBuffers();
     void fillOutputBuffers();
 
+    bool drainAnyInputBuffer();
+    BufferInfo *findInputBufferByDataPointer(void *ptr);
+    BufferInfo *findEmptyInputBuffer();
+
     // Returns true iff a flush was initiated and a completion event is
     // upcoming, false otherwise (A flush was not necessary as we own all
     // the buffers on that port).
@@ -313,7 +321,7 @@ private:
 
     void dumpPortStatus(OMX_U32 portIndex);
 
-    status_t configureCodec(const sp<MetaData> &meta, uint32_t flags);
+    status_t configureCodec(const sp<MetaData> &meta);
 
     static uint32_t getComponentQuirks(
             const char *componentName, bool isEncoder);
index e36b01f..1ac2c1f 100644 (file)
@@ -477,6 +477,15 @@ sp<MediaSource> OMXCodec::Create(
         const char *matchComponentName,
         uint32_t flags,
         const sp<ANativeWindow> &nativeWindow) {
+    int32_t requiresSecureBuffers;
+    if (source->getFormat()->findInt32(
+                kKeyRequiresSecureBuffers,
+                &requiresSecureBuffers)
+            && requiresSecureBuffers) {
+        flags |= kIgnoreCodecSpecificData;
+        flags |= kUseSecureInputBuffers;
+    }
+
     const char *mime;
     bool success = meta->findCString(kKeyMIMEType, &mime);
     CHECK(success);
@@ -530,17 +539,17 @@ sp<MediaSource> OMXCodec::Create(
             LOGV("Successfully allocated OMX node '%s'", componentName);
 
             sp<OMXCodec> codec = new OMXCodec(
-                    omx, node, quirks,
+                    omx, node, quirks, flags,
                     createEncoder, mime, componentName,
                     source, nativeWindow);
 
             observer->setCodec(codec);
 
-            err = codec->configureCodec(meta, flags);
+            err = codec->configureCodec(meta);
 
             if (err == OK) {
                 if (!strcmp("OMX.Nvidia.mpeg2v.decode", componentName)) {
-                    codec->mOnlySubmitOneBufferAtOneTime = true;
+                    codec->mFlags |= kOnlySubmitOneInputBufferAtOneTime;
                 }
 
                 return codec;
@@ -553,24 +562,11 @@ sp<MediaSource> OMXCodec::Create(
     return NULL;
 }
 
-status_t OMXCodec::configureCodec(const sp<MetaData> &meta, uint32_t flags) {
-    mIsMetaDataStoredInVideoBuffers = false;
-    if (flags & kStoreMetaDataInVideoBuffers) {
-        mIsMetaDataStoredInVideoBuffers = true;
-    }
-
-    mOnlySubmitOneBufferAtOneTime = false;
-    if (flags & kOnlySubmitOneInputBufferAtOneTime) {
-        mOnlySubmitOneBufferAtOneTime = true;
-    }
+status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
+    LOGV("configureCodec protected=%d",
+         (mFlags & kEnableGrallocUsageProtected) ? 1 : 0);
 
-    mEnableGrallocUsageProtected = false;
-    if (flags & kEnableGrallocUsageProtected) {
-        mEnableGrallocUsageProtected = true;
-    }
-    LOGV("configureCodec protected=%d", mEnableGrallocUsageProtected);
-
-    if (!(flags & kIgnoreCodecSpecificData)) {
+    if (!(mFlags & kIgnoreCodecSpecificData)) {
         uint32_t type;
         const void *data;
         size_t size;
@@ -745,7 +741,7 @@ status_t OMXCodec::configureCodec(const sp<MetaData> &meta, uint32_t flags) {
 
     initOutputFormat(meta);
 
-    if ((flags & kClientNeedsFramebuffer)
+    if ((mFlags & kClientNeedsFramebuffer)
             && !strncmp(mComponentName, "OMX.SEC.", 8)) {
         OMX_INDEXTYPE index;
 
@@ -1468,7 +1464,8 @@ status_t OMXCodec::setVideoOutputFormat(
 }
 
 OMXCodec::OMXCodec(
-        const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
+        const sp<IOMX> &omx, IOMX::node_id node,
+        uint32_t quirks, uint32_t flags,
         bool isEncoder,
         const char *mime,
         const char *componentName,
@@ -1478,6 +1475,7 @@ OMXCodec::OMXCodec(
       mOMXLivesLocally(omx->livesLocally(getpid())),
       mNode(node),
       mQuirks(quirks),
+      mFlags(flags),
       mIsEncoder(isEncoder),
       mMIME(strdup(mime)),
       mComponentName(strdup(componentName)),
@@ -1645,13 +1643,14 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
         return allocateOutputBuffersFromNativeWindow();
     }
 
-    if (mEnableGrallocUsageProtected && portIndex == kPortIndexOutput) {
+    if ((mFlags & kEnableGrallocUsageProtected) && portIndex == kPortIndexOutput) {
         LOGE("protected output buffers must be stent to an ANativeWindow");
         return PERMISSION_DENIED;
     }
 
     status_t err = OK;
-    if (mIsMetaDataStoredInVideoBuffers && portIndex == kPortIndexInput) {
+    if ((mFlags & kStoreMetaDataInVideoBuffers)
+            && portIndex == kPortIndexInput) {
         err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE);
         if (err != OK) {
             LOGE("Storing meta data in video buffers is not supported");
@@ -1687,7 +1686,8 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
 
         IOMX::buffer_id buffer;
         if (portIndex == kPortIndexInput
-                && (mQuirks & kRequiresAllocateBufferOnInputPorts)) {
+                && ((mQuirks & kRequiresAllocateBufferOnInputPorts)
+                    || (mFlags & kUseSecureInputBuffers))) {
             if (mOMXLivesLocally) {
                 mem.clear();
 
@@ -1748,6 +1748,31 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) {
 
     // dumpPortStatus(portIndex);
 
+    if (portIndex == kPortIndexInput && (mFlags & kUseSecureInputBuffers)) {
+        Vector<MediaBuffer *> buffers;
+        for (size_t i = 0; i < def.nBufferCountActual; ++i) {
+            const BufferInfo &info = mPortBuffers[kPortIndexInput].itemAt(i);
+
+            MediaBuffer *mbuf = new MediaBuffer(info.mData, info.mSize);
+            buffers.push(mbuf);
+        }
+
+        status_t err = mSource->setBuffers(buffers);
+
+        if (err != OK) {
+            for (size_t i = 0; i < def.nBufferCountActual; ++i) {
+                buffers.editItemAt(i)->release();
+            }
+            buffers.clear();
+
+            CODEC_LOGE(
+                    "Codec requested to use secure input buffers but "
+                    "upstream source didn't support that.");
+
+            return err;
+        }
+    }
+
     return OK;
 }
 
@@ -1815,7 +1840,7 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() {
         // XXX: Currently this error is logged, but not fatal.
         usage = 0;
     }
-    if (mEnableGrallocUsageProtected) {
+    if (mFlags & kEnableGrallocUsageProtected) {
         usage |= GRALLOC_USAGE_PROTECTED;
     }
 
@@ -2067,7 +2092,12 @@ void OMXCodec::on_message(const omx_message &msg) {
             } else if (mState != ERROR
                     && mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
                 CHECK_EQ((int)mPortStatus[kPortIndexInput], (int)ENABLED);
-                drainInputBuffer(&buffers->editItemAt(i));
+
+                if (mFlags & kUseSecureInputBuffers) {
+                    drainAnyInputBuffer();
+                } else {
+                    drainInputBuffer(&buffers->editItemAt(i));
+                }
             }
             break;
         }
@@ -2804,32 +2834,81 @@ void OMXCodec::fillOutputBuffers() {
 void OMXCodec::drainInputBuffers() {
     CHECK(mState == EXECUTING || mState == RECONFIGURING);
 
-    Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
-    for (size_t i = 0; i < buffers->size(); ++i) {
-        BufferInfo *info = &buffers->editItemAt(i);
+    if (mFlags & kUseSecureInputBuffers) {
+        Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+        for (size_t i = 0; i < buffers->size(); ++i) {
+            if (!drainAnyInputBuffer()
+                    || (mFlags & kOnlySubmitOneInputBufferAtOneTime)) {
+                break;
+            }
+        }
+    } else {
+        Vector<BufferInfo> *buffers = &mPortBuffers[kPortIndexInput];
+        for (size_t i = 0; i < buffers->size(); ++i) {
+            BufferInfo *info = &buffers->editItemAt(i);
 
-        if (info->mStatus != OWNED_BY_US) {
-            continue;
+            if (info->mStatus != OWNED_BY_US) {
+                continue;
+            }
+
+            if (!drainInputBuffer(info)) {
+                break;
+            }
+
+            if (mFlags & kOnlySubmitOneInputBufferAtOneTime) {
+                break;
+            }
         }
+    }
+}
 
-        if (!drainInputBuffer(info)) {
-            break;
+bool OMXCodec::drainAnyInputBuffer() {
+    return drainInputBuffer((BufferInfo *)NULL);
+}
+
+OMXCodec::BufferInfo *OMXCodec::findInputBufferByDataPointer(void *ptr) {
+    Vector<BufferInfo> *infos = &mPortBuffers[kPortIndexInput];
+    for (size_t i = 0; i < infos->size(); ++i) {
+        BufferInfo *info = &infos->editItemAt(i);
+
+        if (info->mData == ptr) {
+            CODEC_LOGV(
+                    "input buffer data ptr = %p, buffer_id = %p",
+                    ptr,
+                    info->mBuffer);
+
+            return info;
         }
+    }
 
-        if (mOnlySubmitOneBufferAtOneTime) {
-            break;
+    TRESPASS();
+}
+
+OMXCodec::BufferInfo *OMXCodec::findEmptyInputBuffer() {
+    Vector<BufferInfo> *infos = &mPortBuffers[kPortIndexInput];
+    for (size_t i = 0; i < infos->size(); ++i) {
+        BufferInfo *info = &infos->editItemAt(i);
+
+        if (info->mStatus == OWNED_BY_US) {
+            return info;
         }
     }
+
+    TRESPASS();
 }
 
 bool OMXCodec::drainInputBuffer(BufferInfo *info) {
-    CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US);
+    if (info != NULL) {
+        CHECK_EQ((int)info->mStatus, (int)OWNED_BY_US);
+    }
 
     if (mSignalledEOS) {
         return false;
     }
 
     if (mCodecSpecificDataIndex < mCodecSpecificData.size()) {
+        CHECK(!(mFlags & kUseSecureInputBuffers));
+
         const CodecSpecificData *specific =
             mCodecSpecificData[mCodecSpecificDataIndex];
 
@@ -2925,6 +3004,11 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) {
             break;
         }
 
+        if (mFlags & kUseSecureInputBuffers) {
+            info = findInputBufferByDataPointer(srcBuffer->data());
+            CHECK(info != NULL);
+        }
+
         size_t remainingBytes = info->mSize - offset;
 
         if (srcBuffer->range_length() > remainingBytes) {
@@ -2960,14 +3044,24 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) {
             releaseBuffer = false;
             info->mMediaBuffer = srcBuffer;
         } else {
-            if (mIsMetaDataStoredInVideoBuffers) {
+            if (mFlags & kStoreMetaDataInVideoBuffers) {
                 releaseBuffer = false;
                 info->mMediaBuffer = srcBuffer;
             }
-            memcpy((uint8_t *)info->mData + offset,
-                    (const uint8_t *)srcBuffer->data()
-                        + srcBuffer->range_offset(),
-                    srcBuffer->range_length());
+
+            if (mFlags & kUseSecureInputBuffers) {
+                // Data in "info" is already provided at this time.
+
+                releaseBuffer = false;
+
+                CHECK(info->mMediaBuffer == NULL);
+                info->mMediaBuffer = srcBuffer;
+            } else {
+                memcpy((uint8_t *)info->mData + offset,
+                        (const uint8_t *)srcBuffer->data()
+                            + srcBuffer->range_offset(),
+                        srcBuffer->range_length());
+            }
         }
 
         int64_t lastBufferTimeUs;
@@ -3036,6 +3130,16 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) {
                info->mBuffer, offset,
                timestampUs, timestampUs / 1E6);
 
+    if (info == NULL) {
+        CHECK(mFlags & kUseSecureInputBuffers);
+        CHECK(signalEOS);
+
+        // This is fishy, there's still a MediaBuffer corresponding to this
+        // info available to the source at this point even though we're going
+        // to use it to signal EOS to the codec.
+        info = findEmptyInputBuffer();
+    }
+
     err = mOMX->emptyBuffer(
             mNode, info->mBuffer, 0, offset,
             flags, timestampUs);