Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 577dd43e authored by Andreas Huber's avatar Andreas Huber Committed by Android (Google) Code Review
Browse files

Merge "Support a "secure input buffer" mode for use by Widevine DRM in OMXCodec."

parents 3edf4509 0bb6b4c5
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -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();

+2 −0
Original line number Diff line number Diff line
@@ -121,6 +121,8 @@ enum {

    // To store the timed text format data
    kKeyTextFormatData    = 'text',  // raw data

    kKeyRequiresSecureBuffers = 'secu',  // bool (int32_t)
};

enum {
+14 −6
Original line number Diff line number Diff line
@@ -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);
+146 −42
Original line number Diff line number Diff line
@@ -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;
    }

    mEnableGrallocUsageProtected = false;
    if (flags & kEnableGrallocUsageProtected) {
        mEnableGrallocUsageProtected = true;
    }
    LOGV("configureCodec protected=%d", mEnableGrallocUsageProtected);
status_t OMXCodec::configureCodec(const sp<MetaData> &meta) {
    LOGV("configureCodec protected=%d",
         (mFlags & kEnableGrallocUsageProtected) ? 1 : 0);

    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,8 +2092,13 @@ void OMXCodec::on_message(const omx_message &msg) {
            } else if (mState != ERROR
                    && mPortStatus[kPortIndexInput] != SHUTTING_DOWN) {
                CHECK_EQ((int)mPortStatus[kPortIndexInput], (int)ENABLED);

                if (mFlags & kUseSecureInputBuffers) {
                    drainAnyInputBuffer();
                } else {
                    drainInputBuffer(&buffers->editItemAt(i));
                }
            }
            break;
        }

@@ -2804,6 +2834,15 @@ void OMXCodec::fillOutputBuffers() {
void OMXCodec::drainInputBuffers() {
    CHECK(mState == EXECUTING || mState == RECONFIGURING);

    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);
@@ -2816,20 +2855,60 @@ void OMXCodec::drainInputBuffers() {
                break;
            }

        if (mOnlySubmitOneBufferAtOneTime) {
            if (mFlags & kOnlySubmitOneInputBufferAtOneTime) {
                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;
        }
    }

    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) {
    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,15 +3044,25 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) {
            releaseBuffer = false;
            info->mMediaBuffer = srcBuffer;
        } else {
            if (mIsMetaDataStoredInVideoBuffers) {
            if (mFlags & kStoreMetaDataInVideoBuffers) {
                releaseBuffer = false;
                info->mMediaBuffer = srcBuffer;
            }

            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;
        CHECK(srcBuffer->meta_data()->findInt64(kKeyTime, &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);