diff options
author | Lajos Molnar <lajos@google.com> | 2014-10-10 17:15:17 -0700 |
---|---|---|
committer | Lajos Molnar <lajos@google.com> | 2014-10-13 23:16:20 -0700 |
commit | 2edda09a2ad1d112c52acd37d323f63f0a492d67 (patch) | |
tree | ef7d3fbbf888e258fb12b24ddf23a04dac3e54c5 /media/libstagefright/omx | |
parent | 512e979284de984427e5b2f73b9054ae1b5e2b0a (diff) | |
download | frameworks_av-2edda09a2ad1d112c52acd37d323f63f0a492d67.zip frameworks_av-2edda09a2ad1d112c52acd37d323f63f0a492d67.tar.gz frameworks_av-2edda09a2ad1d112c52acd37d323f63f0a492d67.tar.bz2 |
stagefright: fix surface input handling of software encoders
- added SoftVideoEncoder for common color conversion and
extension handling logic
- fix YUV420 SemiPlanar handling that should be NV12 not NV21
Bug: 17935149
Change-Id: I9b8d05678b1862dd37bf349ea83d67bdf1bb5560
Diffstat (limited to 'media/libstagefright/omx')
-rw-r--r-- | media/libstagefright/omx/Android.mk | 6 | ||||
-rw-r--r-- | media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp | 311 |
2 files changed, 317 insertions, 0 deletions
diff --git a/media/libstagefright/omx/Android.mk b/media/libstagefright/omx/Android.mk index cd912e7..aaa8334 100644 --- a/media/libstagefright/omx/Android.mk +++ b/media/libstagefright/omx/Android.mk @@ -1,6 +1,10 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) +ifeq ($(TARGET_DEVICE), manta) + LOCAL_CFLAGS += -DSURFACE_IS_BGR32 +endif + LOCAL_SRC_FILES:= \ GraphicBufferSource.cpp \ OMX.cpp \ @@ -10,6 +14,7 @@ LOCAL_SRC_FILES:= \ SoftOMXComponent.cpp \ SoftOMXPlugin.cpp \ SoftVideoDecoderOMXComponent.cpp \ + SoftVideoEncoderOMXComponent.cpp \ LOCAL_C_INCLUDES += \ $(TOP)/frameworks/av/media/libstagefright \ @@ -18,6 +23,7 @@ LOCAL_C_INCLUDES += \ LOCAL_SHARED_LIBRARIES := \ libbinder \ + libhardware \ libmedia \ libutils \ liblog \ diff --git a/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp new file mode 100644 index 0000000..8bff142 --- /dev/null +++ b/media/libstagefright/omx/SoftVideoEncoderOMXComponent.cpp @@ -0,0 +1,311 @@ +/* + * Copyright 2014 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. + */ + +#include <inttypes.h> + +//#define LOG_NDEBUG 0 +#define LOG_TAG "SoftVideoEncoderOMXComponent" +#include <utils/Log.h> + +#include "include/SoftVideoEncoderOMXComponent.h" + +#include <hardware/gralloc.h> +#include <media/hardware/HardwareAPI.h> +#include <media/stagefright/foundation/ADebug.h> +#include <media/stagefright/foundation/ALooper.h> +#include <media/stagefright/foundation/AMessage.h> +#include <media/stagefright/MediaDefs.h> + +#include <ui/GraphicBuffer.h> +#include <ui/GraphicBufferMapper.h> + +namespace android { + +SoftVideoEncoderOMXComponent::SoftVideoEncoderOMXComponent( + const char *name, + const OMX_CALLBACKTYPE *callbacks, + OMX_PTR appData, + OMX_COMPONENTTYPE **component) + : SimpleSoftOMXComponent(name, callbacks, appData, component), + mGrallocModule(NULL) { +} + +// static +void SoftVideoEncoderOMXComponent::ConvertFlexYUVToPlanar( + uint8_t *dst, size_t dstStride, size_t dstVStride, + struct android_ycbcr *ycbcr, int32_t width, int32_t height) { + const uint8_t *src = (const uint8_t *)ycbcr->y; + const uint8_t *srcU = (const uint8_t *)ycbcr->cb; + const uint8_t *srcV = (const uint8_t *)ycbcr->cr; + uint8_t *dstU = dst + dstVStride * dstStride; + uint8_t *dstV = dstU + (dstVStride >> 1) * (dstStride >> 1); + + for (size_t y = height; y > 0; --y) { + memcpy(dst, src, width); + dst += dstStride; + src += ycbcr->ystride; + } + if (ycbcr->cstride == ycbcr->ystride >> 1 && ycbcr->chroma_step == 1) { + // planar + for (size_t y = height >> 1; y > 0; --y) { + memcpy(dstU, srcU, width >> 1); + dstU += dstStride >> 1; + srcU += ycbcr->cstride; + memcpy(dstV, srcV, width >> 1); + dstV += dstStride >> 1; + srcV += ycbcr->cstride; + } + } else { + // arbitrary + for (size_t y = height >> 1; y > 0; --y) { + for (size_t x = width >> 1; x > 0; --x) { + *dstU++ = *srcU; + *dstV++ = *srcV; + srcU += ycbcr->chroma_step; + srcV += ycbcr->chroma_step; + } + dstU += (dstStride >> 1) - (width >> 1); + dstV += (dstStride >> 1) - (width >> 1); + srcU += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step; + srcV += ycbcr->cstride - (width >> 1) * ycbcr->chroma_step; + } + } +} + +// static +void SoftVideoEncoderOMXComponent::ConvertYUV420SemiPlanarToYUV420Planar( + const uint8_t *inYVU, uint8_t* outYUV, int32_t width, int32_t height) { + // TODO: add support for stride + int32_t outYsize = width * height; + uint32_t *outY = (uint32_t *) outYUV; + uint16_t *outCb = (uint16_t *) (outYUV + outYsize); + uint16_t *outCr = (uint16_t *) (outYUV + outYsize + (outYsize >> 2)); + + /* Y copying */ + memcpy(outY, inYVU, outYsize); + + /* U & V copying */ + // FIXME this only works if width is multiple of 4 + uint32_t *inYVU_4 = (uint32_t *) (inYVU + outYsize); + for (int32_t i = height >> 1; i > 0; --i) { + for (int32_t j = width >> 2; j > 0; --j) { + uint32_t temp = *inYVU_4++; + uint32_t tempU = temp & 0xFF; + tempU = tempU | ((temp >> 8) & 0xFF00); + + uint32_t tempV = (temp >> 8) & 0xFF; + tempV = tempV | ((temp >> 16) & 0xFF00); + + *outCb++ = tempU; + *outCr++ = tempV; + } + } +} + +// static +void SoftVideoEncoderOMXComponent::ConvertRGB32ToPlanar( + uint8_t *dstY, size_t dstStride, size_t dstVStride, + const uint8_t *src, size_t width, size_t height, size_t srcStride, + bool bgr) { + CHECK((width & 1) == 0); + CHECK((height & 1) == 0); + + uint8_t *dstU = dstY + dstStride * dstVStride; + uint8_t *dstV = dstU + (dstStride >> 1) * (dstVStride >> 1); + +#ifdef SURFACE_IS_BGR32 + bgr = !bgr; +#endif + + const size_t redOffset = bgr ? 2 : 0; + const size_t greenOffset = 1; + const size_t blueOffset = bgr ? 0 : 2; + + for (size_t y = 0; y < height; ++y) { + for (size_t x = 0; x < width; ++x) { + unsigned red = src[redOffset]; + unsigned green = src[greenOffset]; + unsigned blue = src[blueOffset]; + + // using ITU-R BT.601 conversion matrix + unsigned luma = + ((red * 66 + green * 129 + blue * 25) >> 8) + 16; + + dstY[x] = luma; + + if ((x & 1) == 0 && (y & 1) == 0) { + unsigned U = + ((-red * 38 - green * 74 + blue * 112) >> 8) + 128; + + unsigned V = + ((red * 112 - green * 94 - blue * 18) >> 8) + 128; + + dstU[x >> 1] = U; + dstV[x >> 1] = V; + } + src += 4; + } + + if ((y & 1) == 0) { + dstU += dstStride >> 1; + dstV += dstStride >> 1; + } + + src += srcStride - 4 * width; + dstY += dstStride; + } +} + +const uint8_t *SoftVideoEncoderOMXComponent::extractGraphicBuffer( + uint8_t *dst, size_t dstSize, + const uint8_t *src, size_t srcSize, + size_t width, size_t height) const { + size_t dstStride = width; + size_t dstVStride = height; + + MetadataBufferType bufferType = *(MetadataBufferType *)src; + bool usingGraphicBuffer = bufferType == kMetadataBufferTypeGraphicBuffer; + if (!usingGraphicBuffer && bufferType != kMetadataBufferTypeGrallocSource) { + ALOGE("Unsupported metadata type (%d)", bufferType); + return NULL; + } + + if (mGrallocModule == NULL) { + CHECK_EQ(0, hw_get_module(GRALLOC_HARDWARE_MODULE_ID, &mGrallocModule)); + } + + const gralloc_module_t *grmodule = + (const gralloc_module_t *)mGrallocModule; + + buffer_handle_t handle; + int format; + size_t srcStride; + size_t srcVStride; + if (usingGraphicBuffer) { + if (srcSize < 4 + sizeof(GraphicBuffer *)) { + ALOGE("Metadata is too small (%zu vs %zu)", srcSize, 4 + sizeof(GraphicBuffer *)); + return NULL; + } + + GraphicBuffer *buffer = *(GraphicBuffer **)(src + 4); + handle = buffer->handle; + format = buffer->format; + srcStride = buffer->stride; + srcVStride = buffer->height; + // convert stride from pixels to bytes + if (format != HAL_PIXEL_FORMAT_YV12 && + format != HAL_PIXEL_FORMAT_YCbCr_420_888) { + // TODO do we need to support other formats? + srcStride *= 4; + } + } else { + // TODO: remove this part. Check if anyone uses this. + + if (srcSize < 4 + sizeof(buffer_handle_t)) { + ALOGE("Metadata is too small (%zu vs %zu)", srcSize, 4 + sizeof(buffer_handle_t)); + return NULL; + } + + handle = *(buffer_handle_t *)(src + 4); + // assume HAL_PIXEL_FORMAT_RGBA_8888 + // there is no way to get the src stride without the graphic buffer + format = HAL_PIXEL_FORMAT_RGBA_8888; + srcStride = width * 4; + srcVStride = height; + } + + size_t neededSize = + dstStride * dstVStride + (width >> 1) + + (dstStride >> 1) * ((dstVStride >> 1) + (height >> 1) - 1); + if (dstSize < neededSize) { + ALOGE("destination buffer is too small (%zu vs %zu)", dstSize, neededSize); + return NULL; + } + + void *bits = NULL; + struct android_ycbcr ycbcr; + status_t res; + if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) { + res = grmodule->lock_ycbcr( + grmodule, handle, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, + 0, 0, width, height, &ycbcr); + } else { + res = grmodule->lock( + grmodule, handle, + GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_NEVER, + 0, 0, width, height, &bits); + } + if (res != OK) { + ALOGE("Unable to lock image buffer %p for access", handle); + return NULL; + } + + switch (format) { + case HAL_PIXEL_FORMAT_YV12: // YCrCb / YVU planar + // convert to flex YUV + ycbcr.y = bits; + ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride; + ycbcr.cb = (uint8_t *)ycbcr.cr + (srcStride >> 1) * (srcVStride >> 1); + ycbcr.chroma_step = 1; + ycbcr.cstride = srcVStride >> 1; + ycbcr.ystride = srcVStride; + ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height); + break; + case HAL_PIXEL_FORMAT_YCrCb_420_SP: // YCrCb / YVU semiplanar, NV21 + // convert to flex YUV + ycbcr.y = bits; + ycbcr.cr = (uint8_t *)bits + srcStride * srcVStride; + ycbcr.cb = (uint8_t *)ycbcr.cr + 1; + ycbcr.chroma_step = 2; + ycbcr.cstride = srcVStride; + ycbcr.ystride = srcVStride; + ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height); + break; + case HAL_PIXEL_FORMAT_YCbCr_420_888: + ConvertFlexYUVToPlanar(dst, dstStride, dstVStride, &ycbcr, width, height); + break; + case HAL_PIXEL_FORMAT_RGBA_8888: + case HAL_PIXEL_FORMAT_BGRA_8888: + ConvertRGB32ToPlanar( + dst, dstStride, dstVStride, + (const uint8_t *)bits, width, height, srcStride, + format == HAL_PIXEL_FORMAT_BGRA_8888); + break; + default: + ALOGE("Unsupported pixel format %#x", format); + dst = NULL; + break; + } + + if (grmodule->unlock(grmodule, handle) != OK) { + ALOGE("Unable to unlock image buffer %p for access", handle); + } + + return dst; +} + +OMX_ERRORTYPE SoftVideoEncoderOMXComponent::getExtensionIndex( + const char *name, OMX_INDEXTYPE *index) { + if (!strcmp(name, "OMX.google.android.index.storeMetaDataInBuffers") || + !strcmp(name, "OMX.google.android.index.storeGraphicBufferInMetaData")) { + *(int32_t*)index = kStoreMetaDataExtensionIndex; + return OMX_ErrorNone; + } + return SimpleSoftOMXComponent::getExtensionIndex(name, index); +} + +} // namespace android |