android13/vendor/rockchip/hardware/interfaces/codec2/component/mpi/C2RKMpiDec.cpp

1942 lines
71 KiB
C++
Executable File

/*
* Copyright (C) 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.
*/
#undef ROCKCHIP_LOG_TAG
#define ROCKCHIP_LOG_TAG "C2RKMpiDec"
#include <C2Debug.h>
#include <C2PlatformSupport.h>
#include <C2AllocatorGralloc.h>
#include <Codec2Mapper.h>
#include <ui/GraphicBufferMapper.h>
#include <gralloc_priv_omx.h>
#include <sys/syscall.h>
#include <media/stagefright/foundation/ALookup.h>
#include "hardware/hardware_rockchip.h"
#include "hardware/gralloc_rockchip.h"
#include "C2RKMpiDec.h"
#include "C2RKLog.h"
#include "C2RKMediaUtils.h"
#include "C2RKRgaDef.h"
#include "C2RKChipFeaturesDef.h"
#include "C2RKGrallocDef.h"
#include "C2RKColorAspects.h"
#include "C2RKNalParser.h"
#include "C2RKVersion.h"
#include "C2RKEnv.h"
#include "C2VdecExtendFeature.h"
#include "C2RKExtendParam.h"
#include "C2RKMlvecLegacy.h"
namespace android {
/* max support video resolution */
constexpr uint32_t kMaxVideoWidth = 8192;
constexpr uint32_t kMaxVideoHeight = 4320;
constexpr size_t kMinInputBufferSize = 2 * 1024 * 1024;
struct MlvecParams {
std::shared_ptr<C2DriverVersion::output> driverInfo;
std::shared_ptr<C2LowLatencyMode::output> lowLatencyMode;
};
class C2RKMpiDec::IntfImpl : public C2RKInterface<void>::BaseParams {
public:
explicit IntfImpl(
const std::shared_ptr<C2ReflectorHelper> &helper,
C2String name,
C2Component::kind_t kind,
C2Component::domain_t domain,
C2String mediaType)
: C2RKInterface<void>::BaseParams(helper, name, kind, domain, mediaType) {
mMlvecParams = std::make_shared<MlvecParams>();
addParameter(
DefineParam(mActualOutputDelay, C2_PARAMKEY_OUTPUT_DELAY)
.withDefault(new C2PortActualDelayTuning::output(C2_DEFAULT_OUTPUT_DELAY))
.withFields({C2F(mActualOutputDelay, value).inRange(0, C2_MAX_OUTPUT_DELAY)})
.withSetter(Setter<decltype(*mActualOutputDelay)>::StrictValueWithNoDeps)
.build());
addParameter(
DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
.withConstValue(new C2ComponentAttributesSetting(C2Component::ATTRIB_IS_TEMPORAL))
.build());
// input picture frame size
addParameter(
DefineParam(mSize, C2_PARAMKEY_PICTURE_SIZE)
.withDefault(new C2StreamPictureSizeInfo::output(0u, 320, 240))
.withFields({
C2F(mSize, width).inRange(2, kMaxVideoWidth, 2),
C2F(mSize, height).inRange(2, kMaxVideoWidth, 2),
})
.withSetter(SizeSetter)
.build());
addParameter(
DefineParam(mMaxSize, C2_PARAMKEY_MAX_PICTURE_SIZE)
.withDefault(new C2StreamMaxPictureSizeTuning::output(0u, 320, 240))
.withFields({
C2F(mSize, width).inRange(2, kMaxVideoWidth, 2),
C2F(mSize, height).inRange(2, kMaxVideoWidth, 2),
})
.withSetter(MaxPictureSizeSetter, mSize)
.build());
addParameter(
DefineParam(mBlockSize, C2_PARAMKEY_BLOCK_SIZE)
.withDefault(new C2StreamBlockSizeInfo::output(0u, 320, 240))
.withFields({
C2F(mBlockSize, width).inRange(2, kMaxVideoWidth, 2),
C2F(mBlockSize, height).inRange(2, kMaxVideoWidth, 2),
})
.withSetter(BlockSizeSetter)
.build());
std::vector<uint32_t> pixelFormats = { HAL_PIXEL_FORMAT_YCBCR_420_888 };
if (C2RKMediaUtils::isP010Allowed()) {
pixelFormats.push_back(HAL_PIXEL_FORMAT_YCBCR_P010);
}
// TODO: support more formats?
addParameter(
DefineParam(mPixelFormat, C2_PARAMKEY_PIXEL_FORMAT)
.withDefault(new C2StreamPixelFormatInfo::output(
0u, HAL_PIXEL_FORMAT_YCBCR_420_888))
.withFields({C2F(mPixelFormat, value).oneOf(pixelFormats)})
.withSetter((Setter<decltype(*mPixelFormat)>::StrictValueWithNoDeps))
.build());
// profile and level
if (mediaType == MEDIA_MIMETYPE_VIDEO_AVC) {
addParameter(
DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
.withDefault(new C2StreamProfileLevelInfo::input(0u,
C2Config::PROFILE_AVC_BASELINE, C2Config::LEVEL_AVC_5_1))
.withFields({
C2F(mProfileLevel, profile).oneOf({
C2Config::PROFILE_AVC_CONSTRAINED_BASELINE,
C2Config::PROFILE_AVC_BASELINE,
C2Config::PROFILE_AVC_MAIN,
C2Config::PROFILE_AVC_CONSTRAINED_HIGH,
C2Config::PROFILE_AVC_PROGRESSIVE_HIGH,
C2Config::PROFILE_AVC_HIGH,
C2Config::PROFILE_AVC_HIGH_10,
C2Config::PROFILE_AVC_PROGRESSIVE_HIGH_10}),
C2F(mProfileLevel, level).oneOf({
C2Config::LEVEL_AVC_1, C2Config::LEVEL_AVC_1B, C2Config::LEVEL_AVC_1_1,
C2Config::LEVEL_AVC_1_2, C2Config::LEVEL_AVC_1_3,
C2Config::LEVEL_AVC_2, C2Config::LEVEL_AVC_2_1, C2Config::LEVEL_AVC_2_2,
C2Config::LEVEL_AVC_3, C2Config::LEVEL_AVC_3_1, C2Config::LEVEL_AVC_3_2,
C2Config::LEVEL_AVC_4, C2Config::LEVEL_AVC_4_1, C2Config::LEVEL_AVC_4_2,
C2Config::LEVEL_AVC_5, C2Config::LEVEL_AVC_5_1, C2Config::LEVEL_AVC_5_2,
C2Config::LEVEL_AVC_6, C2Config::LEVEL_AVC_6_1, C2Config::LEVEL_AVC_6_2})
})
.withSetter(ProfileLevelSetter, mSize)
.build());
} else if (mediaType == MEDIA_MIMETYPE_VIDEO_HEVC) {
addParameter(
DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
.withDefault(new C2StreamProfileLevelInfo::input(0u,
C2Config::PROFILE_HEVC_MAIN, C2Config::LEVEL_HEVC_MAIN_5_1))
.withFields({
C2F(mProfileLevel, profile).oneOf({
C2Config::PROFILE_HEVC_MAIN,
C2Config::PROFILE_HEVC_MAIN_10}),
C2F(mProfileLevel, level).oneOf({
C2Config::LEVEL_HEVC_MAIN_1,
C2Config::LEVEL_HEVC_MAIN_2, C2Config::LEVEL_HEVC_MAIN_2_1,
C2Config::LEVEL_HEVC_MAIN_3, C2Config::LEVEL_HEVC_MAIN_3_1,
C2Config::LEVEL_HEVC_MAIN_4, C2Config::LEVEL_HEVC_MAIN_4_1,
C2Config::LEVEL_HEVC_MAIN_5, C2Config::LEVEL_HEVC_MAIN_5_1,
C2Config::LEVEL_HEVC_MAIN_5_2, C2Config::LEVEL_HEVC_MAIN_6,
C2Config::LEVEL_HEVC_MAIN_6_1, C2Config::LEVEL_HEVC_MAIN_6_2,
C2Config::LEVEL_HEVC_HIGH_4, C2Config::LEVEL_HEVC_HIGH_4_1,
C2Config::LEVEL_HEVC_HIGH_5, C2Config::LEVEL_HEVC_HIGH_5_1,
C2Config::LEVEL_HEVC_HIGH_5_2, C2Config::LEVEL_HEVC_HIGH_6,
C2Config::LEVEL_HEVC_HIGH_6_1, C2Config::LEVEL_HEVC_HIGH_6_2})
})
.withSetter(ProfileLevelSetter, mSize)
.build());
} else if (mediaType == MEDIA_MIMETYPE_VIDEO_MPEG2) {
addParameter(
DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
.withDefault(new C2StreamProfileLevelInfo::input(0u,
C2Config::PROFILE_MP2V_SIMPLE, C2Config::LEVEL_MP2V_HIGH))
.withFields({
C2F(mProfileLevel, profile).oneOf({
C2Config::PROFILE_MP2V_SIMPLE,
C2Config::PROFILE_MP2V_MAIN}),
C2F(mProfileLevel, level).oneOf({
C2Config::LEVEL_MP2V_LOW,
C2Config::LEVEL_MP2V_MAIN,
C2Config::LEVEL_MP2V_HIGH_1440,
C2Config::LEVEL_MP2V_HIGH})
})
.withSetter(ProfileLevelSetter, mSize)
.build());
} else if (mediaType == MEDIA_MIMETYPE_VIDEO_MPEG4) {
addParameter(
DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
.withDefault(new C2StreamProfileLevelInfo::input(0u,
C2Config::PROFILE_MP4V_SIMPLE, C2Config::LEVEL_MP4V_3))
.withFields({
C2F(mProfileLevel, profile).oneOf({
C2Config::PROFILE_MP4V_SIMPLE}),
C2F(mProfileLevel, level).oneOf({
C2Config::LEVEL_MP4V_0,
C2Config::LEVEL_MP4V_0B,
C2Config::LEVEL_MP4V_1,
C2Config::LEVEL_MP4V_2,
C2Config::LEVEL_MP4V_3})
})
.withSetter(ProfileLevelSetter, mSize)
.build());
} else if (mediaType == MEDIA_MIMETYPE_VIDEO_H263) {
addParameter(
DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
.withDefault(new C2StreamProfileLevelInfo::input(0u,
C2Config::PROFILE_H263_BASELINE, C2Config::LEVEL_H263_30))
.withFields({
C2F(mProfileLevel, profile).oneOf({
C2Config::PROFILE_H263_BASELINE,
C2Config::PROFILE_H263_ISWV2}),
C2F(mProfileLevel, level).oneOf({
C2Config::LEVEL_H263_10,
C2Config::LEVEL_H263_20,
C2Config::LEVEL_H263_30,
C2Config::LEVEL_H263_40,
C2Config::LEVEL_H263_45})
})
.withSetter(ProfileLevelSetter, mSize)
.build());
} else if (mediaType == MEDIA_MIMETYPE_VIDEO_VP9) {
addParameter(
DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
.withDefault(new C2StreamProfileLevelInfo::input(0u,
C2Config::PROFILE_VP9_0, C2Config::LEVEL_VP9_5))
.withFields({
C2F(mProfileLevel, profile).oneOf({
C2Config::PROFILE_VP9_0,
C2Config::PROFILE_VP9_2}),
C2F(mProfileLevel, level).oneOf({
C2Config::LEVEL_VP9_1,
C2Config::LEVEL_VP9_1_1,
C2Config::LEVEL_VP9_2,
C2Config::LEVEL_VP9_2_1,
C2Config::LEVEL_VP9_3,
C2Config::LEVEL_VP9_3_1,
C2Config::LEVEL_VP9_4,
C2Config::LEVEL_VP9_4_1,
C2Config::LEVEL_VP9_5,
C2Config::LEVEL_VP9_5_1,
C2Config::LEVEL_VP9_5_2,
C2Config::LEVEL_VP9_6,
C2Config::LEVEL_VP9_6_1,
C2Config::LEVEL_VP9_6_2})
})
.withSetter(ProfileLevelSetter, mSize)
.build());
} else if (mediaType == MEDIA_MIMETYPE_VIDEO_AV1) {
addParameter(
DefineParam(mProfileLevel, C2_PARAMKEY_PROFILE_LEVEL)
.withDefault(new C2StreamProfileLevelInfo::input(0u,
C2Config::PROFILE_AV1_0, C2Config::LEVEL_AV1_7_3))
.withFields({
C2F(mProfileLevel, profile).oneOf({
C2Config::PROFILE_AV1_0,
C2Config::PROFILE_AV1_0}),
C2F(mProfileLevel, level).oneOf({
C2Config::LEVEL_AV1_2, C2Config::LEVEL_AV1_2_1, C2Config::LEVEL_AV1_2_2,
C2Config::LEVEL_AV1_2_3, C2Config::LEVEL_AV1_3, C2Config::LEVEL_AV1_3_1,
C2Config::LEVEL_AV1_3_2, C2Config::LEVEL_AV1_3_3, C2Config::LEVEL_AV1_4,
C2Config::LEVEL_AV1_4_1, C2Config::LEVEL_AV1_4_2, C2Config::LEVEL_AV1_4_3,
C2Config::LEVEL_AV1_5, C2Config::LEVEL_AV1_5_1, C2Config::LEVEL_AV1_5_2,
C2Config::LEVEL_AV1_5_3, C2Config::LEVEL_AV1_6, C2Config::LEVEL_AV1_6_1,
C2Config::LEVEL_AV1_6_2, C2Config::LEVEL_AV1_6_3, C2Config::LEVEL_AV1_7,
C2Config::LEVEL_AV1_7_1, C2Config::LEVEL_AV1_7_2, C2Config::LEVEL_AV1_7_3})
})
.withSetter(ProfileLevelSetter, mSize)
.build());
}
// max input buffer size
addParameter(
DefineParam(mMaxInputSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
.withDefault(new C2StreamMaxBufferSizeInfo::input(0u, kMinInputBufferSize))
.withFields({
C2F(mMaxInputSize, value).any(),
})
.calculatedAs(MaxInputSizeSetter, mMaxSize)
.build());
// ColorInfo
C2ChromaOffsetStruct locations[1] = { C2ChromaOffsetStruct::ITU_YUV_420_0() };
std::shared_ptr<C2StreamColorInfo::output> defaultColorInfo =
C2StreamColorInfo::output::AllocShared(
1u, 0u, 8u /* bitDepth */, C2Color::YUV_420);
memcpy(defaultColorInfo->m.locations, locations, sizeof(locations));
defaultColorInfo =
C2StreamColorInfo::output::AllocShared(
{ C2ChromaOffsetStruct::ITU_YUV_420_0() },
0u, 8u /* bitDepth */, C2Color::YUV_420);
helper->addStructDescriptors<C2ChromaOffsetStruct>();
addParameter(
DefineParam(mColorInfo, C2_PARAMKEY_CODED_COLOR_INFO)
.withConstValue(defaultColorInfo)
.build());
// colorAspects
addParameter(
DefineParam(mDefaultColorAspects, C2_PARAMKEY_DEFAULT_COLOR_ASPECTS)
.withDefault(new C2StreamColorAspectsTuning::output(
0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
.withFields({
C2F(mDefaultColorAspects, range).inRange(
C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
C2F(mDefaultColorAspects, primaries).inRange(
C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
C2F(mDefaultColorAspects, transfer).inRange(
C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
C2F(mDefaultColorAspects, matrix).inRange(
C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
})
.withSetter(DefaultColorAspectsSetter)
.build());
// vui colorAspects
if (mediaType == MEDIA_MIMETYPE_VIDEO_AVC ||
mediaType == MEDIA_MIMETYPE_VIDEO_HEVC ||
mediaType == MEDIA_MIMETYPE_VIDEO_MPEG2) {
addParameter(
DefineParam(mCodedColorAspects, C2_PARAMKEY_VUI_COLOR_ASPECTS)
.withDefault(new C2StreamColorAspectsInfo::input(
0u, C2Color::RANGE_LIMITED, C2Color::PRIMARIES_UNSPECIFIED,
C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
.withFields({
C2F(mCodedColorAspects, range).inRange(
C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
C2F(mCodedColorAspects, primaries).inRange(
C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
C2F(mCodedColorAspects, transfer).inRange(
C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
C2F(mCodedColorAspects, matrix).inRange(
C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
})
.withSetter(CodedColorAspectsSetter)
.build());
addParameter(
DefineParam(mColorAspects, C2_PARAMKEY_COLOR_ASPECTS)
.withDefault(new C2StreamColorAspectsInfo::output(
0u, C2Color::RANGE_UNSPECIFIED, C2Color::PRIMARIES_UNSPECIFIED,
C2Color::TRANSFER_UNSPECIFIED, C2Color::MATRIX_UNSPECIFIED))
.withFields({
C2F(mColorAspects, range).inRange(
C2Color::RANGE_UNSPECIFIED, C2Color::RANGE_OTHER),
C2F(mColorAspects, primaries).inRange(
C2Color::PRIMARIES_UNSPECIFIED, C2Color::PRIMARIES_OTHER),
C2F(mColorAspects, transfer).inRange(
C2Color::TRANSFER_UNSPECIFIED, C2Color::TRANSFER_OTHER),
C2F(mColorAspects, matrix).inRange(
C2Color::MATRIX_UNSPECIFIED, C2Color::MATRIX_OTHER)
})
.withSetter(ColorAspectsSetter, mDefaultColorAspects, mCodedColorAspects)
.build());
addParameter(
DefineParam(mLowLatency, C2_PARAMKEY_LOW_LATENCY_MODE)
.withDefault(new C2GlobalLowLatencyModeTuning(false))
.withFields({C2F(mLowLatency, value)})
.withSetter(Setter<decltype(*mLowLatency)>::NonStrictValueWithNoDeps)
.build());
/* extend parameter definition */
addParameter(
DefineParam(mMlvecParams->driverInfo, C2_PARAMKEY_MLVEC_DEC_DRI_VERSION)
.withConstValue(new C2DriverVersion::output(MLVEC_DRIVER_VERSION))
.build());
addParameter(
DefineParam(mMlvecParams->lowLatencyMode, C2_PARAMKEY_MLVEC_DEC_LOW_LATENCY_MODE)
.withDefault(new C2LowLatencyMode::output(0))
.withFields({
C2F(mMlvecParams->lowLatencyMode, enable).any(),
})
.withSetter(MLowLatenctyModeSetter)
.build());
}
}
static C2R SizeSetter(bool mayBlock, const C2P<C2StreamPictureSizeInfo::output> &oldMe,
C2P<C2StreamPictureSizeInfo::output> &me) {
(void)mayBlock;
C2R res = C2R::Ok();
if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
me.set().width = oldMe.v.width;
}
if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
me.set().height = oldMe.v.height;
}
if (me.set().width * me.set().height > kMaxVideoWidth * kMaxVideoHeight) {
c2_warn("max support video resolution %dx%d, cur %dx%d",
kMaxVideoWidth, kMaxVideoHeight, me.set().width, me.set().height);
}
return res;
}
static C2R MaxPictureSizeSetter(bool mayBlock, C2P<C2StreamMaxPictureSizeTuning::output> &me,
const C2P<C2StreamPictureSizeInfo::output> &size) {
(void)mayBlock;
// TODO: get max width/height from the size's field helpers vs. hardcoding
me.set().width = c2_min(c2_max(me.v.width, size.v.width), kMaxVideoWidth);
me.set().height = c2_min(c2_max(me.v.height, size.v.height), kMaxVideoWidth);
if (me.set().width * me.set().height > kMaxVideoWidth * kMaxVideoHeight) {
c2_warn("max support video resolution %dx%d, cur %dx%d",
kMaxVideoWidth, kMaxVideoHeight, me.set().width, me.set().height);
}
return C2R::Ok();
}
static C2R BlockSizeSetter(bool mayBlock, const C2P<C2StreamBlockSizeInfo::output> &oldMe,
C2P<C2StreamBlockSizeInfo::output> &me) {
(void)mayBlock;
C2R res = C2R::Ok();
if (!me.F(me.v.width).supportsAtAll(me.v.width)) {
res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.width)));
me.set().width = oldMe.v.width;
}
if (!me.F(me.v.height).supportsAtAll(me.v.height)) {
res = res.plus(C2SettingResultBuilder::BadValue(me.F(me.v.height)));
me.set().height = oldMe.v.height;
}
return res;
}
static C2R ProfileLevelSetter(bool mayBlock, C2P<C2StreamProfileLevelInfo::input> &me,
const C2P<C2StreamPictureSizeInfo::output> &size) {
(void)mayBlock;
(void)size;
(void)me; // TODO: validate
return C2R::Ok();
}
static C2R MaxInputSizeSetter(bool mayBlock, C2P<C2StreamMaxBufferSizeInfo::input> &me,
const C2P<C2StreamMaxPictureSizeTuning::output> &maxSize) {
(void)mayBlock;
// assume compression ratio of 2
me.set().value = c2_max((((maxSize.v.width + 63) / 64)
* ((maxSize.v.height + 63) / 64) * 3072), kMinInputBufferSize);
return C2R::Ok();
}
static C2R DefaultColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsTuning::output> &me) {
(void)mayBlock;
if (me.v.range > C2Color::RANGE_OTHER) {
me.set().range = C2Color::RANGE_OTHER;
}
if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
me.set().primaries = C2Color::PRIMARIES_OTHER;
}
if (me.v.transfer > C2Color::TRANSFER_OTHER) {
me.set().transfer = C2Color::TRANSFER_OTHER;
}
if (me.v.matrix > C2Color::MATRIX_OTHER) {
me.set().matrix = C2Color::MATRIX_OTHER;
}
return C2R::Ok();
}
static C2R CodedColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::input> &me) {
(void)mayBlock;
if (me.v.range > C2Color::RANGE_OTHER) {
me.set().range = C2Color::RANGE_OTHER;
}
if (me.v.primaries > C2Color::PRIMARIES_OTHER) {
me.set().primaries = C2Color::PRIMARIES_OTHER;
}
if (me.v.transfer > C2Color::TRANSFER_OTHER) {
me.set().transfer = C2Color::TRANSFER_OTHER;
}
if (me.v.matrix > C2Color::MATRIX_OTHER) {
me.set().matrix = C2Color::MATRIX_OTHER;
}
return C2R::Ok();
}
static C2R ColorAspectsSetter(bool mayBlock, C2P<C2StreamColorAspectsInfo::output> &me,
const C2P<C2StreamColorAspectsTuning::output> &def,
const C2P<C2StreamColorAspectsInfo::input> &coded) {
(void)mayBlock;
// take default values for all unspecified fields, and coded values for specified ones
me.set().range = coded.v.range == RANGE_UNSPECIFIED ? def.v.range : coded.v.range;
me.set().primaries = coded.v.primaries == PRIMARIES_UNSPECIFIED
? def.v.primaries : coded.v.primaries;
me.set().transfer = coded.v.transfer == TRANSFER_UNSPECIFIED
? def.v.transfer : coded.v.transfer;
me.set().matrix = coded.v.matrix == MATRIX_UNSPECIFIED ? def.v.matrix : coded.v.matrix;
return C2R::Ok();
}
static C2R MLowLatenctyModeSetter(
bool mayBlock, C2P<C2LowLatencyMode::output> &me) {
(void)mayBlock;
(void)me;
return C2R::Ok();
}
std::shared_ptr<C2StreamPictureSizeInfo::output> getSize_l() {
return mSize;
}
std::shared_ptr<C2StreamColorAspectsInfo::output> getColorAspects_l() {
return mColorAspects;
}
std::shared_ptr<C2StreamColorAspectsTuning::output> getDefaultColorAspects_l() {
return mDefaultColorAspects;
}
std::shared_ptr<C2GlobalLowLatencyModeTuning> getLowLatency_l() {
return mLowLatency;
}
std::shared_ptr<C2StreamProfileLevelInfo::input> getProfileLevel_l() {
return mProfileLevel;
}
std::shared_ptr<C2StreamPixelFormatInfo::output> getPixelFormat_l() const {
return mPixelFormat;
}
std::shared_ptr<MlvecParams> getMlvecParams_l() {
return mMlvecParams;
}
private:
std::shared_ptr<C2StreamPictureSizeInfo::output> mSize;
std::shared_ptr<C2StreamMaxPictureSizeTuning::output> mMaxSize;
std::shared_ptr<C2StreamBlockSizeInfo::output> mBlockSize;
std::shared_ptr<C2StreamPixelFormatInfo::output> mPixelFormat;
std::shared_ptr<C2StreamProfileLevelInfo::input> mProfileLevel;
std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mMaxInputSize;
std::shared_ptr<C2StreamColorInfo::output> mColorInfo;
std::shared_ptr<C2StreamColorAspectsTuning::output> mDefaultColorAspects;
std::shared_ptr<C2StreamColorAspectsInfo::input> mCodedColorAspects;
std::shared_ptr<C2StreamColorAspectsInfo::output> mColorAspects;
std::shared_ptr<C2GlobalLowLatencyModeTuning> mLowLatency;
std::shared_ptr<MlvecParams> mMlvecParams;
};
C2RKMpiDec::C2RKMpiDec(
const char *name,
c2_node_id_t id,
const std::shared_ptr<IntfImpl> &intfImpl)
: C2RKComponent(std::make_shared<C2RKInterface<IntfImpl>>(name, id, intfImpl)),
mIntf(intfImpl),
mDump(nullptr),
mMppCtx(nullptr),
mMppMpi(nullptr),
mCodingType(MPP_VIDEO_CodingUnused),
mColorFormat(MPP_FMT_YUV420SP),
mFrmGrp(nullptr),
mWidth(0),
mHeight(0),
mHorStride(0),
mVerStride(0),
mGrallocVersion(0),
mLastPts(-1),
mGeneration(0),
mStarted(false),
mFlushed(true),
mOutputEos(false),
mSignalledInputEos(false),
mSignalledError(false),
mSizeInfoUpdate(false),
mLowLatencyMode(false),
mGraphicBufferSource(false),
mScaleEnabled(false),
mBufferMode(false) {
if (!C2RKMediaUtils::getCodingTypeFromComponentName(name, &mCodingType)) {
c2_err("failed to get codingType from component %s", name);
}
/*
* only a few chips, and the version above Android 11 supports gralloc 4.0
*/
uint32_t grallocVersion = C2RKGrallocDef::getGrallocVersion();
uint32_t androidVersion = C2RKGrallocDef::getAndroidVerison();
if (grallocVersion > 3 && androidVersion >= 30) {
mGrallocVersion = 4;
}
sDecConcurrentInstances.fetch_add(1, std::memory_order_relaxed);
//c2_info("component name: %s\r\nversion: %s", name, C2_GIT_BUILD_VERSION);
}
C2RKMpiDec::~C2RKMpiDec() {
c2_log_func_enter();
if (sDecConcurrentInstances.load() > 0) {
sDecConcurrentInstances.fetch_sub(1, std::memory_order_relaxed);
}
onRelease();
}
c2_status_t C2RKMpiDec::onInit() {
c2_status_t ret = C2_OK;
c2_log_func_enter();
ret = updateOutputDelay();
if (ret != C2_OK) {
c2_err("failed to update output delay, ret %d", ret);
}
return ret;
}
c2_status_t C2RKMpiDec::onStop() {
c2_log_func_enter();
if (!mFlushed) {
return onFlush_sm();
}
return C2_OK;
}
void C2RKMpiDec::onReset() {
c2_log_func_enter();
onStop();
}
void C2RKMpiDec::onRelease() {
c2_log_func_enter();
mStarted = false;
mGraphicBufferSource = false;
if (!mFlushed) {
onFlush_sm();
}
if (mOutBlock) {
mOutBlock.reset();
}
if (mDump != nullptr) {
delete mDump;
mDump = nullptr;
}
if (mFrmGrp != nullptr) {
mpp_buffer_group_put(mFrmGrp);
mFrmGrp = nullptr;
}
if (mMppCtx) {
mpp_destroy(mMppCtx);
mMppCtx = nullptr;
}
}
c2_status_t C2RKMpiDec::onFlush_sm() {
c2_status_t ret = C2_OK;
c2_log_func_enter();
if (!mFlushed) {
mOutputEos = false;
mSignalledInputEos = false;
mSignalledError = false;
mGeneration = 0;
clearOutBuffers();
if (mFrmGrp) {
mpp_buffer_group_clear(mFrmGrp);
}
if (mMppMpi) {
mMppMpi->reset(mMppCtx);
}
mFlushed = true;
}
return ret;
}
c2_status_t C2RKMpiDec::initDecoder(const std::unique_ptr<C2Work> &work) {
MPP_RET err = MPP_OK;
c2_log_func_enter();
{
IntfImpl::Lock lock = mIntf->lock();
mWidth = mIntf->getSize_l()->width;
mHeight = mIntf->getSize_l()->height;
mPrimaries = (uint32_t)mIntf->getDefaultColorAspects_l()->primaries;
mTransfer = (uint32_t)mIntf->getDefaultColorAspects_l()->transfer;
mRange = (uint32_t)mIntf->getDefaultColorAspects_l()->range;
mHalPixelFormat = mIntf->getPixelFormat_l()->value;
if (mIntf->getLowLatency_l() != nullptr) {
mLowLatencyMode = (mIntf->getLowLatency_l()->value > 0) ? true : false ;
}
if (!mLowLatencyMode && mIntf->getMlvecParams_l()->lowLatencyMode != nullptr) {
mLowLatencyMode = (mIntf->getMlvecParams_l()->lowLatencyMode->enable != 0);
}
if (mIntf->getProfileLevel_l() != nullptr) {
mProfile = (uint32_t)mIntf->getProfileLevel_l()->profile;
}
}
c2_info("init: w %d h %d coding %d", mWidth, mHeight, mCodingType);
err = mpp_create(&mMppCtx, &mMppMpi);
if (err != MPP_OK) {
c2_err("failed to mpp_create, ret %d", err);
goto error;
}
// TODO: workround: CTS-CodecDecoderTest
// testFlushNative[15(c2.rk.mpeg2.decoder_video/mpeg2)
if (mCodingType == MPP_VIDEO_CodingMPEG2) {
uint32_t vmode = 0, split = 1;
mMppMpi->control(mMppCtx, MPP_DEC_SET_ENABLE_DEINTERLACE, &vmode);
mMppMpi->control(mMppCtx, MPP_DEC_SET_PARSER_SPLIT_MODE, &split);
} else {
// enable deinterlace, but not decting
uint32_t vmode = 1;
mMppMpi->control(mMppCtx, MPP_DEC_SET_ENABLE_DEINTERLACE, &vmode);
}
{
// enable fast mode,
uint32_t fastParser = 1;
mMppMpi->control(mMppCtx, MPP_DEC_SET_PARSER_FAST_MODE, &fastParser);
uint32_t disableErr = 1;
mMppMpi->control(mMppCtx, MPP_DEC_SET_DISABLE_ERROR, &disableErr);
}
err = mpp_init(mMppCtx, MPP_CTX_DEC, mCodingType);
if (err != MPP_OK) {
c2_err("failed to mpp_init, ret %d", err);
goto error;
}
{
// enable fast-play mode, ignore the effect of B-frame.
uint32_t fastPlay = 1;
mMppMpi->control(mMppCtx, MPP_DEC_SET_ENABLE_FAST_PLAY, &fastPlay);
if (mLowLatencyMode) {
uint32_t deinterlace = 0, immediate = 1;
c2_info("enable lowLatency, enable mpp immediate-out mode");
mMppMpi->control(mMppCtx, MPP_DEC_SET_ENABLE_DEINTERLACE, &deinterlace);
mMppMpi->control(mMppCtx, MPP_DEC_SET_IMMEDIATE_OUT, &immediate);
}
}
{
MppFrame frame = nullptr;
if (mProfile == PROFILE_AVC_HIGH_10 ||
mProfile == PROFILE_HEVC_MAIN_10 ||
(mBufferMode && mHalPixelFormat == HAL_PIXEL_FORMAT_YCBCR_P010)) {
c2_info("setup 10Bit format with profile %d halPixelFmt %d",
mProfile, mHalPixelFormat);
mColorFormat = MPP_FMT_YUV420SP_10BIT;
}
uint32_t mppFmt = mColorFormat;
if (checkPreferFbcOutput(work)) {
mFbcCfg.mode = C2RKChipFeaturesDef::getFbcOutputMode(mCodingType);
if (mFbcCfg.mode) {
c2_info("use mpp fbc output mode");
mppFmt |= MPP_FRAME_FBC_AFBC_V2;
}
} else {
mFbcCfg.mode = 0;
}
mMppMpi->control(mMppCtx, MPP_DEC_SET_OUTPUT_FORMAT, (MppParam)&mppFmt);
mpp_frame_init(&frame);
mpp_frame_set_width(frame, mWidth);
mpp_frame_set_height(frame, mHeight);
mpp_frame_set_fmt(frame, (MppFrameFormat)mppFmt);
mMppMpi->control(mMppCtx, MPP_DEC_SET_FRAME_INFO, (MppParam)frame);
/*
* Command "set-frame-info" may failed to provide stride info in old
* mpp version, so config unaligned resolution for stride and then
* info-change will sent to transmit correct stride.
*/
if (mpp_frame_get_hor_stride(frame) <= 0 ||
mpp_frame_get_ver_stride(frame) <= 0)
{
mpp_frame_set_hor_stride(frame, mWidth);
mpp_frame_set_ver_stride(frame, mHeight);
mMppMpi->control(mMppCtx, MPP_DEC_SET_FRAME_INFO, (MppParam)frame);
}
mHorStride = mpp_frame_get_hor_stride(frame);
mVerStride = mpp_frame_get_ver_stride(frame);
c2_info("init: get stride [%d:%d]", mHorStride, mVerStride);
mpp_frame_deinit(&frame);
}
/*
* For buffer mode, since we don't konw when the last buffer will use
* up by user, so we use MPP internal buffer group, and copy output to
* dst block(mOutBlock).
*/
if (!mBufferMode) {
err = mpp_buffer_group_get_external(&mFrmGrp, MPP_BUFFER_TYPE_ION);
if (err != MPP_OK) {
c2_err("failed to get buffer_group, err %d", err);
goto error;
}
mMppMpi->control(mMppCtx, MPP_DEC_SET_EXT_BUF_GROUP, mFrmGrp);
}
/* fbc decode output has padding inside, set crop before display */
if (mFbcCfg.mode) {
C2RKChipFeaturesDef::getFbcOutputOffset(mCodingType,
&mFbcCfg.paddingX,
&mFbcCfg.paddingY);
c2_info("fbc padding offset(%d, %d)", mFbcCfg.paddingX, mFbcCfg.paddingY);
}
if (!mDump) {
// init dump object
mDump = new C2RKDump();
mDump->initDump(mHorStride, mVerStride, false);
}
mStarted = true;
return C2_OK;
error:
if (mMppCtx) {
mpp_destroy(mMppCtx);
mMppCtx = nullptr;
}
return C2_CORRUPTED;
}
bool C2RKMpiDec::checkPreferFbcOutput(const std::unique_ptr<C2Work> &work) {
if (mGraphicBufferSource) {
c2_info("get graphicBufferSource in, perfer non-fbc mode");
return false;
}
if (mBufferMode) {
c2_info("bufferMode perfer non-fbc mode");
return false;
}
/* SMPTEST2084 = 6 */
if (mTransfer == 6) {
c2_info("get transfer SMPTEST2084, prefer fbc output mode");
return true;
}
if (mProfile == PROFILE_AVC_HIGH_10 || mProfile == PROFILE_HEVC_MAIN_10) {
c2_info("get 10bit profile, prefer fbc output mode");
return true;
}
// kodi/photos/files does not transmit profile level(10bit etc) to C2, so
// get bitDepth info from spspps in this case.
if (work->input.flags & C2FrameData::FLAG_CODEC_CONFIG) {
C2ReadView rView = mDummyReadView;
if (!work->input.buffers.empty()) {
rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
if (!rView.error()) {
uint8_t *inData = const_cast<uint8_t *>(rView.data());
size_t inSize = rView.capacity();
int32_t depth = C2RKNalParser::getBitDepth(inData, inSize, mCodingType);
if (depth == 10) {
c2_info("get 10bit profile tag from spspps, prefer fbc output mode");
return true;
}
}
}
}
if (mWidth * mHeight > 2304 * 1080 || mCodingType == MPP_VIDEO_CodingVP9 || mCodingType == MPP_VIDEO_CodingHEVC) {
return true;
}
return false;
}
bool C2RKMpiDec::checkIsGBSource(const std::shared_ptr<C2BlockPool> &pool) {
c2_status_t ret = C2_OK;
uint32_t blockW = 176;
uint32_t blockH = 144;
uint64_t usage = RK_GRALLOC_USAGE_SPECIFY_STRIDE;
uint32_t format = HAL_PIXEL_FORMAT_YCrCb_NV12;
std::shared_ptr<C2GraphicBlock> block;
ret = pool->fetchGraphicBlock(blockW, blockH, format,
C2AndroidMemoryUsage::FromGrallocUsage(usage),
&block);
if (ret != C2_OK) {
c2_err("failed to fetchGraphicBlock, err %d", ret);
//TODO
}
auto c2Handle = block->handle();
uint32_t bqSlot, width, height, format1, stride, generation;
uint64_t usage1, bqId;
android::_UnwrapNativeCodec2GrallocMetadata(
c2Handle, &width, &height, &format1, &usage1,
&stride, &generation, &bqId, &bqSlot);
block.reset();
if (usage1 & GRALLOC_USAGE_HW_VIDEO_ENCODER)
return true;
return false;
}
void C2RKMpiDec::fillEmptyWork(const std::unique_ptr<C2Work> &work) {
uint32_t flags = 0;
c2_trace_func_enter();
if (work->input.flags & C2FrameData::FLAG_END_OF_STREAM) {
flags |= C2FrameData::FLAG_END_OF_STREAM;
c2_info("signalling eos");
}
work->worklets.front()->output.flags = (C2FrameData::flags_t)flags;
work->worklets.front()->output.buffers.clear();
work->worklets.front()->output.ordinal = work->input.ordinal;
work->workletsProcessed = 1u;
}
void C2RKMpiDec::finishWork(OutWorkEntry *entry) {
if (!entry->outblock) {
c2_err("empty block, finish work failed.");
return;
}
uint32_t left = mFbcCfg.mode ? mFbcCfg.paddingX : 0;
uint32_t top = mFbcCfg.mode ? mFbcCfg.paddingY : 0;
std::shared_ptr<C2Buffer> buffer
= createGraphicBuffer(std::move(entry->outblock),
C2Rect(mWidth, mHeight).at(left, top));
mOutBlock = nullptr;
{
if (mCodingType == MPP_VIDEO_CodingAVC ||
mCodingType == MPP_VIDEO_CodingHEVC ||
mCodingType == MPP_VIDEO_CodingMPEG2) {
IntfImpl::Lock lock = mIntf->lock();
buffer->setInfo(mIntf->getColorAspects_l());
}
}
auto fillWork = [buffer, entry](const std::unique_ptr<C2Work> &work) {
// now output work is new work, frame index remove by input work,
// output work set to incomplete to ignore frame index check
work->worklets.front()->output.flags = C2FrameData::FLAG_INCOMPLETE;
work->worklets.front()->output.buffers.clear();
work->worklets.front()->output.buffers.push_back(buffer);
work->worklets.front()->output.ordinal = work->input.ordinal;
work->worklets.front()->output.ordinal.timestamp = entry->timestamp;
work->workletsProcessed = 1u;
};
std::unique_ptr<C2Work> outputWork(new C2Work);
outputWork->worklets.clear();
outputWork->worklets.emplace_back(new C2Worklet);
outputWork->input.ordinal.timestamp = 0;
outputWork->input.ordinal.frameIndex = OUTPUT_WORK_INDEX;
outputWork->input.ordinal.customOrdinal = 0;
outputWork->result = C2_OK;
if (mSizeInfoUpdate) {
c2_info("update new size %dx%d config to framework.", mWidth, mHeight);
C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
outputWork->worklets.front()->output.configUpdate.push_back(C2Param::Copy(size));
mSizeInfoUpdate = false;
}
finish(outputWork, fillWork);
}
c2_status_t C2RKMpiDec::drainInternal(
uint32_t drainMode,
const std::shared_ptr<C2BlockPool> &pool,
const std::unique_ptr<C2Work> &work) {
c2_log_func_enter();
if (drainMode == NO_DRAIN) {
c2_warn("drain with NO_DRAIN: no-op");
return C2_OK;
}
if (drainMode == DRAIN_CHAIN) {
c2_warn("DRAIN_CHAIN not supported");
return C2_OMITTED;
}
c2_status_t ret = C2_OK;
OutWorkEntry entry;
uint32_t kMaxRetryNum = 20;
uint32_t retry = 0;
while (true){
ret = ensureDecoderState(pool);
if (ret != C2_OK && work) {
mSignalledError = true;
work->workletsProcessed = 1u;
work->result = C2_CORRUPTED;
return C2_CORRUPTED;
}
ret = getoutframe(&entry, false);
if (ret == C2_OK && entry.outblock) {
finishWork(&entry);
} else if (drainMode == DRAIN_COMPONENT_NO_EOS && !work) {
c2_info("drain without wait eos, done.");
break;
}
if (mOutputEos && work) {
fillEmptyWork(work);
break;
}
if ((++retry) > kMaxRetryNum) {
mOutputEos = true;
c2_warn("drain: eos not found, force set output EOS.");
} else {
usleep(5 * 1000);
}
}
c2_log_func_leave();
return C2_OK;
}
c2_status_t C2RKMpiDec::drain(
uint32_t drainMode,
const std::shared_ptr<C2BlockPool> &pool) {
return drainInternal(drainMode, pool, nullptr);
}
void C2RKMpiDec::process(
const std::unique_ptr<C2Work> &work,
const std::shared_ptr<C2BlockPool> &pool) {
c2_status_t err = C2_OK;
// Initialize output work
work->result = C2_OK;
work->workletsProcessed = 0u;
work->worklets.front()->output.flags = work->input.flags;
mBufferMode = (pool->getLocalId() <= C2BlockPool::PLATFORM_START);
// Initialize decoder if not already initialized
if (!mStarted) {
mGraphicBufferSource = checkIsGBSource(pool);
err = initDecoder(work);
if (err != C2_OK) {
work->result = C2_BAD_VALUE;
c2_info("failed to initialize, signalled Error");
return;
}
}
if (mSignalledInputEos || mSignalledError) {
work->result = C2_BAD_VALUE;
return;
}
uint8_t *inData = nullptr;
size_t inSize = 0u;
C2ReadView rView = mDummyReadView;
if (!work->input.buffers.empty()) {
rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
inData = const_cast<uint8_t *>(rView.data());
inSize = rView.capacity();
if (inSize && rView.error()) {
c2_err("failed to read rWiew, error %d", rView.error());
work->result = rView.error();
return;
}
}
uint32_t flags = work->input.flags;
uint64_t frameIndex = work->input.ordinal.frameIndex.peekull();
uint64_t timestamp = work->input.ordinal.timestamp.peekll();
c2_trace("in buffer attr. size %zu timestamp %lld frameindex %lld, flags %x",
inSize, timestamp, frameIndex, flags);
bool eos = ((flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
bool hasPicture = false;
bool needGetFrame = false;
bool sendPacketFlag = true;
uint32_t outfrmCnt = 0;
OutWorkEntry entry;
if ((flags & C2FrameData::FLAG_CODEC_CONFIG) == 0) {
// reset flush flag when get non-config frame.
mFlushed = false;
}
err = ensureDecoderState(pool);
if (err != C2_OK) {
mSignalledError = true;
work->workletsProcessed = 1u;
work->result = C2_CORRUPTED;
return;
}
inPacket:
needGetFrame = false;
sendPacketFlag = true;
// may block, quit util enqueue success.
err = sendpacket(inData, inSize, timestamp, flags);
if (err != C2_OK) {
c2_warn("failed to enqueue packet, pts %lld", timestamp);
needGetFrame = true;
sendPacketFlag = false;
} else {
if (!eos) {
fillEmptyWork(work);
}
// TODO workround: CTS-CodecDecoderTest
// testFlushNative[15(c2.rk.mpeg2.decoder_video/mpeg2)
if (mLastPts != timestamp) {
mLastPts = timestamp;
}
}
outframe:
if (!eos) {
err = getoutframe(&entry, needGetFrame);
if (err == C2_OK) {
outfrmCnt++;
needGetFrame = false;
hasPicture = true;
} else if (err == C2_CORRUPTED) {
mSignalledError = true;
work->workletsProcessed = 1u;
work->result = C2_CORRUPTED;
return;
}
}
if (eos) {
drainInternal(DRAIN_COMPONENT_WITH_EOS, pool, work);
mSignalledInputEos = true;
} else if (hasPicture) {
finishWork(&entry);
/* Avoid stock frame, continue to search available output */
ensureDecoderState(pool);
hasPicture = false;
if (sendPacketFlag == false) {
goto inPacket;
}
goto outframe;
} else if (err == C2_NO_MEMORY) {
// update new size config.
C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
std::vector<std::unique_ptr<C2SettingResult>> failures;
err = mIntf->config({&size}, C2_MAY_BLOCK, &failures);
if (err != OK) {
c2_err("failed to set width and height");
mSignalledError = true;
work->workletsProcessed = 1u;
work->result = C2_CORRUPTED;
return;
}
err = updateOutputDelay();
if (err != C2_OK) {
c2_err("failed to update output delay, ret %d", err);
return;
}
ensureDecoderState(pool);
// feekback config update to first output frame.
mSizeInfoUpdate = true;
goto outframe;
} else if (outfrmCnt == 0) {
usleep(1000);
if (mLowLatencyMode && flags == 0) {
goto outframe;
}
}
}
void C2RKMpiDec::setDefaultCodecColorAspectsIfNeeded(ColorAspects &aspects) {
typedef ColorAspects CA;
// reset unsupport other aspect
if (aspects.mMatrixCoeffs == CA::MatrixOther)
aspects.mMatrixCoeffs = CA::MatrixUnspecified;
if (aspects.mPrimaries == CA::PrimariesOther)
aspects.mPrimaries = CA::PrimariesUnspecified;
static const ALookup<CA::Primaries, CA::MatrixCoeffs> sPMAspectMap = {
{
{ CA::PrimariesUnspecified, CA::MatrixUnspecified },
{ CA::PrimariesBT709_5, CA::MatrixBT709_5 },
{ CA::PrimariesBT601_6_625, CA::MatrixBT601_6 },
{ CA::PrimariesBT601_6_525, CA::MatrixBT601_6 },
{ CA::PrimariesBT2020, CA::MatrixBT2020 },
{ CA::PrimariesBT470_6M, CA::MatrixBT470_6M },
}
};
if (aspects.mMatrixCoeffs == CA::MatrixUnspecified
&& aspects.mPrimaries != CA::PrimariesUnspecified) {
sPMAspectMap.map(aspects.mPrimaries, &aspects.mMatrixCoeffs);
} else if (aspects.mPrimaries == CA::PrimariesUnspecified
&& aspects.mMatrixCoeffs != CA::MatrixUnspecified) {
if (aspects.mMatrixCoeffs == CA::MatrixBT601_6) {
if ((mWidth <= 720 && mHeight <= 480) || (mHeight <= 720 && mWidth <= 480)) {
aspects.mPrimaries = CA::PrimariesBT601_6_525;
} else {
aspects.mPrimaries = CA::PrimariesBT601_6_625;
}
} else {
sPMAspectMap.map(aspects.mMatrixCoeffs, &aspects.mPrimaries);
}
}
}
void C2RKMpiDec::getVuiParams(MppFrame frame) {
VuiColorAspects aspects;
aspects.primaries = mpp_frame_get_color_primaries(frame);
aspects.transfer = mpp_frame_get_color_trc(frame);
aspects.coeffs = mpp_frame_get_colorspace(frame);
if (mCodingType == MPP_VIDEO_CodingMPEG2) {
aspects.fullRange = 0;
} else {
aspects.fullRange =
(mpp_frame_get_color_range(frame) == MPP_FRAME_RANGE_JPEG);
}
// convert vui aspects to C2 values if changed
if (!(aspects == mBitstreamColorAspects)) {
mBitstreamColorAspects = aspects;
ColorAspects sfAspects;
C2StreamColorAspectsInfo::input codedAspects = { 0u };
c2_info("Got vui color aspects, P(%d) T(%d) M(%d) R(%d)",
aspects.primaries, aspects.transfer,
aspects.coeffs, aspects.fullRange);
ColorUtils::convertIsoColorAspectsToCodecAspects(
aspects.primaries, aspects.transfer, aspects.coeffs,
aspects.fullRange, sfAspects);
setDefaultCodecColorAspectsIfNeeded(sfAspects);
if (!C2Mapper::map(sfAspects.mPrimaries, &codedAspects.primaries)) {
codedAspects.primaries = C2Color::PRIMARIES_UNSPECIFIED;
}
if (!C2Mapper::map(sfAspects.mRange, &codedAspects.range)) {
codedAspects.range = C2Color::RANGE_UNSPECIFIED;
}
if (!C2Mapper::map(sfAspects.mMatrixCoeffs, &codedAspects.matrix)) {
codedAspects.matrix = C2Color::MATRIX_UNSPECIFIED;
}
if (!C2Mapper::map(sfAspects.mTransfer, &codedAspects.transfer)) {
codedAspects.transfer = C2Color::TRANSFER_UNSPECIFIED;
}
std::vector<std::unique_ptr<C2SettingResult>> failures;
mIntf->config({&codedAspects}, C2_MAY_BLOCK, &failures);
c2_info("set colorAspects (R:%d(%s), P:%d(%s), M:%d(%s), T:%d(%s))",
sfAspects.mRange, asString(sfAspects.mRange),
sfAspects.mPrimaries, asString(sfAspects.mPrimaries),
sfAspects.mMatrixCoeffs, asString(sfAspects.mMatrixCoeffs),
sfAspects.mTransfer, asString(sfAspects.mTransfer));
}
}
/* copy output MppBuffer, if not output buffer specified, copy to mOutBlock default. */
c2_status_t C2RKMpiDec::copyOutputBuffer(MppBuffer srcBuffer, MppBuffer dstBuffer) {
RgaInfo srcInfo, dstInfo;
int32_t srcFd = 0, dstFd = 0;
srcFd = mpp_buffer_get_fd(srcBuffer);
if (dstBuffer != nullptr) {
dstFd = mpp_buffer_get_fd(dstBuffer);
} else {
auto c2Handle = mOutBlock->handle();
dstFd = c2Handle->data[0];
}
C2RKRgaDef::SetRgaInfo(&srcInfo, srcFd, mWidth, mHeight, mHorStride, mVerStride);
C2RKRgaDef::SetRgaInfo(&dstInfo, dstFd, mWidth, mHeight, mHorStride, mVerStride);
if (C2RKRgaDef::NV12ToNV12(srcInfo, dstInfo)) {
return C2_OK;
}
/* try CPU copy if get rga process fail */
uint8_t *srcPtr = (uint8_t*)mpp_buffer_get_ptr(srcBuffer);
uint8_t *dstPtr = nullptr;
if (dstBuffer != nullptr) {
// store outdated decode output
dstPtr = (uint8_t*)mpp_buffer_get_ptr(dstBuffer);
} else {
// copy mppBuffer to output mOutBlock
C2GraphicView wView = mOutBlock->map().get();
dstPtr = wView.data()[C2PlanarLayout::PLANE_Y];
}
memcpy(dstPtr, srcPtr, mHorStride * mVerStride * 3 / 2);
return C2_OK;
}
c2_status_t C2RKMpiDec::sendpacket(uint8_t *data, size_t size, uint64_t pts, uint32_t flags) {
c2_status_t ret = C2_OK;
MppPacket packet = nullptr;
mpp_packet_init(&packet, data, size);
mpp_packet_set_pts(packet, pts);
mpp_packet_set_pos(packet, data);
mpp_packet_set_length(packet, size);
if (flags & C2FrameData::FLAG_END_OF_STREAM) {
c2_info("send input eos");
mpp_packet_set_eos(packet);
}
if (flags & C2FrameData::FLAG_CODEC_CONFIG) {
mpp_packet_set_extra_data(packet);
}
MPP_RET err = MPP_OK;
uint32_t kMaxRetryNum = 3;
uint32_t retry = 0;
while (true) {
err = mMppMpi->decode_put_packet(mMppCtx, packet);
if (err == MPP_OK) {
c2_trace("send packet pts %lld size %d", pts, size);
/* dump input data if neccessary */
mDump->recordInFile(data, size);
/* dump show input process fps if neccessary */
mDump->showDebugFps(DUMP_ROLE_INPUT);
break;
}
if ((++retry) > kMaxRetryNum) {
ret = C2_CORRUPTED;
break;
}
usleep(4 * 1000);
}
mpp_packet_deinit(&packet);
return ret;
}
c2_status_t C2RKMpiDec::getoutframe(OutWorkEntry *entry, bool needGetFrame) {
c2_status_t ret = C2_OK;
MPP_RET err = MPP_OK;
MppFrame frame = nullptr;
uint64_t pts = 0;
uint32_t tryCount = 0;
std::shared_ptr<C2GraphicBlock> outblock = nullptr;
REDO:
err = mMppMpi->decode_get_frame(mMppCtx, &frame);
tryCount++;
if (MPP_OK != err || !frame) {
if (needGetFrame == true && tryCount < 10) {
c2_info("need to get frame");
usleep(5 * 1000);
goto REDO;
}
return C2_NOT_FOUND;
}
uint32_t width = mpp_frame_get_width(frame);
uint32_t height = mpp_frame_get_height(frame);
uint32_t hstride = mpp_frame_get_hor_stride(frame);
uint32_t vstride = mpp_frame_get_ver_stride(frame);
MppFrameFormat format = mpp_frame_get_fmt(frame);
if (mpp_frame_get_info_change(frame)) {
c2_info("info-change with old dimensions(%dx%d) stride(%dx%d) fmt %d", \
mWidth, mHeight, mHorStride, mVerStride, mColorFormat);
c2_info("info-change with new dimensions(%dx%d) stride(%dx%d) fmt %d", \
width, height, hstride, vstride, format);
if (width > kMaxVideoWidth || height > kMaxVideoWidth) {
c2_err("unsupport video size %dx%d, signalled Error.", width, height);
ret = C2_CORRUPTED;
goto exit;
}
if (!mBufferMode) {
clearOutBuffers();
mpp_buffer_group_clear(mFrmGrp);
}
/*
* All buffer group config done. Set info change ready to let
* decoder continue decoding
*/
err = mMppMpi->control(mMppCtx, MPP_DEC_SET_INFO_CHANGE_READY, nullptr);
if (err) {
c2_err("failed to set info-change ready, ret %d", ret);
ret = C2_CORRUPTED;
goto exit;
}
mWidth = width;
mHeight = height;
mHorStride = hstride;
mVerStride = vstride;
mColorFormat = format;
if (MPP_FRAME_FMT_IS_FBC(mColorFormat)) {
mFbcCfg.mode = RT_COMPRESS_AFBC_16x16;
} else {
mFbcCfg.mode = 0;
}
ret = C2_NO_MEMORY;
} else {
uint32_t err = mpp_frame_get_errinfo(frame);
uint32_t eos = mpp_frame_get_eos(frame);
MppBuffer mppBuffer = mpp_frame_get_buffer(frame);
pts = mpp_frame_get_pts(frame);
c2_trace("get one frame [%d:%d] stride [%d:%d] pts %lld err %d eos %d",
width, height, hstride, vstride, pts, err, eos);
if (eos) {
c2_info("get output eos.");
mOutputEos = true;
// ignore null frame with eos
if (!mppBuffer) goto exit;
}
if (mBufferMode) {
if (mHalPixelFormat == HAL_PIXEL_FORMAT_YCBCR_P010) {
C2GraphicView wView = mOutBlock->map().get();
C2PlanarLayout layout = wView.layout();
uint8_t *src = (uint8_t*)mpp_buffer_get_ptr(mppBuffer);
uint8_t *dstY = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_Y]);
uint8_t *dstUV = const_cast<uint8_t *>(wView.data()[C2PlanarLayout::PLANE_U]);
size_t dstYStride = layout.planes[C2PlanarLayout::PLANE_Y].rowInc;
size_t dstUVStride = layout.planes[C2PlanarLayout::PLANE_U].rowInc;
C2RKMediaUtils::convert10BitNV12ToP010(
dstY, dstUV, dstYStride, dstUVStride,
src, hstride, vstride, width, height);
} else {
// copy mppBuffer to output mOutBlock in buffer mode
copyOutputBuffer(mppBuffer);
}
outblock = mOutBlock;
} else {
OutBuffer *outBuffer = findOutBuffer(mppBuffer);
if (!outBuffer) {
// new surface generation means all output buffers need to be reset, but
// outdated buffer still work in mpp decoder. in this case, we use new
// generation buffer to store outdated decode output.
c2_warn("get outdated mppBuffer %p, drain it.", mppBuffer);
MppBuffer newBuffer = nullptr;
mpp_buffer_get(mFrmGrp, &newBuffer, 1);
outBuffer = findOutBuffer(newBuffer);
if (!outBuffer) {
c2_err("not find newBuffer %p in outBuffer list.", newBuffer);
goto exit;
} else {
copyOutputBuffer(mppBuffer, newBuffer);
mppBuffer = newBuffer;
}
} else {
mpp_buffer_inc_ref(mppBuffer);
}
outBuffer->site = BUFFER_SITE_BY_C2;
outblock = outBuffer->block;
}
if (mCodingType == MPP_VIDEO_CodingAVC ||
mCodingType == MPP_VIDEO_CodingHEVC ||
mCodingType == MPP_VIDEO_CodingMPEG2) {
getVuiParams(frame);
}
if (mScaleEnabled) {
configFrameScaleMeta(frame, outblock);
}
/* dump output data if neccessary */
if (C2RKDump::getDumpFlag() & C2_DUMP_RECORD_DEC_OUT) {
void *data = mpp_buffer_get_ptr(mppBuffer);
mDump->recordOutFile(data, hstride, vstride, RAW_TYPE_YUV420SP);
}
/* dump show output process fps if neccessary */
mDump->showDebugFps(DUMP_ROLE_OUTPUT);
ret = C2_OK;
}
exit:
if (frame) {
mpp_frame_deinit(&frame);
frame = nullptr;
}
entry->outblock = outblock;
entry->timestamp = pts;
return ret;
}
c2_status_t C2RKMpiDec::checkSurfaceConfig(std::shared_ptr<C2GraphicBlock> block) {
if (!mScaleEnabled) {
updateScaleCfg(block);
}
uint32_t bqSlot, width, height, format, stride, generation;
uint64_t usage, bqId;
auto c2Handle = block->handle();
android::_UnwrapNativeCodec2GrallocMetadata(
c2Handle, &width, &height, &format, &usage,
&stride, &generation, &bqId, &bqSlot);
if (mGeneration == 0) {
mGeneration = generation;
} else if (mGeneration != generation) {
c2_info("generation change to %d, clear old buffer", generation);
clearOldGenerationOutBuffers(generation);
mpp_buffer_group_clear(mFrmGrp);
mGeneration = generation;
return C2_NO_MEMORY;
}
return C2_OK;
}
c2_status_t C2RKMpiDec::commitBufferToMpp(std::shared_ptr<C2GraphicBlock> block) {
auto c2Handle = block->handle();
uint32_t fd = c2Handle->data[0];
uint32_t bqSlot, width, height, format, stride, generation;
uint64_t usage, bqId;
android::_UnwrapNativeCodec2GrallocMetadata(
c2Handle, &width, &height, &format, &usage,
&stride, &generation, &bqId, &bqSlot);
auto GetC2BlockSize
= [c2Handle, width, height, format, usage, stride]() -> uint32_t {
gralloc_private_handle_t pHandle;
buffer_handle_t bHandle;
native_handle_t *nHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
GraphicBufferMapper &gm(GraphicBufferMapper::get());
gm.importBuffer(const_cast<native_handle_t *>(nHandle),
width, height, 1, format, usage,
stride, &bHandle);
Rockchip_get_gralloc_private((uint32_t *)bHandle, &pHandle);
gm.freeBuffer(bHandle);
native_handle_delete(nHandle);
return pHandle.size;
};
OutBuffer *buffer = findOutBuffer(bqSlot);
if (buffer) {
/* commit this buffer back to mpp */
MppBuffer mppBuffer = buffer->mppBuffer;
if (mppBuffer) {
mpp_buffer_put(mppBuffer);
}
buffer->block = block;
buffer->site = BUFFER_SITE_BY_MPI;
c2_trace("put this buffer, slot %d fd %d gene %d mppBuf %p",
bqSlot, fd, generation, mppBuffer);
} else {
/* register this buffer to mpp group */
MppBuffer mppBuffer;
MppBufferInfo info;
memset(&info, 0, sizeof(info));
info.type = MPP_BUFFER_TYPE_ION;
info.fd = fd;
info.ptr = nullptr;
info.hnd = nullptr;
info.size = GetC2BlockSize();
info.index = bqSlot;
mpp_buffer_import_with_tag(
mFrmGrp, &info, &mppBuffer, "codec2", __FUNCTION__);
OutBuffer *buffer = new OutBuffer;
buffer->index = bqSlot;
buffer->mppBuffer = mppBuffer;
buffer->block = block;
buffer->site = BUFFER_SITE_BY_MPI;
buffer->generation = generation;
mpp_buffer_put(mppBuffer);
mOutBuffers.push(buffer);
c2_trace("import this buffer, slot %d fd %d size %d mppBuf %p gene %d listSize %d",
bqSlot, fd, info.size, mppBuffer, generation, mOutBuffers.size());
}
return C2_OK;
}
c2_status_t C2RKMpiDec::ensureDecoderState(
const std::shared_ptr<C2BlockPool> &pool) {
c2_status_t ret = C2_OK;
uint32_t blockW = mHorStride;
uint32_t blockH = mVerStride;
uint64_t usage = RK_GRALLOC_USAGE_SPECIFY_STRIDE;
uint32_t format = C2RKMediaUtils::colorFormatMpiToAndroid(mColorFormat, mFbcCfg.mode);
if (mBufferMode && mHalPixelFormat == HAL_PIXEL_FORMAT_YCBCR_P010) {
format = HAL_PIXEL_FORMAT_YCBCR_P010;
}
std::lock_guard<std::mutex> lock(mPoolMutex);
// NOTE: private grallc align flag only support in gralloc 4.0.
if (mGrallocVersion == 4) {
blockW = mWidth;
usage = C2RKMediaUtils::getStrideUsage(mWidth, mHorStride);
blockH = mHeight;
usage |= C2RKMediaUtils::getHStrideUsage(mHeight, mVerStride);
}
if (mFbcCfg.mode) {
// NOTE: FBC case may have offset y on top and vertical stride
// should aligned to 16.
blockH = C2_ALIGN(mVerStride + mFbcCfg.paddingY, 16);
// In fbc 10bit mode, treat width of buffer as pixer_stride.
if (format == HAL_PIXEL_FORMAT_YUV420_10BIT_I ||
format == HAL_PIXEL_FORMAT_Y210) {
blockW = C2_ALIGN(mWidth, 64);
}
} else if (mCodingType == MPP_VIDEO_CodingVP9 && mGrallocVersion < 4) {
// vp9 need odd 256 align
blockW = C2_ALIGN_ODD(mWidth, 256);
}
switch(mTransfer) {
case ColorTransfer::kColorTransferST2084:
usage |= ((GRALLOC_NV12_10_HDR_10 << 24) & GRALLOC_COLOR_SPACE_MASK); // hdr10;
break;
case ColorTransfer::kColorTransferHLG:
usage |= ((GRALLOC_NV12_10_HDR_HLG << 24) & GRALLOC_COLOR_SPACE_MASK); // hdr-hlg
break;
}
switch (mPrimaries) {
case C2Color::PRIMARIES_BT601_525:
usage |= MALI_GRALLOC_USAGE_YUV_COLOR_SPACE_BT601;
break;
case C2Color::PRIMARIES_BT709:
usage |= MALI_GRALLOC_USAGE_YUV_COLOR_SPACE_BT709;
break;
}
switch (mRange) {
case C2Color::RANGE_FULL:
usage |= MALI_GRALLOC_USAGE_RANGE_WIDE;
break;
case C2Color::RANGE_LIMITED:
usage |= MALI_GRALLOC_USAGE_RANGE_NARROW;
break;
}
// only large than gralloc 4 can support int64 usage.
// otherwise, gralloc 3 will check high 32bit is empty,
// if not empty, will alloc buffer failed and return
// error. So we need clear high 32 bit.
if (mGrallocVersion < 4) {
usage &= 0xffffffff;
}
if (mScaleEnabled) {
usage |= GRALLOC_USAGE_RKVDEC_SCALING;
}
/*
* For buffer mode, since we don't konw when the last buffer will use
* up by user, so we use MPP internal buffer group, and copy output to
* dst block(mOutBlock).
*/
if (mBufferMode) {
if (mOutBlock &&
(mOutBlock->width() != blockW || mOutBlock->height() != blockH)) {
mOutBlock.reset();
}
if (!mOutBlock) {
usage |= (GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN);
usage |= RK_GRALLOC_USAGE_WITHIN_4G;
ret = pool->fetchGraphicBlock(blockW, blockH, format,
C2AndroidMemoryUsage::FromGrallocUsage(usage),
&mOutBlock);
if (ret != C2_OK) {
c2_err("failed to fetchGraphicBlock, err %d usage 0x%llx", ret, usage);
return ret;
}
c2_trace("required (%dx%d) usage 0x%llx format 0x%x , fetch done",
blockW, blockH, usage, format);
}
} else {
std::shared_ptr<C2GraphicBlock> outblock;
uint32_t count = mIntf->mActualOutputDelay->value - getOutBufferCountOwnByMpi();
uint32_t i = 0;
while (i < count) {
ret = pool->fetchGraphicBlock(blockW, blockH, format,
C2AndroidMemoryUsage::FromGrallocUsage(usage),
&outblock);
if (ret != C2_OK) {
c2_err("failed to fetchGraphicBlock, err %d", ret);
break;
}
ret = checkSurfaceConfig(outblock);
if (ret == C2_NO_MEMORY) {
c2_info("get surface changed, update output buffer");
count = mIntf->mActualOutputDelay->value - getOutBufferCountOwnByMpi();
i = 0;
}
if (outblock) {
commitBufferToMpp(outblock);
i++;
}
}
c2_trace("required (%dx%d) usage 0x%llx format 0x%x, fetch %d/%d",
blockW, blockH, usage, format, i, count);
}
return ret;
}
c2_status_t C2RKMpiDec::updateOutputDelay() {
c2_status_t err = C2_OK;
uint32_t outputDelay = 0;
C2StreamPictureSizeInfo::output size(0u, mWidth, mHeight);
C2StreamProfileLevelInfo::input profileLevel(0u, PROFILE_UNUSED, LEVEL_UNUSED);
err = mIntf->query(
{ &size, &profileLevel },
{},
C2_DONT_BLOCK,
nullptr);
outputDelay = C2RKMediaUtils::calculateOutputDelay(size.width, size.height,
mCodingType, profileLevel.level);
c2_info("codec(%d) video(%dx%d) profile&level(%d %d) needs %d reference frames",
mCodingType, size.width, size.height,
profileLevel.profile, profileLevel.level, outputDelay);
C2PortActualDelayTuning::output tuningOutputDelay(outputDelay);
std::vector<std::unique_ptr<C2SettingResult>> failures;
err = mIntf->config({&tuningOutputDelay},
C2_MAY_BLOCK,
&failures);
return err;
}
c2_status_t C2RKMpiDec::updateScaleCfg(std::shared_ptr<C2GraphicBlock> block) {
if (!mScaleEnabled && C2RKChipFeaturesDef::getScaleMetaCap()) {
auto c2Handle = block->handle();
native_handle_t *nHandle = UnwrapNativeCodec2GrallocHandle(c2Handle);
int enable = C2VdecExtendFeature::checkNeedScale((buffer_handle_t)nHandle);
if (enable == 1) {
MppDecCfg cfg;
mpp_dec_cfg_init(&cfg);
mMppMpi->control(mMppCtx, MPP_DEC_GET_CFG, cfg);
if(!mpp_dec_cfg_set_u32(cfg, "base:enable_thumbnail", enable)) {
mScaleEnabled = true;
}
mMppMpi->control(mMppCtx, MPP_DEC_SET_CFG, cfg);
mpp_dec_cfg_deinit(cfg);
c2_info("enable scale dec %d.", enable);
}
native_handle_delete(nHandle);
}
return C2_OK;
}
c2_status_t C2RKMpiDec::configFrameScaleMeta(
MppFrame frame, std::shared_ptr<C2GraphicBlock> block) {
if (block && block->handle()
&& mpp_frame_has_meta(frame) && mpp_frame_get_thumbnail_en(frame)) {
MppMeta meta = NULL;
int32_t scaleYOffset = 0;
int32_t scaleUVOffset = 0;
int32_t width = 0, height = 0;
MppFrameFormat format;
C2PreScaleParam scaleParam;
memset(&scaleParam, 0, sizeof(C2PreScaleParam));
native_handle_t *nHandle = UnwrapNativeCodec2GrallocHandle(block->handle());
width = mpp_frame_get_width(frame);
height = mpp_frame_get_height(frame);
format = mpp_frame_get_fmt(frame);
meta = mpp_frame_get_meta(frame);
mpp_meta_get_s32(meta, KEY_DEC_TBN_Y_OFFSET, &scaleYOffset);
mpp_meta_get_s32(meta, KEY_DEC_TBN_UV_OFFSET, &scaleUVOffset);
scaleParam.thumbWidth = width >> 1;
scaleParam.thumbHeight = height >> 1;
scaleParam.thumbHorStride = C2_ALIGN(mHorStride >> 1, 16);
scaleParam.yOffset = scaleYOffset;
scaleParam.uvOffset = scaleUVOffset;
if ((format & MPP_FRAME_FMT_MASK) == MPP_FMT_YUV420SP_10BIT) {
scaleParam.format = HAL_PIXEL_FORMAT_YCrCb_NV12_10;
} else {
scaleParam.format = HAL_PIXEL_FORMAT_YCrCb_NV12;
}
C2VdecExtendFeature::configFrameScaleMeta(nHandle, &scaleParam);
memcpy((void *)&block->handle()->data,
(void *)&nHandle->data,
sizeof(int) * (nHandle->numFds + nHandle->numInts));
native_handle_delete(nHandle);
}
return C2_OK;
}
class C2RKMpiDecFactory : public C2ComponentFactory {
public:
explicit C2RKMpiDecFactory(std::string componentName)
: mHelper(std::static_pointer_cast<C2ReflectorHelper>(
GetCodec2PlatformComponentStore()->getParamReflector())),
mComponentName(componentName) {
if (!C2RKMediaUtils::getMimeFromComponentName(componentName, &mMime)) {
c2_err("failed to get mime from component %s", componentName.c_str());
}
if (!C2RKMediaUtils::getDomainFromComponentName(componentName, &mDomain)) {
c2_err("failed to get domain from component %s", componentName.c_str());
}
if (!C2RKMediaUtils::getKindFromComponentName(componentName, &mKind)) {
c2_err("failed to get kind from component %s", componentName.c_str());
}
}
virtual c2_status_t createComponent(
c2_node_id_t id,
std::shared_ptr<C2Component>* const component,
std::function<void(C2Component*)> deleter) override {
if (sDecConcurrentInstances.load() >= kMaxDecConcurrentInstances) {
c2_warn("Reject to Initialize() due to too many dec instances: %d",
sDecConcurrentInstances.load());
return C2_NO_MEMORY;
}
*component = std::shared_ptr<C2Component>(
new C2RKMpiDec(
mComponentName.c_str(),
id,
std::make_shared<C2RKMpiDec::IntfImpl>
(mHelper, mComponentName, mKind, mDomain, mMime)),
deleter);
return C2_OK;
}
virtual c2_status_t createInterface(
c2_node_id_t id,
std::shared_ptr<C2ComponentInterface>* const interface,
std::function<void(C2ComponentInterface*)> deleter) override {
*interface = std::shared_ptr<C2ComponentInterface>(
new C2RKInterface<C2RKMpiDec::IntfImpl>(
mComponentName.c_str(),
id,
std::make_shared<C2RKMpiDec::IntfImpl>
(mHelper, mComponentName, mKind, mDomain, mMime)),
deleter);
return C2_OK;
}
virtual ~C2RKMpiDecFactory() override = default;
private:
std::shared_ptr<C2ReflectorHelper> mHelper;
std::string mComponentName;
std::string mMime;
C2Component::kind_t mKind;
C2Component::domain_t mDomain;
};
C2ComponentFactory* CreateRKMpiDecFactory(std::string componentName) {
return new ::android::C2RKMpiDecFactory(componentName);
}
} // namespace android