diff options
author | Andreas Huber <andih@google.com> | 2012-05-22 12:55:03 -0700 |
---|---|---|
committer | Andreas Huber <andih@google.com> | 2012-05-22 12:55:03 -0700 |
commit | bc098410be55f9d96f394b3981a0c482b83859b6 (patch) | |
tree | 45681d846f6862d558b04be1a4b36bb4a2b4c54f /media | |
parent | a6490c65f93e1cbe969fba499978e8d64214108a (diff) | |
download | frameworks_av-bc098410be55f9d96f394b3981a0c482b83859b6.zip frameworks_av-bc098410be55f9d96f394b3981a0c482b83859b6.tar.gz frameworks_av-bc098410be55f9d96f394b3981a0c482b83859b6.tar.bz2 |
Tell surface flinger that we want to protect output buffers from being
sent to HDMI (without HDCP) and push a few black frames on IDLE->LOADED
similar to OMXCodec's behaviour.
Change-Id: Iea6055a115151ca881220a70a31af6ade2c58cb3
related-to-bug: 6537187
Diffstat (limited to 'media')
-rw-r--r-- | media/libstagefright/ACodec.cpp | 174 | ||||
-rw-r--r-- | media/libstagefright/NuMediaExtractor.cpp | 6 |
2 files changed, 180 insertions, 0 deletions
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 2a8b3b6..b2f1746 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -520,6 +520,29 @@ status_t ACodec::allocateOutputBuffersFromNativeWindow() { usage = 0; } + if (mFlags & kFlagIsSecure) { + usage |= GRALLOC_USAGE_PROTECTED; + } + + // Make sure to check whether either Stagefright or the video decoder + // requested protected buffers. + if (usage & GRALLOC_USAGE_PROTECTED) { + // Verify that the ANativeWindow sends images directly to + // SurfaceFlinger. + int queuesToNativeWindow = 0; + err = mNativeWindow->query( + mNativeWindow.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, + &queuesToNativeWindow); + if (err != 0) { + ALOGE("error authenticating native window: %d", err); + return err; + } + if (queuesToNativeWindow != 1) { + ALOGE("native window could not be authenticated"); + return PERMISSION_DENIED; + } + } + err = native_window_set_usage( mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP); @@ -2103,6 +2126,149 @@ void ACodec::signalError(OMX_ERRORTYPE error, status_t internalError) { notify->post(); } +status_t ACodec::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) { + ALOGE("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) { + ALOGE("error pushing blank frames: api_connect failed: %s (%d)", + strerror(-err), -err); + return err; + } + + err = native_window_set_buffers_geometry(mNativeWindow.get(), 1, 1, + HAL_PIXEL_FORMAT_RGBX_8888); + if (err != NO_ERROR) { + ALOGE("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) { + ALOGE("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) { + ALOGE("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) { + ALOGE("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) { + ALOGE("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) { + ALOGE("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) { + ALOGE("error pushing blank frames: lock failed: %s (%d)", + strerror(-err), -err); + goto error; + } + + *img = 0; + + err = buf->unlock(); + if (err != NO_ERROR) { + ALOGE("error pushing blank frames: unlock failed: %s (%d)", + strerror(-err), -err); + goto error; + } + + err = mNativeWindow->queueBuffer(mNativeWindow.get(), + buf->getNativeBuffer()); + if (err != NO_ERROR) { + ALOGE("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) { + ALOGE("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) { + ALOGE("error pushing blank frames: api_connect failed: %s (%d)", + strerror(-err), -err); + return err; + } + + return NO_ERROR; + } +} + //////////////////////////////////////////////////////////////////////////////// ACodec::PortDescription::PortDescription() { @@ -3417,6 +3583,14 @@ void ACodec::ExecutingToIdleState::changeStateIfWeOwnAllBuffers() { CHECK_EQ(mCodec->freeBuffersOnPort(kPortIndexInput), (status_t)OK); CHECK_EQ(mCodec->freeBuffersOnPort(kPortIndexOutput), (status_t)OK); + if (mCodec->mFlags & kFlagIsSecure && mCodec->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. + mCodec->pushBlankBuffersToNativeWindow(); + } + mCodec->changeState(mCodec->mIdleToLoadedState); } } diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp index cfe4773..29e1d21 100644 --- a/media/libstagefright/NuMediaExtractor.cpp +++ b/media/libstagefright/NuMediaExtractor.cpp @@ -325,6 +325,12 @@ ssize_t NuMediaExtractor::fetchTrackSamples( CHECK(info->mSample == NULL); info->mFinalResult = err; + + if (info->mFinalResult != ERROR_END_OF_STREAM) { + ALOGW("read on track %d failed with error %d", + info->mTrackIndex, err); + } + info->mSampleTimeUs = -1ll; continue; } else { |