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

Commit 2d531e1b authored by Mathias Agopian's avatar Mathias Agopian Committed by Android (Google) Code Review
Browse files

Merge "Refactored SurfaceMediaSource"

parents d2469c3f bdddc659
Loading
Loading
Loading
Loading
+55 −200
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#define ANDROID_GUI_SURFACEMEDIASOURCE_H

#include <gui/ISurfaceTexture.h>
#include <gui/BufferQueue.h>

#include <utils/threads.h>
#include <utils/Vector.h>
@@ -31,16 +32,31 @@ class IGraphicBufferAlloc;
class String8;
class GraphicBuffer;

class SurfaceMediaSource : public BnSurfaceTexture, public MediaSource,
                                            public MediaBufferObserver {
// ASSUMPTIONS
// 1. SurfaceMediaSource is initialized with width*height which
// can never change.  However, deqeueue buffer does not currently
// enforce this as in BufferQueue, dequeue can be used by SurfaceTexture
// which can modify the default width and heght.  Also neither the width
// nor height can be 0.
// 2. setSynchronousMode is never used (basically no one should call
// setSynchronousMode(false)
// 3. setCrop, setTransform, setScalingMode should never be used
// 4. queueBuffer returns a filled buffer to the SurfaceMediaSource. In addition, a
// timestamp must be provided for the buffer. The timestamp is in
// nanoseconds, and must be monotonically increasing. Its other semantics
// (zero point, etc) are client-dependent and should be documented by the
// client.
// 5. Once disconnected, SurfaceMediaSource can be reused (can not
// connect again)
// 6. Stop is a hard stop, the last few frames held by the encoder
// may be dropped.  It is possible to wait for the buffers to be
// returned (but not implemented)

class SurfaceMediaSource : public MediaSource,
                                public MediaBufferObserver,
                                protected BufferQueue::ConsumerListener {
public:
    enum { MIN_UNDEQUEUED_BUFFERS = 4};
    enum {
        MIN_ASYNC_BUFFER_SLOTS = MIN_UNDEQUEUED_BUFFERS + 1,
        MIN_SYNC_BUFFER_SLOTS  = MIN_UNDEQUEUED_BUFFERS
    };
    enum { NUM_BUFFER_SLOTS = 32 };
    enum { NO_CONNECTED_API = 0 };

    struct FrameAvailableListener : public virtual RefBase {
        // onFrameAvailable() is called from queueBuffer() is the FIFO is
@@ -51,13 +67,13 @@ public:
        virtual void onFrameAvailable() = 0;
    };

    SurfaceMediaSource(uint32_t bufW, uint32_t bufH);
    SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeight);

    virtual ~SurfaceMediaSource();


    // For the MediaSource interface for use by StageFrightRecorder:
    virtual status_t start(MetaData *params = NULL);

    virtual status_t stop() { return reset(); }
    virtual status_t read(
            MediaBuffer **buffer, const ReadOptions *options = NULL);
@@ -77,81 +93,6 @@ public:
    virtual void signalBufferReturned(MediaBuffer* buffer);
    // end of MediaSource interface

    uint32_t getBufferCount( ) const { return mBufferCount;}


    // setBufferCount updates the number of available buffer slots.  After
    // calling this all buffer slots are both unallocated and owned by the
    // SurfaceMediaSource object (i.e. they are not owned by the client).
    virtual status_t setBufferCount(int bufferCount);

    virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);

    // dequeueBuffer gets the next buffer slot index for the client to use. If a
    // buffer slot is available then that slot index is written to the location
    // pointed to by the buf argument and a status of OK is returned.  If no
    // slot is available then a status of -EBUSY is returned and buf is
    // unmodified.
    virtual status_t dequeueBuffer(int *buf, uint32_t w, uint32_t h,
            uint32_t format, uint32_t usage);

    // queueBuffer returns a filled buffer to the SurfaceMediaSource. In addition, a
    // timestamp must be provided for the buffer. The timestamp is in
    // nanoseconds, and must be monotonically increasing. Its other semantics
    // (zero point, etc) are client-dependent and should be documented by the
    // client.
    virtual status_t queueBuffer(int buf, int64_t timestamp,
            const Rect& crop, int scalingMode, uint32_t transform,
            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);
    virtual void cancelBuffer(int buf);

    // onFrameReceivedLocked informs the buffer consumers (StageFrightRecorder)
    // or listeners that a frame has been received
    // The buffer is not made available for dequeueing immediately. We need to
    // wait to hear from StageFrightRecorder to set the buffer FREE
    // Make sure this is called when the mutex is locked
    virtual status_t onFrameReceivedLocked();

    virtual int query(int what, int* value);

    // setSynchronousMode set whether dequeueBuffer is synchronous or
    // asynchronous. In synchronous mode, dequeueBuffer blocks until
    // a buffer is available, the currently bound buffer can be dequeued and
    // queued buffers will be retired in order.
    // The default mode is synchronous.
    // TODO: Clarify the minute differences bet sycn /async
    // modes (S.Encoder vis-a-vis SurfaceTexture)
    virtual status_t setSynchronousMode(bool enabled);

    // connect attempts to connect a client API to the SurfaceMediaSource.  This
    // must be called before any other ISurfaceTexture methods are called except
    // for getAllocator.
    //
    // This method will fail if the connect was previously called on the
    // SurfaceMediaSource and no corresponding disconnect call was made.
    virtual status_t connect(int api,
            uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform);

    // disconnect attempts to disconnect a client API from the SurfaceMediaSource.
    // Calling this method will cause any subsequent calls to other
    // ISurfaceTexture methods to fail except for getAllocator and connect.
    // Successfully calling connect after this will allow the other methods to
    // succeed again.
    //
    // This method will fail if the the SurfaceMediaSource is not currently
    // connected to the specified client API.
    virtual status_t disconnect(int api);

    // getqueuedCount returns the number of queued frames waiting in the
    // FIFO. In asynchronous mode, this always returns 0 or 1 since
    // frames are not accumulating in the FIFO.
    size_t getQueuedCount() const;

    // setBufferCountServer set the buffer count. If the client has requested
    // a buffer count using setBufferCount, the server-buffer count will
    // take effect once the client sets the count back to zero.
    status_t setBufferCountServer(int bufferCount);

    // getTimestamp retrieves the timestamp associated with the image
    // set by the most recent call to read()
    //
@@ -176,105 +117,42 @@ public:
    // pass metadata through the buffers. Currently, it is force set to true
    bool isMetaDataStoredInVideoBuffers() const;

    sp<BufferQueue> getBufferQueue() const { return mBufferQueue; }

protected:

    // freeAllBuffersLocked frees the resources (both GraphicBuffer and EGLImage) for
    // all slots.
    void freeAllBuffersLocked();
    // Implementation of the BufferQueue::ConsumerListener interface.  These
    // calls are used to notify the SurfaceTexture of asynchronous events in the
    // BufferQueue.
    virtual void onFrameAvailable();

    // Used as a hook to BufferQueue::disconnect()
    // This is called by the client side when it is done
    // TODO: Currently, this also sets mStopped to true which
    // is needed for unblocking the encoder which might be
    // waiting to read more frames. So if on the client side,
    // the same thread supplies the frames and also calls stop
    // on the encoder, the client has to call disconnect before
    // it calls stop.
    // In the case of the camera,
    // that need not be required since the thread supplying the
    // frames is separate than the one calling stop.
    virtual void onBuffersReleased();

    static bool isExternalFormat(uint32_t format);

private:
    // mBufferQueue is the exchange point between the producer and
    // this consumer
    sp<BufferQueue> mBufferQueue;

    status_t setBufferCountServerLocked(int bufferCount);

    enum { INVALID_BUFFER_SLOT = -1 };
    // mBufferSlot caches GraphicBuffers from the buffer queue
    sp<GraphicBuffer> mBufferSlot[BufferQueue::NUM_BUFFER_SLOTS];

    struct BufferSlot {

        BufferSlot()
            : mBufferState(BufferSlot::FREE),
              mRequestBufferCalled(false),
              mTimestamp(0) {
        }

        // mGraphicBuffer points to the buffer allocated for this slot or is
        // NULL if no buffer has been allocated.
        sp<GraphicBuffer> mGraphicBuffer;

        // BufferState represents the different states in which a buffer slot
        // can be.
        enum BufferState {
            // FREE indicates that the buffer is not currently being used and
            // will not be used in the future until it gets dequeued and
            // subseqently queued by the client.
            FREE = 0,

            // DEQUEUED indicates that the buffer has been dequeued by the
            // client, but has not yet been queued or canceled. The buffer is
            // considered 'owned' by the client, and the server should not use
            // it for anything.
            //
            // Note that when in synchronous-mode (mSynchronousMode == true),
            // the buffer that's currently attached to the texture may be
            // dequeued by the client.  That means that the current buffer can
            // be in either the DEQUEUED or QUEUED state.  In asynchronous mode,
            // however, the current buffer is always in the QUEUED state.
            DEQUEUED = 1,

            // QUEUED indicates that the buffer has been queued by the client,
            // and has not since been made available for the client to dequeue.
            // Attaching the buffer to the texture does NOT transition the
            // buffer away from the QUEUED state. However, in Synchronous mode
            // the current buffer may be dequeued by the client under some
            // circumstances. See the note about the current buffer in the
            // documentation for DEQUEUED.
            QUEUED = 2,
        };

        // mBufferState is the current state of this buffer slot.
        BufferState mBufferState;

        // mRequestBufferCalled is used for validating that the client did
        // call requestBuffer() when told to do so. Technically this is not
        // needed but useful for debugging and catching client bugs.
        bool mRequestBufferCalled;

        // mTimestamp is the current timestamp for this buffer slot. This gets
        // to set by queueBuffer each time this slot is queued.
        int64_t mTimestamp;
    };

    // mSlots is the array of buffer slots that must be mirrored on the client
    // side. This allows buffer ownership to be transferred between the client
    // and server without sending a GraphicBuffer over binder. The entire array
    // is initialized to NULL at construction time, and buffers are allocated
    // for a slot when requestBuffer is called with that slot's index.
    BufferSlot mSlots[NUM_BUFFER_SLOTS];

    // mDefaultWidth holds the default width of allocated buffers. It is used
    // in requestBuffers() if a width and height of zero is specified.
    uint32_t mDefaultWidth;

    // mDefaultHeight holds the default height of allocated buffers. It is used
    // in requestBuffers() if a width and height of zero is specified.
    uint32_t mDefaultHeight;

    // mPixelFormat holds the pixel format of allocated buffers. It is used
    // in requestBuffers() if a format of zero is specified.
    uint32_t mPixelFormat;

    // mBufferCount is the number of buffer slots that the client and server
    // must maintain. It defaults to MIN_ASYNC_BUFFER_SLOTS and can be changed
    // by calling setBufferCount or setBufferCountServer
    int mBufferCount;

    // mClientBufferCount is the number of buffer slots requested by the
    // client. The default is zero, which means the client doesn't care how
    // many buffers there are
    int mClientBufferCount;

    // mServerBufferCount buffer count requested by the server-side
    int mServerBufferCount;
    // The permenent width and height of SMS buffers
    int mWidth;
    int mHeight;

    // mCurrentSlot is the buffer slot index of the buffer that is currently
    // being used by buffer consumer
@@ -287,43 +165,21 @@ private:
    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
    int mCurrentSlot;


    // mCurrentBuf is the graphic buffer of the current slot to be used by
    // buffer consumer. It's possible that this buffer is not associated
    // with any buffer slot, so we must track it separately in order to
    // properly use IGraphicBufferAlloc::freeAllGraphicBuffersExcept.
    sp<GraphicBuffer> mCurrentBuf;


    // mCurrentTimestamp is the timestamp for the current texture. It
    // gets set to mLastQueuedTimestamp each time updateTexImage is called.
    int64_t mCurrentTimestamp;

    // mGraphicBufferAlloc is the connection to SurfaceFlinger that is used to
    // allocate new GraphicBuffer objects.
    sp<IGraphicBufferAlloc> mGraphicBufferAlloc;

    // mFrameAvailableListener is the listener object that will be called when a
    // new frame becomes available. If it is not NULL it will be called from
    // queueBuffer.
    sp<FrameAvailableListener> mFrameAvailableListener;

    // mSynchronousMode whether we're in synchronous mode or not
    bool mSynchronousMode;

    // mConnectedApi indicates the API that is currently connected to this
    // SurfaceTexture.  It defaults to NO_CONNECTED_API (= 0), and gets updated
    // by the connect and disconnect methods.
    int mConnectedApi;

    // mDequeueCondition condition used for dequeueBuffer in synchronous mode
    mutable Condition mDequeueCondition;


    // mQueue is a FIFO of queued buffers used in synchronous mode
    typedef Vector<int> Fifo;
    Fifo mQueue;

    // mMutex is the mutex used to prevent concurrent access to the member
    // variables of SurfaceMediaSource objects. It must be locked whenever the
    // member variables are accessed.
@@ -353,7 +209,6 @@ private:
    // mFrameAvailableCondition condition used to indicate whether there
    // is a frame available for dequeuing
    Condition mFrameAvailableCondition;
    Condition mFrameCompleteCondition;

    status_t reset();

+1 −1
Original line number Diff line number Diff line
@@ -90,7 +90,7 @@ status_t StagefrightRecorder::init() {
// while encoding GL Frames
sp<ISurfaceTexture> StagefrightRecorder::querySurfaceMediaSource() const {
    ALOGV("Get SurfaceMediaSource");
    return mSurfaceMediaSource;
    return mSurfaceMediaSource->getBufferQueue();
}

status_t StagefrightRecorder::setAudioSource(audio_source_t as) {
+138 −634

File changed.

Preview size limit exceeded, changes collapsed.

+13 −10
Original line number Diff line number Diff line
@@ -107,8 +107,8 @@ protected:
                    window.get(), NULL);
        } else {
            ALOGV("No actual display. Choosing EGLSurface based on SurfaceMediaSource");
            sp<ISurfaceTexture> sms = new SurfaceMediaSource(
                    getSurfaceWidth(), getSurfaceHeight());
            sp<ISurfaceTexture> sms = (new SurfaceMediaSource(
                    getSurfaceWidth(), getSurfaceHeight()))->getBufferQueue();
            sp<SurfaceTextureClient> stc = new SurfaceTextureClient(sms);
            sp<ANativeWindow> window = stc;

@@ -359,9 +359,9 @@ protected:
    virtual void SetUp() {
        android::ProcessState::self()->startThreadPool();
        mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
        mSMS->setSynchronousMode(true);

        // Manual cast is required to avoid constructor ambiguity
        mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS));
        mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS->getBufferQueue()));
        mANW = mSTC;
    }

@@ -396,7 +396,7 @@ protected:
        ALOGV("SMS-GLTest::SetUp()");
        android::ProcessState::self()->startThreadPool();
        mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
        mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS));
        mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS->getBufferQueue()));
        mANW = mSTC;

        // Doing the setup related to the GL Side
@@ -675,7 +675,7 @@ TEST_F(SurfaceMediaSourceTest, DISABLED_DummyEncodingFromCpuFilledYV12BufferNpo

// Delayed pass of multiple buffers from the native_window the SurfaceMediaSource
// Dummy Encoder
TEST_F(SurfaceMediaSourceTest,  DISABLED_DummyLagEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
TEST_F(SurfaceMediaSourceTest,  DummyLagEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
    ALOGV("Test # %d", testId++);
    ALOGV("Testing MultiBufferPass, Dummy Recorder Lagging **************");

@@ -686,8 +686,10 @@ TEST_F(SurfaceMediaSourceTest, DISABLED_DummyLagEncodingFromCpuFilledYV12Buffer
    writer.start();

    int32_t nFramesCount = 1;
    const int FRAMES_LAG = mSMS->getBufferCount() - 1;
    const int FRAMES_LAG = SurfaceMediaSource::MIN_UNDEQUEUED_BUFFERS;

    while (nFramesCount <= 300) {
        ALOGV("Frame: %d", nFramesCount);
        oneBufferPass(mYuvTexWidth, mYuvTexHeight);
        // Forcing the writer to lag behind a few frames
        if (nFramesCount > FRAMES_LAG) {
@@ -700,7 +702,7 @@ TEST_F(SurfaceMediaSourceTest, DISABLED_DummyLagEncodingFromCpuFilledYV12Buffer

// pass multiple buffers from the native_window the SurfaceMediaSource
// A dummy writer (MULTITHREADED) is used to simulate actual MPEG4Writer
TEST_F(SurfaceMediaSourceTest, DISABLED_DummyThreadedEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
TEST_F(SurfaceMediaSourceTest, DummyThreadedEncodingFromCpuFilledYV12BufferNpotMultiBufferPass) {
    ALOGV("Test # %d", testId++);
    ALOGV("Testing MultiBufferPass, Dummy Recorder Multi-Threaded **********");
    ASSERT_EQ(NO_ERROR, native_window_set_buffers_format(mANW.get(),
@@ -711,6 +713,7 @@ TEST_F(SurfaceMediaSourceTest, DISABLED_DummyThreadedEncodingFromCpuFilledYV12Bu

    int32_t nFramesCount = 0;
    while (nFramesCount <= 300) {
        ALOGV("Frame: %d", nFramesCount);
        oneBufferPass(mYuvTexWidth, mYuvTexHeight);

        nFramesCount++;
@@ -774,7 +777,7 @@ TEST_F(SurfaceMediaSourceGLTest, ChooseAndroidRecordableEGLConfigDummyWriter) {
    ALOGV("Verify creating a surface w/ right config + dummy writer*********");

    mSMS = new SurfaceMediaSource(mYuvTexWidth, mYuvTexHeight);
    mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS));
    mSTC = new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >( mSMS->getBufferQueue()));
    mANW = mSTC;

    DummyRecorder writer(mSMS);