Skip to content

Commit c0e4293

Browse files
author
Jamie Gennis
committed
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
1 parent be25d5b commit c0e4293

File tree

2 files changed

+161
-0
lines changed

2 files changed

+161
-0
lines changed

include/media/stagefright/OMXCodec.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ struct OMXCodec : public MediaSource,
277277
status_t queueBufferToNativeWindow(BufferInfo *info);
278278
status_t cancelBufferToNativeWindow(BufferInfo *info);
279279
BufferInfo* dequeueBufferFromNativeWindow();
280+
status_t pushBlankBuffersToNativeWindow();
280281

281282
status_t freeBuffersOnPort(
282283
OMX_U32 portIndex, bool onlyThoseWeOwn = false);

media/libstagefright/OMXCodec.cpp

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2001,6 +2001,157 @@ OMXCodec::BufferInfo* OMXCodec::dequeueBufferFromNativeWindow() {
20012001
return bufInfo;
20022002
}
20032003

2004+
status_t OMXCodec::pushBlankBuffersToNativeWindow() {
2005+
status_t err = NO_ERROR;
2006+
ANativeWindowBuffer* anb = NULL;
2007+
int numBufs = 0;
2008+
int minUndequeuedBufs = 0;
2009+
2010+
// We need to reconnect to the ANativeWindow as a CPU client to ensure that
2011+
// no frames get dropped by SurfaceFlinger assuming that these are video
2012+
// frames.
2013+
err = native_window_api_disconnect(mNativeWindow.get(),
2014+
NATIVE_WINDOW_API_MEDIA);
2015+
if (err != NO_ERROR) {
2016+
LOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
2017+
strerror(-err), -err);
2018+
return err;
2019+
}
2020+
2021+
err = native_window_api_connect(mNativeWindow.get(),
2022+
NATIVE_WINDOW_API_CPU);
2023+
if (err != NO_ERROR) {
2024+
LOGE("error pushing blank frames: api_connect failed: %s (%d)",
2025+
strerror(-err), -err);
2026+
return err;
2027+
}
2028+
2029+
err = native_window_set_scaling_mode(mNativeWindow.get(),
2030+
NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
2031+
if (err != NO_ERROR) {
2032+
LOGE("error pushing blank frames: set_buffers_geometry failed: %s (%d)",
2033+
strerror(-err), -err);
2034+
goto error;
2035+
}
2036+
2037+
err = native_window_set_buffers_geometry(mNativeWindow.get(), 1, 1,
2038+
HAL_PIXEL_FORMAT_RGBX_8888);
2039+
if (err != NO_ERROR) {
2040+
LOGE("error pushing blank frames: set_buffers_geometry failed: %s (%d)",
2041+
strerror(-err), -err);
2042+
goto error;
2043+
}
2044+
2045+
err = native_window_set_usage(mNativeWindow.get(),
2046+
GRALLOC_USAGE_SW_WRITE_OFTEN);
2047+
if (err != NO_ERROR) {
2048+
LOGE("error pushing blank frames: set_usage failed: %s (%d)",
2049+
strerror(-err), -err);
2050+
goto error;
2051+
}
2052+
2053+
err = mNativeWindow->query(mNativeWindow.get(),
2054+
NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
2055+
if (err != NO_ERROR) {
2056+
LOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query "
2057+
"failed: %s (%d)", strerror(-err), -err);
2058+
goto error;
2059+
}
2060+
2061+
numBufs = minUndequeuedBufs + 1;
2062+
err = native_window_set_buffer_count(mNativeWindow.get(), numBufs);
2063+
if (err != NO_ERROR) {
2064+
LOGE("error pushing blank frames: set_buffer_count failed: %s (%d)",
2065+
strerror(-err), -err);
2066+
goto error;
2067+
}
2068+
2069+
// We push numBufs + 1 buffers to ensure that we've drawn into the same
2070+
// buffer twice. This should guarantee that the buffer has been displayed
2071+
// on the screen and then been replaced, so an previous video frames are
2072+
// guaranteed NOT to be currently displayed.
2073+
for (int i = 0; i < numBufs + 1; i++) {
2074+
err = mNativeWindow->dequeueBuffer(mNativeWindow.get(), &anb);
2075+
if (err != NO_ERROR) {
2076+
LOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)",
2077+
strerror(-err), -err);
2078+
goto error;
2079+
}
2080+
2081+
sp<GraphicBuffer> buf(new GraphicBuffer(anb, false));
2082+
err = mNativeWindow->lockBuffer(mNativeWindow.get(),
2083+
buf->getNativeBuffer());
2084+
if (err != NO_ERROR) {
2085+
LOGE("error pushing blank frames: lockBuffer failed: %s (%d)",
2086+
strerror(-err), -err);
2087+
goto error;
2088+
}
2089+
2090+
// Fill the buffer with the a 1x1 checkerboard pattern ;)
2091+
uint32_t* img = NULL;
2092+
err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
2093+
if (err != NO_ERROR) {
2094+
LOGE("error pushing blank frames: lock failed: %s (%d)",
2095+
strerror(-err), -err);
2096+
goto error;
2097+
}
2098+
2099+
*img = 0;
2100+
2101+
err = buf->unlock();
2102+
if (err != NO_ERROR) {
2103+
LOGE("error pushing blank frames: unlock failed: %s (%d)",
2104+
strerror(-err), -err);
2105+
goto error;
2106+
}
2107+
2108+
err = mNativeWindow->queueBuffer(mNativeWindow.get(),
2109+
buf->getNativeBuffer());
2110+
if (err != NO_ERROR) {
2111+
LOGE("error pushing blank frames: queueBuffer failed: %s (%d)",
2112+
strerror(-err), -err);
2113+
goto error;
2114+
}
2115+
2116+
anb = NULL;
2117+
}
2118+
2119+
error:
2120+
2121+
if (err != NO_ERROR) {
2122+
// Clean up after an error.
2123+
if (anb != NULL) {
2124+
mNativeWindow->cancelBuffer(mNativeWindow.get(), anb);
2125+
}
2126+
2127+
native_window_api_disconnect(mNativeWindow.get(),
2128+
NATIVE_WINDOW_API_CPU);
2129+
native_window_api_connect(mNativeWindow.get(),
2130+
NATIVE_WINDOW_API_MEDIA);
2131+
2132+
return err;
2133+
} else {
2134+
// Clean up after success.
2135+
err = native_window_api_disconnect(mNativeWindow.get(),
2136+
NATIVE_WINDOW_API_CPU);
2137+
if (err != NO_ERROR) {
2138+
LOGE("error pushing blank frames: api_disconnect failed: %s (%d)",
2139+
strerror(-err), -err);
2140+
return err;
2141+
}
2142+
2143+
err = native_window_api_connect(mNativeWindow.get(),
2144+
NATIVE_WINDOW_API_MEDIA);
2145+
if (err != NO_ERROR) {
2146+
LOGE("error pushing blank frames: api_connect failed: %s (%d)",
2147+
strerror(-err), -err);
2148+
return err;
2149+
}
2150+
2151+
return NO_ERROR;
2152+
}
2153+
}
2154+
20042155
int64_t OMXCodec::retrieveDecodingTimeUs(bool isCodecSpecific) {
20052156
CHECK(mIsEncoder);
20062157

@@ -2589,6 +2740,15 @@ void OMXCodec::onStateChange(OMX_STATETYPE newState) {
25892740
mPortStatus[kPortIndexInput] = ENABLED;
25902741
mPortStatus[kPortIndexOutput] = ENABLED;
25912742

2743+
if ((mFlags & kEnableGrallocUsageProtected) &&
2744+
mNativeWindow != NULL) {
2745+
// We push enough 1x1 blank buffers to ensure that one of
2746+
// them has made it to the display. This allows the OMX
2747+
// component teardown to zero out any protected buffers
2748+
// without the risk of scanning out one of those buffers.
2749+
pushBlankBuffersToNativeWindow();
2750+
}
2751+
25922752
setState(IDLE_TO_LOADED);
25932753
}
25942754
break;

0 commit comments

Comments
 (0)