summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/SurfaceMediaSource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'media/libstagefright/SurfaceMediaSource.cpp')
-rw-r--r--media/libstagefright/SurfaceMediaSource.cpp152
1 files changed, 120 insertions, 32 deletions
diff --git a/media/libstagefright/SurfaceMediaSource.cpp b/media/libstagefright/SurfaceMediaSource.cpp
index 300d2fc..3c002fc 100644
--- a/media/libstagefright/SurfaceMediaSource.cpp
+++ b/media/libstagefright/SurfaceMediaSource.cpp
@@ -18,8 +18,8 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/SurfaceMediaSource.h>
-#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MetaData.h>
#include <OMX_IVCommon.h>
#include <MetadataBufferType.h>
@@ -39,20 +39,22 @@ SurfaceMediaSource::SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeig
mWidth(bufferWidth),
mHeight(bufferHeight),
mCurrentSlot(BufferQueue::INVALID_BUFFER_SLOT),
+ mNumPendingBuffers(0),
mCurrentTimestamp(0),
mFrameRate(30),
- mStopped(false),
+ mStarted(false),
mNumFramesReceived(0),
mNumFramesEncoded(0),
- mFirstFrameTimestamp(0)
-{
- ALOGV("SurfaceMediaSource::SurfaceMediaSource");
+ mFirstFrameTimestamp(0),
+ mMaxAcquiredBufferCount(4), // XXX double-check the default
+ mUseAbsoluteTimestamps(false) {
+ ALOGV("SurfaceMediaSource");
if (bufferWidth == 0 || bufferHeight == 0) {
ALOGE("Invalid dimensions %dx%d", bufferWidth, bufferHeight);
}
- mBufferQueue = new BufferQueue(true, MIN_UNDEQUEUED_BUFFERS);
+ mBufferQueue = new BufferQueue(true);
mBufferQueue->setDefaultBufferSize(bufferWidth, bufferHeight);
mBufferQueue->setSynchronousMode(true);
mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_VIDEO_ENCODER |
@@ -77,21 +79,19 @@ SurfaceMediaSource::SurfaceMediaSource(uint32_t bufferWidth, uint32_t bufferHeig
}
SurfaceMediaSource::~SurfaceMediaSource() {
- ALOGV("SurfaceMediaSource::~SurfaceMediaSource");
- if (!mStopped) {
- reset();
- }
+ ALOGV("~SurfaceMediaSource");
+ CHECK(!mStarted);
}
nsecs_t SurfaceMediaSource::getTimestamp() {
- ALOGV("SurfaceMediaSource::getTimestamp");
+ ALOGV("getTimestamp");
Mutex::Autolock lock(mMutex);
return mCurrentTimestamp;
}
void SurfaceMediaSource::setFrameAvailableListener(
const sp<FrameAvailableListener>& listener) {
- ALOGV("SurfaceMediaSource::setFrameAvailableListener");
+ ALOGV("setFrameAvailableListener");
Mutex::Autolock lock(mMutex);
mFrameAvailableListener = listener;
}
@@ -113,6 +113,7 @@ void SurfaceMediaSource::dump(String8& result, const char* prefix,
status_t SurfaceMediaSource::setFrameRate(int32_t fps)
{
+ ALOGV("setFrameRate");
Mutex::Autolock lock(mMutex);
const int MAX_FRAME_RATE = 60;
if (fps < 0 || fps > MAX_FRAME_RATE) {
@@ -128,36 +129,100 @@ bool SurfaceMediaSource::isMetaDataStoredInVideoBuffers() const {
}
int32_t SurfaceMediaSource::getFrameRate( ) const {
+ ALOGV("getFrameRate");
Mutex::Autolock lock(mMutex);
return mFrameRate;
}
status_t SurfaceMediaSource::start(MetaData *params)
{
- ALOGV("started!");
+ ALOGV("start");
+
+ Mutex::Autolock lock(mMutex);
+
+ CHECK(!mStarted);
mStartTimeNs = 0;
int64_t startTimeUs;
- if (params && params->findInt64(kKeyTime, &startTimeUs)) {
- mStartTimeNs = startTimeUs * 1000;
+ int32_t bufferCount = 0;
+ if (params) {
+ if (params->findInt64(kKeyTime, &startTimeUs)) {
+ mStartTimeNs = startTimeUs * 1000;
+ }
+
+ if (!params->findInt32(kKeyNumBuffers, &bufferCount)) {
+ ALOGE("Failed to find the advertised buffer count");
+ return UNKNOWN_ERROR;
+ }
+
+ if (bufferCount <= 1) {
+ ALOGE("bufferCount %d is too small", bufferCount);
+ return BAD_VALUE;
+ }
+
+ mMaxAcquiredBufferCount = bufferCount;
+ }
+
+ CHECK_GT(mMaxAcquiredBufferCount, 1);
+
+ status_t err =
+ mBufferQueue->setMaxAcquiredBufferCount(mMaxAcquiredBufferCount);
+
+ if (err != OK) {
+ return err;
}
+ mNumPendingBuffers = 0;
+ mStarted = true;
+
return OK;
}
+status_t SurfaceMediaSource::setMaxAcquiredBufferCount(size_t count) {
+ ALOGV("setMaxAcquiredBufferCount(%d)", count);
+ Mutex::Autolock lock(mMutex);
-status_t SurfaceMediaSource::reset()
-{
- ALOGV("Reset");
+ CHECK_GT(count, 1);
+ mMaxAcquiredBufferCount = count;
+
+ return OK;
+}
+status_t SurfaceMediaSource::setUseAbsoluteTimestamps() {
+ ALOGV("setUseAbsoluteTimestamps");
Mutex::Autolock lock(mMutex);
- // TODO: Add waiting on mFrameCompletedCondition here?
- mStopped = true;
+ mUseAbsoluteTimestamps = true;
+ return OK;
+}
+
+status_t SurfaceMediaSource::stop()
+{
+ ALOGV("stop");
+ Mutex::Autolock lock(mMutex);
+
+ if (!mStarted) {
+ return OK;
+ }
+
+ while (mNumPendingBuffers > 0) {
+ ALOGI("Still waiting for %d buffers to be returned.",
+ mNumPendingBuffers);
+
+#if DEBUG_PENDING_BUFFERS
+ for (size_t i = 0; i < mPendingBuffers.size(); ++i) {
+ ALOGI("%d: %p", i, mPendingBuffers.itemAt(i));
+ }
+#endif
+
+ mMediaBuffersAvailableCondition.wait(mMutex);
+ }
+
+ mStarted = false;
mFrameAvailableCondition.signal();
- mBufferQueue->consumerDisconnect();
+ mMediaBuffersAvailableCondition.signal();
- return OK;
+ return mBufferQueue->consumerDisconnect();
}
sp<MetaData> SurfaceMediaSource::getFormat()
@@ -193,9 +258,8 @@ sp<MetaData> SurfaceMediaSource::getFormat()
// Note: Call only when you have the lock
static void passMetadataBuffer(MediaBuffer **buffer,
buffer_handle_t bufferHandle) {
- // MediaBuffer allocates and owns this data
- MediaBuffer *tempBuffer = new MediaBuffer(4 + sizeof(buffer_handle_t));
- char *data = (char *)tempBuffer->data();
+ *buffer = new MediaBuffer(4 + sizeof(buffer_handle_t));
+ char *data = (char *)(*buffer)->data();
if (data == NULL) {
ALOGE("Cannot allocate memory for metadata buffer!");
return;
@@ -203,7 +267,6 @@ static void passMetadataBuffer(MediaBuffer **buffer,
OMX_U32 type = kMetadataBufferTypeGrallocSource;
memcpy(data, &type, 4);
memcpy(data + 4, &bufferHandle, sizeof(buffer_handle_t));
- *buffer = tempBuffer;
ALOGV("handle = %p, , offset = %d, length = %d",
bufferHandle, (*buffer)->range_length(), (*buffer)->range_offset());
@@ -217,6 +280,10 @@ status_t SurfaceMediaSource::read( MediaBuffer **buffer,
*buffer = NULL;
+ while (mStarted && mNumPendingBuffers == mMaxAcquiredBufferCount) {
+ mMediaBuffersAvailableCondition.wait(mMutex);
+ }
+
// Update the current buffer info
// TODO: mCurrentSlot can be made a bufferstate since there
// can be more than one "current" slots.
@@ -224,7 +291,7 @@ status_t SurfaceMediaSource::read( MediaBuffer **buffer,
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) {
+ while (mStarted) {
status_t err = mBufferQueue->acquireBuffer(&item);
if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
@@ -238,13 +305,14 @@ status_t SurfaceMediaSource::read( MediaBuffer **buffer,
}
// check for the timing of this buffer
- if (mNumFramesReceived == 0) {
+ if (mNumFramesReceived == 0 && !mUseAbsoluteTimestamps) {
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);
+ mBufferQueue->releaseBuffer(item.mBuf, EGL_NO_DISPLAY,
+ EGL_NO_SYNC_KHR, Fence::NO_FENCE);
continue;
}
mStartTimeNs = item.mTimestamp - mStartTimeNs;
@@ -264,7 +332,7 @@ status_t SurfaceMediaSource::read( MediaBuffer **buffer,
// If the loop was exited as a result of stopping the recording,
// it is OK
- if (mStopped) {
+ if (!mStarted) {
ALOGV("Read: SurfaceMediaSource is stopped. Returning ERROR_END_OF_STREAM.");
return ERROR_END_OF_STREAM;
}
@@ -282,6 +350,7 @@ status_t SurfaceMediaSource::read( MediaBuffer **buffer,
mNumFramesEncoded++;
// Pass the data to the MediaBuffer. Pass in only the metadata
+
passMetadataBuffer(buffer, mBufferSlot[mCurrentSlot]->handle);
(*buffer)->setObserver(this);
@@ -291,6 +360,13 @@ status_t SurfaceMediaSource::read( MediaBuffer **buffer,
mNumFramesEncoded, mCurrentTimestamp / 1000,
mCurrentTimestamp / 1000 - prevTimeStamp / 1000);
+ ++mNumPendingBuffers;
+
+#if DEBUG_PENDING_BUFFERS
+ mPendingBuffers.push_back(*buffer);
+#endif
+
+ ALOGV("returning mbuf %p", *buffer);
return OK;
}
@@ -333,7 +409,8 @@ void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) {
ALOGV("Slot %d returned, matches handle = %p", id,
mBufferSlot[id]->handle);
- mBufferQueue->releaseBuffer(id, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+ mBufferQueue->releaseBuffer(id, EGL_NO_DISPLAY, EGL_NO_SYNC_KHR,
+ Fence::NO_FENCE);
buffer->setObserver(0);
buffer->release();
@@ -346,6 +423,18 @@ void SurfaceMediaSource::signalBufferReturned(MediaBuffer *buffer) {
if (!foundBuffer) {
CHECK(!"signalBufferReturned: bogus buffer");
}
+
+#if DEBUG_PENDING_BUFFERS
+ for (size_t i = 0; i < mPendingBuffers.size(); ++i) {
+ if (mPendingBuffers.itemAt(i) == buffer) {
+ mPendingBuffers.removeAt(i);
+ break;
+ }
+ }
+#endif
+
+ --mNumPendingBuffers;
+ mMediaBuffersAvailableCondition.broadcast();
}
// Part of the BufferQueue::ConsumerListener
@@ -374,7 +463,6 @@ void SurfaceMediaSource::onBuffersReleased() {
Mutex::Autolock lock(mMutex);
mFrameAvailableCondition.signal();
- mStopped = true;
for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
mBufferSlot[i] = 0;