android13/vendor/rockchip/hardware/interfaces/rockit/direct/RTMetadataRetrieverCallback...

438 lines
12 KiB
C++

/*
* Copyright 2020 Rockchip Electronics Co. LTD
*
* 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 "RTMetadataRetrieverCallback"
#include <vector>
#include <utils/RefBase.h>
#include <private/media/VideoFrame.h>
#include <binder/MemoryBase.h>
#include <binder/MemoryHeapBase.h>
#include <media/openmax/OMX_IVCommon.h>
#include <media/stagefright/ColorConverter.h>
#include "RTMetadataRetrieverCallback.h"
#include "RTLibDefine.h"
#include "RTMediaMetaKeys.h"
namespace android {
#if 1
#define Debug ALOGV
#else
#define Debug ALOGD
#endif
struct MetaDataCallBackCtx {
// bit per sample
int mBpp;
// input yuv format
int mSrcFormat;
// output yuv format
int mDstFormat;
// width of input yuv
int mWidth;
// height of input yuv
int mHeight;
// width of input buffer
int mWStride;
// height of input buffer
int mHStride;
// rotation of input video frame
int mRotation;
int mBitDepth;
std::vector<sp<IMemory> > mFrames;
};
static MetaDataCallBackCtx* getContext(void* context) {
MetaDataCallBackCtx* ctx = static_cast<MetaDataCallBackCtx*>(context);
return ctx;
}
static void rtFormatDump(int format) {
switch (format) {
case RT_FMT_YUV420SP:
Debug("%s YUV420 SP", __FUNCTION__);
break;
case RT_FMT_YUV420SP_10BIT:
Debug("%s YUV420 SP 10bit", __FUNCTION__);
break;
case RT_FMT_ARGB8888:
Debug("%s ARGB 8888", __FUNCTION__);
break;
case RT_FMT_RGB565:
Debug("%s RGB 565", __FUNCTION__);
break;
default:
ALOGD("%s: add more here, format = %d", __FUNCTION__, format);
break;
}
}
static void omxFormatDump(int format) {
switch (format) {
case OMX_COLOR_FormatYUV420SemiPlanar:
Debug("%s YUV420 SP", __FUNCTION__);
break;
case OMX_COLOR_Format32bitARGB8888:
Debug("%s ARGB 8888", __FUNCTION__);
break;
case OMX_COLOR_Format16bitRGB565:
Debug("%s RGB 565", __FUNCTION__);
break;
default:
ALOGD("%s: add more here, format = %d", __FUNCTION__, format);
break;
}
}
RTMetadataRetrieverCallback::RTMetadataRetrieverCallback() {
MetaDataCallBackCtx* ctx = new MetaDataCallBackCtx();
assert(ctx != NULL);
ctx->mBpp = 2;
ctx->mSrcFormat = RT_FMT_YUV420SP;
ctx->mDstFormat = OMX_COLOR_Format16bitRGB565;
ctx->mWidth = RT_FMT_RGB565;
ctx->mHeight = 0;
ctx->mRotation = 0;
mCtx = static_cast<void*>(ctx);
}
RTMetadataRetrieverCallback::~RTMetadataRetrieverCallback() {
MetaDataCallBackCtx* ctx = getContext(mCtx);
if (ctx != NULL) {
ctx->mFrames.clear();
delete ctx;
ctx = NULL;
}
}
int RTMetadataRetrieverCallback::init(RtMetaData* meta) {
if (meta == NULL)
return -1;
MetaDataCallBackCtx* ctx = getContext(mCtx);
if (ctx == NULL)
return -1;
int width = 0, height = 0;
int displayWidth = 0, displayHeight = 0;
int format = 0, rotation = 0;
int dstFormat = 0;
int bitDepth = 0;
// stride of width and height
if (!meta->findInt32(kKeyFrameW, &width)) {
ALOGD("%s not find width stride in meta", __FUNCTION__);
}
if (!meta->findInt32(kKeyFrameH, &height)) {
ALOGD("%s not find height stride in meta", __FUNCTION__);
}
// valid width and height of datas
if (!meta->findInt32(kKeyVCodecWidth, &displayWidth)) {
ALOGD("%s not find width in meta", __FUNCTION__);
}
if (!meta->findInt32(kKeyVCodecHeight, &displayHeight)) {
ALOGD("%s not find height in meta", __FUNCTION__);
}
if (!meta->findInt32(kKeyCodecFormat, &format)) {
format = RT_FMT_YUV420SP;
ALOGD("%s not find src format in meta, use NV12 for default", __FUNCTION__);
}
if (!meta->findInt32(kKeyVCodecRotation, &rotation)) {
rotation = 0;
}
if (!meta->findInt32(kRetrieverDstColorFormat, &dstFormat)) {
dstFormat = OMX_COLOR_Format16bitRGB565;
ALOGD("%s not find src format in meta, use RGB56 for default", __FUNCTION__);
}
if (!meta->findInt32(kKeyVSettingBitdepth, &bitDepth)) {
bitDepth = 8;
ALOGD("%s not find bitDepth in meta, use 8 for default", __FUNCTION__);
}
uint32_t bpp = 2; /*rgb565 - 2bytes*/
if (dstFormat == OMX_COLOR_Format16bitRGB565) {
bpp = 2;
} else {
bpp = 4;
}
ctx->mWidth = displayWidth;
ctx->mHeight = displayHeight;
ctx->mWStride = width;
ctx->mHStride = height;
ctx->mSrcFormat = format;
ctx->mDstFormat = dstFormat;
ctx->mBpp = bpp;
ctx->mRotation = rotation;
ctx->mBitDepth = bitDepth;
rtFormatDump(ctx->mSrcFormat);
omxFormatDump(ctx->mDstFormat);
Debug("%s: Stride(%d x %d), Video(%d x %d), bpp = %d, rotation = %d",
__FUNCTION__, ctx->mWStride, ctx->mHStride,
ctx->mWidth, ctx->mHeight, ctx->mBpp, ctx->mRotation);
return 0;
}
int RTMetadataRetrieverCallback::transfRT2OmxColorFormat(int src) {
int dst = OMX_COLOR_FormatYUV420SemiPlanar;
switch (src) {
case RT_FMT_YUV420SP:
case RT_FMT_YUV420SP_10BIT: // yuv420sp 10bit will convert to yuv420sp 8bit
dst = OMX_COLOR_FormatYUV420SemiPlanar;
break;
case RT_FMT_RGB565:
dst = OMX_COLOR_Format16bitRGB565;
break;
case RT_FMT_ARGB8888:
dst = OMX_COLOR_Format32bitARGB8888;
break;
default:
ALOGD("%s: src format = %d not support", __FUNCTION__, src);
dst = OMX_COLOR_FormatUnused;
break;
}
return (int)dst;
}
int RTMetadataRetrieverCallback::fillVideoFrame(RtMetaData* meta) {
if (meta == NULL)
return -1;
MetaDataCallBackCtx* ctx = getContext(mCtx);
if (ctx == NULL)
return -1;
sp<IMemory> frameMem = allocVideoFrame(meta);
if (frameMem.get() == NULL)
return -1;
VideoFrame* frame = static_cast<VideoFrame*>(frameMem->unsecurePointer());
setFrame(frameMem);
OMX_COLOR_FORMATTYPE srcFormat = (OMX_COLOR_FORMATTYPE)transfRT2OmxColorFormat(ctx->mSrcFormat);
OMX_COLOR_FORMATTYPE drcFormat = (OMX_COLOR_FORMATTYPE)ctx->mDstFormat;
// (OMX_COLOR_FORMATTYPE)transfRT2OmxColorFormat(ctx->mDstFormat);
if (srcFormat == OMX_COLOR_FormatUnused || (drcFormat == OMX_COLOR_FormatUnused)) {
return -1;
}
ColorConverter converter(srcFormat, drcFormat);
uint8_t *srcYuvAddr = 0;
uint8_t *dstYuvAddr = NULL;
uint8_t *convertAddr = NULL;
int32_t width = ctx->mWStride;
int32_t height = ctx->mHStride;
int32_t stride = ctx->mWStride;
// find src yuv adress
if (meta->findPointer(kRetrieverBufferAddress, (void**)&srcYuvAddr) != RT_TRUE) {
ALOGD("%s: not find srcYuvAddr", __FUNCTION__);
goto _FAIL;
}
int32_t crop_left, crop_top, crop_right, crop_bottom;
if (1) {
crop_left = crop_top = 0;
crop_right = ctx->mWidth - 1;
crop_bottom = ctx->mHeight - 1;
}
if (converter.isValid()) {
// first. if input format is yuv420sp 10bit, convert it to yuv420sp 8 bit
if (ctx->mSrcFormat == RT_FMT_YUV420SP_10BIT) {
dstYuvAddr = (uint8_t *)malloc(ctx->mHStride * ctx->mWStride * 3 / 2);
if (dstYuvAddr == NULL) {
ALOGE("fail to malloc yuv address.");
return -1;
}
convert10bitTo8bit(srcYuvAddr, dstYuvAddr);
stride = width;
}
convertAddr = (dstYuvAddr != NULL) ? dstYuvAddr : srcYuvAddr;
#if 0
if (mYuvFile) {
int32_t size = width * height * 3 / 2;
fwrite(convertAddr, 1, size, mYuvFile);
fflush(mYuvFile);
ALOGI("stagefright dump yuv [%d x %d] size %d stride %d",width,height,size,stride);
fclose(mYuvFile);
mYuvFile = NULL;
}
#endif
// second. convert src/input's format to dst's format
converter.convert(
convertAddr,
width, height, stride,
crop_left, crop_top, crop_right, crop_bottom,
frame->getFlattenedData(),
frame->mWidth, frame->mHeight, frame->mRowBytes,
0, 0, frame->mWidth - 1, frame->mHeight - 1);
if (dstYuvAddr) {
free(dstYuvAddr);
dstYuvAddr = NULL;
}
}
return 0;
_FAIL:
return -1;
}
sp<IMemory> RTMetadataRetrieverCallback::allocVideoFrame(RtMetaData* meta) {
if (meta == NULL)
return NULL;
MetaDataCallBackCtx* ctx = getContext(mCtx);
if (ctx == NULL)
return NULL;
int displayWidth = ctx->mWidth;
int displayHeight = ctx->mHeight;
int width = ctx->mWidth;
int height = ctx->mHeight;
int bpp = ctx->mBpp;
int rotation = ctx->mRotation;
int bitDepth = ctx->mBitDepth;
uint32_t tileWidth = 0;
uint32_t tileHeight = 0;
//ALOGE("file: %s func %s line %d bitDepth %d",__FILE__,__FUNCTION__,__LINE__,bitDepth);
VideoFrame frame(width, height, displayWidth, displayHeight,
tileWidth, tileHeight, rotation, bpp, bitDepth, true/*hasData*/, 0/*iccSize*/);
size_t size = frame.getFlattenedSize();
sp<MemoryHeapBase> heap = new MemoryHeapBase(size, 0, "RTMetadataRetrieverClient");
sp<IMemory> frameMem = NULL;
VideoFrame* frameCopy = NULL;
if (heap == NULL) {
ALOGE("failed to create MemoryDealer");
goto _FAIL;
}
frameMem = new MemoryBase(heap, 0, size);
if (frameMem == NULL) {
ALOGE("not enough memory for VideoFrame size=%zu", size);
heap.clear();
goto _FAIL;
}
frameCopy = static_cast<VideoFrame*>(frameMem->unsecurePointer());
frameCopy->init(frame,NULL,0);
return frameMem;
_FAIL:
return NULL;
}
void RTMetadataRetrieverCallback::freeVideoFrame(sp<IMemory> frame)
{
if (frame.get() != NULL) {
frame.clear();
}
}
uint8_t RTMetadataRetrieverCallback::fetch_data(uint8_t *line, uint32_t num) {
uint32_t offset = 0;
uint32_t value = 0;
offset = (num * 2) & 7;
value = (line[num * 10 / 8] >> offset) | (line[num * 10 / 8 + 1] << (8 - offset));
value = (value & 0x3ff) >> 2;
return (uint8_t)value;
}
int RTMetadataRetrieverCallback::convert10bitTo8bit(uint8_t *src, uint8_t *dst) {
MetaDataCallBackCtx* ctx = getContext(mCtx);
if (ctx == NULL)
return -1;
if ((src == NULL) || (dst == NULL))
return -1;
int horStride = ctx->mWStride;
int verStride = ctx->mHStride;
int width = ctx->mWStride;
int height = ctx->mHStride;
uint8_t *srcBase = src;
uint8_t *dstBase = dst;
int i = 0;
int j = 0;
Debug("%s width = %d height = %d horStride = %d verStride = %d",
__FUNCTION__, width, height, horStride, verStride);
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++)
dst[j] = fetch_data(src, j);
dst += width;
src += horStride;
}
src = srcBase + verStride * horStride;
dst = dstBase + width * height;
for (i = 0; i < height / 2; i++) {
for (j = 0; j < width; j++)
dst[j] = fetch_data(src, j);
dst += width;
src += horStride;
}
return 0;
}
sp<IMemory> RTMetadataRetrieverCallback::extractFrame(RTFrameRect *rect) {
(void)rect;
MetaDataCallBackCtx* ctx = getContext(mCtx);
if (ctx == NULL)
return NULL;
return ctx->mFrames.size() > 0 ? ctx->mFrames[0] : NULL;
}
sp<IMemory> RTMetadataRetrieverCallback::extractFrames() {
return mFrameMemory;
}
}