Loading include/media/stagefright/SurfaceMediaSource.h +11 −4 Original line number Diff line number Diff line Loading @@ -182,9 +182,9 @@ public: protected: // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for // freeAllBuffersLocked frees the resources (both GraphicBuffer and EGLImage) for // all slots. void freeAllBuffers(); void freeAllBuffersLocked(); static bool isExternalFormat(uint32_t format); private: Loading Loading @@ -337,8 +337,15 @@ private: // Set to a default of 30 fps if not specified by the client side int32_t mFrameRate; // mStarted is a flag to check if the recording has started bool mStarted; // mStopped is a flag to check if the recording is going on bool mStopped; // mNumFramesReceived indicates the number of frames recieved from // the client side int mNumFramesReceived; // mNumFramesEncoded indicates the number of frames passed on to the // encoder int mNumFramesEncoded; // mFrameAvailableCondition condition used to indicate whether there // is a frame available for dequeuing Loading include/media/stagefright/openmax/OMX_IVCommon.h +2 −1 Original line number Diff line number Diff line Loading @@ -154,7 +154,8 @@ typedef enum OMX_COLOR_FORMATTYPE { * Gralloc Buffers. * FIXME: In the process of reserving some enum values for * Android-specific OMX IL colorformats. Change this enum to * an acceptable range once that is done.*/ * an acceptable range once that is done. * */ OMX_COLOR_FormatAndroidOpaque = 0x7F000001, OMX_TI_COLOR_FormatYUV420PackedSemiPlanar = 0x7F000100, OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00, Loading media/libstagefright/OMXCodec.cpp +13 −2 Original line number Diff line number Diff line Loading @@ -838,6 +838,15 @@ static size_t getFrameSize( case OMX_COLOR_FormatYUV420Planar: case OMX_COLOR_FormatYUV420SemiPlanar: case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: /* * FIXME: For the Opaque color format, the frame size does not * need to be (w*h*3)/2. It just needs to * be larger than certain minimum buffer size. However, * currently, this opaque foramt has been tested only on * YUV420 formats. If that is changed, then we need to revisit * this part in the future */ case OMX_COLOR_FormatAndroidOpaque: return (width * height * 3) / 2; default: Loading Loading @@ -887,7 +896,7 @@ status_t OMXCodec::isColorFormatSupported( // Make sure that omx component does not overwrite // the incremented index (bug 2897413). CHECK_EQ(index, portFormat.nIndex); if ((portFormat.eColorFormat == colorFormat)) { if (portFormat.eColorFormat == colorFormat) { LOGV("Found supported color format: %d", portFormat.eColorFormat); return OK; // colorFormat is supported! } Loading Loading @@ -2923,6 +2932,7 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) { size_t offset = 0; int32_t n = 0; for (;;) { MediaBuffer *srcBuffer; if (mSeekTimeUs >= 0) { Loading Loading @@ -3021,6 +3031,7 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) { CHECK(info->mMediaBuffer == NULL); info->mMediaBuffer = srcBuffer; } else { CHECK(srcBuffer->data() != NULL) ; memcpy((uint8_t *)info->mData + offset, (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(), Loading media/libstagefright/SurfaceMediaSource.cpp +111 −67 Original line number Diff line number Diff line Loading @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ // #define LOG_NDEBUG 0 #define LOG_TAG "SurfaceMediaSource" Loading Loading @@ -47,7 +46,9 @@ SurfaceMediaSource::SurfaceMediaSource(uint32_t bufW, uint32_t bufH) : mSynchronousMode(true), mConnectedApi(NO_CONNECTED_API), mFrameRate(30), mStarted(false) { mNumFramesReceived(0), mNumFramesEncoded(0), mStopped(false) { LOGV("SurfaceMediaSource::SurfaceMediaSource"); sp<ISurfaceComposer> composer(ComposerService::getComposerService()); mGraphicBufferAlloc = composer->createGraphicBufferAlloc(); Loading @@ -55,10 +56,9 @@ SurfaceMediaSource::SurfaceMediaSource(uint32_t bufW, uint32_t bufH) : SurfaceMediaSource::~SurfaceMediaSource() { LOGV("SurfaceMediaSource::~SurfaceMediaSource"); if (mStarted) { if (!mStopped) { stop(); } freeAllBuffers(); } size_t SurfaceMediaSource::getQueuedCount() const { Loading Loading @@ -139,12 +139,12 @@ status_t SurfaceMediaSource::setBufferCount(int bufferCount) { // here we're guaranteed that the client doesn't have dequeued buffers // and will release all of its buffer references. freeAllBuffers(); mBufferCount = bufferCount; mClientBufferCount = bufferCount; mCurrentSlot = INVALID_BUFFER_SLOT; mQueue.clear(); mDequeueCondition.signal(); freeAllBuffersLocked(); return OK; } Loading @@ -164,7 +164,7 @@ status_t SurfaceMediaSource::requestBuffer(int slot, sp<GraphicBuffer>* buf) { status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { LOGV("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. Loading @@ -184,10 +184,7 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, return BAD_VALUE; } Mutex::Autolock lock(mMutex); status_t returnFlags(OK); int found, foundSync; int dequeuedCount = 0; bool tryAgain = true; Loading Loading @@ -218,6 +215,9 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, LOGV("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 ? Loading @@ -228,7 +228,7 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, ((mServerBufferCount != mBufferCount) || (mServerBufferCount < minBufferCountNeeded))) { // here we're guaranteed that mQueue is empty freeAllBuffers(); freeAllBuffersLocked(); mBufferCount = mServerBufferCount; if (mBufferCount < minBufferCountNeeded) mBufferCount = minBufferCountNeeded; Loading Loading @@ -290,9 +290,12 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, // for for some buffers to be consumed tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT); if (tryAgain) { LOGW("Waiting..In synchronous mode and no buffer to dQ"); LOGV("Waiting..In synchronous mode and no buffer to dequeue"); mDequeueCondition.wait(mMutex); } if (mStopped) { return NO_INIT; } } if (mSynchronousMode && found == INVALID_BUFFER_SLOT) { Loading @@ -304,7 +307,7 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, return -EBUSY; } const int buf = found; const int bufIndex = found; *outBuf = found; const bool useDefaultSize = !w && !h; Loading @@ -322,9 +325,9 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, // buffer is now in DEQUEUED (but can also be current at the same time, // if we're in synchronous mode) mSlots[buf].mBufferState = BufferSlot::DEQUEUED; mSlots[bufIndex].mBufferState = BufferSlot::DEQUEUED; const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer); const sp<GraphicBuffer>& buffer(mSlots[bufIndex].mGraphicBuffer); if ((buffer == NULL) || (uint32_t(buffer->width) != w) || (uint32_t(buffer->height) != h) || Loading @@ -342,22 +345,25 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, if (updateFormat) { mPixelFormat = format; } mSlots[buf].mGraphicBuffer = graphicBuffer; mSlots[buf].mRequestBufferCalled = false; 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) { LOGE("setSynchronousMode: SurfaceMediaSource has been stopped!"); return NO_INIT; } status_t err = OK; if (!enabled) { // going to asynchronous mode, drain the queue while (mSynchronousMode != enabled && !mQueue.isEmpty()) { mDequeueCondition.wait(mMutex); } // Async mode is not allowed LOGE("SurfaceMediaSource can be used only synchronous mode!"); return INVALID_OPERATION; } if (mSynchronousMode != enabled) { Loading @@ -368,13 +374,19 @@ status_t SurfaceMediaSource::setSynchronousMode(bool enabled) { mSynchronousMode = enabled; mDequeueCondition.signal(); } return err; return OK; } status_t SurfaceMediaSource::connect(int api, uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { LOGV("SurfaceMediaSource::connect"); Mutex::Autolock lock(mMutex); if (mStopped) { LOGE("Connect: SurfaceMediaSource has been stopped!"); return NO_INIT; } status_t err = NO_ERROR; switch (api) { case NATIVE_WINDOW_API_EGL: Loading @@ -397,9 +409,25 @@ status_t SurfaceMediaSource::connect(int api, 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) { LOGV("SurfaceMediaSource::disconnect"); Mutex::Autolock lock(mMutex); if (mStopped) { LOGE("disconnect: SurfaceMediaSoource is already stopped!"); return NO_INIT; } status_t err = NO_ERROR; switch (api) { case NATIVE_WINDOW_API_EGL: Loading @@ -408,6 +436,9 @@ status_t SurfaceMediaSource::disconnect(int api) { case NATIVE_WINDOW_API_CAMERA: if (mConnectedApi == api) { mConnectedApi = NO_CONNECTED_API; mStopped = true; mDequeueCondition.signal(); mFrameAvailableCondition.signal(); } else { err = -EINVAL; } Loading @@ -419,45 +450,47 @@ status_t SurfaceMediaSource::disconnect(int api) { return err; } status_t SurfaceMediaSource::queueBuffer(int buf, int64_t timestamp, status_t SurfaceMediaSource::queueBuffer(int bufIndex, int64_t timestamp, uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { LOGV("queueBuffer"); Mutex::Autolock lock(mMutex); if (buf < 0 || buf >= mBufferCount) { if (bufIndex < 0 || bufIndex >= mBufferCount) { LOGE("queueBuffer: slot index out of range [0, %d]: %d", mBufferCount, buf); mBufferCount, bufIndex); return -EINVAL; } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { } else if (mSlots[bufIndex].mBufferState != BufferSlot::DEQUEUED) { LOGE("queueBuffer: slot %d is not owned by the client (state=%d)", buf, mSlots[buf].mBufferState); bufIndex, mSlots[bufIndex].mBufferState); return -EINVAL; } else if (!mSlots[buf].mRequestBufferCalled) { } else if (!mSlots[bufIndex].mRequestBufferCalled) { LOGE("queueBuffer: slot %d was enqueued without requesting a " "buffer", buf); "buffer", bufIndex); return -EINVAL; } if (mSynchronousMode) { // in synchronous mode we queue all buffers in a FIFO mQueue.push_back(buf); LOGV("Client queued buffer on slot: %d, Q size = %d", buf, mQueue.size()); mQueue.push_back(bufIndex); mNumFramesReceived++; LOGV("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(buf); 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 = buf; *front = bufIndex; } } mSlots[buf].mBufferState = BufferSlot::QUEUED; mSlots[buf].mTimestamp = timestamp; 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(); Loading @@ -482,7 +515,7 @@ status_t SurfaceMediaSource::queueBuffer(int buf, int64_t timestamp, // wait to hear from StageFrightRecorder to set the buffer FREE // Make sure this is called when the mutex is locked status_t SurfaceMediaSource::onFrameReceivedLocked() { LOGV("On Frame Received"); LOGV("On Frame Received locked"); // Signal the encoder that a new frame has arrived mFrameAvailableCondition.signal(); Loading @@ -501,19 +534,19 @@ status_t SurfaceMediaSource::onFrameReceivedLocked() { } void SurfaceMediaSource::cancelBuffer(int buf) { void SurfaceMediaSource::cancelBuffer(int bufIndex) { LOGV("SurfaceMediaSource::cancelBuffer"); Mutex::Autolock lock(mMutex); if (buf < 0 || buf >= mBufferCount) { if (bufIndex < 0 || bufIndex >= mBufferCount) { LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount, buf); mBufferCount, bufIndex); return; } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { } else if (mSlots[bufIndex].mBufferState != BufferSlot::DEQUEUED) { LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", buf, mSlots[buf].mBufferState); bufIndex, mSlots[bufIndex].mBufferState); return; } mSlots[buf].mBufferState = BufferSlot::FREE; mSlots[bufIndex].mBufferState = BufferSlot::FREE; mDequeueCondition.signal(); } Loading @@ -531,8 +564,8 @@ void SurfaceMediaSource::setFrameAvailableListener( mFrameAvailableListener = listener; } void SurfaceMediaSource::freeAllBuffers() { LOGV("freeAllBuffers"); void SurfaceMediaSource::freeAllBuffersLocked() { LOGV("freeAllBuffersLocked"); for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { mSlots[i].mGraphicBuffer = 0; mSlots[i].mBufferState = BufferSlot::FREE; Loading Loading @@ -648,10 +681,7 @@ int32_t SurfaceMediaSource::getFrameRate( ) const { status_t SurfaceMediaSource::start(MetaData *params) { LOGV("start"); Mutex::Autolock lock(mMutex); CHECK(!mStarted); mStarted = true; LOGV("started!"); return OK; } Loading @@ -662,8 +692,11 @@ status_t SurfaceMediaSource::stop() Mutex::Autolock lock(mMutex); // TODO: Add waiting on mFrameCompletedCondition here? mStarted = false; mStopped = true; mFrameAvailableCondition.signal(); mDequeueCondition.signal(); mQueue.clear(); freeAllBuffersLocked(); return OK; } Loading @@ -690,21 +723,23 @@ sp<MetaData> SurfaceMediaSource::getFormat() status_t SurfaceMediaSource::read( MediaBuffer **buffer, const ReadOptions *options) { Mutex::Autolock autoLock(mMutex) ; LOGV("Read. Size of queued buffer: %d", mQueue.size()); *buffer = NULL; Mutex::Autolock autoLock(mMutex) ; // If the recording has started and the queue is empty, then just // wait here till the frames come in from the client side while (mStarted && mQueue.empty()) { while (!mStopped && mQueue.empty()) { LOGV("NO FRAMES! Recorder waiting for FrameAvailableCondition"); mFrameAvailableCondition.wait(mMutex); } // If the loop was exited as a result of stopping the recording, // it is OK if (!mStarted) { return OK; if (mStopped) { LOGV("Read: SurfaceMediaSource is stopped. Returning NO_INIT;"); return NO_INIT; } // Update the current buffer info Loading @@ -712,15 +747,20 @@ status_t SurfaceMediaSource::read( MediaBuffer **buffer, // can be more than one "current" slots. Fifo::iterator front(mQueue.begin()); mCurrentSlot = *front; mQueue.erase(front); mCurrentBuf = mSlots[mCurrentSlot].mGraphicBuffer; int64_t prevTimeStamp = mCurrentTimestamp; mCurrentTimestamp = mSlots[mCurrentSlot].mTimestamp; mNumFramesEncoded++; // Pass the data to the MediaBuffer. Pass in only the metadata passMetadataBufferLocked(buffer); (*buffer)->setObserver(this); (*buffer)->add_ref(); (*buffer)->meta_data()->setInt64(kKeyTime, mCurrentTimestamp); (*buffer)->meta_data()->setInt64(kKeyTime, mCurrentTimestamp / 1000); LOGV("Frames encoded = %d, timestamp = %lld, time diff = %lld", mNumFramesEncoded, mCurrentTimestamp / 1000, mCurrentTimestamp / 1000 - prevTimeStamp / 1000); return OK; } Loading @@ -743,15 +783,17 @@ void SurfaceMediaSource::passMetadataBufferLocked(MediaBuffer **buffer) { new MediaBuffer(4 + sizeof(buffer_handle_t)); char *data = (char *)tempBuffer->data(); if (data == NULL) { LOGE("Cannot allocate memory for passing buffer metadata!"); LOGE("Cannot allocate memory for metadata buffer!"); return; } OMX_U32 type = kMetadataBufferTypeGrallocSource; memcpy(data, &type, 4); memcpy(data + 4, &(mCurrentBuf->handle), sizeof(buffer_handle_t)); *buffer = tempBuffer; } LOGV("handle = %p, , offset = %d, length = %d", mCurrentBuf->handle, (*buffer)->range_length(), (*buffer)->range_offset()); } void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) { LOGV("signalBufferReturned"); Loading @@ -759,16 +801,19 @@ void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) { bool foundBuffer = false; Mutex::Autolock autoLock(mMutex); if (!mStarted) { LOGW("signalBufferReturned: mStarted = false! Nothing to do!"); if (mStopped) { LOGV("signalBufferReturned: mStopped = true! Nothing to do!"); return; } for (Fifo::iterator it = mQueue.begin(); it != mQueue.end(); ++it) { CHECK(mSlots[*it].mGraphicBuffer != NULL); if (checkBufferMatchesSlot(*it, buffer)) { mSlots[*it].mBufferState = BufferSlot::FREE; mQueue.erase(it); for (int id = 0; id < NUM_BUFFER_SLOTS; id++) { if (mSlots[id].mGraphicBuffer == NULL) { continue; } if (checkBufferMatchesSlot(id, buffer)) { LOGV("Slot %d returned, matches handle = %p", id, mSlots[id].mGraphicBuffer->handle); mSlots[id].mBufferState = BufferSlot::FREE; buffer->setObserver(0); buffer->release(); mDequeueCondition.signal(); Loading @@ -792,5 +837,4 @@ bool SurfaceMediaSource::checkBufferMatchesSlot(int slot, MediaBuffer *buffer) { return mSlots[slot].mGraphicBuffer->handle == bufferHandle; } } // end of namespace android media/libstagefright/tests/Android.mk +4 −3 Original line number Diff line number Diff line Loading @@ -19,12 +19,13 @@ LOCAL_SHARED_LIBRARIES := \ libbinder \ libcutils \ libgui \ libstlport \ libui \ libutils \ libmedia \ libstagefright \ libstagefright_omx \ libstagefright_foundation \ libstlport \ libui \ libutils \ LOCAL_STATIC_LIBRARIES := \ libgtest \ Loading Loading
include/media/stagefright/SurfaceMediaSource.h +11 −4 Original line number Diff line number Diff line Loading @@ -182,9 +182,9 @@ public: protected: // freeAllBuffers frees the resources (both GraphicBuffer and EGLImage) for // freeAllBuffersLocked frees the resources (both GraphicBuffer and EGLImage) for // all slots. void freeAllBuffers(); void freeAllBuffersLocked(); static bool isExternalFormat(uint32_t format); private: Loading Loading @@ -337,8 +337,15 @@ private: // Set to a default of 30 fps if not specified by the client side int32_t mFrameRate; // mStarted is a flag to check if the recording has started bool mStarted; // mStopped is a flag to check if the recording is going on bool mStopped; // mNumFramesReceived indicates the number of frames recieved from // the client side int mNumFramesReceived; // mNumFramesEncoded indicates the number of frames passed on to the // encoder int mNumFramesEncoded; // mFrameAvailableCondition condition used to indicate whether there // is a frame available for dequeuing Loading
include/media/stagefright/openmax/OMX_IVCommon.h +2 −1 Original line number Diff line number Diff line Loading @@ -154,7 +154,8 @@ typedef enum OMX_COLOR_FORMATTYPE { * Gralloc Buffers. * FIXME: In the process of reserving some enum values for * Android-specific OMX IL colorformats. Change this enum to * an acceptable range once that is done.*/ * an acceptable range once that is done. * */ OMX_COLOR_FormatAndroidOpaque = 0x7F000001, OMX_TI_COLOR_FormatYUV420PackedSemiPlanar = 0x7F000100, OMX_QCOM_COLOR_FormatYVU420SemiPlanar = 0x7FA30C00, Loading
media/libstagefright/OMXCodec.cpp +13 −2 Original line number Diff line number Diff line Loading @@ -838,6 +838,15 @@ static size_t getFrameSize( case OMX_COLOR_FormatYUV420Planar: case OMX_COLOR_FormatYUV420SemiPlanar: case OMX_TI_COLOR_FormatYUV420PackedSemiPlanar: /* * FIXME: For the Opaque color format, the frame size does not * need to be (w*h*3)/2. It just needs to * be larger than certain minimum buffer size. However, * currently, this opaque foramt has been tested only on * YUV420 formats. If that is changed, then we need to revisit * this part in the future */ case OMX_COLOR_FormatAndroidOpaque: return (width * height * 3) / 2; default: Loading Loading @@ -887,7 +896,7 @@ status_t OMXCodec::isColorFormatSupported( // Make sure that omx component does not overwrite // the incremented index (bug 2897413). CHECK_EQ(index, portFormat.nIndex); if ((portFormat.eColorFormat == colorFormat)) { if (portFormat.eColorFormat == colorFormat) { LOGV("Found supported color format: %d", portFormat.eColorFormat); return OK; // colorFormat is supported! } Loading Loading @@ -2923,6 +2932,7 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) { size_t offset = 0; int32_t n = 0; for (;;) { MediaBuffer *srcBuffer; if (mSeekTimeUs >= 0) { Loading Loading @@ -3021,6 +3031,7 @@ bool OMXCodec::drainInputBuffer(BufferInfo *info) { CHECK(info->mMediaBuffer == NULL); info->mMediaBuffer = srcBuffer; } else { CHECK(srcBuffer->data() != NULL) ; memcpy((uint8_t *)info->mData + offset, (const uint8_t *)srcBuffer->data() + srcBuffer->range_offset(), Loading
media/libstagefright/SurfaceMediaSource.cpp +111 −67 Original line number Diff line number Diff line Loading @@ -13,7 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ // #define LOG_NDEBUG 0 #define LOG_TAG "SurfaceMediaSource" Loading Loading @@ -47,7 +46,9 @@ SurfaceMediaSource::SurfaceMediaSource(uint32_t bufW, uint32_t bufH) : mSynchronousMode(true), mConnectedApi(NO_CONNECTED_API), mFrameRate(30), mStarted(false) { mNumFramesReceived(0), mNumFramesEncoded(0), mStopped(false) { LOGV("SurfaceMediaSource::SurfaceMediaSource"); sp<ISurfaceComposer> composer(ComposerService::getComposerService()); mGraphicBufferAlloc = composer->createGraphicBufferAlloc(); Loading @@ -55,10 +56,9 @@ SurfaceMediaSource::SurfaceMediaSource(uint32_t bufW, uint32_t bufH) : SurfaceMediaSource::~SurfaceMediaSource() { LOGV("SurfaceMediaSource::~SurfaceMediaSource"); if (mStarted) { if (!mStopped) { stop(); } freeAllBuffers(); } size_t SurfaceMediaSource::getQueuedCount() const { Loading Loading @@ -139,12 +139,12 @@ status_t SurfaceMediaSource::setBufferCount(int bufferCount) { // here we're guaranteed that the client doesn't have dequeued buffers // and will release all of its buffer references. freeAllBuffers(); mBufferCount = bufferCount; mClientBufferCount = bufferCount; mCurrentSlot = INVALID_BUFFER_SLOT; mQueue.clear(); mDequeueCondition.signal(); freeAllBuffersLocked(); return OK; } Loading @@ -164,7 +164,7 @@ status_t SurfaceMediaSource::requestBuffer(int slot, sp<GraphicBuffer>* buf) { status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, uint32_t format, uint32_t usage) { LOGV("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. Loading @@ -184,10 +184,7 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, return BAD_VALUE; } Mutex::Autolock lock(mMutex); status_t returnFlags(OK); int found, foundSync; int dequeuedCount = 0; bool tryAgain = true; Loading Loading @@ -218,6 +215,9 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, LOGV("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 ? Loading @@ -228,7 +228,7 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, ((mServerBufferCount != mBufferCount) || (mServerBufferCount < minBufferCountNeeded))) { // here we're guaranteed that mQueue is empty freeAllBuffers(); freeAllBuffersLocked(); mBufferCount = mServerBufferCount; if (mBufferCount < minBufferCountNeeded) mBufferCount = minBufferCountNeeded; Loading Loading @@ -290,9 +290,12 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, // for for some buffers to be consumed tryAgain = mSynchronousMode && (foundSync == INVALID_BUFFER_SLOT); if (tryAgain) { LOGW("Waiting..In synchronous mode and no buffer to dQ"); LOGV("Waiting..In synchronous mode and no buffer to dequeue"); mDequeueCondition.wait(mMutex); } if (mStopped) { return NO_INIT; } } if (mSynchronousMode && found == INVALID_BUFFER_SLOT) { Loading @@ -304,7 +307,7 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, return -EBUSY; } const int buf = found; const int bufIndex = found; *outBuf = found; const bool useDefaultSize = !w && !h; Loading @@ -322,9 +325,9 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, // buffer is now in DEQUEUED (but can also be current at the same time, // if we're in synchronous mode) mSlots[buf].mBufferState = BufferSlot::DEQUEUED; mSlots[bufIndex].mBufferState = BufferSlot::DEQUEUED; const sp<GraphicBuffer>& buffer(mSlots[buf].mGraphicBuffer); const sp<GraphicBuffer>& buffer(mSlots[bufIndex].mGraphicBuffer); if ((buffer == NULL) || (uint32_t(buffer->width) != w) || (uint32_t(buffer->height) != h) || Loading @@ -342,22 +345,25 @@ status_t SurfaceMediaSource::dequeueBuffer(int *outBuf, uint32_t w, uint32_t h, if (updateFormat) { mPixelFormat = format; } mSlots[buf].mGraphicBuffer = graphicBuffer; mSlots[buf].mRequestBufferCalled = false; 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) { LOGE("setSynchronousMode: SurfaceMediaSource has been stopped!"); return NO_INIT; } status_t err = OK; if (!enabled) { // going to asynchronous mode, drain the queue while (mSynchronousMode != enabled && !mQueue.isEmpty()) { mDequeueCondition.wait(mMutex); } // Async mode is not allowed LOGE("SurfaceMediaSource can be used only synchronous mode!"); return INVALID_OPERATION; } if (mSynchronousMode != enabled) { Loading @@ -368,13 +374,19 @@ status_t SurfaceMediaSource::setSynchronousMode(bool enabled) { mSynchronousMode = enabled; mDequeueCondition.signal(); } return err; return OK; } status_t SurfaceMediaSource::connect(int api, uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { LOGV("SurfaceMediaSource::connect"); Mutex::Autolock lock(mMutex); if (mStopped) { LOGE("Connect: SurfaceMediaSource has been stopped!"); return NO_INIT; } status_t err = NO_ERROR; switch (api) { case NATIVE_WINDOW_API_EGL: Loading @@ -397,9 +409,25 @@ status_t SurfaceMediaSource::connect(int api, 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) { LOGV("SurfaceMediaSource::disconnect"); Mutex::Autolock lock(mMutex); if (mStopped) { LOGE("disconnect: SurfaceMediaSoource is already stopped!"); return NO_INIT; } status_t err = NO_ERROR; switch (api) { case NATIVE_WINDOW_API_EGL: Loading @@ -408,6 +436,9 @@ status_t SurfaceMediaSource::disconnect(int api) { case NATIVE_WINDOW_API_CAMERA: if (mConnectedApi == api) { mConnectedApi = NO_CONNECTED_API; mStopped = true; mDequeueCondition.signal(); mFrameAvailableCondition.signal(); } else { err = -EINVAL; } Loading @@ -419,45 +450,47 @@ status_t SurfaceMediaSource::disconnect(int api) { return err; } status_t SurfaceMediaSource::queueBuffer(int buf, int64_t timestamp, status_t SurfaceMediaSource::queueBuffer(int bufIndex, int64_t timestamp, uint32_t* outWidth, uint32_t* outHeight, uint32_t* outTransform) { LOGV("queueBuffer"); Mutex::Autolock lock(mMutex); if (buf < 0 || buf >= mBufferCount) { if (bufIndex < 0 || bufIndex >= mBufferCount) { LOGE("queueBuffer: slot index out of range [0, %d]: %d", mBufferCount, buf); mBufferCount, bufIndex); return -EINVAL; } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { } else if (mSlots[bufIndex].mBufferState != BufferSlot::DEQUEUED) { LOGE("queueBuffer: slot %d is not owned by the client (state=%d)", buf, mSlots[buf].mBufferState); bufIndex, mSlots[bufIndex].mBufferState); return -EINVAL; } else if (!mSlots[buf].mRequestBufferCalled) { } else if (!mSlots[bufIndex].mRequestBufferCalled) { LOGE("queueBuffer: slot %d was enqueued without requesting a " "buffer", buf); "buffer", bufIndex); return -EINVAL; } if (mSynchronousMode) { // in synchronous mode we queue all buffers in a FIFO mQueue.push_back(buf); LOGV("Client queued buffer on slot: %d, Q size = %d", buf, mQueue.size()); mQueue.push_back(bufIndex); mNumFramesReceived++; LOGV("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(buf); 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 = buf; *front = bufIndex; } } mSlots[buf].mBufferState = BufferSlot::QUEUED; mSlots[buf].mTimestamp = timestamp; 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(); Loading @@ -482,7 +515,7 @@ status_t SurfaceMediaSource::queueBuffer(int buf, int64_t timestamp, // wait to hear from StageFrightRecorder to set the buffer FREE // Make sure this is called when the mutex is locked status_t SurfaceMediaSource::onFrameReceivedLocked() { LOGV("On Frame Received"); LOGV("On Frame Received locked"); // Signal the encoder that a new frame has arrived mFrameAvailableCondition.signal(); Loading @@ -501,19 +534,19 @@ status_t SurfaceMediaSource::onFrameReceivedLocked() { } void SurfaceMediaSource::cancelBuffer(int buf) { void SurfaceMediaSource::cancelBuffer(int bufIndex) { LOGV("SurfaceMediaSource::cancelBuffer"); Mutex::Autolock lock(mMutex); if (buf < 0 || buf >= mBufferCount) { if (bufIndex < 0 || bufIndex >= mBufferCount) { LOGE("cancelBuffer: slot index out of range [0, %d]: %d", mBufferCount, buf); mBufferCount, bufIndex); return; } else if (mSlots[buf].mBufferState != BufferSlot::DEQUEUED) { } else if (mSlots[bufIndex].mBufferState != BufferSlot::DEQUEUED) { LOGE("cancelBuffer: slot %d is not owned by the client (state=%d)", buf, mSlots[buf].mBufferState); bufIndex, mSlots[bufIndex].mBufferState); return; } mSlots[buf].mBufferState = BufferSlot::FREE; mSlots[bufIndex].mBufferState = BufferSlot::FREE; mDequeueCondition.signal(); } Loading @@ -531,8 +564,8 @@ void SurfaceMediaSource::setFrameAvailableListener( mFrameAvailableListener = listener; } void SurfaceMediaSource::freeAllBuffers() { LOGV("freeAllBuffers"); void SurfaceMediaSource::freeAllBuffersLocked() { LOGV("freeAllBuffersLocked"); for (int i = 0; i < NUM_BUFFER_SLOTS; i++) { mSlots[i].mGraphicBuffer = 0; mSlots[i].mBufferState = BufferSlot::FREE; Loading Loading @@ -648,10 +681,7 @@ int32_t SurfaceMediaSource::getFrameRate( ) const { status_t SurfaceMediaSource::start(MetaData *params) { LOGV("start"); Mutex::Autolock lock(mMutex); CHECK(!mStarted); mStarted = true; LOGV("started!"); return OK; } Loading @@ -662,8 +692,11 @@ status_t SurfaceMediaSource::stop() Mutex::Autolock lock(mMutex); // TODO: Add waiting on mFrameCompletedCondition here? mStarted = false; mStopped = true; mFrameAvailableCondition.signal(); mDequeueCondition.signal(); mQueue.clear(); freeAllBuffersLocked(); return OK; } Loading @@ -690,21 +723,23 @@ sp<MetaData> SurfaceMediaSource::getFormat() status_t SurfaceMediaSource::read( MediaBuffer **buffer, const ReadOptions *options) { Mutex::Autolock autoLock(mMutex) ; LOGV("Read. Size of queued buffer: %d", mQueue.size()); *buffer = NULL; Mutex::Autolock autoLock(mMutex) ; // If the recording has started and the queue is empty, then just // wait here till the frames come in from the client side while (mStarted && mQueue.empty()) { while (!mStopped && mQueue.empty()) { LOGV("NO FRAMES! Recorder waiting for FrameAvailableCondition"); mFrameAvailableCondition.wait(mMutex); } // If the loop was exited as a result of stopping the recording, // it is OK if (!mStarted) { return OK; if (mStopped) { LOGV("Read: SurfaceMediaSource is stopped. Returning NO_INIT;"); return NO_INIT; } // Update the current buffer info Loading @@ -712,15 +747,20 @@ status_t SurfaceMediaSource::read( MediaBuffer **buffer, // can be more than one "current" slots. Fifo::iterator front(mQueue.begin()); mCurrentSlot = *front; mQueue.erase(front); mCurrentBuf = mSlots[mCurrentSlot].mGraphicBuffer; int64_t prevTimeStamp = mCurrentTimestamp; mCurrentTimestamp = mSlots[mCurrentSlot].mTimestamp; mNumFramesEncoded++; // Pass the data to the MediaBuffer. Pass in only the metadata passMetadataBufferLocked(buffer); (*buffer)->setObserver(this); (*buffer)->add_ref(); (*buffer)->meta_data()->setInt64(kKeyTime, mCurrentTimestamp); (*buffer)->meta_data()->setInt64(kKeyTime, mCurrentTimestamp / 1000); LOGV("Frames encoded = %d, timestamp = %lld, time diff = %lld", mNumFramesEncoded, mCurrentTimestamp / 1000, mCurrentTimestamp / 1000 - prevTimeStamp / 1000); return OK; } Loading @@ -743,15 +783,17 @@ void SurfaceMediaSource::passMetadataBufferLocked(MediaBuffer **buffer) { new MediaBuffer(4 + sizeof(buffer_handle_t)); char *data = (char *)tempBuffer->data(); if (data == NULL) { LOGE("Cannot allocate memory for passing buffer metadata!"); LOGE("Cannot allocate memory for metadata buffer!"); return; } OMX_U32 type = kMetadataBufferTypeGrallocSource; memcpy(data, &type, 4); memcpy(data + 4, &(mCurrentBuf->handle), sizeof(buffer_handle_t)); *buffer = tempBuffer; } LOGV("handle = %p, , offset = %d, length = %d", mCurrentBuf->handle, (*buffer)->range_length(), (*buffer)->range_offset()); } void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) { LOGV("signalBufferReturned"); Loading @@ -759,16 +801,19 @@ void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) { bool foundBuffer = false; Mutex::Autolock autoLock(mMutex); if (!mStarted) { LOGW("signalBufferReturned: mStarted = false! Nothing to do!"); if (mStopped) { LOGV("signalBufferReturned: mStopped = true! Nothing to do!"); return; } for (Fifo::iterator it = mQueue.begin(); it != mQueue.end(); ++it) { CHECK(mSlots[*it].mGraphicBuffer != NULL); if (checkBufferMatchesSlot(*it, buffer)) { mSlots[*it].mBufferState = BufferSlot::FREE; mQueue.erase(it); for (int id = 0; id < NUM_BUFFER_SLOTS; id++) { if (mSlots[id].mGraphicBuffer == NULL) { continue; } if (checkBufferMatchesSlot(id, buffer)) { LOGV("Slot %d returned, matches handle = %p", id, mSlots[id].mGraphicBuffer->handle); mSlots[id].mBufferState = BufferSlot::FREE; buffer->setObserver(0); buffer->release(); mDequeueCondition.signal(); Loading @@ -792,5 +837,4 @@ bool SurfaceMediaSource::checkBufferMatchesSlot(int slot, MediaBuffer *buffer) { return mSlots[slot].mGraphicBuffer->handle == bufferHandle; } } // end of namespace android
media/libstagefright/tests/Android.mk +4 −3 Original line number Diff line number Diff line Loading @@ -19,12 +19,13 @@ LOCAL_SHARED_LIBRARIES := \ libbinder \ libcutils \ libgui \ libstlport \ libui \ libutils \ libmedia \ libstagefright \ libstagefright_omx \ libstagefright_foundation \ libstlport \ libui \ libutils \ LOCAL_STATIC_LIBRARIES := \ libgtest \ Loading