summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/omx/GraphicBufferSource.cpp
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2013-07-31 13:50:42 -0700
committerAndreas Huber <andih@google.com>2013-08-13 10:11:46 -0700
commita61285dcf1da8a2cf40c499ee3a7b9fc4d74ac58 (patch)
treea360123ee73434ee45608b03a02d8fb6ff431c3b /media/libstagefright/omx/GraphicBufferSource.cpp
parent1b832c3d8f2b1b24f9bc7025afd2b4a8b4e6c6f9 (diff)
downloadframeworks_av-a61285dcf1da8a2cf40c499ee3a7b9fc4d74ac58.zip
frameworks_av-a61285dcf1da8a2cf40c499ee3a7b9fc4d74ac58.tar.gz
frameworks_av-a61285dcf1da8a2cf40c499ee3a7b9fc4d74ac58.tar.bz2
Optionally repeat the previously submitted frame to the encoder
if no new frame has been delivered by surface flinger within the timeout interval. Change-Id: I282f1b726dfe5646b178d7858d6f5d4f5a264fde
Diffstat (limited to 'media/libstagefright/omx/GraphicBufferSource.cpp')
-rw-r--r--media/libstagefright/omx/GraphicBufferSource.cpp167
1 files changed, 164 insertions, 3 deletions
diff --git a/media/libstagefright/omx/GraphicBufferSource.cpp b/media/libstagefright/omx/GraphicBufferSource.cpp
index 325ffcf..cf43e94 100644
--- a/media/libstagefright/omx/GraphicBufferSource.cpp
+++ b/media/libstagefright/omx/GraphicBufferSource.cpp
@@ -22,6 +22,7 @@
#include <OMX_Core.h>
#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AMessage.h>
#include <media/hardware/MetadataBufferType.h>
#include <ui/GraphicBuffer.h>
@@ -39,7 +40,13 @@ GraphicBufferSource::GraphicBufferSource(OMXNodeInstance* nodeInstance,
mSuspended(false),
mNumFramesAvailable(0),
mEndOfStream(false),
- mEndOfStreamSent(false) {
+ mEndOfStreamSent(false),
+ mRepeatAfterUs(-1ll),
+ mRepeatLastFrameGeneration(0),
+ mLatestSubmittedBufferId(-1),
+ mLatestSubmittedBufferFrameNum(0),
+ mLatestSubmittedBufferUseCount(0),
+ mRepeatBufferDeferred(false) {
ALOGV("GraphicBufferSource w=%u h=%u c=%u",
bufferWidth, bufferHeight, bufferCount);
@@ -123,6 +130,22 @@ void GraphicBufferSource::omxExecuting() {
if (mEndOfStream && mNumFramesAvailable == 0) {
submitEndOfInputStream_l();
}
+
+ if (mRepeatAfterUs > 0ll && mLooper == NULL) {
+ mReflector = new AHandlerReflector<GraphicBufferSource>(this);
+
+ mLooper = new ALooper;
+ mLooper->registerHandler(mReflector);
+ mLooper->start();
+
+ if (mLatestSubmittedBufferId >= 0) {
+ sp<AMessage> msg =
+ new AMessage(kWhatRepeatLastFrame, mReflector->id());
+
+ msg->setInt32("generation", ++mRepeatLastFrameGeneration);
+ msg->post(mRepeatAfterUs);
+ }
+ }
}
void GraphicBufferSource::omxLoaded(){
@@ -132,6 +155,14 @@ void GraphicBufferSource::omxLoaded(){
ALOGW("Dropped back down to Loaded without Executing");
}
+ if (mLooper != NULL) {
+ mLooper->unregisterHandler(mReflector->id());
+ mReflector.clear();
+
+ mLooper->stop();
+ mLooper.clear();
+ }
+
ALOGV("--> loaded; avail=%d eos=%d eosSent=%d",
mNumFramesAvailable, mEndOfStream, mEndOfStreamSent);
@@ -211,8 +242,12 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) {
ALOGV("cbi %d matches bq slot %d, handle=%p",
cbi, id, mBufferSlot[id]->handle);
- mBufferQueue->releaseBuffer(id, codecBuffer.mFrameNumber,
- EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
+ if (id == mLatestSubmittedBufferId) {
+ CHECK_GT(mLatestSubmittedBufferUseCount--, 0);
+ } else {
+ mBufferQueue->releaseBuffer(id, codecBuffer.mFrameNumber,
+ EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
+ }
} else {
ALOGV("codecBufferEmptied: no match for emptied buffer in cbi %d",
cbi);
@@ -232,7 +267,16 @@ void GraphicBufferSource::codecBufferEmptied(OMX_BUFFERHEADERTYPE* header) {
// send that.
ALOGV("buffer freed, EOS pending");
submitEndOfInputStream_l();
+ } else if (mRepeatBufferDeferred) {
+ bool success = repeatLatestSubmittedBuffer_l();
+ if (success) {
+ ALOGV("deferred repeatLatestSubmittedBuffer_l SUCCESS");
+ } else {
+ ALOGV("deferred repeatLatestSubmittedBuffer_l FAILURE");
+ }
+ mRepeatBufferDeferred = false;
}
+
return;
}
@@ -264,6 +308,16 @@ void GraphicBufferSource::suspend(bool suspend) {
}
mSuspended = false;
+
+ if (mExecuting && mNumFramesAvailable == 0 && mRepeatBufferDeferred) {
+ if (repeatLatestSubmittedBuffer_l()) {
+ ALOGV("suspend/deferred repeatLatestSubmittedBuffer_l SUCCESS");
+
+ mRepeatBufferDeferred = false;
+ } else {
+ ALOGV("suspend/deferred repeatLatestSubmittedBuffer_l FAILURE");
+ }
+ }
}
bool GraphicBufferSource::fillCodecBuffer_l() {
@@ -318,11 +372,68 @@ bool GraphicBufferSource::fillCodecBuffer_l() {
EGL_NO_DISPLAY, EGL_NO_SYNC_KHR, Fence::NO_FENCE);
} else {
ALOGV("buffer submitted (bq %d, cbi %d)", item.mBuf, cbi);
+ setLatestSubmittedBuffer_l(item);
+ }
+
+ return true;
+}
+
+bool GraphicBufferSource::repeatLatestSubmittedBuffer_l() {
+ CHECK(mExecuting && mNumFramesAvailable == 0);
+
+ if (mLatestSubmittedBufferId < 0 || mSuspended) {
+ return false;
+ }
+
+ int cbi = findAvailableCodecBuffer_l();
+ if (cbi < 0) {
+ // No buffers available, bail.
+ ALOGV("repeatLatestSubmittedBuffer_l: no codec buffers.");
+ return false;
+ }
+
+ BufferQueue::BufferItem item;
+ item.mBuf = mLatestSubmittedBufferId;
+ item.mFrameNumber = mLatestSubmittedBufferFrameNum;
+
+ status_t err = submitBuffer_l(item, cbi);
+
+ if (err != OK) {
+ return false;
}
+ ++mLatestSubmittedBufferUseCount;
+
return true;
}
+void GraphicBufferSource::setLatestSubmittedBuffer_l(
+ const BufferQueue::BufferItem &item) {
+ ALOGV("setLatestSubmittedBuffer_l");
+
+ if (mLatestSubmittedBufferId >= 0) {
+ if (mLatestSubmittedBufferUseCount == 0) {
+ mBufferQueue->releaseBuffer(
+ mLatestSubmittedBufferId,
+ mLatestSubmittedBufferFrameNum,
+ EGL_NO_DISPLAY,
+ EGL_NO_SYNC_KHR,
+ Fence::NO_FENCE);
+ }
+ }
+
+ mLatestSubmittedBufferId = item.mBuf;
+ mLatestSubmittedBufferFrameNum = item.mFrameNumber;
+ mLatestSubmittedBufferUseCount = 1;
+ mRepeatBufferDeferred = false;
+
+ if (mReflector != NULL) {
+ sp<AMessage> msg = new AMessage(kWhatRepeatLastFrame, mReflector->id());
+ msg->setInt32("generation", ++mRepeatLastFrameGeneration);
+ msg->post(mRepeatAfterUs);
+ }
+}
+
status_t GraphicBufferSource::signalEndOfInputStream() {
Mutex::Autolock autoLock(mMutex);
ALOGV("signalEndOfInputStream: exec=%d avail=%d eos=%d",
@@ -470,6 +581,9 @@ void GraphicBufferSource::onFrameAvailable() {
mNumFramesAvailable++;
+ mRepeatBufferDeferred = false;
+ ++mRepeatLastFrameGeneration;
+
if (mExecuting) {
fillCodecBuffer_l();
}
@@ -495,4 +609,51 @@ void GraphicBufferSource::onBuffersReleased() {
}
}
+status_t GraphicBufferSource::setRepeatPreviousFrameDelayUs(
+ int64_t repeatAfterUs) {
+ Mutex::Autolock autoLock(mMutex);
+
+ if (mExecuting || repeatAfterUs <= 0ll) {
+ return INVALID_OPERATION;
+ }
+
+ mRepeatAfterUs = repeatAfterUs;
+
+ return OK;
+}
+
+void GraphicBufferSource::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatRepeatLastFrame:
+ {
+ Mutex::Autolock autoLock(mMutex);
+
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+
+ if (generation != mRepeatLastFrameGeneration) {
+ // stale
+ break;
+ }
+
+ if (!mExecuting || mNumFramesAvailable > 0) {
+ break;
+ }
+
+ bool success = repeatLatestSubmittedBuffer_l();
+
+ if (success) {
+ ALOGV("repeatLatestSubmittedBuffer_l SUCCESS");
+ } else {
+ ALOGV("repeatLatestSubmittedBuffer_l FAILURE");
+ mRepeatBufferDeferred = true;
+ }
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+}
+
} // namespace android