diff options
-rw-r--r-- | include/media/stagefright/SurfaceMediaSource.h | 255 | ||||
-rw-r--r-- | media/libmediaplayerservice/StagefrightRecorder.cpp | 2 | ||||
-rw-r--r-- | media/libstagefright/SurfaceMediaSource.cpp | 772 | ||||
-rw-r--r-- | media/libstagefright/tests/SurfaceMediaSource_test.cpp | 23 |
4 files changed, 207 insertions, 845 deletions
diff --git a/include/media/stagefright/SurfaceMediaSource.h b/include/media/stagefright/SurfaceMediaSource.h index c0dc074..e25d444 100644 --- a/include/media/stagefright/SurfaceMediaSource.h +++ b/include/media/stagefright/SurfaceMediaSource.h @@ -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 }; + enum { MIN_UNDEQUEUED_BUFFERS = 4}; 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 }; - - 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]; + // mBufferSlot caches GraphicBuffers from the buffer queue + sp<GraphicBuffer> mBufferSlot[BufferQueue::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(); diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp index ca79657..2c5644f 100644 --- a/media/libmediaplayerservice/StagefrightRecorder.cpp +++ b/media/libmediaplayerservice/StagefrightRecorder.cpp @@ -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) { diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp index 1345cd9..efc71a8 100644 --- a/media/libstagefright/SurfaceMediaSource.cpp +++ b/media/libstagefright/SurfaceMediaSource.cpp @@ -35,545 +35,50 @@ namespace android { -SurfaceMediaSource::SurfaceMediaSource(uint32_t bufW, uint32_t bufH) : - mDefaultWidth(bufW), - mDefaultHeight(bufH), - mPixelFormat(0), - mBufferCount(MIN_ASYNC_BUFFER_SLOTS), - mClientBufferCount(0), - mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS), - mCurrentSlot(INVALID_BUFFER_SLOT), - mCurrentTimestamp(0), - mSynchronousMode(true), - mConnectedApi(NO_CONNECTED_API), - mFrameRate(30), - mStopped(false), - mNumFramesReceived(0), - mNumFramesEncoded(0), - mFirstFrameTimestamp(0) { +SurfaceMediaSource::SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeight) : + mWidth(bufferWidth), + mHeight(bufferHeight), + mCurrentSlot(BufferQueue::INVALID_BUFFER_SLOT), + mCurrentTimestamp(0), + mFrameRate(30), + mStopped(false), + mNumFramesReceived(0), + mNumFramesEncoded(0), + mFirstFrameTimestamp(0) +{ ALOGV("SurfaceMediaSource::SurfaceMediaSource"); - sp<ISurfaceComposer> composer(ComposerService::getComposerService()); - mGraphicBufferAlloc = composer->createGraphicBufferAlloc(); - if (mGraphicBufferAlloc == 0) { - ALOGE("createGraphicBufferAlloc() failed in SurfaceMediaSource()"); - } -} -SurfaceMediaSource::~SurfaceMediaSource() { - ALOGV("SurfaceMediaSource::~SurfaceMediaSource"); - if (!mStopped) { - reset(); + if (bufferWidth == 0 || bufferHeight == 0) { + ALOGE("Invalid dimensions %dx%d", bufferWidth, bufferHeight); } -} - -size_t SurfaceMediaSource::getQueuedCount() const { - Mutex::Autolock lock(mMutex); - return mQueue.size(); -} - -status_t SurfaceMediaSource::setBufferCountServerLocked(int bufferCount) { - if (bufferCount > NUM_BUFFER_SLOTS) - return BAD_VALUE; - // special-case, nothing to do - if (bufferCount == mBufferCount) - return OK; - - if (!mClientBufferCount && - bufferCount >= mBufferCount) { - // easy, we just have more buffers - mBufferCount = bufferCount; - mServerBufferCount = bufferCount; - mDequeueCondition.signal(); - } else { - // we're here because we're either - // - reducing the number of available buffers - // - or there is a client-buffer-count in effect - - // less than 2 buffers is never allowed - if (bufferCount < 2) - return BAD_VALUE; - - // when there is non client-buffer-count in effect, the client is not - // allowed to dequeue more than one buffer at a time, - // so the next time they dequeue a buffer, we know that they don't - // own one. the actual resizing will happen during the next - // dequeueBuffer. - - mServerBufferCount = bufferCount; - } - return OK; -} - -// Called from the consumer side -status_t SurfaceMediaSource::setBufferCountServer(int bufferCount) { - Mutex::Autolock lock(mMutex); - return setBufferCountServerLocked(bufferCount); -} - -status_t SurfaceMediaSource::setBufferCount(int bufferCount) { - ALOGV("SurfaceMediaSource::setBufferCount"); - if (bufferCount > NUM_BUFFER_SLOTS) { - ALOGE("setBufferCount: bufferCount is larger than the number of buffer slots"); - return BAD_VALUE; - } - - Mutex::Autolock lock(mMutex); - // Error out if the user has dequeued buffers - for (int i = 0 ; i < mBufferCount ; i++) { - if (mSlots[i].mBufferState == BufferSlot::DEQUEUED) { - ALOGE("setBufferCount: client owns some buffers"); - return INVALID_OPERATION; - } - } + mBufferQueue = new BufferQueue(true, MIN_UNDEQUEUED_BUFFERS); + mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight); + mBufferQueue->setSynchronousMode(true); - if (bufferCount == 0) { - const int minBufferSlots = mSynchronousMode ? - MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; - mClientBufferCount = 0; - bufferCount = (mServerBufferCount >= minBufferSlots) ? - mServerBufferCount : minBufferSlots; - return setBufferCountServerLocked(bufferCount); - } - - // We don't allow the client to set a buffer-count less than - // MIN_ASYNC_BUFFER_SLOTS (3), there is no reason for it. - if (bufferCount < MIN_ASYNC_BUFFER_SLOTS) { - return BAD_VALUE; - } - - // here we're guaranteed that the client doesn't have dequeued buffers - // and will release all of its buffer references. - mBufferCount = bufferCount; - mClientBufferCount = bufferCount; - mCurrentSlot = INVALID_BUFFER_SLOT; - mQueue.clear(); - mDequeueCondition.signal(); - freeAllBuffersLocked(); - return OK; -} - -status_t SurfaceMediaSource::requestBuffer(int slot, sp<GraphicBuffer>* buf) { - ALOGV("SurfaceMediaSource::requestBuffer"); - Mutex::Autolock lock(mMutex); - if (slot < 0 || mBufferCount <= slot) { - ALOGE("requestBuffer: slot index out of range [0, %d]: %d", - mBufferCount, slot); - return BAD_VALUE; - } - mSlots[slot].mRequestBufferCalled = true; - *buf = mSlots[slot].mGraphicBuffer; - return NO_ERROR; -} - -status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, - uint32_t format, uint32_t usage) { - ALOGV("dequeueBuffer"); - Mutex::Autolock lock(mMutex); - - // Check for the buffer size- the client should just use the - // default width and height, and not try to set those. - // This is needed since - // the getFormat() returns mDefaultWidth/ Height for the OMX. It is - // queried by OMX in the beginning and not every time a frame comes. - // Not sure if there is a way to update the - // frame size while recording. So as of now, the client side - // sets the default values via the constructor, and the encoder is - // setup to encode frames of that size - // The design might need to change in the future. - // TODO: Currently just uses mDefaultWidth/Height. In the future - // we might declare mHeight and mWidth and check against those here. - if ((w != 0) || (h != 0)) { - if ((w != mDefaultWidth) || (h != mDefaultHeight)) { - ALOGE("dequeuebuffer: invalid buffer size! Req: %dx%d, Found: %dx%d", - mDefaultWidth, mDefaultHeight, w, h); - return BAD_VALUE; - } - } - - status_t returnFlags(OK); - int found, foundSync; - int dequeuedCount = 0; - bool tryAgain = true; - while (tryAgain) { - // We need to wait for the FIFO to drain if the number of buffer - // needs to change. - // - // The condition "number of buffer needs to change" is true if - // - the client doesn't care about how many buffers there are - // - AND the actual number of buffer is different from what was - // set in the last setBufferCountServer() - // - OR - - // setBufferCountServer() was set to a value incompatible with - // the synchronization mode (for instance because the sync mode - // changed since) - // - // As long as this condition is true AND the FIFO is not empty, we - // wait on mDequeueCondition. - - int minBufferCountNeeded = mSynchronousMode ? - MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; - - if (!mClientBufferCount && - ((mServerBufferCount != mBufferCount) || - (mServerBufferCount < minBufferCountNeeded))) { - // wait for the FIFO to drain - while (!mQueue.isEmpty()) { - ALOGV("Waiting for the FIFO to drain"); - mDequeueCondition.wait(mMutex); - } - if (mStopped) { - return NO_INIT; - } - // need to check again since the mode could have changed - // while we were waiting - minBufferCountNeeded = mSynchronousMode ? - MIN_SYNC_BUFFER_SLOTS : MIN_ASYNC_BUFFER_SLOTS; - } - - if (!mClientBufferCount && - ((mServerBufferCount != mBufferCount) || - (mServerBufferCount < minBufferCountNeeded))) { - // here we're guaranteed that mQueue is empty - freeAllBuffersLocked(); - mBufferCount = mServerBufferCount; - if (mBufferCount < minBufferCountNeeded) - mBufferCount = minBufferCountNeeded; - mCurrentSlot = INVALID_BUFFER_SLOT; - returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS; - } - - // look for a free buffer to give to the client - found = INVALID_BUFFER_SLOT; - foundSync = INVALID_BUFFER_SLOT; - dequeuedCount = 0; - for (int i = 0; i < mBufferCount; i++) { - const int state = mSlots[i].mBufferState; - if (state == BufferSlot::DEQUEUED) { - dequeuedCount++; - continue; // won't be continuing if could - // dequeue a non 'FREE' current slot like - // that in SurfaceTexture - } - // In case of Encoding, we do not deque the mCurrentSlot buffer - // since we follow synchronous mode (unlike possibly in - // SurfaceTexture that could be using the asynch mode - // or has some mechanism in GL to be able to wait till the - // currentslot is done using the data) - // Here, we have to wait for the MPEG4Writer(or equiv) - // to tell us when it's done using the current buffer - if (state == BufferSlot::FREE) { - foundSync = i; - // Unlike that in SurfaceTexture, - // We don't need to worry if it is the - // currentslot or not as it is in state FREE - found = i; - break; - } - } - - // clients are not allowed to dequeue more than one buffer - // if they didn't set a buffer count. - if (!mClientBufferCount && dequeuedCount) { - return -EINVAL; - } - - // See whether a buffer has been queued since the last setBufferCount so - // we know whether to perform the MIN_UNDEQUEUED_BUFFERS check below. - bool bufferHasBeenQueued = mCurrentSlot != INVALID_BUFFER_SLOT; - if (bufferHasBeenQueued) { - // make sure the client is not trying to dequeue more buffers - // than allowed. - const int avail = mBufferCount - (dequeuedCount+1); - if (avail < (MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode))) { - ALOGE("dequeueBuffer: MIN_UNDEQUEUED_BUFFERS=%d exceeded (dequeued=%d)", - MIN_UNDEQUEUED_BUFFERS-int(mSynchronousMode), - dequeuedCount); - return -EBUSY; - } - } - - // we're in synchronous mode and didn't find a buffer, we need to wait - // for for some buffers to be consumed - tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT); - if (tryAgain) { - ALOGV("Waiting..In synchronous mode and no buffer to dequeue"); - mDequeueCondition.wait(mMutex); - } - if (mStopped) { - return NO_INIT; - } - } - - if (mSynchronousMode && found == INVALID_BUFFER_SLOT) { - // foundSync guaranteed to be != INVALID_BUFFER_SLOT - found = foundSync; - } - - if (found == INVALID_BUFFER_SLOT) { - return -EBUSY; - } - - const int bufIndex = found; - *outBuf = found; - - const bool useDefaultSize = !w && !h; - if (useDefaultSize) { - // use the default size - w = mDefaultWidth; - h = mDefaultHeight; - } - - const bool updateFormat = (format != 0); - if (!updateFormat) { - // keep the current (or default) format - format = mPixelFormat; - } - - // buffer is now in DEQUEUED (but can also be current at the same time, - // if we're in synchronous mode) - mSlots[bufIndex].mBufferState = BufferSlot::DEQUEUED; - - const sp<GraphicBuffer>& buffer(mSlots[bufIndex].mGraphicBuffer); - if ((buffer == NULL) || - (uint32_t(buffer->width) != w) || - (uint32_t(buffer->height) != h) || - (uint32_t(buffer->format) != format) || - ((uint32_t(buffer->usage) & usage) != usage)) { - // XXX: This will be changed to USAGE_HW_VIDEO_ENCODER once driver - // issues with that flag get fixed. - usage |= GraphicBuffer::USAGE_HW_TEXTURE; - status_t error; - sp<GraphicBuffer> graphicBuffer( - mGraphicBufferAlloc->createGraphicBuffer( - w, h, format, usage, &error)); - if (graphicBuffer == 0) { - ALOGE("dequeueBuffer: SurfaceComposer::createGraphicBuffer failed"); - return error; - } - if (updateFormat) { - mPixelFormat = format; - } - mSlots[bufIndex].mGraphicBuffer = graphicBuffer; - mSlots[bufIndex].mRequestBufferCalled = false; - returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION; - } - return returnFlags; -} - -// TODO: clean this up -status_t SurfaceMediaSource::setSynchronousMode(bool enabled) { - Mutex::Autolock lock(mMutex); - if (mStopped) { - ALOGE("setSynchronousMode: SurfaceMediaSource has been stopped!"); - return NO_INIT; - } - - if (!enabled) { - // Async mode is not allowed - ALOGE("SurfaceMediaSource can be used only synchronous mode!"); - return INVALID_OPERATION; - } - - if (mSynchronousMode != enabled) { - // - if we're going to asynchronous mode, the queue is guaranteed to be - // empty here - // - if the client set the number of buffers, we're guaranteed that - // we have at least 3 (because we don't allow less) - mSynchronousMode = enabled; - mDequeueCondition.signal(); - } - return OK; -} - -status_t SurfaceMediaSource::connect(int api, - uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { - ALOGV("SurfaceMediaSource::connect"); - Mutex::Autolock lock(mMutex); - - if (mStopped) { - ALOGE("Connect: SurfaceMediaSource has been stopped!"); - return NO_INIT; - } - - status_t err = NO_ERROR; - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - if (mConnectedApi != NO_CONNECTED_API) { - err = -EINVAL; - } else { - mConnectedApi = api; - *outWidth = mDefaultWidth; - *outHeight = mDefaultHeight; - *outTransform = 0; - } - break; - default: - err = -EINVAL; - break; - } - return err; -} - -// 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. -status_t SurfaceMediaSource::disconnect(int api) { - ALOGV("SurfaceMediaSource::disconnect"); - Mutex::Autolock lock(mMutex); - - if (mStopped) { - ALOGE("disconnect: SurfaceMediaSoource is already stopped!"); - return NO_INIT; - } - - status_t err = NO_ERROR; - switch (api) { - case NATIVE_WINDOW_API_EGL: - case NATIVE_WINDOW_API_CPU: - case NATIVE_WINDOW_API_MEDIA: - case NATIVE_WINDOW_API_CAMERA: - if (mConnectedApi == api) { - mConnectedApi = NO_CONNECTED_API; - mStopped = true; - mDequeueCondition.signal(); - mFrameAvailableCondition.signal(); - } else { - err = -EINVAL; - } - break; - default: - err = -EINVAL; - break; - } - return err; -} - -status_t SurfaceMediaSource::queueBuffer(int bufIndex, int64_t timestamp, - const Rect& crop, int scalingMode, uint32_t transform, - uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { - ALOGV("queueBuffer"); - - Mutex::Autolock lock(mMutex); - *outWidth = mDefaultWidth; - *outHeight = mDefaultHeight; - *outTransform = 0; - - if (bufIndex < 0 || bufIndex >= mBufferCount) { - ALOGE("queueBuffer: slot index out of range [0, %d]: %d", - mBufferCount, bufIndex); - return -EINVAL; - } else if (mSlots[bufIndex].mBufferState != BufferSlot::DEQUEUED) { - ALOGE("queueBuffer: slot %d is not owned by the client (state=%d)", - bufIndex, mSlots[bufIndex].mBufferState); - return -EINVAL; - } else if (!mSlots[bufIndex].mRequestBufferCalled) { - ALOGE("queueBuffer: slot %d was enqueued without requesting a " - "buffer", bufIndex); - return -EINVAL; - } - - if (mNumFramesReceived == 0) { - mFirstFrameTimestamp = timestamp; - // Initial delay - if (mStartTimeNs > 0) { - if (timestamp < mStartTimeNs) { - // This frame predates start of record, discard - mSlots[bufIndex].mBufferState = BufferSlot::FREE; - mDequeueCondition.signal(); - return OK; - } - mStartTimeNs = timestamp - mStartTimeNs; - } - } - timestamp = mStartTimeNs + (timestamp - mFirstFrameTimestamp); - - mNumFramesReceived++; - if (mSynchronousMode) { - // in synchronous mode we queue all buffers in a FIFO - mQueue.push_back(bufIndex); - ALOGV("Client queued buf# %d @slot: %d, Q size = %d, handle = %p, timestamp = %lld", - mNumFramesReceived, bufIndex, mQueue.size(), - mSlots[bufIndex].mGraphicBuffer->handle, timestamp); - } else { - // in asynchronous mode we only keep the most recent buffer - if (mQueue.empty()) { - mQueue.push_back(bufIndex); - } else { - Fifo::iterator front(mQueue.begin()); - // buffer currently queued is freed - mSlots[*front].mBufferState = BufferSlot::FREE; - // and we record the new buffer index in the queued list - *front = bufIndex; - } - } - - mSlots[bufIndex].mBufferState = BufferSlot::QUEUED; - mSlots[bufIndex].mTimestamp = timestamp; - // TODO: (Confirm) Don't want to signal dequeue here. - // May be just in asynchronous mode? - // mDequeueCondition.signal(); - - // Once the queuing is done, we need to let the listener - // and signal the buffer consumer (encoder) know that a - // buffer is available - onFrameReceivedLocked(); - - - return OK; -} - - -// onFrameReceivedLocked informs the buffer consumers (StageFrightRecorder) -// or listeners that a frame has been received -// It is supposed to be called only from queuebuffer. -// 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 -status_t SurfaceMediaSource::onFrameReceivedLocked() { - ALOGV("On Frame Received locked"); - // Signal the encoder that a new frame has arrived - mFrameAvailableCondition.signal(); + sp<ISurfaceComposer> composer(ComposerService::getComposerService()); - // call back the listener - // TODO: The listener may not be needed in SurfaceMediaSource at all. - // This can be made a SurfaceTexture specific thing - sp<FrameAvailableListener> listener; - if (mSynchronousMode || mQueue.empty()) { - listener = mFrameAvailableListener; - } + // Note that we can't create an sp<...>(this) in a ctor that will not keep a + // reference once the ctor ends, as that would cause the refcount of 'this' + // dropping to 0 at the end of the ctor. Since all we need is a wp<...> + // that's what we create. + wp<BufferQueue::ConsumerListener> listener; + sp<BufferQueue::ConsumerListener> proxy; + listener = static_cast<BufferQueue::ConsumerListener*>(this); + proxy = new BufferQueue::ProxyConsumerListener(listener); - if (listener != 0) { - listener->onFrameAvailable(); + status_t err = mBufferQueue->consumerConnect(proxy); + if (err != NO_ERROR) { + ALOGE("SurfaceMediaSource: error connecting to BufferQueue: %s (%d)", + strerror(-err), err); } - return OK; } - -void SurfaceMediaSource::cancelBuffer(int bufIndex) { - ALOGV("SurfaceMediaSource::cancelBuffer"); - Mutex::Autolock lock(mMutex); - if (bufIndex < 0 || bufIndex >= mBufferCount) { - ALOGE("cancelBuffer: slot index out of range [0, %d]: %d", - mBufferCount, bufIndex); - return; - } else if (mSlots[bufIndex].mBufferState != BufferSlot::DEQUEUED) { - ALOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", - bufIndex, mSlots[bufIndex].mBufferState); - return; +SurfaceMediaSource::~SurfaceMediaSource() { + ALOGV("SurfaceMediaSource::~SurfaceMediaSource"); + if (!mStopped) { + reset(); } - mSlots[bufIndex].mBufferState = BufferSlot::FREE; - mDequeueCondition.signal(); } nsecs_t SurfaceMediaSource::getTimestamp() { @@ -582,7 +87,6 @@ nsecs_t SurfaceMediaSource::getTimestamp() { return mCurrentTimestamp; } - void SurfaceMediaSource::setFrameAvailableListener( const sp<FrameAvailableListener>& listener) { ALOGV("SurfaceMediaSource::setFrameAvailableListener"); @@ -590,49 +94,11 @@ void SurfaceMediaSource::setFrameAvailableListener( mFrameAvailableListener = listener; } -void SurfaceMediaSource::freeAllBuffersLocked() { - ALOGV("freeAllBuffersLocked"); - for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { - mSlots[i].mGraphicBuffer = 0; - mSlots[i].mBufferState = BufferSlot::FREE; - } -} - sp<GraphicBuffer> SurfaceMediaSource::getCurrentBuffer() const { Mutex::Autolock lock(mMutex); return mCurrentBuf; } -int SurfaceMediaSource::query(int what, int* outValue) -{ - ALOGV("query"); - Mutex::Autolock lock(mMutex); - int value; - switch (what) { - case NATIVE_WINDOW_WIDTH: - value = mDefaultWidth; - if (!mDefaultWidth && !mDefaultHeight && mCurrentBuf != 0) - value = mCurrentBuf->width; - break; - case NATIVE_WINDOW_HEIGHT: - value = mDefaultHeight; - if (!mDefaultWidth && !mDefaultHeight && mCurrentBuf != 0) - value = mCurrentBuf->height; - break; - case NATIVE_WINDOW_FORMAT: - value = mPixelFormat; - break; - case NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS: - value = mSynchronousMode ? - (MIN_UNDEQUEUED_BUFFERS-1) : MIN_UNDEQUEUED_BUFFERS; - break; - default: - return BAD_VALUE; - } - outValue[0] = value; - return NO_ERROR; -} - void SurfaceMediaSource::dump(String8& result) const { char buffer[1024]; @@ -642,46 +108,10 @@ void SurfaceMediaSource::dump(String8& result) const void SurfaceMediaSource::dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const { - Mutex::Autolock _l(mMutex); - snprintf(buffer, SIZE, - "%smBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], " - "mPixelFormat=%d, \n", - prefix, mBufferCount, mSynchronousMode, mDefaultWidth, mDefaultHeight, - mPixelFormat); - result.append(buffer); - - String8 fifo; - int fifoSize = 0; - Fifo::const_iterator i(mQueue.begin()); - while (i != mQueue.end()) { - snprintf(buffer, SIZE, "%02d ", *i++); - fifoSize++; - fifo.append(buffer); - } + Mutex::Autolock lock(mMutex); result.append(buffer); - - struct { - const char * operator()(int state) const { - switch (state) { - case BufferSlot::DEQUEUED: return "DEQUEUED"; - case BufferSlot::QUEUED: return "QUEUED"; - case BufferSlot::FREE: return "FREE"; - default: return "Unknown"; - } - } - } stateName; - - for (int i = 0; i < mBufferCount; i++) { - const BufferSlot& slot(mSlots[i]); - snprintf(buffer, SIZE, - "%s%s[%02d] state=%-8s, " - "timestamp=%lld\n", - prefix, (i==mCurrentSlot)?">":" ", i, stateName(slot.mBufferState), - slot.mTimestamp - ); - result.append(buffer); - } + mBufferQueue->dump(result); } status_t SurfaceMediaSource::setFrameRate(int32_t fps) @@ -726,10 +156,9 @@ status_t SurfaceMediaSource::reset() Mutex::Autolock lock(mMutex); // TODO: Add waiting on mFrameCompletedCondition here? mStopped = true; + mFrameAvailableCondition.signal(); - mDequeueCondition.signal(); - mQueue.clear(); - freeAllBuffersLocked(); + mBufferQueue->consumerDisconnect(); return OK; } @@ -737,17 +166,18 @@ status_t SurfaceMediaSource::reset() sp<MetaData> SurfaceMediaSource::getFormat() { ALOGV("getFormat"); - Mutex::Autolock autoLock(mMutex); + + Mutex::Autolock lock(mMutex); sp<MetaData> meta = new MetaData; - meta->setInt32(kKeyWidth, mDefaultWidth); - meta->setInt32(kKeyHeight, mDefaultHeight); + meta->setInt32(kKeyWidth, mWidth); + meta->setInt32(kKeyHeight, mHeight); // The encoder format is set as an opaque colorformat // The encoder will later find out the actual colorformat // from the GL Frames itself. meta->setInt32(kKeyColorFormat, OMX_COLOR_FormatAndroidOpaque); - meta->setInt32(kKeyStride, mDefaultWidth); - meta->setInt32(kKeySliceHeight, mDefaultHeight); + meta->setInt32(kKeyStride, mWidth); + meta->setInt32(kKeySliceHeight, mHeight); meta->setInt32(kKeyFrameRate, mFrameRate); meta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_RAW); return meta; @@ -756,16 +186,54 @@ sp<MetaData> SurfaceMediaSource::getFormat() status_t SurfaceMediaSource::read( MediaBuffer **buffer, const ReadOptions *options) { - Mutex::Autolock autoLock(mMutex) ; + ALOGV("read"); + Mutex::Autolock lock(mMutex); - ALOGV("Read. Size of queued buffer: %d", mQueue.size()); *buffer = NULL; + // Update the current buffer info + // TODO: mCurrentSlot can be made a bufferstate since there + // can be more than one "current" slots. + + BufferQueue::BufferItem item; // If the recording has started and the queue is empty, then just // wait here till the frames come in from the client side - while (!mStopped && mQueue.empty()) { - ALOGV("NO FRAMES! Recorder waiting for FrameAvailableCondition"); - mFrameAvailableCondition.wait(mMutex); + while (!mStopped) { + + status_t err = mBufferQueue->acquireBuffer(&item); + if (err == BufferQueue::NO_BUFFER_AVAILABLE) { + // wait for a buffer to be queued + mFrameAvailableCondition.wait(mMutex); + } else if (err == OK) { + + // First time seeing the buffer? Added it to the SMS slot + if (item.mGraphicBuffer != NULL) { + mBufferSlot[item.mBuf] = item.mGraphicBuffer; + } + + // check for the timing of this buffer + if (mNumFramesReceived == 0) { + mFirstFrameTimestamp = item.mTimestamp; + // Initial delay + if (mStartTimeNs > 0) { + if (item.mTimestamp < mStartTimeNs) { + // This frame predates start of record, discard + mBufferQueue->releaseBuffer(item.mBuf, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); + continue; + } + mStartTimeNs = item.mTimestamp - mStartTimeNs; + } + } + item.mTimestamp = mStartTimeNs + (item.mTimestamp - mFirstFrameTimestamp); + + mNumFramesReceived++; + + break; + } else { + ALOGE("read: acquire failed with error code %d", err); + return ERROR_END_OF_STREAM; + } + } // If the loop was exited as a result of stopping the recording, @@ -775,15 +243,15 @@ status_t SurfaceMediaSource::read( MediaBuffer **buffer, return ERROR_END_OF_STREAM; } - // Update the current buffer info - // TODO: mCurrentSlot can be made a bufferstate since there - // can be more than one "current" slots. - Fifo::iterator front(mQueue.begin()); - mCurrentSlot = *front; - mQueue.erase(front); - mCurrentBuf = mSlots[mCurrentSlot].mGraphicBuffer; + mCurrentSlot = item.mBuf; + + // First time seeing the buffer? Added it to the SMS slot + if (item.mGraphicBuffer != NULL) { + mBufferSlot[mCurrentSlot] = item.mGraphicBuffer; + } + mCurrentBuf = mBufferSlot[mCurrentSlot]; int64_t prevTimeStamp = mCurrentTimestamp; - mCurrentTimestamp = mSlots[mCurrentSlot].mTimestamp; + mCurrentTimestamp = item.mTimestamp; mNumFramesEncoded++; // Pass the data to the MediaBuffer. Pass in only the metadata @@ -796,6 +264,7 @@ status_t SurfaceMediaSource::read( MediaBuffer **buffer, mNumFramesEncoded, mCurrentTimestamp / 1000, mCurrentTimestamp / 1000 - prevTimeStamp / 1000); + return OK; } @@ -833,25 +302,27 @@ void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) { ALOGV("signalBufferReturned"); bool foundBuffer = false; - Mutex::Autolock autoLock(mMutex); + + Mutex::Autolock lock(mMutex); if (mStopped) { ALOGV("signalBufferReturned: mStopped = true! Nothing to do!"); return; } - for (int id = 0; id < NUM_BUFFER_SLOTS; id++) { - if (mSlots[id].mGraphicBuffer == NULL) { + for (int id = 0; id < BufferQueue::NUM_BUFFER_SLOTS; id++) { + if (mBufferSlot[id] == NULL) { continue; } if (checkBufferMatchesSlot(id, buffer)) { ALOGV("Slot %d returned, matches handle = %p", id, - mSlots[id].mGraphicBuffer->handle); - mSlots[id].mBufferState = BufferSlot::FREE; + mBufferSlot[id]->handle); + + mBufferQueue->releaseBuffer(id, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR); + buffer->setObserver(0); buffer->release(); - mDequeueCondition.signal(); - mFrameCompleteCondition.signal(); + foundBuffer = true; break; } @@ -868,7 +339,40 @@ bool SurfaceMediaSource::checkBufferMatchesSlot(int slot, MediaBuffer *buffer) { // copy the byte stream into our handle buffer_handle_t bufferHandle ; memcpy( &bufferHandle, (char *)(buffer->data()) + 4, sizeof(buffer_handle_t)); - return mSlots[slot].mGraphicBuffer->handle == bufferHandle; + return mBufferSlot[slot]->handle == bufferHandle; +} + +// Part of the BufferQueue::ConsumerListener +void SurfaceMediaSource::onFrameAvailable() { + ALOGV("onFrameAvailable"); + + sp<FrameAvailableListener> listener; + { // scope for the lock + Mutex::Autolock lock(mMutex); + mFrameAvailableCondition.broadcast(); + listener = mFrameAvailableListener; + } + + if (listener != NULL) { + ALOGV("actually calling onFrameAvailable"); + listener->onFrameAvailable(); + } +} + +// SurfaceMediaSource hijacks this event to assume +// the prodcuer is disconnecting from the BufferQueue +// and that it should stop the recording +void SurfaceMediaSource::onBuffersReleased() { + ALOGV("onBuffersReleased"); + + Mutex::Autolock lock(mMutex); + + mFrameAvailableCondition.signal(); + mStopped = true; + + for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) { + mBufferSlot[i] = 0; + } } } // end of namespace android diff --git a/media/libstagefright/tests/SurfaceMediaSource_test.cpp b/media/libstagefright/tests/SurfaceMediaSource_test.cpp index fe77cf7..10713fe 100644 --- a/media/libstagefright/tests/SurfaceMediaSource_test.cpp +++ b/media/libstagefright/tests/SurfaceMediaSource_test.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -// #define LOG_NDEBUG 0 +//#define LOG_NDEBUG 0 #define LOG_TAG "SurfaceMediaSource_test" #include <gtest/gtest.h> @@ -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); |