summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJamie Gennis <jgennis@google.com>2011-10-25 14:50:16 -0700
committerJamie Gennis <jgennis@google.com>2011-10-25 18:35:02 -0700
commit1765d6e0c962d2b89897c0278f969084f632d181 (patch)
tree236c1712a02b293093d658a3248804ebaf4f3786
parent55f4bc5c3d1acfaa735b8b19cf34b6b68f6cfcca (diff)
Stagefright: push blank buffers when tearing down
This change makes OMXCodec push RGB 565 buffers filled with black to an ANativeWindow when tearing down after decoding to protected gralloc buffers. This allows the OMX tear down to zero out any protected buffers that were used without the possibility that the buffer is still being used by SurfaceFlinger or HWComposer. Bug: 5483222 Change-Id: I8acedd81a7bb67dfdc2fd15733e3375b6ce8d560
-rw-r--r--include/media/stagefright/OMXCodec.h1
-rwxr-xr-xmedia/libstagefright/OMXCodec.cpp160
2 files changed, 161 insertions, 0 deletions
diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h
index 0d5a7263..c21d19d4 100644
--- a/include/media/stagefright/OMXCodec.h
+++ b/include/media/stagefright/OMXCodec.h
@@ -277,6 +277,7 @@ private:
status_t queueBufferToNativeWindow(BufferInfo *info);
status_t cancelBufferToNativeWindow(BufferInfo *info);
BufferInfo* dequeueBufferFromNativeWindow();
+ status_t pushBlankBuffersToNativeWindow();
status_t freeBuffersOnPort(
OMX_U32 portIndex, bool onlyThoseWeOwn = false);
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 00d414ce..b20bfcb7 100755
--- a/media/libstagefright/OMXCodec.cpp
+++ b/media/libstagefright/OMXCodec.cpp
@@ -2001,6 +2001,157 @@ OMXCodec::BufferInfo* OMXCodec::dequeueBufferFromNativeWindow() {
return bufInfo;
}
+status_t OMXCodec::pushBlankBuffersToNativeWindow() {
+ status_t err = NO_ERROR;
+ ANativeWindowBuffer* anb = NULL;
+ int numBufs = 0;
+ int minUndequeuedBufs = 0;
+
+ // We need to reconnect to the ANativeWindow as a CPU client to ensure that
+ // no frames get dropped by SurfaceFlinger assuming that these are video
+ // frames.
+ err = native_window_api_disconnect(mNativeWindow.get(),
+ NATIVE_WINDOW_API_MEDIA);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+
+ err = native_window_api_connect(mNativeWindow.get(),
+ NATIVE_WINDOW_API_CPU);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: api_connect failed: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+
+ err = native_window_set_scaling_mode(mNativeWindow.get(),
+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: set_buffers_geometry failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ err = native_window_set_buffers_geometry(mNativeWindow.get(), 1, 1,
+ HAL_PIXEL_FORMAT_RGBX_8888);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: set_buffers_geometry failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ err = native_window_set_usage(mNativeWindow.get(),
+ GRALLOC_USAGE_SW_WRITE_OFTEN);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: set_usage failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ err = mNativeWindow->query(mNativeWindow.get(),
+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query "
+ "failed: %s (%d)", strerror(-err), -err);
+ goto error;
+ }
+
+ numBufs = minUndequeuedBufs + 1;
+ err = native_window_set_buffer_count(mNativeWindow.get(), numBufs);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: set_buffer_count failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ // We push numBufs + 1 buffers to ensure that we've drawn into the same
+ // buffer twice. This should guarantee that the buffer has been displayed
+ // on the screen and then been replaced, so an previous video frames are
+ // guaranteed NOT to be currently displayed.
+ for (int i = 0; i < numBufs + 1; i++) {
+ err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &anb);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
+ err = mNativeWindow->lockBuffer(mNativeWindow.get(),
+ buf->getNativeBuffer());
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: lockBuffer failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ // Fill the buffer with the a 1x1 checkerboard pattern ;)
+ uint32_t* img = NULL;
+ err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: lock failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ *img = 0;
+
+ err = buf->unlock();
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: unlock failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ err = mNativeWindow->queueBuffer(mNativeWindow.get(),
+ buf->getNativeBuffer());
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: queueBuffer failed: %s (%d)",
+ strerror(-err), -err);
+ goto error;
+ }
+
+ anb = NULL;
+ }
+
+error:
+
+ if (err != NO_ERROR) {
+ // Clean up after an error.
+ if (anb != NULL) {
+ mNativeWindow->cancelBuffer(mNativeWindow.get(), anb);
+ }
+
+ native_window_api_disconnect(mNativeWindow.get(),
+ NATIVE_WINDOW_API_CPU);
+ native_window_api_connect(mNativeWindow.get(),
+ NATIVE_WINDOW_API_MEDIA);
+
+ return err;
+ } else {
+ // Clean up after success.
+ err = native_window_api_disconnect(mNativeWindow.get(),
+ NATIVE_WINDOW_API_CPU);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+
+ err = native_window_api_connect(mNativeWindow.get(),
+ NATIVE_WINDOW_API_MEDIA);
+ if (err != NO_ERROR) {
+ LOGE("error pushing blank frames: api_connect failed: %s (%d)",
+ strerror(-err), -err);
+ return err;
+ }
+
+ return NO_ERROR;
+ }
+}
+
int64_t OMXCodec::retrieveDecodingTimeUs(bool isCodecSpecific) {
CHECK(mIsEncoder);
@@ -2589,6 +2740,15 @@ void OMXCodec::onStateChange(OMX_STATETYPE newState) {
mPortStatus[kPortIndexInput] = ENABLED;
mPortStatus[kPortIndexOutput] = ENABLED;
+ if ((mFlags & kEnableGrallocUsageProtected) &&
+ mNativeWindow != NULL) {
+ // We push enough 1x1 blank buffers to ensure that one of
+ // them has made it to the display. This allows the OMX
+ // component teardown to zero out any protected buffers
+ // without the risk of scanning out one of those buffers.
+ pushBlankBuffersToNativeWindow();
+ }
+
setState(IDLE_TO_LOADED);
}
break;