summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/OMXCodec.cpp
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 /media/libstagefright/OMXCodec.cpp
parent55f4bc5c3d1acfaa735b8b19cf34b6b68f6cfcca (diff)
downloadframeworks_av-1765d6e0c962d2b89897c0278f969084f632d181.zip
frameworks_av-1765d6e0c962d2b89897c0278f969084f632d181.tar.gz
frameworks_av-1765d6e0c962d2b89897c0278f969084f632d181.tar.bz2
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
Diffstat (limited to 'media/libstagefright/OMXCodec.cpp')
-rwxr-xr-xmedia/libstagefright/OMXCodec.cpp160
1 files changed, 160 insertions, 0 deletions
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp
index 00d414c..b20bfcb 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;