@@ -2010,6 +2010,157 @@ OMXCodec::BufferInfo* OMXCodec::dequeueBufferFromNativeWindow() {
20102010 return bufInfo;
20112011}
20122012
2013+ status_t OMXCodec::pushBlankBuffersToNativeWindow () {
2014+ status_t err = NO_ERROR;
2015+ ANativeWindowBuffer* anb = NULL ;
2016+ int numBufs = 0 ;
2017+ int minUndequeuedBufs = 0 ;
2018+
2019+ // We need to reconnect to the ANativeWindow as a CPU client to ensure that
2020+ // no frames get dropped by SurfaceFlinger assuming that these are video
2021+ // frames.
2022+ err = native_window_api_disconnect (mNativeWindow .get (),
2023+ NATIVE_WINDOW_API_MEDIA);
2024+ if (err != NO_ERROR) {
2025+ LOGE (" error pushing blank frames: api_disconnect failed: %s (%d)" ,
2026+ strerror (-err), -err);
2027+ return err;
2028+ }
2029+
2030+ err = native_window_api_connect (mNativeWindow .get (),
2031+ NATIVE_WINDOW_API_CPU);
2032+ if (err != NO_ERROR) {
2033+ LOGE (" error pushing blank frames: api_connect failed: %s (%d)" ,
2034+ strerror (-err), -err);
2035+ return err;
2036+ }
2037+
2038+ err = native_window_set_scaling_mode (mNativeWindow .get (),
2039+ NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
2040+ if (err != NO_ERROR) {
2041+ LOGE (" error pushing blank frames: set_buffers_geometry failed: %s (%d)" ,
2042+ strerror (-err), -err);
2043+ goto error;
2044+ }
2045+
2046+ err = native_window_set_buffers_geometry (mNativeWindow .get (), 1 , 1 ,
2047+ HAL_PIXEL_FORMAT_RGBX_8888);
2048+ if (err != NO_ERROR) {
2049+ LOGE (" error pushing blank frames: set_buffers_geometry failed: %s (%d)" ,
2050+ strerror (-err), -err);
2051+ goto error;
2052+ }
2053+
2054+ err = native_window_set_usage (mNativeWindow .get (),
2055+ GRALLOC_USAGE_SW_WRITE_OFTEN);
2056+ if (err != NO_ERROR) {
2057+ LOGE (" error pushing blank frames: set_usage failed: %s (%d)" ,
2058+ strerror (-err), -err);
2059+ goto error;
2060+ }
2061+
2062+ err = mNativeWindow ->query (mNativeWindow .get (),
2063+ NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs);
2064+ if (err != NO_ERROR) {
2065+ LOGE (" error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query "
2066+ " failed: %s (%d)" , strerror (-err), -err);
2067+ goto error;
2068+ }
2069+
2070+ numBufs = minUndequeuedBufs + 1 ;
2071+ err = native_window_set_buffer_count (mNativeWindow .get (), numBufs);
2072+ if (err != NO_ERROR) {
2073+ LOGE (" error pushing blank frames: set_buffer_count failed: %s (%d)" ,
2074+ strerror (-err), -err);
2075+ goto error;
2076+ }
2077+
2078+ // We push numBufs + 1 buffers to ensure that we've drawn into the same
2079+ // buffer twice. This should guarantee that the buffer has been displayed
2080+ // on the screen and then been replaced, so an previous video frames are
2081+ // guaranteed NOT to be currently displayed.
2082+ for (int i = 0 ; i < numBufs + 1 ; i++) {
2083+ err = mNativeWindow ->dequeueBuffer (mNativeWindow .get (), &anb);
2084+ if (err != NO_ERROR) {
2085+ LOGE (" error pushing blank frames: dequeueBuffer failed: %s (%d)" ,
2086+ strerror (-err), -err);
2087+ goto error;
2088+ }
2089+
2090+ sp<GraphicBuffer> buf (new GraphicBuffer (anb, false ));
2091+ err = mNativeWindow ->lockBuffer (mNativeWindow .get (),
2092+ buf->getNativeBuffer ());
2093+ if (err != NO_ERROR) {
2094+ LOGE (" error pushing blank frames: lockBuffer failed: %s (%d)" ,
2095+ strerror (-err), -err);
2096+ goto error;
2097+ }
2098+
2099+ // Fill the buffer with the a 1x1 checkerboard pattern ;)
2100+ uint32_t * img = NULL ;
2101+ err = buf->lock (GRALLOC_USAGE_SW_WRITE_OFTEN, (void **)(&img));
2102+ if (err != NO_ERROR) {
2103+ LOGE (" error pushing blank frames: lock failed: %s (%d)" ,
2104+ strerror (-err), -err);
2105+ goto error;
2106+ }
2107+
2108+ *img = 0 ;
2109+
2110+ err = buf->unlock ();
2111+ if (err != NO_ERROR) {
2112+ LOGE (" error pushing blank frames: unlock failed: %s (%d)" ,
2113+ strerror (-err), -err);
2114+ goto error;
2115+ }
2116+
2117+ err = mNativeWindow ->queueBuffer (mNativeWindow .get (),
2118+ buf->getNativeBuffer ());
2119+ if (err != NO_ERROR) {
2120+ LOGE (" error pushing blank frames: queueBuffer failed: %s (%d)" ,
2121+ strerror (-err), -err);
2122+ goto error;
2123+ }
2124+
2125+ anb = NULL ;
2126+ }
2127+
2128+ error:
2129+
2130+ if (err != NO_ERROR) {
2131+ // Clean up after an error.
2132+ if (anb != NULL ) {
2133+ mNativeWindow ->cancelBuffer (mNativeWindow .get (), anb);
2134+ }
2135+
2136+ native_window_api_disconnect (mNativeWindow .get (),
2137+ NATIVE_WINDOW_API_CPU);
2138+ native_window_api_connect (mNativeWindow .get (),
2139+ NATIVE_WINDOW_API_MEDIA);
2140+
2141+ return err;
2142+ } else {
2143+ // Clean up after success.
2144+ err = native_window_api_disconnect (mNativeWindow .get (),
2145+ NATIVE_WINDOW_API_CPU);
2146+ if (err != NO_ERROR) {
2147+ LOGE (" error pushing blank frames: api_disconnect failed: %s (%d)" ,
2148+ strerror (-err), -err);
2149+ return err;
2150+ }
2151+
2152+ err = native_window_api_connect (mNativeWindow .get (),
2153+ NATIVE_WINDOW_API_MEDIA);
2154+ if (err != NO_ERROR) {
2155+ LOGE (" error pushing blank frames: api_connect failed: %s (%d)" ,
2156+ strerror (-err), -err);
2157+ return err;
2158+ }
2159+
2160+ return NO_ERROR;
2161+ }
2162+ }
2163+
20132164int64_t OMXCodec::retrieveDecodingTimeUs (bool isCodecSpecific) {
20142165 CHECK (mIsEncoder );
20152166
@@ -2598,6 +2749,15 @@ void OMXCodec::onStateChange(OMX_STATETYPE newState) {
25982749 mPortStatus [kPortIndexInput ] = ENABLED;
25992750 mPortStatus [kPortIndexOutput ] = ENABLED;
26002751
2752+ if ((mFlags & kEnableGrallocUsageProtected ) &&
2753+ mNativeWindow != NULL ) {
2754+ // We push enough 1x1 blank buffers to ensure that one of
2755+ // them has made it to the display. This allows the OMX
2756+ // component teardown to zero out any protected buffers
2757+ // without the risk of scanning out one of those buffers.
2758+ pushBlankBuffersToNativeWindow ();
2759+ }
2760+
26012761 setState (IDLE_TO_LOADED);
26022762 }
26032763 break ;
0 commit comments