Loading media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp +23 −537 Original line number Diff line number Diff line Loading @@ -83,139 +83,6 @@ std::shared_ptr<C2ComponentInterface> BuildIntf( .build(); } #if 0 using SupportedValuesWithFields = C2SoftAvcDecIntf::SupportedValuesWithFields; struct ValidateParam { explicit ValidateParam( const std::map<C2ParamField, SupportedValuesWithFields> &supportedValues) : mSupportedValues(supportedValues) {} template <class T, bool SIGNED = std::is_signed<T>::value, size_t SIZE = sizeof(T)> struct Getter { static T get(const C2Value::Primitive &) { static_assert(!std::is_arithmetic<T>::value, "non-arithmetic type"); static_assert(!std::is_floating_point<T>::value || std::is_same<T, float>::value, "float is the only supported floating point type"); static_assert(sizeof(T) <= 8, "type exceeds 64-bit"); } }; template <class T> bool validateField( const C2FieldSupportedValues &supportedValues, const T &value) { switch (supportedValues.type) { case C2FieldSupportedValues::EMPTY: { return false; } case C2FieldSupportedValues::RANGE: { // TODO: handle step, num, denom return Getter<T>::get(supportedValues.range.min) <= value && value <= Getter<T>::get(supportedValues.range.max); } case C2FieldSupportedValues::VALUES: { for (const auto &val : supportedValues.values) { if (Getter<T>::get(val) == value) { return true; } } return false; } case C2FieldSupportedValues::FLAGS: // TODO return false; } return false; } protected: const std::map<C2ParamField, SupportedValuesWithFields> &mSupportedValues; }; template <> struct ValidateParam::Getter<float> { static float get(const C2Value::Primitive &value) { return value.fp; } }; template <class T> struct ValidateParam::Getter<T, true, 8u> { static int64_t get(const C2Value::Primitive &value) { return value.i64; } }; template <class T> struct ValidateParam::Getter<T, true, 4u> { static int32_t get(const C2Value::Primitive &value) { return value.i32; } }; template <class T> struct ValidateParam::Getter<T, false, 8u> { static uint64_t get(const C2Value::Primitive &value) { return value.u64; } }; template <class T> struct ValidateParam::Getter<T, false, 4u> { static uint32_t get(const C2Value::Primitive &value) { return value.u32; } }; template <class T> struct ValidateSimpleParam : public ValidateParam { explicit ValidateSimpleParam( const std::map<C2ParamField, SupportedValuesWithFields> &supportedValues) : ValidateParam(supportedValues) {} std::unique_ptr<C2SettingResult> operator() (C2Param *c2param) { T* param = (T*)c2param; C2ParamField field(param, &T::value); const C2FieldSupportedValues &supportedValues = mSupportedValues.at(field).supported; if (!validateField(supportedValues, param->value)) { return std::unique_ptr<C2SettingResult>( new C2SettingResult {C2SettingResult::BAD_VALUE, {field, nullptr}, {}}); } return nullptr; } }; template <class T> struct ValidateVideoSize : public ValidateParam { explicit ValidateVideoSize( const std::map<C2ParamField, SupportedValuesWithFields> &supportedValues) : ValidateParam(supportedValues) {} std::unique_ptr<C2SettingResult> operator() (C2Param *c2param) { T* param = (T*)c2param; C2ParamField field(param, &T::width); const C2FieldSupportedValues &supportedWidth = mSupportedValues.at(field).supported; if (!validateField(supportedWidth, param->width)) { return std::unique_ptr<C2SettingResult>( new C2SettingResult {C2SettingResult::BAD_VALUE, {field, nullptr}, {}}); } field = C2ParamField(param, &T::height); const C2FieldSupportedValues &supportedHeight = mSupportedValues.at(field).supported; if (!validateField(supportedHeight, param->height)) { return std::unique_ptr<C2SettingResult>( new C2SettingResult {C2SettingResult::BAD_VALUE, {field, nullptr}, {}}); } return nullptr; } }; template <class T> struct ValidateCString { explicit ValidateCString(const char *expected) : mExpected(expected) {} std::unique_ptr<C2SettingResult> operator() (C2Param *c2param) { T* param = (T*)c2param; if (strncmp(param->m.value, mExpected, param->flexCount()) != 0) { return std::unique_ptr<C2SettingResult>( new C2SettingResult {C2SettingResult::BAD_VALUE, {C2ParamField(param, &T::m), nullptr}, {}}); } return nullptr; } private: const char *mExpected; }; #endif void fillEmptyWork(const std::unique_ptr<C2Work> &work) { uint32_t flags = 0; if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM)) { Loading @@ -229,398 +96,6 @@ void fillEmptyWork(const std::unique_ptr<C2Work> &work) { } // namespace #if 0 #define CASE(member) \ case decltype(component->member)::CORE_INDEX: \ return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor( \ static_cast<decltype(component->member) *>(nullptr))) class C2SoftAvcDecIntf::ParamReflector : public C2ParamReflector { public: virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) override { constexpr C2SoftAvcDecIntf *component = nullptr; switch (coreIndex.coreIndex()) { CASE(mDomainInfo); CASE(mInputStreamCount); CASE(mInputStreamFormat); // Output counterparts for the above would be redundant. CASE(mVideoSize); CASE(mMaxVideoSizeHint); // port mime configs are stored as unique_ptr. case C2PortMimeConfig::CORE_INDEX: return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor( static_cast<C2PortMimeConfig *>(nullptr))); } return nullptr; } }; #undef CASE // static const CodecProfileLevel kProfileLevels[] = { // { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel52 }, // { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel52 }, // { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel52 }, // }; C2SoftAvcDecIntf::C2SoftAvcDecIntf(const char *name, c2_node_id_t id) : mName(name), mId(id), mDomainInfo(C2DomainVideo), mInputStreamCount(1u), mOutputStreamCount(1u), mInputStreamFormat(0u, C2FormatCompressed), mOutputStreamFormat(0u, C2FormatVideo), mProfile(0u, kAvcProfileUnknown), mLevel(0u, kAvcLevelUnknown), mBlockSize(0u), mAlignment(0u), mFrameRate(0u, 0), mBlocksPerSecond(0u, 0), mParamReflector(new ParamReflector) { ALOGV("in %s", __func__); mInputPortMime = C2PortMimeConfig::input::AllocUnique(strlen(CODEC_MIME_TYPE) + 1); strcpy(mInputPortMime->m.value, CODEC_MIME_TYPE); mOutputPortMime = C2PortMimeConfig::output::AllocUnique(strlen(MEDIA_MIMETYPE_VIDEO_RAW) + 1); strcpy(mOutputPortMime->m.value, MEDIA_MIMETYPE_VIDEO_RAW); mVideoSize.width = 320; mVideoSize.height = 240; mBlockSize.width = 16; mBlockSize.height = 16; mAlignment.width = 2; mAlignment.height = 2; mMaxVideoSizeHint.width = H264_MAX_FRAME_WIDTH; mMaxVideoSizeHint.height = H264_MAX_FRAME_HEIGHT; mOutputBlockPools = C2PortBlockPoolsTuning::output::AllocUnique({}); auto insertParam = [¶ms = mParams] (C2Param *param) { params[param->index()] = param; }; auto markReadOnly = [&supported = mSupportedValues] (auto *param) { supported.emplace( C2ParamField(param, &std::remove_pointer<decltype(param)>::type::value), C2FieldSupportedValues(false /* flags */, {})); }; auto markReadOnlyVideoSize = [&supported = mSupportedValues] (auto *param) { supported.emplace( C2ParamField(param, &std::remove_pointer<decltype(param)>::type::width), C2FieldSupportedValues(false /* flags */, {})); supported.emplace( C2ParamField(param, &std::remove_pointer<decltype(param)>::type::height), C2FieldSupportedValues(false /* flags */, {})); }; insertParam(&mDomainInfo); markReadOnly(&mDomainInfo); mFieldVerifiers[mDomainInfo.index()] = ValidateSimpleParam<decltype(mDomainInfo)>(mSupportedValues); insertParam(mInputPortMime.get()); mFieldVerifiers[mInputPortMime->index()] = ValidateCString<std::remove_reference<decltype(*mInputPortMime)>::type>(CODEC_MIME_TYPE); insertParam(&mInputStreamCount); markReadOnly(&mInputStreamCount); mFieldVerifiers[mInputStreamCount.index()] = ValidateSimpleParam<decltype(mInputStreamCount)>(mSupportedValues); insertParam(mOutputPortMime.get()); mFieldVerifiers[mOutputPortMime->index()] = ValidateCString<std::remove_reference<decltype(*mOutputPortMime)>::type>(MEDIA_MIMETYPE_VIDEO_RAW); insertParam(&mOutputStreamCount); markReadOnly(&mOutputStreamCount); mFieldVerifiers[mOutputStreamCount.index()] = ValidateSimpleParam<decltype(mOutputStreamCount)>(mSupportedValues); insertParam(&mInputStreamFormat); markReadOnly(&mInputStreamFormat); mFieldVerifiers[mInputStreamFormat.index()] = ValidateSimpleParam<decltype(mInputStreamFormat)>(mSupportedValues); insertParam(&mOutputStreamFormat); markReadOnly(&mOutputStreamFormat); mFieldVerifiers[mOutputStreamFormat.index()] = ValidateSimpleParam<decltype(mOutputStreamFormat)>(mSupportedValues); insertParam(&mVideoSize); markReadOnlyVideoSize(&mVideoSize); mFieldVerifiers[mVideoSize.index()] = ValidateVideoSize<decltype(mVideoSize)>(mSupportedValues); insertParam(&mMaxVideoSizeHint); mSupportedValues.emplace( C2ParamField(&mMaxVideoSizeHint, &C2MaxVideoSizeHintPortSetting::width), C2FieldSupportedValues(H264_MIN_FRAME_WIDTH, H264_MAX_FRAME_WIDTH, mAlignment.width)); mSupportedValues.emplace( C2ParamField(&mMaxVideoSizeHint, &C2MaxVideoSizeHintPortSetting::height), C2FieldSupportedValues(H264_MIN_FRAME_HEIGHT, H264_MAX_FRAME_HEIGHT, mAlignment.height)); mFieldVerifiers[mMaxVideoSizeHint.index()] = ValidateVideoSize<decltype(mMaxVideoSizeHint)>(mSupportedValues); insertParam(&mProfile); mSupportedValues.emplace( C2ParamField(&mProfile, &C2AvcProfileInfo::value), C2FieldSupportedValues(false /* flags */, { kAvcProfileUnknown, kAvcProfileBaseline, kAvcProfileMain, kAvcProfileHigh, })); mFieldVerifiers[mProfile.index()] = ValidateSimpleParam<decltype(mProfile)>(mSupportedValues); insertParam(&mLevel); mSupportedValues.emplace( C2ParamField(&mLevel, &C2AvcLevelInfo::value), C2FieldSupportedValues(false /* flags */, { kAvcLevelUnknown, kAvcLevel10, kAvcLevel1b, kAvcLevel11, kAvcLevel12, kAvcLevel13, kAvcLevel20, kAvcLevel21, kAvcLevel22, kAvcLevel30, kAvcLevel31, kAvcLevel32, kAvcLevel40, kAvcLevel41, kAvcLevel42, kAvcLevel50, kAvcLevel51, kAvcLevel52, })); mFieldVerifiers[mLevel.index()] = ValidateSimpleParam<decltype(mLevel)>(mSupportedValues); insertParam(&mBlockSize); markReadOnlyVideoSize(&mBlockSize); mFieldVerifiers[mBlockSize.index()] = ValidateVideoSize<decltype(mBlockSize)>(mSupportedValues); insertParam(&mAlignment); markReadOnlyVideoSize(&mAlignment); mFieldVerifiers[mAlignment.index()] = ValidateVideoSize<decltype(mAlignment)>(mSupportedValues); insertParam(&mFrameRate); mSupportedValues.emplace( C2ParamField(&mFrameRate, &C2FrameRateInfo::value), C2FieldSupportedValues(0, 240)); mFieldVerifiers[mFrameRate.index()] = ValidateSimpleParam<decltype(mFrameRate)>(mSupportedValues); insertParam(&mBlocksPerSecond); mSupportedValues.emplace( C2ParamField(&mFrameRate, &C2BlocksPerSecondInfo::value), C2FieldSupportedValues(0, 244800)); mFieldVerifiers[mBlocksPerSecond.index()] = ValidateSimpleParam<decltype(mBlocksPerSecond)>(mSupportedValues); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( true, "_domain", &mDomainInfo)); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( true, "_input_port_mime", mInputPortMime.get())); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( true, "_input_stream_count", &mInputStreamCount)); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( true, "_output_port_mime", mOutputPortMime.get())); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( true, "_output_stream_count", &mOutputStreamCount)); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( true, "_input_stream_format", &mInputStreamFormat)); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( true, "_output_stream_format", &mOutputStreamFormat)); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( false, "_video_size", &mVideoSize)); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( false, "_max_video_size_hint", &mMaxVideoSizeHint)); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( false, "_output_block_pools", mOutputBlockPools.get())); } C2SoftAvcDecIntf::~C2SoftAvcDecIntf() { ALOGV("in %s", __func__); } C2String C2SoftAvcDecIntf::getName() const { return mName; } c2_node_id_t C2SoftAvcDecIntf::getId() const { return mId; } c2_status_t C2SoftAvcDecIntf::query_vb( const std::vector<C2Param*> & stackParams, const std::vector<C2Param::Index> & heapParamIndices, c2_blocking_t mayBlock, std::vector<std::unique_ptr<C2Param>>* const heapParams) const { (void)mayBlock; for (C2Param* const param : stackParams) { if (!*param) { continue; } uint32_t index = param->index(); if (!mParams.count(index)) { // TODO: add support for output-block-pools (this will be done when we move all // config to shared ptr) continue; } C2Param *myParam = mParams.find(index)->second; if (myParam->size() != param->size()) { param->invalidate(); continue; } param->updateFrom(*myParam); } for (const C2Param::Index index : heapParamIndices) { if (mParams.count(index)) { C2Param *myParam = mParams.find(index)->second; heapParams->emplace_back(C2Param::Copy(*myParam)); } } return C2_OK; } c2_status_t C2SoftAvcDecIntf::config_vb( const std::vector<C2Param*> ¶ms, c2_blocking_t mayBlock, std::vector<std::unique_ptr<C2SettingResult>>* const failures) { (void)mayBlock; c2_status_t err = C2_OK; for (C2Param *param : params) { uint32_t index = param->index(); if (param->index() == mOutputBlockPools.get()->index()) { // setting output block pools mOutputBlockPools.reset( (C2PortBlockPoolsTuning::output *)C2Param::Copy(*param).release()); continue; } if (mParams.count(index) == 0) { // We can't create C2SettingResult with no field, so just skipping in this case. err = C2_BAD_INDEX; continue; } C2Param *myParam = mParams.find(index)->second; std::unique_ptr<C2SettingResult> result; if (!(result = mFieldVerifiers[index](param))) { myParam->updateFrom(*param); updateSupportedValues(); } else { failures->push_back(std::move(result)); err = C2_BAD_VALUE; } } return err; } c2_status_t C2SoftAvcDecIntf::createTunnel_sm(c2_node_id_t targetComponent) { // Tunneling is not supported (void) targetComponent; return C2_OMITTED; } c2_status_t C2SoftAvcDecIntf::releaseTunnel_sm(c2_node_id_t targetComponent) { // Tunneling is not supported (void) targetComponent; return C2_OMITTED; } std::shared_ptr<C2ParamReflector> C2SoftAvcDecIntf::getParamReflector() const { return mParamReflector; } c2_status_t C2SoftAvcDecIntf::querySupportedParams_nb( std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const { params->insert(params->begin(), mParamDescs.begin(), mParamDescs.end()); return C2_OK; } c2_status_t C2SoftAvcDecIntf::querySupportedValues_vb( std::vector<C2FieldSupportedValuesQuery> &fields, c2_blocking_t mayBlock) const { (void)mayBlock; c2_status_t res = C2_OK; for (C2FieldSupportedValuesQuery &query : fields) { if (mSupportedValues.count(query.field) == 0) { query.status = C2_BAD_INDEX; res = C2_BAD_INDEX; } else { query.status = C2_OK; query.values = mSupportedValues.at(query.field).supported; } } return res; } void C2SoftAvcDecIntf::updateSupportedValues() { int32_t maxWidth = H264_MAX_FRAME_WIDTH; int32_t maxHeight = H264_MAX_FRAME_HEIGHT; // cf: Rec. ITU-T H.264 A.3 int maxFrameRate = 172; std::vector<C2ParamField> fields; if (mLevel.value != kAvcLevelUnknown) { // cf: Rec. ITU-T H.264 Table A-1 constexpr int MaxFS[] = { // 0 1 2 3 4 5 6 7 8 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 99, 396, 396, 396, 0, 0, 0, 0, 0, 0, 396, 792, 1620, 0, 0, 0, 0, 0, 0, 0, 1620, 3600, 5120, 0, 0, 0, 0, 0, 0, 0, 8192, 8192, 8704, 0, 0, 0, 0, 0, 0, 0, 22080, 36864, 36864, }; constexpr int MaxMBPS[] = { // 0 1 2 3 4 5 6 7 8 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 1485, 1485, 3000, 6000, 11880, 0, 0, 0, 0, 0, 0, 11880, 19800, 20250, 0, 0, 0, 0, 0, 0, 0, 40500, 108000, 216000, 0, 0, 0, 0, 0, 0, 0, 245760, 245760, 522240, 0, 0, 0, 0, 0, 0, 0, 589824, 983040, 2073600, }; // cf: Rec. ITU-T H.264 A.3.1 maxWidth = std::min(maxWidth, floor32(std::sqrt(MaxFS[mLevel.value] * 8)) * MB_SIZE); maxHeight = std::min(maxHeight, floor32(std::sqrt(MaxFS[mLevel.value] * 8)) * MB_SIZE); int32_t MBs = ((mVideoSize.width + 15) / 16) * ((mVideoSize.height + 15) / 16); maxFrameRate = std::min(maxFrameRate, MaxMBPS[mLevel.value] / MBs); fields.push_back(C2ParamField(&mLevel, &C2AvcLevelInfo::value)); } SupportedValuesWithFields &maxWidthVals = mSupportedValues.at( C2ParamField(&mMaxVideoSizeHint, &C2MaxVideoSizeHintPortSetting::width)); maxWidthVals.supported.range.max = maxWidth; maxWidthVals.restrictingFields.clear(); maxWidthVals.restrictingFields.insert(fields.begin(), fields.end()); SupportedValuesWithFields &maxHeightVals = mSupportedValues.at( C2ParamField(&mMaxVideoSizeHint, &C2MaxVideoSizeHintPortSetting::height)); maxHeightVals.supported.range.max = maxHeight; maxHeightVals.restrictingFields.clear(); maxHeightVals.restrictingFields.insert(fields.begin(), fields.end()); SupportedValuesWithFields &frameRate = mSupportedValues.at( C2ParamField(&mFrameRate, &C2FrameRateInfo::value)); frameRate.supported.range.max = maxFrameRate; frameRate.restrictingFields.clear(); frameRate.restrictingFields.insert(fields.begin(), fields.end()); } #endif /////////////////////////////////////////////////////////////////////////////// C2SoftAvcDec::C2SoftAvcDec( Loading Loading @@ -654,6 +129,7 @@ c2_status_t C2SoftAvcDec::onInit() { } c2_status_t C2SoftAvcDec::onStop() { ALOGV("onStop"); mSignalledError = false; resetDecoder(); resetPlugin(); Loading @@ -662,6 +138,7 @@ c2_status_t C2SoftAvcDec::onStop() { } void C2SoftAvcDec::onReset() { ALOGV("onReset"); (void)onStop(); } Loading @@ -672,17 +149,6 @@ void C2SoftAvcDec::onRelease() { c2_status_t C2SoftAvcDec::onFlush_sm() { setFlushMode(); /* Allocate a picture buffer to flushed data */ uint32_t displayStride = mWidth; uint32_t displayHeight = mHeight; uint32_t bufferSize = displayStride * displayHeight * 3 / 2; mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize); if (NULL == mFlushOutBuffer) { ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize); return C2_NO_MEMORY; } while (true) { ivd_video_decode_ip_t s_dec_ip; ivd_video_decode_op_t s_dec_op; Loading Loading @@ -854,6 +320,18 @@ status_t C2SoftAvcDec::setFlushMode() { s_video_flush_op.u4_error_code); return UNKNOWN_ERROR; } /* Allocate a picture buffer to flushed data */ uint32_t displayStride = mWidth; uint32_t displayHeight = mHeight; uint32_t bufferSize = displayStride * displayHeight * 3 / 2; mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize); if (NULL == mFlushOutBuffer) { ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize); return C2_NO_MEMORY; } return OK; } Loading Loading @@ -993,6 +471,7 @@ bool C2SoftAvcDec::setDecodeArgs( ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t); ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t); ps_dec_op->u4_output_present = 0; ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE; Loading Loading @@ -1095,7 +574,7 @@ void C2SoftAvcDec::process( const C2ConstLinearBlock &buffer = work->input.buffers[0]->data().linearBlocks().front(); if (buffer.capacity() == 0) { if (buffer.size() == 0) { ALOGV("empty input: %llu", work->input.ordinal.frameIndex.peekull()); // TODO: result? fillEmptyWork(work); Loading @@ -1109,6 +588,13 @@ void C2SoftAvcDec::process( } C2ReadView input = work->input.buffers[0]->data().linearBlocks().front().map().get(); if (input.error() != C2_OK) { work->result = input.error(); fillEmptyWork(work); ALOGD("map error: %d", input.error()); return; } ALOGV("buffer.size() = %u, input.capacity() = %u", buffer.size(), input.capacity()); uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF; size_t inOffset = 0u; Loading Loading
media/libstagefright/codecs/avcdec/C2SoftAvcDec.cpp +23 −537 Original line number Diff line number Diff line Loading @@ -83,139 +83,6 @@ std::shared_ptr<C2ComponentInterface> BuildIntf( .build(); } #if 0 using SupportedValuesWithFields = C2SoftAvcDecIntf::SupportedValuesWithFields; struct ValidateParam { explicit ValidateParam( const std::map<C2ParamField, SupportedValuesWithFields> &supportedValues) : mSupportedValues(supportedValues) {} template <class T, bool SIGNED = std::is_signed<T>::value, size_t SIZE = sizeof(T)> struct Getter { static T get(const C2Value::Primitive &) { static_assert(!std::is_arithmetic<T>::value, "non-arithmetic type"); static_assert(!std::is_floating_point<T>::value || std::is_same<T, float>::value, "float is the only supported floating point type"); static_assert(sizeof(T) <= 8, "type exceeds 64-bit"); } }; template <class T> bool validateField( const C2FieldSupportedValues &supportedValues, const T &value) { switch (supportedValues.type) { case C2FieldSupportedValues::EMPTY: { return false; } case C2FieldSupportedValues::RANGE: { // TODO: handle step, num, denom return Getter<T>::get(supportedValues.range.min) <= value && value <= Getter<T>::get(supportedValues.range.max); } case C2FieldSupportedValues::VALUES: { for (const auto &val : supportedValues.values) { if (Getter<T>::get(val) == value) { return true; } } return false; } case C2FieldSupportedValues::FLAGS: // TODO return false; } return false; } protected: const std::map<C2ParamField, SupportedValuesWithFields> &mSupportedValues; }; template <> struct ValidateParam::Getter<float> { static float get(const C2Value::Primitive &value) { return value.fp; } }; template <class T> struct ValidateParam::Getter<T, true, 8u> { static int64_t get(const C2Value::Primitive &value) { return value.i64; } }; template <class T> struct ValidateParam::Getter<T, true, 4u> { static int32_t get(const C2Value::Primitive &value) { return value.i32; } }; template <class T> struct ValidateParam::Getter<T, false, 8u> { static uint64_t get(const C2Value::Primitive &value) { return value.u64; } }; template <class T> struct ValidateParam::Getter<T, false, 4u> { static uint32_t get(const C2Value::Primitive &value) { return value.u32; } }; template <class T> struct ValidateSimpleParam : public ValidateParam { explicit ValidateSimpleParam( const std::map<C2ParamField, SupportedValuesWithFields> &supportedValues) : ValidateParam(supportedValues) {} std::unique_ptr<C2SettingResult> operator() (C2Param *c2param) { T* param = (T*)c2param; C2ParamField field(param, &T::value); const C2FieldSupportedValues &supportedValues = mSupportedValues.at(field).supported; if (!validateField(supportedValues, param->value)) { return std::unique_ptr<C2SettingResult>( new C2SettingResult {C2SettingResult::BAD_VALUE, {field, nullptr}, {}}); } return nullptr; } }; template <class T> struct ValidateVideoSize : public ValidateParam { explicit ValidateVideoSize( const std::map<C2ParamField, SupportedValuesWithFields> &supportedValues) : ValidateParam(supportedValues) {} std::unique_ptr<C2SettingResult> operator() (C2Param *c2param) { T* param = (T*)c2param; C2ParamField field(param, &T::width); const C2FieldSupportedValues &supportedWidth = mSupportedValues.at(field).supported; if (!validateField(supportedWidth, param->width)) { return std::unique_ptr<C2SettingResult>( new C2SettingResult {C2SettingResult::BAD_VALUE, {field, nullptr}, {}}); } field = C2ParamField(param, &T::height); const C2FieldSupportedValues &supportedHeight = mSupportedValues.at(field).supported; if (!validateField(supportedHeight, param->height)) { return std::unique_ptr<C2SettingResult>( new C2SettingResult {C2SettingResult::BAD_VALUE, {field, nullptr}, {}}); } return nullptr; } }; template <class T> struct ValidateCString { explicit ValidateCString(const char *expected) : mExpected(expected) {} std::unique_ptr<C2SettingResult> operator() (C2Param *c2param) { T* param = (T*)c2param; if (strncmp(param->m.value, mExpected, param->flexCount()) != 0) { return std::unique_ptr<C2SettingResult>( new C2SettingResult {C2SettingResult::BAD_VALUE, {C2ParamField(param, &T::m), nullptr}, {}}); } return nullptr; } private: const char *mExpected; }; #endif void fillEmptyWork(const std::unique_ptr<C2Work> &work) { uint32_t flags = 0; if ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM)) { Loading @@ -229,398 +96,6 @@ void fillEmptyWork(const std::unique_ptr<C2Work> &work) { } // namespace #if 0 #define CASE(member) \ case decltype(component->member)::CORE_INDEX: \ return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor( \ static_cast<decltype(component->member) *>(nullptr))) class C2SoftAvcDecIntf::ParamReflector : public C2ParamReflector { public: virtual std::unique_ptr<C2StructDescriptor> describe(C2Param::CoreIndex coreIndex) override { constexpr C2SoftAvcDecIntf *component = nullptr; switch (coreIndex.coreIndex()) { CASE(mDomainInfo); CASE(mInputStreamCount); CASE(mInputStreamFormat); // Output counterparts for the above would be redundant. CASE(mVideoSize); CASE(mMaxVideoSizeHint); // port mime configs are stored as unique_ptr. case C2PortMimeConfig::CORE_INDEX: return std::unique_ptr<C2StructDescriptor>(new C2StructDescriptor( static_cast<C2PortMimeConfig *>(nullptr))); } return nullptr; } }; #undef CASE // static const CodecProfileLevel kProfileLevels[] = { // { OMX_VIDEO_AVCProfileBaseline, OMX_VIDEO_AVCLevel52 }, // { OMX_VIDEO_AVCProfileMain, OMX_VIDEO_AVCLevel52 }, // { OMX_VIDEO_AVCProfileHigh, OMX_VIDEO_AVCLevel52 }, // }; C2SoftAvcDecIntf::C2SoftAvcDecIntf(const char *name, c2_node_id_t id) : mName(name), mId(id), mDomainInfo(C2DomainVideo), mInputStreamCount(1u), mOutputStreamCount(1u), mInputStreamFormat(0u, C2FormatCompressed), mOutputStreamFormat(0u, C2FormatVideo), mProfile(0u, kAvcProfileUnknown), mLevel(0u, kAvcLevelUnknown), mBlockSize(0u), mAlignment(0u), mFrameRate(0u, 0), mBlocksPerSecond(0u, 0), mParamReflector(new ParamReflector) { ALOGV("in %s", __func__); mInputPortMime = C2PortMimeConfig::input::AllocUnique(strlen(CODEC_MIME_TYPE) + 1); strcpy(mInputPortMime->m.value, CODEC_MIME_TYPE); mOutputPortMime = C2PortMimeConfig::output::AllocUnique(strlen(MEDIA_MIMETYPE_VIDEO_RAW) + 1); strcpy(mOutputPortMime->m.value, MEDIA_MIMETYPE_VIDEO_RAW); mVideoSize.width = 320; mVideoSize.height = 240; mBlockSize.width = 16; mBlockSize.height = 16; mAlignment.width = 2; mAlignment.height = 2; mMaxVideoSizeHint.width = H264_MAX_FRAME_WIDTH; mMaxVideoSizeHint.height = H264_MAX_FRAME_HEIGHT; mOutputBlockPools = C2PortBlockPoolsTuning::output::AllocUnique({}); auto insertParam = [¶ms = mParams] (C2Param *param) { params[param->index()] = param; }; auto markReadOnly = [&supported = mSupportedValues] (auto *param) { supported.emplace( C2ParamField(param, &std::remove_pointer<decltype(param)>::type::value), C2FieldSupportedValues(false /* flags */, {})); }; auto markReadOnlyVideoSize = [&supported = mSupportedValues] (auto *param) { supported.emplace( C2ParamField(param, &std::remove_pointer<decltype(param)>::type::width), C2FieldSupportedValues(false /* flags */, {})); supported.emplace( C2ParamField(param, &std::remove_pointer<decltype(param)>::type::height), C2FieldSupportedValues(false /* flags */, {})); }; insertParam(&mDomainInfo); markReadOnly(&mDomainInfo); mFieldVerifiers[mDomainInfo.index()] = ValidateSimpleParam<decltype(mDomainInfo)>(mSupportedValues); insertParam(mInputPortMime.get()); mFieldVerifiers[mInputPortMime->index()] = ValidateCString<std::remove_reference<decltype(*mInputPortMime)>::type>(CODEC_MIME_TYPE); insertParam(&mInputStreamCount); markReadOnly(&mInputStreamCount); mFieldVerifiers[mInputStreamCount.index()] = ValidateSimpleParam<decltype(mInputStreamCount)>(mSupportedValues); insertParam(mOutputPortMime.get()); mFieldVerifiers[mOutputPortMime->index()] = ValidateCString<std::remove_reference<decltype(*mOutputPortMime)>::type>(MEDIA_MIMETYPE_VIDEO_RAW); insertParam(&mOutputStreamCount); markReadOnly(&mOutputStreamCount); mFieldVerifiers[mOutputStreamCount.index()] = ValidateSimpleParam<decltype(mOutputStreamCount)>(mSupportedValues); insertParam(&mInputStreamFormat); markReadOnly(&mInputStreamFormat); mFieldVerifiers[mInputStreamFormat.index()] = ValidateSimpleParam<decltype(mInputStreamFormat)>(mSupportedValues); insertParam(&mOutputStreamFormat); markReadOnly(&mOutputStreamFormat); mFieldVerifiers[mOutputStreamFormat.index()] = ValidateSimpleParam<decltype(mOutputStreamFormat)>(mSupportedValues); insertParam(&mVideoSize); markReadOnlyVideoSize(&mVideoSize); mFieldVerifiers[mVideoSize.index()] = ValidateVideoSize<decltype(mVideoSize)>(mSupportedValues); insertParam(&mMaxVideoSizeHint); mSupportedValues.emplace( C2ParamField(&mMaxVideoSizeHint, &C2MaxVideoSizeHintPortSetting::width), C2FieldSupportedValues(H264_MIN_FRAME_WIDTH, H264_MAX_FRAME_WIDTH, mAlignment.width)); mSupportedValues.emplace( C2ParamField(&mMaxVideoSizeHint, &C2MaxVideoSizeHintPortSetting::height), C2FieldSupportedValues(H264_MIN_FRAME_HEIGHT, H264_MAX_FRAME_HEIGHT, mAlignment.height)); mFieldVerifiers[mMaxVideoSizeHint.index()] = ValidateVideoSize<decltype(mMaxVideoSizeHint)>(mSupportedValues); insertParam(&mProfile); mSupportedValues.emplace( C2ParamField(&mProfile, &C2AvcProfileInfo::value), C2FieldSupportedValues(false /* flags */, { kAvcProfileUnknown, kAvcProfileBaseline, kAvcProfileMain, kAvcProfileHigh, })); mFieldVerifiers[mProfile.index()] = ValidateSimpleParam<decltype(mProfile)>(mSupportedValues); insertParam(&mLevel); mSupportedValues.emplace( C2ParamField(&mLevel, &C2AvcLevelInfo::value), C2FieldSupportedValues(false /* flags */, { kAvcLevelUnknown, kAvcLevel10, kAvcLevel1b, kAvcLevel11, kAvcLevel12, kAvcLevel13, kAvcLevel20, kAvcLevel21, kAvcLevel22, kAvcLevel30, kAvcLevel31, kAvcLevel32, kAvcLevel40, kAvcLevel41, kAvcLevel42, kAvcLevel50, kAvcLevel51, kAvcLevel52, })); mFieldVerifiers[mLevel.index()] = ValidateSimpleParam<decltype(mLevel)>(mSupportedValues); insertParam(&mBlockSize); markReadOnlyVideoSize(&mBlockSize); mFieldVerifiers[mBlockSize.index()] = ValidateVideoSize<decltype(mBlockSize)>(mSupportedValues); insertParam(&mAlignment); markReadOnlyVideoSize(&mAlignment); mFieldVerifiers[mAlignment.index()] = ValidateVideoSize<decltype(mAlignment)>(mSupportedValues); insertParam(&mFrameRate); mSupportedValues.emplace( C2ParamField(&mFrameRate, &C2FrameRateInfo::value), C2FieldSupportedValues(0, 240)); mFieldVerifiers[mFrameRate.index()] = ValidateSimpleParam<decltype(mFrameRate)>(mSupportedValues); insertParam(&mBlocksPerSecond); mSupportedValues.emplace( C2ParamField(&mFrameRate, &C2BlocksPerSecondInfo::value), C2FieldSupportedValues(0, 244800)); mFieldVerifiers[mBlocksPerSecond.index()] = ValidateSimpleParam<decltype(mBlocksPerSecond)>(mSupportedValues); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( true, "_domain", &mDomainInfo)); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( true, "_input_port_mime", mInputPortMime.get())); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( true, "_input_stream_count", &mInputStreamCount)); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( true, "_output_port_mime", mOutputPortMime.get())); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( true, "_output_stream_count", &mOutputStreamCount)); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( true, "_input_stream_format", &mInputStreamFormat)); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( true, "_output_stream_format", &mOutputStreamFormat)); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( false, "_video_size", &mVideoSize)); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( false, "_max_video_size_hint", &mMaxVideoSizeHint)); mParamDescs.push_back(std::make_shared<C2ParamDescriptor>( false, "_output_block_pools", mOutputBlockPools.get())); } C2SoftAvcDecIntf::~C2SoftAvcDecIntf() { ALOGV("in %s", __func__); } C2String C2SoftAvcDecIntf::getName() const { return mName; } c2_node_id_t C2SoftAvcDecIntf::getId() const { return mId; } c2_status_t C2SoftAvcDecIntf::query_vb( const std::vector<C2Param*> & stackParams, const std::vector<C2Param::Index> & heapParamIndices, c2_blocking_t mayBlock, std::vector<std::unique_ptr<C2Param>>* const heapParams) const { (void)mayBlock; for (C2Param* const param : stackParams) { if (!*param) { continue; } uint32_t index = param->index(); if (!mParams.count(index)) { // TODO: add support for output-block-pools (this will be done when we move all // config to shared ptr) continue; } C2Param *myParam = mParams.find(index)->second; if (myParam->size() != param->size()) { param->invalidate(); continue; } param->updateFrom(*myParam); } for (const C2Param::Index index : heapParamIndices) { if (mParams.count(index)) { C2Param *myParam = mParams.find(index)->second; heapParams->emplace_back(C2Param::Copy(*myParam)); } } return C2_OK; } c2_status_t C2SoftAvcDecIntf::config_vb( const std::vector<C2Param*> ¶ms, c2_blocking_t mayBlock, std::vector<std::unique_ptr<C2SettingResult>>* const failures) { (void)mayBlock; c2_status_t err = C2_OK; for (C2Param *param : params) { uint32_t index = param->index(); if (param->index() == mOutputBlockPools.get()->index()) { // setting output block pools mOutputBlockPools.reset( (C2PortBlockPoolsTuning::output *)C2Param::Copy(*param).release()); continue; } if (mParams.count(index) == 0) { // We can't create C2SettingResult with no field, so just skipping in this case. err = C2_BAD_INDEX; continue; } C2Param *myParam = mParams.find(index)->second; std::unique_ptr<C2SettingResult> result; if (!(result = mFieldVerifiers[index](param))) { myParam->updateFrom(*param); updateSupportedValues(); } else { failures->push_back(std::move(result)); err = C2_BAD_VALUE; } } return err; } c2_status_t C2SoftAvcDecIntf::createTunnel_sm(c2_node_id_t targetComponent) { // Tunneling is not supported (void) targetComponent; return C2_OMITTED; } c2_status_t C2SoftAvcDecIntf::releaseTunnel_sm(c2_node_id_t targetComponent) { // Tunneling is not supported (void) targetComponent; return C2_OMITTED; } std::shared_ptr<C2ParamReflector> C2SoftAvcDecIntf::getParamReflector() const { return mParamReflector; } c2_status_t C2SoftAvcDecIntf::querySupportedParams_nb( std::vector<std::shared_ptr<C2ParamDescriptor>> * const params) const { params->insert(params->begin(), mParamDescs.begin(), mParamDescs.end()); return C2_OK; } c2_status_t C2SoftAvcDecIntf::querySupportedValues_vb( std::vector<C2FieldSupportedValuesQuery> &fields, c2_blocking_t mayBlock) const { (void)mayBlock; c2_status_t res = C2_OK; for (C2FieldSupportedValuesQuery &query : fields) { if (mSupportedValues.count(query.field) == 0) { query.status = C2_BAD_INDEX; res = C2_BAD_INDEX; } else { query.status = C2_OK; query.values = mSupportedValues.at(query.field).supported; } } return res; } void C2SoftAvcDecIntf::updateSupportedValues() { int32_t maxWidth = H264_MAX_FRAME_WIDTH; int32_t maxHeight = H264_MAX_FRAME_HEIGHT; // cf: Rec. ITU-T H.264 A.3 int maxFrameRate = 172; std::vector<C2ParamField> fields; if (mLevel.value != kAvcLevelUnknown) { // cf: Rec. ITU-T H.264 Table A-1 constexpr int MaxFS[] = { // 0 1 2 3 4 5 6 7 8 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 99, 396, 396, 396, 0, 0, 0, 0, 0, 0, 396, 792, 1620, 0, 0, 0, 0, 0, 0, 0, 1620, 3600, 5120, 0, 0, 0, 0, 0, 0, 0, 8192, 8192, 8704, 0, 0, 0, 0, 0, 0, 0, 22080, 36864, 36864, }; constexpr int MaxMBPS[] = { // 0 1 2 3 4 5 6 7 8 9 0, 0, 0, 0, 0, 0, 0, 0, 0, 1485, 1485, 3000, 6000, 11880, 0, 0, 0, 0, 0, 0, 11880, 19800, 20250, 0, 0, 0, 0, 0, 0, 0, 40500, 108000, 216000, 0, 0, 0, 0, 0, 0, 0, 245760, 245760, 522240, 0, 0, 0, 0, 0, 0, 0, 589824, 983040, 2073600, }; // cf: Rec. ITU-T H.264 A.3.1 maxWidth = std::min(maxWidth, floor32(std::sqrt(MaxFS[mLevel.value] * 8)) * MB_SIZE); maxHeight = std::min(maxHeight, floor32(std::sqrt(MaxFS[mLevel.value] * 8)) * MB_SIZE); int32_t MBs = ((mVideoSize.width + 15) / 16) * ((mVideoSize.height + 15) / 16); maxFrameRate = std::min(maxFrameRate, MaxMBPS[mLevel.value] / MBs); fields.push_back(C2ParamField(&mLevel, &C2AvcLevelInfo::value)); } SupportedValuesWithFields &maxWidthVals = mSupportedValues.at( C2ParamField(&mMaxVideoSizeHint, &C2MaxVideoSizeHintPortSetting::width)); maxWidthVals.supported.range.max = maxWidth; maxWidthVals.restrictingFields.clear(); maxWidthVals.restrictingFields.insert(fields.begin(), fields.end()); SupportedValuesWithFields &maxHeightVals = mSupportedValues.at( C2ParamField(&mMaxVideoSizeHint, &C2MaxVideoSizeHintPortSetting::height)); maxHeightVals.supported.range.max = maxHeight; maxHeightVals.restrictingFields.clear(); maxHeightVals.restrictingFields.insert(fields.begin(), fields.end()); SupportedValuesWithFields &frameRate = mSupportedValues.at( C2ParamField(&mFrameRate, &C2FrameRateInfo::value)); frameRate.supported.range.max = maxFrameRate; frameRate.restrictingFields.clear(); frameRate.restrictingFields.insert(fields.begin(), fields.end()); } #endif /////////////////////////////////////////////////////////////////////////////// C2SoftAvcDec::C2SoftAvcDec( Loading Loading @@ -654,6 +129,7 @@ c2_status_t C2SoftAvcDec::onInit() { } c2_status_t C2SoftAvcDec::onStop() { ALOGV("onStop"); mSignalledError = false; resetDecoder(); resetPlugin(); Loading @@ -662,6 +138,7 @@ c2_status_t C2SoftAvcDec::onStop() { } void C2SoftAvcDec::onReset() { ALOGV("onReset"); (void)onStop(); } Loading @@ -672,17 +149,6 @@ void C2SoftAvcDec::onRelease() { c2_status_t C2SoftAvcDec::onFlush_sm() { setFlushMode(); /* Allocate a picture buffer to flushed data */ uint32_t displayStride = mWidth; uint32_t displayHeight = mHeight; uint32_t bufferSize = displayStride * displayHeight * 3 / 2; mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize); if (NULL == mFlushOutBuffer) { ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize); return C2_NO_MEMORY; } while (true) { ivd_video_decode_ip_t s_dec_ip; ivd_video_decode_op_t s_dec_op; Loading Loading @@ -854,6 +320,18 @@ status_t C2SoftAvcDec::setFlushMode() { s_video_flush_op.u4_error_code); return UNKNOWN_ERROR; } /* Allocate a picture buffer to flushed data */ uint32_t displayStride = mWidth; uint32_t displayHeight = mHeight; uint32_t bufferSize = displayStride * displayHeight * 3 / 2; mFlushOutBuffer = (uint8_t *)memalign(128, bufferSize); if (NULL == mFlushOutBuffer) { ALOGE("Could not allocate flushOutputBuffer of size %u", bufferSize); return C2_NO_MEMORY; } return OK; } Loading Loading @@ -993,6 +471,7 @@ bool C2SoftAvcDec::setDecodeArgs( ps_dec_ip->u4_size = sizeof(ivd_video_decode_ip_t); ps_dec_op->u4_size = sizeof(ivd_video_decode_op_t); ps_dec_op->u4_output_present = 0; ps_dec_ip->e_cmd = IVD_CMD_VIDEO_DECODE; Loading Loading @@ -1095,7 +574,7 @@ void C2SoftAvcDec::process( const C2ConstLinearBlock &buffer = work->input.buffers[0]->data().linearBlocks().front(); if (buffer.capacity() == 0) { if (buffer.size() == 0) { ALOGV("empty input: %llu", work->input.ordinal.frameIndex.peekull()); // TODO: result? fillEmptyWork(work); Loading @@ -1109,6 +588,13 @@ void C2SoftAvcDec::process( } C2ReadView input = work->input.buffers[0]->data().linearBlocks().front().map().get(); if (input.error() != C2_OK) { work->result = input.error(); fillEmptyWork(work); ALOGD("map error: %d", input.error()); return; } ALOGV("buffer.size() = %u, input.capacity() = %u", buffer.size(), input.capacity()); uint32_t workIndex = work->input.ordinal.frameIndex.peeku() & 0xFFFFFFFF; size_t inOffset = 0u; Loading