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

Commit 58a36ada authored by Jamie Gennis's avatar Jamie Gennis
Browse files

Add decode-to-ANativeWindow support to Stagefright.

This change adds support to Stagefright for doing OMX video decoding directly
into buffers dequeued from an ANativeWindow.  It does this by registering the
dequeued buffers with the OMX component using an Android-specific OMX
extension, and then exchanging buffers between the OMX component and the
ANativeWindow.

Change-Id: Ida66f836503255a68d378c6903d96dfe9747ce87
parent 9532677a
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@

namespace android {

class GraphicBuffer;
class MediaBuffer;
class MediaBufferObserver;
class MetaData;
@@ -48,6 +49,8 @@ public:

    MediaBuffer(size_t size);

    MediaBuffer(const sp<GraphicBuffer>& graphicBuffer);

    // Decrements the reference count and returns the buffer to its
    // associated MediaBufferGroup if the reference count drops to 0.
    void release();
@@ -63,6 +66,8 @@ public:

    void set_range(size_t offset, size_t length);

    sp<GraphicBuffer> graphicBuffer() const;

    sp<MetaData> meta_data();

    // Clears meta data and resets the range to the full extent.
@@ -94,6 +99,7 @@ private:

    void *mData;
    size_t mSize, mRangeOffset, mRangeLength;
    sp<GraphicBuffer> mGraphicBuffer;

    bool mOwnsData;

+3 −0
Original line number Diff line number Diff line
@@ -99,6 +99,9 @@ enum {
    kKeyValidSamples      = 'valD',  // int32_t

    kKeyIsUnreadable      = 'unre',  // bool (int32_t)

    // An indication that a video buffer has been rendered.
    kKeyRendered          = 'rend',  // bool (int32_t)
};

enum {
+19 −2
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@

#define OMX_CODEC_H_

#include <android/native_window.h>
#include <media/IOMX.h>
#include <media/stagefright/MediaBuffer.h>
#include <media/stagefright/MediaSource.h>
@@ -44,7 +45,8 @@ struct OMXCodec : public MediaSource,
            const sp<MetaData> &meta, bool createEncoder,
            const sp<MediaSource> &source,
            const char *matchComponentName = NULL,
            uint32_t flags = 0);
            uint32_t flags = 0,
            const sp<ANativeWindow> &nativeWindow = NULL);

    static void setComponentRole(
            const sp<IOMX> &omx, IOMX::node_id node, bool isEncoder,
@@ -114,6 +116,7 @@ private:
    struct BufferInfo {
        IOMX::buffer_id mBuffer;
        bool mOwnedByComponent;
        bool mOwnedByNativeWindow;
        sp<IMemory> mMem;
        size_t mSize;
        void *mData;
@@ -159,13 +162,21 @@ private:

    bool mPaused;

    sp<ANativeWindow> mNativeWindow;

    // The index in each of the mPortBuffers arrays of the buffer that will be
    // submitted to OMX next.  This only applies when using buffers from a
    // native window.
    size_t mNextNativeBufferIndex[2];

    // A list of indices into mPortStatus[kPortIndexOutput] filled with data.
    List<size_t> mFilledBuffers;
    Condition mBufferFilled;

    OMXCodec(const sp<IOMX> &omx, IOMX::node_id node, uint32_t quirks,
             bool isEncoder, const char *mime, const char *componentName,
             const sp<MediaSource> &source);
             const sp<MediaSource> &source,
             const sp<ANativeWindow> &nativeWindow);

    void addCodecSpecificData(const void *data, size_t size);
    void clearCodecSpecificData();
@@ -216,6 +227,11 @@ private:

    status_t allocateBuffers();
    status_t allocateBuffersOnPort(OMX_U32 portIndex);
    status_t allocateOutputBuffersFromNativeWindow();

    status_t queueBufferToNativeWindow(BufferInfo *info);
    status_t cancelBufferToNativeWindow(BufferInfo *info);
    BufferInfo* dequeueBufferFromNativeWindow();

    status_t freeBuffersOnPort(
            OMX_U32 portIndex, bool onlyThoseWeOwn = false);
@@ -250,6 +266,7 @@ private:

    status_t init();
    void initOutputFormat(const sp<MetaData> &inputFormat);
    status_t initNativeWindow();

    void dumpPortStatus(OMX_U32 portIndex);

+49 −12
Original line number Diff line number Diff line
@@ -194,6 +194,35 @@ void AwesomeLocalRenderer::init(
    }
}

struct AwesomeNativeWindowRenderer : public AwesomeRenderer {
    AwesomeNativeWindowRenderer(const sp<ANativeWindow> &nativeWindow)
        : mNativeWindow(nativeWindow) {
    }

    virtual void render(MediaBuffer *buffer) {
        status_t err = mNativeWindow->queueBuffer(
                mNativeWindow.get(), buffer->graphicBuffer().get());
        if (err != 0) {
            LOGE("queueBuffer failed with error %s (%d)", strerror(-err),
                    -err);
            return;
        }

        sp<MetaData> metaData = buffer->meta_data();
        metaData->setInt32(kKeyRendered, 1);
    }

protected:
    virtual ~AwesomeNativeWindowRenderer() {}

private:
    sp<ANativeWindow> mNativeWindow;

    AwesomeNativeWindowRenderer(const AwesomeNativeWindowRenderer &);
    AwesomeNativeWindowRenderer &operator=(
            const AwesomeNativeWindowRenderer &);
};

AwesomePlayer::AwesomePlayer()
    : mQueueStarted(false),
      mTimeSource(NULL),
@@ -805,8 +834,16 @@ void AwesomePlayer::initRenderer_l() {
        IPCThreadState::self()->flushCommands();

        if (mSurface != NULL) {
            if (strncmp(component, "OMX.", 4) == 0) {
                // Hardware decoders avoid the CPU color conversion by decoding
                // directly to ANativeBuffers, so we must use a renderer that
                // just pushes those buffers to the ANativeWindow.
                mVideoRenderer = new AwesomeNativeWindowRenderer(mSurface);
            } else {
                // Other decoders are instantiated locally and as a consequence
            // allocate their buffers in local address space.
                // allocate their buffers in local address space.  This renderer
                // then performs a color conversion and copy to get the data
                // into the ANativeBuffer.
                mVideoRenderer = new AwesomeLocalRenderer(
                    false,  // previewOnly
                    component,
@@ -815,6 +852,7 @@ void AwesomePlayer::initRenderer_l() {
                    mSurface,
                    mVideoWidth, mVideoHeight,
                    decodedWidth, decodedHeight);
            }
        } else {
            // Our OMX codecs allocate buffers on the media_server side
            // therefore they require a remote IOMXRenderer that knows how
@@ -1054,7 +1092,7 @@ status_t AwesomePlayer::initVideoDecoder(uint32_t flags) {
            mClient.interface(), mVideoTrack->getFormat(),
            false, // createEncoder
            mVideoTrack,
            NULL, flags);
            NULL, flags, mSurface);

    if (mVideoSource != NULL) {
        int64_t durationUs;
@@ -1811,4 +1849,3 @@ void AwesomePlayer::postAudioSeekComplete() {
}

}  // namespace android
+26 −3
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MetaData.h>

#include <ui/GraphicBuffer.h>

namespace android {

// XXX make this truly atomic.
@@ -61,6 +63,20 @@ MediaBuffer::MediaBuffer(size_t size)
      mOriginal(NULL) {
}

MediaBuffer::MediaBuffer(const sp<GraphicBuffer>& graphicBuffer)
    : mObserver(NULL),
      mNextBuffer(NULL),
      mRefCount(0),
      mData(NULL),
      mSize(1),
      mRangeOffset(0),
      mRangeLength(mSize),
      mGraphicBuffer(graphicBuffer),
      mOwnsData(false),
      mMetaData(new MetaData),
      mOriginal(NULL) {
}

void MediaBuffer::release() {
    if (mObserver == NULL) {
        CHECK_EQ(mRefCount, 0);
@@ -92,10 +108,12 @@ void MediaBuffer::add_ref() {
}

void *MediaBuffer::data() const {
    CHECK(mGraphicBuffer == NULL);
    return mData;
}

size_t MediaBuffer::size() const {
    CHECK(mGraphicBuffer == NULL);
    return mSize;
}

@@ -108,15 +126,19 @@ size_t MediaBuffer::range_length() const {
}

void MediaBuffer::set_range(size_t offset, size_t length) {
    if (offset + length > mSize) {
    if ((mGraphicBuffer == NULL) && (offset + length > mSize)) {
        LOGE("offset = %d, length = %d, mSize = %d", offset, length, mSize);
    }
    CHECK(offset + length <= mSize);
    CHECK((mGraphicBuffer != NULL) || (offset + length <= mSize));

    mRangeOffset = offset;
    mRangeLength = length;
}

sp<GraphicBuffer> MediaBuffer::graphicBuffer() const {
    return mGraphicBuffer;
}

sp<MetaData> MediaBuffer::meta_data() {
    return mMetaData;
}
@@ -158,6 +180,8 @@ int MediaBuffer::refcount() const {
}

MediaBuffer *MediaBuffer::clone() {
    CHECK_EQ(mGraphicBuffer, NULL);

    MediaBuffer *buffer = new MediaBuffer(mData, mSize);
    buffer->set_range(mRangeOffset, mRangeLength);
    buffer->mMetaData = new MetaData(*mMetaData.get());
@@ -169,4 +193,3 @@ MediaBuffer *MediaBuffer::clone() {
}

}  // namespace android
Loading