Merge "Stagefright: push blank buffers when tearing down" into ics-mr0
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user