diff options
author | Lajos Molnar <lajos@google.com> | 2015-05-06 14:01:08 -0700 |
---|---|---|
committer | Lajos Molnar <lajos@google.com> | 2015-05-07 11:46:15 -0700 |
commit | b2d0b487efd40700199852c9a18b369b1651f15b (patch) | |
tree | abfee9d4cd5df8e4e99d3cb6b5350ef54d543011 | |
parent | 70c75d8c15707d5eade38fe3e622f8500c29556b (diff) | |
download | frameworks_av-b2d0b487efd40700199852c9a18b369b1651f15b.zip frameworks_av-b2d0b487efd40700199852c9a18b369b1651f15b.tar.gz frameworks_av-b2d0b487efd40700199852c9a18b369b1651f15b.tar.bz2 |
stagefright: move native window helpers into SurfaceUtils
Bug: 20885565
Change-Id: I2ed14be8a7cb08b1ed4ea65cb9286dc1384fe64a
-rw-r--r-- | include/media/stagefright/ACodec.h | 5 | ||||
-rw-r--r-- | include/media/stagefright/OMXCodec.h | 2 | ||||
-rw-r--r-- | include/media/stagefright/SurfaceUtils.h | 34 | ||||
-rw-r--r-- | media/libstagefright/ACodec.cpp | 212 | ||||
-rw-r--r-- | media/libstagefright/Android.mk | 1 | ||||
-rw-r--r-- | media/libstagefright/OMXCodec.cpp | 240 | ||||
-rw-r--r-- | media/libstagefright/SurfaceUtils.cpp | 215 |
7 files changed, 268 insertions, 441 deletions
diff --git a/include/media/stagefright/ACodec.h b/include/media/stagefright/ACodec.h index cdb923d..0a54df9 100644 --- a/include/media/stagefright/ACodec.h +++ b/include/media/stagefright/ACodec.h @@ -236,9 +236,6 @@ private: status_t freeBuffer(OMX_U32 portIndex, size_t i); status_t handleSetSurface(const sp<Surface> &surface); - status_t setNativeWindowSizeFormatAndUsage( - ANativeWindow *nativeWindow /* nonnull */, - int width, int height, int format, int rotation, int usage); status_t setupNativeWindowSizeFormatAndUsage(ANativeWindow *nativeWindow /* nonnull */); status_t configureOutputBuffersFromNativeWindow( @@ -332,8 +329,6 @@ private: status_t initNativeWindow(); - status_t pushBlankBuffersToNativeWindow(); - // Returns true iff all buffers on the given port have status // OWNED_BY_US or OWNED_BY_NATIVE_WINDOW. bool allYourBuffersAreBelongToUs(OMX_U32 portIndex); diff --git a/include/media/stagefright/OMXCodec.h b/include/media/stagefright/OMXCodec.h index 84b1b1a..7fabcb3 100644 --- a/include/media/stagefright/OMXCodec.h +++ b/include/media/stagefright/OMXCodec.h @@ -298,7 +298,6 @@ 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); @@ -347,7 +346,6 @@ private: status_t configureCodec(const sp<MetaData> &meta); - status_t applyRotation(); status_t waitForBufferFilled_l(); int64_t getDecodingTimeUs(); diff --git a/include/media/stagefright/SurfaceUtils.h b/include/media/stagefright/SurfaceUtils.h new file mode 100644 index 0000000..c1a9c0a --- /dev/null +++ b/include/media/stagefright/SurfaceUtils.h @@ -0,0 +1,34 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef SURFACE_UTILS_H_ + +#define SURFACE_UTILS_H_ + +#include <utils/Errors.h> + +struct ANativeWindow; + +namespace android { + +status_t setNativeWindowSizeFormatAndUsage( + ANativeWindow *nativeWindow /* nonnull */, + int width, int height, int format, int rotation, int usage); +status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */); + +} // namespace android + +#endif // SURFACE_UTILS_H_ diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp index 22395cc..134bdae 100644 --- a/media/libstagefright/ACodec.cpp +++ b/media/libstagefright/ACodec.cpp @@ -42,6 +42,7 @@ #include <media/stagefright/OMXClient.h> #include <media/stagefright/OMXCodec.h> #include <media/stagefright/PersistentSurface.h> +#include <media/stagefright/SurfaceUtils.h> #include <media/hardware/HardwareAPI.h> #include <OMX_AudioExt.h> @@ -748,82 +749,6 @@ status_t ACodec::allocateBuffersOnPort(OMX_U32 portIndex) { return OK; } -status_t ACodec::setNativeWindowSizeFormatAndUsage( - ANativeWindow *nativeWindow /* nonnull */, - int width, int height, int format, int rotation, int usage) { - status_t err = native_window_set_buffers_dimensions(nativeWindow, width, height); - if (err != 0) { - ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", strerror(-err), -err); - return err; - } - - err = native_window_set_buffers_format(nativeWindow, format); - if (err != 0) { - ALOGE("native_window_set_buffers_format failed: %s (%d)", strerror(-err), -err); - return err; - } - - int transform = 0; - if ((rotation % 90) == 0) { - switch ((rotation / 90) & 3) { - case 1: transform = HAL_TRANSFORM_ROT_90; break; - case 2: transform = HAL_TRANSFORM_ROT_180; break; - case 3: transform = HAL_TRANSFORM_ROT_270; break; - default: transform = 0; break; - } - } - - err = native_window_set_buffers_transform(nativeWindow, transform); - if (err != 0) { - ALOGE("native_window_set_buffers_transform failed: %s (%d)", strerror(-err), -err); - return err; - } - - // 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 = nativeWindow->query( - nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &queuesToNativeWindow); - if (err != 0) { - ALOGE("error authenticating native window: %s (%d)", strerror(-err), -err); - return err; - } - if (queuesToNativeWindow != 1) { - ALOGE("native window could not be authenticated"); - return PERMISSION_DENIED; - } - } - - int consumerUsage = 0; - err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage); - if (err != 0) { - ALOGW("failed to get consumer usage bits. ignoring"); - err = 0; - } - - int finalUsage = usage | consumerUsage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP; - ALOGV("gralloc usage: %#x(ACodec) + %#x(Consumer) = %#x", usage, consumerUsage, finalUsage); - err = native_window_set_usage(nativeWindow, finalUsage); - if (err != 0) { - ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err); - return err; - } - - err = native_window_set_scaling_mode( - nativeWindow, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - if (err != 0) { - ALOGE("native_window_set_scaling_mode failed: %s (%d)", strerror(-err), -err); - return err; - } - - ALOGD("set up nativeWindow %p for %dx%d, color %#x, rotation %d, usage %#x", - nativeWindow, width, height, format, rotation, finalUsage); - return OK; -} - status_t ACodec::setupNativeWindowSizeFormatAndUsage(ANativeWindow *nativeWindow /* nonnull */) { OMX_PARAM_PORTDEFINITIONTYPE def; InitOMXParams(&def); @@ -849,6 +774,8 @@ status_t ACodec::setupNativeWindowSizeFormatAndUsage(ANativeWindow *nativeWindow usage |= GRALLOC_USAGE_PROTECTED; } + usage |= GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP; + ALOGV("gralloc usage: %#x(OMX) => %#x(ACodec)", omxUsage, usage); return setNativeWindowSizeFormatAndUsage( nativeWindow, @@ -4123,137 +4050,6 @@ 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 = setNativeWindowSizeFormatAndUsage( - mNativeWindow.get(), 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set format failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - static_cast<Surface*>(mNativeWindow.get()) - ->getIGraphicBufferProducer()->allowAllocation(true); - - 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 = native_window_dequeue_buffer_and_wait(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)); - - // 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(), -1); - 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, -1); - } - - 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() { @@ -6148,7 +5944,7 @@ void ACodec::ExecutingToIdleState::changeStateIfWeOwnAllBuffers() { // 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(); + pushBlankBuffersToNativeWindow(mCodec->mNativeWindow.get()); } mCodec->changeState(mCodec->mIdleToLoadedState); diff --git a/media/libstagefright/Android.mk b/media/libstagefright/Android.mk index 45581f3..fa17b2e 100644 --- a/media/libstagefright/Android.mk +++ b/media/libstagefright/Android.mk @@ -57,6 +57,7 @@ LOCAL_SRC_FILES:= \ StagefrightMediaScanner.cpp \ StagefrightMetadataRetriever.cpp \ SurfaceMediaSource.cpp \ + SurfaceUtils.cpp \ ThrottledSource.cpp \ TimeSource.cpp \ TimedEventQueue.cpp \ diff --git a/media/libstagefright/OMXCodec.cpp b/media/libstagefright/OMXCodec.cpp index 8d4bab8..aa6a7c0 100644 --- a/media/libstagefright/OMXCodec.cpp +++ b/media/libstagefright/OMXCodec.cpp @@ -43,6 +43,7 @@ #include <media/stagefright/MediaExtractor.h> #include <media/stagefright/MetaData.h> #include <media/stagefright/OMXCodec.h> +#include <media/stagefright/SurfaceUtils.h> #include <media/stagefright/Utils.h> #include <media/stagefright/SkipCutBuffer.h> #include <utils/Vector.h> @@ -1783,35 +1784,6 @@ status_t OMXCodec::allocateBuffersOnPort(OMX_U32 portIndex) { return OK; } -status_t OMXCodec::applyRotation() { - sp<MetaData> meta = mSource->getFormat(); - - int32_t rotationDegrees; - if (!meta->findInt32(kKeyRotation, &rotationDegrees)) { - rotationDegrees = 0; - } - - uint32_t transform; - switch (rotationDegrees) { - case 0: transform = 0; break; - case 90: transform = HAL_TRANSFORM_ROT_90; break; - case 180: transform = HAL_TRANSFORM_ROT_180; break; - case 270: transform = HAL_TRANSFORM_ROT_270; break; - default: transform = 0; break; - } - - status_t err = OK; - - if (transform) { - err = native_window_set_buffers_transform( - mNativeWindow.get(), transform); - ALOGE("native_window_set_buffers_transform failed: %s (%d)", - strerror(-err), -err); - } - - return err; -} - status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { // Get the number of buffers needed. OMX_PARAM_PORTDEFINITIONTYPE def; @@ -1825,30 +1797,11 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { return err; } - err = native_window_set_buffers_dimensions( - mNativeWindow.get(), - def.format.video.nFrameWidth, - def.format.video.nFrameHeight); - - if (err != 0) { - ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", - strerror(-err), -err); - return err; - } - - err = native_window_set_buffers_format( - mNativeWindow.get(), - def.format.video.eColorFormat); - - if (err != 0) { - ALOGE("native_window_set_buffers_format failed: %s (%d)", - strerror(-err), -err); - return err; - } + sp<MetaData> meta = mSource->getFormat(); - err = applyRotation(); - if (err != OK) { - return err; + int32_t rotationDegrees; + if (!meta->findInt32(kKeyRotation, &rotationDegrees)) { + rotationDegrees = 0; } // Set up the native window. @@ -1859,34 +1812,19 @@ status_t OMXCodec::allocateOutputBuffersFromNativeWindow() { // XXX: Currently this error is logged, but not fatal. usage = 0; } + if (mFlags & kEnableGrallocUsageProtected) { 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; - } - } - - ALOGV("native_window_set_usage usage=0x%x", usage); - err = native_window_set_usage( - mNativeWindow.get(), usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP); + err = setNativeWindowSizeFormatAndUsage( + mNativeWindow.get(), + def.format.video.nFrameWidth, + def.format.video.nFrameHeight, + def.format.video.eColorFormat, + rotationDegrees, + usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP); if (err != 0) { - ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err); return err; } @@ -2053,156 +1991,6 @@ 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) { - 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_dimensions(mNativeWindow.get(), 1, 1); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_buffers_dimensions failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = native_window_set_buffers_format(mNativeWindow.get(), HAL_PIXEL_FORMAT_RGBX_8888); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_buffers_format 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 = native_window_set_scaling_mode(mNativeWindow.get(), - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - if (err != OK) { - ALOGE("error pushing blank frames: set_scaling_mode 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 = native_window_dequeue_buffer_and_wait(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)); - - // 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(), -1); - 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, -1); - } - - 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; - } -} - int64_t OMXCodec::getDecodingTimeUs() { CHECK(mIsEncoder && mIsVideo); @@ -2784,7 +2572,7 @@ void OMXCodec::onStateChange(OMX_STATETYPE newState) { // 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(); + pushBlankBuffersToNativeWindow(mNativeWindow.get()); } setState(IDLE_TO_LOADED); diff --git a/media/libstagefright/SurfaceUtils.cpp b/media/libstagefright/SurfaceUtils.cpp new file mode 100644 index 0000000..6b62e43 --- /dev/null +++ b/media/libstagefright/SurfaceUtils.cpp @@ -0,0 +1,215 @@ +/* + * Copyright 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SurfaceUtils" +#include <utils/Log.h> + +#include <media/stagefright/SurfaceUtils.h> + +#include <gui/Surface.h> + +namespace android { + +status_t setNativeWindowSizeFormatAndUsage( + ANativeWindow *nativeWindow /* nonnull */, + int width, int height, int format, int rotation, int usage) { + status_t err = native_window_set_buffers_dimensions(nativeWindow, width, height); + if (err != NO_ERROR) { + ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", strerror(-err), -err); + return err; + } + + err = native_window_set_buffers_format(nativeWindow, format); + if (err != NO_ERROR) { + ALOGE("native_window_set_buffers_format failed: %s (%d)", strerror(-err), -err); + return err; + } + + int transform = 0; + if ((rotation % 90) == 0) { + switch ((rotation / 90) & 3) { + case 1: transform = HAL_TRANSFORM_ROT_90; break; + case 2: transform = HAL_TRANSFORM_ROT_180; break; + case 3: transform = HAL_TRANSFORM_ROT_270; break; + default: transform = 0; break; + } + } + + err = native_window_set_buffers_transform(nativeWindow, transform); + if (err != NO_ERROR) { + ALOGE("native_window_set_buffers_transform failed: %s (%d)", strerror(-err), -err); + return err; + } + + // 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 = nativeWindow->query( + nativeWindow, NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, &queuesToNativeWindow); + if (err != NO_ERROR) { + ALOGE("error authenticating native window: %s (%d)", strerror(-err), -err); + return err; + } + if (queuesToNativeWindow != 1) { + ALOGE("native window could not be authenticated"); + return PERMISSION_DENIED; + } + } + + int consumerUsage = 0; + err = nativeWindow->query(nativeWindow, NATIVE_WINDOW_CONSUMER_USAGE_BITS, &consumerUsage); + if (err != NO_ERROR) { + ALOGW("failed to get consumer usage bits. ignoring"); + err = NO_ERROR; + } + + int finalUsage = usage | consumerUsage; + ALOGV("gralloc usage: %#x(producer) + %#x(consumer) = %#x", usage, consumerUsage, finalUsage); + err = native_window_set_usage(nativeWindow, finalUsage); + if (err != NO_ERROR) { + ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err); + return err; + } + + err = native_window_set_scaling_mode( + nativeWindow, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); + if (err != NO_ERROR) { + ALOGE("native_window_set_scaling_mode failed: %s (%d)", strerror(-err), -err); + return err; + } + + ALOGD("set up nativeWindow %p for %dx%d, color %#x, rotation %d, usage %#x", + nativeWindow, width, height, format, rotation, finalUsage); + return NO_ERROR; +} + +status_t pushBlankBuffersToNativeWindow(ANativeWindow *nativeWindow /* nonnull */) { + 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(nativeWindow, 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(nativeWindow, NATIVE_WINDOW_API_CPU); + if (err != NO_ERROR) { + ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err); + (void)native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA); + return err; + } + + err = setNativeWindowSizeFormatAndUsage( + nativeWindow, 1, 1, HAL_PIXEL_FORMAT_RGBX_8888, 0, GRALLOC_USAGE_SW_WRITE_OFTEN); + if (err != NO_ERROR) { + goto error; + } + + static_cast<Surface*>(nativeWindow)->getIGraphicBufferProducer()->allowAllocation(true); + + err = nativeWindow->query(nativeWindow, + 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(nativeWindow, 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 = native_window_dequeue_buffer_and_wait(nativeWindow, &anb); + if (err != NO_ERROR) { + ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)", + strerror(-err), -err); + break; + } + + sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); + + // 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); + break; + } + + *img = 0; + + err = buf->unlock(); + if (err != NO_ERROR) { + ALOGE("error pushing blank frames: unlock failed: %s (%d)", strerror(-err), -err); + break; + } + + err = nativeWindow->queueBuffer(nativeWindow, buf->getNativeBuffer(), -1); + if (err != NO_ERROR) { + ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)", strerror(-err), -err); + break; + } + + anb = NULL; + } + +error: + + if (anb != NULL) { + nativeWindow->cancelBuffer(nativeWindow, anb, -1); + anb = NULL; + } + + // Clean up after success or error. + status_t err2 = native_window_api_disconnect(nativeWindow, NATIVE_WINDOW_API_CPU); + if (err2 != NO_ERROR) { + ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", strerror(-err2), -err2); + if (err == NO_ERROR) { + err = err2; + } + } + + err2 = native_window_api_connect(nativeWindow, NATIVE_WINDOW_API_MEDIA); + if (err2 != NO_ERROR) { + ALOGE("error pushing blank frames: api_connect failed: %s (%d)", strerror(-err), -err); + if (err == NO_ERROR) { + err = err2; + } + } + + return err; +} + +} // namespace android + |