| /* |
| * Copyright (C) 2011 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 1 |
| #define LOG_TAG "PreviewRenderer" |
| #include <utils/Log.h> |
| |
| #include "PreviewRenderer.h" |
| |
| #include <binder/MemoryHeapBase.h> |
| #include <binder/MemoryHeapPmem.h> |
| #include <media/stagefright/MediaDebug.h> |
| #include <surfaceflinger/Surface.h> |
| |
| namespace android { |
| |
| PreviewRenderer* PreviewRenderer::CreatePreviewRenderer (OMX_COLOR_FORMATTYPE colorFormat, |
| const sp<Surface> &surface, |
| size_t displayWidth, size_t displayHeight, |
| size_t decodedWidth, size_t decodedHeight, |
| int32_t rotationDegrees) { |
| |
| PreviewRenderer* returnCtx = |
| new PreviewRenderer(colorFormat, |
| surface, |
| displayWidth, displayHeight, |
| decodedWidth, decodedHeight, |
| rotationDegrees); |
| |
| int result = 0; |
| |
| int halFormat; |
| switch (returnCtx->mColorFormat) { |
| case OMX_COLOR_FormatYUV420Planar: |
| { |
| halFormat = HAL_PIXEL_FORMAT_YV12; |
| returnCtx->mYUVMode = None; |
| break; |
| } |
| default: |
| halFormat = HAL_PIXEL_FORMAT_RGB_565; |
| |
| returnCtx->mConverter = new ColorConverter( |
| returnCtx->mColorFormat, OMX_COLOR_Format16bitRGB565); |
| CHECK(returnCtx->mConverter->isValid()); |
| break; |
| } |
| |
| CHECK(returnCtx->mSurface.get() != NULL); |
| CHECK(returnCtx->mDecodedWidth > 0); |
| CHECK(returnCtx->mDecodedHeight > 0); |
| CHECK(returnCtx->mConverter == NULL || returnCtx->mConverter->isValid()); |
| |
| result = native_window_set_usage( |
| returnCtx->mSurface.get(), |
| GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_OFTEN |
| | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP); |
| |
| if ( result == 0 ) { |
| result = native_window_set_buffer_count(returnCtx->mSurface.get(), 3); |
| if ( result == 0 ) { |
| result = native_window_set_scaling_mode(returnCtx->mSurface.get(), |
| NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); |
| if ( result == 0 ) { |
| result = native_window_set_buffers_geometry( |
| returnCtx->mSurface.get(), |
| returnCtx->mDecodedWidth, returnCtx->mDecodedHeight, |
| halFormat); |
| if ( result == 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; |
| } |
| if (transform) { |
| result = native_window_set_buffers_transform( |
| returnCtx->mSurface.get(), transform); |
| |
| } |
| } |
| } |
| } |
| } |
| |
| if ( result != 0 ) |
| { |
| /* free the ctx */ |
| returnCtx->~PreviewRenderer(); |
| return NULL; |
| } |
| |
| return returnCtx; |
| } |
| |
| PreviewRenderer::PreviewRenderer( |
| OMX_COLOR_FORMATTYPE colorFormat, |
| const sp<Surface> &surface, |
| size_t displayWidth, size_t displayHeight, |
| size_t decodedWidth, size_t decodedHeight, |
| int32_t rotationDegrees) |
| : mColorFormat(colorFormat), |
| mConverter(NULL), |
| mYUVMode(None), |
| mSurface(surface), |
| mDisplayWidth(displayWidth), |
| mDisplayHeight(displayHeight), |
| mDecodedWidth(decodedWidth), |
| mDecodedHeight(decodedHeight) { |
| |
| LOGV("input format = %d", mColorFormat); |
| LOGV("display = %d x %d, decoded = %d x %d", |
| mDisplayWidth, mDisplayHeight, mDecodedWidth, mDecodedHeight); |
| |
| mDecodedWidth = mDisplayWidth; |
| mDecodedHeight = mDisplayHeight; |
| } |
| |
| PreviewRenderer::~PreviewRenderer() { |
| delete mConverter; |
| mConverter = NULL; |
| } |
| |
| |
| // |
| // Provides a buffer and associated stride |
| // This buffer is allocated by the SurfaceFlinger |
| // |
| // For optimal display performances, you should : |
| // 1) call getBufferYV12() |
| // 2) fill the buffer with your data |
| // 3) call renderYV12() to take these changes into account |
| // |
| // For each call to getBufferYV12(), you must also call renderYV12() |
| // Expected format in the buffer is YV12 formats (similar to YUV420 planar fromat) |
| // for more details on this YV12 cf hardware/libhardware/include/hardware/hardware.h |
| // |
| void PreviewRenderer::getBufferYV12(uint8_t **data, size_t *stride) { |
| int err = OK; |
| LOGV("getBuffer START"); |
| |
| if ((err = mSurface->ANativeWindow::dequeueBuffer(mSurface.get(), &mBuf)) != 0) { |
| LOGW("Surface::dequeueBuffer returned error %d", err); |
| return; |
| } |
| |
| CHECK_EQ(0, mSurface->ANativeWindow::lockBuffer(mSurface.get(), mBuf)); |
| |
| GraphicBufferMapper &mapper = GraphicBufferMapper::get(); |
| |
| Rect bounds(mDecodedWidth, mDecodedHeight); |
| |
| void *dst; |
| CHECK_EQ(0, mapper.lock( |
| mBuf->handle, GRALLOC_USAGE_SW_WRITE_OFTEN, bounds, &dst)); |
| LOGV("Buffer locked"); |
| |
| *data = (uint8_t*)dst; |
| *stride = mBuf->stride; |
| |
| LOGV("getBuffer END %p %d", dst, mBuf->stride); |
| } |
| |
| |
| // |
| // Display the content of the buffer provided by last call to getBufferYV12() |
| // |
| // See getBufferYV12() for details. |
| // |
| void PreviewRenderer::renderYV12() { |
| LOGV("renderYV12() START"); |
| int err = OK; |
| |
| GraphicBufferMapper &mapper = GraphicBufferMapper::get(); |
| |
| if (mBuf!= NULL) { |
| CHECK_EQ(0, mapper.unlock(mBuf->handle)); |
| |
| if ((err = mSurface->ANativeWindow::queueBuffer(mSurface.get(), mBuf)) != 0) { |
| LOGW("Surface::queueBuffer returned error %d", err); |
| } |
| } |
| mBuf = NULL; |
| LOGV("renderYV12() END"); |
| } |
| |
| } // namespace android |