diff options
author | Jamie Gennis <jgennis@google.com> | 2011-10-26 20:34:38 +0000 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2011-10-26 20:34:38 +0000 |
commit | 5ded5fc55f2da2af0a76a9ddc52d27948b227037 (patch) | |
tree | 56d574dfaee8cd32f7f732a90e247f5cedafc1f5 /media | |
parent | 6f444425fe1bb62e12973c5df6a3161bc2aa2ce7 (diff) | |
parent | b7b4eaaa05284634d50d581d924a250f1194f66d (diff) | |
download | frameworks_base-5ded5fc55f2da2af0a76a9ddc52d27948b227037.zip frameworks_base-5ded5fc55f2da2af0a76a9ddc52d27948b227037.tar.gz frameworks_base-5ded5fc55f2da2af0a76a9ddc52d27948b227037.tar.bz2 |
am b7b4eaaa: Merge "Stagefright: push blank buffers when tearing down" into ics-mr0
* commit 'b7b4eaaa05284634d50d581d924a250f1194f66d':
Stagefright: push blank buffers when tearing down
Diffstat (limited to 'media')
-rwxr-xr-x | media/libstagefright/OMXCodec.cpp | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 7e55790..dfd3f4a 100755 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -2010,6 +2010,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); @@ -2598,6 +2749,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; |