807 lines
29 KiB
C++
807 lines
29 KiB
C++
/*
|
|
* Copyright (C) 2013 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 "GoldfishVideoDecoderOMXComponent"
|
|
#include <utils/Log.h>
|
|
|
|
#include "GoldfishVideoDecoderOMXComponent.h"
|
|
|
|
#include <media/stagefright/foundation/ADebug.h>
|
|
#include <media/stagefright/foundation/ALooper.h>
|
|
#include <media/stagefright/foundation/AMessage.h>
|
|
#include <media/stagefright/foundation/AUtils.h>
|
|
#include <media/stagefright/foundation/MediaDefs.h>
|
|
#include <media/hardware/HardwareAPI.h>
|
|
|
|
namespace android {
|
|
|
|
template<class T>
|
|
static void InitOMXParams(T *params) {
|
|
params->nSize = sizeof(T);
|
|
params->nVersion.s.nVersionMajor = 1;
|
|
params->nVersion.s.nVersionMinor = 0;
|
|
params->nVersion.s.nRevision = 0;
|
|
params->nVersion.s.nStep = 0;
|
|
}
|
|
|
|
GoldfishVideoDecoderOMXComponent::GoldfishVideoDecoderOMXComponent(
|
|
const char *name,
|
|
const char *componentRole,
|
|
OMX_VIDEO_CODINGTYPE codingType,
|
|
const CodecProfileLevel *profileLevels,
|
|
size_t numProfileLevels,
|
|
int32_t width,
|
|
int32_t height,
|
|
const OMX_CALLBACKTYPE *callbacks,
|
|
OMX_PTR appData,
|
|
OMX_COMPONENTTYPE **component)
|
|
: SimpleGoldfishOMXComponent(name, callbacks, appData, component),
|
|
mIsAdaptive(false),
|
|
mAdaptiveMaxWidth(0),
|
|
mAdaptiveMaxHeight(0),
|
|
mWidth(width),
|
|
mHeight(height),
|
|
mCropLeft(0),
|
|
mCropTop(0),
|
|
mCropWidth(width),
|
|
mCropHeight(height),
|
|
mOutputFormat(OMX_COLOR_FormatYUV420Planar),
|
|
mOutputPortSettingsChange(NONE),
|
|
mUpdateColorAspects(false),
|
|
mMinInputBufferSize(384), // arbitrary, using one uncompressed macroblock
|
|
mMinCompressionRatio(1), // max input size is normally the output size
|
|
mComponentRole(componentRole),
|
|
mCodingType(codingType),
|
|
mProfileLevels(profileLevels),
|
|
mNumProfileLevels(numProfileLevels) {
|
|
|
|
// init all the color aspects to be Unspecified.
|
|
memset(&mDefaultColorAspects, 0, sizeof(ColorAspects));
|
|
memset(&mBitstreamColorAspects, 0, sizeof(ColorAspects));
|
|
memset(&mFinalColorAspects, 0, sizeof(ColorAspects));
|
|
memset(&mHdrStaticInfo, 0, sizeof(HDRStaticInfo));
|
|
}
|
|
|
|
void GoldfishVideoDecoderOMXComponent::initPorts(
|
|
OMX_U32 numInputBuffers,
|
|
OMX_U32 inputBufferSize,
|
|
OMX_U32 numOutputBuffers,
|
|
const char *mimeType,
|
|
OMX_U32 minCompressionRatio) {
|
|
initPorts(numInputBuffers, numInputBuffers, inputBufferSize,
|
|
numOutputBuffers, numOutputBuffers, mimeType, minCompressionRatio);
|
|
}
|
|
|
|
void GoldfishVideoDecoderOMXComponent::initPorts(
|
|
OMX_U32 numMinInputBuffers,
|
|
OMX_U32 numInputBuffers,
|
|
OMX_U32 inputBufferSize,
|
|
OMX_U32 numMinOutputBuffers,
|
|
OMX_U32 numOutputBuffers,
|
|
const char *mimeType,
|
|
OMX_U32 minCompressionRatio) {
|
|
mMinInputBufferSize = inputBufferSize;
|
|
mMinCompressionRatio = minCompressionRatio;
|
|
|
|
OMX_PARAM_PORTDEFINITIONTYPE def;
|
|
InitOMXParams(&def);
|
|
|
|
def.nPortIndex = kInputPortIndex;
|
|
def.eDir = OMX_DirInput;
|
|
def.nBufferCountMin = numMinInputBuffers;
|
|
def.nBufferCountActual = numInputBuffers;
|
|
def.nBufferSize = inputBufferSize;
|
|
def.bEnabled = OMX_TRUE;
|
|
def.bPopulated = OMX_FALSE;
|
|
def.eDomain = OMX_PortDomainVideo;
|
|
def.bBuffersContiguous = OMX_FALSE;
|
|
def.nBufferAlignment = 1;
|
|
|
|
def.format.video.cMIMEType = const_cast<char *>(mimeType);
|
|
def.format.video.pNativeRender = NULL;
|
|
/* size is initialized in updatePortDefinitions() */
|
|
def.format.video.nBitrate = 0;
|
|
def.format.video.xFramerate = 0;
|
|
def.format.video.bFlagErrorConcealment = OMX_FALSE;
|
|
def.format.video.eCompressionFormat = mCodingType;
|
|
def.format.video.eColorFormat = OMX_COLOR_FormatUnused;
|
|
def.format.video.pNativeWindow = NULL;
|
|
|
|
addPort(def);
|
|
|
|
def.nPortIndex = kOutputPortIndex;
|
|
def.eDir = OMX_DirOutput;
|
|
def.nBufferCountMin = numMinOutputBuffers;
|
|
def.nBufferCountActual = numOutputBuffers;
|
|
def.bEnabled = OMX_TRUE;
|
|
def.bPopulated = OMX_FALSE;
|
|
def.eDomain = OMX_PortDomainVideo;
|
|
def.bBuffersContiguous = OMX_FALSE;
|
|
def.nBufferAlignment = 2;
|
|
|
|
def.format.video.cMIMEType = const_cast<char *>("video/raw");
|
|
def.format.video.pNativeRender = NULL;
|
|
/* size is initialized in updatePortDefinitions() */
|
|
def.format.video.nBitrate = 0;
|
|
def.format.video.xFramerate = 0;
|
|
def.format.video.bFlagErrorConcealment = OMX_FALSE;
|
|
def.format.video.eCompressionFormat = OMX_VIDEO_CodingUnused;
|
|
def.format.video.pNativeWindow = NULL;
|
|
|
|
addPort(def);
|
|
|
|
updatePortDefinitions(true /* updateCrop */, true /* updateInputSize */);
|
|
}
|
|
|
|
void GoldfishVideoDecoderOMXComponent::updatePortDefinitions(bool updateCrop, bool updateInputSize) {
|
|
OMX_PARAM_PORTDEFINITIONTYPE *outDef = &editPortInfo(kOutputPortIndex)->mDef;
|
|
outDef->format.video.nFrameWidth = outputBufferWidth();
|
|
outDef->format.video.nFrameHeight = outputBufferHeight();
|
|
outDef->format.video.eColorFormat = mOutputFormat;
|
|
outDef->format.video.nSliceHeight = outDef->format.video.nFrameHeight;
|
|
|
|
int32_t bpp = (mOutputFormat == OMX_COLOR_FormatYUV420Planar16) ? 2 : 1;
|
|
outDef->format.video.nStride = outDef->format.video.nFrameWidth * bpp;
|
|
outDef->nBufferSize =
|
|
(outDef->format.video.nStride * outDef->format.video.nSliceHeight * 3) / 2;
|
|
|
|
OMX_PARAM_PORTDEFINITIONTYPE *inDef = &editPortInfo(kInputPortIndex)->mDef;
|
|
inDef->format.video.nFrameWidth = mWidth;
|
|
inDef->format.video.nFrameHeight = mHeight;
|
|
// input port is compressed, hence it has no stride
|
|
inDef->format.video.nStride = 0;
|
|
inDef->format.video.nSliceHeight = 0;
|
|
|
|
// when output format changes, input buffer size does not actually change
|
|
if (updateInputSize) {
|
|
inDef->nBufferSize = max(
|
|
outDef->nBufferSize / mMinCompressionRatio,
|
|
max(mMinInputBufferSize, inDef->nBufferSize));
|
|
}
|
|
|
|
if (updateCrop) {
|
|
mCropLeft = 0;
|
|
mCropTop = 0;
|
|
mCropWidth = mWidth;
|
|
mCropHeight = mHeight;
|
|
}
|
|
}
|
|
|
|
|
|
uint32_t GoldfishVideoDecoderOMXComponent::outputBufferWidth() {
|
|
return max(mIsAdaptive ? mAdaptiveMaxWidth : 0, mWidth);
|
|
}
|
|
|
|
uint32_t GoldfishVideoDecoderOMXComponent::outputBufferHeight() {
|
|
return max(mIsAdaptive ? mAdaptiveMaxHeight : 0, mHeight);
|
|
}
|
|
|
|
void GoldfishVideoDecoderOMXComponent::handlePortSettingsChange(
|
|
bool *portWillReset, uint32_t width, uint32_t height,
|
|
OMX_COLOR_FORMATTYPE outputFormat,
|
|
CropSettingsMode cropSettingsMode, bool fakeStride) {
|
|
*portWillReset = false;
|
|
bool sizeChanged = (width != mWidth || height != mHeight);
|
|
bool formatChanged = (outputFormat != mOutputFormat);
|
|
bool updateCrop = (cropSettingsMode == kCropUnSet);
|
|
bool cropChanged = (cropSettingsMode == kCropChanged);
|
|
bool strideChanged = false;
|
|
if (fakeStride) {
|
|
OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
|
|
if (def->format.video.nStride != (OMX_S32)width
|
|
|| def->format.video.nSliceHeight != (OMX_U32)height) {
|
|
strideChanged = true;
|
|
}
|
|
}
|
|
|
|
if (formatChanged || sizeChanged || cropChanged || strideChanged) {
|
|
if (formatChanged) {
|
|
ALOGD("formatChanged: 0x%08x -> 0x%08x", mOutputFormat, outputFormat);
|
|
}
|
|
mOutputFormat = outputFormat;
|
|
mWidth = width;
|
|
mHeight = height;
|
|
|
|
if ((sizeChanged && !mIsAdaptive)
|
|
|| width > mAdaptiveMaxWidth
|
|
|| height > mAdaptiveMaxHeight
|
|
|| formatChanged) {
|
|
if (mIsAdaptive) {
|
|
if (width > mAdaptiveMaxWidth) {
|
|
mAdaptiveMaxWidth = width;
|
|
}
|
|
if (height > mAdaptiveMaxHeight) {
|
|
mAdaptiveMaxHeight = height;
|
|
}
|
|
}
|
|
updatePortDefinitions(updateCrop);
|
|
notify(OMX_EventPortSettingsChanged, kOutputPortIndex, 0, NULL);
|
|
mOutputPortSettingsChange = AWAITING_DISABLED;
|
|
*portWillReset = true;
|
|
} else {
|
|
updatePortDefinitions(updateCrop);
|
|
|
|
if (fakeStride) {
|
|
// MAJOR HACK that is not pretty, it's just to fool the renderer to read the correct
|
|
// data.
|
|
// Some software decoders (e.g. SoftMPEG4) fill decoded frame directly to output
|
|
// buffer without considering the output buffer stride and slice height. So this is
|
|
// used to signal how the buffer is arranged. The alternative is to re-arrange the
|
|
// output buffer in SoftMPEG4, but that results in memcopies.
|
|
OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(kOutputPortIndex)->mDef;
|
|
def->format.video.nStride = mWidth;
|
|
def->format.video.nSliceHeight = mHeight;
|
|
}
|
|
|
|
notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
|
|
OMX_IndexConfigCommonOutputCrop, NULL);
|
|
}
|
|
} else if (mUpdateColorAspects) {
|
|
notify(OMX_EventPortSettingsChanged, kOutputPortIndex,
|
|
kDescribeColorAspectsIndex, NULL);
|
|
mUpdateColorAspects = false;
|
|
}
|
|
}
|
|
|
|
void GoldfishVideoDecoderOMXComponent::dumpColorAspects(const ColorAspects &colorAspects) {
|
|
ALOGD("dumpColorAspects: (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s)) ",
|
|
colorAspects.mRange, asString(colorAspects.mRange),
|
|
colorAspects.mPrimaries, asString(colorAspects.mPrimaries),
|
|
colorAspects.mMatrixCoeffs, asString(colorAspects.mMatrixCoeffs),
|
|
colorAspects.mTransfer, asString(colorAspects.mTransfer));
|
|
}
|
|
|
|
bool GoldfishVideoDecoderOMXComponent::colorAspectsDiffer(
|
|
const ColorAspects &a, const ColorAspects &b) {
|
|
if (a.mRange != b.mRange
|
|
|| a.mPrimaries != b.mPrimaries
|
|
|| a.mTransfer != b.mTransfer
|
|
|| a.mMatrixCoeffs != b.mMatrixCoeffs) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void GoldfishVideoDecoderOMXComponent::updateFinalColorAspects(
|
|
const ColorAspects &otherAspects, const ColorAspects &preferredAspects) {
|
|
Mutex::Autolock autoLock(mColorAspectsLock);
|
|
ColorAspects newAspects;
|
|
newAspects.mRange = preferredAspects.mRange != ColorAspects::RangeUnspecified ?
|
|
preferredAspects.mRange : otherAspects.mRange;
|
|
newAspects.mPrimaries = preferredAspects.mPrimaries != ColorAspects::PrimariesUnspecified ?
|
|
preferredAspects.mPrimaries : otherAspects.mPrimaries;
|
|
newAspects.mTransfer = preferredAspects.mTransfer != ColorAspects::TransferUnspecified ?
|
|
preferredAspects.mTransfer : otherAspects.mTransfer;
|
|
newAspects.mMatrixCoeffs = preferredAspects.mMatrixCoeffs != ColorAspects::MatrixUnspecified ?
|
|
preferredAspects.mMatrixCoeffs : otherAspects.mMatrixCoeffs;
|
|
|
|
// Check to see if need update mFinalColorAspects.
|
|
if (colorAspectsDiffer(mFinalColorAspects, newAspects)) {
|
|
mFinalColorAspects = newAspects;
|
|
mUpdateColorAspects = true;
|
|
}
|
|
}
|
|
|
|
status_t GoldfishVideoDecoderOMXComponent::handleColorAspectsChange() {
|
|
int perference = getColorAspectPreference();
|
|
ALOGD("Color Aspects preference: %d ", perference);
|
|
|
|
if (perference == kPreferBitstream) {
|
|
updateFinalColorAspects(mDefaultColorAspects, mBitstreamColorAspects);
|
|
} else if (perference == kPreferContainer) {
|
|
updateFinalColorAspects(mBitstreamColorAspects, mDefaultColorAspects);
|
|
} else {
|
|
return OMX_ErrorUnsupportedSetting;
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
void GoldfishVideoDecoderOMXComponent::copyYV12FrameToOutputBuffer(
|
|
uint8_t *dst, const uint8_t *srcY, const uint8_t *srcU, const uint8_t *srcV,
|
|
size_t srcYStride, size_t srcUStride, size_t srcVStride) {
|
|
OMX_PARAM_PORTDEFINITIONTYPE *outDef = &editPortInfo(kOutputPortIndex)->mDef;
|
|
int32_t bpp = (outDef->format.video.eColorFormat == OMX_COLOR_FormatYUV420Planar16) ? 2 : 1;
|
|
|
|
size_t dstYStride = outputBufferWidth() * bpp;
|
|
size_t dstUVStride = dstYStride / 2;
|
|
size_t dstHeight = outputBufferHeight();
|
|
uint8_t *dstStart = dst;
|
|
|
|
for (size_t i = 0; i < mHeight; ++i) {
|
|
memcpy(dst, srcY, mWidth * bpp);
|
|
srcY += srcYStride;
|
|
dst += dstYStride;
|
|
}
|
|
|
|
dst = dstStart + dstYStride * dstHeight;
|
|
for (size_t i = 0; i < mHeight / 2; ++i) {
|
|
memcpy(dst, srcU, mWidth / 2 * bpp);
|
|
srcU += srcUStride;
|
|
dst += dstUVStride;
|
|
}
|
|
|
|
dst = dstStart + (5 * dstYStride * dstHeight) / 4;
|
|
for (size_t i = 0; i < mHeight / 2; ++i) {
|
|
memcpy(dst, srcV, mWidth / 2 * bpp);
|
|
srcV += srcVStride;
|
|
dst += dstUVStride;
|
|
}
|
|
}
|
|
|
|
OMX_ERRORTYPE GoldfishVideoDecoderOMXComponent::internalGetParameter(
|
|
OMX_INDEXTYPE index, OMX_PTR params) {
|
|
switch (index) {
|
|
case OMX_IndexParamVideoPortFormat:
|
|
{
|
|
OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
|
|
(OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
|
|
|
|
if (!isValidOMXParam(formatParams)) {
|
|
return OMX_ErrorBadParameter;
|
|
}
|
|
|
|
if (formatParams->nPortIndex > kMaxPortIndex) {
|
|
return OMX_ErrorBadPortIndex;
|
|
}
|
|
|
|
if (formatParams->nIndex != 0) {
|
|
return OMX_ErrorNoMore;
|
|
}
|
|
|
|
if (formatParams->nPortIndex == kInputPortIndex) {
|
|
formatParams->eCompressionFormat = mCodingType;
|
|
formatParams->eColorFormat = OMX_COLOR_FormatUnused;
|
|
formatParams->xFramerate = 0;
|
|
} else {
|
|
CHECK_EQ(formatParams->nPortIndex, 1u);
|
|
|
|
formatParams->eCompressionFormat = OMX_VIDEO_CodingUnused;
|
|
formatParams->eColorFormat = OMX_COLOR_FormatYUV420Planar;
|
|
formatParams->xFramerate = 0;
|
|
}
|
|
|
|
return OMX_ErrorNone;
|
|
}
|
|
|
|
case OMX_IndexParamVideoProfileLevelQuerySupported:
|
|
{
|
|
OMX_VIDEO_PARAM_PROFILELEVELTYPE *profileLevel =
|
|
(OMX_VIDEO_PARAM_PROFILELEVELTYPE *) params;
|
|
|
|
if (!isValidOMXParam(profileLevel)) {
|
|
return OMX_ErrorBadParameter;
|
|
}
|
|
|
|
if (profileLevel->nPortIndex != kInputPortIndex) {
|
|
ALOGE("Invalid port index: %" PRIu32, profileLevel->nPortIndex);
|
|
return OMX_ErrorUnsupportedIndex;
|
|
}
|
|
|
|
if (profileLevel->nProfileIndex >= mNumProfileLevels) {
|
|
return OMX_ErrorNoMore;
|
|
}
|
|
|
|
profileLevel->eProfile = mProfileLevels[profileLevel->nProfileIndex].mProfile;
|
|
profileLevel->eLevel = mProfileLevels[profileLevel->nProfileIndex].mLevel;
|
|
return OMX_ErrorNone;
|
|
}
|
|
|
|
default:
|
|
return SimpleGoldfishOMXComponent::internalGetParameter(index, params);
|
|
}
|
|
}
|
|
|
|
OMX_ERRORTYPE GoldfishVideoDecoderOMXComponent::internalSetParameter(
|
|
OMX_INDEXTYPE index, const OMX_PTR params) {
|
|
// Include extension index OMX_INDEXEXTTYPE.
|
|
const int32_t indexFull = index;
|
|
|
|
switch (indexFull) {
|
|
case OMX_IndexParamStandardComponentRole:
|
|
{
|
|
const OMX_PARAM_COMPONENTROLETYPE *roleParams =
|
|
(const OMX_PARAM_COMPONENTROLETYPE *)params;
|
|
|
|
if (!isValidOMXParam(roleParams)) {
|
|
return OMX_ErrorBadParameter;
|
|
}
|
|
|
|
if (strncmp((const char *)roleParams->cRole,
|
|
mComponentRole,
|
|
OMX_MAX_STRINGNAME_SIZE - 1)) {
|
|
return OMX_ErrorUndefined;
|
|
}
|
|
|
|
return OMX_ErrorNone;
|
|
}
|
|
|
|
case OMX_IndexParamVideoPortFormat:
|
|
{
|
|
OMX_VIDEO_PARAM_PORTFORMATTYPE *formatParams =
|
|
(OMX_VIDEO_PARAM_PORTFORMATTYPE *)params;
|
|
|
|
if (!isValidOMXParam(formatParams)) {
|
|
return OMX_ErrorBadParameter;
|
|
}
|
|
|
|
if (formatParams->nPortIndex > kMaxPortIndex) {
|
|
return OMX_ErrorBadPortIndex;
|
|
}
|
|
|
|
if (formatParams->nPortIndex == kInputPortIndex) {
|
|
if (formatParams->eCompressionFormat != mCodingType
|
|
|| formatParams->eColorFormat != OMX_COLOR_FormatUnused) {
|
|
return OMX_ErrorUnsupportedSetting;
|
|
}
|
|
} else {
|
|
if (formatParams->eCompressionFormat != OMX_VIDEO_CodingUnused
|
|
|| formatParams->eColorFormat != OMX_COLOR_FormatYUV420Planar) {
|
|
return OMX_ErrorUnsupportedSetting;
|
|
}
|
|
}
|
|
|
|
return OMX_ErrorNone;
|
|
}
|
|
|
|
case kPrepareForAdaptivePlaybackIndex:
|
|
{
|
|
const PrepareForAdaptivePlaybackParams* adaptivePlaybackParams =
|
|
(const PrepareForAdaptivePlaybackParams *)params;
|
|
|
|
if (!isValidOMXParam(adaptivePlaybackParams)) {
|
|
return OMX_ErrorBadParameter;
|
|
}
|
|
|
|
mIsAdaptive = adaptivePlaybackParams->bEnable;
|
|
if (mIsAdaptive) {
|
|
mAdaptiveMaxWidth = adaptivePlaybackParams->nMaxFrameWidth;
|
|
mAdaptiveMaxHeight = adaptivePlaybackParams->nMaxFrameHeight;
|
|
mWidth = mAdaptiveMaxWidth;
|
|
mHeight = mAdaptiveMaxHeight;
|
|
} else {
|
|
mAdaptiveMaxWidth = 0;
|
|
mAdaptiveMaxHeight = 0;
|
|
}
|
|
updatePortDefinitions(true /* updateCrop */, true /* updateInputSize */);
|
|
return OMX_ErrorNone;
|
|
}
|
|
|
|
case OMX_IndexParamPortDefinition:
|
|
{
|
|
OMX_PARAM_PORTDEFINITIONTYPE *newParams =
|
|
(OMX_PARAM_PORTDEFINITIONTYPE *)params;
|
|
|
|
if (!isValidOMXParam(newParams)) {
|
|
return OMX_ErrorBadParameter;
|
|
}
|
|
|
|
OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &newParams->format.video;
|
|
OMX_PARAM_PORTDEFINITIONTYPE *def = &editPortInfo(newParams->nPortIndex)->mDef;
|
|
|
|
uint32_t oldWidth = def->format.video.nFrameWidth;
|
|
uint32_t oldHeight = def->format.video.nFrameHeight;
|
|
uint32_t newWidth = video_def->nFrameWidth;
|
|
uint32_t newHeight = video_def->nFrameHeight;
|
|
// We need width, height, stride and slice-height to be non-zero and sensible.
|
|
// These values were chosen to prevent integer overflows further down the line, and do
|
|
// not indicate support for 32kx32k video.
|
|
if (newWidth > 32768 || newHeight > 32768
|
|
|| video_def->nStride > 32768 || video_def->nStride < -32768
|
|
|| video_def->nSliceHeight > 32768) {
|
|
ALOGE("b/22885421");
|
|
return OMX_ErrorBadParameter;
|
|
}
|
|
if (newWidth != oldWidth || newHeight != oldHeight) {
|
|
bool outputPort = (newParams->nPortIndex == kOutputPortIndex);
|
|
if (outputPort) {
|
|
// only update (essentially crop) if size changes
|
|
mWidth = newWidth;
|
|
mHeight = newHeight;
|
|
|
|
updatePortDefinitions(true /* updateCrop */, true /* updateInputSize */);
|
|
// reset buffer size based on frame size
|
|
newParams->nBufferSize = def->nBufferSize;
|
|
} else {
|
|
// For input port, we only set nFrameWidth and nFrameHeight. Buffer size
|
|
// is updated when configuring the output port using the max-frame-size,
|
|
// though client can still request a larger size.
|
|
def->format.video.nFrameWidth = newWidth;
|
|
def->format.video.nFrameHeight = newHeight;
|
|
}
|
|
}
|
|
return SimpleGoldfishOMXComponent::internalSetParameter(index, params);
|
|
}
|
|
|
|
default:
|
|
return SimpleGoldfishOMXComponent::internalSetParameter(index, params);
|
|
}
|
|
}
|
|
|
|
OMX_ERRORTYPE GoldfishVideoDecoderOMXComponent::getConfig(
|
|
OMX_INDEXTYPE index, OMX_PTR params) {
|
|
switch ((int)index) {
|
|
case OMX_IndexConfigCommonOutputCrop:
|
|
{
|
|
OMX_CONFIG_RECTTYPE *rectParams = (OMX_CONFIG_RECTTYPE *)params;
|
|
|
|
if (!isValidOMXParam(rectParams)) {
|
|
return OMX_ErrorBadParameter;
|
|
}
|
|
|
|
if (rectParams->nPortIndex != kOutputPortIndex) {
|
|
return OMX_ErrorUndefined;
|
|
}
|
|
|
|
rectParams->nLeft = mCropLeft;
|
|
rectParams->nTop = mCropTop;
|
|
rectParams->nWidth = mCropWidth;
|
|
rectParams->nHeight = mCropHeight;
|
|
|
|
return OMX_ErrorNone;
|
|
}
|
|
case kDescribeColorAspectsIndex:
|
|
{
|
|
if (!supportsDescribeColorAspects()) {
|
|
return OMX_ErrorUnsupportedIndex;
|
|
}
|
|
|
|
DescribeColorAspectsParams* colorAspectsParams =
|
|
(DescribeColorAspectsParams *)params;
|
|
|
|
if (!isValidOMXParam(colorAspectsParams)) {
|
|
return OMX_ErrorBadParameter;
|
|
}
|
|
|
|
if (colorAspectsParams->nPortIndex != kOutputPortIndex) {
|
|
return OMX_ErrorBadParameter;
|
|
}
|
|
|
|
colorAspectsParams->sAspects = mFinalColorAspects;
|
|
if (colorAspectsParams->bRequestingDataSpace || colorAspectsParams->bDataSpaceChanged) {
|
|
return OMX_ErrorUnsupportedSetting;
|
|
}
|
|
|
|
return OMX_ErrorNone;
|
|
}
|
|
|
|
case kDescribeHdrStaticInfoIndex:
|
|
{
|
|
if (!supportDescribeHdrStaticInfo()) {
|
|
return OMX_ErrorUnsupportedIndex;
|
|
}
|
|
|
|
DescribeHDRStaticInfoParams* hdrStaticInfoParams =
|
|
(DescribeHDRStaticInfoParams *)params;
|
|
|
|
if (!isValidOMXParam(hdrStaticInfoParams)) {
|
|
return OMX_ErrorBadParameter;
|
|
}
|
|
|
|
if (hdrStaticInfoParams->nPortIndex != kOutputPortIndex) {
|
|
return OMX_ErrorBadPortIndex;
|
|
}
|
|
|
|
hdrStaticInfoParams->sInfo = mHdrStaticInfo;
|
|
|
|
return OMX_ErrorNone;
|
|
}
|
|
|
|
case kDescribeHdr10PlusInfoIndex:
|
|
{
|
|
if (!supportDescribeHdr10PlusInfo()) {
|
|
return OMX_ErrorUnsupportedIndex;
|
|
}
|
|
|
|
if (mHdr10PlusOutputs.size() > 0) {
|
|
auto it = mHdr10PlusOutputs.begin();
|
|
|
|
auto info = (*it).get();
|
|
|
|
DescribeHDR10PlusInfoParams* outParams =
|
|
(DescribeHDR10PlusInfoParams *)params;
|
|
|
|
outParams->nParamSizeUsed = info->size();
|
|
|
|
// If the buffer provided by the client does not have enough
|
|
// storage, return the size only and do not remove the param yet.
|
|
if (outParams->nParamSize >= info->size()) {
|
|
memcpy(outParams->nValue, info->data(), info->size());
|
|
mHdr10PlusOutputs.erase(it);
|
|
}
|
|
return OMX_ErrorNone;
|
|
}
|
|
return OMX_ErrorUnderflow;
|
|
}
|
|
|
|
default:
|
|
return OMX_ErrorUnsupportedIndex;
|
|
}
|
|
}
|
|
|
|
OMX_ERRORTYPE GoldfishVideoDecoderOMXComponent::internalSetConfig(
|
|
OMX_INDEXTYPE index, const OMX_PTR params, bool *frameConfig){
|
|
switch ((int)index) {
|
|
case kDescribeColorAspectsIndex:
|
|
{
|
|
if (!supportsDescribeColorAspects()) {
|
|
return OMX_ErrorUnsupportedIndex;
|
|
}
|
|
const DescribeColorAspectsParams* colorAspectsParams =
|
|
(const DescribeColorAspectsParams *)params;
|
|
|
|
if (!isValidOMXParam(colorAspectsParams)) {
|
|
return OMX_ErrorBadParameter;
|
|
}
|
|
|
|
if (colorAspectsParams->nPortIndex != kOutputPortIndex) {
|
|
return OMX_ErrorBadParameter;
|
|
}
|
|
|
|
// Update color aspects if necessary.
|
|
if (colorAspectsDiffer(colorAspectsParams->sAspects, mDefaultColorAspects)) {
|
|
mDefaultColorAspects = colorAspectsParams->sAspects;
|
|
status_t err = handleColorAspectsChange();
|
|
CHECK(err == OK);
|
|
}
|
|
return OMX_ErrorNone;
|
|
}
|
|
|
|
case kDescribeHdrStaticInfoIndex:
|
|
{
|
|
if (!supportDescribeHdrStaticInfo()) {
|
|
return OMX_ErrorUnsupportedIndex;
|
|
}
|
|
|
|
const DescribeHDRStaticInfoParams* hdrStaticInfoParams =
|
|
(DescribeHDRStaticInfoParams *)params;
|
|
|
|
if (!isValidOMXParam(hdrStaticInfoParams)) {
|
|
return OMX_ErrorBadParameter;
|
|
}
|
|
|
|
if (hdrStaticInfoParams->nPortIndex != kOutputPortIndex) {
|
|
return OMX_ErrorBadPortIndex;
|
|
}
|
|
|
|
mHdrStaticInfo = hdrStaticInfoParams->sInfo;
|
|
updatePortDefinitions(false);
|
|
|
|
return OMX_ErrorNone;
|
|
}
|
|
|
|
case kDescribeHdr10PlusInfoIndex:
|
|
{
|
|
if (!supportDescribeHdr10PlusInfo()) {
|
|
return OMX_ErrorUnsupportedIndex;
|
|
}
|
|
|
|
const DescribeHDR10PlusInfoParams* inParams =
|
|
(DescribeHDR10PlusInfoParams *)params;
|
|
|
|
if (*frameConfig) {
|
|
// This is a request to append to the current frame config set.
|
|
// For now, we only support kDescribeHdr10PlusInfoIndex, which
|
|
// we simply replace with the last set value.
|
|
if (mHdr10PlusInputs.size() > 0) {
|
|
*(--mHdr10PlusInputs.end()) = ABuffer::CreateAsCopy(
|
|
inParams->nValue, inParams->nParamSizeUsed);
|
|
} else {
|
|
ALOGW("Ignoring kDescribeHdr10PlusInfoIndex: append to "
|
|
"frame config while no frame config is present");
|
|
}
|
|
} else {
|
|
// This is a frame config, setting *frameConfig to true so that
|
|
// the client marks the next queued input frame to apply it.
|
|
*frameConfig = true;
|
|
mHdr10PlusInputs.push_back(ABuffer::CreateAsCopy(
|
|
inParams->nValue, inParams->nParamSizeUsed));
|
|
}
|
|
return OMX_ErrorNone;
|
|
}
|
|
|
|
default:
|
|
return OMX_ErrorUnsupportedIndex;
|
|
}
|
|
}
|
|
|
|
sp<ABuffer> GoldfishVideoDecoderOMXComponent::dequeueInputFrameConfig() {
|
|
auto it = mHdr10PlusInputs.begin();
|
|
sp<ABuffer> info = *it;
|
|
mHdr10PlusInputs.erase(it);
|
|
return info;
|
|
}
|
|
|
|
void GoldfishVideoDecoderOMXComponent::queueOutputFrameConfig(const sp<ABuffer> &info) {
|
|
mHdr10PlusOutputs.push_back(info);
|
|
notify(OMX_EventConfigUpdate,
|
|
kOutputPortIndex,
|
|
kDescribeHdr10PlusInfoIndex,
|
|
NULL);
|
|
}
|
|
|
|
OMX_ERRORTYPE GoldfishVideoDecoderOMXComponent::getExtensionIndex(
|
|
const char *name, OMX_INDEXTYPE *index) {
|
|
if (!strcmp(name, "OMX.google.android.index.prepareForAdaptivePlayback")) {
|
|
*(int32_t*)index = kPrepareForAdaptivePlaybackIndex;
|
|
return OMX_ErrorNone;
|
|
} else if (!strcmp(name, "OMX.google.android.index.describeColorAspects")
|
|
&& supportsDescribeColorAspects()) {
|
|
*(int32_t*)index = kDescribeColorAspectsIndex;
|
|
return OMX_ErrorNone;
|
|
} else if (!strcmp(name, "OMX.google.android.index.describeHDRStaticInfo")
|
|
&& supportDescribeHdrStaticInfo()) {
|
|
*(int32_t*)index = kDescribeHdrStaticInfoIndex;
|
|
return OMX_ErrorNone;
|
|
} else if (!strcmp(name, "OMX.google.android.index.describeHDR10PlusInfo")
|
|
&& supportDescribeHdr10PlusInfo()) {
|
|
*(int32_t*)index = kDescribeHdr10PlusInfoIndex;
|
|
return OMX_ErrorNone;
|
|
}
|
|
|
|
return SimpleGoldfishOMXComponent::getExtensionIndex(name, index);
|
|
}
|
|
|
|
bool GoldfishVideoDecoderOMXComponent::supportsDescribeColorAspects() {
|
|
return getColorAspectPreference() != kNotSupported;
|
|
}
|
|
|
|
int GoldfishVideoDecoderOMXComponent::getColorAspectPreference() {
|
|
return kNotSupported;
|
|
}
|
|
|
|
bool GoldfishVideoDecoderOMXComponent::supportDescribeHdrStaticInfo() {
|
|
return false;
|
|
}
|
|
|
|
bool GoldfishVideoDecoderOMXComponent::supportDescribeHdr10PlusInfo() {
|
|
return false;
|
|
}
|
|
|
|
void GoldfishVideoDecoderOMXComponent::onReset() {
|
|
mOutputPortSettingsChange = NONE;
|
|
}
|
|
|
|
void GoldfishVideoDecoderOMXComponent::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
|
|
if (portIndex != kOutputPortIndex) {
|
|
return;
|
|
}
|
|
|
|
switch (mOutputPortSettingsChange) {
|
|
case NONE:
|
|
break;
|
|
|
|
case AWAITING_DISABLED:
|
|
{
|
|
CHECK(!enabled);
|
|
mOutputPortSettingsChange = AWAITING_ENABLED;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
|
|
CHECK(enabled);
|
|
mOutputPortSettingsChange = NONE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
} // namespace android
|