From 635ed194f0a7868421721732fa474120e56d1ed2 Mon Sep 17 00:00:00 2001 From: ancimoon Date: Mon, 1 Nov 2021 09:44:04 +0000 Subject: [PATCH 01/22] !92 change to new negotiate flow Signed-off-by: Hu Chang --- engine/pipeline/core/compatible_check.cpp | 470 ++++++++++++-- engine/pipeline/core/compatible_check.h | 56 +- engine/pipeline/core/filter.h | 10 +- engine/pipeline/core/port.cpp | 50 +- engine/pipeline/core/port.h | 20 +- .../audio_decoder/audio_decoder_filter.cpp | 91 ++- .../audio_decoder/audio_decoder_filter.h | 8 +- .../filters/codec/decoder_filter_base.cpp | 30 + .../filters/codec/decoder_filter_base.h | 2 + .../pipeline/filters/common/plugin_utils.cpp | 15 + engine/pipeline/filters/common/plugin_utils.h | 5 +- .../pipeline/filters/demux/demuxer_filter.cpp | 23 +- .../pipeline/filters/demux/demuxer_filter.h | 6 +- .../sink/audio_sink/audio_sink_filter.cpp | 72 ++- .../sink/audio_sink/audio_sink_filter.h | 8 +- .../filters/source/media_source_filter.cpp | 8 +- engine/plugin/core/plugin_meta.h | 17 + .../audio_ffmpeg_decoder_plugin.cpp | 1 + .../sdl/audio_sink/sdl_audio_sink_plugin.cpp | 3 +- engine/utils/event.h | 1 - tests/ut/TestCompatibleCheck.cpp | 593 ++++++++++++++++++ 21 files changed, 1332 insertions(+), 157 deletions(-) diff --git a/engine/pipeline/core/compatible_check.cpp b/engine/pipeline/core/compatible_check.cpp index ef2ef065..87ce4739 100644 --- a/engine/pipeline/core/compatible_check.cpp +++ b/engine/pipeline/core/compatible_check.cpp @@ -47,39 +47,101 @@ static inline bool IsDiscreteAllowed(uint8_t flags) return ALLOW_DISCRETE & flags; } -MEDIA_UNUSED static bool StringCapabilityCheck(const std::pair& tagEntry, - const Meta& meta, uint8_t flags); +using CapEntry = std::pair; + template -bool NumericalCapabilityCheck(const std::pair& tagEntry, const Meta& meta, +bool NumericalCapabilityCheck(const CapEntry& tagEntry, const Plugin::Meta& meta, uint8_t flags, std::function compareFunc); template -bool FixInvalDiscNumericalCheck(const std::pair& capability, const Meta& meta) +bool FixInvalDiscNumericalCheck(const CapEntry& capability, const Plugin::Meta& meta) { return NumericalCapabilityCheck(capability, meta, ALLOW_FIXED | ALLOW_INTERVAL | ALLOW_DISCRETE, [](T a, T b) { return a - b; }); } template -bool FixDiscNumericalCheck(const std::pair& capability, const Meta& meta) +bool FixDiscNumericalCheck(const CapEntry& capability, const Plugin::Meta& meta) { return NumericalCapabilityCheck(capability, meta, ALLOW_FIXED | ALLOW_DISCRETE, [](T a, T b) { return static_cast(a) - static_cast(b); }); } -static std::map&, const Meta&)>> - g_capabilityCheckMap = { - {CapabilityID::AUDIO_CHANNELS, FixInvalDiscNumericalCheck}, - {CapabilityID::AUDIO_SAMPLE_RATE, FixInvalDiscNumericalCheck}, - {CapabilityID::AUDIO_MPEG_VERSION, FixInvalDiscNumericalCheck}, - {CapabilityID::AUDIO_MPEG_LAYER, FixInvalDiscNumericalCheck}, - {CapabilityID::AUDIO_CHANNEL_LAYOUT, FixDiscNumericalCheck}, - {CapabilityID::AUDIO_SAMPLE_FORMAT, FixDiscNumericalCheck}, - {CapabilityID::AUDIO_AAC_PROFILE, FixDiscNumericalCheck}, - {CapabilityID::AUDIO_AAC_LEVEL, FixDiscNumericalCheck}, - {CapabilityID::AUDIO_AAC_STREAM_FORMAT, FixDiscNumericalCheck}, +template +bool CapabilityValueCheck(const Plugin::ValueType& val1, const Plugin::ValueType& val2, uint8_t flags, + std::function cmpFunc, Plugin::ValueType& outValue); + +template +bool FixInvalDiscCapValCheck(const Plugin::ValueType& val1, const Plugin::ValueType& val2, Plugin::ValueType& outValue) +{ + return CapabilityValueCheck(val1, val2, ALLOW_FIXED | ALLOW_INTERVAL | ALLOW_DISCRETE, [](T a, T b) { + return a - b; + }, outValue); +} + +template +bool FixDiscCapValCheck(const Plugin::ValueType& val1, const Plugin::ValueType& val2, Plugin::ValueType& outValue) +{ + return CapabilityValueCheck(val1, val2, ALLOW_FIXED | ALLOW_DISCRETE, [](T a, T b) { + return static_cast(a) - static_cast(b); + }, outValue); +} + +static std::vector g_allCapabilityId = { + CapabilityID::AUDIO_SAMPLE_RATE, // 0 + CapabilityID::AUDIO_CHANNELS, // 1 + CapabilityID::AUDIO_CHANNEL_LAYOUT, // 2 + CapabilityID::AUDIO_SAMPLE_FORMAT, // 3 + CapabilityID::AUDIO_MPEG_VERSION, // 4 + CapabilityID::AUDIO_MPEG_LAYER, // 5 + CapabilityID::AUDIO_AAC_PROFILE, // 6 + CapabilityID::AUDIO_AAC_LEVEL, // 7 + CapabilityID::AUDIO_AAC_STREAM_FORMAT, // 8 +}; + + +static std::map> + g_capabilityCheckMap = { + {g_allCapabilityId[0], FixInvalDiscNumericalCheck}, // 0 + {g_allCapabilityId[1], FixInvalDiscNumericalCheck}, // 1 + {g_allCapabilityId[2], FixDiscNumericalCheck}, // 2 + {g_allCapabilityId[3], FixDiscNumericalCheck}, // 3 + {g_allCapabilityId[4], FixInvalDiscNumericalCheck}, // 4 + {g_allCapabilityId[5], FixInvalDiscNumericalCheck}, // 5 + {g_allCapabilityId[6], FixDiscNumericalCheck}, // 6 + {g_allCapabilityId[7], FixInvalDiscNumericalCheck}, // 7 + {g_allCapabilityId[8], FixDiscNumericalCheck}, // 8 +}; + +template +bool ExtractFixedCap(const Plugin::ValueType& value, Plugin::ValueType& fixedValue); +static std::map> g_capExtrMap = { + {g_allCapabilityId[0], ExtractFixedCap}, // 0 + {g_allCapabilityId[1], ExtractFixedCap}, // 1 + {g_allCapabilityId[2], ExtractFixedCap}, // 2 + {g_allCapabilityId[3], ExtractFixedCap}, // 3 + {g_allCapabilityId[4], ExtractFixedCap}, // 4 + {g_allCapabilityId[5], ExtractFixedCap}, // 5 + {g_allCapabilityId[6], ExtractFixedCap}, // 6 + {g_allCapabilityId[7], ExtractFixedCap}, // 7 + {g_allCapabilityId[8], ExtractFixedCap}, // 8 }; +static std::map> + g_capabilityValueCheckMap = { + {g_allCapabilityId[0], FixInvalDiscCapValCheck}, // 0 + {g_allCapabilityId[1], FixInvalDiscCapValCheck}, // 1 + {g_allCapabilityId[2], FixDiscCapValCheck}, // 2 + {g_allCapabilityId[3], FixDiscCapValCheck}, // 3 + {g_allCapabilityId[4], FixInvalDiscCapValCheck}, // 4 + {g_allCapabilityId[5], FixInvalDiscCapValCheck}, // 5 + {g_allCapabilityId[6], FixDiscCapValCheck}, // 6 + {g_allCapabilityId[7], FixInvalDiscCapValCheck}, // 7 + {g_allCapabilityId[8], FixDiscCapValCheck}, // 8 +}; + + static bool StringEqIgnoreCase(const std::string& s1, const std::string& s2) { if (s1.length() == s2.length()) { @@ -88,41 +150,49 @@ static bool StringEqIgnoreCase(const std::string& s1, const std::string& s2) return false; } -bool CompatibleWith(const Capability& capability, const Meta& meta) +bool IsSubsetMime(const std::string& subset, const std::string& universe) { - // first check mime - std::string mimeInMeta; - if (!meta.GetString(Plugin::MetaID::MIME, mimeInMeta)) { - MEDIA_LOG_E("mime is not found in meta when check compatible"); - return false; - } - - size_t devLinePosInMeta = mimeInMeta.find_first_of('/'); + size_t devLinePosInMeta = subset.find_first_of('/'); if (devLinePosInMeta == 0 || devLinePosInMeta == std::string::npos) { - MEDIA_LOG_E("wrong format of meta mime, must be xx/xxx"); + MEDIA_LOG_E("wrong format of subset mime, must be xx/xxx"); return false; } - if (capability.mime == "*") { + if (universe == "*") { return true; } - size_t devLinePosInCap = capability.mime.find_first_of('/'); + size_t devLinePosInCap = universe.find_first_of('/'); if (devLinePosInCap == 0 || devLinePosInCap == std::string::npos) { - MEDIA_LOG_E("wrong format of capability mime, must be * or xx/* or xx/xxx"); + MEDIA_LOG_E("wrong format of universe mime, must be * or xx/* or xx/xxx"); return false; } // if media type is not the same, return false - if (!StringEqIgnoreCase(mimeInMeta.substr(0, devLinePosInMeta), capability.mime.substr(0, devLinePosInCap))) { + if (!StringEqIgnoreCase(subset.substr(0, devLinePosInMeta), universe.substr(0, devLinePosInCap))) { return false; } // if media type of capability is like audio/* video/* image/* etc. always return true - if (capability.mime.substr(devLinePosInCap + 1) == "*") { + if (universe.substr(devLinePosInCap + 1) == "*") { return true; } // left mime string compare - if (!StringEqIgnoreCase(capability.mime.substr(devLinePosInCap + 1), mimeInMeta.substr(devLinePosInMeta + 1))) { + if (!StringEqIgnoreCase(universe.substr(devLinePosInCap + 1), subset.substr(devLinePosInMeta + 1))) { + return false; + } + return true; +} + +bool CompatibleWith(const Capability& capability, const Plugin::Meta& meta) +{ + // first check mime + std::string mimeInMeta; + if (!meta.GetString(Plugin::MetaID::MIME, mimeInMeta)) { + MEDIA_LOG_E("mime is not found in meta when check compatible"); + return false; + } + + if (!IsSubsetMime(mimeInMeta, capability.mime)) { return false; } @@ -139,55 +209,179 @@ bool CompatibleWith(const Capability& capability, const Meta& meta) return true; } -bool CompatibleWith(const CapabilitySet& capability, const Meta& meta) +bool CompatibleWith(const CapabilitySet& capability, const Plugin::Meta& meta) { - for (const auto& cap : capability) { - if (CompatibleWith(cap, meta)) { - return true; - } + return std::any_of(capability.begin(), capability.end(), [&meta](const Plugin::Capability& cap) { + return CompatibleWith(cap, meta); + }); +} + +template +T Max(T val1, T val2, std::function compareFunc) +{ + if (compareFunc(val1, val2) >= 0) { + return val1; + } + return val2; +} + +template +T Min(T val1, T val2, std::function compareFunc) +{ + if (compareFunc(val1, val2) <= 0) { + return val1; + } + return val2; +} + +template +bool FFCapabilityCheck(const Plugin::FixedCapability& v1, const Plugin::FixedCapability& v2, + std::function& cmpFunc, Plugin::ValueType& outValue) +{ + if (cmpFunc(v1, v2) == 0) { + outValue = v1; + return true; } return false; } -static bool StringCapabilityCheck(const std::pair& tagEntry, const Meta& meta, - uint8_t flags) +template +bool FICapabilityCheck(const Plugin::FixedCapability& v1, const Plugin::IntervalCapability& v2, + const std::function& cmpFunc, Plugin::ValueType& outValue) { - std::string metaValue; - if (!meta.GetString(static_cast(tagEntry.first), metaValue) || IsIntervalAllowed(flags)) { + T max = Max(v2.first, v2.second, cmpFunc); + T min = Min(v2.first, v2.second, cmpFunc); + if (cmpFunc(v1, min) >= 0 && cmpFunc(v1, max) <= 0) { + outValue = v1; + return true; + } + return false; +} + +template +bool FDCapabilityCheck(const Plugin::FixedCapability& v1, const Plugin::DiscreteCapability& v2, + const std::function& cmpFunc, Plugin::ValueType& outValue) +{ + if (std::any_of(v2.begin(), v2.end(), [&v1, &cmpFunc](const T& tmp){return cmpFunc(tmp, v1) == 0;})) { + outValue = v1; + return true; + } + return false; +} + +template +bool IICapabilityCheck(const Plugin::IntervalCapability& v1, const Plugin::IntervalCapability& v2, + const std::function& cmpFunc, Plugin::ValueType& outValue) +{ + T max1 = Max(v1.first, v1.second, cmpFunc); + T min1 = Min(v1.first, v1.second, cmpFunc); + T max2 = Max(v2.first, v2.second, cmpFunc); + T min2 = Min(v2.first, v2.second, cmpFunc); + T tmpMin = Max(min1, min2, cmpFunc); + T tmpMax = Min(max1, max2, cmpFunc); + auto compRes = cmpFunc(tmpMin, tmpMax); + if (compRes > 0) { return false; + } else if (compRes == 0) { + outValue = Plugin::FixedCapability(tmpMin); + } else { + outValue = Plugin::IntervalCapability(tmpMin, tmpMax); } - if (IsFixedAllowed(flags)) { - if (tagEntry.second.Type() == typeid(const char*)) { - auto capabilityValue = Plugin::AnyCast(tagEntry.second); - return metaValue == capabilityValue; - } else if (tagEntry.second.Type() == typeid(char*)) { - auto capabilityValue = Plugin::AnyCast(tagEntry.second); - return metaValue == capabilityValue; - } else if (tagEntry.second.Type() == typeid(std::string)) { - auto capabilityValue = Plugin::AnyCast(tagEntry.second); - return metaValue == capabilityValue; - } else if (tagEntry.second.Type() == typeid(Plugin::DiscreteCapability)) { // 列表 - auto capabilityValues = Plugin::AnyCast>(tagEntry.second); - return std::any_of(capabilityValues.begin(), capabilityValues.end(), - [&metaValue](const char* cap) { return metaValue == cap; }); + return true; +} + +template +bool IDCapabilityCheck(const Plugin::IntervalCapability& v1, const Plugin::DiscreteCapability& v2, + const std::function& cmpFunc, Plugin::ValueType& outValue) +{ + Plugin::DiscreteCapability tmpOut; + for (const auto& oneValue : v2) { + if (cmpFunc(oneValue, v1.first) >= 0 && cmpFunc(oneValue, v1.second) <= 0) { + tmpOut.emplace_back(oneValue); } } - if (IsDiscreteAllowed(flags)) { - if (tagEntry.second.Type() == typeid(Plugin::DiscreteCapability)) { // 列表 - auto capabilityValues = Plugin::AnyCast>(tagEntry.second); - return std::any_of(capabilityValues.begin(), capabilityValues.end(), - [&metaValue](const char* cap) { return metaValue == cap; }); - } else if (tagEntry.second.Type() == typeid(Plugin::DiscreteCapability)) { - auto capabilityValues = Plugin::AnyCast>(tagEntry.second); - return std::any_of(capabilityValues.begin(), capabilityValues.end(), - [&metaValue](const std::string& cap) { return metaValue == cap; }); + if (tmpOut.empty()) { + return false; + } + if (tmpOut.size() == 1) { + outValue = Plugin::FixedCapability(tmpOut[0]); + } else { + outValue = Plugin::DiscreteCapability(tmpOut); + } + return true; +} + +template +bool DDCapabilityCheck(const Plugin::DiscreteCapability& v1, const Plugin::DiscreteCapability& v2, + const std::function& cmpFunc, Plugin::ValueType& outValue) +{ + Plugin::DiscreteCapability tmpOut; + for (const auto& cap1 : v1) { + if (std::any_of(v2.begin(), v2.end(), [&cap1, &cmpFunc](const T& tmp){return cmpFunc(cap1, tmp) == 0;})) { + tmpOut.emplace_back(cap1); } } + if (tmpOut.empty()) { + return false; + } + if (tmpOut.size() == 1) { + outValue = Plugin::FixedCapability(tmpOut[0]); + } else { + outValue = Plugin::DiscreteCapability(tmpOut); + } + return true; +} + +template +bool FixedNumericalCapabilityCheck(const T& value2, const Plugin::ValueType& value1, + uint8_t flags, std::function cmpFunc, Plugin::ValueType& outValue) +{ + if (value1.Type() == typeid(T)) { + return FFCapabilityCheck(value2, Plugin::AnyCast(value1), cmpFunc, outValue); + } + if (IsIntervalAllowed(flags) && value1.Type() == typeid(Plugin::IntervalCapability)) { + return FICapabilityCheck(value2, Plugin::AnyCast>(value1), cmpFunc, outValue); + } + if (IsDiscreteAllowed(flags) && value1.Type() == typeid(Plugin::DiscreteCapability)) { + return FDCapabilityCheck(value2, Plugin::AnyCast>(value1), cmpFunc, outValue); + } + return false; +} + +template +bool IntervalNumericalCapabilityCheck(const Plugin::IntervalCapability& value2, const Plugin::ValueType& value1, + uint8_t flags, std::function cmpFunc, Plugin::ValueType& outValue) +{ + if (IsFixedAllowed(flags) && value1.Type() == typeid(T)) { + return FICapabilityCheck(Plugin::AnyCast(value1), value2, cmpFunc, outValue); + } + if (value1.Type() == typeid(Plugin::IntervalCapability)) { + return IICapabilityCheck(Plugin::AnyCast>(value1), value2, cmpFunc, outValue); + } + if (IsDiscreteAllowed(flags) && value1.Type() == typeid(Plugin::DiscreteCapability)) { + return IDCapabilityCheck(value2, Plugin::AnyCast>(value1), cmpFunc, outValue); + } return false; } template -bool NumericalCapabilityCheck(const std::pair& tagEntry, const Meta& meta, +bool DiscreteNumericalCapabilityCheck(const Plugin::DiscreteCapability& value2, const Plugin::ValueType& value1, + uint8_t flags, std::function cmpFunc, Plugin::ValueType& outValue) +{ + if (IsFixedAllowed(flags) && value1.Type() == typeid(T)) { + return FDCapabilityCheck(Plugin::AnyCast(value1), value2, cmpFunc, outValue); + } + if (IsIntervalAllowed(flags) && value1.Type() == typeid(Plugin::IntervalCapability)) { + return IDCapabilityCheck(Plugin::AnyCast>(value1), value2, cmpFunc, outValue); + } + if (value1.Type() == typeid(Plugin::DiscreteCapability)) { + return DDCapabilityCheck(Plugin::AnyCast>(value1), value2, cmpFunc, outValue); + } + return false; +} + +template +bool NumericalCapabilityCheck(const std::pair& tagEntry, const Plugin::Meta& meta, uint8_t flags, std::function compareFunc) { T metaValue; @@ -214,6 +408,152 @@ bool NumericalCapabilityCheck(const std::pair& } return false; } + +template +bool CapabilityValueCheck(const Plugin::ValueType& val1, const Plugin::ValueType& val2, uint8_t flags, + std::function cmpFunc, Plugin::ValueType& outValue) +{ + if (IsFixedAllowed(flags) && val1.Type() == typeid(Plugin::FixedCapability)) { + return FixedNumericalCapabilityCheck(Plugin::AnyCast>(val1), val2, flags, cmpFunc, + outValue); + } + if (IsIntervalAllowed(flags) && val1.Type() == typeid(Plugin::IntervalCapability)) { + return IntervalNumericalCapabilityCheck(Plugin::AnyCast>(val1), val2, flags, + cmpFunc, outValue); + } + if (IsDiscreteAllowed(flags) && val1.Type() == typeid(Plugin::DiscreteCapability)) { + return DiscreteNumericalCapabilityCheck(Plugin::AnyCast>(val1), val2, flags, + cmpFunc, outValue); + } + return false; +} + +bool MergeCapabilityKeys(const Capability& originCap, const Capability& otherCap, Capability& resCap) +{ + resCap.keys.clear(); + for (const auto& pairKey : originCap.keys) { + auto oIte = otherCap.keys.find(pairKey.first); + if (oIte == otherCap.keys.end()) { + // if key is not in otherCap, then put into resCap + resCap.keys.insert(pairKey); + continue; + } + // if key is in otherCap, calculate the intersections + auto funcIte = g_capabilityValueCheckMap.find(pairKey.first); + if (funcIte == g_capabilityValueCheckMap.end()) { + MEDIA_LOG_W("found one capability %d cannot be applied", pairKey.first); + continue; + } + Plugin::ValueType tmp; + if ((funcIte->second)(pairKey.second, oIte->second, tmp)) { + resCap.keys[pairKey.first] = tmp; + } else { + // if no intersections return false + resCap.keys.clear(); + return false; + } + } + // if key is otherCap but not in originCap, put into resCap + for (const auto& pairKey : otherCap.keys) { + if (resCap.keys.count(pairKey.first) == 0) { + resCap.keys.insert(pairKey); + } + } + return true; +} + +bool MergeCapability(const Capability& originCap, const Capability& otherCap, Capability& resCap) +{ + resCap.mime.clear(); + resCap.keys.clear(); + if (!IsSubsetMime(originCap.mime, otherCap.mime)) { + return false; + } + if (!MergeCapabilityKeys(originCap, otherCap, resCap)) { + return false; + } + resCap.mime = originCap.mime; + return true; +} + +bool ApplyCapabilitySet(const Capability& originCap, const CapabilitySet& capabilitySet, Capability& resCap) +{ + Capability tmp; + for (const auto& cap : capabilitySet) { + if (MergeCapability(originCap, cap, resCap)) { + return true; + } + } + return false; +} + +template +bool ExtractFixedCap(const Plugin::ValueType& value, Plugin::ValueType& fixedValue) +{ + if (value.Type() == typeid(Plugin::FixedCapability)) { + fixedValue = Plugin::AnyCast>(value); + return true; + } else if (value.Type() == typeid(Plugin::IntervalCapability)) { + auto tmp = Plugin::AnyCast>(value); + fixedValue = tmp.first; + return true; + } else if (value.Type() == typeid(Plugin::DiscreteCapability)) { + auto tmp = Plugin::AnyCast>(value); + if (!tmp.empty()) { + fixedValue = tmp[0]; + return true; + } + } + return false; +} + +std::shared_ptr MetaToCapability(const Plugin::Meta& meta) +{ + auto ret = std::make_shared(); + std::string mime; + if (meta.GetString(Plugin::MetaID::MIME, mime)) { + ret->mime = mime; + } + for (const auto& key : g_allCapabilityId) { + Plugin::ValueType tmp; + if (meta.GetData(static_cast(key), tmp)) { + ret->keys[key] = tmp; + } + } + return ret; +} + +bool MergeMetaWithCapability(const Plugin::Meta& meta, const Capability& cap, Plugin::Meta& resMeta) +{ + resMeta.Clear(); + // change meta into capability firstly + Capability metaCap; + metaCap.mime = cap.mime; + for (const auto& key : g_allCapabilityId) { + Plugin::ValueType tmp; + if (meta.GetData(static_cast(key), tmp)) { + metaCap.keys[key] = tmp; + } + } + Capability resCap; + if (!MergeCapability(metaCap, cap, resCap)) { + return false; + } + // merge capability + resMeta.Update(meta); + resMeta.SetString(Plugin::MetaID::MIME, cap.mime); + for (const auto& oneCap : resCap.keys) { + if (g_capExtrMap.count(oneCap.first) == 0) { + continue; + } + auto func = g_capExtrMap[oneCap.first]; + Plugin::ValueType tmp; + if (func(oneCap.second, tmp)) { + resMeta.SetData(static_cast(oneCap.first), tmp); + } + } + return true; +} } // namespace Pipeline } // namespace Media } // namespace OHOS diff --git a/engine/pipeline/core/compatible_check.h b/engine/pipeline/core/compatible_check.h index a0e1d2c3..93ee2b51 100644 --- a/engine/pipeline/core/compatible_check.h +++ b/engine/pipeline/core/compatible_check.h @@ -23,10 +23,60 @@ namespace OHOS { namespace Media { namespace Pipeline { -using Meta = Plugin::Meta; +bool CompatibleWith(const Capability& capability, const Plugin::Meta& meta); +bool CompatibleWith(const CapabilitySet& capability, const Plugin::Meta& meta); -bool CompatibleWith(const Capability &capability, const Meta& meta); -bool CompatibleWith(const CapabilitySet &capability, const Meta& meta); +/** + * merge otherCap keys with originCap keys: + * 1. if key exists in only one Cap (e.g. only exists in originCap or otherCap), then put key into resCap directly + * 2. if key exists in both originCap and otherCap, then intersections will be calculated + * 2.1 if intersections of any key is empty, return false + * 2.2 otherwise, put intersections into resCap + * The mime of resCap is not set. + * + * @param originCap originCap + * @param otherCap otherCap + * @param resCap out parameter. The merge result is in it. + * @return success + */ +bool MergeCapabilityKeys(const Capability& originCap, const Capability& otherCap, Capability& resCap); + +/** + * merge otherCap with originCap. The rule of merging keys is the same as MergeCapabilityKeys. Besides, it requires that + * mime in originCap should be subset of mime in otherCap. The mime of resCap is set as originCap.mime. + * + * @param originCap originCap + * @param otherCap otherCap + * @param resCap out parameter. The merge result is in it. + * @return success + */ +bool MergeCapability(const Capability& originCap, const Capability& otherCap, Capability& resCap); + + +/** + * change meta info capability + * + * @param meta target meta + * @return result capability + */ +std::shared_ptr MetaToCapability(const Plugin::Meta& meta); + +/** + * merge meta with capability. This function firstly change meta into capability metaCap. The mime of metaCap is the + * the same as cap. Then, merge metaCap and cap. + * After that, output the resMeta according merge result and origin meta, as the following rules: + * 1. if one meta key only exist in origin meta, put it into resMeta + * 2. if one meta key exist in both origin meta and capability merge results, then translate the one in capability merge + * results into fixed values + * + * @param meta origin meta + * @param cap origin cap + * @param resMeta result meta + * @return success to merge + */ +bool MergeMetaWithCapability(const Plugin::Meta& meta, const Capability& cap, Plugin::Meta& resMeta); + +bool ApplyCapabilitySet(const Capability& originCap, const CapabilitySet& capabilitySet, Capability& resCap); } } } diff --git a/engine/pipeline/core/filter.h b/engine/pipeline/core/filter.h index b10e2b18..373183a4 100644 --- a/engine/pipeline/core/filter.h +++ b/engine/pipeline/core/filter.h @@ -66,11 +66,17 @@ public: virtual std::vector GetWorkModes() = 0; // OutPort调用 // InPort调用此接口确定是否要继续往后协商 - virtual bool Negotiate(const std::string& inPort, const std::shared_ptr& inMeta, - CapabilitySet& outCaps) + virtual bool Negotiate(const std::string& inPort, const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) { return false; } + + virtual bool Configure(const std::string& inPort, const std::shared_ptr& upstreamMeta) + { + return false; + } + virtual ErrorCode PushData(const std::string& inPort, AVBufferPtr buffer) = 0; // InPort调用 virtual ErrorCode PullData(const std::string& outPort, uint64_t offset, size_t size, AVBufferPtr& data) = 0; // OutPort调用 diff --git a/engine/pipeline/core/port.cpp b/engine/pipeline/core/port.cpp index 6ba867e2..8056be34 100644 --- a/engine/pipeline/core/port.cpp +++ b/engine/pipeline/core/port.cpp @@ -69,11 +69,17 @@ std::shared_ptr InPort::GetPeerPort() return prevPort.lock(); } -bool InPort::Negotiate(const std::shared_ptr& inMeta, CapabilitySet& outCaps) +bool InPort::Negotiate(const std::shared_ptr& upstreamCap, Capability& upstreamNegotiatedCap) { - return filter && filter->Negotiate(name, inMeta, outCaps); + return filter && filter->Negotiate(name, upstreamCap, upstreamNegotiatedCap); } +bool InPort::Configure(const std::shared_ptr& upstreamMeta) +{ + return filter && filter->Configure(name, upstreamMeta); +} + + void InPort::PushData(AVBufferPtr buffer) { if (filter) { @@ -144,9 +150,15 @@ std::shared_ptr OutPort::GetPeerPort() return nextPort; } -bool OutPort::Negotiate(const std::shared_ptr& inMeta, CapabilitySet& outCaps) +bool OutPort::Negotiate(const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) { - return nextPort->Negotiate(inMeta, outCaps); + return nextPort->Negotiate(upstreamCap, upstreamNegotiatedCap); +} + +bool OutPort::Configure(const std::shared_ptr &upstreamMeta) +{ + return nextPort->Configure(upstreamMeta); } void OutPort::PushData(AVBufferPtr buffer) @@ -176,13 +188,22 @@ ErrorCode EmptyInPort::Activate(const std::vector& modes, WorkMode& ou MEDIA_LOG_E("Activate in EmptyInPort"); return ErrorCode::SUCCESS; } -bool EmptyInPort::Negotiate(const std::shared_ptr& inMeta, CapabilitySet& outCaps) +bool EmptyInPort::Negotiate(const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) { - UNUSED_VARIABLE(inMeta); - UNUSED_VARIABLE(outCaps); + UNUSED_VARIABLE(upstreamCap); + UNUSED_VARIABLE(upstreamNegotiatedCap); MEDIA_LOG_E("Negotiate in EmptyInPort"); return false; } + +bool EmptyInPort::Configure(const std::shared_ptr& upstreamMeta) +{ + UNUSED_VARIABLE(upstreamMeta); + MEDIA_LOG_E("Configure in EmptyInPort"); + return false; +} + void EmptyInPort::PushData(AVBufferPtr buffer) { UNUSED_VARIABLE(buffer); @@ -210,13 +231,22 @@ ErrorCode EmptyOutPort::Activate(const std::vector& modes, WorkMode& o MEDIA_LOG_E("Activate in EmptyOutPort"); return ErrorCode::SUCCESS; } -bool EmptyOutPort::Negotiate(const std::shared_ptr& inMeta, CapabilitySet& outCaps) +bool EmptyOutPort::Negotiate(const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) { - UNUSED_VARIABLE(inMeta); - UNUSED_VARIABLE(outCaps); + UNUSED_VARIABLE(upstreamCap); + UNUSED_VARIABLE(upstreamNegotiatedCap); MEDIA_LOG_E("Negotiate in EmptyOutPort"); return false; } + +bool EmptyOutPort::Configure(const std::shared_ptr& upstreamMeta) +{ + UNUSED_VARIABLE(upstreamMeta); + MEDIA_LOG_E("Configure in EmptyOutPort"); + return false; +} + void EmptyOutPort::PushData(AVBufferPtr buffer) { UNUSED_VARIABLE(buffer); diff --git a/engine/pipeline/core/port.h b/engine/pipeline/core/port.h index c022c3a7..9b314687 100644 --- a/engine/pipeline/core/port.h +++ b/engine/pipeline/core/port.h @@ -48,7 +48,9 @@ public: virtual ErrorCode Connect(std::shared_ptr port) = 0; virtual ErrorCode Disconnect() = 0; virtual ErrorCode Activate(const std::vector& modes, WorkMode& outMode) = 0; - virtual bool Negotiate(const std::shared_ptr& inMeta, CapabilitySet& outCaps) = 0; + virtual bool Negotiate(const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) = 0; + virtual bool Configure(const std::shared_ptr &upstreamMeta) = 0; virtual void PushData(AVBufferPtr buffer) = 0; virtual ErrorCode PullData(uint64_t offset, size_t size, AVBufferPtr& data) = 0; @@ -70,7 +72,9 @@ public: ErrorCode Disconnect() override; ErrorCode Activate(const std::vector& modes, WorkMode& outMode) override; std::shared_ptr GetPeerPort() override; - bool Negotiate(const std::shared_ptr& inMeta, CapabilitySet& outCaps) override; + bool Negotiate(const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) override; + bool Configure(const std::shared_ptr& upstreamMeta) override; void PushData(AVBufferPtr buffer) override; ErrorCode PullData(uint64_t offset, size_t size, AVBufferPtr& data) override; @@ -87,7 +91,9 @@ public: ErrorCode Disconnect() override; ErrorCode Activate(const std::vector& modes, WorkMode& outMode) override; std::shared_ptr GetPeerPort() override; - bool Negotiate(const std::shared_ptr& inMeta, CapabilitySet& outCaps) override; + bool Negotiate(const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) override; + bool Configure(const std::shared_ptr& upstreamMeta) override; void PushData(AVBufferPtr buffer) override; ErrorCode PullData(uint64_t offset, size_t size, AVBufferPtr& data) override; @@ -108,7 +114,9 @@ public: ~EmptyInPort() override = default; ErrorCode Connect(std::shared_ptr port) override; ErrorCode Activate(const std::vector& modes, WorkMode& outMode) override; - bool Negotiate(const std::shared_ptr& inMeta, CapabilitySet& outCaps) override; + bool Negotiate(const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) override; + bool Configure(const std::shared_ptr& upstreamMeta) override; void PushData(AVBufferPtr buffer) override; ErrorCode PullData(uint64_t offset, size_t size, AVBufferPtr& data) override; @@ -126,7 +134,9 @@ public: ~EmptyOutPort() override = default; ErrorCode Connect(std::shared_ptr port) override; ErrorCode Activate(const std::vector& modes, WorkMode& outMode) override; - bool Negotiate(const std::shared_ptr& inMeta, CapabilitySet& outCaps) override; + bool Negotiate(const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) override; + bool Configure(const std::shared_ptr& upstreamMeta) override; void PushData(AVBufferPtr buffer) override; ErrorCode PullData(uint64_t offset, size_t size, AVBufferPtr& data) override; diff --git a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp index 2bbb2104..ca011cb8 100644 --- a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp +++ b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp @@ -197,37 +197,77 @@ ErrorCode AudioDecoderFilter::Prepare() return ErrorCode::SUCCESS; } -bool AudioDecoderFilter::Negotiate(const std::string& inPort, const std::shared_ptr &inMeta, - CapabilitySet& outCaps) +bool AudioDecoderFilter::Negotiate(const std::string& inPort, + const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) { if (state_ != FilterState::PREPARING) { MEDIA_LOG_W("decoder filter is not in preparing when negotiate"); return false; } - auto creator = [] (const std::string& pluginName) { - return Plugin::PluginManager::Instance().CreateCodecPlugin(pluginName); - }; - ErrorCode err = FindPluginAndUpdate(inMeta, Plugin::PluginType::CODEC, plugin_, - targetPluginInfo_, creator); - RETURN_TARGET_ERR_MESSAGE_LOG_IF_FAIL(err, false, "cannot find matched plugin"); - outCaps = targetPluginInfo_->inCaps; auto targetOutPort = GetRouteOutPort(inPort); if (targetOutPort == nullptr) { MEDIA_LOG_E("decoder out port is not found"); return false; } - // todo how to decide pcm caps - std::shared_ptr pcmMeta = std::make_shared(); - // shall we avoid copy - pcmMeta->Update(*inMeta); - pcmMeta->SetString(Plugin::MetaID::MIME, MEDIA_MIME_AUDIO_RAW); - CapabilitySet sinkCaps; - if (!targetOutPort->Negotiate(pcmMeta, sinkCaps)) { - MEDIA_LOG_E("negotiate with sink failed"); + std::shared_ptr selectedPluginInfo; + bool atLeastOutCapMatched = false; + auto candidatePlugins = FindAvailablePlugins(*upstreamCap, Plugin::PluginType::CODEC); + for (const auto& candidate : candidatePlugins) { + if (candidate.first->outCaps.empty()) { + MEDIA_LOG_W("decoder plugin must have out caps"); + } + for (const auto& outCap : candidate.first->outCaps) { // each codec plugin should have at least one out cap + auto thisOut = std::make_shared(); + if (!MergeCapabilityKeys(*upstreamCap, outCap, *thisOut)) { + MEDIA_LOG_W("one of out cap of plugin %s does not match with upstream capability", + candidate.first->name.c_str()); + continue; + } + atLeastOutCapMatched = true; + thisOut->mime = outCap.mime; + if (targetOutPort->Negotiate(thisOut, capNegWithDownstream_)) + { + capNegWithUpstream_ = candidate.second; + selectedPluginInfo = candidate.first; + MEDIA_LOG_I("choose plugin %s as working parameter", candidate.first->name); + break; + } + } + } + if (!atLeastOutCapMatched) { + MEDIA_LOG_W("cannot find available decoder plugin"); return false; } - err = ConfigureToStartPluginLocked(inMeta); + if (selectedPluginInfo == nullptr) { + MEDIA_LOG_W("cannot find available downstream plugin"); + return false; + } + return UpdateAndInitPluginByInfo(selectedPluginInfo); +} + +bool AudioDecoderFilter::Configure(const std::string &inPort, const std::shared_ptr &upstreamMeta) +{ + if (plugin_ == nullptr || targetPluginInfo_ == nullptr) { + MEDIA_LOG_E("cannot configure decoder when no plugin available"); + return false; + } + + auto thisMeta = std::make_shared(); + if (!MergeMetaWithCapability(*upstreamMeta, capNegWithDownstream_, *thisMeta)) { + MEDIA_LOG_E("cannot configure decoder plugin since meta is not compatible with negotiated caps"); + } + auto targetOutPort = GetRouteOutPort(inPort); + if (targetOutPort == nullptr) { + MEDIA_LOG_E("decoder out port is not found"); + return false; + } + if (!targetOutPort->Configure(thisMeta)) { + MEDIA_LOG_E("decoder filter downstream Configure failed"); + return false; + } + auto err = ConfigureToStartPluginLocked(thisMeta); if (err != ErrorCode::SUCCESS) { MEDIA_LOG_E("decoder configure error"); OnEvent({EVENT_ERROR, err}); @@ -268,8 +308,6 @@ ErrorCode AudioDecoderFilter::ConfigureToStartPluginLocked(const std::shared_ptr { auto err = TranslatePluginStatus(plugin_->SetDataCallback(dataCallback_)); RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "set decoder plugin callback failed"); - err = TranslatePluginStatus(plugin_->Init()); - RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "decoder plugin init error"); err = ConfigureWithMetaLocked(meta); RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "configure decoder plugin error"); @@ -372,10 +410,13 @@ ErrorCode AudioDecoderFilter::Stop() { MEDIA_LOG_I("AudioDecoderFilter stop start."); // 先改变底层状态 然后停掉上层线程 否则会产生死锁 - auto err = TranslatePluginStatus(plugin_->Flush()); - RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "decoder flush error"); - err = TranslatePluginStatus(plugin_->Stop()); - RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "decoder stop error"); + ErrorCode err ; + if (plugin_ != nullptr) { + err = TranslatePluginStatus(plugin_->Flush()); + RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "decoder flush error"); + err = TranslatePluginStatus(plugin_->Stop()); + RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "decoder stop error"); + } outBufferQ_->SetActive(false); pushTask_->Pause(); @@ -403,7 +444,6 @@ ErrorCode AudioDecoderFilter::Release() if (inBufferQ_ != nullptr) { inBufferQ_->SetActive(false); - inBufferQ_.reset(); } // 先停止线程 然后释放bufferQ 如果顺序反过来 可能导致线程访问已经释放的锁 if (pushTask_ != nullptr) { @@ -413,7 +453,6 @@ ErrorCode AudioDecoderFilter::Release() if (outBufferQ_ != nullptr) { outBufferQ_->SetActive(false); - outBufferQ_.reset(); } return ErrorCode::SUCCESS; } diff --git a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.h b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.h index d90aa702..741e7210 100644 --- a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.h +++ b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.h @@ -32,8 +32,10 @@ public: ErrorCode Prepare() override; - bool Negotiate(const std::string &inPort, const std::shared_ptr &inMeta, - CapabilitySet &outCaps) override; + bool Negotiate(const std::string& inPort, const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) override; + + bool Configure(const std::string& inPort, const std::shared_ptr& upstreamMeta) override; ErrorCode PushData(const std::string &inPort, AVBufferPtr buffer) override; @@ -84,6 +86,8 @@ private: bool isFlushing_ {false}; std::shared_ptr dataCallback_ {nullptr}; + Capability capNegWithDownstream_; + Capability capNegWithUpstream_; }; } } diff --git a/engine/pipeline/filters/codec/decoder_filter_base.cpp b/engine/pipeline/filters/codec/decoder_filter_base.cpp index 9ee498a0..37d570f0 100644 --- a/engine/pipeline/filters/codec/decoder_filter_base.cpp +++ b/engine/pipeline/filters/codec/decoder_filter_base.cpp @@ -84,6 +84,36 @@ ErrorCode DecoderFilterBase::GetParameter(int32_t key, Plugin::Any& value) } } } +bool DecoderFilterBase::UpdateAndInitPluginByInfo(const std::shared_ptr& selectedPluginInfo) +{ + if (selectedPluginInfo == nullptr) { + MEDIA_LOG_W("no available info to update plugin"); + return false; + } + if (plugin_ != nullptr){ + if (targetPluginInfo_ != nullptr && targetPluginInfo_->name == selectedPluginInfo->name) { + if (plugin_->Reset() == Plugin::Status::OK) { + return true; + } + MEDIA_LOG_W("reuse previous plugin %s failed, will create new plugin", targetPluginInfo_->name.c_str()); + } + plugin_->Deinit(); + } + + plugin_ = Plugin::PluginManager::Instance().CreateCodecPlugin(selectedPluginInfo->name); + if (plugin_ == nullptr) { + MEDIA_LOG_E("cannot create plugin %s", selectedPluginInfo->name.c_str()); + return false; + } + auto err = TranslatePluginStatus(plugin_->Init()); + if (err != ErrorCode::SUCCESS) { + MEDIA_LOG_E("decoder plugin init error"); + return false; + } + targetPluginInfo_ = selectedPluginInfo; + return true; +} + } } } diff --git a/engine/pipeline/filters/codec/decoder_filter_base.h b/engine/pipeline/filters/codec/decoder_filter_base.h index da67ac8c..4863b34a 100644 --- a/engine/pipeline/filters/codec/decoder_filter_base.h +++ b/engine/pipeline/filters/codec/decoder_filter_base.h @@ -56,6 +56,8 @@ protected: return err; } + bool UpdateAndInitPluginByInfo(const std::shared_ptr& selectedPluginInfo); + ThreadDrivingMode drivingMode_ {ThreadDrivingMode::ASYNC}; // plugin diff --git a/engine/pipeline/filters/common/plugin_utils.cpp b/engine/pipeline/filters/common/plugin_utils.cpp index 98c42493..cdc5e115 100644 --- a/engine/pipeline/filters/common/plugin_utils.cpp +++ b/engine/pipeline/filters/common/plugin_utils.cpp @@ -39,6 +39,21 @@ bool TranslateIntoParameter(const int& key, OHOS::Media::Plugin::Tag& tag) return true; } +std::vector, Plugin::Capability>> + FindAvailablePlugins(const Plugin::Capability& upStreamCaps, Plugin::PluginType pluginType) +{ + auto pluginNames = Plugin::PluginManager::Instance().ListPlugins(pluginType); + std::vector, Plugin::Capability>> infos; + for (const auto & name : pluginNames) { + auto tmpInfo = Plugin::PluginManager::Instance().GetPluginInfo(pluginType, name); + Capability cap; + if (ApplyCapabilitySet(upStreamCaps, tmpInfo->inCaps, cap)) { + infos.emplace_back(tmpInfo, cap); + } + } + return infos; +} + template ErrorCode FindPluginAndUpdate(const std::shared_ptr& inMeta, Plugin::PluginType pluginType, std::shared_ptr& plugin, std::shared_ptr& pluginInfo, diff --git a/engine/pipeline/filters/common/plugin_utils.h b/engine/pipeline/filters/common/plugin_utils.h index dc33293c..e92b446a 100644 --- a/engine/pipeline/filters/common/plugin_utils.h +++ b/engine/pipeline/filters/common/plugin_utils.h @@ -34,7 +34,7 @@ namespace Media { namespace Pipeline { #define RETURN_PLUGIN_NOT_FOUND_IF_NULL(plugin) \ if ((plugin) == nullptr) { \ - return ErrorCode::ERROR_PLUGIN_NOT_FOUND; \ + return ErrorCode::ERROR_PLUGIN_NOT_FOUND; \ } /** @@ -46,6 +46,9 @@ ErrorCode TranslatePluginStatus(Plugin::Status pluginError); bool TranslateIntoParameter(const int &key, OHOS::Media::Plugin::Tag &tag); +std::vector, Plugin::Capability>> + FindAvailablePlugins(const Plugin::Capability& upStreamCaps, Plugin::PluginType pluginType); + template ErrorCode FindPluginAndUpdate(const std::shared_ptr &inMeta, Plugin::PluginType pluginType, std::shared_ptr& plugin, std::shared_ptr& pluginInfo, diff --git a/engine/pipeline/filters/demux/demuxer_filter.cpp b/engine/pipeline/filters/demux/demuxer_filter.cpp index 663c75e6..03ca48da 100644 --- a/engine/pipeline/filters/demux/demuxer_filter.cpp +++ b/engine/pipeline/filters/demux/demuxer_filter.cpp @@ -17,6 +17,7 @@ #include "demuxer_filter.h" #include +#include "compatible_check.h" #include "factory/filter_factory.h" #include "foundation/log.h" #include "utils/constants.h" @@ -201,13 +202,19 @@ ErrorCode DemuxerFilter::PushData(const std::string& inPort, AVBufferPtr buffer) return ErrorCode::SUCCESS; } -bool DemuxerFilter::Negotiate(const std::string& inPort, const std::shared_ptr& inMeta, - CapabilitySet& outCaps) +bool DemuxerFilter::Negotiate(const std::string &inPort, const std::shared_ptr &upstreamCap, + Capability &upstreamNegotiatedCap) { (void)inPort; - (void)outCaps; - (void)inMeta->GetUint64(Plugin::MetaID::MEDIA_FILE_SIZE, mediaDataSize_); - return inMeta->GetString(Plugin::MetaID::MEDIA_FILE_EXTENSION, uriSuffix_); + (void)upstreamCap; + (void)upstreamNegotiatedCap; + return true; +} + +bool DemuxerFilter::Configure(const std::string &inPort, const std::shared_ptr &upstreamMeta) +{ + (void)upstreamMeta->GetUint64(Plugin::MetaID::MEDIA_FILE_SIZE, mediaDataSize_); + return upstreamMeta->GetString(Plugin::MetaID::MEDIA_FILE_EXTENSION, uriSuffix_); } ErrorCode DemuxerFilter::SeekTo(int64_t msec) @@ -446,9 +453,11 @@ void DemuxerFilter::NegotiateDownstream() { for (auto& stream : mediaMetaData_.trackInfos) { if (stream.needNegoCaps) { - CapabilitySet caps; + Capability caps; MEDIA_LOG_I("demuxer negotiate with streamIdx: %u", stream.streamIdx); - if (stream.port->Negotiate(GetStreamMeta(stream.streamIdx), caps)) { + auto streamMeta = GetStreamMeta(stream.streamIdx); + auto tmpCap = MetaToCapability(*streamMeta); + if (stream.port->Negotiate(tmpCap, caps) && stream.port->Configure(streamMeta)) { stream.needNegoCaps = false; } else { task_->PauseAsync(); diff --git a/engine/pipeline/filters/demux/demuxer_filter.h b/engine/pipeline/filters/demux/demuxer_filter.h index 2965f94d..91c6082f 100644 --- a/engine/pipeline/filters/demux/demuxer_filter.h +++ b/engine/pipeline/filters/demux/demuxer_filter.h @@ -54,8 +54,10 @@ public: ErrorCode PushData(const std::string& inPort, AVBufferPtr buffer) override; - bool Negotiate(const std::string& inPort, const std::shared_ptr& inMeta, - CapabilitySet& peerCaps) override; + bool Negotiate(const std::string &inPort, const std::shared_ptr &upstreamCap, + Capability &upstreamNegotiatedCap) override; + + bool Configure(const std::string &inPort, const std::shared_ptr &upstreamMeta) override; ErrorCode SeekTo(int64_t msec); diff --git a/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp b/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp index a5f58115..cd728974 100644 --- a/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp +++ b/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp @@ -63,17 +63,6 @@ ErrorCode AudioSinkFilter::SetParameter(int32_t key, const Plugin::Any& value) return SetPluginParameter(tag, value); } -template -ErrorCode AudioSinkFilter::GetPluginParameter(Tag tag, T& value) -{ - Plugin::Any tmp; - auto err = TranslatePluginStatus(plugin_->GetParameter(tag, tmp)); - if (err == ErrorCode::SUCCESS && tmp.Type() == typeid(T)) { - value = Plugin::AnyCast(tmp); - } - return err; -} - ErrorCode AudioSinkFilter::GetParameter(int32_t key, Plugin::Any& value) { if (state_.load() == FilterState::CREATED) { @@ -88,20 +77,52 @@ ErrorCode AudioSinkFilter::GetParameter(int32_t key, Plugin::Any& value) return TranslatePluginStatus(plugin_->GetParameter(tag, value)); } -bool AudioSinkFilter::Negotiate(const std::string& inPort, const std::shared_ptr& inMeta, - CapabilitySet& outCaps) +bool AudioSinkFilter::Negotiate(const std::string& inPort, const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) { MEDIA_LOG_D("audio sink negotiate started"); - auto creator = [](const std::string& pluginName) { - return Plugin::PluginManager::Instance().CreateAudioSinkPlugin(pluginName); - }; - auto err = FindPluginAndUpdate(inMeta, Plugin::PluginType::AUDIO_SINK, plugin_, - targetPluginInfo_, creator); - RETURN_TARGET_ERR_MESSAGE_LOG_IF_FAIL(err, false, "cannot find matched plugin"); + auto candidatePlugins = FindAvailablePlugins(*upstreamCap, Plugin::PluginType::AUDIO_SINK); + if (candidatePlugins.empty()) { + MEDIA_LOG_E("no available audio sink plugin"); + return false; + } + // always use first one + std::shared_ptr selectedPluginInfo = candidatePlugins[0].first; + upstreamNegotiatedCap = candidatePlugins[0].second; - outCaps = targetPluginInfo_->inCaps; + // try to reuse plugin + if (plugin_ != nullptr){ + if (targetPluginInfo_ != nullptr && targetPluginInfo_->name == selectedPluginInfo->name) { + if (plugin_->Reset() == Plugin::Status::OK) { + return true; + } + MEDIA_LOG_W("reuse previous plugin %s failed, will create new plugin", targetPluginInfo_->name.c_str()); + } + plugin_->Deinit(); + } + plugin_ = Plugin::PluginManager::Instance().CreateAudioSinkPlugin(selectedPluginInfo->name); + if (plugin_ == nullptr) { + MEDIA_LOG_E("cannot create plugin %s", selectedPluginInfo->name.c_str()); + return false; + } - err = ConfigureToPreparePlugin(inMeta); + auto err = TranslatePluginStatus(plugin_->Init()); + if (err != ErrorCode::SUCCESS) { + MEDIA_LOG_E("audio sink plugin init error"); + return false; + } + targetPluginInfo_ = selectedPluginInfo; + return true; +} + +bool AudioSinkFilter::Configure(const std::string& inPort, const std::shared_ptr& upstreamMeta) +{ + if (plugin_ == nullptr || targetPluginInfo_ == nullptr) { + MEDIA_LOG_E("cannot configure decoder when no plugin available"); + return false; + } + + auto err = ConfigureToPreparePlugin(upstreamMeta); if (err != ErrorCode::SUCCESS) { MEDIA_LOG_E("sink configure error"); OnEvent({EVENT_ERROR, err}); @@ -113,6 +134,7 @@ bool AudioSinkFilter::Negotiate(const std::string& inPort, const std::shared_ptr return true; } + ErrorCode AudioSinkFilter::ConfigureWithMeta(const std::shared_ptr& meta) { uint32_t channels; @@ -149,9 +171,7 @@ ErrorCode AudioSinkFilter::ConfigureWithMeta(const std::shared_ptr& meta) { - auto err = TranslatePluginStatus(plugin_->Init()); - RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "sink plugin init error."); - err = ConfigureWithMeta(meta); + auto err = ConfigureWithMeta(meta); if (err != ErrorCode::SUCCESS) { MEDIA_LOG_E("sink configuration failed "); return err; @@ -221,7 +241,9 @@ ErrorCode AudioSinkFilter::Stop() { MEDIA_LOG_I("audio sink stop start"); FilterBase::Stop(); - plugin_->Stop(); + if (plugin_ != nullptr) { + plugin_->Stop(); + } if (pushThreadIsBlocking.load()) { startWorkingCondition_.NotifyOne(); } diff --git a/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.h b/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.h index 3c95d11e..34913c9d 100644 --- a/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.h +++ b/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.h @@ -40,8 +40,10 @@ public: ErrorCode GetParameter(int32_t key, Plugin::Any& value) override; - bool Negotiate(const std::string& inPort, const std::shared_ptr& inMeta, - CapabilitySet& outCaps) override; + bool Negotiate(const std::string& inPort, const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) override; + + bool Configure(const std::string& inPort, const std::shared_ptr& upstreamMeta) override; ErrorCode PushData(const std::string& inPort, AVBufferPtr buffer) override; @@ -59,8 +61,6 @@ private: ErrorCode SetPluginParameter(Tag tag, const Plugin::ValueType& value); ErrorCode ConfigureToPreparePlugin(const std::shared_ptr& meta); ErrorCode ConfigureWithMeta(const std::shared_ptr& meta); - template - ErrorCode GetPluginParameter(Tag tag, T& value); std::atomic pushThreadIsBlocking {false}; bool isFlushing {false}; diff --git a/engine/pipeline/filters/source/media_source_filter.cpp b/engine/pipeline/filters/source/media_source_filter.cpp index 62a6a086..839437c0 100644 --- a/engine/pipeline/filters/source/media_source_filter.cpp +++ b/engine/pipeline/filters/source/media_source_filter.cpp @@ -16,7 +16,7 @@ #define LOG_TAG "MediaSourceFilter" #include "media_source_filter.h" -#include "utils/type_define.h" +#include "compatible_check.h" #include "factory/filter_factory.h" #include "plugin/interface/source_plugin.h" #include "plugin/core/plugin_meta.h" @@ -242,8 +242,10 @@ ErrorCode MediaSourceFilter::DoNegotiate(const std::shared_ptr& sou if ((plugin_->GetSize(fileSize) == Status::OK) && (fileSize != 0)) { suffixMeta->SetUint64(Media::Plugin::MetaID::MEDIA_FILE_SIZE, fileSize); } - CapabilitySet peerCaps; - if (!GetOutPort(PORT_NAME_DEFAULT)->Negotiate(suffixMeta, peerCaps)) { + Capability peerCap; + auto tmpCap = MetaToCapability(*suffixMeta); + if (!GetOutPort(PORT_NAME_DEFAULT)->Negotiate(tmpCap, peerCap) || + !GetOutPort(PORT_NAME_DEFAULT)->Configure(suffixMeta)) { MEDIA_LOG_E("Negotiate fail!"); return ErrorCode::ERROR_INVALID_PARAM_VALUE; } diff --git a/engine/plugin/core/plugin_meta.h b/engine/plugin/core/plugin_meta.h index 76258bc8..08b166a8 100644 --- a/engine/plugin/core/plugin_meta.h +++ b/engine/plugin/core/plugin_meta.h @@ -120,6 +120,17 @@ public: return true; } + bool GetData(Plugin::MetaID id, Plugin::ValueType& value) const + { + auto ite = items_.find(id); + if (ite == items_.end()) { + return false; + } + value = ite->second; + return true; + } + + void Clear(); /** @@ -148,6 +159,12 @@ public: return true; } + bool SetData(Plugin::MetaID id, const Plugin::ValueType& value) + { + items_[id] = value; + return true; + } + private: std::map items_{}; }; diff --git a/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp b/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp index bde3a9d4..6b01b820 100644 --- a/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp +++ b/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp @@ -144,6 +144,7 @@ void UpdatePluginDefinition(const AVCodec* codec, CodecPluginDef& definition) } } definition.inCaps.push_back(cap); + definition.outCaps.push_back(Capability(OHOS::Media::MEDIA_MIME_AUDIO_RAW)); } uint32_t GetWidth(AVSampleFormat sampleFormat) { diff --git a/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp b/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp index 07c946ea..9d95b128 100644 --- a/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp +++ b/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp @@ -89,7 +89,8 @@ const Status SdlAudioRegister(const std::shared_ptr& reg) AudioSinkPluginDef definition; definition.name = "sdl_audio_sink"; definition.rank = 100; // 100 - definition.inCaps.emplace_back(Capability(OHOS::Media::MEDIA_MIME_AUDIO_RAW)); + Capability cap(OHOS::Media::MEDIA_MIME_AUDIO_RAW); + definition.inCaps.emplace_back(cap); definition.creator = AudioSinkPluginCreator; return reg->AddPlugin(definition); } diff --git a/engine/utils/event.h b/engine/utils/event.h index 386d4a5d..a895f336 100644 --- a/engine/utils/event.h +++ b/engine/utils/event.h @@ -20,7 +20,6 @@ namespace OHOS { namespace Media { -class Meta; // 各个组件向Pipeline报告的事件类型 enum EventType { diff --git a/tests/ut/TestCompatibleCheck.cpp b/tests/ut/TestCompatibleCheck.cpp index 82e99126..28e3aca1 100644 --- a/tests/ut/TestCompatibleCheck.cpp +++ b/tests/ut/TestCompatibleCheck.cpp @@ -207,4 +207,597 @@ TEST(TestCapabilityListCompatible, CapabilityList_compatible) { ASSERT_FALSE(Pipeline::CompatibleWith(ca3, meta)); ASSERT_FALSE(Pipeline::CompatibleWith(cs1, meta)); } + +TEST(TestApplyCapability, mime_Test) +{ + Capability wildcard {"*"}; + Capability audioWildcard {"audio/*"}; + Capability testWildcard {"test/*"}; + Capability wrongWildcard {"/audio*"}; + Capability wrongCapability {"wrong"}; + Capability rawMimeCapability {"audio/raw"}; + Capability mpegMimeCapability {"audio/mpeg"}; + + Capability out; + ASSERT_TRUE(Pipeline::MergeCapability(audioWildcard, wildcard, out)); + ASSERT_TRUE(out.mime == audioWildcard.mime); + ASSERT_TRUE(out.keys.empty()); + + ASSERT_FALSE(Pipeline::MergeCapability(wrongWildcard, wildcard, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + ASSERT_FALSE(Pipeline::MergeCapability(wrongCapability, wildcard, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + ASSERT_FALSE(Pipeline::MergeCapability(wrongCapability, audioWildcard, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + + ASSERT_TRUE(Pipeline::MergeCapability(rawMimeCapability, wildcard, out)); + ASSERT_TRUE(out.mime == rawMimeCapability.mime); + ASSERT_TRUE(out.keys.empty()); + + ASSERT_TRUE(Pipeline::MergeCapability(rawMimeCapability, audioWildcard, out)); + ASSERT_TRUE(out.mime == rawMimeCapability.mime); + ASSERT_TRUE(out.keys.empty()); + + ASSERT_FALSE(Pipeline::MergeCapability(rawMimeCapability, testWildcard, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + ASSERT_FALSE(Pipeline::MergeCapability(rawMimeCapability, mpegMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + ASSERT_FALSE(Pipeline::MergeCapability(rawMimeCapability, wrongWildcard, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); +} + +TEST(TestMergeCapabilityKeys, SingleType_Test) +{ + Capability wildMimeCapability("*"); + Capability out; + + Capability rawFixedMimeCapability (MEDIA_MIME_AUDIO_RAW); + rawFixedMimeCapability.AppendFixedKey(CapabilityID::AUDIO_SAMPLE_RATE, 8000); + + ASSERT_TRUE(Pipeline::MergeCapabilityKeys(rawFixedMimeCapability, wildMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(Plugin::AnyCast(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]) == 8000); + + Capability rawFixedMimeCapability2 (MEDIA_MIME_AUDIO_MPEG); + rawFixedMimeCapability2.AppendFixedKey(CapabilityID::AUDIO_SAMPLE_RATE, 8000); + + // fix apply with fix + ASSERT_TRUE(Pipeline::MergeCapabilityKeys(rawFixedMimeCapability, rawFixedMimeCapability2, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(Plugin::AnyCast(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]) == 8000); + + // apply failed + Capability rawFixedMimeCapability3 (MEDIA_MIME_AUDIO_RAW); + rawFixedMimeCapability3.AppendFixedKey(CapabilityID::AUDIO_SAMPLE_RATE, 4000); + ASSERT_FALSE(Pipeline::MergeCapabilityKeys(rawFixedMimeCapability, rawFixedMimeCapability3, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + Capability rawListMimeCapability {MEDIA_MIME_AUDIO_RAW}; + rawListMimeCapability.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_RATE, {8000, 32000, 48000, 44100}); + + ASSERT_TRUE(Pipeline::MergeCapabilityKeys(rawListMimeCapability, wildMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + auto disCaps = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(disCaps[0] == 8000); + ASSERT_TRUE(disCaps[1] == 32000); + ASSERT_TRUE(disCaps[2] == 48000); + ASSERT_TRUE(disCaps[3] == 44100); + + // fix apply with discrete + ASSERT_TRUE(Pipeline::MergeCapabilityKeys(rawFixedMimeCapability, rawListMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(Plugin::AnyCast(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]) == 8000); + + // apply failed + Capability rawFixedMimeCapability4 (MEDIA_MIME_AUDIO_RAW); + rawFixedMimeCapability4.AppendFixedKey(CapabilityID::AUDIO_SAMPLE_RATE, 4000); + ASSERT_FALSE(Pipeline::MergeCapabilityKeys(rawFixedMimeCapability4, rawListMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + // discrete apply with discrete + Capability rawListMimeCapability2 {MEDIA_MIME_AUDIO_RAW}; + rawListMimeCapability2.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_RATE, {1000, 2000, 48000, 44100}); + ASSERT_TRUE(Pipeline::MergeCapabilityKeys(rawListMimeCapability2, rawListMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + auto tmp1 = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(tmp1.size() == 2); + ASSERT_TRUE(tmp1[0] == 48000); + ASSERT_TRUE(tmp1[1] == 44100); + + // discrete apply with discrete + Capability rawListMimeCapability3 {MEDIA_MIME_AUDIO_RAW}; + rawListMimeCapability3.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_RATE, {1000, 2000, 4000, 44100}); + ASSERT_TRUE(Pipeline::MergeCapabilityKeys(rawListMimeCapability3, rawListMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + auto tmp2 = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(tmp2 == 44100); + + // discrete apply with discrete failed + Capability rawListMimeCapability4 {MEDIA_MIME_AUDIO_RAW}; + rawListMimeCapability4.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_RATE, {1000, 2000, 4000, 4100}); + ASSERT_FALSE(Pipeline::MergeCapabilityKeys(rawListMimeCapability4, rawListMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + Capability rawIntervalMimeCapability {MEDIA_MIME_AUDIO_RAW}; + rawIntervalMimeCapability.AppendIntervalKey(CapabilityID::AUDIO_SAMPLE_RATE, 8000, 48000); + + ASSERT_TRUE(Pipeline::MergeCapabilityKeys(rawIntervalMimeCapability, wildMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + auto intCaps = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(intCaps.first == 8000); + ASSERT_TRUE(intCaps.second == 48000); + + // inter apply with fix + ASSERT_TRUE(Pipeline::MergeCapabilityKeys(rawFixedMimeCapability, rawIntervalMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(Plugin::AnyCast(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]) == 8000); + + ASSERT_TRUE(Pipeline::MergeCapabilityKeys(rawIntervalMimeCapability, rawFixedMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(Plugin::AnyCast(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]) == 8000); + + Capability rawFixedMimeCapability5 (MEDIA_MIME_AUDIO_RAW); + rawFixedMimeCapability5.AppendFixedKey(CapabilityID::AUDIO_SAMPLE_RATE, 4000); + ASSERT_FALSE(Pipeline::MergeCapabilityKeys(rawFixedMimeCapability5, rawIntervalMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + // inter apply with inter + Capability rawIntervalMimeCapability2 {MEDIA_MIME_AUDIO_RAW}; + rawIntervalMimeCapability2.AppendIntervalKey(CapabilityID::AUDIO_SAMPLE_RATE, 3000, 9000); + ASSERT_TRUE(Pipeline::MergeCapabilityKeys(rawIntervalMimeCapability2, rawIntervalMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + auto intCaps2 = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(intCaps2.first == 8000); + ASSERT_TRUE(intCaps2.second == 9000); + + ASSERT_TRUE(Pipeline::MergeCapabilityKeys(rawIntervalMimeCapability, rawIntervalMimeCapability2, out)); + ASSERT_TRUE(out.mime.empty()); + auto intCaps3 = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(intCaps3.first == 8000); + ASSERT_TRUE(intCaps3.second == 9000); + + Capability rawIntervalMimeCapability3 {MEDIA_MIME_AUDIO_RAW}; + rawIntervalMimeCapability3.AppendIntervalKey(CapabilityID::AUDIO_SAMPLE_RATE, 3000, 4000); + ASSERT_FALSE(Pipeline::MergeCapabilityKeys(rawIntervalMimeCapability3, rawIntervalMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + // inter apply with discrete + Capability rawListMimeCapability5 {MEDIA_MIME_AUDIO_RAW}; + rawListMimeCapability5.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_RATE, {1000, 2000, 4000, 4100}); + ASSERT_FALSE(Pipeline::MergeCapabilityKeys(rawIntervalMimeCapability, rawListMimeCapability5, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + Capability rawListMimeCapability6 {MEDIA_MIME_AUDIO_RAW}; + rawListMimeCapability6.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_RATE, {1000, 2000, 4000, 44100}); + ASSERT_TRUE(Pipeline::MergeCapabilityKeys(rawIntervalMimeCapability, rawListMimeCapability6, out)); + ASSERT_TRUE(out.mime.empty()); + auto intCaps4 = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(intCaps4 == 44100); + + Capability rawListMimeCapability7 {MEDIA_MIME_AUDIO_RAW}; + rawListMimeCapability7.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_RATE, {1000, 2000, 40000, 44100}); + ASSERT_TRUE(Pipeline::MergeCapabilityKeys(rawIntervalMimeCapability, rawListMimeCapability7, out)); + ASSERT_TRUE(out.mime.empty()); + auto intCaps5 = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(intCaps5.size() == 2); + ASSERT_TRUE(intCaps5[0] == 40000); + ASSERT_TRUE(intCaps5[1] == 44100); +} + +TEST(TestMergeCapability, SingleType_Test) +{ + Capability wildMimeCapability("*"); + Capability out; + + Capability rawFixedMimeCapability (MEDIA_MIME_AUDIO_RAW); + rawFixedMimeCapability.AppendFixedKey(CapabilityID::AUDIO_SAMPLE_RATE, 8000); + + ASSERT_TRUE(Pipeline::MergeCapability(rawFixedMimeCapability, wildMimeCapability, out)); + ASSERT_TRUE(out.mime == rawFixedMimeCapability.mime); + ASSERT_TRUE(Plugin::AnyCast(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]) == 8000); + + Capability rawFixedMimeCapability2 (MEDIA_MIME_AUDIO_RAW); + rawFixedMimeCapability2.AppendFixedKey(CapabilityID::AUDIO_SAMPLE_RATE, 8000); + + // fix apply with fix + ASSERT_TRUE(Pipeline::MergeCapability(rawFixedMimeCapability, rawFixedMimeCapability2, out)); + ASSERT_TRUE(out.mime == rawFixedMimeCapability.mime); + ASSERT_TRUE(Plugin::AnyCast(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]) == 8000); + + // apply failed + Capability rawFixedMimeCapability3 (MEDIA_MIME_AUDIO_RAW); + rawFixedMimeCapability3.AppendFixedKey(CapabilityID::AUDIO_SAMPLE_RATE, 4000); + ASSERT_FALSE(Pipeline::MergeCapability(rawFixedMimeCapability, rawFixedMimeCapability3, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + Capability rawListMimeCapability {MEDIA_MIME_AUDIO_RAW}; + rawListMimeCapability.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_RATE, {8000, 32000, 48000, 44100}); + + ASSERT_TRUE(Pipeline::MergeCapability(rawListMimeCapability, wildMimeCapability, out)); + ASSERT_TRUE(out.mime == rawListMimeCapability.mime); + auto disCaps = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(disCaps[0] == 8000); + ASSERT_TRUE(disCaps[1] == 32000); + ASSERT_TRUE(disCaps[2] == 48000); + ASSERT_TRUE(disCaps[3] == 44100); + + // fix apply with discrete + ASSERT_TRUE(Pipeline::MergeCapability(rawFixedMimeCapability, rawListMimeCapability, out)); + ASSERT_TRUE(out.mime == rawFixedMimeCapability.mime); + ASSERT_TRUE(Plugin::AnyCast(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]) == 8000); + + // apply failed + Capability rawFixedMimeCapability4 (MEDIA_MIME_AUDIO_RAW); + rawFixedMimeCapability4.AppendFixedKey(CapabilityID::AUDIO_SAMPLE_RATE, 4000); + ASSERT_FALSE(Pipeline::MergeCapability(rawFixedMimeCapability4, rawListMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + // discrete apply with discrete + Capability rawListMimeCapability2 {MEDIA_MIME_AUDIO_RAW}; + rawListMimeCapability2.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_RATE, {1000, 2000, 48000, 44100}); + ASSERT_TRUE(Pipeline::MergeCapability(rawListMimeCapability2, rawListMimeCapability, out)); + ASSERT_TRUE(out.mime == rawListMimeCapability2.mime); + auto tmp1 = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(tmp1.size() == 2); + ASSERT_TRUE(tmp1[0] == 48000); + ASSERT_TRUE(tmp1[1] == 44100); + + // discrete apply with discrete + Capability rawListMimeCapability3 {MEDIA_MIME_AUDIO_RAW}; + rawListMimeCapability3.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_RATE, {1000, 2000, 4000, 44100}); + ASSERT_TRUE(Pipeline::MergeCapability(rawListMimeCapability3, rawListMimeCapability, out)); + ASSERT_TRUE(out.mime == rawListMimeCapability3.mime); + auto tmp2 = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(tmp2 == 44100); + + // discrete apply with discrete failed + Capability rawListMimeCapability4 {MEDIA_MIME_AUDIO_RAW}; + rawListMimeCapability4.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_RATE, {1000, 2000, 4000, 4100}); + ASSERT_FALSE(Pipeline::MergeCapability(rawListMimeCapability4, rawListMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + Capability rawIntervalMimeCapability {MEDIA_MIME_AUDIO_RAW}; + rawIntervalMimeCapability.AppendIntervalKey(CapabilityID::AUDIO_SAMPLE_RATE, 8000, 48000); + + ASSERT_TRUE(Pipeline::MergeCapability(rawIntervalMimeCapability, wildMimeCapability, out)); + ASSERT_TRUE(out.mime == rawIntervalMimeCapability.mime); + auto intCaps = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(intCaps.first == 8000); + ASSERT_TRUE(intCaps.second == 48000); + + // inter apply with fix + ASSERT_TRUE(Pipeline::MergeCapability(rawFixedMimeCapability, rawIntervalMimeCapability, out)); + ASSERT_TRUE(out.mime == rawFixedMimeCapability.mime); + ASSERT_TRUE(Plugin::AnyCast(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]) == 8000); + + ASSERT_TRUE(Pipeline::MergeCapability(rawIntervalMimeCapability, rawFixedMimeCapability, out)); + ASSERT_TRUE(out.mime == rawIntervalMimeCapability.mime); + ASSERT_TRUE(Plugin::AnyCast(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]) == 8000); + + Capability rawFixedMimeCapability5 (MEDIA_MIME_AUDIO_RAW); + rawFixedMimeCapability5.AppendFixedKey(CapabilityID::AUDIO_SAMPLE_RATE, 4000); + ASSERT_FALSE(Pipeline::MergeCapability(rawFixedMimeCapability5, rawIntervalMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + // inter apply with inter + Capability rawIntervalMimeCapability2 {MEDIA_MIME_AUDIO_RAW}; + rawIntervalMimeCapability2.AppendIntervalKey(CapabilityID::AUDIO_SAMPLE_RATE, 3000, 9000); + ASSERT_TRUE(Pipeline::MergeCapability(rawIntervalMimeCapability2, rawIntervalMimeCapability, out)); + ASSERT_TRUE(out.mime == rawIntervalMimeCapability2.mime); + auto intCaps2 = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(intCaps2.first == 8000); + ASSERT_TRUE(intCaps2.second == 9000); + + ASSERT_TRUE(Pipeline::MergeCapability(rawIntervalMimeCapability, rawIntervalMimeCapability2, out)); + ASSERT_TRUE(out.mime == rawIntervalMimeCapability.mime); + auto intCaps3 = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(intCaps3.first == 8000); + ASSERT_TRUE(intCaps3.second == 9000); + + Capability rawIntervalMimeCapability3 {MEDIA_MIME_AUDIO_RAW}; + rawIntervalMimeCapability3.AppendIntervalKey(CapabilityID::AUDIO_SAMPLE_RATE, 3000, 4000); + ASSERT_FALSE(Pipeline::MergeCapability(rawIntervalMimeCapability3, rawIntervalMimeCapability, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + // inter apply with discrete + Capability rawListMimeCapability5 {MEDIA_MIME_AUDIO_RAW}; + rawListMimeCapability5.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_RATE, {1000, 2000, 4000, 4100}); + ASSERT_FALSE(Pipeline::MergeCapability(rawIntervalMimeCapability, rawListMimeCapability5, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + Capability rawListMimeCapability6 {MEDIA_MIME_AUDIO_RAW}; + rawListMimeCapability6.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_RATE, {1000, 2000, 4000, 44100}); + ASSERT_TRUE(Pipeline::MergeCapability(rawIntervalMimeCapability, rawListMimeCapability6, out)); + ASSERT_TRUE(out.mime == rawIntervalMimeCapability.mime); + auto intCaps4 = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(intCaps4 == 44100); + + Capability rawListMimeCapability7 {MEDIA_MIME_AUDIO_RAW}; + rawListMimeCapability7.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_RATE, {1000, 2000, 40000, 44100}); + ASSERT_TRUE(Pipeline::MergeCapability(rawIntervalMimeCapability, rawListMimeCapability7, out)); + ASSERT_TRUE(out.mime == rawIntervalMimeCapability.mime); + auto intCaps5 = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(intCaps5.size() == 2); + ASSERT_TRUE(intCaps5[0] == 40000); + ASSERT_TRUE(intCaps5[1] == 44100); +} + +TEST(TestMergeCapability, ComplexType_Test) +{ + Capability wildMimeCapability("*"); + Capability out; + + Capability cap1 (MEDIA_MIME_AUDIO_RAW); + cap1.AppendFixedKey(CapabilityID::AUDIO_SAMPLE_RATE, 8000); + cap1.AppendIntervalKey(CapabilityID::AUDIO_CHANNELS, 2, 8); + cap1.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_FORMAT, { + Plugin::AudioSampleFormat::S64, Plugin::AudioSampleFormat::S64P, Plugin::AudioSampleFormat::U64, + Plugin::AudioSampleFormat::U64P, Plugin::AudioSampleFormat::F64, + }); + + Capability cap2(MEDIA_MIME_AUDIO_APE); + + ASSERT_FALSE(Pipeline::MergeCapability(cap1, cap2, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); + + Capability cap3(MEDIA_MIME_AUDIO_RAW); + ASSERT_TRUE(Pipeline::MergeCapability(cap1, cap3, out)); + ASSERT_TRUE(Plugin::AnyCast(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]) == 8000); + auto intCaps = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_CHANNELS]); + ASSERT_TRUE(intCaps.first == 2); + ASSERT_TRUE(intCaps.second == 8); + auto disCaps = Plugin::AnyCast>( + out.keys[CapabilityID::AUDIO_SAMPLE_FORMAT]); + ASSERT_TRUE(disCaps.size() == 5); + ASSERT_TRUE(disCaps[0] == Plugin::AudioSampleFormat::S64); + ASSERT_TRUE(disCaps[1] == Plugin::AudioSampleFormat::S64P); + ASSERT_TRUE(disCaps[2] == Plugin::AudioSampleFormat::U64); + ASSERT_TRUE(disCaps[3] == Plugin::AudioSampleFormat::U64P); + ASSERT_TRUE(disCaps[4] == Plugin::AudioSampleFormat::F64); + + Capability cap4(MEDIA_MIME_AUDIO_RAW); + cap4.AppendIntervalKey(CapabilityID::AUDIO_SAMPLE_RATE, 8000, 96000); + cap4.AppendFixedKey(CapabilityID::AUDIO_CHANNELS, 4); + cap4.AppendDiscreteKeys(CapabilityID::AUDIO_CHANNEL_LAYOUT, { + Plugin::AudioChannelLayout::STEREO, Plugin::AudioChannelLayout::SURROUND, + Plugin::AudioChannelLayout::CH_5POINT1, Plugin::AudioChannelLayout::CH_7POINT1, + }); + ASSERT_TRUE(Pipeline::MergeCapability(cap1, cap4, out)); + ASSERT_TRUE(Plugin::AnyCast(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]) == 8000); + ASSERT_TRUE(Plugin::AnyCast(out.keys[CapabilityID::AUDIO_CHANNELS]) == 4); + auto disCaps1 = Plugin::AnyCast>( + out.keys[CapabilityID::AUDIO_SAMPLE_FORMAT]); + ASSERT_TRUE(disCaps.size() == 5); + ASSERT_TRUE(disCaps[0] == Plugin::AudioSampleFormat::S64); + ASSERT_TRUE(disCaps[1] == Plugin::AudioSampleFormat::S64P); + ASSERT_TRUE(disCaps[2] == Plugin::AudioSampleFormat::U64); + ASSERT_TRUE(disCaps[3] == Plugin::AudioSampleFormat::U64P); + ASSERT_TRUE(disCaps[4] == Plugin::AudioSampleFormat::F64); + auto intCaps1 = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_CHANNEL_LAYOUT]); + ASSERT_TRUE(intCaps1.size() == 4); + ASSERT_TRUE(intCaps1[0] == Plugin::AudioChannelLayout::STEREO); + ASSERT_TRUE(intCaps1[1] == Plugin::AudioChannelLayout::SURROUND); + ASSERT_TRUE(intCaps1[2] == Plugin::AudioChannelLayout::CH_5POINT1); + ASSERT_TRUE(intCaps1[3] == Plugin::AudioChannelLayout::CH_7POINT1); + + Capability cap5(MEDIA_MIME_AUDIO_RAW); + cap5.AppendIntervalKey(CapabilityID::AUDIO_SAMPLE_RATE, 8000, 96000); + cap5.AppendFixedKey(CapabilityID::AUDIO_CHANNELS, 10); + cap5.AppendDiscreteKeys(CapabilityID::AUDIO_CHANNEL_LAYOUT, { + Plugin::AudioChannelLayout::STEREO, Plugin::AudioChannelLayout::SURROUND, + Plugin::AudioChannelLayout::CH_5POINT1, Plugin::AudioChannelLayout::CH_7POINT1, + }); + ASSERT_FALSE(Pipeline::MergeCapability(cap1, cap5, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); +} + +TEST(TestApplyCapabilitySet, ComplexType_Test) +{ + Capability out; + + Capability cap1 (MEDIA_MIME_AUDIO_RAW); + cap1.AppendFixedKey(CapabilityID::AUDIO_SAMPLE_RATE, 8000); + cap1.AppendIntervalKey(CapabilityID::AUDIO_CHANNELS, 2, 8); + cap1.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_FORMAT, { + Plugin::AudioSampleFormat::S64, Plugin::AudioSampleFormat::S64P, Plugin::AudioSampleFormat::U64, + Plugin::AudioSampleFormat::U64P, Plugin::AudioSampleFormat::F64, + }); + + Capability cap2(MEDIA_MIME_AUDIO_APE); + Capability cap3(MEDIA_MIME_AUDIO_RAW); + + Capability cap4(MEDIA_MIME_AUDIO_RAW); + cap4.AppendIntervalKey(CapabilityID::AUDIO_SAMPLE_RATE, 8000, 96000); + cap4.AppendFixedKey(CapabilityID::AUDIO_CHANNELS, 4); + cap4.AppendDiscreteKeys(CapabilityID::AUDIO_CHANNEL_LAYOUT, { + Plugin::AudioChannelLayout::STEREO, Plugin::AudioChannelLayout::SURROUND, + Plugin::AudioChannelLayout::CH_5POINT1, Plugin::AudioChannelLayout::CH_7POINT1, + }); + + Capability cap5(MEDIA_MIME_AUDIO_RAW); + cap5.AppendIntervalKey(CapabilityID::AUDIO_SAMPLE_RATE, 8000, 96000); + cap5.AppendFixedKey(CapabilityID::AUDIO_CHANNELS, 10); + cap5.AppendDiscreteKeys(CapabilityID::AUDIO_CHANNEL_LAYOUT, { + Plugin::AudioChannelLayout::STEREO, Plugin::AudioChannelLayout::SURROUND, + Plugin::AudioChannelLayout::CH_5POINT1, Plugin::AudioChannelLayout::CH_7POINT1, + }); + + CapabilitySet capSet1 = {cap2, cap3}; + ASSERT_TRUE(Pipeline::ApplyCapabilitySet(cap1, capSet1, out)); + ASSERT_TRUE(Plugin::AnyCast(out.keys[CapabilityID::AUDIO_SAMPLE_RATE]) == 8000); + auto intCaps = Plugin::AnyCast>(out.keys[CapabilityID::AUDIO_CHANNELS]); + ASSERT_TRUE(intCaps.first == 2); + ASSERT_TRUE(intCaps.second == 8); + auto disCaps = Plugin::AnyCast>( + out.keys[CapabilityID::AUDIO_SAMPLE_FORMAT]); + ASSERT_TRUE(disCaps.size() == 5); + ASSERT_TRUE(disCaps[0] == Plugin::AudioSampleFormat::S64); + ASSERT_TRUE(disCaps[1] == Plugin::AudioSampleFormat::S64P); + ASSERT_TRUE(disCaps[2] == Plugin::AudioSampleFormat::U64); + ASSERT_TRUE(disCaps[3] == Plugin::AudioSampleFormat::U64P); + ASSERT_TRUE(disCaps[4] == Plugin::AudioSampleFormat::F64); + + CapabilitySet capSet2 = {cap2, cap5}; + ASSERT_FALSE(Pipeline::ApplyCapabilitySet(cap1, capSet2, out)); + ASSERT_TRUE(out.mime.empty()); + ASSERT_TRUE(out.keys.empty()); +} + +TEST(TestMetaToCap, MetaToCap_Test) +{ + Meta meta; + meta.SetString(MetaID::MIME, MEDIA_MIME_AUDIO_RAW); + meta.SetUint32(MetaID::AUDIO_MPEG_VERSION, 1); + meta.SetData(MetaID::AUDIO_CHANNEL_LAYOUT, AudioChannelLayout::STEREO); + meta.SetUint32(MetaID::AUDIO_CHANNELS, 2); + meta.SetUint32(MetaID::AUDIO_SAMPLE_RATE, 48000); + auto cap = Pipeline::MetaToCapability(meta); + ASSERT_STREQ(MEDIA_MIME_AUDIO_RAW, cap->mime.c_str()); + auto mpegVersion = Plugin::AnyCast(cap->keys[CapabilityID::AUDIO_MPEG_VERSION]); + ASSERT_TRUE(mpegVersion == 1); + + auto channelLayout = Plugin::AnyCast(cap->keys[CapabilityID::AUDIO_CHANNEL_LAYOUT]); + ASSERT_TRUE(channelLayout == AudioChannelLayout::STEREO); + + auto channels = Plugin::AnyCast(cap->keys[CapabilityID::AUDIO_CHANNELS]); + ASSERT_TRUE(channels == 2); + + auto sampleRate = Plugin::AnyCast(cap->keys[CapabilityID::AUDIO_SAMPLE_RATE]); + ASSERT_TRUE(sampleRate == 48000); +} + +TEST(TestMergeMetaWithCapability, MergeMetaWithEmptyKeyCapability_Test) +{ + Meta meta; + meta.SetString(MetaID::MIME, MEDIA_MIME_AUDIO_MPEG); + meta.SetUint32(MetaID::AUDIO_MPEG_VERSION, 1); + meta.SetData(MetaID::AUDIO_CHANNEL_LAYOUT, AudioChannelLayout::STEREO); + meta.SetUint32(MetaID::AUDIO_CHANNELS, 2); + meta.SetUint32(MetaID::AUDIO_SAMPLE_RATE, 48000); + meta.SetData(MetaID::AUDIO_SAMPLE_FORMAT, AudioSampleFormat::U16P); + + Capability cap0(MEDIA_MIME_AUDIO_RAW); + Meta out1; + std::string outMime1; + uint32_t outMpegVersion1 = 0; + AudioChannelLayout outAudioChannelLayout1; + uint32_t outChannels1 = 0; + uint32_t outSampleRate1 = 0; + AudioSampleFormat outSampleFormat1 = AudioSampleFormat::U8; + ASSERT_TRUE(Pipeline::MergeMetaWithCapability(meta, cap0, out1)); + ASSERT_TRUE(out1.GetString(MetaID::MIME, outMime1)); + ASSERT_STREQ(outMime1.c_str(), MEDIA_MIME_AUDIO_RAW); + ASSERT_TRUE(out1.GetUint32(MetaID::AUDIO_MPEG_VERSION, outMpegVersion1)); + ASSERT_TRUE(outMpegVersion1 == 1); + ASSERT_TRUE(out1.GetData(MetaID::AUDIO_CHANNEL_LAYOUT, outAudioChannelLayout1)); + ASSERT_TRUE(outAudioChannelLayout1 == AudioChannelLayout::STEREO); + ASSERT_TRUE(out1.GetUint32(MetaID::AUDIO_CHANNELS, outChannels1)); + ASSERT_TRUE(outChannels1 == 2); + ASSERT_TRUE(out1.GetUint32(MetaID::AUDIO_SAMPLE_RATE, outSampleRate1)); + ASSERT_TRUE(outSampleRate1 == 48000); + ASSERT_TRUE(out1.GetData(MetaID::AUDIO_SAMPLE_FORMAT, outSampleFormat1)); + ASSERT_TRUE(outSampleFormat1 == AudioSampleFormat::U16P); +} + +TEST(TestMergeMetaWithCapability, Merge_meta_contains_meta_ony_key_capability_Test) +{ + Meta meta; + meta.SetString(MetaID::MIME, MEDIA_MIME_AUDIO_MPEG); + meta.SetUint32(MetaID::AUDIO_MPEG_VERSION, 1); + meta.SetData(MetaID::AUDIO_CHANNEL_LAYOUT, AudioChannelLayout::STEREO); + meta.SetUint32(MetaID::AUDIO_CHANNELS, 2); + meta.SetUint32(MetaID::AUDIO_SAMPLE_RATE, 48000); + meta.SetInt64(MetaID::MEDIA_BITRATE, 128000); + + Capability cap0(MEDIA_MIME_AUDIO_RAW); + cap0.AppendFixedKey(CapabilityID::AUDIO_MPEG_VERSION, 1); + cap0.AppendFixedKey(CapabilityID::AUDIO_SAMPLE_RATE, 48000); + cap0.AppendDiscreteKeys(CapabilityID::AUDIO_CHANNEL_LAYOUT, + {AudioChannelLayout::STEREO,AudioChannelLayout::SURROUND}); + cap0.AppendIntervalKey(CapabilityID::AUDIO_CHANNELS, 1, 8); + cap0.AppendDiscreteKeys(CapabilityID::AUDIO_SAMPLE_FORMAT, + {AudioSampleFormat::U16P, AudioSampleFormat::U8}); + cap0.AppendIntervalKey(CapabilityID::AUDIO_MPEG_LAYER, 3, 7); + + Meta out1; + std::string outMime1; + uint32_t outMpegVersion1 = 0; + AudioChannelLayout outAudioChannelLayout1; + uint32_t outChannels1 = 0; + uint32_t outSampleRate1 = 0; + AudioSampleFormat outSampleFormat1 = AudioSampleFormat::U8; + uint32_t outMpegLayer = 0; + int64_t outBitRate = 0; + + ASSERT_TRUE(Pipeline::MergeMetaWithCapability(meta, cap0, out1)); + ASSERT_TRUE(out1.GetString(MetaID::MIME, outMime1)); + ASSERT_STREQ(outMime1.c_str(), MEDIA_MIME_AUDIO_RAW); + ASSERT_TRUE(out1.GetUint32(MetaID::AUDIO_MPEG_VERSION, outMpegVersion1)); + ASSERT_TRUE(outMpegVersion1 == 1); + ASSERT_TRUE(out1.GetData(MetaID::AUDIO_CHANNEL_LAYOUT, outAudioChannelLayout1)); + ASSERT_TRUE(outAudioChannelLayout1 == AudioChannelLayout::STEREO); + ASSERT_TRUE(out1.GetUint32(MetaID::AUDIO_CHANNELS, outChannels1)); + ASSERT_TRUE(outChannels1 == 2); + ASSERT_TRUE(out1.GetUint32(MetaID::AUDIO_SAMPLE_RATE, outSampleRate1)); + ASSERT_TRUE(outSampleRate1 == 48000); + ASSERT_TRUE(out1.GetData(MetaID::AUDIO_SAMPLE_FORMAT, outSampleFormat1)); + ASSERT_TRUE(outSampleFormat1 == AudioSampleFormat::U16P); + ASSERT_TRUE(out1.GetUint32(MetaID::AUDIO_MPEG_LAYER, outMpegLayer)); + ASSERT_TRUE(outMpegLayer == 3); + ASSERT_TRUE(out1.GetInt64(MetaID::MEDIA_BITRATE, outBitRate)); + ASSERT_TRUE(outBitRate == 128000); +} + +TEST(TestMergeMetaWithCapability, Merge_meta_with_capability_failed_Test) +{ + Meta meta; + meta.SetString(MetaID::MIME, MEDIA_MIME_AUDIO_MPEG); + meta.SetUint32(MetaID::AUDIO_MPEG_VERSION, 1); + meta.SetData(MetaID::AUDIO_CHANNEL_LAYOUT, AudioChannelLayout::STEREO); + meta.SetUint32(MetaID::AUDIO_CHANNELS, 2); + meta.SetUint32(MetaID::AUDIO_SAMPLE_RATE, 48000); + meta.SetInt64(MetaID::MEDIA_BITRATE, 128000); + + Capability cap0(MEDIA_MIME_AUDIO_RAW); + cap0.AppendFixedKey(CapabilityID::AUDIO_MPEG_VERSION, 2); + Meta out1; + ASSERT_FALSE(Pipeline::MergeMetaWithCapability(meta, cap0, out1)); + + Capability cap1(MEDIA_MIME_AUDIO_RAW); + cap1.AppendDiscreteKeys(CapabilityID::AUDIO_CHANNEL_LAYOUT, + {AudioChannelLayout::CH_5POINT1,AudioChannelLayout::SURROUND}); + Meta out2; + ASSERT_FALSE(Pipeline::MergeMetaWithCapability(meta, cap1, out2)); + + + Capability cap2(MEDIA_MIME_AUDIO_RAW); + cap2.AppendIntervalKey(CapabilityID::AUDIO_CHANNELS, 3, 8); + Meta out3; + ASSERT_FALSE(Pipeline::MergeMetaWithCapability(meta, cap2, out3)); +} } \ No newline at end of file -- Gitee From b3ecace5f26db6c32f1cc5e3e39d1dcdadd82ded Mon Sep 17 00:00:00 2001 From: ancimoon Date: Tue, 2 Nov 2021 03:56:53 +0000 Subject: [PATCH 02/22] !96 add allowed paramter table of each filter Signed-off-by: Hu Chang --- engine/pipeline/BUILD.gn | 1 + engine/pipeline/core/compatible_check.cpp | 1 - engine/pipeline/core/filter_base.h | 3 + engine/pipeline/core/filter_type.h | 35 +++++++++++ .../audio_decoder/audio_decoder_filter.cpp | 21 +------ .../audio_decoder/audio_decoder_filter.h | 13 ---- .../filters/codec/decoder_filter_base.cpp | 24 +++++-- .../filters/codec/decoder_filter_base.h | 2 + .../filters/common/plugin_settings.cpp | 63 +++++++++++++++++++ .../pipeline/filters/common/plugin_settings.h | 39 ++++++++++++ .../pipeline/filters/demux/demuxer_filter.cpp | 7 ++- .../pipeline/filters/demux/demuxer_filter.h | 6 +- .../sink/audio_sink/audio_sink_filter.cpp | 40 ++++-------- .../filters/source/media_source_filter.cpp | 1 + engine/plugin/core/plugin_meta.h | 1 - .../sdl/audio_sink/sdl_audio_sink_plugin.cpp | 2 +- 16 files changed, 182 insertions(+), 77 deletions(-) create mode 100644 engine/pipeline/core/filter_type.h create mode 100644 engine/pipeline/filters/common/plugin_settings.cpp create mode 100644 engine/pipeline/filters/common/plugin_settings.h diff --git a/engine/pipeline/BUILD.gn b/engine/pipeline/BUILD.gn index a38113f8..c191c7ff 100644 --- a/engine/pipeline/BUILD.gn +++ b/engine/pipeline/BUILD.gn @@ -24,6 +24,7 @@ if (defined(ohos_lite)) { "factory/filter_factory.cpp", "filters/codec/audio_decoder/audio_decoder_filter.cpp", "filters/codec/decoder_filter_base.cpp", + "filters/common/plugin_settings.cpp", "filters/common/plugin_utils.cpp", "filters/demux/data_packer.cpp", "filters/demux/demuxer_filter.cpp", diff --git a/engine/pipeline/core/compatible_check.cpp b/engine/pipeline/core/compatible_check.cpp index 87ce4739..0a3e0e3d 100644 --- a/engine/pipeline/core/compatible_check.cpp +++ b/engine/pipeline/core/compatible_check.cpp @@ -23,7 +23,6 @@ #include "foundation/log.h" #include "utils/utils.h" -#include "plugin/common/plugin_audio_tags.h" namespace OHOS { namespace Media { diff --git a/engine/pipeline/core/filter_base.h b/engine/pipeline/core/filter_base.h index fb92294e..2fb79172 100644 --- a/engine/pipeline/core/filter_base.h +++ b/engine/pipeline/core/filter_base.h @@ -25,6 +25,7 @@ #include "utils/constants.h" #include "utils/event.h" #include "utils/utils.h" +#include "filter_type.h" #include "port.h" namespace OHOS { @@ -120,6 +121,8 @@ protected: std::map mediaTypeCntMap_ {}; + FilterType filterType_ {FilterType::NONE}; + private: template static T FindPort(const std::vector& list, const std::string& name); diff --git a/engine/pipeline/core/filter_type.h b/engine/pipeline/core/filter_type.h new file mode 100644 index 00000000..c7ddf814 --- /dev/null +++ b/engine/pipeline/core/filter_type.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021-2021 Huawei Device 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. + */ + +#ifndef HISTREAMER_PIPELINE_CORE_FILTER_TYPE_H +#define HISTREAMER_PIPELINE_CORE_FILTER_TYPE_H + +namespace OHOS { +namespace Media { +namespace Pipeline { +enum struct FilterType : uint8_t { + NONE = 0, + MEDIA_SOURCE, + DEMUXER, + AUDIO_DECODER, + VIDEO_DECODER, + AUDIO_SINK, + VIDEO_SINK, +}; +} // Pipeline +} // Media +} // OHOS + +#endif // HISTREAMER_PIPELINE_CORE_FILTER_TYPE_H diff --git a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp index ca011cb8..989ad4d7 100644 --- a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp +++ b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp @@ -113,6 +113,7 @@ private: AudioDecoderFilter::AudioDecoderFilter(const std::string &name): DecoderFilterBase(name), dataCallback_(std::make_shared(*this)) { + filterType_ = FilterType::AUDIO_DECODER; MEDIA_LOG_D("audio decoder ctor called"); } @@ -284,26 +285,6 @@ bool AudioDecoderFilter::Configure(const std::string &inPort, const std::shared_ return true; } -ErrorCode AudioDecoderFilter::ConfigureWithMetaLocked(const std::shared_ptr &meta) -{ -#define SET_TAG_AND_LOG(T, metaId, tagId) \ -do { \ - ret = SetTagFromMetaLocked(meta, metaId, tagId); \ - if (ret != ErrorCode::SUCCESS) { \ - MEDIA_LOG_W("set plugin audio " #tagId " error with code %d", ret); \ - } \ -} while (0) - - ErrorCode ret; - SET_TAG_AND_LOG(uint32_t, Plugin::MetaID::AUDIO_CHANNELS, Tag::AUDIO_CHANNELS); - SET_TAG_AND_LOG(uint32_t, Plugin::MetaID::AUDIO_SAMPLE_RATE, Tag::AUDIO_SAMPLE_RATE); - SET_TAG_AND_LOG(int64_t, Plugin::MetaID::MEDIA_BITRATE, Tag::MEDIA_BITRATE); - SET_TAG_AND_LOG(Plugin::AudioSampleFormat, Plugin::MetaID::AUDIO_SAMPLE_FORMAT, Tag::AUDIO_SAMPLE_FORMAT); - SET_TAG_AND_LOG(uint32_t, Plugin::MetaID::AUDIO_SAMPLE_PER_FRAME, Tag::AUDIO_SAMPLE_PER_FRAME); - SET_TAG_AND_LOG(std::vector, Plugin::MetaID::MEDIA_CODEC_CONFIG, Tag::MEDIA_CODEC_CONFIG); - return ErrorCode::SUCCESS; -} - ErrorCode AudioDecoderFilter::ConfigureToStartPluginLocked(const std::shared_ptr& meta) { auto err = TranslatePluginStatus(plugin_->SetDataCallback(dataCallback_)); diff --git a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.h b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.h index 741e7210..74d92d7f 100644 --- a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.h +++ b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.h @@ -48,8 +48,6 @@ private: ErrorCode ConfigureToStartPluginLocked(const std::shared_ptr &meta); - ErrorCode ConfigureWithMetaLocked(const std::shared_ptr &meta); - void HandleFrame(); void HandleOneFrame(const std::shared_ptr &data); @@ -66,17 +64,6 @@ private: private: ErrorCode QueueAllBufferInPoolToPluginLocked(); - template - inline ErrorCode SetTagFromMetaLocked(const std::shared_ptr &meta, Plugin::MetaID metaId, - Tag tag) - { - T tmp; - if (meta->GetData(metaId, tmp)) { - return SetPluginParameterLocked(tag, tmp); - } - return ErrorCode::ERROR_NOT_FOUND; - } - std::shared_ptr> inBufferQ_; std::shared_ptr> outBufferQ_; // PCM data std::shared_ptr handleFrameTask_ {}; // dequeue from es bufferQ then enqueue to plugin diff --git a/engine/pipeline/filters/codec/decoder_filter_base.cpp b/engine/pipeline/filters/codec/decoder_filter_base.cpp index 37d570f0..21056491 100644 --- a/engine/pipeline/filters/codec/decoder_filter_base.cpp +++ b/engine/pipeline/filters/codec/decoder_filter_base.cpp @@ -16,19 +16,31 @@ #define LOG_TAG "AudioDecoderFilter" #include "decoder_filter_base.h" -#include "utils/constants.h" + +#include "pipeline/filters/common/plugin_settings.h" #include "utils/memory_helper.h" -#include "osal/utils/util.h" -#include "factory/filter_factory.h" -#include "common/plugin_utils.h" -#include "plugin/common/plugin_audio_tags.h" namespace OHOS { namespace Media { namespace Pipeline { DecoderFilterBase::DecoderFilterBase(const std::string &name): FilterBase(name) {} -DecoderFilterBase::~DecoderFilterBase(){} +DecoderFilterBase::~DecoderFilterBase()= default; + +ErrorCode DecoderFilterBase::ConfigureWithMetaLocked(const std::shared_ptr &meta) +{ + auto parameterMap = PluginParameterTable::FindAllowedParameterMap(filterType_); + for (const auto& keyPair : parameterMap) { + Plugin::ValueType outValue; + if (meta->GetData(static_cast(keyPair.first), outValue) && + keyPair.second.second(outValue)) { + SetPluginParameterLocked(keyPair.first, outValue); + } else { + MEDIA_LOG_W("parameter %s in meta is not found or type mismatch", keyPair.second.first.c_str()); + } + } + return ErrorCode::SUCCESS; +} ErrorCode DecoderFilterBase::SetPluginParameterLocked(Tag tag, const Plugin::ValueType &value) { diff --git a/engine/pipeline/filters/codec/decoder_filter_base.h b/engine/pipeline/filters/codec/decoder_filter_base.h index 4863b34a..b6b22d8b 100644 --- a/engine/pipeline/filters/codec/decoder_filter_base.h +++ b/engine/pipeline/filters/codec/decoder_filter_base.h @@ -43,6 +43,8 @@ public: ErrorCode GetParameter(int32_t key, Plugin::Any &value) override; protected: + ErrorCode ConfigureWithMetaLocked(const std::shared_ptr &meta); + ErrorCode SetPluginParameterLocked(Tag tag, const Plugin::ValueType &value); template diff --git a/engine/pipeline/filters/common/plugin_settings.cpp b/engine/pipeline/filters/common/plugin_settings.cpp new file mode 100644 index 00000000..dd7e4b78 --- /dev/null +++ b/engine/pipeline/filters/common/plugin_settings.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2021-2021 Huawei Device 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. + */ + +#include "plugin_settings.h" + +#include +#include "plugin/common/plugin_audio_tags.h" + +#define DECLARE_PARAMETER_ITEM(tag, type) \ +{tag, {#tag, CheckParameterType}} + +namespace OHOS { +namespace Media { +namespace Pipeline { +const PluginParaAllowedMap g_emptyMap; + +template +static bool CheckParameterType(const Plugin::ValueType& value) +{ + return value.Type() == typeid(T); +} + +const PluginParaAllowedMap& PluginParameterTable::FindAllowedParameterMap(FilterType category) +{ + auto ite = table_.find(category); + if (ite == table_.end()) { + return g_emptyMap; + } + return ite->second; +} + +const std::map PluginParameterTable::table_ = { + {FilterType::AUDIO_DECODER, { + DECLARE_PARAMETER_ITEM(Plugin::Tag::AUDIO_CHANNELS, uint32_t), + DECLARE_PARAMETER_ITEM(Plugin::Tag::AUDIO_SAMPLE_RATE, uint32_t), + DECLARE_PARAMETER_ITEM(Plugin::Tag::MEDIA_BITRATE, int64_t), + DECLARE_PARAMETER_ITEM(Plugin::Tag::AUDIO_SAMPLE_FORMAT, Plugin::AudioSampleFormat), + DECLARE_PARAMETER_ITEM(Plugin::Tag::AUDIO_SAMPLE_PER_FRAME, uint32_t), + DECLARE_PARAMETER_ITEM(Plugin::Tag::MEDIA_CODEC_CONFIG, std::vector), + }}, + {FilterType::AUDIO_SINK, { + DECLARE_PARAMETER_ITEM(Plugin::Tag::AUDIO_CHANNELS, uint32_t), + DECLARE_PARAMETER_ITEM(Plugin::Tag::AUDIO_SAMPLE_RATE, uint32_t), + DECLARE_PARAMETER_ITEM(Plugin::Tag::AUDIO_SAMPLE_FORMAT, Plugin::AudioSampleFormat), + DECLARE_PARAMETER_ITEM(Plugin::Tag::AUDIO_CHANNEL_LAYOUT, Plugin::AudioChannelLayout), + DECLARE_PARAMETER_ITEM(Plugin::Tag::AUDIO_SAMPLE_PER_FRAME, uint32_t), + }}, +}; +} +} +} \ No newline at end of file diff --git a/engine/pipeline/filters/common/plugin_settings.h b/engine/pipeline/filters/common/plugin_settings.h new file mode 100644 index 00000000..ec940362 --- /dev/null +++ b/engine/pipeline/filters/common/plugin_settings.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021-2021 Huawei Device 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. + */ + +#ifndef HISTREAMER_PIPELINE_FILTER_PLUGIN_SETTINGS_H +#define HISTREAMER_PIPELINE_FILTER_PLUGIN_SETTINGS_H + +#include + +#include "pipeline/core/filter_type.h" +#include "plugin/common/plugin_tags.h" +#include "plugin/common/plugin_types.h" + +namespace OHOS { +namespace Media { +namespace Pipeline { +using PluginParaAllowedMap = std::map>>; + +struct PluginParameterTable { + static const PluginParaAllowedMap& FindAllowedParameterMap(FilterType category); +private: + static const std::map table_; +}; +} // Pipeline +} // Media +} // OHOS +#endif // HISTREAMER_PIPELINE_FILTER_PLUGIN_SETTINGS_H diff --git a/engine/pipeline/filters/demux/demuxer_filter.cpp b/engine/pipeline/filters/demux/demuxer_filter.cpp index 03ca48da..1e51cc1c 100644 --- a/engine/pipeline/filters/demux/demuxer_filter.cpp +++ b/engine/pipeline/filters/demux/demuxer_filter.cpp @@ -102,6 +102,7 @@ DemuxerFilter::DemuxerFilter(std::string name) mediaMetaData_(), curTimeUs_(0) { + filterType_ = FilterType::DEMUXER; MEDIA_LOG_D("ctor called"); } @@ -202,8 +203,8 @@ ErrorCode DemuxerFilter::PushData(const std::string& inPort, AVBufferPtr buffer) return ErrorCode::SUCCESS; } -bool DemuxerFilter::Negotiate(const std::string &inPort, const std::shared_ptr &upstreamCap, - Capability &upstreamNegotiatedCap) +bool DemuxerFilter::Negotiate(const std::string& inPort, const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) { (void)inPort; (void)upstreamCap; @@ -211,7 +212,7 @@ bool DemuxerFilter::Negotiate(const std::string &inPort, const std::shared_ptr &upstreamMeta) +bool DemuxerFilter::Configure(const std::string& inPort, const std::shared_ptr& upstreamMeta) { (void)upstreamMeta->GetUint64(Plugin::MetaID::MEDIA_FILE_SIZE, mediaDataSize_); return upstreamMeta->GetString(Plugin::MetaID::MEDIA_FILE_EXTENSION, uriSuffix_); diff --git a/engine/pipeline/filters/demux/demuxer_filter.h b/engine/pipeline/filters/demux/demuxer_filter.h index 91c6082f..5677e37f 100644 --- a/engine/pipeline/filters/demux/demuxer_filter.h +++ b/engine/pipeline/filters/demux/demuxer_filter.h @@ -54,10 +54,10 @@ public: ErrorCode PushData(const std::string& inPort, AVBufferPtr buffer) override; - bool Negotiate(const std::string &inPort, const std::shared_ptr &upstreamCap, - Capability &upstreamNegotiatedCap) override; + bool Negotiate(const std::string& inPort, const std::shared_ptr& upstreamCap, + Capability& upstreamNegotiatedCap) override; - bool Configure(const std::string &inPort, const std::shared_ptr &upstreamMeta) override; + bool Configure(const std::string& inPort, const std::shared_ptr& upstreamMeta) override; ErrorCode SeekTo(int64_t msec); diff --git a/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp b/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp index cd728974..a495f0c3 100644 --- a/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp +++ b/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp @@ -19,6 +19,7 @@ #include "common/plugin_utils.h" #include "factory/filter_factory.h" #include "foundation/log.h" +#include "pipeline/filters/common/plugin_settings.h" namespace OHOS { namespace Media { @@ -27,6 +28,7 @@ static AutoRegisterFilter g_registerFilterHelper("builtin.playe AudioSinkFilter::AudioSinkFilter(const std::string& name) : FilterBase(name) { + filterType_ = FilterType::AUDIO_SINK; MEDIA_LOG_I("audio sink ctor called"); } AudioSinkFilter::~AudioSinkFilter() @@ -137,35 +139,15 @@ bool AudioSinkFilter::Configure(const std::string& inPort, const std::shared_ptr ErrorCode AudioSinkFilter::ConfigureWithMeta(const std::shared_ptr& meta) { - uint32_t channels; - if (meta->GetUint32(Plugin::MetaID::AUDIO_CHANNELS, channels)) { - MEDIA_LOG_D("found audio channel meta"); - SetPluginParameter(Tag::AUDIO_CHANNELS, channels); - } - uint32_t sampleRate; - if (meta->GetUint32(Plugin::MetaID::AUDIO_SAMPLE_RATE, sampleRate)) { - MEDIA_LOG_D("found audio sample rate meta"); - SetPluginParameter(Tag::AUDIO_SAMPLE_RATE, sampleRate); - } - int64_t bitRate; - if (meta->GetInt64(Plugin::MetaID::MEDIA_BITRATE, bitRate)) { - MEDIA_LOG_D("found audio bit rate meta"); - SetPluginParameter(Tag::MEDIA_BITRATE, bitRate); - } - - auto audioFormat = Plugin::AudioSampleFormat::U8; - if (meta->GetData(Plugin::MetaID::AUDIO_SAMPLE_FORMAT, audioFormat)) { - SetPluginParameter(Tag::AUDIO_SAMPLE_FORMAT, audioFormat); - } - - auto audioChannelLayout = Plugin::AudioChannelLayout::STEREO; - if (meta->GetData(Plugin::MetaID::AUDIO_CHANNEL_LAYOUT, audioChannelLayout)) { - SetPluginParameter(Tag::AUDIO_CHANNEL_LAYOUT, audioChannelLayout); - } - - uint32_t samplePerFrame = 0; - if (meta->GetUint32(Plugin::MetaID::AUDIO_SAMPLE_PER_FRAME, samplePerFrame)) { - SetPluginParameter(Tag::AUDIO_SAMPLE_PER_FRAME, samplePerFrame); + auto parameterMap = PluginParameterTable::FindAllowedParameterMap(filterType_); + for (const auto& keyPair : parameterMap) { + Plugin::ValueType outValue; + if (meta->GetData(static_cast(keyPair.first), outValue) && + keyPair.second.second(outValue)) { + SetPluginParameter(keyPair.first, outValue); + } else { + MEDIA_LOG_W("parameter %s in meta is not found or type mismatch", keyPair.second.first.c_str()); + } } return ErrorCode::SUCCESS; } diff --git a/engine/pipeline/filters/source/media_source_filter.cpp b/engine/pipeline/filters/source/media_source_filter.cpp index 839437c0..7313b9e5 100644 --- a/engine/pipeline/filters/source/media_source_filter.cpp +++ b/engine/pipeline/filters/source/media_source_filter.cpp @@ -42,6 +42,7 @@ MediaSourceFilter::MediaSourceFilter(const std::string& name) pluginAllocator_(nullptr), pluginInfo_(nullptr) { + filterType_ = FilterType::MEDIA_SOURCE; MEDIA_LOG_D("ctor called"); } diff --git a/engine/plugin/core/plugin_meta.h b/engine/plugin/core/plugin_meta.h index 08b166a8..dfb9fd3d 100644 --- a/engine/plugin/core/plugin_meta.h +++ b/engine/plugin/core/plugin_meta.h @@ -130,7 +130,6 @@ public: return true; } - void Clear(); /** diff --git a/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp b/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp index 9d95b128..cfbb5d50 100644 --- a/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp +++ b/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp @@ -240,7 +240,7 @@ Status SdlAudioSinkPlugin::SetParameter(Tag tag, const ValueType& value) break; } default: - MEDIA_LOG_I("receive one parameter with unconcern key"); + MEDIA_LOG_W("receive one parameter with unconcern key"); break; } return Status::OK; -- Gitee From a4a0f3073370bf1d85ce1786932669f74d325e08 Mon Sep 17 00:00:00 2001 From: ancimoon Date: Wed, 3 Nov 2021 09:30:03 +0000 Subject: [PATCH 03/22] !105 change stream to track Signed-off-by: Hu Chang --- engine/pipeline/core/pipeline_core.cpp | 22 ++++++++--------- engine/pipeline/core/pipeline_core.h | 6 ++--- .../pipeline/filters/demux/demuxer_filter.cpp | 24 +++++++++---------- engine/player/hiplayer_impl.cpp | 8 +++---- engine/player/hiplayer_impl.h | 4 ++-- engine/plugin/common/plugin_tags.h | 6 ++--- engine/plugin/core/demuxer.h | 2 +- engine/plugin/core/plugin_meta.h | 2 +- engine/plugin/core/plugin_wrapper.cpp | 6 ++--- .../demuxer/ffmpeg_track_meta.cpp | 6 ++--- tests/ut/TestMetaBundle.cpp | 18 +++++++------- 11 files changed, 52 insertions(+), 52 deletions(-) diff --git a/engine/pipeline/core/pipeline_core.cpp b/engine/pipeline/core/pipeline_core.cpp index 2d8d971d..2c47cd31 100644 --- a/engine/pipeline/core/pipeline_core.cpp +++ b/engine/pipeline/core/pipeline_core.cpp @@ -21,11 +21,11 @@ namespace OHOS { namespace Media { namespace Pipeline { -std::shared_ptr OHOS::Media::Pipeline::MetaBundle::GetStreamMeta(int32_t streamIndex) +std::shared_ptr OHOS::Media::Pipeline::MetaBundle::GeTrackMeta(int32_t trackId) { - for (auto& ptr : streamMeta_) { + for (auto& ptr : trackMeta_) { uint32_t found = 0; - if (ptr->GetUint32(Plugin::MetaID::STREAM_INDEX, found) && found == streamIndex) { + if (ptr->GetUint32(Plugin::MetaID::TRACK_ID, found) && found == trackId) { return ptr; } } @@ -40,23 +40,23 @@ void MetaBundle::UpdateGlobalMeta(const Plugin::Meta& meta) globalMeta_->Update(meta); } -void MetaBundle::UpdateStreamMeta(const Plugin::Meta& meta) +void MetaBundle::UpdateTrackMeta(const Plugin::Meta& meta) { - uint32_t streamIndex = 0; - if (!meta.GetUint32(Plugin::MetaID::STREAM_INDEX, streamIndex)) { - MEDIA_LOG_W("update stream meta with invalid meta, which contains no stream index, will ignore this meta"); + uint32_t trackId = 0; + if (!meta.GetUint32(Plugin::MetaID::TRACK_ID, trackId)) { + MEDIA_LOG_W("update stream meta with invalid meta, which contains no track id, will ignore this meta"); return; } - for (const auto& tmp : streamMeta_) { - uint32_t stIndex = 0; - if (tmp->GetUint32(Plugin::MetaID::STREAM_INDEX, stIndex) && streamIndex == stIndex) { + for (const auto& tmp : trackMeta_) { + uint32_t tid = 0; + if (tmp->GetUint32(Plugin::MetaID::TRACK_ID, tid) && trackId == tid) { tmp->Update(meta); return; } } auto ptr = std::make_shared(); ptr->Update(meta); - streamMeta_.emplace_back(ptr); + trackMeta_.emplace_back(ptr); } PipelineCore::PipelineCore(const std::string& name) diff --git a/engine/pipeline/core/pipeline_core.h b/engine/pipeline/core/pipeline_core.h index d06613ca..eb5e250e 100644 --- a/engine/pipeline/core/pipeline_core.h +++ b/engine/pipeline/core/pipeline_core.h @@ -44,15 +44,15 @@ public: return globalMeta_; } - std::shared_ptr GetStreamMeta(int32_t streamIndex); + std::shared_ptr GeTrackMeta(int32_t trackId); void UpdateGlobalMeta(const Plugin::Meta& meta); - void UpdateStreamMeta(const Plugin::Meta& meta); + void UpdateTrackMeta(const Plugin::Meta& meta); private: std::shared_ptr globalMeta_; - std::vector> streamMeta_; + std::vector> trackMeta_; }; class PipelineCore : public Pipeline { diff --git a/engine/pipeline/filters/demux/demuxer_filter.cpp b/engine/pipeline/filters/demux/demuxer_filter.cpp index 1e51cc1c..4f7996e6 100644 --- a/engine/pipeline/filters/demux/demuxer_filter.cpp +++ b/engine/pipeline/filters/demux/demuxer_filter.cpp @@ -349,7 +349,7 @@ void DemuxerFilter::InitMediaMetaData(const Plugin::MediaInfoHelper& mediaInfo) mediaMetaData_.globalMeta = std::make_shared(mediaInfo.globalMeta); mediaMetaData_.trackMetas.clear(); int trackCnt = 0; - for (auto& trackMeta : mediaInfo.streamMeta) { + for (auto& trackMeta : mediaInfo.trackMeta) { mediaMetaData_.trackMetas.push_back(std::make_shared(trackMeta)); if (!trackMeta.Empty()) { ++trackCnt; @@ -368,36 +368,36 @@ bool DemuxerFilter::PrepareStreams(const Plugin::MediaInfoHelper& mediaInfo) MEDIA_LOG_D("PrepareStreams called"); InitMediaMetaData(mediaInfo); outPorts_.clear(); - int streamCnt = mediaInfo.streamMeta.size(); + int streamCnt = mediaInfo.trackMeta.size(); PortInfo portInfo; portInfo.type = PortType::OUT; portInfo.ports.reserve(streamCnt); int audioTrackCnt = 0; for (int i = 0; i < streamCnt; ++i) { - if (mediaInfo.streamMeta[i].Empty()) { - MEDIA_LOG_E("PrepareStreams, unsupported stream with streamIdx = %d", i); + if (mediaInfo.trackMeta[i].Empty()) { + MEDIA_LOG_E("PrepareStreams, unsupported stream with trackId = %d", i); continue; } std::string mime; - uint32_t streamIdx = 0; - if (!mediaInfo.streamMeta[i].GetString(Plugin::MetaID::MIME, mime) || - !mediaInfo.streamMeta[i].GetUint32(Plugin::MetaID::STREAM_INDEX, streamIdx)) { - MEDIA_LOG_E("PrepareStreams failed to extract mime or streamIdx."); + uint32_t trackId = 0; + if (!mediaInfo.trackMeta[i].GetString(Plugin::MetaID::MIME, mime) || + !mediaInfo.trackMeta[i].GetUint32(Plugin::MetaID::TRACK_ID, trackId)) { + MEDIA_LOG_E("PrepareStreams failed to extract mime or trackId."); continue; } if (IsAudioMime(mime)) { - MEDIA_LOG_D("PrepareStreams, audio stream with streamIdx = %u.", streamIdx); + MEDIA_LOG_D("PrepareStreams, audio stream with trackId = %u.", trackId); if (audioTrackCnt == 1) { - MEDIA_LOG_E("PrepareStreams, discard audio stream: %d.", streamIdx); + MEDIA_LOG_E("PrepareStreams, discard audio track: %d.", trackId); continue; } ++audioTrackCnt; } auto port = std::make_shared(this, NamePort(mime)); - MEDIA_LOG_I("PrepareStreams, streamIdx: %d, portName: %s", i, port->GetName().c_str()); + MEDIA_LOG_I("PrepareStreams, trackId: %d, portName: %s", i, port->GetName().c_str()); outPorts_.push_back(port); portInfo.ports.push_back({port->GetName(), IsRawAudio(mime)}); - mediaMetaData_.trackInfos.emplace_back(streamIdx, std::move(port), true); + mediaMetaData_.trackInfos.emplace_back(trackId, std::move(port), true); } if (portInfo.ports.empty()) { MEDIA_LOG_E("PrepareStreams failed due to no valid port."); diff --git a/engine/player/hiplayer_impl.cpp b/engine/player/hiplayer_impl.cpp index 2eeabe21..543f0bc2 100644 --- a/engine/player/hiplayer_impl.cpp +++ b/engine/player/hiplayer_impl.cpp @@ -449,7 +449,7 @@ ErrorCode HiPlayerImpl::OnCallback(const FilterCallbackType& type, Filter* filte return ret; } -ErrorCode HiPlayerImpl::GetStreamCnt(size_t& cnt) const +ErrorCode HiPlayerImpl::GetTrackCnt(size_t& cnt) const { cnt = streamMeta_.size(); return ErrorCode::SUCCESS; @@ -461,12 +461,12 @@ ErrorCode HiPlayerImpl::GetSourceMeta(shared_ptr& meta) cons return meta ? ErrorCode::SUCCESS : ErrorCode::ERROR_NOT_FOUND; } -ErrorCode HiPlayerImpl::GetStreamMeta(size_t index, shared_ptr& meta) const +ErrorCode HiPlayerImpl::GetTrackMeta(size_t id, shared_ptr& meta) const { - if (index > streamMeta_.size() || index < 0) { + if (id > streamMeta_.size() || id < 0) { return ErrorCode::ERROR_INVALID_PARAM_VALUE; } - meta = streamMeta_[index].lock(); + meta = streamMeta_[id].lock(); if (meta == nullptr) { return ErrorCode::ERROR_NOT_FOUND; } diff --git a/engine/player/hiplayer_impl.h b/engine/player/hiplayer_impl.h index 255a7a00..aea6da21 100644 --- a/engine/player/hiplayer_impl.h +++ b/engine/player/hiplayer_impl.h @@ -112,8 +112,8 @@ public: ErrorCode SetBufferSize(size_t size); ErrorCode GetSourceMeta(std::shared_ptr& meta) const; - ErrorCode GetStreamCnt(size_t& cnt) const; - ErrorCode GetStreamMeta(size_t index, std::shared_ptr& meta) const; + ErrorCode GetTrackCnt(size_t& cnt) const; + ErrorCode GetTrackMeta(size_t id, std::shared_ptr& meta) const; ErrorCode SetVolume(float volume); diff --git a/engine/plugin/common/plugin_tags.h b/engine/plugin/common/plugin_tags.h index 4a08ae7e..1fce3eff 100644 --- a/engine/plugin/common/plugin_tags.h +++ b/engine/plugin/common/plugin_tags.h @@ -77,7 +77,7 @@ enum struct Tag : uint32_t { /* -------------------- regular tag -------------------- */ MIME = SECTION_REGULAR_START + 1, // string - STREAM_INDEX, // uint32_t + TRACK_ID, // uint32_t REQUIRED_OUT_BUFFER_CNT, // uint32_t required buffer count of plugin; read only tag PARAMETER_STRUCT, // ParameterStruct @@ -151,8 +151,8 @@ enum struct Direction : uint8_t { struct ParameterStruct { uint32_t direction {static_cast(Direction::IN) | static_cast(Direction::OUT)}; ///< direction of parameter, default is in and out - int32_t streamIndex { - -1}; ///< indicates stream that will be effected by this parameter, -1 means that all stream will be effected + int32_t trackId { + -1}; ///< indicates track that will be effected by this parameter, -1 means that all tracks will be effected Tag tagId; ///< parameter tag id ValueType value; ///< value of the parameter }; diff --git a/engine/plugin/core/demuxer.h b/engine/plugin/core/demuxer.h index 5e7ee2b2..9eff2900 100644 --- a/engine/plugin/core/demuxer.h +++ b/engine/plugin/core/demuxer.h @@ -29,7 +29,7 @@ using AllocatorHelper = Allocator; struct MediaInfoHelper { Meta globalMeta; - std::vector streamMeta; + std::vector trackMeta; }; struct DataSourceHelper { diff --git a/engine/plugin/core/plugin_meta.h b/engine/plugin/core/plugin_meta.h index dfb9fd3d..305adc7a 100644 --- a/engine/plugin/core/plugin_meta.h +++ b/engine/plugin/core/plugin_meta.h @@ -36,7 +36,7 @@ constexpr typename std::underlying_type::type to_underlying(E e) noexcept */ enum struct MetaID : uint32_t { MIME = to_underlying(Tag::MIME), - STREAM_INDEX = to_underlying(Tag::STREAM_INDEX), + TRACK_ID = to_underlying(Tag::TRACK_ID), MEDIA_CODEC_CONFIG = to_underlying(Tag::MEDIA_CODEC_CONFIG), AUDIO_CHANNELS = to_underlying(Tag::AUDIO_CHANNELS), diff --git a/engine/plugin/core/plugin_wrapper.cpp b/engine/plugin/core/plugin_wrapper.cpp index 1a10c55c..d01043b2 100644 --- a/engine/plugin/core/plugin_wrapper.cpp +++ b/engine/plugin/core/plugin_wrapper.cpp @@ -19,7 +19,7 @@ namespace { std::set g_metaIdSet = { OHOS::Media::Plugin::MetaID::MIME, - OHOS::Media::Plugin::MetaID::STREAM_INDEX, + OHOS::Media::Plugin::MetaID::TRACK_ID, OHOS::Media::Plugin::MetaID::MEDIA_CODEC_CONFIG, OHOS::Media::Plugin::MetaID::MEDIA_BITRATE, OHOS::Media::Plugin::MetaID::AUDIO_CHANNELS, @@ -66,11 +66,11 @@ void ConvertToMediaInfoHelper(uint32_t pkgVersion, const MediaInfo& src, MediaIn if (streamSize <= 0) { return; } - dest.streamMeta.resize(streamSize); + dest.trackMeta.resize(streamSize); for (size_t i = 0; i < streamSize; ++i) { for (auto const& meta : src.tracks[i]) { if (g_metaIdSet.count(MetaID(meta.first))) { - dest.streamMeta[i].SetData(MetaID(meta.first), meta.second); + dest.trackMeta[i].SetData(MetaID(meta.first), meta.second); } } } diff --git a/engine/plugin/plugins/ffmpeg_adapter/demuxer/ffmpeg_track_meta.cpp b/engine/plugin/plugins/ffmpeg_adapter/demuxer/ffmpeg_track_meta.cpp index 6f3db290..9ebf0b79 100644 --- a/engine/plugin/plugins/ffmpeg_adapter/demuxer/ffmpeg_track_meta.cpp +++ b/engine/plugin/plugins/ffmpeg_adapter/demuxer/ffmpeg_track_meta.cpp @@ -60,7 +60,7 @@ bool IsPcmStream(const AVStream& avStream) void ConvertCommonAudioStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& context, TagMap& meta) { - meta.insert({Tag::STREAM_INDEX, static_cast(avStream.index)}); + meta.insert({Tag::TRACK_ID, static_cast(avStream.index)}); if (context->channels != -1) { meta.insert({Tag::AUDIO_SAMPLE_RATE, static_cast(context->sample_rate)}); meta.insert({Tag::AUDIO_CHANNELS, static_cast(context->channels)}); @@ -137,7 +137,7 @@ void ConvertAACLatmStreamToMetaInfo(const AVStream& avStream, const std::shared_ TagMap& meta) { meta.insert({Tag::MIME, std::string(MEDIA_MIME_AUDIO_AAC_LATM)}); - meta.insert({Tag::STREAM_INDEX, static_cast(avStream.index)}); + meta.insert({Tag::TRACK_ID, static_cast(avStream.index)}); if (context->channels != -1) { meta.insert({Tag::AUDIO_SAMPLE_RATE, static_cast(context->sample_rate)}); meta.insert({Tag::AUDIO_CHANNELS, static_cast(context->channels)}); @@ -155,7 +155,7 @@ void ConvertAACLatmStreamToMetaInfo(const AVStream& avStream, const std::shared_ void ConvertAVCStreamToMetaInfo(const AVStream& avStream, const std::shared_ptr& context, TagMap& meta) { meta.insert({Tag::MIME, std::string(MEDIA_MIME_VIDEO_AVC)}); - meta.insert({Tag::STREAM_INDEX, static_cast(avStream.index)}); + meta.insert({Tag::TRACK_ID, static_cast(avStream.index)}); meta.insert({Tag::MEDIA_BITRATE, context->bit_rate}); meta.insert({Tag::VIDEO_WIDTH, static_cast(context->width)}); meta.insert({Tag::VIDEO_HEIGHT, static_cast(context->height)}); diff --git a/tests/ut/TestMetaBundle.cpp b/tests/ut/TestMetaBundle.cpp index 58f8b91f..eb31d793 100644 --- a/tests/ut/TestMetaBundle.cpp +++ b/tests/ut/TestMetaBundle.cpp @@ -30,7 +30,7 @@ TEST(Test_meta_bundle, GetNull_before_Update) { Pipeline::MetaBundle bundle; ASSERT_TRUE(bundle.GetGlobalMeta() == nullptr); - ASSERT_TRUE(bundle.GetStreamMeta(0) == nullptr); + ASSERT_TRUE(bundle.GeTrackMeta(0) == nullptr); } TEST(Test_meta_bundle, GetGlobalMeta_after_Update) @@ -45,7 +45,7 @@ TEST(Test_meta_bundle, GetGlobalMeta_after_Update) Pipeline::MetaBundle bundle; ASSERT_TRUE(bundle.GetGlobalMeta() == nullptr); - ASSERT_TRUE(bundle.GetStreamMeta(0) == nullptr); + ASSERT_TRUE(bundle.GeTrackMeta(0) == nullptr); bundle.UpdateGlobalMeta(meta); auto out = bundle.GetGlobalMeta(); ASSERT_TRUE(out != nullptr); @@ -69,13 +69,13 @@ TEST(Test_meta_bundle, GetStreamMeta_after_Update) Pipeline::MetaBundle bundle; ASSERT_TRUE(bundle.GetGlobalMeta() == nullptr); - ASSERT_TRUE(bundle.GetStreamMeta(0) == nullptr); - bundle.UpdateStreamMeta(meta); - auto out = bundle.GetStreamMeta(0); + ASSERT_TRUE(bundle.GeTrackMeta(0) == nullptr); + bundle.UpdateTrackMeta(meta); + auto out = bundle.GeTrackMeta(0); ASSERT_TRUE(out == nullptr); - meta.SetUint32(Media::Plugin::MetaID::STREAM_INDEX, 1); - bundle.UpdateStreamMeta(meta); - out = bundle.GetStreamMeta(1); + meta.SetUint32(Media::Plugin::MetaID::TRACK_ID, 1); + bundle.UpdateTrackMeta(meta); + out = bundle.GeTrackMeta(1); std::string outString; ASSERT_TRUE(out->GetString(Media::Plugin::MetaID::MIME, outString)); ASSERT_STREQ("audio/mpeg", outString.c_str()); @@ -84,7 +84,7 @@ TEST(Test_meta_bundle, GetStreamMeta_after_Update) int32_t oChannel = 0; ASSERT_FALSE(out->GetInt32(Media::Plugin::MetaID::AUDIO_CHANNELS, oChannel)); uint32_t sIndex = 0; - ASSERT_TRUE(out->GetUint32(Media::Plugin::MetaID::STREAM_INDEX, sIndex)); + ASSERT_TRUE(out->GetUint32(Media::Plugin::MetaID::TRACK_ID, sIndex)); ASSERT_EQ(sIndex, 1); } } // namespace Test -- Gitee From a7cecb799fc68ac30385870e7ff916c8efdba285 Mon Sep 17 00:00:00 2001 From: leo_ysl <9693773+leo_ysl@user.noreply.gitee.com> Date: Thu, 4 Nov 2021 01:07:56 +0000 Subject: [PATCH 04/22] !106 remove ring buffer. Signed-off-by: Li Yong --- engine/plugin/plugins/hdi_adapter/BUILD.gn | 1 - .../plugins/hdi_adapter/sink/hos_au_sink.cpp | 1 - .../plugins/hdi_adapter/sink/ring_buffer.cpp | 129 ------------------ .../plugins/hdi_adapter/sink/ring_buffer.h | 62 --------- 4 files changed, 193 deletions(-) delete mode 100644 engine/plugin/plugins/hdi_adapter/sink/ring_buffer.cpp delete mode 100644 engine/plugin/plugins/hdi_adapter/sink/ring_buffer.h diff --git a/engine/plugin/plugins/hdi_adapter/BUILD.gn b/engine/plugin/plugins/hdi_adapter/BUILD.gn index fbf53b9e..14c1acba 100644 --- a/engine/plugin/plugins/hdi_adapter/BUILD.gn +++ b/engine/plugin/plugins/hdi_adapter/BUILD.gn @@ -25,7 +25,6 @@ if (defined(ohos_lite)) { plugin_hdi_adapter_src = [ "sink/hos_au_sink.cpp", - "sink/ring_buffer.cpp", "utils/hdi_au_utils.cpp", ] diff --git a/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp b/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp index 6f969817..e6366d43 100644 --- a/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp +++ b/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp @@ -25,7 +25,6 @@ #include "foundation/osal/utils/util.h" #include "plugin/common/plugin_audio_tags.h" #include "plugins/hdi_adapter/utils/hdi_au_utils.h" -#include "ring_buffer.h" #include "securec.h" #include "utils/constants.h" #include "utils/utils.h" diff --git a/engine/plugin/plugins/hdi_adapter/sink/ring_buffer.cpp b/engine/plugin/plugins/hdi_adapter/sink/ring_buffer.cpp deleted file mode 100644 index f4b1b560..00000000 --- a/engine/plugin/plugins/hdi_adapter/sink/ring_buffer.cpp +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Copyright (c) 2021-2021 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "HdiRingBuffer" - -#include "ring_buffer.h" -#include "foundation/log.h" -#include "utils/memory_helper.h" -#include "plugin/common/plugin_buffer.h" - -namespace OHOS { -namespace Media { -namespace HosLitePlugin { -bool RingBuffer::Init() -{ - buffer_ = OHOS::Media::MemoryHelper::make_unique(bufferSize_); - return buffer_ != nullptr; -} -std::shared_ptr RingBuffer::ReadBufferWithoutAdvance(size_t readSize, size_t& outSize) -{ - OHOS::Media::OSAL::ScopedLock lck(writeMutex_); - std::shared_ptr ptr; - if (!isActive_) { - ptr = nullptr; - outSize = 0; - return ptr; - } - auto available = tail_ - head_; - available = (available > readSize) ? readSize : available; - size_t index = head_ % bufferSize_; - if (index + available < bufferSize_) { - ptr = std::shared_ptr(buffer_.get() + index, [](uint8_t* ptr) {}); // do not delete memory - outSize = available; - return ptr; - } - - ptr = std::shared_ptr(new (std::nothrow) uint8_t[available], std::default_delete()); - if (ptr == nullptr) { - outSize = 0; - } else { - outSize = available; - if (memcpy_s(ptr.get(), bufferSize_ - index, buffer_.get() + index, bufferSize_ - index) != EOK) { - MEDIA_LOG_E("memcpy_s failed when read buffer"); - outSize = 0; - } - if (available - (bufferSize_ - index) > 0 && memcpy_s(ptr.get() + (bufferSize_ - index), - available - (bufferSize_ - index), buffer_.get(), available - (bufferSize_ - index)) != EOK) { - MEDIA_LOG_E("memcpy_s failed when read buffer"); - outSize = 0; - } - } - return ptr; -} -void RingBuffer::Advance(size_t size) -{ - OHOS::Media::OSAL::ScopedLock lck(writeMutex_); - if (!isActive_) { - return; - } - head_ += size; - writeCondition_.NotifyAll(); -} -void RingBuffer::WriteBuffer(const std::shared_ptr& inputInfo) -{ - auto mem = inputInfo->GetMemory(); - size_t writeSize = mem->GetSize(); - auto ptr = mem->GetReadOnlyData(); - OHOS::Media::OSAL::ScopedLock lck(writeMutex_); - if (!isActive_) { - return; - } - while (writeSize + tail_ > head_ + bufferSize_) { - writeCondition_.Wait(lck); - if (!isActive_) { - return; - } - } - size_t index = tail_ % bufferSize_; - if (index + writeSize < bufferSize_) { - if (memcpy_s(buffer_.get() + index, writeSize, ptr, writeSize) != EOK) { - MEDIA_LOG_E("memcpy_s failed when write buffer"); - writeSize = 0; - } - tail_ += writeSize; - return; - } - if (memcpy_s(buffer_.get() + index, bufferSize_ - index, ptr, bufferSize_ - index) != EOK) { - MEDIA_LOG_E("memcpy_s failed when write buffer"); - return; - } - if (writeSize - (bufferSize_ - index) > 0 && memcpy_s(buffer_.get(), writeSize - (bufferSize_ - index), - ((uint8_t*)ptr) + bufferSize_ - index, writeSize - (bufferSize_ - index)) != EOK) { - MEDIA_LOG_E("memcpy_s failed when write buffer"); - return; - } - tail_ += writeSize; -} -void RingBuffer::SetActive(bool active) -{ - OHOS::Media::OSAL::ScopedLock lck(writeMutex_); - isActive_ = active; - if (!active) { - head_ = 0; - tail_ = 0; - writeCondition_.NotifyOne(); - } -} -void RingBuffer::Clear() -{ - OHOS::Media::OSAL::ScopedLock lck(writeMutex_); - head_ = 0; - tail_ = 0; - writeCondition_.NotifyOne(); -} -} -} -} \ No newline at end of file diff --git a/engine/plugin/plugins/hdi_adapter/sink/ring_buffer.h b/engine/plugin/plugins/hdi_adapter/sink/ring_buffer.h deleted file mode 100644 index 204868c7..00000000 --- a/engine/plugin/plugins/hdi_adapter/sink/ring_buffer.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2021-2021 Huawei Device 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. - */ - -#ifndef HISTREAMER_HDI_ADAPTER_RING_BUFFER_H -#define HISTREAMER_HDI_ADAPTER_RING_BUFFER_H - -#include -#include - -#include "foundation/osal/thread/condition_variable.h" -#include "foundation/osal/thread/mutex.h" - -namespace OHOS { -namespace Media { -namespace Plugin { -class Buffer; -} -namespace HosLitePlugin { -class RingBuffer { -public: - explicit RingBuffer(size_t bufferSize) : bufferSize_(bufferSize) {} - - ~RingBuffer() = default; - - bool Init(); - - std::shared_ptr ReadBufferWithoutAdvance(size_t readSize, size_t& outSize); - - void Advance(size_t size); - - void WriteBuffer(const std::shared_ptr& inputInfo); - - void SetActive(bool active); - - void Clear(); - -private: - const size_t bufferSize_; - std::unique_ptr buffer_ {}; - size_t head_ {0}; // head - size_t tail_ {0}; // tail - OHOS::Media::OSAL::Mutex writeMutex_ {}; - OHOS::Media::OSAL::ConditionVariable writeCondition_ {}; - bool isActive_ {true}; -}; -} // namespace HosLitePlugin -} // namespace Media -} // namespace OHOS - -#endif // MEDIA_PIPELINE_RING_BUFFER_H -- Gitee From c9dd56d44518ad7c73c096ee990b753952796ecb Mon Sep 17 00:00:00 2001 From: leo_ysl <9693773+leo_ysl@user.noreply.gitee.com> Date: Thu, 4 Nov 2021 03:37:53 +0000 Subject: [PATCH 05/22] !107 using custom scheduling policy only for ohos lite. Signed-off-by: Li Yong --- engine/foundation/osal/thread/thread.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/engine/foundation/osal/thread/thread.cpp b/engine/foundation/osal/thread/thread.cpp index a8a3a7ba..52076bc3 100644 --- a/engine/foundation/osal/thread/thread.cpp +++ b/engine/foundation/osal/thread/thread.cpp @@ -65,8 +65,10 @@ bool Thread::CreateThread(const std::function& func) pthread_attr_t attr; pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); +#ifdef MEDIA_OHOS pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED); pthread_attr_setschedpolicy(&attr, SCHED_RR); +#endif struct sched_param sched = {static_cast(priority_)}; pthread_attr_setschedparam(&attr, &sched); #if defined(THREAD_STACK_SIZE) and THREAD_STACK_SIZE > 0 -- Gitee From 859a077e399621657efa20fb571f36fbdb4f5b6b Mon Sep 17 00:00:00 2001 From: ancimoon Date: Thu, 4 Nov 2021 08:50:28 +0000 Subject: [PATCH 06/22] !108 restrict inCaps of audio sink plugin must contains sample format Signed-off-by: Hu Chang --- .../audio_decoder/audio_decoder_filter.cpp | 2 +- .../sink/audio_sink/audio_sink_filter.cpp | 7 + .../plugins/hdi_adapter/sink/hos_au_sink.cpp | 176 ++++++++++++------ .../plugins/hdi_adapter/sink/hos_au_sink.h | 4 +- .../hdi_adapter/utils/hdi_au_utils.cpp | 41 ++++ .../plugins/hdi_adapter/utils/hdi_au_utils.h | 3 + .../sdl/audio_sink/sdl_audio_sink_plugin.cpp | 6 + 7 files changed, 177 insertions(+), 62 deletions(-) diff --git a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp index 989ad4d7..453d7364 100644 --- a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp +++ b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp @@ -217,7 +217,7 @@ bool AudioDecoderFilter::Negotiate(const std::string& inPort, auto candidatePlugins = FindAvailablePlugins(*upstreamCap, Plugin::PluginType::CODEC); for (const auto& candidate : candidatePlugins) { if (candidate.first->outCaps.empty()) { - MEDIA_LOG_W("decoder plugin must have out caps"); + MEDIA_LOG_E("decoder plugin must have out caps"); } for (const auto& outCap : candidate.first->outCaps) { // each codec plugin should have at least one out cap auto thisOut = std::make_shared(); diff --git a/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp b/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp index a495f0c3..44db53f8 100644 --- a/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp +++ b/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp @@ -90,6 +90,13 @@ bool AudioSinkFilter::Negotiate(const std::string& inPort, const std::shared_ptr } // always use first one std::shared_ptr selectedPluginInfo = candidatePlugins[0].first; + for (const auto& onCap : selectedPluginInfo->inCaps) { + if (onCap.keys.count(CapabilityID::AUDIO_SAMPLE_FORMAT) == 0) { + MEDIA_LOG_E("each in caps of sink must contains valid audio sample format"); + return false; + } + } + upstreamNegotiatedCap = candidatePlugins[0].second; // try to reuse plugin diff --git a/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp b/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp index e6366d43..b1705a93 100644 --- a/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp +++ b/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp @@ -39,6 +39,7 @@ constexpr int32_t RANK100 = 100; constexpr int32_t HALF = 2; constexpr int32_t SEC_TO_MILLS = 1000; constexpr int32_t PCM_CHAN_CNT = 2; +static std::map> g_sinkInfos; Status LoadAndInitAdapter(AudioManager* proxyManager, AudioAdapterDescriptor* descriptor, AudioAdapter** adapter) { @@ -78,11 +79,83 @@ Status LoadAndInitAdapter(AudioManager* proxyManager, AudioAdapterDescriptor* de return Status::OK; } -std::shared_ptr AudioSinkPluginCreator(const std::string& name) +void UpdatePluginCapWithPortCap(const AudioPortCapability& portCap, Capability& pluginCap) +{ + for(size_t cnt = 0; cnt < portCap.formatNum; cnt++) { + auto pluginCaps = OHOS::Media::HosLitePlugin::HdiAuFormat2PluginFormat(portCap.formats[cnt]); + if (pluginCaps.empty()) { + continue; + } + if (pluginCaps.size() == 1) { + pluginCap.AppendFixedKey(Capability::Key::AUDIO_SAMPLE_FORMAT, pluginCaps[0]); + } else { + pluginCap.AppendDiscreteKeys(Capability::Key::AUDIO_SAMPLE_FORMAT, pluginCaps); + } + } + auto pluginSampleRates = OHOS::Media::HosLitePlugin::HdiSampleRatesMask2PluginRates(portCap.sampleRateMasks); + if (!pluginSampleRates.empty()) { + if (pluginSampleRates.size() == 1) { + pluginCap.AppendFixedKey(Capability::Key::AUDIO_SAMPLE_RATE, pluginSampleRates[0]); + } else { + pluginCap.AppendDiscreteKeys(Capability::Key::AUDIO_SAMPLE_RATE, pluginSampleRates); + } + } + AudioChannelLayout pluginLayout; + if (OHOS::Media::HosLitePlugin::HdiMask2PluginChannelLayout(portCap.channelMasks, pluginLayout)) { + pluginCap.AppendFixedKey(Capability::Key::AUDIO_CHANNEL_LAYOUT, pluginLayout); + } + if (portCap.channelCount > 0) { + pluginCap.AppendIntervalKey(Capability::Key::AUDIO_CHANNELS, 1, portCap.channelCount); + } +} + +std::shared_ptr AudioSinkPluginCreator(const std::string &name) { return std::make_shared(name); } +void RegisterOutportOnAdapter(const std::shared_ptr& reg, const AudioAdapterDescriptor& desc, + AudioAdapter* adapter) +{ + CapabilitySet adapterCapabilities; + bool usingDefaultCaps = false; + uint32_t pIndex = 0; + for (uint32_t portIndex = 0; portIndex < desc.portNum; portIndex++) { + if (desc.ports[portIndex].dir != PORT_OUT) { + continue; + } + Capability capability(OHOS::Media::MEDIA_MIME_AUDIO_RAW); + AudioPortCapability portCap{0}; + if (adapter->GetPortCapability != nullptr && + adapter->GetPortCapability(adapter, &desc.ports[portIndex], &portCap) == 0) { + UpdatePluginCapWithPortCap(portCap, capability); + usingDefaultCaps = false; + } else { + MEDIA_LOG_W("query port capability failed when registering plugin, set audio sample format as S16/S16P"); + capability.AppendDiscreteKeys(Capability::Key::AUDIO_SAMPLE_FORMAT, + {AudioSampleFormat::S16, AudioSampleFormat::S16P}); + usingDefaultCaps = true; + } + adapterCapabilities.emplace_back(capability); + pIndex = portIndex; + break; // only take the first out port + } + if (adapterCapabilities.empty()) { + return; + } + AudioSinkPluginDef sinkPluginDef; + sinkPluginDef.creator = AudioSinkPluginCreator; + sinkPluginDef.name = desc.adapterName; + sinkPluginDef.inCaps = adapterCapabilities; + sinkPluginDef.rank = RANK100; + if (reg->AddPlugin(sinkPluginDef) == Status::OK) { + g_sinkInfos[sinkPluginDef.name] = std::make_pair(pIndex, usingDefaultCaps); + MEDIA_LOG_D("register plugin %s succ.", desc.adapterName); + } else { + MEDIA_LOG_W("register plugin %s failed", desc.adapterName); + } +} + Status RegisterHdiSinkPlugins(const std::shared_ptr& reg) { auto proxyManager = GetAudioManagerFuncs(); @@ -103,33 +176,17 @@ Status RegisterHdiSinkPlugins(const std::shared_ptr& reg) if (LoadAndInitAdapter(proxyManager, &descriptors[index], &adapter) != Status::OK) { continue; } - CapabilitySet adapterCapabilities; - for (uint32_t portIndex = 0; portIndex < desc.portNum; portIndex++) { - if (desc.ports[portIndex].dir != PORT_OUT) { - continue; - } - Capability capability(OHOS::Media::MEDIA_MIME_AUDIO_RAW); - adapterCapabilities.emplace_back(capability); - break; - } - if (adapterCapabilities.empty()) { - continue; - } - AudioSinkPluginDef sinkPluginDef; - sinkPluginDef.creator = AudioSinkPluginCreator; - sinkPluginDef.name = desc.adapterName; - sinkPluginDef.inCaps = adapterCapabilities; - sinkPluginDef.rank = RANK100; + RegisterOutportOnAdapter(reg, desc, adapter); proxyManager->UnloadAdapter(proxyManager, adapter); - if (reg->AddPlugin(sinkPluginDef) == Status::OK) { - MEDIA_LOG_D("register plugin %s succ.", desc.adapterName); - } else { - MEDIA_LOG_W("register plugin %s failed", desc.adapterName); - } } return Status::OK; } +void UnRegisterAudioDecoderPlugin() +{ + g_sinkInfos.clear(); +} + template inline Status AssignIfCastSuccess(T& lvalue, const Any& anyValue, const char* tagName) { @@ -148,7 +205,7 @@ int32_t CalculateBufferSize(const AudioSampleAttributes& attributes) return attributes.frameSize * attributes.period; } -PLUGIN_DEFINITION(HdiAuSink, LicenseType::APACHE_V2, RegisterHdiSinkPlugins, []() {}); +PLUGIN_DEFINITION(HdiAuSink, LicenseType::APACHE_V2, RegisterHdiSinkPlugins, UnRegisterAudioDecoderPlugin); } // namespace namespace OHOS { namespace Media { @@ -165,6 +222,9 @@ HdiSink::HdiSink(std::string name) { // default is media sampleAttributes_.type = AUDIO_IN_MEDIA; + if (g_sinkInfos.count(pluginName_) != 0) { + usingDefaultInCaps_ = g_sinkInfos[pluginName_].second; + } } Status HdiSink::Init() @@ -187,11 +247,11 @@ Status HdiSink::Init() if (pluginName_ != desc.adapterName) { continue; } - if (LoadAndInitAdapter(audioManager_, &descriptors[index], &audioAdapter_) != Status::OK) { continue; } adapterDescriptor_ = descriptors[index]; + break; } if (audioAdapter_ == nullptr) { MEDIA_LOG_E("cannot find adapter with name %s", pluginName_.c_str()); @@ -235,6 +295,31 @@ Status HdiSink::Deinit() return Status::OK; } +Status HdiSink::ProcessInputSampleFormat(const ValueType& value) +{ + AudioSampleFormat format; + auto ret = AssignIfCastSuccess(format, value, "audioSampleFormat"); + if (ret != Status::OK) { + return ret; + } + if (PluginAuFormat2HdiAttrs(format, sampleAttributes_)) { + // if using default in caps e.g. S16/S16P always pass non-interleaved pcm data to hdi + // otherwise using the specified format + if (usingDefaultInCaps_) { + if (sampleAttributes_.interleaved) { + isInputInterleaved_ = true; + sampleAttributes_.interleaved = false; + } else { + isInputInterleaved_ = false; + } + } + return Status::OK; + } else { + MEDIA_LOG_E("audioSampleFormat mismatch"); + return Status::ERROR_MISMATCHED_TYPE; + } +} + Status HdiSink::SetParameter(Tag tag, const ValueType& value) { switch (tag) { @@ -242,26 +327,8 @@ Status HdiSink::SetParameter(Tag tag, const ValueType& value) return AssignIfCastSuccess(sampleAttributes_.channelCount, value, "channel"); case Tag::AUDIO_SAMPLE_RATE: return AssignIfCastSuccess(sampleAttributes_.sampleRate, value, "sampleRate"); - case Tag::AUDIO_SAMPLE_FORMAT: { - AudioSampleFormat format; - auto ret = AssignIfCastSuccess(format, value, "audioSampleFormat"); - if (ret != Status::OK) { - return ret; - } - if (PluginAuFormat2HdiAttrs(format, sampleAttributes_)) { - // always configure hdi with non-interleaved - if (sampleAttributes_.interleaved) { - isInputInterleaved_ = true; - sampleAttributes_.interleaved = false; - } else { - isInputInterleaved_ = false; - } - return Status::OK; - } else { - MEDIA_LOG_E("audioSampleFormat mismatch"); - return Status::ERROR_MISMATCHED_TYPE; - } - } + case Tag::AUDIO_SAMPLE_FORMAT: + return ProcessInputSampleFormat(value); case Tag::AUDIO_SAMPLE_PER_FRAME: return AssignIfCastSuccess(sampleAttributes_.period, value, "samples per frame"); case Tag::AUDIO_CHANNEL_LAYOUT: { @@ -295,20 +362,11 @@ Status HdiSink::Prepare() sampleAttributes_.frameSize = GetPcmBytes(sampleAttributes_.format) * sampleAttributes_.channelCount; sampleAttributes_.startThreshold = sampleAttributes_.period / sampleAttributes_.frameSize; sampleAttributes_.stopThreshold = INT32_MAX; - bool foundPort = false; - for (uint32_t portIndex = 0; portIndex < adapterDescriptor_.portNum; portIndex++) { - if (adapterDescriptor_.ports[portIndex].dir == PORT_OUT) { - audioPort_ = adapterDescriptor_.ports[portIndex]; - foundPort = true; - break; - } - } - if (!foundPort) { + if (g_sinkInfos.count(pluginName_) == 0) { MEDIA_LOG_E("cannot find out port"); return Status::ERROR_UNKNOWN; } - - deviceDescriptor_.portId = audioPort_.portId; + deviceDescriptor_.portId = g_sinkInfos[pluginName_].first; deviceDescriptor_.pins = PIN_OUT_SPEAKER; deviceDescriptor_.desc = nullptr; @@ -318,7 +376,6 @@ Status HdiSink::Prepare() (sampleAttributes_.type == AUDIO_IN_MEDIA) ? "media" : "communication", sampleAttributes_.channelCount, sampleAttributes_.sampleRate, channelMask_, sampleAttributes_.format, sampleAttributes_.isSignedData, sampleAttributes_.interleaved, sampleAttributes_.period, sampleAttributes_.frameSize); - { OHOS::Media::OSAL::ScopedLock lock(renderMutex_); auto ret = audioAdapter_->CreateRender(audioAdapter_, &deviceDescriptor_, &sampleAttributes_, &audioRender_); @@ -329,7 +386,7 @@ Status HdiSink::Prepare() } } MEDIA_LOG_I("create audio render successfully"); - if ((sampleAttributes_.channelCount == PCM_CHAN_CNT) && isInputInterleaved_) { + if (sampleAttributes_.channelCount == PCM_CHAN_CNT && usingDefaultInCaps_ && isInputInterleaved_) { cacheData_.resize(CalculateBufferSize(sampleAttributes_)); } return Status::OK; @@ -339,7 +396,6 @@ Status HdiSink::Reset() { MEDIA_LOG_D("Reset entered."); ReleaseRender(); - (void)memset_s(&audioPort_, sizeof(audioPort_), 0, sizeof(audioPort_)); (void)memset_s(&sampleAttributes_, sizeof(sampleAttributes_), 0, sizeof(sampleAttributes_)); (void)memset_s(&deviceDescriptor_, sizeof(deviceDescriptor_), 0, sizeof(deviceDescriptor_)); isInputInterleaved_ = false; @@ -628,7 +684,7 @@ void HdiSink::Deinterleave32(uint8_t* inData, uint8_t* outData, int32_t frameCnt bool HdiSink::HandleInterleaveData(uint8_t* origData, int32_t frameCnt) { - if ((sampleAttributes_.channelCount != PCM_CHAN_CNT) || !isInputInterleaved_) { + if (sampleAttributes_.channelCount != PCM_CHAN_CNT || !usingDefaultInCaps_ || !isInputInterleaved_) { return false; } bool isHandled = true; diff --git a/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.h b/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.h index 87981e2b..f5cdcd9e 100644 --- a/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.h +++ b/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.h @@ -102,6 +102,8 @@ private: void DoRender(); + Media::Plugin::Status ProcessInputSampleFormat(const Media::Plugin::ValueType& value); + private: OHOS::Media::OSAL::Mutex renderMutex_ {}; @@ -111,7 +113,6 @@ private: AudioAdapterDescriptor adapterDescriptor_ {}; AudioAdapter* audioAdapter_ {nullptr}; AudioRender* audioRender_ {nullptr}; - AudioPort audioPort_ {}; AudioDeviceDescriptor deviceDescriptor_ {}; AudioSampleAttributes sampleAttributes_ {}; bool isInputInterleaved_{false}; @@ -123,6 +124,7 @@ private: BlockingQueue> bufferQueue_; std::shared_ptr currBuffer_; size_t currBufferOffset_; + bool usingDefaultInCaps_ {true}; // if true pass hdi with S16P pcm data and convert input into non-interleaved }; } } diff --git a/engine/plugin/plugins/hdi_adapter/utils/hdi_au_utils.cpp b/engine/plugin/plugins/hdi_adapter/utils/hdi_au_utils.cpp index b0f511cc..6dd754a0 100644 --- a/engine/plugin/plugins/hdi_adapter/utils/hdi_au_utils.cpp +++ b/engine/plugin/plugins/hdi_adapter/utils/hdi_au_utils.cpp @@ -81,6 +81,35 @@ bool PluginAuFormat2HdiAttrs(OHOS::Media::Plugin::AudioSampleFormat pFormat, Aud return false; } +std::vector HdiAuFormat2PluginFormat(AudioFormat audioFormat) +{ + std::vector ret; + switch (audioFormat) { + case AUDIO_FORMAT_PCM_8_BIT: + ret.emplace_back(OHOS::Media::Plugin::AudioSampleFormat::U8); + ret.emplace_back(OHOS::Media::Plugin::AudioSampleFormat::U8P); + ret.emplace_back(OHOS::Media::Plugin::AudioSampleFormat::S8); + ret.emplace_back(OHOS::Media::Plugin::AudioSampleFormat::S8P); + break; + case AUDIO_FORMAT_PCM_16_BIT: + ret.emplace_back(OHOS::Media::Plugin::AudioSampleFormat::U16); + ret.emplace_back(OHOS::Media::Plugin::AudioSampleFormat::U16P); + ret.emplace_back(OHOS::Media::Plugin::AudioSampleFormat::S16); + ret.emplace_back(OHOS::Media::Plugin::AudioSampleFormat::S16P); + break; + case AUDIO_FORMAT_PCM_32_BIT: + ret.emplace_back(OHOS::Media::Plugin::AudioSampleFormat::U32); + ret.emplace_back(OHOS::Media::Plugin::AudioSampleFormat::U32P); + ret.emplace_back(OHOS::Media::Plugin::AudioSampleFormat::S32); + ret.emplace_back(OHOS::Media::Plugin::AudioSampleFormat::S32P); + break; + default: + // do nothing + break; + } + return ret; +} + bool HdiAttrs2PluginAuFormat(AudioSampleAttributes attrs, OHOS::Media::Plugin::AudioSampleFormat& pFormat) { for (const auto& item : g_phft) { @@ -104,6 +133,18 @@ bool PluginSampleRate2HdiRate(uint32_t pRate, AudioSampleRatesMask& mask) mask = AUDIO_SAMPLE_RATE_MASK_INVALID; return false; } + +std::vector HdiSampleRatesMask2PluginRates(uint32_t mask) +{ + std::vector ret; + for (const auto& pairKey : g_phst) { + if ((static_cast(pairKey.second) & mask) != 0) { + ret.emplace_back(pairKey.first); + } + } + return ret; +} + bool HdiRate2PluginSampleRate(AudioSampleRatesMask mask, uint32_t& pRate) { for (const auto& item : g_phst) { diff --git a/engine/plugin/plugins/hdi_adapter/utils/hdi_au_utils.h b/engine/plugin/plugins/hdi_adapter/utils/hdi_au_utils.h index 7eee2b77..f32324aa 100644 --- a/engine/plugin/plugins/hdi_adapter/utils/hdi_au_utils.h +++ b/engine/plugin/plugins/hdi_adapter/utils/hdi_au_utils.h @@ -16,6 +16,7 @@ #ifndef HISTREAMER_HDI_ADAPTER_AU_UTILS_H #define HISTREAMER_HDI_ADAPTER_AU_UTILS_H +#include #include "audio_types.h" #include "plugin/common/plugin_audio_tags.h" @@ -23,9 +24,11 @@ namespace OHOS { namespace Media { namespace HosLitePlugin { bool PluginAuFormat2HdiAttrs(OHOS::Media::Plugin::AudioSampleFormat pFormat, AudioSampleAttributes& attrs); +std::vector HdiAuFormat2PluginFormat(AudioFormat audioFormat); bool HdiAttrs2PluginAuFormat(AudioSampleAttributes attrs, OHOS::Media::Plugin::AudioSampleFormat& pFormat); bool PluginSampleRate2HdiRate(uint32_t pRate, AudioSampleRatesMask& mask); +std::vector HdiSampleRatesMask2PluginRates(uint32_t mask); bool HdiRate2PluginSampleRate(AudioSampleRatesMask mask, uint32_t& pRate); bool PluginChannelLayout2HdiMask(OHOS::Media::Plugin::AudioChannelLayout layout, AudioChannelMask& mask); diff --git a/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp b/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp index cfbb5d50..82a7fef5 100644 --- a/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp +++ b/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp @@ -90,6 +90,12 @@ const Status SdlAudioRegister(const std::shared_ptr& reg) definition.name = "sdl_audio_sink"; definition.rank = 100; // 100 Capability cap(OHOS::Media::MEDIA_MIME_AUDIO_RAW); + cap.AppendDiscreteKeys(Capability::Key::AUDIO_SAMPLE_FORMAT, { + AudioSampleFormat::U8, AudioSampleFormat::U8P, AudioSampleFormat::S8, AudioSampleFormat::S8P, + AudioSampleFormat::U16, AudioSampleFormat::U16P, AudioSampleFormat::S16, AudioSampleFormat::S16P, + AudioSampleFormat::U32, AudioSampleFormat::U32P, AudioSampleFormat::S32, AudioSampleFormat::S32P, + AudioSampleFormat::F32, AudioSampleFormat::F32P, AudioSampleFormat::F64, AudioSampleFormat::F64P + }); definition.inCaps.emplace_back(cap); definition.creator = AudioSinkPluginCreator; return reg->AddPlugin(definition); -- Gitee From b64d0df482417646d30ab9b16f4d7737b8aa6997 Mon Sep 17 00:00:00 2001 From: leo_ysl <9693773+leo_ysl@user.noreply.gitee.com> Date: Thu, 4 Nov 2021 09:00:05 +0000 Subject: [PATCH 07/22] !109 make sure starting task successfully in case of pthread_cond_signal failure. Signed-off-by: Li Yong --- engine/foundation/osal/thread/condition_variable.cpp | 10 ++++++++-- engine/foundation/osal/thread/task.cpp | 5 +++-- engine/foundation/osal/thread/task.h | 1 - 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/engine/foundation/osal/thread/condition_variable.cpp b/engine/foundation/osal/thread/condition_variable.cpp index 13f1c7a1..313cc32f 100644 --- a/engine/foundation/osal/thread/condition_variable.cpp +++ b/engine/foundation/osal/thread/condition_variable.cpp @@ -53,12 +53,18 @@ ConditionVariable::~ConditionVariable() noexcept void ConditionVariable::NotifyOne() noexcept { - pthread_cond_signal(&cond_); + int ret = pthread_cond_signal(&cond_); + if (ret != 0) { + MEDIA_LOG_E("NotifyOne failed with errno = %d", ret); + } } void ConditionVariable::NotifyAll() noexcept { - pthread_cond_broadcast(&cond_); + int ret = pthread_cond_broadcast(&cond_); + if (ret != 0) { + MEDIA_LOG_E("NotifyAll failed with errno = %d", ret); + } } void ConditionVariable::Wait(ScopedLock& lock) noexcept diff --git a/engine/foundation/osal/thread/task.cpp b/engine/foundation/osal/thread/task.cpp index 5424de1f..1dceabca 100644 --- a/engine/foundation/osal/thread/task.cpp +++ b/engine/foundation/osal/thread/task.cpp @@ -127,10 +127,11 @@ void Task::Run() MEDIA_LOG_D("task %s stopped, exit task", name_.c_str()); break; } + OSAL::ScopedLock lock(stateMutex_); if (runningState_.load() == RunningState::PAUSED) { - OSAL::ScopedLock lock(cvMutex_); pauseDone_ = true; - cv_.Wait(lock, [this] { return runningState_.load() != RunningState::PAUSED; }); + constexpr int timeoutMs = 500; + cv_.WaitFor(lock, timeoutMs, [this] { return runningState_.load() != RunningState::PAUSED; }); } } } diff --git a/engine/foundation/osal/thread/task.h b/engine/foundation/osal/thread/task.h index 98f5ea3d..cbb3e716 100644 --- a/engine/foundation/osal/thread/task.h +++ b/engine/foundation/osal/thread/task.h @@ -66,7 +66,6 @@ private: OSAL::Thread loop_; OSAL::Mutex stateMutex_{}; - OSAL::Mutex cvMutex_{}; OSAL::ConditionVariable cv_{}; std::atomic pauseDone_{}; std::atomic workInProgress_{}; -- Gitee From e382ab9fe5b971bf30a27db81c7ce09896d7f04c Mon Sep 17 00:00:00 2001 From: ancimoon Date: Fri, 5 Nov 2021 02:43:37 +0000 Subject: [PATCH 08/22] !110 rm deps on audio proxy manager Signed-off-by: Hu Chang --- engine/plugin/plugins/hdi_adapter/BUILD.gn | 1 - .../plugins/hdi_adapter/sink/hos_au_sink.cpp | 20 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/engine/plugin/plugins/hdi_adapter/BUILD.gn b/engine/plugin/plugins/hdi_adapter/BUILD.gn index 14c1acba..13ac054e 100644 --- a/engine/plugin/plugins/hdi_adapter/BUILD.gn +++ b/engine/plugin/plugins/hdi_adapter/BUILD.gn @@ -31,7 +31,6 @@ if (defined(ohos_lite)) { config("plugin_hdi_adapter_config") { include_dirs = [ "//drivers/peripheral/audio/interfaces/include", - "//drivers/peripheral/audio/hal/hdi_binder/proxy/include", ] ldflags = [ "-lhdi_videodisplayer" ] } diff --git a/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp b/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp index b1705a93..cd8f30cc 100644 --- a/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp +++ b/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp @@ -19,7 +19,7 @@ #include #include #include "audio_adapter.h" -#include "audio_proxy_manager.h" +#include "audio_manager.h" #include "foundation/log.h" #include "foundation/osal/thread/scoped_lock.h" #include "foundation/osal/utils/util.h" @@ -41,9 +41,9 @@ constexpr int32_t SEC_TO_MILLS = 1000; constexpr int32_t PCM_CHAN_CNT = 2; static std::map> g_sinkInfos; -Status LoadAndInitAdapter(AudioManager* proxyManager, AudioAdapterDescriptor* descriptor, AudioAdapter** adapter) +Status LoadAndInitAdapter(AudioManager* audioManager, AudioAdapterDescriptor* descriptor, AudioAdapter** adapter) { - if (proxyManager == nullptr) { + if (audioManager == nullptr) { MEDIA_LOG_E("no audio manager when load adapter"); return Status::ERROR_UNKNOWN; } @@ -51,7 +51,7 @@ Status LoadAndInitAdapter(AudioManager* proxyManager, AudioAdapterDescriptor* de MEDIA_LOG_E("**adapter null ptr"); return Status::ERROR_INVALID_PARAMETER; } - if (proxyManager->LoadAdapter(proxyManager, descriptor, adapter) < 0) { + if (audioManager->LoadAdapter(audioManager, descriptor, adapter) < 0) { *adapter = nullptr; MEDIA_LOG_W("failed to load adapter %s", descriptor->adapterName); return Status::ERROR_UNSUPPORTED_FORMAT; @@ -72,7 +72,7 @@ Status LoadAndInitAdapter(AudioManager* proxyManager, AudioAdapterDescriptor* de } while (++retryCnt < MAX_RETRY_CNT); if (retryCnt >= MAX_RETRY_CNT) { MEDIA_LOG_W("cannot init port on adapter %s after retry %d times", descriptor->adapterName, retryCnt); - proxyManager->UnloadAdapter(proxyManager, *adapter); + audioManager->UnloadAdapter(audioManager, *adapter); *adapter = nullptr; return Status::ERROR_UNKNOWN; } @@ -158,14 +158,14 @@ void RegisterOutportOnAdapter(const std::shared_ptr& reg, const AudioA Status RegisterHdiSinkPlugins(const std::shared_ptr& reg) { - auto proxyManager = GetAudioManagerFuncs(); - if (proxyManager == nullptr) { + auto audioManager = GetAudioManagerFuncs(); + if (audioManager == nullptr) { MEDIA_LOG_E("cannot find audio manager funcs"); return Status::ERROR_UNKNOWN; } int32_t adapterSize = 0; AudioAdapterDescriptor* descriptors = nullptr; - int32_t ret = proxyManager->GetAllAdapters(proxyManager, &descriptors, &adapterSize); + int32_t ret = audioManager->GetAllAdapters(audioManager, &descriptors, &adapterSize); if (ret != 0 || adapterSize == 0) { MEDIA_LOG_E("cannot find available audio adapter"); return Status::OK; @@ -173,11 +173,11 @@ Status RegisterHdiSinkPlugins(const std::shared_ptr& reg) for (int32_t index = 0; index < adapterSize; index++) { AudioAdapter* adapter = nullptr; const auto& desc = descriptors[index]; - if (LoadAndInitAdapter(proxyManager, &descriptors[index], &adapter) != Status::OK) { + if (LoadAndInitAdapter(audioManager, &descriptors[index], &adapter) != Status::OK) { continue; } RegisterOutportOnAdapter(reg, desc, adapter); - proxyManager->UnloadAdapter(proxyManager, adapter); + audioManager->UnloadAdapter(audioManager, adapter); } return Status::OK; } -- Gitee From d3bbdb3d2b2d4ded567b9aa95188c491246c7c62 Mon Sep 17 00:00:00 2001 From: shihaojun Date: Mon, 8 Nov 2021 09:26:10 +0000 Subject: [PATCH 09/22] !111 modify plugin interface description Signed-off-by: Shihaojun --- engine/plugin/common/plugin_tags.h | 60 ++++++++++----------- engine/plugin/interface/audio_sink_plugin.h | 13 ----- engine/plugin/interface/codec_plugin.h | 4 -- engine/plugin/interface/demuxer_plugin.h | 7 --- engine/plugin/interface/plugin_base.h | 11 +--- engine/plugin/interface/source_plugin.h | 5 -- engine/plugin/interface/video_sink_plugin.h | 4 -- 7 files changed, 32 insertions(+), 72 deletions(-) diff --git a/engine/plugin/common/plugin_tags.h b/engine/plugin/common/plugin_tags.h index 1fce3eff..e8f8c8d1 100644 --- a/engine/plugin/common/plugin_tags.h +++ b/engine/plugin/common/plugin_tags.h @@ -77,51 +77,51 @@ enum struct Tag : uint32_t { /* -------------------- regular tag -------------------- */ MIME = SECTION_REGULAR_START + 1, // string - TRACK_ID, // uint32_t - REQUIRED_OUT_BUFFER_CNT, // uint32_t required buffer count of plugin; read only tag - PARAMETER_STRUCT, // ParameterStruct + TRACK_ID, ///< uint32_t, track id + REQUIRED_OUT_BUFFER_CNT, ///< uint32_t required buffer count of plugin; read only tag + PARAMETER_STRUCT, ///< @see ParameterStruct /* -------------------- media tag -------------------- */ MEDIA_TITLE = SECTION_MEDIA_START + 1, // string - MEDIA_ARTIST, // string - MEDIA_LYRICIST, // string - MEDIA_ALBUM, // string - MEDIA_ALBUM_ARTIST, // string - MEDIA_DATE, // string, format:YYYY-MM-DD - MEDIA_COMMENT, // string - MEDIA_GENRE, // string - MEDIA_COPYRIGHT, // string - MEDIA_LANGUAGE, // string - MEDIA_DESCRIPTION, // string - MEDIA_LYRICS, // string - MEDIA_DURATION, // uint64_t - MEDIA_FILE_SIZE, // uint64_t - MEDIA_BITRATE, // int64_t - MEDIA_FILE_EXTENSION, // string - MEDIA_CODEC_CONFIG, // vector, e.g. AudioSpecificConfig for mp4 + MEDIA_ARTIST, ///< string, artist + MEDIA_LYRICIST, ///< string, lyricist + MEDIA_ALBUM, ///< string, album + MEDIA_ALBUM_ARTIST, ///< string, album artist + MEDIA_DATE, ///< string, media date, format:YYYY-MM-DD + MEDIA_COMMENT, ///< string, comment + MEDIA_GENRE, ///< string, genre + MEDIA_COPYRIGHT, ///< string, copyright + MEDIA_LANGUAGE, ///< string, language + MEDIA_DESCRIPTION, ///< string, description + MEDIA_LYRICS, ///< string, cyrics + MEDIA_DURATION, ///< uint64_t, duration + MEDIA_FILE_SIZE, ///< uint64_t, file size + MEDIA_BITRATE, ///< int64_t, bite rate + MEDIA_FILE_EXTENSION, ///< string, file extension + MEDIA_CODEC_CONFIG, ///< vector, codec config. e.g. AudioSpecificConfig for mp4 MEDIA_POSITION, ///< uint64_t : The byte position within media stream/file /* -------------------- audio universal tag -------------------- */ AUDIO_CHANNELS = SECTION_AUDIO_UNIVERSAL_START + 1, // uint32_t - AUDIO_CHANNEL_LAYOUT, // AudioChannelLayout - AUDIO_SAMPLE_RATE, // uint32_t - AUDIO_SAMPLE_FORMAT, // AudioSampleFormat - AUDIO_SAMPLE_PER_FRAME, // uint32_t + AUDIO_CHANNEL_LAYOUT, ///< @see AudioChannelLayout + AUDIO_SAMPLE_RATE, ///< uint32_t, sample rate + AUDIO_SAMPLE_FORMAT, ///< @see AudioSampleFormat + AUDIO_SAMPLE_PER_FRAME, ///< uint32_t, sample per frame /* -------------------- audio specific tag -------------------- */ AUDIO_SPECIFIC_MPEG_START = MAKE_AUDIO_SPECIFIC_START(AudioFormat::MPEG), - AUDIO_MPEG_VERSION, // uint32_t - AUDIO_MPEG_LAYER, // uint32_t + AUDIO_MPEG_VERSION, ///< uint32_t, mpeg version + AUDIO_MPEG_LAYER, ///< uint32_t, mpeg layer AUDIO_SPECIFIC_AAC_START = MAKE_AUDIO_SPECIFIC_START(AudioFormat::AAC), - AUDIO_AAC_PROFILE, // AudioAacProfile - AUDIO_AAC_LEVEL, // uint32_t - AUDIO_AAC_STREAM_FORMAT, // AudioAacStreamFormat + AUDIO_AAC_PROFILE, ///< @see AudioAacProfile + AUDIO_AAC_LEVEL, ///< uint32_t, acc level + AUDIO_AAC_STREAM_FORMAT, ///< @see AudioAacStreamFormat /* -------------------- video universal tag -------------------- */ VIDEO_WIDTH = SECTION_VIDEO_UNIVERSAL_START + 1, // uint32_t - VIDEO_HEIGHT, // uint32_t - VIDEO_PIXEL_FORMAT, // uint32_t + VIDEO_HEIGHT, ///< uint32_t, video height + VIDEO_PIXEL_FORMAT, ///< uint32_t, video pixel format }; using ValueType = Any; diff --git a/engine/plugin/interface/audio_sink_plugin.h b/engine/plugin/interface/audio_sink_plugin.h index fc58a01c..ea4e6d22 100644 --- a/engine/plugin/interface/audio_sink_plugin.h +++ b/engine/plugin/interface/audio_sink_plugin.h @@ -44,7 +44,6 @@ struct AudioSinkPlugin : public PluginBase { * Value true means that the audio is muted, and false means the opposite. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status GetMute(bool& mute) = 0; @@ -57,7 +56,6 @@ struct AudioSinkPlugin : public PluginBase { * Value true means that the audio is muted, and false means the opposite. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status SetMute(bool mute) = 0; @@ -69,7 +67,6 @@ struct AudioSinkPlugin : public PluginBase { * @param volume Indicates the volume to set. The value ranges from 0.0 to 1.0. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status GetVolume(float& volume) = 0; @@ -81,7 +78,6 @@ struct AudioSinkPlugin : public PluginBase { * @param volume Indicates the volume to set. The value ranges from 0.0 to 1.0. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. * @retval ERROR_INVALID_DATA: The value is not in the valid range. */ virtual Status SetVolume(float volume) = 0; @@ -94,7 +90,6 @@ struct AudioSinkPlugin : public PluginBase { * @param speed Indicates the pointer to the current rendering speed to obtain. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status GetSpeed(float& speed) = 0; @@ -106,7 +101,6 @@ struct AudioSinkPlugin : public PluginBase { * @param speed speed Indicates the pointer to the current rendering speed to obtain. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. * @retval ERROR_INVALID_DATA: The value is not in the valid range. */ virtual Status SetSpeed(float speed) = 0; @@ -119,7 +113,6 @@ struct AudioSinkPlugin : public PluginBase { * * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status Pause() = 0; @@ -131,7 +124,6 @@ struct AudioSinkPlugin : public PluginBase { * * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status Resume() = 0; @@ -143,7 +135,6 @@ struct AudioSinkPlugin : public PluginBase { * @param ms Indicates the pointer to the latency (in milliseconds) to be obtained. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status GetLatency(uint64_t& ms) = 0; @@ -155,7 +146,6 @@ struct AudioSinkPlugin : public PluginBase { * @param size size Indicates the pointer to the audio frame size (in bytes). * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status GetFrameSize(size_t& size) = 0; @@ -167,7 +157,6 @@ struct AudioSinkPlugin : public PluginBase { * @param count Indicates the pointer to the number of audio frames in the audio buffer. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status GetFrameCount(uint32_t& count) = 0; @@ -179,7 +168,6 @@ struct AudioSinkPlugin : public PluginBase { * @param input Indicates the pointer to the frame to write. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status Write(const std::shared_ptr& input) = 0; @@ -190,7 +178,6 @@ struct AudioSinkPlugin : public PluginBase { * * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status Flush() = 0; }; diff --git a/engine/plugin/interface/codec_plugin.h b/engine/plugin/interface/codec_plugin.h index 617e058b..2aa64005 100644 --- a/engine/plugin/interface/codec_plugin.h +++ b/engine/plugin/interface/codec_plugin.h @@ -74,7 +74,6 @@ struct CodecPlugin : public PluginBase { * @param timeoutMs Indicates the timeout duration. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state * @retval ERROR_INVALID_DATA: The input buffer is invalid. * @retval ERROR_TIMED_OUT: Operation timeout. */ @@ -89,7 +88,6 @@ struct CodecPlugin : public PluginBase { * @param timeoutMs Indicates the timeout duration. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state * @retval ERROR_INVALID_DATA: The output buffer is invalid. * @retval ERROR_TIMED_OUT: Operation timeout. */ @@ -102,7 +100,6 @@ struct CodecPlugin : public PluginBase { * * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state */ virtual Status Flush() = 0; @@ -114,7 +111,6 @@ struct CodecPlugin : public PluginBase { * @param cb Data callback, NULL callback listening is canceled. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status SetDataCallback(const std::weak_ptr& dataCallback) = 0; }; diff --git a/engine/plugin/interface/demuxer_plugin.h b/engine/plugin/interface/demuxer_plugin.h index 777e1eb4..d19bba3d 100644 --- a/engine/plugin/interface/demuxer_plugin.h +++ b/engine/plugin/interface/demuxer_plugin.h @@ -94,7 +94,6 @@ struct DemuxerPlugin : public PluginBase { * @param source Data source where data read from. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state */ virtual Status SetDataSource(const std::shared_ptr& source) = 0; @@ -107,7 +106,6 @@ struct DemuxerPlugin : public PluginBase { * @param mediaInfo Indicates the pointer to the source attributes * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state */ virtual Status GetMediaInfo(MediaInfo& mediaInfo) = 0; @@ -128,7 +126,6 @@ struct DemuxerPlugin : public PluginBase { * @param trackId Identifies the media track. If an invalid value is passed, the default media track specified. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state */ virtual Status SelectTrack(int32_t trackId) = 0; @@ -140,7 +137,6 @@ struct DemuxerPlugin : public PluginBase { * @param trackId Identifies the media track. ignore the invalid value is passed. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state */ virtual Status UnselectTrack(int32_t trackId) = 0; @@ -152,7 +148,6 @@ struct DemuxerPlugin : public PluginBase { * @param trackIds Identifies the array of selected media tracks. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state */ virtual Status GetSelectedTracks(std::vector& trackIds) = 0; @@ -165,7 +160,6 @@ struct DemuxerPlugin : public PluginBase { * @param timeOutMs Indicates the time required for waiting data frame read. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state * @retval ERROR_TIMED_OUT: Operation timeout. */ virtual Status ReadFrame(Buffer& buffer, int32_t timeOutMs) = 0; @@ -182,7 +176,6 @@ struct DemuxerPlugin : public PluginBase { * @param mode Indicates the seek mode. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state * @retval ERROR_INVALID_DATA: The input data is invalid. */ virtual Status SeekTo(int32_t trackId, int64_t timeStampUs, SeekMode mode) = 0; diff --git a/engine/plugin/interface/plugin_base.h b/engine/plugin/interface/plugin_base.h index 41b00cc8..4b6c0a50 100644 --- a/engine/plugin/interface/plugin_base.h +++ b/engine/plugin/interface/plugin_base.h @@ -57,7 +57,8 @@ struct Callback { * @brief Base class of a plugin. All plugins of different types inherit this interface. * * @details The base class contains only common operation methods and defines basic operation processes. - * Different operations are valid only in the corresponding states. Some operations also change the plugin status. + * Different operations are valid only in the corresponding states. The timing of calls is guaranteed by + * the plugin framework. Some operations also change the plugin status. * For details, see the description of each function. * * @since 1.0 @@ -89,7 +90,6 @@ struct PluginBase { * @return Execution status return * @retval OK: Plugin initialization succeeded. * @retval ERROR_NO_MEMORY: Memory allocation or external resource loading error caused by insufficient memory. - * @retval ERROR_WRONG_STATE: Call this function in non CREATED state */ virtual Status Init() { @@ -119,7 +119,6 @@ struct PluginBase { * @return Execution status return * @retval OK: Plugin deinitialize succeeded. * @retval ERROR_NO_MEMORY: Memory allocation error caused by insufficient memory. - * @retval ERROR_WRONG_STATE: Call this function in non INITIALIZED state */ virtual Status Prepare() { @@ -134,7 +133,6 @@ struct PluginBase { * * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in wrong state * @retval ERROR_UNIMPLEMENTED: This method is not implemented and cannot respond to reset. */ virtual Status Reset() @@ -151,7 +149,6 @@ struct PluginBase { * * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non PREPARED state */ virtual Status Start() { @@ -166,7 +163,6 @@ struct PluginBase { * * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non RUNNING state */ virtual Status Stop() { @@ -195,7 +191,6 @@ struct PluginBase { * @param value Plugin parameter value. which is described by Any type. Need check the real type in tag. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. * @retval ERROR_INVALID_PARAMETER: The plugin does not support this parameter. */ virtual Status GetParameter(Tag tag, ValueType &value) @@ -212,7 +207,6 @@ struct PluginBase { * @param value Plugin parameter value. which is described by Any type. Need check the real type in tag. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. * @retval ERROR_INVALID_PARAMETER: The plugin does not support this parameter. * @retval ERROR_INVALID_DATA: The value is not in the valid range. * @retval ERROR_MISMATCHED_TYPE: The data type is mismatched. @@ -238,7 +232,6 @@ struct PluginBase { * @param cb Message callback, NULL callback listening is canceled. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status SetCallback(const std::shared_ptr &cb) = 0; diff --git a/engine/plugin/interface/source_plugin.h b/engine/plugin/interface/source_plugin.h index 16de3668..18461976 100644 --- a/engine/plugin/interface/source_plugin.h +++ b/engine/plugin/interface/source_plugin.h @@ -46,7 +46,6 @@ struct SourcePlugin : public PluginBase { * or to read the detailed information required by the data. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state * @retval ERROR_INVALID_DATA: Uri is not supported. */ virtual Status SetSource(std::string& uri, std::shared_ptr> params = nullptr) = 0; @@ -60,7 +59,6 @@ struct SourcePlugin : public PluginBase { * @param expectedLen Expected data size to be read * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state * @retval ERROR_NOT_ENOUGH_DATA: Data not enough * @retval END_OF_STREAM: End of stream */ @@ -74,7 +72,6 @@ struct SourcePlugin : public PluginBase { * @param size data source size. * @return Execution status return. * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state */ virtual Status GetSize(size_t& size) = 0; @@ -85,7 +82,6 @@ struct SourcePlugin : public PluginBase { * * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state */ virtual bool IsSeekable() = 0; @@ -99,7 +95,6 @@ struct SourcePlugin : public PluginBase { * @param offset position to read data frames * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state * @retval ERROR_INVALID_DATA: The offset is invalid. */ virtual Status SeekTo(uint64_t offset) = 0; diff --git a/engine/plugin/interface/video_sink_plugin.h b/engine/plugin/interface/video_sink_plugin.h index 857f5aee..c2d1825a 100644 --- a/engine/plugin/interface/video_sink_plugin.h +++ b/engine/plugin/interface/video_sink_plugin.h @@ -43,7 +43,6 @@ struct VideoSinkPlugin : public PluginBase { * * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status Pause() = 0; @@ -55,7 +54,6 @@ struct VideoSinkPlugin : public PluginBase { * * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status Resume() = 0; @@ -67,7 +65,6 @@ struct VideoSinkPlugin : public PluginBase { * @param input Indicates the pointer to the frame to write. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status Write(const std::shared_ptr& input) = 0; @@ -78,7 +75,6 @@ struct VideoSinkPlugin : public PluginBase { * * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_WRONG_STATE: Call this function in non wrong state. */ virtual Status Flush() = 0; }; -- Gitee From 9eeb08c79b9925fbc14865685e20fa34ebde4932 Mon Sep 17 00:00:00 2001 From: ancimoon Date: Mon, 8 Nov 2021 09:35:49 +0000 Subject: [PATCH 10/22] !112 refactor error code Signed-off-by: Hu Chang --- engine/foundation/error_code.h | 30 +++++-------- engine/pipeline/core/pipeline_core.cpp | 11 +++-- engine/pipeline/core/port.cpp | 13 +++--- engine/pipeline/core/port.h | 3 +- .../audio_decoder/audio_decoder_filter.cpp | 6 +-- .../filters/codec/decoder_filter_base.cpp | 16 +++---- .../video_decoder/video_decoder_filter.cpp | 12 +++--- .../pipeline/filters/common/plugin_utils.cpp | 29 ++++++++++--- engine/pipeline/filters/common/plugin_utils.h | 10 +++-- .../pipeline/filters/demux/demuxer_filter.cpp | 13 +++--- .../sink/audio_sink/audio_sink_filter.cpp | 18 ++++---- .../sink/video_sink/video_sink_filter.cpp | 16 +++---- .../filters/source/media_source_filter.cpp | 16 +++---- engine/player/hiplayer_impl.cpp | 42 +++++++++++-------- engine/player/internal/init_state.h | 2 +- engine/player/internal/pause_state.h | 2 +- engine/player/internal/playing_state.h | 2 +- engine/player/internal/preparing_state.h | 2 +- engine/player/internal/ready_state.h | 2 +- engine/player/internal/state_machine.cpp | 4 +- engine/plugin/common/plugin_types.h | 3 +- engine/plugin/core/plugin_register.cpp | 2 +- engine/plugin/interface/plugin_definition.h | 4 +- engine/plugin/interface/source_plugin.h | 5 ++- .../audio_ffmpeg_decoder_plugin.cpp | 6 +-- .../demuxer/ffmpeg_demuxer_plugin.cpp | 6 +-- .../video_ffmpeg_decoder_plugin.cpp | 4 +- .../sdl/audio_sink/sdl_audio_sink_plugin.cpp | 2 +- .../sdl/video_sink/sdl_video_sink_plugin.cpp | 4 +- .../source/file_source/file_source_plugin.cpp | 10 ++--- .../stream_source/stream_source_plugin.cpp | 6 +-- interface/histreamer/hiplayer.h | 4 ++ tests/ut/TestStateMachine.cpp | 4 +- 33 files changed, 168 insertions(+), 141 deletions(-) diff --git a/engine/foundation/error_code.h b/engine/foundation/error_code.h index ff3e2b73..36171323 100644 --- a/engine/foundation/error_code.h +++ b/engine/foundation/error_code.h @@ -21,26 +21,16 @@ namespace Media { enum struct ErrorCode : int32_t { END_OF_STREAM = 1, SUCCESS = 0, - ERROR_UNKNOWN = -1, - ERROR_UNIMPLEMENTED = -2, - ERROR_NOT_FOUND = -3, - ERROR_INVALID_PARAM_TYPE = -4, - ERROR_INVALID_PARAM_VALUE = -5, - ERROR_INVALID_OPERATION = -6, - ERROR_INVALID_SOURCE = -7, - ERROR_INVALID_STREAM_INDEX = -8, - ERROR_INITIALIZATION_FAILURE = -9, - ERROR_NULL_POINTER = -10, - ERROR_ACTIVATE = -11, - ERROR_NEGOTIATE_FAILED = -12, - ERROR_LOAD_URI_FAILED = -13, - ERROR_PLUGIN_NOT_FOUND = -14, - ERROR_PORT_UNEXPECTED = -15, - ERROR_STATE = -16, - ERROR_PARSE_META_FAILED = -17, - ERROR_SEEK_FAILURE = -18, - ERROR_ALREADY_EXISTS = -19, - ERROR_TIMEOUT = -20 + ERROR_UNKNOWN = INT32_MIN + 0, + ERROR_UNIMPLEMENTED = ERROR_UNKNOWN + 1, + ERROR_AGAIN = ERROR_UNKNOWN + 2, + ERROR_INVALID_PARAMETER_VALUE = ERROR_UNKNOWN + 3, + ERROR_INVALID_PARAMETER_TYPE = ERROR_UNKNOWN + 4, + ERROR_INVALID_OPERATION = ERROR_UNKNOWN + 5, + ERROR_UNSUPPORTED_FORMAT = ERROR_UNKNOWN + 6, + ERROR_NOT_EXISTED = ERROR_UNKNOWN + 7, + ERROR_TIMED_OUT = ERROR_UNKNOWN + 8, + ERROR_NO_MEMORY = ERROR_UNKNOWN + 9, }; } // namespace Media } // namespace OHOS diff --git a/engine/pipeline/core/pipeline_core.cpp b/engine/pipeline/core/pipeline_core.cpp index 2c47cd31..0721a482 100644 --- a/engine/pipeline/core/pipeline_core.cpp +++ b/engine/pipeline/core/pipeline_core.cpp @@ -115,7 +115,7 @@ ErrorCode PipelineCore::Pause() return ErrorCode::SUCCESS; } if (state_ != FilterState::READY && state_ != FilterState::RUNNING) { - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_INVALID_OPERATION; } state_ = FilterState::PAUSED; for (auto it = filters_.rbegin(); it != filters_.rend(); ++it) { @@ -194,7 +194,8 @@ ErrorCode PipelineCore::AddFilters(std::initializer_list filtersIn) } } if (filtersToAdd.empty()) { - return ErrorCode::ERROR_ALREADY_EXISTS; + MEDIA_LOG_I("filters already exists"); + return ErrorCode::SUCCESS; } { OSAL::ScopedLock lock(mutex_); @@ -208,19 +209,17 @@ ErrorCode PipelineCore::RemoveFilter(Filter* filter) { auto it = std::find_if(filters_.begin(), filters_.end(), [&filter](const Filter* filterPtr) { return filterPtr == filter; }); - ErrorCode rtv = ErrorCode::ERROR_INVALID_PARAM_VALUE; if (it != filters_.end()) { MEDIA_LOG_I("RemoveFilter %s", (*it)->GetName().c_str()); filters_.erase(it); - rtv = ErrorCode::SUCCESS; } - return rtv; + return ErrorCode::SUCCESS; } ErrorCode PipelineCore::RemoveFilterChain(Filter* firstFilter) { if (!firstFilter) { - return ErrorCode::ERROR_NULL_POINTER; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } std::queue levelFilters; levelFilters.push(firstFilter); diff --git a/engine/pipeline/core/port.cpp b/engine/pipeline/core/port.cpp index 8056be34..d51f40de 100644 --- a/engine/pipeline/core/port.cpp +++ b/engine/pipeline/core/port.cpp @@ -61,7 +61,7 @@ ErrorCode InPort::Activate(const std::vector& modes, WorkMode& outMode return ErrorCode::SUCCESS; } MEDIA_LOG_E("[Filter %s] InPort %s Activate error: prevPort destructed", filter->GetName().c_str(), name.c_str()); - return ErrorCode::ERROR_NULL_POINTER; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } std::shared_ptr InPort::GetPeerPort() @@ -95,7 +95,7 @@ ErrorCode InPort::PullData(uint64_t offset, size_t size, AVBufferPtr& data) return ptr->PullData(offset, size, data); } MEDIA_LOG_E("prevPort destructed"); - return ErrorCode::ERROR_NULL_POINTER; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } ErrorCode OutPort::Connect(std::shared_ptr port) @@ -105,7 +105,7 @@ ErrorCode OutPort::Connect(std::shared_ptr port) return ErrorCode::SUCCESS; } MEDIA_LOG_E("Connect filters that are not in the same pipeline."); - return ErrorCode::ERROR_INVALID_PARAM_VALUE; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } ErrorCode OutPort::Disconnect() @@ -140,9 +140,10 @@ ErrorCode OutPort::Activate(const std::vector& modes, WorkMode& outMod } } } else { - MEDIA_LOG_E("filter destructed"); + MEDIA_LOG_E("no valid filter"); } - return ErrorCode::ERROR_NEGOTIATE_FAILED; + MEDIA_LOG_E("negotiate failed"); + return ErrorCode::ERROR_UNKNOWN; } std::shared_ptr OutPort::GetPeerPort() @@ -172,7 +173,7 @@ ErrorCode OutPort::PullData(uint64_t offset, size_t size, AVBufferPtr& data) return filter->PullData(name, offset, size, data); } MEDIA_LOG_E("filter destructed"); - return ErrorCode::ERROR_NULL_POINTER; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } ErrorCode EmptyInPort::Connect(std::shared_ptr port) diff --git a/engine/pipeline/core/port.h b/engine/pipeline/core/port.h index 9b314687..81398567 100644 --- a/engine/pipeline/core/port.h +++ b/engine/pipeline/core/port.h @@ -36,7 +36,7 @@ enum class WorkMode { PUSH, PULL }; class Port { public: Port(InfoTransfer* ownerFilter, std::string portName, bool ownerNegotiate) - : filter(ownerFilter), name(std::move(portName)), useFilterNegotiate(ownerNegotiate) {} + : filter(ownerFilter), name(std::move(portName)) {} virtual ~Port() = default; const std::string& GetName(); const InfoTransfer* GetOwnerFilter() const; @@ -58,7 +58,6 @@ protected: InfoTransfer* filter; WorkMode workMode {WorkMode::PUSH}; const std::string name; - bool useFilterNegotiate; }; class OutPort; diff --git a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp index 453d7364..c4219708 100644 --- a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp +++ b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp @@ -151,7 +151,7 @@ ErrorCode AudioDecoderFilter::Start() MEDIA_LOG_D("audio decoder start called"); if (state_ != FilterState::READY && state_ != FilterState::PAUSED) { MEDIA_LOG_W("call decoder start() when state is not ready or working"); - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_INVALID_OPERATION; } return FilterBase::Start(); } @@ -160,7 +160,7 @@ ErrorCode AudioDecoderFilter::Prepare() { if (state_ != FilterState::INITIALIZED) { MEDIA_LOG_W("decoder filter is not in init state"); - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_INVALID_OPERATION; } if (!outBufferQ_) { outBufferQ_ = std::make_shared>("adecOutBuffQueue", @@ -333,7 +333,7 @@ ErrorCode AudioDecoderFilter::PushData(const std::string &inPort, AVBufferPtr bu { if (state_ != FilterState::READY && state_ != FilterState::PAUSED && state_ != FilterState::RUNNING) { MEDIA_LOG_W("pushing data to decoder when state is %d", static_cast(state_.load())); - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_INVALID_OPERATION; } if (isFlushing_) { MEDIA_LOG_I("decoder is flushing, discarding this data from port %s", inPort.c_str()); diff --git a/engine/pipeline/filters/codec/decoder_filter_base.cpp b/engine/pipeline/filters/codec/decoder_filter_base.cpp index 21056491..b5b7a697 100644 --- a/engine/pipeline/filters/codec/decoder_filter_base.cpp +++ b/engine/pipeline/filters/codec/decoder_filter_base.cpp @@ -50,16 +50,16 @@ ErrorCode DecoderFilterBase::SetPluginParameterLocked(Tag tag, const Plugin::Val ErrorCode DecoderFilterBase::SetParameter(int32_t key, const Plugin::Any& value) { if (state_.load() == FilterState::CREATED) { - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_AGAIN; } switch (key) { case KEY_CODEC_DRIVE_MODE: { if (state_ == FilterState::READY || state_ == FilterState::RUNNING || state_ == FilterState::PAUSED) { MEDIA_LOG_W("decoder cannot set parameter KEY_CODEC_DRIVE_MODE in this state"); - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_AGAIN; } if (value.Type() != typeid(ThreadDrivingMode)) { - return ErrorCode::ERROR_INVALID_PARAM_TYPE; + return ErrorCode::ERROR_INVALID_PARAMETER_TYPE; } drivingMode_ = Plugin::AnyCast(value); return ErrorCode::SUCCESS; @@ -68,9 +68,9 @@ ErrorCode DecoderFilterBase::SetParameter(int32_t key, const Plugin::Any& value) Tag tag = Tag::INVALID; if (!TranslateIntoParameter(key, tag)) { MEDIA_LOG_I("SetParameter key %d is out of boundary", key); - return ErrorCode::ERROR_INVALID_PARAM_VALUE; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } - RETURN_PLUGIN_NOT_FOUND_IF_NULL(plugin_); + RETURN_AGAIN_IF_NULL(plugin_); return SetPluginParameterLocked(tag, value); } } @@ -79,7 +79,7 @@ ErrorCode DecoderFilterBase::SetParameter(int32_t key, const Plugin::Any& value) ErrorCode DecoderFilterBase::GetParameter(int32_t key, Plugin::Any& value) { if (state_.load() == FilterState::CREATED) { - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_AGAIN; } switch (key) { case KEY_CODEC_DRIVE_MODE: @@ -89,9 +89,9 @@ ErrorCode DecoderFilterBase::GetParameter(int32_t key, Plugin::Any& value) Tag tag = Tag::INVALID; if (!TranslateIntoParameter(key, tag)) { MEDIA_LOG_I("GetParameter key %d is out of boundary", key); - return ErrorCode::ERROR_INVALID_PARAM_VALUE; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } - RETURN_PLUGIN_NOT_FOUND_IF_NULL(plugin_); + RETURN_AGAIN_IF_NULL(plugin_); return TranslatePluginStatus(plugin_->GetParameter(tag, value)); } } diff --git a/engine/pipeline/filters/codec/video_decoder/video_decoder_filter.cpp b/engine/pipeline/filters/codec/video_decoder/video_decoder_filter.cpp index 8ae11ce9..46361e77 100644 --- a/engine/pipeline/filters/codec/video_decoder/video_decoder_filter.cpp +++ b/engine/pipeline/filters/codec/video_decoder/video_decoder_filter.cpp @@ -98,7 +98,7 @@ ErrorCode VideoDecoderFilter::Start() MEDIA_LOG_D("video decoder start called"); if (state_ != FilterState::READY && state_ != FilterState::PAUSED) { MEDIA_LOG_W("call decoder start() when state_ is not ready or working"); - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_INVALID_OPERATION; } return FilterBase::Start(); } @@ -108,7 +108,7 @@ ErrorCode VideoDecoderFilter::Prepare() MEDIA_LOG_D("video decoder prepare called"); if (state_ != FilterState::INITIALIZED) { MEDIA_LOG_W("decoder filter is not in init state_"); - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_INVALID_OPERATION; } if (!outBufQue_) { outBufQue_ = std::make_shared>("vdecFilterOutBufQue", DEFAULT_OUT_BUFFER_POOL_SIZE); @@ -213,13 +213,13 @@ ErrorCode VideoDecoderFilter::SetVideoDecoderFormat(const std::shared_ptr(Plugin::VideoPixelFormat::NV12); if (!meta->GetString(Plugin::MetaID::MIME, vdecFormat_.mime)) { - return ErrorCode::ERROR_INVALID_PARAM_VALUE; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } if (!meta->GetUint32(Plugin::MetaID::VIDEO_WIDTH, vdecFormat_.width)) { - return ErrorCode::ERROR_INVALID_PARAM_VALUE; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } if (!meta->GetUint32(Plugin::MetaID::VIDEO_HEIGHT, vdecFormat_.height)) { - return ErrorCode::ERROR_INVALID_PARAM_VALUE; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } if (!meta->GetInt64(Plugin::MetaID::MEDIA_BITRATE, vdecFormat_.bitRate)) { MEDIA_LOG_D("Do not have codec bit rate"); @@ -326,7 +326,7 @@ ErrorCode VideoDecoderFilter::PushData(const std::string& inPort, AVBufferPtr bu { if (state_ != FilterState::READY && state_ != FilterState::PAUSED && state_ != FilterState::RUNNING) { MEDIA_LOG_W("pushing data to decoder when state_ is %d", static_cast(state_.load())); - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_INVALID_OPERATION; } if (isFlushing_) { MEDIA_LOG_I("decoder is flushing, discarding this data from port %s", inPort.c_str()); diff --git a/engine/pipeline/filters/common/plugin_utils.cpp b/engine/pipeline/filters/common/plugin_utils.cpp index cdc5e115..6aa8fd33 100644 --- a/engine/pipeline/filters/common/plugin_utils.cpp +++ b/engine/pipeline/filters/common/plugin_utils.cpp @@ -18,6 +18,24 @@ namespace OHOS { namespace Media { namespace Pipeline { +const static std::map g_transTable = { + {Plugin::Status::END_OF_STREAM, ErrorCode::END_OF_STREAM}, + {Plugin::Status::OK, ErrorCode::SUCCESS}, + {Plugin::Status::NO_ERROR, ErrorCode::SUCCESS}, + {Plugin::Status::ERROR_UNKNOWN, ErrorCode::ERROR_UNKNOWN}, + {Plugin::Status::ERROR_PLUGIN_ALREADY_EXISTS,ErrorCode::ERROR_UNKNOWN}, + {Plugin::Status::ERROR_INCOMPATIBLE_VERSION, ErrorCode::ERROR_UNKNOWN}, + {Plugin::Status::ERROR_NO_MEMORY, ErrorCode::ERROR_NO_MEMORY}, + {Plugin::Status::ERROR_WRONG_STATE,ErrorCode::ERROR_INVALID_OPERATION}, + {Plugin::Status::ERROR_UNIMPLEMENTED, ErrorCode::ERROR_UNIMPLEMENTED}, + {Plugin::Status::ERROR_INVALID_PARAMETER, ErrorCode::ERROR_INVALID_PARAMETER_VALUE}, + {Plugin::Status::ERROR_INVALID_DATA, ErrorCode::ERROR_UNKNOWN}, + {Plugin::Status::ERROR_MISMATCHED_TYPE, ErrorCode::ERROR_INVALID_PARAMETER_TYPE}, + {Plugin::Status::ERROR_TIMED_OUT, ErrorCode::ERROR_TIMED_OUT}, + {Plugin::Status::ERROR_UNSUPPORTED_FORMAT, ErrorCode::ERROR_UNSUPPORTED_FORMAT}, + {Plugin::Status::ERROR_NOT_ENOUGH_DATA,ErrorCode::ERROR_UNKNOWN}, + {Plugin::Status::ERROR_NOT_EXISTED, ErrorCode::ERROR_NOT_EXISTED} +}; /** * translate plugin error into pipeline error code * @param pluginError @@ -25,10 +43,11 @@ namespace Pipeline { */ OHOS::Media::ErrorCode TranslatePluginStatus(Plugin::Status pluginError) { - if (pluginError != OHOS::Media::Plugin::Status::OK) { - return OHOS::Media::ErrorCode::ERROR_UNKNOWN; + auto ite = g_transTable.find(pluginError); + if (ite == g_transTable.end()) { + return ErrorCode::ERROR_UNKNOWN; } - return OHOS::Media::ErrorCode::SUCCESS; + return ite->second; } bool TranslateIntoParameter(const int& key, OHOS::Media::Plugin::Tag& tag) { @@ -69,7 +88,7 @@ ErrorCode FindPluginAndUpdate(const std::shared_ptr& inMeta, } } if (info == nullptr) { - return ErrorCode::ERROR_PLUGIN_NOT_FOUND; + return ErrorCode::ERROR_UNSUPPORTED_FORMAT; } // try to reuse the plugin if their name are the same @@ -83,7 +102,7 @@ ErrorCode FindPluginAndUpdate(const std::shared_ptr& inMeta, } plugin = pluginCreator(info->name); if (plugin == nullptr) { - return ErrorCode::ERROR_PLUGIN_NOT_FOUND; + return ErrorCode::ERROR_UNSUPPORTED_FORMAT; } pluginInfo = info; return ErrorCode::SUCCESS; diff --git a/engine/pipeline/filters/common/plugin_utils.h b/engine/pipeline/filters/common/plugin_utils.h index e92b446a..2d27da2a 100644 --- a/engine/pipeline/filters/common/plugin_utils.h +++ b/engine/pipeline/filters/common/plugin_utils.h @@ -32,10 +32,12 @@ namespace OHOS { namespace Media { namespace Pipeline { -#define RETURN_PLUGIN_NOT_FOUND_IF_NULL(plugin) \ - if ((plugin) == nullptr) { \ - return ErrorCode::ERROR_PLUGIN_NOT_FOUND; \ - } +#define RETURN_AGAIN_IF_NULL(plugin) \ +do { \ + if ((plugin) == nullptr) { \ + return ErrorCode::ERROR_AGAIN; \ + }\ +} while (0) /** * translate plugin error into pipeline error code diff --git a/engine/pipeline/filters/demux/demuxer_filter.cpp b/engine/pipeline/filters/demux/demuxer_filter.cpp index 4f7996e6..dfc9b2b4 100644 --- a/engine/pipeline/filters/demux/demuxer_filter.cpp +++ b/engine/pipeline/filters/demux/demuxer_filter.cpp @@ -222,7 +222,7 @@ ErrorCode DemuxerFilter::SeekTo(int64_t msec) { if (!plugin_) { MEDIA_LOG_E("SeekTo failed due to no valid plugin"); - return ErrorCode::ERROR_NULL_POINTER; + return ErrorCode::ERROR_INVALID_OPERATION; } ErrorCode rtv = ErrorCode::SUCCESS; auto ret = plugin_->SeekTo(-1, msec * 1000, Plugin::SeekMode::BACKWARD); // 1000 @@ -232,7 +232,7 @@ ErrorCode DemuxerFilter::SeekTo(int64_t msec) } } else { MEDIA_LOG_E("SeekTo failed with return value: %d", static_cast(ret)); - rtv = ErrorCode::ERROR_SEEK_FAILURE; + rtv = ErrorCode::ERROR_UNKNOWN; } return rtv; } @@ -274,7 +274,7 @@ bool DemuxerFilter::InitPlugin(std::string pluginName) if (pluginName.empty()) { return false; } - if (!(pluginName_ == pluginName)) { + if (pluginName_ != pluginName) { if (plugin_) { plugin_->Deinit(); } @@ -340,7 +340,7 @@ void DemuxerFilter::MediaTypeFound(std::string pluginName) if (InitPlugin(std::move(pluginName))) { task_->Start(); } else { - OnEvent({EVENT_ERROR, ErrorCode::ERROR_PLUGIN_NOT_FOUND}); + OnEvent({EVENT_ERROR, ErrorCode::ERROR_UNSUPPORTED_FORMAT}); } } @@ -462,7 +462,7 @@ void DemuxerFilter::NegotiateDownstream() stream.needNegoCaps = false; } else { task_->PauseAsync(); - OnEvent({EVENT_ERROR, ErrorCode::ERROR_PLUGIN_NOT_FOUND}); + OnEvent({EVENT_ERROR, ErrorCode::ERROR_UNSUPPORTED_FORMAT}); } } } @@ -492,7 +492,8 @@ void DemuxerFilter::DemuxerLoop() OnEvent({EVENT_READY, {}}); } else { task_->PauseAsync(); - OnEvent({EVENT_ERROR, ErrorCode::ERROR_PARSE_META_FAILED}); + MEDIA_LOG_E("demuxer filter parse meta failed"); + OnEvent({EVENT_ERROR, ErrorCode::ERROR_UNKNOWN}); } } } diff --git a/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp b/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp index 44db53f8..8e33fc03 100644 --- a/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp +++ b/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp @@ -54,28 +54,28 @@ ErrorCode AudioSinkFilter::SetPluginParameter(Tag tag, const Plugin::ValueType& ErrorCode AudioSinkFilter::SetParameter(int32_t key, const Plugin::Any& value) { if (state_.load() == FilterState::CREATED) { - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_AGAIN; } Tag tag = Tag::INVALID; if (!TranslateIntoParameter(key, tag)) { MEDIA_LOG_I("SetParameter key %d is out of boundary", key); - return ErrorCode::ERROR_INVALID_PARAM_VALUE; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } - RETURN_PLUGIN_NOT_FOUND_IF_NULL(plugin_); + RETURN_AGAIN_IF_NULL(plugin_); return SetPluginParameter(tag, value); } ErrorCode AudioSinkFilter::GetParameter(int32_t key, Plugin::Any& value) { if (state_.load() == FilterState::CREATED) { - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_AGAIN; } Tag tag = Tag::INVALID; if (!TranslateIntoParameter(key, tag)) { MEDIA_LOG_I("GetParameter key %d is out of boundary", key); - return ErrorCode::ERROR_INVALID_PARAM_VALUE; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } - RETURN_PLUGIN_NOT_FOUND_IF_NULL(plugin_); + RETURN_AGAIN_IF_NULL(plugin_); return TranslatePluginStatus(plugin_->GetParameter(tag, value)); } @@ -211,7 +211,7 @@ ErrorCode AudioSinkFilter::Start() MEDIA_LOG_D("start called"); if (state_ != FilterState::READY && state_ != FilterState::PAUSED) { MEDIA_LOG_W("sink is not ready when start, state: %d", state_.load()); - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_INVALID_OPERATION; } auto err = FilterBase::Start(); if (err != ErrorCode::SUCCESS) { @@ -246,7 +246,7 @@ ErrorCode AudioSinkFilter::Pause() // only worked when state is working if (state_ != FilterState::READY && state_ != FilterState::RUNNING) { MEDIA_LOG_W("audio sink cannot pause when not working"); - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_INVALID_OPERATION; } auto err = FilterBase::Pause(); RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "audio sink pause failed"); @@ -288,7 +288,7 @@ ErrorCode AudioSinkFilter::SetVolume(float volume) { if (state_ != FilterState::READY && state_ != FilterState::RUNNING && state_ != FilterState::PAUSED) { MEDIA_LOG_E("audio sink filter cannot set volume in state %d", state_.load()); - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_AGAIN; } MEDIA_LOG_W("set volume %.3f", volume); return TranslatePluginStatus(plugin_->SetVolume(volume)); diff --git a/engine/pipeline/filters/sink/video_sink/video_sink_filter.cpp b/engine/pipeline/filters/sink/video_sink/video_sink_filter.cpp index 8e1a4fbd..cc7f750f 100644 --- a/engine/pipeline/filters/sink/video_sink/video_sink_filter.cpp +++ b/engine/pipeline/filters/sink/video_sink/video_sink_filter.cpp @@ -64,28 +64,28 @@ void VideoSinkFilter::Init(EventReceiver* receiver, FilterCallback* callback) ErrorCode VideoSinkFilter::SetParameter(int32_t key, const Plugin::Any& value) { if (state_.load() == FilterState::CREATED) { - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_AGAIN; } Tag tag = Tag::INVALID; if (!TranslateIntoParameter(key, tag)) { MEDIA_LOG_I("SetParameter key %d is out of boundary", key); - return ErrorCode::ERROR_INVALID_PARAM_VALUE; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } - RETURN_PLUGIN_NOT_FOUND_IF_NULL(plugin_); + RETURN_AGAIN_IF_NULL(plugin_); return TranslatePluginStatus(plugin_->SetParameter(tag, value)); } ErrorCode VideoSinkFilter::GetParameter(int32_t key, Plugin::Any& value) { if (state_.load() == FilterState::CREATED) { - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_AGAIN; } Tag tag = Tag::INVALID; if (!TranslateIntoParameter(key, tag)) { MEDIA_LOG_I("GetParameter key %d is out of boundary", key); - return ErrorCode::ERROR_INVALID_PARAM_VALUE; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } - RETURN_PLUGIN_NOT_FOUND_IF_NULL(plugin_); + RETURN_AGAIN_IF_NULL(plugin_); return TranslatePluginStatus(plugin_->GetParameter(tag, value)); } @@ -218,7 +218,7 @@ ErrorCode VideoSinkFilter::Start() MEDIA_LOG_D("start called"); if (state_ != FilterState::READY && state_ != FilterState::PAUSED) { MEDIA_LOG_W("sink is not ready when start, state_: %d", state_.load()); - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_INVALID_OPERATION; } inBufQueue_->SetActive(true); renderTask_->Start(); @@ -252,7 +252,7 @@ ErrorCode VideoSinkFilter::Pause() MEDIA_LOG_D("Video sink filter pause start"); if (state_ != FilterState::READY && state_ != FilterState::RUNNING) { MEDIA_LOG_W("video sink cannot pause when not working"); - return ErrorCode::ERROR_STATE; + return ErrorCode::ERROR_INVALID_OPERATION; } RETURN_ERR_MESSAGE_LOG_IF_FAIL(FilterBase::Pause(), "Video sink pause fail"); RETURN_ERR_MESSAGE_LOG_IF_FAIL(TranslatePluginStatus(plugin_->Pause()), "Pause plugin fail"); diff --git a/engine/pipeline/filters/source/media_source_filter.cpp b/engine/pipeline/filters/source/media_source_filter.cpp index 7313b9e5..943cd499 100644 --- a/engine/pipeline/filters/source/media_source_filter.cpp +++ b/engine/pipeline/filters/source/media_source_filter.cpp @@ -62,7 +62,7 @@ ErrorCode MediaSourceFilter::SetSource(const std::shared_ptr& sourc MEDIA_LOG_D("IN"); if (source == nullptr) { MEDIA_LOG_E("Invalid source"); - return ErrorCode::ERROR_INVALID_SOURCE; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } protocol_.clear(); ErrorCode err = FindPlugin(source); @@ -126,7 +126,7 @@ ErrorCode MediaSourceFilter::Prepare() { MEDIA_LOG_D("IN"); if (plugin_ == nullptr) { - return ErrorCode::ERROR_PLUGIN_NOT_FOUND; + return ErrorCode::ERROR_INVALID_OPERATION; } auto err = TranslatePluginStatus(plugin_->Prepare()); if (err == ErrorCode::SUCCESS) { @@ -142,14 +142,14 @@ ErrorCode MediaSourceFilter::Start() if (taskPtr_) { taskPtr_->Start(); } - return plugin_ ? TranslatePluginStatus(plugin_->Start()) : ErrorCode::ERROR_PLUGIN_NOT_FOUND; + return plugin_ ? TranslatePluginStatus(plugin_->Start()) : ErrorCode::ERROR_INVALID_OPERATION; } ErrorCode MediaSourceFilter::PullData(const std::string& outPort, uint64_t offset, size_t size, AVBufferPtr& data) { MEDIA_LOG_D("IN, offset: %llu, size: %zu, outPort: %s", offset, size, outPort.c_str()); if (!plugin_) { - return ErrorCode::ERROR_PLUGIN_NOT_FOUND; + return ErrorCode::ERROR_INVALID_OPERATION; } ErrorCode err; auto readSize = size; @@ -196,7 +196,7 @@ ErrorCode MediaSourceFilter::Stop() } protocol_.clear(); uri_.clear(); - ErrorCode ret = ErrorCode::ERROR_PLUGIN_NOT_FOUND; + ErrorCode ret = ErrorCode::SUCCESS; if (plugin_) { ret = TranslatePluginStatus(plugin_->Stop()); } @@ -248,7 +248,7 @@ ErrorCode MediaSourceFilter::DoNegotiate(const std::shared_ptr& sou if (!GetOutPort(PORT_NAME_DEFAULT)->Negotiate(tmpCap, peerCap) || !GetOutPort(PORT_NAME_DEFAULT)->Configure(suffixMeta)) { MEDIA_LOG_E("Negotiate fail!"); - return ErrorCode::ERROR_INVALID_PARAM_VALUE; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } } } @@ -329,7 +329,7 @@ ErrorCode MediaSourceFilter::FindPlugin(const std::shared_ptr& sour ParseProtocol(source); if (protocol_.empty()) { MEDIA_LOG_E("protocol_ is empty"); - return ErrorCode::ERROR_NULL_POINTER; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } PluginManager& pluginManager = PluginManager::Instance(); std::set nameList = pluginManager.ListPlugins(PluginType::SOURCE); @@ -347,7 +347,7 @@ ErrorCode MediaSourceFilter::FindPlugin(const std::shared_ptr& sour } } MEDIA_LOG_I("Cannot find any plugin"); - return ErrorCode::ERROR_PLUGIN_NOT_FOUND; + return ErrorCode::ERROR_UNSUPPORTED_FORMAT; } } // namespace Pipeline } // namespace Media diff --git a/engine/player/hiplayer_impl.cpp b/engine/player/hiplayer_impl.cpp index 543f0bc2..aba4cca1 100644 --- a/engine/player/hiplayer_impl.cpp +++ b/engine/player/hiplayer_impl.cpp @@ -123,7 +123,7 @@ int32_t HiPlayerImpl::Prepare() } else if (curFsmState_ == StateId::INIT) { return to_underlying(errorCode_.load()); } else { - return to_underlying(ErrorCode::ERROR_STATE); + return to_underlying(ErrorCode::ERROR_INVALID_OPERATION); } } @@ -182,7 +182,7 @@ int32_t HiPlayerImpl::SetVolume(float leftVolume, float rightVolume) { if (leftVolume < 0 || leftVolume > MAX_MEDIA_VOLUME || rightVolume < 0 || rightVolume > MAX_MEDIA_VOLUME) { MEDIA_LOG_E("volume not valid, should be in range [0,100]"); - return to_underlying(ErrorCode::ERROR_INVALID_PARAM_VALUE); + return to_underlying(ErrorCode::ERROR_INVALID_PARAMETER_VALUE); } if (leftVolume < 1e-6 && rightVolume >= 1e-6) { // 1e-6 volume_ = rightVolume; @@ -283,14 +283,16 @@ ErrorCode HiPlayerImpl::DoStop() ErrorCode HiPlayerImpl::DoSeek(int64_t msec) { - { - pipeline_->FlushStart(); - pipeline_->FlushEnd(); - } + pipeline_->FlushStart(); + pipeline_->FlushEnd(); auto rtv = demuxer_->SeekTo(msec); auto ptr = callback_.lock(); if (ptr != nullptr) { - ptr->OnRewindToComplete(); + if (rtv != ErrorCode::SUCCESS) { + ptr->OnError(to_underlying(PlayerErrorTypeExt::SEEK_ERROR), to_underlying(rtv)); + } else { + ptr->OnRewindToComplete(); + } } return rtv; } @@ -383,7 +385,7 @@ int32_t HiPlayerImpl::GetDuration(int64_t& outDurationMs) auto sourceMeta = sourceMeta_.lock(); if (sourceMeta == nullptr) { outDurationMs = 0; - return to_underlying(ErrorCode::ERROR_NOT_FOUND); + return to_underlying(ErrorCode::ERROR_AGAIN); } if (sourceMeta->GetUint64(Media::Plugin::MetaID::MEDIA_DURATION, duration)) { outDurationMs = duration; @@ -403,14 +405,14 @@ int32_t HiPlayerImpl::GetDuration(int64_t& outDurationMs) outDurationMs = duration; return to_underlying(ErrorCode::SUCCESS); } - return to_underlying(ErrorCode::ERROR_NOT_FOUND); + return to_underlying(ErrorCode::ERROR_AGAIN); } ErrorCode HiPlayerImpl::SetVolume(float volume) { if (audioSink_ == nullptr) { MEDIA_LOG_W("cannot set volume while audio sink filter is null"); - return ErrorCode::ERROR_NULL_POINTER; + return ErrorCode::ERROR_AGAIN; } ErrorCode ret = ErrorCode::SUCCESS; if (volume > 0) { @@ -458,24 +460,27 @@ ErrorCode HiPlayerImpl::GetTrackCnt(size_t& cnt) const ErrorCode HiPlayerImpl::GetSourceMeta(shared_ptr& meta) const { meta = sourceMeta_.lock(); - return meta ? ErrorCode::SUCCESS : ErrorCode::ERROR_NOT_FOUND; + return meta ? ErrorCode::SUCCESS : ErrorCode::ERROR_AGAIN; } ErrorCode HiPlayerImpl::GetTrackMeta(size_t id, shared_ptr& meta) const { if (id > streamMeta_.size() || id < 0) { - return ErrorCode::ERROR_INVALID_PARAM_VALUE; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } meta = streamMeta_[id].lock(); if (meta == nullptr) { - return ErrorCode::ERROR_NOT_FOUND; + return ErrorCode::ERROR_AGAIN; } return ErrorCode::SUCCESS; } ErrorCode HiPlayerImpl::NewAudioPortFound(Filter* filter, const Plugin::Any& parameter) { - ErrorCode rtv = ErrorCode::ERROR_PORT_UNEXPECTED; + if (parameter.Type() != typeid(PortInfo)) { + return ErrorCode::ERROR_INVALID_PARAMETER_TYPE; + } + ErrorCode rtv = ErrorCode::ERROR_INVALID_PARAMETER_VALUE; auto param = Plugin::AnyCast(parameter); if (filter == demuxer_.get() && param.type == PortType::OUT) { MEDIA_LOG_I("new port found on demuxer %zu", param.ports.size()); @@ -507,9 +512,12 @@ ErrorCode HiPlayerImpl::NewAudioPortFound(Filter* filter, const Plugin::Any& par #ifdef VIDEO_SUPPORT ErrorCode HiPlayerImpl::NewVideoPortFound(Filter* filter, const Plugin::Any& parameter) { + if (parameter.Type() != typeid(PortInfo)) { + return ErrorCode::ERROR_INVALID_PARAMETER_TYPE; + } auto param = Plugin::AnyCast(parameter); if (filter != demuxer_.get() || param.type != PortType::OUT) { - return ErrorCode::ERROR_PORT_UNEXPECTED; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } std::vector newFilters; for (const auto& portDesc : param.ports) { @@ -517,7 +525,7 @@ ErrorCode HiPlayerImpl::NewVideoPortFound(Filter* filter, const Plugin::Any& par MEDIA_LOG_I("port name %s", portDesc.name.c_str()); videoDecoder = FilterFactory::Instance().CreateFilterWithType( "builtin.player.videodecoder", "videodecoder-" + portDesc.name); - if (pipeline_->AddFilters({videoDecoder.get()}) != ErrorCode::ERROR_ALREADY_EXISTS) { + if (pipeline_->AddFilters({videoDecoder.get()}) == ErrorCode::SUCCESS) { // link demuxer and video decoder auto fromPort = filter->GetOutPort(portDesc.name); auto toPort = videoDecoder->GetInPort(PORT_NAME_DEFAULT); @@ -525,7 +533,7 @@ ErrorCode HiPlayerImpl::NewVideoPortFound(Filter* filter, const Plugin::Any& par newFilters.emplace_back(videoDecoder.get()); // link video decoder and video sink - if (pipeline_->AddFilters({videoSink.get()}) != ErrorCode::ERROR_ALREADY_EXISTS) { + if (pipeline_->AddFilters({videoSink.get()}) == ErrorCode::SUCCESS) { fromPort = videoDecoder->GetOutPort(PORT_NAME_DEFAULT); toPort = videoSink->GetInPort(PORT_NAME_DEFAULT); FAIL_LOG(pipeline_->LinkPorts(fromPort, toPort)); // link ports diff --git a/engine/player/internal/init_state.h b/engine/player/internal/init_state.h index 28df3577..54602d87 100644 --- a/engine/player/internal/init_state.h +++ b/engine/player/internal/init_state.h @@ -39,7 +39,7 @@ public: std::shared_ptr source; if (param.Type() != typeid(std::shared_ptr) || !(source = Plugin::AnyCast>(param))) { - return {ErrorCode::ERROR_INVALID_SOURCE, Action::ACTION_BUTT}; + return {ErrorCode::ERROR_INVALID_PARAMETER_TYPE, Action::ACTION_BUTT}; } auto ret = executor_.DoSetSource(source); return {ret, Action::TRANS_TO_PREPARING}; diff --git a/engine/player/internal/pause_state.h b/engine/player/internal/pause_state.h index b1eb9135..d26eb37c 100644 --- a/engine/player/internal/pause_state.h +++ b/engine/player/internal/pause_state.h @@ -49,7 +49,7 @@ public: { MEDIA_LOG_D("Seek in pause state."); if (param.Type() != typeid(int64_t)) { - return {ErrorCode::ERROR_INVALID_PARAM_VALUE, Action::ACTION_BUTT}; + return {ErrorCode::ERROR_INVALID_PARAMETER_TYPE, Action::ACTION_BUTT}; } auto timeMs = Plugin::AnyCast(param); auto ret = executor_.DoSeek(timeMs); diff --git a/engine/player/internal/playing_state.h b/engine/player/internal/playing_state.h index 6059df86..fe1f5dbb 100644 --- a/engine/player/internal/playing_state.h +++ b/engine/player/internal/playing_state.h @@ -53,7 +53,7 @@ public: { MEDIA_LOG_D("Seek in playing state."); if (param.Type() != typeid(int64_t)) { - return {ErrorCode::ERROR_INVALID_PARAM_VALUE, Action::ACTION_BUTT}; + return {ErrorCode::ERROR_INVALID_PARAMETER_TYPE, Action::ACTION_BUTT}; } auto timeMs = Plugin::AnyCast(param); auto ret = executor_.DoSeek(timeMs); diff --git a/engine/player/internal/preparing_state.h b/engine/player/internal/preparing_state.h index 0fc36546..47eb1414 100644 --- a/engine/player/internal/preparing_state.h +++ b/engine/player/internal/preparing_state.h @@ -54,7 +54,7 @@ public: { MEDIA_LOG_D("Seek in preparing state."); if (param.Type() != typeid(int64_t)) { - return {ErrorCode::ERROR_INVALID_PARAM_VALUE, Action::ACTION_BUTT}; + return {ErrorCode::ERROR_INVALID_PARAMETER_TYPE, Action::ACTION_BUTT}; } auto timeMs = Plugin::AnyCast(param); auto ret = executor_.DoSeek(timeMs); diff --git a/engine/player/internal/ready_state.h b/engine/player/internal/ready_state.h index 22260fe6..053d9c05 100644 --- a/engine/player/internal/ready_state.h +++ b/engine/player/internal/ready_state.h @@ -47,7 +47,7 @@ public: { MEDIA_LOG_D("Seek in ready state."); if (param.Type() != typeid(int64_t)) { - return {ErrorCode::ERROR_INVALID_PARAM_VALUE, Action::ACTION_BUTT}; + return {ErrorCode::ERROR_INVALID_PARAMETER_TYPE, Action::ACTION_BUTT}; } auto timeMs = Plugin::AnyCast(param); auto ret = executor_.DoSeek(timeMs); diff --git a/engine/player/internal/state_machine.cpp b/engine/player/internal/state_machine.cpp index 461a49e3..6dc0c066 100644 --- a/engine/player/internal/state_machine.cpp +++ b/engine/player/internal/state_machine.cpp @@ -62,7 +62,7 @@ ErrorCode StateMachine::SendEvent(Intent intent, const Plugin::Any& param) const ErrorCode StateMachine::SendEvent(Intent intent, const Plugin::Any& param) { constexpr int timeoutMs = 5000; - ErrorCode errorCode = ErrorCode::ERROR_TIMEOUT; + ErrorCode errorCode = ErrorCode::ERROR_TIMED_OUT; if (!intentSync_.WaitFor( intent, [this, intent, param] { SendEventAsync(intent, param); }, timeoutMs, errorCode)) { MEDIA_LOG_E("SendEvent timeout, intent: %d", static_cast(intent)); @@ -173,7 +173,7 @@ ErrorCode StateMachine::TransitionTo(const std::shared_ptr& state) { if (state == nullptr) { MEDIA_LOG_E("TransitionTo, nullptr for state"); - return ErrorCode::ERROR_NULL_POINTER; + return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } ErrorCode rtv = ErrorCode::SUCCESS; if (state != curState_) { diff --git a/engine/plugin/common/plugin_types.h b/engine/plugin/common/plugin_types.h index 4b447d60..a6b91fd9 100644 --- a/engine/plugin/common/plugin_types.h +++ b/engine/plugin/common/plugin_types.h @@ -65,7 +65,7 @@ enum struct Status : int32_t { OK = 0, ///< The execution result is correct. NO_ERROR = OK, ///< Same as Status::OK ERROR_UNKNOWN = -1, ///< An unknown error occurred. - ERROR_ALREADY_EXISTS = -2, ///< The plugin already exists, usually occurs when in plugin registered. + ERROR_PLUGIN_ALREADY_EXISTS = -2, ///< The plugin already exists, usually occurs when in plugin registered. ERROR_INCOMPATIBLE_VERSION = -3, ///< Incompatible version, may occur during plugin registration or function calling. ERROR_NO_MEMORY = -4, ///< The system memory is insufficient. @@ -77,6 +77,7 @@ enum struct Status : int32_t { ERROR_TIMED_OUT = -10, ///< Operation timeout. ERROR_UNSUPPORTED_FORMAT = -11, ///< The plugin not support this format/name. ERROR_NOT_ENOUGH_DATA = -12, ///< Not enough data when read from source. + ERROR_NOT_EXISTED = -13, ///< Source is not existed. }; /** diff --git a/engine/plugin/core/plugin_register.cpp b/engine/plugin/core/plugin_register.cpp index 7262e449..f0385481 100644 --- a/engine/plugin/core/plugin_register.cpp +++ b/engine/plugin/core/plugin_register.cpp @@ -79,7 +79,7 @@ Status PluginRegister::RegisterImpl::AddPlugin(const PluginDefBase& def) registerData->registerTable[def.pluginType].erase(def.name); } else { // 重复注册,且有更合适的版本存在 - return Status::ERROR_ALREADY_EXISTS; + return Status::ERROR_PLUGIN_ALREADY_EXISTS; } } registerData->registerNames[def.pluginType].insert(def.name); diff --git a/engine/plugin/interface/plugin_definition.h b/engine/plugin/interface/plugin_definition.h index 5ae62470..af6dd5aa 100644 --- a/engine/plugin/interface/plugin_definition.h +++ b/engine/plugin/interface/plugin_definition.h @@ -117,7 +117,7 @@ struct Register { * @param def Basic information about the plugin * @return Registration status return * @retval OK: The plugin is registered succeed. - * @retval ERROR_ALREADY_EXISTS: The plugin already exists in plugin registered. + * @retval ERROR_PLUGIN_ALREADY_EXISTS: The plugin already exists in plugin registered. * @retval ERROR_INCOMPATIBLE_VERSION: Incompatible version during plugin registration. */ virtual Status AddPlugin(const PluginDefBase& def) = 0; @@ -141,7 +141,7 @@ struct PackageRegister : Register { * @param def plugin packaging information. * @return Registration status return * @retval OK: The package is registered succeed without any errors. - * @retval ERROR_ALREADY_EXISTS: The package or plugins already exists. + * @retval ERROR_PLUGIN_ALREADY_EXISTS: The package or plugins already exists. * @retval ERROR_INCOMPATIBLE_VERSION: Incompatible plugin interface version or api version. */ virtual Status AddPackage(const PackageDef& def) = 0; diff --git a/engine/plugin/interface/source_plugin.h b/engine/plugin/interface/source_plugin.h index 18461976..0e843d1d 100644 --- a/engine/plugin/interface/source_plugin.h +++ b/engine/plugin/interface/source_plugin.h @@ -46,7 +46,10 @@ struct SourcePlugin : public PluginBase { * or to read the detailed information required by the data. * @return Execution status return * @retval OK: Plugin reset succeeded. - * @retval ERROR_INVALID_DATA: Uri is not supported. + * @retval ERROR_WRONG_STATE: Call this function in non wrong state + * @retval ERROR_NOT_EXISTED: Uri is not existed. + * @retval ERROR_UNSUPPORTED_FORMAT: Uri is not supported. + * @retval ERROR_INVALID_PARAMETER: Uri is invalid. */ virtual Status SetSource(std::string& uri, std::shared_ptr> params = nullptr) = 0; diff --git a/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp b/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp index 6b01b820..a64e074e 100644 --- a/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp +++ b/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp @@ -340,7 +340,7 @@ Status AudioFfmpegDecoderPlugin::Start() { { OSAL::ScopedLock lock(avMutex_); - if (avCodecContext_.get() == nullptr) { + if (avCodecContext_ == nullptr) { return Status::ERROR_WRONG_STATE; } auto res = avcodec_open2(avCodecContext_.get(), avCodec_.get(), nullptr); @@ -450,8 +450,8 @@ Status AudioFfmpegDecoderPlugin::SendBufferLocked(const std::shared_ptr& Status AudioFfmpegDecoderPlugin::SendBuffer(const std::shared_ptr& inputBuffer) { if (inputBuffer->IsEmpty() && !(inputBuffer->flag & BUFFER_FLAG_EOS)) { - MEDIA_LOG_E("decoder does not support fd buffer"); - return Status::ERROR_INVALID_DATA; + MEDIA_LOG_E("input buffer error"); + return Status::ERROR_INVALID_PARAMETER; } Status ret = Status::OK; { diff --git a/engine/plugin/plugins/ffmpeg_adapter/demuxer/ffmpeg_demuxer_plugin.cpp b/engine/plugin/plugins/ffmpeg_adapter/demuxer/ffmpeg_demuxer_plugin.cpp index 0c5152e5..39e39c5b 100644 --- a/engine/plugin/plugins/ffmpeg_adapter/demuxer/ffmpeg_demuxer_plugin.cpp +++ b/engine/plugin/plugins/ffmpeg_adapter/demuxer/ffmpeg_demuxer_plugin.cpp @@ -190,7 +190,7 @@ Status FFmpegDemuxerPlugin::SetDataSource(const std::shared_ptr& sou Status FFmpegDemuxerPlugin::GetMediaInfo(MediaInfo& mediaInfo) { if (!mediaInfo_ && !ParseMediaData()) { - return Status::ERROR_INVALID_PARAMETER; + return Status::ERROR_WRONG_STATE; } mediaInfo = *mediaInfo_; return Status::OK; @@ -209,12 +209,12 @@ Status FFmpegDemuxerPlugin::SelectTrack(int32_t trackId) { if (!mediaInfo_) { MEDIA_LOG_E("SelectTrack called before GetMediaInfo()..."); - return Status::ERROR_INVALID_DATA; + return Status::ERROR_WRONG_STATE; } if (trackId < 0 || trackId >= static_cast(mediaInfo_->tracks.size())) { MEDIA_LOG_E("SelectTrack called with invalid trackId: %d, number of tracks: %d", trackId, static_cast(mediaInfo_->tracks.size())); - return Status::ERROR_INVALID_DATA; + return Status::ERROR_INVALID_PARAMETER; } OSAL::ScopedLock lock(mutex_); auto it = std::find_if(selectedTrackIds_.begin(), selectedTrackIds_.end(), diff --git a/engine/plugin/plugins/ffmpeg_adapter/video_decoder/video_ffmpeg_decoder_plugin.cpp b/engine/plugin/plugins/ffmpeg_adapter/video_decoder/video_ffmpeg_decoder_plugin.cpp index 21afc47d..699470d9 100644 --- a/engine/plugin/plugins/ffmpeg_adapter/video_decoder/video_ffmpeg_decoder_plugin.cpp +++ b/engine/plugin/plugins/ffmpeg_adapter/video_decoder/video_ffmpeg_decoder_plugin.cpp @@ -183,7 +183,7 @@ Status VideoFfmpegDecoderPlugin::GetParameter(Tag tag, ValueType& value) value = res->second; return Status::OK; } - return Status::ERROR_INVALID_PARAMETER; + return Status::ERROR_INVALID_PARAMETER_VALUE; } template @@ -297,7 +297,7 @@ Status VideoFfmpegDecoderPlugin::OpenCodecContext() if (vdec == nullptr) { MEDIA_LOG_E("Codec: %d is not found", static_cast(avCodecContext_->codec_id)); DeinitCodecContext(); - return Status::ERROR_INVALID_PARAMETER; + return Status::ERROR_INVALID_PARAMETER_VALUE; } auto res = avcodec_open2(avCodecContext_.get(), avCodec_.get(), nullptr); if (res != 0) { diff --git a/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp b/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp index 82a7fef5..c82204ef 100644 --- a/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp +++ b/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp @@ -278,7 +278,7 @@ Status SdlAudioSinkPlugin::SetMute(bool mute) Status SdlAudioSinkPlugin::GetVolume(float& volume) { UNUSED_VARIABLE(volume); - return Status::ERROR_ALREADY_EXISTS; + return Status::ERROR_UNIMPLEMENTED; } Status SdlAudioSinkPlugin::SetVolume(float volume) diff --git a/engine/plugin/plugins/sink/sdl/video_sink/sdl_video_sink_plugin.cpp b/engine/plugin/plugins/sink/sdl/video_sink/sdl_video_sink_plugin.cpp index a43a8808..9ae29bb7 100644 --- a/engine/plugin/plugins/sink/sdl/video_sink/sdl_video_sink_plugin.cpp +++ b/engine/plugin/plugins/sink/sdl/video_sink/sdl_video_sink_plugin.cpp @@ -260,7 +260,7 @@ bool SdlVideoSinkPlugin::IsParameterSupported(Tag tag) Status SdlVideoSinkPlugin::GetParameter(Tag tag, ValueType& value) { - return Status::ERROR_ALREADY_EXISTS; + return Status::ERROR_UNIMPLEMENTED; } Status SdlVideoSinkPlugin::SetParameter(Tag tag, const ValueType& value) @@ -302,7 +302,7 @@ std::shared_ptr SdlVideoSinkPlugin::GetAllocator() Status SdlVideoSinkPlugin::SetCallback(const std::shared_ptr& cb) { - return Status::ERROR_ALREADY_EXISTS; + return Status::ERROR_UNIMPLEMENTED; } Status SdlVideoSinkPlugin::Pause() diff --git a/engine/plugin/plugins/source/file_source/file_source_plugin.cpp b/engine/plugin/plugins/source/file_source/file_source_plugin.cpp index 655567a3..8479ebdc 100644 --- a/engine/plugin/plugins/source/file_source/file_source_plugin.cpp +++ b/engine/plugin/plugins/source/file_source/file_source_plugin.cpp @@ -223,18 +223,18 @@ Status FileSourcePlugin::ParseFileName(std::string& uri) { if (uri.empty()) { MEDIA_LOG_E("uri is empty"); - return Status::ERROR_INVALID_DATA; + return Status::ERROR_INVALID_PARAMETER; } MEDIA_LOG_D("uri: %s", uri.c_str()); if (uri.find("file:/") != std::string::npos) { if (uri.find('#') != std::string::npos) { MEDIA_LOG_E("Invalid file uri format: %s", uri.c_str()); - return Status::ERROR_INVALID_DATA; + return Status::ERROR_INVALID_PARAMETER; } auto pos = uri.find("file:"); if (pos == std::string::npos) { MEDIA_LOG_E("Invalid file uri format: %s", uri.c_str()); - return Status::ERROR_INVALID_DATA; + return Status::ERROR_INVALID_PARAMETER; } pos += 5; // 5: offset if (uri.find("///", pos) != std::string::npos) { @@ -244,7 +244,7 @@ Status FileSourcePlugin::ParseFileName(std::string& uri) pos = uri.find('/', pos); // skip host name if (pos == std::string::npos) { MEDIA_LOG_E("Invalid file uri format: %s", uri.c_str()); - return Status::ERROR_INVALID_DATA; + return Status::ERROR_INVALID_PARAMETER; } pos++; } @@ -261,7 +261,7 @@ Status FileSourcePlugin::CheckFileStat() struct stat fileStat; if (stat(fileName_.c_str(), &fileStat) < 0) { MEDIA_LOG_E("Cannot get info from %s", fileName_.c_str()); - return Status::ERROR_UNKNOWN; + return Status::ERROR_NOT_EXISTED; } if (S_ISDIR(fileStat.st_mode)) { MEDIA_LOG_E("%s is directory", fileName_.c_str()); diff --git a/engine/plugin/plugins/source/stream_source/stream_source_plugin.cpp b/engine/plugin/plugins/source/stream_source/stream_source_plugin.cpp index 150e8dc2..3fe4a94d 100644 --- a/engine/plugin/plugins/source/stream_source/stream_source_plugin.cpp +++ b/engine/plugin/plugins/source/stream_source/stream_source_plugin.cpp @@ -174,7 +174,7 @@ Status StreamSourcePlugin::SetSource(std::string& uri, std::shared_ptr source_ = nullptr; for (const auto& iter_ : *params) { @@ -187,12 +187,12 @@ Status StreamSourcePlugin::SetSource(std::string& uri, std::shared_ptr stream_ = source_->GetSourceStream(); if (stream_ == nullptr) { MEDIA_LOG_E("Get StreamSource fail"); - return Status::ERROR_INVALID_DATA; + return Status::ERROR_INVALID_PARAMETER; } streamCallback_ = std::make_shared(shared_from_this(), stream_); diff --git a/interface/histreamer/hiplayer.h b/interface/histreamer/hiplayer.h index fabcbc76..c62fc2b7 100644 --- a/interface/histreamer/hiplayer.h +++ b/interface/histreamer/hiplayer.h @@ -21,6 +21,10 @@ namespace OHOS { namespace Media { +enum struct PlayerErrorTypeExt : int32_t { + SEEK_ERROR = 1, +}; + #if defined(WIN32) __declspec(dllexport) #endif diff --git a/tests/ut/TestStateMachine.cpp b/tests/ut/TestStateMachine.cpp index b9051621..174ace25 100644 --- a/tests/ut/TestStateMachine.cpp +++ b/tests/ut/TestStateMachine.cpp @@ -39,7 +39,7 @@ public: } ErrorCode DoSetSource(const std::shared_ptr& source) const override { - return source ? ErrorCode::SUCCESS : ErrorCode::ERROR_INVALID_SOURCE; + return source ? ErrorCode::SUCCESS : ErrorCode::ERROR_INVALID_PARAMETER_VALUE; } ErrorCode DoOnReady() override { @@ -89,7 +89,7 @@ TEST_F(TestStateMachine, test_init_state) TEST_F(TestStateMachine, test_set_invalid_source) { EXPECT_TRUE(stateMachine.GetCurrentState() == "InitState"); - EXPECT_EQ(ErrorCode::ERROR_INVALID_SOURCE, stateMachine.SendEvent(Intent::SET_SOURCE)); + EXPECT_EQ(ErrorCode::ERROR_INVALID_PARAMETER_TYPE, stateMachine.SendEvent(Intent::SET_SOURCE)); EXPECT_TRUE(stateMachine.GetCurrentState() == "InitState"); } -- Gitee From da00274b8b77a1bd45bc421257b2b1a261f4b380 Mon Sep 17 00:00:00 2001 From: leo_ysl <9693773+leo_ysl@user.noreply.gitee.com> Date: Tue, 9 Nov 2021 09:18:04 +0000 Subject: [PATCH 11/22] !113 remove thread of sink plugin. Signed-off-by: Li Yong --- engine/foundation/osal/thread/task.cpp | 3 +- engine/foundation/osal/thread/task.h | 1 + engine/pipeline/core/pipeline_core.cpp | 4 +- .../audio_decoder/audio_decoder_filter.cpp | 2 +- .../pipeline/filters/demux/demuxer_filter.cpp | 34 +-- .../pipeline/filters/demux/demuxer_filter.h | 12 +- .../sink/audio_sink/audio_sink_filter.cpp | 20 +- engine/plugin/plugins/hdi_adapter/BUILD.gn | 4 +- .../plugins/hdi_adapter/sink/hos_au_sink.cpp | 201 ++++++++---------- .../plugins/hdi_adapter/sink/hos_au_sink.h | 48 ++--- .../sdl/audio_sink/sdl_audio_sink_plugin.cpp | 4 +- .../source/file_source/file_source_plugin.cpp | 2 +- 12 files changed, 155 insertions(+), 180 deletions(-) diff --git a/engine/foundation/osal/thread/task.cpp b/engine/foundation/osal/thread/task.cpp index 1dceabca..3270c858 100644 --- a/engine/foundation/osal/thread/task.cpp +++ b/engine/foundation/osal/thread/task.cpp @@ -88,7 +88,7 @@ void Task::Pause() if (runningState_.load() == RunningState::STARTED) { pauseDone_ = false; runningState_ = RunningState::PAUSED; - while (!pauseDone_.load()) {} + pauseCond_.Wait(lock, [this] { return pauseDone_.load(); }); } MEDIA_LOG_D("task %s Pause done.", name_.c_str()); } @@ -130,6 +130,7 @@ void Task::Run() OSAL::ScopedLock lock(stateMutex_); if (runningState_.load() == RunningState::PAUSED) { pauseDone_ = true; + pauseCond_.NotifyOne(); constexpr int timeoutMs = 500; cv_.WaitFor(lock, timeoutMs, [this] { return runningState_.load() != RunningState::PAUSED; }); } diff --git a/engine/foundation/osal/thread/task.h b/engine/foundation/osal/thread/task.h index cbb3e716..7ca82049 100644 --- a/engine/foundation/osal/thread/task.h +++ b/engine/foundation/osal/thread/task.h @@ -67,6 +67,7 @@ private: OSAL::Mutex stateMutex_{}; OSAL::ConditionVariable cv_{}; + OSAL::ConditionVariable pauseCond_{}; std::atomic pauseDone_{}; std::atomic workInProgress_{}; }; diff --git a/engine/pipeline/core/pipeline_core.cpp b/engine/pipeline/core/pipeline_core.cpp index 0721a482..4fdee1c0 100644 --- a/engine/pipeline/core/pipeline_core.cpp +++ b/engine/pipeline/core/pipeline_core.cpp @@ -148,7 +148,7 @@ ErrorCode PipelineCore::Stop() MEDIA_LOG_E("PipelineCore error: %zu", filters_.size()); continue; } - auto filterName = (*it)->GetName(); + MEDIA_LOG_I("Stop filter: %s", (*it)->GetName().c_str()); auto rtv = (*it)->Stop(); FALSE_RETURN_V(rtv == ErrorCode::SUCCESS, rtv); } @@ -162,6 +162,7 @@ ErrorCode PipelineCore::Stop() void PipelineCore::FlushStart() { for (auto it = filters_.rbegin(); it != filters_.rend(); ++it) { + MEDIA_LOG_I("FlushStart for filter: %s", (*it)->GetName().c_str()); (*it)->FlushStart(); } } @@ -169,6 +170,7 @@ void PipelineCore::FlushStart() void PipelineCore::FlushEnd() { for (auto it = filters_.rbegin(); it != filters_.rend(); ++it) { + MEDIA_LOG_I("FlushEnd for filter: %s", (*it)->GetName().c_str()); (*it)->FlushEnd(); } } diff --git a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp index c4219708..b550f4e2 100644 --- a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp +++ b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp @@ -232,7 +232,7 @@ bool AudioDecoderFilter::Negotiate(const std::string& inPort, { capNegWithUpstream_ = candidate.second; selectedPluginInfo = candidate.first; - MEDIA_LOG_I("choose plugin %s as working parameter", candidate.first->name); + MEDIA_LOG_I("choose plugin %s as working parameter", candidate.first->name.c_str()); break; } } diff --git a/engine/pipeline/filters/demux/demuxer_filter.cpp b/engine/pipeline/filters/demux/demuxer_filter.cpp index dfc9b2b4..20f03dcf 100644 --- a/engine/pipeline/filters/demux/demuxer_filter.cpp +++ b/engine/pipeline/filters/demux/demuxer_filter.cpp @@ -269,33 +269,41 @@ void DemuxerFilter::InitTypeFinder() } } +bool DemuxerFilter::CreatePlugin(std::string pluginName) +{ + if (plugin_) { + plugin_->Deinit(); + } + plugin_ = Plugin::PluginManager::Instance().CreateDemuxerPlugin(pluginName); + if (!plugin_ || plugin_->Init() != Plugin::Status::OK) { + MEDIA_LOG_E("CreatePlugin %s failed.", pluginName.c_str()); + return false; + } + pluginAllocator_ = plugin_->GetAllocator(); + pluginName_.swap(pluginName); + return true; +} + bool DemuxerFilter::InitPlugin(std::string pluginName) { if (pluginName.empty()) { return false; } if (pluginName_ != pluginName) { - if (plugin_) { - plugin_->Deinit(); - } - plugin_ = Plugin::PluginManager::Instance().CreateDemuxerPlugin(pluginName); - if (!plugin_ || plugin_->Init() != Plugin::Status::OK) { - MEDIA_LOG_E("InitPlugin for %s failed.", pluginName.c_str()); + if (!CreatePlugin(std::move(pluginName))) { return false; } - pluginAllocator_ = plugin_->GetAllocator(); - pluginName_.swap(pluginName); } else { if (plugin_->Reset() != Plugin::Status::OK) { - MEDIA_LOG_E("plugin %s failed to reset.", pluginName.c_str()); - return false; + if (!CreatePlugin(std::move(pluginName))) { + return false; + } } } MEDIA_LOG_W("InitPlugin, %s used.", pluginName_.c_str()); - plugin_->SetDataSource(std::dynamic_pointer_cast(dataSource_)); + (void)plugin_->SetDataSource(std::dynamic_pointer_cast(dataSource_)); pluginState_ = DemuxerState::DEMUXER_STATE_PARSE_HEADER; - plugin_->Prepare(); - return true; + return plugin_->Prepare() == Plugin::Status::OK; } void DemuxerFilter::ActivatePullMode() diff --git a/engine/pipeline/filters/demux/demuxer_filter.h b/engine/pipeline/filters/demux/demuxer_filter.h index 5677e37f..a1cf40bd 100644 --- a/engine/pipeline/filters/demux/demuxer_filter.h +++ b/engine/pipeline/filters/demux/demuxer_filter.h @@ -18,16 +18,16 @@ #include #include +#include "core/filter_base.h" +#include "data_packer.h" #include "osal/thread/mutex.h" #include "osal/thread/task.h" -#include "utils/type_define.h" -#include "utils/utils.h" #include "plugin/common/plugin_types.h" -#include "plugin/core/plugin_meta.h" #include "plugin/core/demuxer.h" +#include "plugin/core/plugin_meta.h" #include "type_finder.h" -#include "data_packer.h" -#include "core/filter_base.h" +#include "utils/type_define.h" +#include "utils/utils.h" namespace OHOS { namespace Media { @@ -93,6 +93,8 @@ private: void InitTypeFinder(); + bool CreatePlugin(std::string pluginName); + bool InitPlugin(std::string pluginName); void ActivatePullMode(); diff --git a/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp b/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp index 8e33fc03..7ded26fb 100644 --- a/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp +++ b/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp @@ -19,6 +19,7 @@ #include "common/plugin_utils.h" #include "factory/filter_factory.h" #include "foundation/log.h" +#include "foundation/osal/utils/util.h" #include "pipeline/filters/common/plugin_settings.h" namespace OHOS { @@ -100,7 +101,7 @@ bool AudioSinkFilter::Negotiate(const std::string& inPort, const std::shared_ptr upstreamNegotiatedCap = candidatePlugins[0].second; // try to reuse plugin - if (plugin_ != nullptr){ + if (plugin_ != nullptr) { if (targetPluginInfo_ != nullptr && targetPluginInfo_->name == selectedPluginInfo->name) { if (plugin_->Reset() == Plugin::Status::OK) { return true; @@ -143,14 +144,12 @@ bool AudioSinkFilter::Configure(const std::string& inPort, const std::shared_ptr return true; } - ErrorCode AudioSinkFilter::ConfigureWithMeta(const std::shared_ptr& meta) { auto parameterMap = PluginParameterTable::FindAllowedParameterMap(filterType_); for (const auto& keyPair : parameterMap) { Plugin::ValueType outValue; - if (meta->GetData(static_cast(keyPair.first), outValue) && - keyPair.second.second(outValue)) { + if (meta->GetData(static_cast(keyPair.first), outValue) && keyPair.second.second(outValue)) { SetPluginParameter(keyPair.first, outValue); } else { MEDIA_LOG_W("parameter %s in meta is not found or type mismatch", keyPair.second.first.c_str()); @@ -190,20 +189,19 @@ ErrorCode AudioSinkFilter::PushData(const std::string& inPort, AVBufferPtr buffe MEDIA_LOG_I("PushData return due to: isFlushing = %d, state = %d", isFlushing, static_cast(state_.load())); return ErrorCode::SUCCESS; } - + auto err = TranslatePluginStatus(plugin_->Write(buffer)); + RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "audio sink write failed"); if ((buffer->flag & BUFFER_FLAG_EOS) != 0) { + constexpr int waitTimeForPlaybackCompleteMs = 60; + OHOS::Media::OSAL::SleepFor(waitTimeForPlaybackCompleteMs); Event event{ .type = EVENT_COMPLETE, }; MEDIA_LOG_D("audio sink push data send event_complete"); OnEvent(event); - MEDIA_LOG_D("audio sink push data end"); - return ErrorCode::SUCCESS; } - auto err = TranslatePluginStatus(plugin_->Write(buffer)); - RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "audio sink write failed"); MEDIA_LOG_D("audio sink push data end"); - return err; + return ErrorCode::SUCCESS; } ErrorCode AudioSinkFilter::Start() @@ -275,12 +273,14 @@ void AudioSinkFilter::FlushStart() if (pushThreadIsBlocking) { startWorkingCondition_.NotifyOne(); } + plugin_->Pause(); plugin_->Flush(); } void AudioSinkFilter::FlushEnd() { MEDIA_LOG_D("audio sink flush end entered"); + plugin_->Resume(); isFlushing = false; } diff --git a/engine/plugin/plugins/hdi_adapter/BUILD.gn b/engine/plugin/plugins/hdi_adapter/BUILD.gn index 13ac054e..5b06d4e9 100644 --- a/engine/plugin/plugins/hdi_adapter/BUILD.gn +++ b/engine/plugin/plugins/hdi_adapter/BUILD.gn @@ -29,9 +29,7 @@ if (defined(ohos_lite)) { ] config("plugin_hdi_adapter_config") { - include_dirs = [ - "//drivers/peripheral/audio/interfaces/include", - ] + include_dirs = [ "//drivers/peripheral/audio/interfaces/include" ] ldflags = [ "-lhdi_videodisplayer" ] } diff --git a/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp b/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp index cd8f30cc..13ceec7d 100644 --- a/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp +++ b/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp @@ -81,7 +81,7 @@ Status LoadAndInitAdapter(AudioManager* audioManager, AudioAdapterDescriptor* de void UpdatePluginCapWithPortCap(const AudioPortCapability& portCap, Capability& pluginCap) { - for(size_t cnt = 0; cnt < portCap.formatNum; cnt++) { + for (size_t cnt = 0; cnt < portCap.formatNum; cnt++) { auto pluginCaps = OHOS::Media::HosLitePlugin::HdiAuFormat2PluginFormat(portCap.formats[cnt]); if (pluginCaps.empty()) { continue; @@ -109,7 +109,7 @@ void UpdatePluginCapWithPortCap(const AudioPortCapability& portCap, Capability& } } -std::shared_ptr AudioSinkPluginCreator(const std::string &name) +std::shared_ptr AudioSinkPluginCreator(const std::string& name) { return std::make_shared(name); } @@ -213,12 +213,7 @@ namespace HosLitePlugin { using namespace OHOS::Media::Plugin; HdiSink::HdiSink(std::string name) - : Plugin::AudioSinkPlugin(std::move(name)), - audioManager_(nullptr), - cacheData_(), - bufferQueue_("HdiSinkQueue"), - currBuffer_(nullptr), - currBufferOffset_(0) + : Plugin::AudioSinkPlugin(std::move(name)), audioManager_(nullptr), cacheData_(), processing_(false), renderCond_() { // default is media sampleAttributes_.type = AUDIO_IN_MEDIA; @@ -257,10 +252,6 @@ Status HdiSink::Init() MEDIA_LOG_E("cannot find adapter with name %s", pluginName_.c_str()); return Status::ERROR_UNKNOWN; } - if (!renderThread_) { - renderThread_ = std::make_shared("auRenderThread", OSAL::ThreadPriority::HIGHEST); - renderThread_->RegisterHandler([this] { DoRender(); }); - } return Status::OK; } @@ -280,9 +271,6 @@ Status HdiSink::Deinit() { MEDIA_LOG_E("Deinit entered."); Stop(); - if (renderThread_ != nullptr) { - renderThread_->Stop(); - } // release all resources ReleaseRender(); if (audioManager_ != nullptr) { @@ -360,8 +348,9 @@ Status HdiSink::GetParameter(Tag tag, ValueType& value) Status HdiSink::Prepare() { sampleAttributes_.frameSize = GetPcmBytes(sampleAttributes_.format) * sampleAttributes_.channelCount; - sampleAttributes_.startThreshold = sampleAttributes_.period / sampleAttributes_.frameSize; + sampleAttributes_.startThreshold = sampleAttributes_.period * sampleAttributes_.frameSize; sampleAttributes_.stopThreshold = INT32_MAX; + sampleAttributes_.silenceThreshold = 0; if (g_sinkInfos.count(pluginName_) == 0) { MEDIA_LOG_E("cannot find out port"); return Status::ERROR_UNKNOWN; @@ -399,6 +388,7 @@ Status HdiSink::Reset() (void)memset_s(&sampleAttributes_, sizeof(sampleAttributes_), 0, sizeof(sampleAttributes_)); (void)memset_s(&deviceDescriptor_, sizeof(deviceDescriptor_), 0, sizeof(deviceDescriptor_)); isInputInterleaved_ = false; + processing_ = false; channelMask_ = AUDIO_CHANNEL_MONO; return Status::OK; @@ -407,44 +397,33 @@ Status HdiSink::Reset() Status HdiSink::Start() { MEDIA_LOG_D("Start entered."); - { - OHOS::Media::OSAL::ScopedLock lock(renderMutex_); - if (audioRender_ == nullptr) { - MEDIA_LOG_E("no available render"); - return Status::ERROR_UNKNOWN; - } + OHOS::Media::OSAL::ScopedLock lock(renderMutex_); + if (audioRender_ == nullptr) { + MEDIA_LOG_E("no available render"); + return Status::ERROR_UNKNOWN; + } - if (audioRender_->control.Start(audioRender_) != 0) { - MEDIA_LOG_E("audio render start error"); - return Status::ERROR_UNKNOWN; - } + if (audioRender_->control.Start(audioRender_) != 0) { + MEDIA_LOG_E("audio render start error"); + return Status::ERROR_UNKNOWN; } - bufferQueue_.SetActive(true); - shouldRenderFrame_ = true; - renderThread_->Start(); + processing_ = true; return Status::OK; } Status HdiSink::Stop() { MEDIA_LOG_D("Stop Entered"); - shouldRenderFrame_ = false; - bufferQueue_.SetActive(false); - renderThread_->Pause(); - currBuffer_ = nullptr; - { - OHOS::Media::OSAL::ScopedLock lock(renderMutex_); - if (audioRender_ == nullptr) { - MEDIA_LOG_E("no available render"); - return Status::OK; - } - if (audioRender_->control.Flush(audioRender_) != 0) { - MEDIA_LOG_E("audio render flush error"); - } - if (audioRender_->control.Stop(audioRender_) != 0) { - MEDIA_LOG_E("audio render stop error"); - return Status::ERROR_UNKNOWN; - } + OHOS::Media::OSAL::ScopedLock lock(renderMutex_); + processing_ = false; + renderCond_.NotifyOne(); + if (audioRender_ == nullptr) { + MEDIA_LOG_E("no available render"); + return Status::OK; + } + if (audioRender_->control.Stop(audioRender_) != 0) { + MEDIA_LOG_E("audio render stop error"); + return Status::ERROR_UNKNOWN; } MEDIA_LOG_D("Stop Exited"); return Status::OK; @@ -558,14 +537,12 @@ Status HdiSink::SetSpeed(float speed) Status HdiSink::Pause() { MEDIA_LOG_D("Pause Entered"); - shouldRenderFrame_ = false; - renderThread_->Pause(); - { - OHOS::Media::OSAL::ScopedLock lock(renderMutex_); - if (audioRender_ != nullptr && audioRender_->control.Pause(audioRender_) != 0) { - MEDIA_LOG_E("pause failed"); - return Status::ERROR_UNKNOWN; - } + OHOS::Media::OSAL::ScopedLock lock(renderMutex_); + processing_ = false; + renderCond_.NotifyOne(); + if (audioRender_ != nullptr && audioRender_->control.Pause(audioRender_) != 0) { + MEDIA_LOG_E("pause failed"); + return Status::ERROR_UNKNOWN; } return Status::OK; } @@ -573,15 +550,12 @@ Status HdiSink::Pause() Status HdiSink::Resume() { MEDIA_LOG_D("Resume Entered"); - { - OHOS::Media::OSAL::ScopedLock lock(renderMutex_); - if (audioRender_ != nullptr && audioRender_->control.Resume(audioRender_) != 0) { - MEDIA_LOG_E("resume failed"); - return Status::ERROR_UNKNOWN; - } + OHOS::Media::OSAL::ScopedLock lock(renderMutex_); + processing_ = true; + if (audioRender_ != nullptr && audioRender_->control.Resume(audioRender_) != 0) { + MEDIA_LOG_E("resume failed"); + return Status::ERROR_UNKNOWN; } - shouldRenderFrame_ = true; - renderThread_->Start(); return Status::OK; } @@ -616,29 +590,35 @@ Status HdiSink::GetFrameCount(uint32_t& count) Status HdiSink::Write(const std::shared_ptr& input) { MEDIA_LOG_D("Write begin."); - if (input != nullptr && !input->IsEmpty()) { - bufferQueue_.Push(input); - MEDIA_LOG_D("write to ring buffer"); + if (!input) { + MEDIA_LOG_E("Write failed due to nullptr."); + return Status::ERROR_INVALID_PARAMETER; } - MEDIA_LOG_D("Write finished."); - return Status::OK; + if (!input->IsEmpty()) { + RenderFrame(input); + MEDIA_LOG_D("Write finished."); + return Status::OK; + } + Status status = Status::OK; + if ((input->flag & BUFFER_FLAG_EOS) != 0) { + // TODO: call DrainBuffer, but now this function is invalid. + } else { + status = Status::ERROR_INVALID_PARAMETER; + } + return status; } Status HdiSink::Flush() { MEDIA_LOG_I("Flush Entered"); - bufferQueue_.Clear(); - { - OHOS::Media::OSAL::ScopedLock lock(renderMutex_); - if (audioRender_ == nullptr) { - MEDIA_LOG_E("no render available, flush must be called after prepare"); - return Status::ERROR_WRONG_STATE; - } - - if (audioRender_->control.Flush(audioRender_) != 0) { - MEDIA_LOG_E("audio render flush error"); - return Status::ERROR_UNKNOWN; - } + OHOS::Media::OSAL::ScopedLock lock(renderMutex_); + if (audioRender_ == nullptr) { + MEDIA_LOG_E("no render available, flush must be called after prepare"); + return Status::ERROR_WRONG_STATE; + } + if (audioRender_->control.Flush(audioRender_) != 0) { + MEDIA_LOG_E("audio render flush error"); + return Status::ERROR_UNKNOWN; } MEDIA_LOG_I("Flush Exited."); return Status::OK; @@ -699,48 +679,39 @@ bool HdiSink::HandleInterleaveData(uint8_t* origData, int32_t frameCnt) return isHandled; } -void HdiSink::DoRender() +void HdiSink::RenderFrame(const std::shared_ptr& input) { MEDIA_LOG_D("DoRender started"); - if (!shouldRenderFrame_.load()) { - return; - } - if (!currBuffer_) { - currBuffer_ = bufferQueue_.Pop(); - if (currBuffer_ == nullptr) { - return; - } - currBufferOffset_ = 0; - } - auto mem = currBuffer_->GetMemory(); - size_t outSize = mem->GetSize() - currBufferOffset_; - auto frame = const_cast(mem->GetReadOnlyData()) + currBufferOffset_; - uint64_t renderSize = 0; - auto ret = 0; - { - OHOS::Media::OSAL::ScopedLock lock(renderMutex_); - if (audioRender_ != nullptr) { - if (HandleInterleaveData(frame, outSize / PCM_CHAN_CNT)) { + auto mem = input->GetMemory(); + auto frame = const_cast(mem->GetReadOnlyData()); + bool dataInterleaved = false; + for (size_t remainingBytes = mem->GetSize(); processing_.load() && remainingBytes > 0;) { + int32_t ret = 0; + uint64_t renderSize = 0; + { + OHOS::Media::OSAL::ScopedLock lock(renderMutex_); + if (audioRender_ == nullptr) { + break; + } + if (!dataInterleaved && HandleInterleaveData(frame, remainingBytes / PCM_CHAN_CNT)) { frame = cacheData_.data(); + dataInterleaved = true; } - ret = audioRender_->RenderFrame(audioRender_, frame, outSize, &renderSize); + ret = audioRender_->RenderFrame(audioRender_, frame, remainingBytes, &renderSize); } - } - if (ret != 0) { - if (ret == HI_ERR_VI_BUF_FULL) { - MEDIA_LOG_I("renderFrame buffer full"); - constexpr int intervalMs = 5; - OHOS::Media::OSAL::SleepFor(intervalMs); - } else { - MEDIA_LOG_E("renderFrame error with code %" PRIu64 "x", static_cast(ret)); + if (ret != 0) { + if (ret == HI_ERR_VI_BUF_FULL) { + MEDIA_LOG_I("renderFrame buffer full"); + constexpr int timeoutMs = 5; + OSAL::ScopedLock lock(renderMutex_); + renderCond_.WaitFor(lock, timeoutMs, [this] { return processing_.load() == false; }); + } else { + MEDIA_LOG_E("renderFrame buffer error %d", ret); + break; + } } - return; - } - if (outSize == renderSize) { - currBuffer_ = nullptr; - MEDIA_LOG_D("render frame %" PRIu64, renderSize); - } else { - currBufferOffset_ += renderSize; + frame += renderSize; + remainingBytes -= renderSize; } } } // namespace HosLitePlugin diff --git a/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.h b/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.h index f5cdcd9e..64f1399c 100644 --- a/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.h +++ b/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.h @@ -18,13 +18,12 @@ #include #include +#include "audio_manager.h" #include "audio_types.h" -#include "foundation/osal/thread/mutex.h" #include "foundation/osal/thread/condition_variable.h" +#include "foundation/osal/thread/mutex.h" #include "foundation/osal/thread/task.h" #include "plugin/interface/audio_sink_plugin.h" -#include "audio_manager.h" -#include "utils/blocking_queue.h" struct AudioAdapter; struct AudioRender; @@ -54,24 +53,23 @@ public: bool IsParameterSupported(Media::Plugin::Tag tag) override; - Media::Plugin::Status GetParameter(Media::Plugin::Tag tag, Media::Plugin::ValueType &value) override; + Media::Plugin::Status GetParameter(Media::Plugin::Tag tag, Media::Plugin::ValueType& value) override; - Media::Plugin::Status - SetParameter(Media::Plugin::Tag tag, const Media::Plugin::ValueType &value) override; + Media::Plugin::Status SetParameter(Media::Plugin::Tag tag, const Media::Plugin::ValueType& value) override; std::shared_ptr GetAllocator() override; - Media::Plugin::Status SetCallback(const std::shared_ptr &cb) override; + Media::Plugin::Status SetCallback(const std::shared_ptr& cb) override; - Media::Plugin::Status GetMute(bool &mute) override; + Media::Plugin::Status GetMute(bool& mute) override; Media::Plugin::Status SetMute(bool mute) override; - Media::Plugin::Status GetVolume(float &volume) override; + Media::Plugin::Status GetVolume(float& volume) override; Media::Plugin::Status SetVolume(float volume) override; - Media::Plugin::Status GetSpeed(float &speed) override; + Media::Plugin::Status GetSpeed(float& speed) override; Media::Plugin::Status SetSpeed(float speed) override; @@ -79,13 +77,13 @@ public: Media::Plugin::Status Resume() override; - Media::Plugin::Status GetLatency(uint64_t &ms) override; + Media::Plugin::Status GetLatency(uint64_t& ms) override; - Media::Plugin::Status GetFrameSize(size_t &size) override; + Media::Plugin::Status GetFrameSize(size_t& size) override; - Media::Plugin::Status GetFrameCount(uint32_t &count) override; + Media::Plugin::Status GetFrameCount(uint32_t& count) override; - Media::Plugin::Status Write(const std::shared_ptr &input) override; + Media::Plugin::Status Write(const std::shared_ptr& input) override; Media::Plugin::Status Flush() override; @@ -100,15 +98,12 @@ private: bool HandleInterleaveData(uint8_t* origData, int32_t frameCnt); - void DoRender(); + void RenderFrame(const std::shared_ptr& input); Media::Plugin::Status ProcessInputSampleFormat(const Media::Plugin::ValueType& value); private: OHOS::Media::OSAL::Mutex renderMutex_ {}; - - std::atomic shouldRenderFrame_ {false}; - AudioManager* audioManager_ {nullptr}; AudioAdapterDescriptor adapterDescriptor_ {}; AudioAdapter* audioAdapter_ {nullptr}; @@ -116,17 +111,14 @@ private: AudioDeviceDescriptor deviceDescriptor_ {}; AudioSampleAttributes sampleAttributes_ {}; bool isInputInterleaved_{false}; - AudioChannelMask channelMask_ {AUDIO_CHANNEL_MONO}; - - std::weak_ptr eventCallback_ {}; - std::shared_ptr renderThread_ {}; + AudioChannelMask channelMask_{AUDIO_CHANNEL_MONO}; + std::weak_ptr eventCallback_{}; std::vector cacheData_; - BlockingQueue> bufferQueue_; - std::shared_ptr currBuffer_; - size_t currBufferOffset_; bool usingDefaultInCaps_ {true}; // if true pass hdi with S16P pcm data and convert input into non-interleaved + std::atomic processing_; + OSAL::ConditionVariable renderCond_; }; -} -} -} +} // namespace HosLitePlugin +} // namespace Media +} // namespace OHOS #endif diff --git a/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp b/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp index c82204ef..0e0f6db0 100644 --- a/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp +++ b/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp @@ -18,11 +18,11 @@ #include "sdl_audio_sink_plugin.h" #include #include "foundation/log.h" -#include "utils/constants.h" -#include "utils/utils.h" #include "plugin/common/plugin_audio_tags.h" #include "plugin/common/plugin_buffer.h" #include "plugins/ffmpeg_adapter/utils/ffmpeg_utils.h" +#include "utils/constants.h" +#include "utils/utils.h" namespace { using namespace OHOS::Media::Plugin; diff --git a/engine/plugin/plugins/source/file_source/file_source_plugin.cpp b/engine/plugin/plugins/source/file_source/file_source_plugin.cpp index 8479ebdc..a0ae24c0 100644 --- a/engine/plugin/plugins/source/file_source/file_source_plugin.cpp +++ b/engine/plugin/plugins/source/file_source/file_source_plugin.cpp @@ -172,7 +172,7 @@ Status FileSourcePlugin::Read(std::shared_ptr& buffer, size_t expectedLe expectedLen = std::min(static_cast(fileSize_ - position_), expectedLen); expectedLen = std::min(bufData->GetCapacity(), expectedLen); - MEDIA_LOG_I("buffer position %zu, expectedLen %zu", position_, expectedLen); + MEDIA_LOG_I("buffer position %" PRIu64 ", expectedLen %zu", position_, expectedLen); auto size = std::fread(bufData->GetWritableData(expectedLen), sizeof(char), expectedLen, fp_); bufData->GetWritableData(size); position_ += bufData->GetSize(); -- Gitee From 1aca6637358afd17a0631e753969e37cfa6244ad Mon Sep 17 00:00:00 2001 From: ancimoon Date: Tue, 9 Nov 2021 09:44:56 +0000 Subject: [PATCH 12/22] !115 refctor log Signed-off-by: Hu Chang --- engine/foundation/log.h | 56 +++++++++---------- .../osal/thread/condition_variable.cpp | 2 +- engine/foundation/osal/thread/mutex.cpp | 2 +- engine/foundation/osal/thread/scoped_lock.cpp | 2 +- engine/foundation/osal/thread/task.cpp | 3 +- engine/foundation/osal/thread/thread.cpp | 4 +- engine/pipeline/core/compatible_check.cpp | 2 +- engine/pipeline/core/filter_base.cpp | 2 +- engine/pipeline/core/pipeline_core.cpp | 2 + engine/pipeline/core/port.cpp | 2 +- .../audio_decoder/audio_decoder_filter.cpp | 5 +- .../filters/codec/decoder_filter_base.cpp | 2 +- .../video_decoder/video_decoder_filter.cpp | 2 +- engine/pipeline/filters/demux/data_packer.cpp | 2 +- .../pipeline/filters/demux/demuxer_filter.cpp | 17 +++--- engine/pipeline/filters/demux/type_finder.cpp | 6 +- .../sink/audio_sink/audio_sink_filter.cpp | 14 ++--- .../sink/video_sink/video_sink_filter.cpp | 2 +- .../filters/source/media_source_filter.cpp | 16 +++--- engine/player/hiplayer.cpp | 4 +- engine/player/hiplayer_impl.cpp | 2 +- engine/player/internal/state.cpp | 2 +- engine/player/internal/state_machine.cpp | 2 +- engine/plugin/core/audio_sink.cpp | 2 +- engine/plugin/core/base.cpp | 26 ++++----- engine/plugin/core/video_sink.cpp | 2 +- .../audio_ffmpeg_decoder_plugin.cpp | 8 ++- .../demuxer/ffmpeg_demuxer_plugin.cpp | 6 +- .../utils/aac_audio_config_parser.cpp | 2 +- .../utils/avc_config_data_parser.cpp | 2 +- .../video_ffmpeg_decoder_plugin.cpp | 2 +- .../plugins/hdi_adapter/sink/hos_au_sink.cpp | 21 +++---- .../hdi_adapter/utils/hdi_au_utils.cpp | 2 +- .../sdl/audio_sink/sdl_audio_sink_plugin.cpp | 2 +- .../sdl/video_sink/sdl_video_sink_plugin.cpp | 2 +- .../source/file_source/file_source_plugin.cpp | 7 +-- .../stream_source/stream_source_plugin.cpp | 2 +- 37 files changed, 120 insertions(+), 119 deletions(-) diff --git a/engine/foundation/log.h b/engine/foundation/log.h index 7e96cc57..4bc863e5 100644 --- a/engine/foundation/log.h +++ b/engine/foundation/log.h @@ -26,49 +26,43 @@ #ifdef MEDIA_OHOS #include "hilog/log.h" #include "media_log.h" +#else +#include "log_adapter.h" #endif -inline std::string MediaGetFileName(std::string file) -{ - if (file == "") { - return "Unknown File"; - } - - return file.substr(file.find_last_of("/\\") + 1); -} +#ifndef HST_LOG_TAG +#define HST_LOG_TAG "NULL" +#endif -#ifndef LOG_TAG -#define LOG_TAG "NULL" +#ifdef MEDIA_OHOS +#ifndef OHOS_DEBUG +#define HST_DECORATOR_HILOG(op, fmt, args...) \ + do { \ + op(LOG_CORE, "%s:" fmt, HST_LOG_TAG, ##args); \ + } while (0) +#else +#define HST_DECORATOR_HILOG(op, fmt, args...)\ + do { \ + op(LOG_CORE, "%s[%d]:" fmt, HST_LOG_TAG, __LINE__, ##args); \ + } while (0) #endif -// Control the logd and logi. -// If logd and logi are needed, #define MEDIA_LOG_DEBUG 1 at the beginning of the cpp file. -#ifndef MEDIA_LOG_DEBUG -#define MEDIA_LOG_DEBUG 0 +#define MEDIA_LOG_D(fmt, ...) HST_DECORATOR_HILOG(HILOG_DEBUG, fmt, ##__VA_ARGS__) +#define MEDIA_LOG_I(fmt, ...) HST_DECORATOR_HILOG(HILOG_INFO, fmt, ##__VA_ARGS__) +#define MEDIA_LOG_W(fmt, ...) HST_DECORATOR_HILOG(HILOG_WARN, fmt, ##__VA_ARGS__) +#define MEDIA_LOG_E(fmt, ...) HST_DECORATOR_HILOG(HILOG_ERROR, fmt, ##__VA_ARGS__) +#define MEDIA_LOG_F(fmt, ...) HST_DECORATOR_HILOG(HILOG_FATAL, fmt, ##__VA_ARGS__) #endif -#define MEDIA_LOG_MESSAGE(level, msg, ...) \ - do { \ - std::string file(__FILE__); \ - std::string bareFile = MediaGetFileName(file); \ - printf("%lu " LOG_TAG " " level " (%s, %d) : Func(%s) " msg "\n", pthread_self(), bareFile.c_str(), __LINE__, \ - __FUNCTION__, ##__VA_ARGS__); \ - fflush(stdout); \ - } while (0) -#ifdef MEDIA_OHOS -#define MEDIA_LOG_E(msg, ...) MEDIA_ERR_LOG(msg, ##__VA_ARGS__) -#define MEDIA_LOG_W(msg, ...) MEDIA_WARNING_LOG(msg, ##__VA_ARGS__) -#define MEDIA_LOG_I(msg, ...) MEDIA_INFO_LOG(msg, ##__VA_ARGS__) -#define MEDIA_LOG_D(msg, ...) MEDIA_DEBUG_LOG(msg, ##__VA_ARGS__) -#else -#include "log_adapter.h" +// Control the MEDIA_LOG_D. +// If MEDIA_LOG_D is needed, #define MEDIA_LOG_DEBUG 1 at the beginning of the cpp file. +#ifndef MEDIA_LOG_DEBUG +#define MEDIA_LOG_DEBUG 0 #endif #if !MEDIA_LOG_DEBUG -#undef MEDIA_LOG_I #undef MEDIA_LOG_D -#define MEDIA_LOG_I(msg, ...) ((void)0) #define MEDIA_LOG_D(msg, ...) ((void)0) #endif diff --git a/engine/foundation/osal/thread/condition_variable.cpp b/engine/foundation/osal/thread/condition_variable.cpp index 313cc32f..0e2cbee5 100644 --- a/engine/foundation/osal/thread/condition_variable.cpp +++ b/engine/foundation/osal/thread/condition_variable.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "ConditionVariable" +#define HST_LOG_TAG "ConditionVariable" #include "condition_variable.h" #include "foundation/log.h" diff --git a/engine/foundation/osal/thread/mutex.cpp b/engine/foundation/osal/thread/mutex.cpp index b609c4b7..ef6c2b3a 100644 --- a/engine/foundation/osal/thread/mutex.cpp +++ b/engine/foundation/osal/thread/mutex.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "Mutex" +#define HST_LOG_TAG "Mutex" #include "mutex.h" #include "foundation/log.h" diff --git a/engine/foundation/osal/thread/scoped_lock.cpp b/engine/foundation/osal/thread/scoped_lock.cpp index 6343554a..0aef0b9b 100644 --- a/engine/foundation/osal/thread/scoped_lock.cpp +++ b/engine/foundation/osal/thread/scoped_lock.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "ScopedLock" +#define HST_LOG_TAG "ScopedLock" #include "scoped_lock.h" diff --git a/engine/foundation/osal/thread/task.cpp b/engine/foundation/osal/thread/task.cpp index 3270c858..56f67788 100644 --- a/engine/foundation/osal/thread/task.cpp +++ b/engine/foundation/osal/thread/task.cpp @@ -13,12 +13,11 @@ * limitations under the License. */ -#define LOG_TAG "Task" +#define HST_LOG_TAG "Task" #include "task.h" #include "foundation/log.h" -#include "utils/util.h" namespace OHOS { namespace Media { diff --git a/engine/foundation/osal/thread/thread.cpp b/engine/foundation/osal/thread/thread.cpp index 52076bc3..b390e4b3 100644 --- a/engine/foundation/osal/thread/thread.cpp +++ b/engine/foundation/osal/thread/thread.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "Thread" +#define HST_LOG_TAG "Thread" #include "thread.h" #include "foundation/log.h" @@ -77,7 +77,7 @@ bool Thread::CreateThread(const std::function& func) #endif int rtv = pthread_create(&id_, &attr, Thread::Run, state_.get()); if (rtv == 0) { - MEDIA_LOG_I("thread %d, id %s create succ", pthread_self(), name_.c_str()); + MEDIA_LOG_I("thread %s, id %" PRIu64 " create succ", name_.c_str(), pthread_self()); SetNameInternal(); } else { state_.reset(); diff --git a/engine/pipeline/core/compatible_check.cpp b/engine/pipeline/core/compatible_check.cpp index 0a3e0e3d..344500c3 100644 --- a/engine/pipeline/core/compatible_check.cpp +++ b/engine/pipeline/core/compatible_check.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "Compatible_Check" +#define HST_LOG_TAG "Compatible_Check" #include "compatible_check.h" diff --git a/engine/pipeline/core/filter_base.cpp b/engine/pipeline/core/filter_base.cpp index cfad5f44..5e48ea0b 100644 --- a/engine/pipeline/core/filter_base.cpp +++ b/engine/pipeline/core/filter_base.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "FilterBase" +#define HST_LOG_TAG "FilterBase" #include "filter_base.h" #include diff --git a/engine/pipeline/core/pipeline_core.cpp b/engine/pipeline/core/pipeline_core.cpp index 4fdee1c0..c64d70c4 100644 --- a/engine/pipeline/core/pipeline_core.cpp +++ b/engine/pipeline/core/pipeline_core.cpp @@ -13,6 +13,8 @@ * limitations under the License. */ +#define HST_LOG_TAG "PipelineCore" + #include "pipeline_core.h" #include #include "foundation/log.h" diff --git a/engine/pipeline/core/port.cpp b/engine/pipeline/core/port.cpp index d51f40de..417fa298 100644 --- a/engine/pipeline/core/port.cpp +++ b/engine/pipeline/core/port.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "FilterPort" +#define HST_LOG_TAG "FilterPort" #include "port.h" #include diff --git a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp index b550f4e2..a8c9c379 100644 --- a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp +++ b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "AudioDecoderFilter" +#define HST_LOG_TAG "AudioDecoderFilter" #include "audio_decoder_filter.h" #include "osal/utils/util.h" @@ -148,7 +148,7 @@ ErrorCode AudioDecoderFilter::QueueAllBufferInPoolToPluginLocked() ErrorCode AudioDecoderFilter::Start() { - MEDIA_LOG_D("audio decoder start called"); + MEDIA_LOG_I("audio decoder start called"); if (state_ != FilterState::READY && state_ != FilterState::PAUSED) { MEDIA_LOG_W("call decoder start() when state is not ready or working"); return ErrorCode::ERROR_INVALID_OPERATION; @@ -158,6 +158,7 @@ ErrorCode AudioDecoderFilter::Start() ErrorCode AudioDecoderFilter::Prepare() { + MEDIA_LOG_I("audio decoder prepare called"); if (state_ != FilterState::INITIALIZED) { MEDIA_LOG_W("decoder filter is not in init state"); return ErrorCode::ERROR_INVALID_OPERATION; diff --git a/engine/pipeline/filters/codec/decoder_filter_base.cpp b/engine/pipeline/filters/codec/decoder_filter_base.cpp index b5b7a697..fd1a7053 100644 --- a/engine/pipeline/filters/codec/decoder_filter_base.cpp +++ b/engine/pipeline/filters/codec/decoder_filter_base.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "AudioDecoderFilter" +#define HST_LOG_TAG "DecoderFilterBase" #include "decoder_filter_base.h" diff --git a/engine/pipeline/filters/codec/video_decoder/video_decoder_filter.cpp b/engine/pipeline/filters/codec/video_decoder/video_decoder_filter.cpp index 46361e77..2781df3d 100644 --- a/engine/pipeline/filters/codec/video_decoder/video_decoder_filter.cpp +++ b/engine/pipeline/filters/codec/video_decoder/video_decoder_filter.cpp @@ -15,7 +15,7 @@ #ifdef VIDEO_SUPPORT -#define LOG_TAG "VideoDecoderFilter" +#define HST_LOG_TAG "VideoDecoderFilter" #include "video_decoder_filter.h" #include "foundation/log.h" diff --git a/engine/pipeline/filters/demux/data_packer.cpp b/engine/pipeline/filters/demux/data_packer.cpp index a7db7441..dad87fcb 100644 --- a/engine/pipeline/filters/demux/data_packer.cpp +++ b/engine/pipeline/filters/demux/data_packer.cpp @@ -272,7 +272,7 @@ AVBufferPtr DataPacker::WrapAssemblerBuffer(uint64_t offset) void DataPacker::Flush() { - MEDIA_LOG_D("DataPacker Flush called."); + MEDIA_LOG_I("DataPacker Flush called."); OSAL::ScopedLock lock(mutex_); que_.clear(); size_ = 0; diff --git a/engine/pipeline/filters/demux/demuxer_filter.cpp b/engine/pipeline/filters/demux/demuxer_filter.cpp index 20f03dcf..f6b0f68a 100644 --- a/engine/pipeline/filters/demux/demuxer_filter.cpp +++ b/engine/pipeline/filters/demux/demuxer_filter.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "DemuxerFilter" +#define HST_LOG_TAG "DemuxerFilter" #include "demuxer_filter.h" #include @@ -129,6 +129,7 @@ void DemuxerFilter::Init(EventReceiver* receiver, FilterCallback* callback) ErrorCode DemuxerFilter::Start() { + MEDIA_LOG_I("Start called."); if (task_) { task_->Start(); } @@ -158,13 +159,13 @@ ErrorCode DemuxerFilter::Stop() ErrorCode DemuxerFilter::Pause() { - MEDIA_LOG_D("Pause called"); + MEDIA_LOG_I("Pause called"); return FilterBase::Pause(); } void DemuxerFilter::FlushStart() { - MEDIA_LOG_D("FlushStart entered"); + MEDIA_LOG_I("FlushStart entered"); if (dataPacker_) { dataPacker_->Flush(); } @@ -175,12 +176,12 @@ void DemuxerFilter::FlushStart() void DemuxerFilter::FlushEnd() { - MEDIA_LOG_D("FlushEnd entered"); + MEDIA_LOG_I("FlushEnd entered"); } ErrorCode DemuxerFilter::Prepare() { - MEDIA_LOG_D("Prepare called"); + MEDIA_LOG_I("Prepare called"); pluginState_ = DemuxerState::DEMUXER_STATE_NULL; Pipeline::WorkMode mode; GetInPort(PORT_NAME_DEFAULT)->Activate({Pipeline::WorkMode::PULL, Pipeline::WorkMode::PUSH}, mode); @@ -300,7 +301,7 @@ bool DemuxerFilter::InitPlugin(std::string pluginName) } } } - MEDIA_LOG_W("InitPlugin, %s used.", pluginName_.c_str()); + MEDIA_LOG_I("InitPlugin, %s used.", pluginName_.c_str()); (void)plugin_->SetDataSource(std::dynamic_pointer_cast(dataSource_)); pluginState_ = DemuxerState::DEMUXER_STATE_PARSE_HEADER; return plugin_->Prepare() == Plugin::Status::OK; @@ -373,7 +374,7 @@ bool DemuxerFilter::IsOffsetValid(int64_t offset) const bool DemuxerFilter::PrepareStreams(const Plugin::MediaInfoHelper& mediaInfo) { - MEDIA_LOG_D("PrepareStreams called"); + MEDIA_LOG_I("PrepareStreams called"); InitMediaMetaData(mediaInfo); outPorts_.clear(); int streamCnt = mediaInfo.trackMeta.size(); @@ -439,7 +440,7 @@ std::shared_ptr DemuxerFilter::GetStreamMeta(uint32_t streamIndex) void DemuxerFilter::SendEventEos() { - MEDIA_LOG_D("SendEventEos called"); + MEDIA_LOG_I("SendEventEos called"); AVBufferPtr bufferPtr = std::make_shared(); bufferPtr->flag = BUFFER_FLAG_EOS; for (const auto& stream : mediaMetaData_.trackInfos) { diff --git a/engine/pipeline/filters/demux/type_finder.cpp b/engine/pipeline/filters/demux/type_finder.cpp index 626cda3f..18f35273 100644 --- a/engine/pipeline/filters/demux/type_finder.cpp +++ b/engine/pipeline/filters/demux/type_finder.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "TypeFinder" +#define HST_LOG_TAG "TypeFinder" #include "type_finder.h" #include @@ -63,12 +63,12 @@ TypeFinder::TypeFinder() peekRange_(), typeFound_() { - MEDIA_LOG_I("TypeFinder ctor called..."); + MEDIA_LOG_D("TypeFinder ctor called..."); } TypeFinder::~TypeFinder() { - MEDIA_LOG_I("TypeFinder dtor called..."); + MEDIA_LOG_D("TypeFinder dtor called..."); if (task_) { task_->Stop(); } diff --git a/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp b/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp index 7ded26fb..a1aa0eb1 100644 --- a/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp +++ b/engine/pipeline/filters/sink/audio_sink/audio_sink_filter.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "AudioSinkFilter" +#define HST_LOG_TAG "AudioSinkFilter" #include "audio_sink_filter.h" #include "common/plugin_utils.h" @@ -83,7 +83,7 @@ ErrorCode AudioSinkFilter::GetParameter(int32_t key, Plugin::Any& value) bool AudioSinkFilter::Negotiate(const std::string& inPort, const std::shared_ptr& upstreamCap, Capability& upstreamNegotiatedCap) { - MEDIA_LOG_D("audio sink negotiate started"); + MEDIA_LOG_I("audio sink negotiate started"); auto candidatePlugins = FindAvailablePlugins(*upstreamCap, Plugin::PluginType::AUDIO_SINK); if (candidatePlugins.empty()) { MEDIA_LOG_E("no available audio sink plugin"); @@ -206,7 +206,7 @@ ErrorCode AudioSinkFilter::PushData(const std::string& inPort, AVBufferPtr buffe ErrorCode AudioSinkFilter::Start() { - MEDIA_LOG_D("start called"); + MEDIA_LOG_I("start called"); if (state_ != FilterState::READY && state_ != FilterState::PAUSED) { MEDIA_LOG_W("sink is not ready when start, state: %d", state_.load()); return ErrorCode::ERROR_INVALID_OPERATION; @@ -240,7 +240,7 @@ ErrorCode AudioSinkFilter::Stop() ErrorCode AudioSinkFilter::Pause() { - MEDIA_LOG_D("audio sink filter pause start"); + MEDIA_LOG_I("audio sink filter pause start"); // only worked when state is working if (state_ != FilterState::READY && state_ != FilterState::RUNNING) { MEDIA_LOG_W("audio sink cannot pause when not working"); @@ -254,7 +254,7 @@ ErrorCode AudioSinkFilter::Pause() } ErrorCode AudioSinkFilter::Resume() { - MEDIA_LOG_D("audio sink filter resume"); + MEDIA_LOG_I("audio sink filter resume"); // only worked when state is paused if (state_ == FilterState::PAUSED) { state_ = FilterState::RUNNING; @@ -268,7 +268,7 @@ ErrorCode AudioSinkFilter::Resume() void AudioSinkFilter::FlushStart() { - MEDIA_LOG_D("audio sink flush start entered"); + MEDIA_LOG_I("audio sink flush start entered"); isFlushing = true; if (pushThreadIsBlocking) { startWorkingCondition_.NotifyOne(); @@ -279,7 +279,7 @@ void AudioSinkFilter::FlushStart() void AudioSinkFilter::FlushEnd() { - MEDIA_LOG_D("audio sink flush end entered"); + MEDIA_LOG_I("audio sink flush end entered"); plugin_->Resume(); isFlushing = false; } diff --git a/engine/pipeline/filters/sink/video_sink/video_sink_filter.cpp b/engine/pipeline/filters/sink/video_sink/video_sink_filter.cpp index cc7f750f..4a2ce3c0 100644 --- a/engine/pipeline/filters/sink/video_sink/video_sink_filter.cpp +++ b/engine/pipeline/filters/sink/video_sink/video_sink_filter.cpp @@ -15,7 +15,7 @@ #ifdef VIDEO_SUPPORT -#define LOG_TAG "VideoSinkFilter" +#define HST_LOG_TAG "VideoSinkFilter" #include "video_sink_filter.h" diff --git a/engine/pipeline/filters/source/media_source_filter.cpp b/engine/pipeline/filters/source/media_source_filter.cpp index 943cd499..f9289ccf 100644 --- a/engine/pipeline/filters/source/media_source_filter.cpp +++ b/engine/pipeline/filters/source/media_source_filter.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "MediaSourceFilter" +#define HST_LOG_TAG "MediaSourceFilter" #include "media_source_filter.h" #include "compatible_check.h" @@ -59,7 +59,7 @@ MediaSourceFilter::~MediaSourceFilter() ErrorCode MediaSourceFilter::SetSource(const std::shared_ptr& source) { - MEDIA_LOG_D("IN"); + MEDIA_LOG_I("SetSource entered."); if (source == nullptr) { MEDIA_LOG_E("Invalid source"); return ErrorCode::ERROR_INVALID_PARAMETER_VALUE; @@ -101,7 +101,7 @@ ErrorCode MediaSourceFilter::InitPlugin(const std::shared_ptr& sour ErrorCode MediaSourceFilter::SetBufferSize(size_t size) { - MEDIA_LOG_D("IN, size: %zu", size); + MEDIA_LOG_I("SetBufferSize, size: %zu", size); bufferSize_ = size; return ErrorCode::SUCCESS; } @@ -124,7 +124,7 @@ std::vector MediaSourceFilter::GetWorkModes() ErrorCode MediaSourceFilter::Prepare() { - MEDIA_LOG_D("IN"); + MEDIA_LOG_I("Prepare entered."); if (plugin_ == nullptr) { return ErrorCode::ERROR_INVALID_OPERATION; } @@ -138,7 +138,7 @@ ErrorCode MediaSourceFilter::Prepare() ErrorCode MediaSourceFilter::Start() { - MEDIA_LOG_D("IN"); + MEDIA_LOG_I("Start entered."); if (taskPtr_) { taskPtr_->Start(); } @@ -190,7 +190,7 @@ ErrorCode MediaSourceFilter::PullData(const std::string& outPort, uint64_t offse ErrorCode MediaSourceFilter::Stop() { - MEDIA_LOG_D("IN"); + MEDIA_LOG_I("Stop entered."); if (taskPtr_) { taskPtr_->Stop(); } @@ -205,12 +205,12 @@ ErrorCode MediaSourceFilter::Stop() void MediaSourceFilter::FlushStart() { - MEDIA_LOG_D("FlushStart entered."); + MEDIA_LOG_I("FlushStart entered."); } void MediaSourceFilter::FlushEnd() { - MEDIA_LOG_D("FlushEnd entered."); + MEDIA_LOG_I("FlushEnd entered."); } void MediaSourceFilter::InitPorts() diff --git a/engine/player/hiplayer.cpp b/engine/player/hiplayer.cpp index aa3f9f6d..18077ecd 100644 --- a/engine/player/hiplayer.cpp +++ b/engine/player/hiplayer.cpp @@ -13,16 +13,18 @@ * limitations under the License. */ -#define LOG_TAG "HiPlayer" +#define HST_LOG_TAG "HiPlayer" #include "histreamer/hiplayer.h" #include "hiplayer_impl.h" +#include "foundation/log.h" namespace OHOS { namespace Media { std::shared_ptr CreateHiPlayer() { + MEDIA_LOG_W("Histreamer compile time: %s %s", __DATE__, __TIME__); return HiPlayerImpl::CreateHiPlayerImpl(); } } // namespace Media diff --git a/engine/player/hiplayer_impl.cpp b/engine/player/hiplayer_impl.cpp index aba4cca1..fd053c25 100644 --- a/engine/player/hiplayer_impl.cpp +++ b/engine/player/hiplayer_impl.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "HiPlayerImpl" +#define HST_LOG_TAG "HiPlayerImpl" #include "hiplayer_impl.h" #include "foundation/log.h" diff --git a/engine/player/internal/state.cpp b/engine/player/internal/state.cpp index a6e6eb48..24e3297e 100644 --- a/engine/player/internal/state.cpp +++ b/engine/player/internal/state.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "State" +#define HST_LOG_TAG "State" #include "state.h" #include "foundation/log.h" diff --git a/engine/player/internal/state_machine.cpp b/engine/player/internal/state_machine.cpp index 6dc0c066..2539ed25 100644 --- a/engine/player/internal/state_machine.cpp +++ b/engine/player/internal/state_machine.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "StateMachine" +#define HST_LOG_TAG "StateMachine" #include "state_machine.h" diff --git a/engine/plugin/core/audio_sink.cpp b/engine/plugin/core/audio_sink.cpp index 5b175d61..9a3c6fa7 100644 --- a/engine/plugin/core/audio_sink.cpp +++ b/engine/plugin/core/audio_sink.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "PluginCoreAuSink" +#define HST_LOG_TAG "PluginCoreAuSink" #include "audio_sink.h" diff --git a/engine/plugin/core/base.cpp b/engine/plugin/core/base.cpp index 88273193..93b67f1d 100644 --- a/engine/plugin/core/base.cpp +++ b/engine/plugin/core/base.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "PluginCoreBase" +#define HST_LOG_TAG "PluginCoreBase" #include "base.h" #include "foundation/log.h" @@ -28,7 +28,7 @@ Base::Base(uint32_t pkgVer, uint32_t apiVer, std::shared_ptr plugin) Status Base::Init() { - MEDIA_LOG_I("%s Enter.", __FUNCTION__); + MEDIA_LOG_D("%s Enter.", __FUNCTION__); OSAL::ScopedLock lock(stateChangeMutex_); RETURN_WRONG_STATE_IF_CON_TRUE(pluginState_ == State::DESTROYED, plugin_, pluginState_.load()); if (pluginState_ != State::CREATED) { @@ -40,13 +40,13 @@ Status Base::Init() if (ret == Status::OK) { pluginState_ = State::INITIALIZED; } - MEDIA_LOG_I("%s Exit.", __FUNCTION__); + MEDIA_LOG_D("%s Exit.", __FUNCTION__); return ret; } Status Base::Deinit() { - MEDIA_LOG_I("%s Enter.", __FUNCTION__); + MEDIA_LOG_D("%s Enter.", __FUNCTION__); OSAL::ScopedLock lock(stateChangeMutex_); if (pluginState_ == State::DESTROYED) { MEDIA_LOG_I("plugin %s already deinited, no need to destroy any more", plugin_->GetName().c_str()); @@ -55,13 +55,13 @@ Status Base::Deinit() auto ret = plugin_->Deinit(); LOG_WARN_IF_NOT_OK(plugin_, ret); pluginState_ = State::DESTROYED; - MEDIA_LOG_I("%s Exit.", __FUNCTION__); + MEDIA_LOG_D("%s Exit.", __FUNCTION__); return ret; } Status Base::Prepare() { - MEDIA_LOG_I("%s Enter.", __FUNCTION__); + MEDIA_LOG_D("%s Enter.", __FUNCTION__); OSAL::ScopedLock lock(stateChangeMutex_); RETURN_WRONG_STATE_IF_CON_TRUE(pluginState_ != State::PREPARED && pluginState_ != State::INITIALIZED, plugin_, pluginState_.load()); @@ -74,13 +74,13 @@ Status Base::Prepare() if (ret == Status::OK) { pluginState_ = State::PREPARED; } - MEDIA_LOG_I("%s Exit.", __FUNCTION__); + MEDIA_LOG_D("%s Exit.", __FUNCTION__); return ret; } Status Base::Reset() { - MEDIA_LOG_I("%s Enter.", __FUNCTION__); + MEDIA_LOG_D("%s Enter.", __FUNCTION__); OSAL::ScopedLock lock(stateChangeMutex_); RETURN_WRONG_STATE_IF_CON_TRUE(pluginState_ == State::RUNNING || pluginState_ == State::PAUSED || pluginState_ == State::DESTROYED, plugin_, pluginState_.load()); @@ -92,13 +92,13 @@ Status Base::Reset() auto ret = plugin_->Reset(); LOG_WARN_IF_NOT_OK(plugin_, ret); pluginState_ = State::INITIALIZED; - MEDIA_LOG_I("%s Exit.", __FUNCTION__); + MEDIA_LOG_D("%s Exit.", __FUNCTION__); return ret; } Status Base::Start() { - MEDIA_LOG_I("%s Enter.", __FUNCTION__); + MEDIA_LOG_D("%s Enter.", __FUNCTION__); OSAL::ScopedLock lock(stateChangeMutex_); RETURN_WRONG_STATE_IF_CON_TRUE(pluginState_ != State::PREPARED && pluginState_ != State::RUNNING, plugin_, pluginState_.load()); @@ -111,13 +111,13 @@ Status Base::Start() if (ret == Status::OK) { pluginState_ = State::RUNNING; } - MEDIA_LOG_I("%s Exit.", __FUNCTION__); + MEDIA_LOG_D("%s Exit.", __FUNCTION__); return ret; } Status Base::Stop() { - MEDIA_LOG_I("%s Enter.", __FUNCTION__); + MEDIA_LOG_D("%s Enter.", __FUNCTION__); OSAL::ScopedLock lock(stateChangeMutex_); if (pluginState_ != State::RUNNING && pluginState_ != State::PAUSED) { MEDIA_LOG_I("plugin %s not running or paused, no need to stop", plugin_->GetName().c_str()); @@ -128,7 +128,7 @@ Status Base::Stop() if (ret == Status::OK) { pluginState_ = State::PREPARED; } - MEDIA_LOG_I("%s Exit.", __FUNCTION__); + MEDIA_LOG_D("%s Exit.", __FUNCTION__); return ret; } diff --git a/engine/plugin/core/video_sink.cpp b/engine/plugin/core/video_sink.cpp index 598d70a4..b68ec386 100644 --- a/engine/plugin/core/video_sink.cpp +++ b/engine/plugin/core/video_sink.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "PluginCoreViSink" +#define HST_LOG_TAG "PluginCoreViSink" #include "video_sink.h" diff --git a/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp b/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp index a64e074e..f52418e6 100644 --- a/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp +++ b/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "Ffmpeg_Au_Decoder" +#define HST_LOG_TAG "Ffmpeg_Au_Decoder" #include "audio_ffmpeg_decoder_plugin.h" #include @@ -373,7 +373,7 @@ Status AudioFfmpegDecoderPlugin::Stop() Status AudioFfmpegDecoderPlugin::QueueOutputBuffer(const std::shared_ptr& outputBuffer, int32_t timeoutMs) { - MEDIA_LOG_I("queue out put"); + MEDIA_LOG_D("queue out put"); (void)timeoutMs; outBufferQ_.Push(outputBuffer); return Status::OK; @@ -509,7 +509,9 @@ void AudioFfmpegDecoderPlugin::ReceiveBufferLocked(Status& status, const std::sh receiveOneFrame = false; status = Status::END_OF_STREAM; } else { - MEDIA_LOG_I("audio decoder receive error: %s", AVStrError(ret).c_str()); + if (ret != AVERROR(EAGAIN)) { // do not print again as error + MEDIA_LOG_I("audio decoder receive error: %s", AVStrError(ret).c_str()); + } notifyBufferDone = false; receiveOneFrame = false; status = Status::OK; diff --git a/engine/plugin/plugins/ffmpeg_adapter/demuxer/ffmpeg_demuxer_plugin.cpp b/engine/plugin/plugins/ffmpeg_adapter/demuxer/ffmpeg_demuxer_plugin.cpp index 39e39c5b..07693366 100644 --- a/engine/plugin/plugins/ffmpeg_adapter/demuxer/ffmpeg_demuxer_plugin.cpp +++ b/engine/plugin/plugins/ffmpeg_adapter/demuxer/ffmpeg_demuxer_plugin.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "FFmpegDemuxerPlugin" +#define HST_LOG_TAG "FFmpegDemuxerPlugin" #include "ffmpeg_demuxer_plugin.h" #include @@ -91,13 +91,13 @@ FFmpegDemuxerPlugin::FFmpegDemuxerPlugin(std::string name) FFmpegDemuxerPlugin::~FFmpegDemuxerPlugin() { - MEDIA_LOG_I("dtor called."); + MEDIA_LOG_D("dtor called."); pluginImpl_ = nullptr; } Status FFmpegDemuxerPlugin::Init() { - MEDIA_LOG_I("Init called."); + MEDIA_LOG_D("Init called."); Reset(); pluginImpl_ = g_pluginInputFormat[pluginName_]; diff --git a/engine/plugin/plugins/ffmpeg_adapter/utils/aac_audio_config_parser.cpp b/engine/plugin/plugins/ffmpeg_adapter/utils/aac_audio_config_parser.cpp index 0a58d47a..19607999 100644 --- a/engine/plugin/plugins/ffmpeg_adapter/utils/aac_audio_config_parser.cpp +++ b/engine/plugin/plugins/ffmpeg_adapter/utils/aac_audio_config_parser.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "AACAudioConfigParser" +#define HST_LOG_TAG "AACAudioConfigParser" #include "aac_audio_config_parser.h" #include "bit_reader.h" diff --git a/engine/plugin/plugins/ffmpeg_adapter/utils/avc_config_data_parser.cpp b/engine/plugin/plugins/ffmpeg_adapter/utils/avc_config_data_parser.cpp index 01728de9..3d06b5c9 100644 --- a/engine/plugin/plugins/ffmpeg_adapter/utils/avc_config_data_parser.cpp +++ b/engine/plugin/plugins/ffmpeg_adapter/utils/avc_config_data_parser.cpp @@ -15,7 +15,7 @@ #ifdef VIDEO_SUPPORT -#define LOG_TAG "AVCConfigDataParser" +#define HST_LOG_TAG "AVCConfigDataParser" #include "avc_config_data_parser.h" #include diff --git a/engine/plugin/plugins/ffmpeg_adapter/video_decoder/video_ffmpeg_decoder_plugin.cpp b/engine/plugin/plugins/ffmpeg_adapter/video_decoder/video_ffmpeg_decoder_plugin.cpp index 699470d9..fd8b3ba9 100644 --- a/engine/plugin/plugins/ffmpeg_adapter/video_decoder/video_ffmpeg_decoder_plugin.cpp +++ b/engine/plugin/plugins/ffmpeg_adapter/video_decoder/video_ffmpeg_decoder_plugin.cpp @@ -15,7 +15,7 @@ #ifdef VIDEO_SUPPORT -#define LOG_TAG "Ffmpeg_Video_Decoder" +#define HST_LOG_TAG "Ffmpeg_Video_Decoder" #include "video_ffmpeg_decoder_plugin.h" #include diff --git a/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp b/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp index 13ceec7d..a2989520 100644 --- a/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp +++ b/engine/plugin/plugins/hdi_adapter/sink/hos_au_sink.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "HdiSink" +#define HST_LOG_TAG "HdiSinkPlugin" #include "hos_au_sink.h" #include @@ -224,7 +224,7 @@ HdiSink::HdiSink(std::string name) Status HdiSink::Init() { - MEDIA_LOG_D("Init entered."); + MEDIA_LOG_I("Init entered."); audioManager_ = GetAudioManagerFuncs(); if (audioManager_ == nullptr) { MEDIA_LOG_E("Init error due to audioManager nullptr"); @@ -269,7 +269,7 @@ Media::Plugin::Status HdiSink::ReleaseRender() Status HdiSink::Deinit() { - MEDIA_LOG_E("Deinit entered."); + MEDIA_LOG_I("Deinit entered."); Stop(); // release all resources ReleaseRender(); @@ -347,6 +347,7 @@ Status HdiSink::GetParameter(Tag tag, ValueType& value) Status HdiSink::Prepare() { + MEDIA_LOG_I("Prepare entered."); sampleAttributes_.frameSize = GetPcmBytes(sampleAttributes_.format) * sampleAttributes_.channelCount; sampleAttributes_.startThreshold = sampleAttributes_.period * sampleAttributes_.frameSize; sampleAttributes_.stopThreshold = INT32_MAX; @@ -383,7 +384,7 @@ Status HdiSink::Prepare() Status HdiSink::Reset() { - MEDIA_LOG_D("Reset entered."); + MEDIA_LOG_I("Reset entered."); ReleaseRender(); (void)memset_s(&sampleAttributes_, sizeof(sampleAttributes_), 0, sizeof(sampleAttributes_)); (void)memset_s(&deviceDescriptor_, sizeof(deviceDescriptor_), 0, sizeof(deviceDescriptor_)); @@ -396,7 +397,7 @@ Status HdiSink::Reset() Status HdiSink::Start() { - MEDIA_LOG_D("Start entered."); + MEDIA_LOG_I("Start entered."); OHOS::Media::OSAL::ScopedLock lock(renderMutex_); if (audioRender_ == nullptr) { MEDIA_LOG_E("no available render"); @@ -413,7 +414,7 @@ Status HdiSink::Start() Status HdiSink::Stop() { - MEDIA_LOG_D("Stop Entered"); + MEDIA_LOG_I("Stop Entered"); OHOS::Media::OSAL::ScopedLock lock(renderMutex_); processing_ = false; renderCond_.NotifyOne(); @@ -536,7 +537,7 @@ Status HdiSink::SetSpeed(float speed) Status HdiSink::Pause() { - MEDIA_LOG_D("Pause Entered"); + MEDIA_LOG_I("Pause Entered"); OHOS::Media::OSAL::ScopedLock lock(renderMutex_); processing_ = false; renderCond_.NotifyOne(); @@ -549,7 +550,7 @@ Status HdiSink::Pause() Status HdiSink::Resume() { - MEDIA_LOG_D("Resume Entered"); + MEDIA_LOG_I("Resume Entered"); OHOS::Media::OSAL::ScopedLock lock(renderMutex_); processing_ = true; if (audioRender_ != nullptr && audioRender_->control.Resume(audioRender_) != 0) { @@ -681,7 +682,7 @@ bool HdiSink::HandleInterleaveData(uint8_t* origData, int32_t frameCnt) void HdiSink::RenderFrame(const std::shared_ptr& input) { - MEDIA_LOG_D("DoRender started"); + MEDIA_LOG_D("RenderFrame started"); auto mem = input->GetMemory(); auto frame = const_cast(mem->GetReadOnlyData()); bool dataInterleaved = false; @@ -701,7 +702,7 @@ void HdiSink::RenderFrame(const std::shared_ptr& input) } if (ret != 0) { if (ret == HI_ERR_VI_BUF_FULL) { - MEDIA_LOG_I("renderFrame buffer full"); + MEDIA_LOG_D("renderFrame buffer full"); // do not log this info constexpr int timeoutMs = 5; OSAL::ScopedLock lock(renderMutex_); renderCond_.WaitFor(lock, timeoutMs, [this] { return processing_.load() == false; }); diff --git a/engine/plugin/plugins/hdi_adapter/utils/hdi_au_utils.cpp b/engine/plugin/plugins/hdi_adapter/utils/hdi_au_utils.cpp index 6dd754a0..55e3df2b 100644 --- a/engine/plugin/plugins/hdi_adapter/utils/hdi_au_utils.cpp +++ b/engine/plugin/plugins/hdi_adapter/utils/hdi_au_utils.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "HdiAuUtils" +#define HST_LOG_TAG "HdiAuUtils" #include "hdi_au_utils.h" diff --git a/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp b/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp index 0e0f6db0..e634d5d1 100644 --- a/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp +++ b/engine/plugin/plugins/sink/sdl/audio_sink/sdl_audio_sink_plugin.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "SdlAudioSinkPlugin" +#define HST_LOG_TAG "SdlAudioSinkPlugin" #include "sdl_audio_sink_plugin.h" #include diff --git a/engine/plugin/plugins/sink/sdl/video_sink/sdl_video_sink_plugin.cpp b/engine/plugin/plugins/sink/sdl/video_sink/sdl_video_sink_plugin.cpp index 9ae29bb7..9c2d3df4 100644 --- a/engine/plugin/plugins/sink/sdl/video_sink/sdl_video_sink_plugin.cpp +++ b/engine/plugin/plugins/sink/sdl/video_sink/sdl_video_sink_plugin.cpp @@ -15,7 +15,7 @@ #ifdef VIDEO_SUPPORT -#define LOG_TAG "SdlVideoSinkPlugin" +#define HST_LOG_TAG "SdlVideoSinkPlugin" #include "sdl_video_sink_plugin.h" #include diff --git a/engine/plugin/plugins/source/file_source/file_source_plugin.cpp b/engine/plugin/plugins/source/file_source/file_source_plugin.cpp index a0ae24c0..f1017a4b 100644 --- a/engine/plugin/plugins/source/file_source/file_source_plugin.cpp +++ b/engine/plugin/plugins/source/file_source/file_source_plugin.cpp @@ -13,14 +13,13 @@ * limitations under the License. */ -#define LOG_TAG "FileSourcePlugin" +#define HST_LOG_TAG "FileSourcePlugin" #include "file_source_plugin.h" #include #include "foundation/log.h" #include "plugin/common/plugin_buffer.h" #include "plugin/common/plugin_types.h" -#include "plugin/core/plugin_manager.h" #include "utils/utils.h" namespace OHOS { @@ -172,7 +171,7 @@ Status FileSourcePlugin::Read(std::shared_ptr& buffer, size_t expectedLe expectedLen = std::min(static_cast(fileSize_ - position_), expectedLen); expectedLen = std::min(bufData->GetCapacity(), expectedLen); - MEDIA_LOG_I("buffer position %" PRIu64 ", expectedLen %zu", position_, expectedLen); + MEDIA_LOG_D("buffer position %" PRIu64 ", expectedLen %zu", position_, expectedLen); auto size = std::fread(bufData->GetWritableData(expectedLen), sizeof(char), expectedLen, fp_); bufData->GetWritableData(size); position_ += bufData->GetSize(); @@ -252,7 +251,7 @@ Status FileSourcePlugin::ParseFileName(std::string& uri) } else { fileName_ = uri; } - MEDIA_LOG_I("fileName_: %s", fileName_.c_str()); + MEDIA_LOG_D("fileName_: %s", fileName_.c_str()); return Status::OK; } diff --git a/engine/plugin/plugins/source/stream_source/stream_source_plugin.cpp b/engine/plugin/plugins/source/stream_source/stream_source_plugin.cpp index 3fe4a94d..188b0f50 100644 --- a/engine/plugin/plugins/source/stream_source/stream_source_plugin.cpp +++ b/engine/plugin/plugins/source/stream_source/stream_source_plugin.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#define LOG_TAG "StreamSourcePlugin" +#define HST_LOG_TAG "StreamSourcePlugin" #include "stream_source_plugin.h" #include "plugin/common/plugin_buffer.h" -- Gitee From 24185804b42e3d43947c16555740c3febd6a05bd Mon Sep 17 00:00:00 2001 From: wuyouqian Date: Tue, 9 Nov 2021 10:13:28 +0000 Subject: [PATCH 13/22] !116 remove codec filter thread to increase efficiency Signed-off-by: wuyouqian --- .../audio_decoder/audio_decoder_filter.cpp | 224 +++--------------- .../audio_decoder/audio_decoder_filter.h | 19 +- engine/plugin/core/codec.cpp | 10 + engine/plugin/core/codec.h | 8 +- engine/plugin/interface/codec_plugin.h | 35 +++ .../audio_ffmpeg_decoder_plugin.cpp | 176 ++++++-------- .../audio_ffmpeg_decoder_plugin.h | 24 +- engine/utils/buffer_pool.h | 17 ++ 8 files changed, 184 insertions(+), 329 deletions(-) diff --git a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp index a8c9c379..6292c9ec 100644 --- a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp +++ b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.cpp @@ -31,8 +31,6 @@ constexpr int32_t AF_64BIT_BYTES = 8; constexpr int32_t AF_32BIT_BYTES = 4; constexpr int32_t AF_16BIT_BYTES = 2; constexpr int32_t AF_8BIT_BYTES = 1; -constexpr int32_t RETRY_TIMES = 3; -constexpr int32_t RETRY_DELAY = 10; // 10ms int32_t CalculateBufferSize(const std::shared_ptr &meta) { @@ -90,28 +88,7 @@ namespace Media { namespace Pipeline { static AutoRegisterFilter g_registerFilterHelper("builtin.player.audiodecoder"); -class AudioDecoderFilter::DataCallbackImpl : public Plugin::DataCallbackHelper { -public: - explicit DataCallbackImpl(AudioDecoderFilter& filter): decoderFilter_(filter){} - - ~DataCallbackImpl() override = default; - - void OnInputBufferDone(const std::shared_ptr &input) override - { - decoderFilter_.OnInputBufferDone(input); - } - - void OnOutputBufferDone(const std::shared_ptr &output) override - { - decoderFilter_.OnOutputBufferDone(output); - } - -private: - AudioDecoderFilter& decoderFilter_; -}; - -AudioDecoderFilter::AudioDecoderFilter(const std::string &name): DecoderFilterBase(name), - dataCallback_(std::make_shared(*this)) +AudioDecoderFilter::AudioDecoderFilter(const std::string &name): DecoderFilterBase(name) { filterType_ = FilterType::AUDIO_DECODER; MEDIA_LOG_D("audio decoder ctor called"); @@ -121,29 +98,6 @@ AudioDecoderFilter::~AudioDecoderFilter() { MEDIA_LOG_D("audio decoder dtor called"); Release(); - if (inBufferQ_) { - inBufferQ_->SetActive(false); - } - if (outBufferQ_) { - outBufferQ_->SetActive(false); - } -} - -ErrorCode AudioDecoderFilter::QueueAllBufferInPoolToPluginLocked() -{ - ErrorCode err = ErrorCode::SUCCESS; - while (!outBufferPool_->Empty()) { - auto ptr = outBufferPool_->AllocateBuffer(); - if (ptr == nullptr) { - MEDIA_LOG_W("cannot allocate buffer in buffer pool"); - continue; - } - err = TranslatePluginStatus(plugin_->QueueOutputBuffer(ptr, -1)); - if (err != ErrorCode::SUCCESS) { - MEDIA_LOG_E("queue output buffer error"); - } - } - return err; } ErrorCode AudioDecoderFilter::Start() @@ -163,37 +117,6 @@ ErrorCode AudioDecoderFilter::Prepare() MEDIA_LOG_W("decoder filter is not in init state"); return ErrorCode::ERROR_INVALID_OPERATION; } - if (!outBufferQ_) { - outBufferQ_ = std::make_shared>("adecOutBuffQueue", - DEFAULT_OUT_BUFFER_POOL_SIZE); - } else { - outBufferQ_->SetActive(true); - } - if (!pushTask_) { - pushTask_ = std::make_shared("adecPushThread"); - pushTask_->RegisterHandler([this] { FinishFrame(); }); - } - if (drivingMode_ == ThreadDrivingMode::ASYNC) { - if (!inBufferQ_) { - inBufferQ_ = std::make_shared>("adecFilterInBufQue", - DEFAULT_IN_BUFFER_POOL_SIZE); - } else { - inBufferQ_->SetActive(true); - } - if (!handleFrameTask_) { - handleFrameTask_ = std::make_shared("adecHandleFrameThread"); - handleFrameTask_->RegisterHandler([this] { HandleFrame(); }); - } - } else { - if (inBufferQ_) { - inBufferQ_->SetActive(false); - inBufferQ_.reset(); - } - if (handleFrameTask_) { - handleFrameTask_->Stop(); - handleFrameTask_.reset(); - } - } auto err = FilterBase::Prepare(); RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "Audio Decoder prepare error because of filter base prepare error"); return ErrorCode::SUCCESS; @@ -275,11 +198,6 @@ bool AudioDecoderFilter::Configure(const std::string &inPort, const std::shared_ OnEvent({EVENT_ERROR, err}); return false; } - - if (drivingMode_ == ThreadDrivingMode::ASYNC && handleFrameTask_ != nullptr) { - handleFrameTask_->Start(); - } - pushTask_->Start(); state_ = FilterState::READY; OnEvent({EVENT_READY}); MEDIA_LOG_I("audio decoder send EVENT_READY"); @@ -288,10 +206,7 @@ bool AudioDecoderFilter::Configure(const std::string &inPort, const std::shared_ ErrorCode AudioDecoderFilter::ConfigureToStartPluginLocked(const std::shared_ptr& meta) { - auto err = TranslatePluginStatus(plugin_->SetDataCallback(dataCallback_)); - RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "set decoder plugin callback failed"); - - err = ConfigureWithMetaLocked(meta); + auto err = ConfigureWithMetaLocked(meta); RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "configure decoder plugin error"); uint32_t bufferCnt = 0; @@ -321,9 +236,6 @@ ErrorCode AudioDecoderFilter::ConfigureToStartPluginLocked(const std::shared_ptr err = TranslatePluginStatus(plugin_->Prepare()); RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "decoder prepare failed"); - err = QueueAllBufferInPoolToPluginLocked(); - RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "queue out buffer to plugin failed"); - err = TranslatePluginStatus(plugin_->Start()); RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "decoder start failed"); @@ -340,13 +252,11 @@ ErrorCode AudioDecoderFilter::PushData(const std::string &inPort, AVBufferPtr bu MEDIA_LOG_I("decoder is flushing, discarding this data from port %s", inPort.c_str()); return ErrorCode::SUCCESS; } - // async - if (drivingMode_ == ThreadDrivingMode::ASYNC) { - inBufferQ_->Push(buffer); - return ErrorCode::SUCCESS; - } - // sync - HandleOneFrame(buffer); + bool isHandled = false; + do { + isHandled = HandleFrame(buffer); + FinishFrame(); + } while (!isHandled); return ErrorCode::SUCCESS; } @@ -354,14 +264,6 @@ void AudioDecoderFilter::FlushStart() { MEDIA_LOG_I("FlushStart entered."); isFlushing_ = true; - if (inBufferQ_) { - inBufferQ_->SetActive(false); - } - handleFrameTask_->PauseAsync(); - if (outBufferQ_) { - outBufferQ_->SetActive(false); - } - pushTask_->PauseAsync(); if (plugin_ != nullptr) { auto err = TranslatePluginStatus(plugin_->Flush()); if (err != ErrorCode::SUCCESS) { @@ -375,17 +277,6 @@ void AudioDecoderFilter::FlushEnd() { MEDIA_LOG_I("FlushEnd entered"); isFlushing_ = false; - if (inBufferQ_) { - inBufferQ_->SetActive(true); - } - handleFrameTask_->Start(); - if (outBufferQ_) { - outBufferQ_->SetActive(true); - } - pushTask_->Start(); - if (plugin_ != nullptr) { - QueueAllBufferInPoolToPluginLocked(); - } } ErrorCode AudioDecoderFilter::Stop() @@ -399,14 +290,6 @@ ErrorCode AudioDecoderFilter::Stop() err = TranslatePluginStatus(plugin_->Stop()); RETURN_ERR_MESSAGE_LOG_IF_FAIL(err, "decoder stop error"); } - outBufferQ_->SetActive(false); - pushTask_->Pause(); - - if (drivingMode_ == ThreadDrivingMode::ASYNC && handleFrameTask_ != nullptr) { - inBufferQ_->SetActive(false); - handleFrameTask_->Pause(); - } - outBufferPool_.reset(); MEDIA_LOG_I("AudioDecoderFilter stop end."); return FilterBase::Stop(); @@ -418,95 +301,52 @@ ErrorCode AudioDecoderFilter::Release() plugin_->Stop(); plugin_->Deinit(); } - - if (drivingMode_ == ThreadDrivingMode::ASYNC && handleFrameTask_ != nullptr) { - handleFrameTask_->Stop(); - handleFrameTask_.reset(); - } - - if (inBufferQ_ != nullptr) { - inBufferQ_->SetActive(false); - } - // 先停止线程 然后释放bufferQ 如果顺序反过来 可能导致线程访问已经释放的锁 - if (pushTask_ != nullptr) { - pushTask_->Stop(); - pushTask_.reset(); - } - - if (outBufferQ_ != nullptr) { - outBufferQ_->SetActive(false); - } return ErrorCode::SUCCESS; } -void AudioDecoderFilter::HandleFrame() +bool AudioDecoderFilter::HandleFrame(const std::shared_ptr& buffer) { MEDIA_LOG_D("HandleFrame called"); - auto oneBuffer = inBufferQ_->Pop(); - if (oneBuffer == nullptr) { - MEDIA_LOG_W("decoder find nullptr in esBufferQ"); - return; + if (TranslatePluginStatus(plugin_->QueueInputBuffer(buffer, 0)) != ErrorCode::SUCCESS) { + MEDIA_LOG_I("Queue input buffer to plugin fail"); + return false; } - HandleOneFrame(oneBuffer); MEDIA_LOG_D("HandleFrame finished"); -} - -void AudioDecoderFilter::HandleOneFrame(const std::shared_ptr& data) -{ - MEDIA_LOG_D("HandleOneFrame called"); - Plugin::Status status = Plugin::Status::OK; - int32_t retryCnt = 0; - do { - status = plugin_->QueueInputBuffer(data, 0); - if (status != Plugin::Status::ERROR_TIMED_OUT) { - break; - } - MEDIA_LOG_I("queue input buffer timeout, will retry"); - retryCnt++; - if (retryCnt <= RETRY_TIMES) { - OSAL::SleepFor(RETRY_DELAY); - } else { - break; - } - } while (true); - if (status != Plugin::Status::OK) { - MEDIA_LOG_W("queue input buffer with error %d, ignore this buffer", status); - } - MEDIA_LOG_D("HandleOneFrame finished"); + return true; } void AudioDecoderFilter::FinishFrame() { MEDIA_LOG_D("begin finish frame"); - // get buffer from plugin - auto ptr = outBufferQ_->Pop(); - if (ptr) { + auto outBuffer = outBufferPool_->AllocateAppendBufferNonBlocking(); + if (outBuffer == nullptr) { + MEDIA_LOG_E("Get out buffer from buffer pool fail"); + return; + } + outBuffer->Reset(); + auto ret = TranslatePluginStatus(plugin_->QueueOutputBuffer(outBuffer, 0)); + if (ret != ErrorCode::SUCCESS) { + MEDIA_LOG_E("Queue out buffer to plugin fail: %d", ret); + return; + } + std::shared_ptr pcmFrame = nullptr; + auto status = plugin_->DequeueOutputBuffer(pcmFrame, 0); + if (status != Plugin::Status::OK && status != Plugin::Status::END_OF_STREAM) { + MEDIA_LOG_E("Dequeue pcm frame from plugin fail: %d", ret); + return; + } + if (pcmFrame) { // push to port auto oPort = outPorts_[0]; if (oPort->GetWorkMode() == WorkMode::PUSH) { - oPort->PushData(ptr); + oPort->PushData(pcmFrame); } else { MEDIA_LOG_W("decoder out port works in pull mode"); } - ptr.reset(); // 释放buffer 如果没有被缓存使其回到buffer pool 如果被sink缓存 则从buffer pool拿其他的buffer - auto oPtr = outBufferPool_->AllocateBuffer(); - if (oPtr != nullptr) { - oPtr->Reset(); - plugin_->QueueOutputBuffer(oPtr, -1); - } + pcmFrame.reset(); // 释放buffer 如果没有被缓存使其回到buffer pool 如果被sink缓存 则从buffer pool拿其他的buffer } MEDIA_LOG_D("end finish frame"); } - -void AudioDecoderFilter::OnInputBufferDone(const std::shared_ptr &buffer) -{ - // do nothing since we has no input buffer pool -} - -void AudioDecoderFilter::OnOutputBufferDone(const std::shared_ptr &buffer) -{ - outBufferQ_->Push(buffer); -} } } } diff --git a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.h b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.h index 74d92d7f..36245211 100644 --- a/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.h +++ b/engine/pipeline/filters/codec/audio_decoder/audio_decoder_filter.h @@ -44,35 +44,18 @@ public: void FlushEnd() override; private: - class DataCallbackImpl; - ErrorCode ConfigureToStartPluginLocked(const std::shared_ptr &meta); - void HandleFrame(); - - void HandleOneFrame(const std::shared_ptr &data); + bool HandleFrame(const std::shared_ptr& buffer); void FinishFrame(); ErrorCode Release(); - // callbacks - void OnInputBufferDone(const std::shared_ptr &buffer); - - void OnOutputBufferDone(const std::shared_ptr &buffer); - private: - ErrorCode QueueAllBufferInPoolToPluginLocked(); - - std::shared_ptr> inBufferQ_; - std::shared_ptr> outBufferQ_; // PCM data - std::shared_ptr handleFrameTask_ {}; // dequeue from es bufferQ then enqueue to plugin - // this task will dequeue from the plugin and then push to downstream - std::shared_ptr pushTask_ {nullptr}; std::shared_ptr> outBufferPool_ {}; bool isFlushing_ {false}; - std::shared_ptr dataCallback_ {nullptr}; Capability capNegWithDownstream_; Capability capNegWithUpstream_; }; diff --git a/engine/plugin/core/codec.cpp b/engine/plugin/core/codec.cpp index 81d577c6..992aaac0 100644 --- a/engine/plugin/core/codec.cpp +++ b/engine/plugin/core/codec.cpp @@ -31,11 +31,21 @@ Status Codec::QueueInputBuffer(const std::shared_ptr& inputBuffer, int32 return codec_->QueueInputBuffer(inputBuffer, timeoutMs); } +Status Codec::DequeueInputBuffer(std::shared_ptr& inputBuffer, int32_t timeoutMs) +{ + return codec_->DequeueInputBuffer(inputBuffer, timeoutMs); +} + Status Codec::QueueOutputBuffer(const std::shared_ptr& outputBuffers, int32_t timeoutMs) { return codec_->QueueOutputBuffer(outputBuffers, timeoutMs); } +Status Codec::DequeueOutputBuffer(std::shared_ptr& outputBuffers, int32_t timeoutMs) +{ + return codec_->DequeueOutputBuffer(outputBuffers, timeoutMs); +} + Status Codec::Flush() { return codec_->Flush(); diff --git a/engine/plugin/core/codec.h b/engine/plugin/core/codec.h index e544f7cc..89b50cca 100644 --- a/engine/plugin/core/codec.h +++ b/engine/plugin/core/codec.h @@ -44,9 +44,13 @@ public: ~Codec() override = default; - Status QueueInputBuffer(const std::shared_ptr &inputBuffer, int32_t timeoutMs); + Status QueueInputBuffer(const std::shared_ptr& inputBuffer, int32_t timeoutMs); - Status QueueOutputBuffer(const std::shared_ptr &outputBuffers, int32_t timeoutMs); + Status DequeueInputBuffer(std::shared_ptr& inputBuffer, int32_t timeoutMs); + + Status QueueOutputBuffer(const std::shared_ptr& outputBuffers, int32_t timeoutMs); + + Status DequeueOutputBuffer(std::shared_ptr& outputBuffers, int32_t timeoutMs); Status Flush(); diff --git a/engine/plugin/interface/codec_plugin.h b/engine/plugin/interface/codec_plugin.h index 2aa64005..2a9cf004 100644 --- a/engine/plugin/interface/codec_plugin.h +++ b/engine/plugin/interface/codec_plugin.h @@ -63,6 +63,7 @@ struct DataCallback { struct CodecPlugin : public PluginBase { /// constructor explicit CodecPlugin(std::string name): PluginBase(std::forward(name)) {} + /** * @brief Queues input data * @@ -78,8 +79,26 @@ struct CodecPlugin : public PluginBase { * @retval ERROR_TIMED_OUT: Operation timeout. */ virtual Status QueueInputBuffer(const std::shared_ptr& inputBuffer, int32_t timeoutMs) = 0; + + /** + * @brief Dequeue input data + * + * This function works in sync mode if need. + * + * The function is valid only in the RUNNING state. + * + * @param inputBuffer Indicates the pointer to the input data. + * @param timeoutMs Indicates the timeout duration. + * @return Execution status return + * @retval OK: Plugin reset succeeded. + * @retval ERROR_INVALID_DATA: The input buffer is invalid. + * @retval ERROR_TIMED_OUT: Operation timeout. + */ + virtual Status DequeueInputBuffer(std::shared_ptr& inputBuffer, int32_t timeoutMs) = 0; + /** * @brief Queues output data + * * This function works with DataCallback::OnOutputBufferDone to implement output data transmission. * * The function is valid only in the RUNNING state. @@ -93,6 +112,22 @@ struct CodecPlugin : public PluginBase { */ virtual Status QueueOutputBuffer(const std::shared_ptr& outputBuffers, int32_t timeoutMs) = 0; + /** + * @brief Dequeues output data + * + * This function works in sync mode if need. + * + * The function is valid only in the RUNNING state. + * + * @param outputBuffers Indicates the pointer to the output data. + * @param timeoutMs Indicates the timeout duration. + * @return Execution status return + * @retval OK: Plugin reset succeeded. + * @retval ERROR_INVALID_DATA: The output buffer is invalid. + * @retval ERROR_TIMED_OUT: Operation timeout. + */ + virtual Status DequeueOutputBuffer(std::shared_ptr& outputBuffers, int32_t timeoutMs) = 0; + /** * @brief Flushes data in the audio buffer. * diff --git a/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp b/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp index f52418e6..95239666 100644 --- a/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp +++ b/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.cpp @@ -177,7 +177,7 @@ namespace OHOS { namespace Media { namespace Plugin { AudioFfmpegDecoderPlugin::AudioFfmpegDecoderPlugin(std::string name) - : CodecPlugin(std::move(name)), outBufferQ_("adecPluginQueue", BUFFER_QUEUE_SIZE) {} + : CodecPlugin(std::move(name)) {} AudioFfmpegDecoderPlugin::~AudioFfmpegDecoderPlugin() { @@ -294,7 +294,6 @@ Status AudioFfmpegDecoderPlugin::Prepare() static_cast(avCodecContext_->workaround_bugs) | static_cast(FF_BUG_AUTODETECT); avCodecContext_->err_recognition = 1; } - outBufferQ_.SetActive(true); return Status::OK; } @@ -325,7 +324,6 @@ Status AudioFfmpegDecoderPlugin::ResetLocked() { audioParameter_.clear(); avCodecContext_.reset(); - outBufferQ_.Clear(); return Status::OK; } @@ -349,7 +347,6 @@ Status AudioFfmpegDecoderPlugin::Start() return Status::ERROR_UNKNOWN; } } - outBufferQ_.SetActive(true); return Status::OK; } @@ -366,19 +363,13 @@ Status AudioFfmpegDecoderPlugin::Stop() } avCodecContext_.reset(); } + if (outBuffer_) { + outBuffer_.reset(); + } } - outBufferQ_.SetActive(false); return ret; } -Status AudioFfmpegDecoderPlugin::QueueOutputBuffer(const std::shared_ptr& outputBuffer, int32_t timeoutMs) -{ - MEDIA_LOG_D("queue out put"); - (void)timeoutMs; - outBufferQ_.Push(outputBuffer); - return Status::OK; -} - Status AudioFfmpegDecoderPlugin::Flush() { MEDIA_LOG_I("Flush entered."); @@ -394,17 +385,50 @@ Status AudioFfmpegDecoderPlugin::QueueInputBuffer(const std::shared_ptr& { MEDIA_LOG_D("queue input buffer"); (void)timeoutMs; - Status status = SendBuffer(inputBuffer); - if (status != Status::OK) { - return status; + if (inputBuffer->IsEmpty() && !(inputBuffer->flag & BUFFER_FLAG_EOS)) { + MEDIA_LOG_E("decoder does not support fd buffer"); + return Status::ERROR_INVALID_DATA; } - bool receiveOneFrame = false; - do { - receiveOneFrame = ReceiveBuffer(status); - if (status != Status::OK) { - break; + Status ret = Status::OK; + { + OSAL::ScopedLock lock(avMutex_); + if (avCodecContext_ == nullptr) { + return Status::ERROR_WRONG_STATE; } - } while (receiveOneFrame); + ret = SendBufferLocked(inputBuffer); + } + return ret; +} + +Status AudioFfmpegDecoderPlugin::DequeueInputBuffer(std::shared_ptr& inputBuffer, int32_t timeoutMs) +{ + // dummy + return Status::OK; +} + +Status AudioFfmpegDecoderPlugin::QueueOutputBuffer(const std::shared_ptr& outputBuffers, int32_t timeoutMs) +{ + MEDIA_LOG_I("queue out put"); + (void)timeoutMs; + if (!outputBuffers) { + return Status::ERROR_INVALID_PARAMETER; + } + outBuffer_ = outputBuffers; + return Status::OK; +} + +Status AudioFfmpegDecoderPlugin::DequeueOutputBuffer(std::shared_ptr& outputBuffers, int32_t timeoutMs) +{ + MEDIA_LOG_I("dequeue out put"); + (void)timeoutMs; + Status status; + do { + status = ReceiveBuffer(); + } while (status == Status::ERROR_NOT_ENOUGH_DATA); + if (status == Status::OK || status == Status::END_OF_STREAM) { + outputBuffers = outBuffer_; + } + outBuffer_.reset(); return status; } @@ -443,30 +467,12 @@ Status AudioFfmpegDecoderPlugin::SendBufferLocked(const std::shared_ptr& auto ret = avcodec_send_packet(avCodecContext_.get(), packetPtr); if (ret < 0) { MEDIA_LOG_E("send buffer error %s", AVStrError(ret).c_str()); + return Status::ERROR_TIMED_OUT; } return Status::OK; } -Status AudioFfmpegDecoderPlugin::SendBuffer(const std::shared_ptr& inputBuffer) -{ - if (inputBuffer->IsEmpty() && !(inputBuffer->flag & BUFFER_FLAG_EOS)) { - MEDIA_LOG_E("input buffer error"); - return Status::ERROR_INVALID_PARAMETER; - } - Status ret = Status::OK; - { - OSAL::ScopedLock lock(avMutex_); - if (avCodecContext_ == nullptr) { - return Status::ERROR_WRONG_STATE; - } - ret = SendBufferLocked(inputBuffer); - } - NotifyInputBufferDone(inputBuffer); - return ret; -} - -void AudioFfmpegDecoderPlugin::ReceiveFrameSucc(const std::shared_ptr& ioInfo, Status& status, - bool& receiveOneFrame, bool& notifyBufferDone) +Status AudioFfmpegDecoderPlugin::ReceiveFrameSucc(const std::shared_ptr& ioInfo) { int32_t channels = cachedFrame_->channels; int32_t samples = cachedFrame_->nb_samples; @@ -476,89 +482,57 @@ void AudioFfmpegDecoderPlugin::ReceiveFrameSucc(const std::shared_ptr& i auto ioInfoMem = ioInfo->GetMemory(); if (ioInfoMem->GetCapacity() < outputSize) { MEDIA_LOG_W("output buffer size is not enough"); - receiveOneFrame = false; - notifyBufferDone = false; - } else { - if (av_sample_fmt_is_planar(avCodecContext_->sample_fmt)) { - int32_t planarSize = outputSize / channels; - for (size_t idx = 0; idx < channels; idx++) { - ioInfoMem->Write(cachedFrame_->extended_data[idx], planarSize); - } - } else { - ioInfoMem->Write(cachedFrame_->data[0], outputSize); + return Status::ERROR_NO_MEMORY; + } + if (av_sample_fmt_is_planar(avCodecContext_->sample_fmt)) { + int32_t planarSize = outputSize / channels; + for (size_t idx = 0; idx < channels; idx++) { + ioInfoMem->Write(cachedFrame_->extended_data[idx], planarSize); } - ioInfo->pts = static_cast(cachedFrame_->pts); - notifyBufferDone = true; - receiveOneFrame = true; - status = Status::OK; + } else { + ioInfoMem->Write(cachedFrame_->data[0], outputSize); } + ioInfo->pts = static_cast(cachedFrame_->pts); + return Status::OK; } -void AudioFfmpegDecoderPlugin::ReceiveBufferLocked(Status& status, const std::shared_ptr& ioInfo, - bool& receiveOneFrame, bool& notifyBufferDone) +Status AudioFfmpegDecoderPlugin::ReceiveBufferLocked(const std::shared_ptr& ioInfo) { + Status status; auto ret = avcodec_receive_frame(avCodecContext_.get(), cachedFrame_.get()); if (ret >= 0) { MEDIA_LOG_D("receive one frame"); - ReceiveFrameSucc(ioInfo, status, receiveOneFrame, notifyBufferDone); + status = ReceiveFrameSucc(ioInfo); } else if (ret == AVERROR_EOF) { MEDIA_LOG_I("eos received"); ioInfo->GetMemory()->Reset(); ioInfo->flag = BUFFER_FLAG_EOS; - notifyBufferDone = true; - receiveOneFrame = false; status = Status::END_OF_STREAM; } else { - if (ret != AVERROR(EAGAIN)) { // do not print again as error - MEDIA_LOG_I("audio decoder receive error: %s", AVStrError(ret).c_str()); - } - notifyBufferDone = false; - receiveOneFrame = false; - status = Status::OK; + MEDIA_LOG_I("audio decoder receive error: %s", AVStrError(ret).c_str()); + status = Status::ERROR_NOT_ENOUGH_DATA; } av_frame_unref(cachedFrame_.get()); + return status; } -bool AudioFfmpegDecoderPlugin::ReceiveBuffer(Status& status) + +Status AudioFfmpegDecoderPlugin::ReceiveBuffer(void) { - bool notifyBufferDone = false; - bool receiveOneFrame = false; - std::shared_ptr ioInfo = outBufferQ_.Pop(); - if (ioInfo == nullptr || ioInfo->IsEmpty()) { + std::shared_ptr ioInfo = outBuffer_; + if ((ioInfo == nullptr) || ioInfo->IsEmpty() || + (ioInfo->GetBufferMeta()->GetType() != BufferMetaType::AUDIO)) { MEDIA_LOG_W("cannot fetch valid buffer to output"); - return false; + return Status::ERROR_NO_MEMORY; } - if (ioInfo->GetBufferMeta()->GetType() != BufferMetaType::AUDIO) { - MEDIA_LOG_W("cannot process with non-audio buffer"); - receiveOneFrame = false; - } else { + Status status; + { OSAL::ScopedLock l(avMutex_); if (avCodecContext_ == nullptr) { - return false; + return Status::ERROR_WRONG_STATE; } - ReceiveBufferLocked(status, ioInfo, receiveOneFrame, notifyBufferDone); - } - if (notifyBufferDone) { - NotifyOutputBufferDone(ioInfo); - } else { - outBufferQ_.Push(ioInfo); - } - return receiveOneFrame; -} - -void AudioFfmpegDecoderPlugin::NotifyInputBufferDone(const std::shared_ptr& input) -{ - auto ptr = dataCb_.lock(); - if (ptr != nullptr) { - ptr->OnInputBufferDone(input); - } -} - -void AudioFfmpegDecoderPlugin::NotifyOutputBufferDone(const std::shared_ptr& output) -{ - auto ptr = dataCb_.lock(); - if (ptr != nullptr) { - ptr->OnOutputBufferDone(output); + status = ReceiveBufferLocked(ioInfo); } + return status; } std::shared_ptr AudioFfmpegDecoderPlugin::GetAllocator() diff --git a/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.h b/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.h index f68d7254..74c390f9 100644 --- a/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.h +++ b/engine/plugin/plugins/ffmpeg_adapter/audio_decoder/audio_ffmpeg_decoder_plugin.h @@ -71,13 +71,16 @@ public: Status QueueInputBuffer(const std::shared_ptr& inputBuffer, int32_t timeoutMs) override; + Status DequeueInputBuffer(std::shared_ptr& inputBuffer, int32_t timeoutMs) override; + Status QueueOutputBuffer(const std::shared_ptr& outputBuffers, int32_t timeoutMs) override; + Status DequeueOutputBuffer(std::shared_ptr& outputBuffers, int32_t timeoutMs) override; + Status Flush() override; Status SetDataCallback(const std::weak_ptr& dataCallback) override { - dataCb_ = dataCallback; return Status::OK; } @@ -91,26 +94,17 @@ private: template bool FindInParameterMapThenAssignLocked(Tag tag, T& assign); - Status SendBuffer(const std::shared_ptr& inputBuffer); - Status SendBufferLocked(const std::shared_ptr& inputBuffer); - void ReceiveFrameSucc(const std::shared_ptr& ioInfo, Status& status, - bool& receiveOneFrame, bool& notifyBufferDone); + Status ReceiveFrameSucc(const std::shared_ptr& ioInfo); - bool ReceiveBuffer(Status& err); - void ReceiveBufferLocked(Status& status, const std::shared_ptr& ioInfo, bool& receiveOneFrame, - bool& notifyBufferDone); + Status ReceiveBuffer(void); - void NotifyInputBufferDone(const std::shared_ptr& input); - - void NotifyOutputBufferDone(const std::shared_ptr& output); + Status ReceiveBufferLocked(const std::shared_ptr& ioInfo); mutable OSAL::Mutex parameterMutex_ {}; std::map audioParameter_ {}; - std::weak_ptr dataCb_ {}; - mutable OSAL::Mutex avMutex_ {}; std::shared_ptr avCodec_ {}; std::shared_ptr avCodecContext_ {}; @@ -118,9 +112,7 @@ private: std::vector paddedBuffer_ {}; size_t paddedBufferSize_ {0}; - - // outBufferQ有自己的锁保护 不要和lock_同时混用 否则可能导致死锁 - OHOS::Media::BlockingQueue> outBufferQ_; + std::shared_ptr outBuffer_ {nullptr}; }; } // namespace Plugin } // namespace Media diff --git a/engine/utils/buffer_pool.h b/engine/utils/buffer_pool.h index 32c0ac03..f9f96f1f 100644 --- a/engine/utils/buffer_pool.h +++ b/engine/utils/buffer_pool.h @@ -59,6 +59,7 @@ public: if (msgSize_ == msgSize && align == align_) { return; } + metaType_ = type; msgSize_ = msgSize; align_ = align; freeBuffers_.clear(); @@ -121,6 +122,21 @@ public: return AllocateBufferUnprotected(); } + std::shared_ptr AllocateAppendBufferNonBlocking() + { + OSAL::ScopedLock lock(mutex_); + if (!isActive_) { + return nullptr; + } + if (freeBuffers_.empty()) { + poolSize_++; + auto buf = new Plugin::Buffer(metaType_); + buf->AllocMemory(nullptr, msgSize_); + freeBuffers_.emplace_back(std::unique_ptr(buf)); + } + return AllocateBufferUnprotected(); + } + size_t Size() const { OSAL::ScopedLock lock(mutex_); @@ -171,6 +187,7 @@ private: size_t align_ {0}; // 0: use default alignment. std::atomic isActive_; std::atomic allocInProgress; + Plugin::BufferMetaType metaType_; }; } // namespace Media } // namespace OHOS -- Gitee From 58a7113c649e5a3cb5af4fddb0066c1392ed72d6 Mon Sep 17 00:00:00 2001 From: binma Date: Thu, 21 Oct 2021 18:38:26 +0800 Subject: [PATCH 14/22] Add minimp3 demuxer and decoder plugins. Change-Id: I946a3d0e579c807d75ffea391c008178f7b19711 Signed-off-by: binma --- engine/plugin/plugins/BUILD.gn | 13 + .../plugin/plugins/minimp3_adapter/BUILD.gn | 58 + .../plugin/plugins/minimp3_adapter/minimp3.h | 1854 +++++++++++++++++ .../minimp3_decoder_plugin.cpp | 324 +++ .../minimp3_adapter/minimp3_decoder_plugin.h | 113 + .../minimp3_demuxer_plugin.cpp | 523 +++++ .../minimp3_adapter/minimp3_demuxer_plugin.h | 140 ++ .../plugins/minimp3_adapter/minimp3_ex.h | 1393 +++++++++++++ .../plugins/minimp3_adapter/minimp3_wrapper.c | 52 + .../plugins/minimp3_adapter/minimp3_wrapper.h | 51 + 10 files changed, 4521 insertions(+) create mode 100755 engine/plugin/plugins/minimp3_adapter/BUILD.gn create mode 100755 engine/plugin/plugins/minimp3_adapter/minimp3.h create mode 100755 engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp create mode 100755 engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.h create mode 100755 engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp create mode 100755 engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h create mode 100755 engine/plugin/plugins/minimp3_adapter/minimp3_ex.h create mode 100755 engine/plugin/plugins/minimp3_adapter/minimp3_wrapper.c create mode 100755 engine/plugin/plugins/minimp3_adapter/minimp3_wrapper.h diff --git a/engine/plugin/plugins/BUILD.gn b/engine/plugin/plugins/BUILD.gn index 8216b772..3681c9ec 100644 --- a/engine/plugin/plugins/BUILD.gn +++ b/engine/plugin/plugins/BUILD.gn @@ -18,6 +18,8 @@ if (defined(ohos_lite)) { print("histreamer plugin config:enable_histreamer_plugin_ffmpeg_adapter =", enable_histreamer_plugin_ffmpeg_adapter) + print("histreamer plugin config:enable_histreamer_plugin_minimp3_adapter =", + enable_histreamer_plugin_minimp3_adapter) print("histreamer plugin config:enable_histreamer_plugin_hdi_adapter =", enable_histreamer_plugin_hdi_adapter) print("histreamer plugin config:enable_histreamer_plugin_file_source =", @@ -31,6 +33,10 @@ if (defined(ohos_lite)) { deps += [ "ffmpeg_adapter:plugin_ffmpeg_adapter" ] } + if (enable_histreamer_plugin_minimp3_adapter) { + deps += [ "minimp3_adapter:plugin_minimp3_adapter" ] + } + if (enable_histreamer_plugin_file_source) { deps += [ "source/file_source:plugin_file_source" ] } @@ -65,6 +71,13 @@ if (defined(ohos_lite)) { ] } + if (enable_histreamer_plugin_minimp3_adapter) { + args += [ + "Minimp3Decoder", + "Minimp3Demuxer", + ] + } + if (enable_histreamer_plugin_file_source) { args += [ "FileSource" ] } diff --git a/engine/plugin/plugins/minimp3_adapter/BUILD.gn b/engine/plugin/plugins/minimp3_adapter/BUILD.gn new file mode 100755 index 00000000..fe0fdd17 --- /dev/null +++ b/engine/plugin/plugins/minimp3_adapter/BUILD.gn @@ -0,0 +1,58 @@ +# Copyright (c) 2021-2021 Huawei Device 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. +# + +if (defined(ohos_lite)) { + import("//build/lite/config/component/lite_component.gni") + import("//build/lite/config/subsystem/multimedia/config.gni") + group("plugin_minimp3_adapter") { + if (ohos_kernel_type == "liteos_m") { + deps = [ + ":histreamer_plugin_Minimp3Decoders", + ":histreamer_plugin_Minimp3Demuxer", + ] + } + } + config("plugin_minimp3_adapter_config") { + include_dirs = [ + "minimp3_adapter", + "//foundation/multimedia/histreamer/engine/foundation", + ] + } + + static_library("histreamer_plugin_Minimp3Decoders") { + sources = [ + "minimp3_decoder_plugin.cpp", + "minimp3_wrapper.c", + ] + public_configs = [ ":plugin_minimp3_adapter_config" ] + public_deps = [ + "//foundation/multimedia/histreamer/engine/foundation:histreamer_foundation", + "//foundation/multimedia/histreamer/engine/plugin:histreamer_plugin_intf", + "//foundation/multimedia/histreamer/engine/utils:histreamer_utils", + ] + } + + static_library("histreamer_plugin_Minimp3Demuxer") { + sources = [ + "minimp3_demuxer_plugin.cpp", + "minimp3_wrapper.c", + ] + public_configs = [ ":plugin_minimp3_adapter_config" ] + public_deps = [ + "//foundation/multimedia/histreamer/engine/foundation:histreamer_foundation", + "//foundation/multimedia/histreamer/engine/plugin:histreamer_plugin_intf", + "//foundation/multimedia/histreamer/engine/utils:histreamer_utils", + ] + } +} diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3.h b/engine/plugin/plugins/minimp3_adapter/minimp3.h new file mode 100755 index 00000000..e4f2b740 --- /dev/null +++ b/engine/plugin/plugins/minimp3_adapter/minimp3.h @@ -0,0 +1,1854 @@ +#ifndef MINIMP3_H +#define MINIMP3_H +/* + https://github.com/lieff/minimp3 + To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. + This software is distributed without any warranty. + See . +*/ +#include + +#define MINIMP3_MAX_SAMPLES_PER_FRAME (1152*2) + +typedef struct +{ + int frame_bytes, frame_offset, channels, hz, layer, bitrate_kbps; +} mp3dec_frame_info_t; + +typedef struct +{ + float mdct_overlap[2][9*32], qmf_state[15*2*32]; + int reserv, free_format_bytes; + unsigned char header[4], reserv_buf[511]; +} mp3dec_t; + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +void mp3dec_init(mp3dec_t *dec); +#ifndef MINIMP3_FLOAT_OUTPUT +typedef int16_t mp3d_sample_t; +#else /* MINIMP3_FLOAT_OUTPUT */ +typedef float mp3d_sample_t; +void mp3dec_f32_to_s16(const float *in, int16_t *out, int num_samples); +#endif /* MINIMP3_FLOAT_OUTPUT */ +int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_sample_t *pcm, mp3dec_frame_info_t *info); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* MINIMP3_H */ +#if defined(MINIMP3_IMPLEMENTATION) && !defined(_MINIMP3_IMPLEMENTATION_GUARD) +#define _MINIMP3_IMPLEMENTATION_GUARD + +#include +#include + +#define MAX_FREE_FORMAT_FRAME_SIZE 2304 /* more than ISO spec's */ +#ifndef MAX_FRAME_SYNC_MATCHES +#define MAX_FRAME_SYNC_MATCHES 10 +#endif /* MAX_FRAME_SYNC_MATCHES */ + +#define MAX_L3_FRAME_PAYLOAD_BYTES MAX_FREE_FORMAT_FRAME_SIZE /* MUST be >= 320000/8/32000*1152 = 1440 */ + +#define MAX_BITRESERVOIR_BYTES 511 +#define SHORT_BLOCK_TYPE 2 +#define STOP_BLOCK_TYPE 3 +#define MODE_MONO 3 +#define MODE_JOINT_STEREO 1 +#define HDR_SIZE 4 +#define HDR_IS_MONO(h) (((h[3]) & 0xC0) == 0xC0) +#define HDR_IS_MS_STEREO(h) (((h[3]) & 0xE0) == 0x60) +#define HDR_IS_FREE_FORMAT(h) (((h[2]) & 0xF0) == 0) +#define HDR_IS_CRC(h) (!((h[1]) & 1)) +#define HDR_TEST_PADDING(h) ((h[2]) & 0x2) +#define HDR_TEST_MPEG1(h) ((h[1]) & 0x8) +#define HDR_TEST_NOT_MPEG25(h) ((h[1]) & 0x10) +#define HDR_TEST_I_STEREO(h) ((h[3]) & 0x10) +#define HDR_TEST_MS_STEREO(h) ((h[3]) & 0x20) +#define HDR_GET_STEREO_MODE(h) (((h[3]) >> 6) & 3) +#define HDR_GET_STEREO_MODE_EXT(h) (((h[3]) >> 4) & 3) +#define HDR_GET_LAYER(h) (((h[1]) >> 1) & 3) +#define HDR_GET_BITRATE(h) ((h[2]) >> 4) +#define HDR_GET_SAMPLE_RATE(h) (((h[2]) >> 2) & 3) +#define HDR_GET_MY_SAMPLE_RATE(h) (HDR_GET_SAMPLE_RATE(h) + (((h[1] >> 3) & 1) + ((h[1] >> 4) & 1))*3) +#define HDR_IS_FRAME_576(h) ((h[1] & 14) == 2) +#define HDR_IS_LAYER_1(h) ((h[1] & 6) == 6) + +#define BITS_DEQUANTIZER_OUT -1 +#define MAX_SCF (255 + BITS_DEQUANTIZER_OUT*4 - 210) +#define MAX_SCFI ((MAX_SCF + 3) & ~3) + +#define MINIMP3_MIN(a, b) ((a) > (b) ? (b) : (a)) +#define MINIMP3_MAX(a, b) ((a) < (b) ? (b) : (a)) + +#if !defined(MINIMP3_NO_SIMD) + +#if !defined(MINIMP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64)) +/* x64 always have SSE2, arm64 always have neon, no need for generic code */ +#define MINIMP3_ONLY_SIMD +#endif /* SIMD checks... */ + +#if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__)) +#if defined(_MSC_VER) +#include +#endif /* defined(_MSC_VER) */ +#include +#define HAVE_SSE 1 +#define HAVE_SIMD 1 +#define VSTORE _mm_storeu_ps +#define VLD _mm_loadu_ps +#define VSET _mm_set1_ps +#define VADD _mm_add_ps +#define VSUB _mm_sub_ps +#define VMUL _mm_mul_ps +#define VMAC(a, x, y) _mm_add_ps(a, _mm_mul_ps(x, y)) +#define VMSB(a, x, y) _mm_sub_ps(a, _mm_mul_ps(x, y)) +#define VMUL_S(x, s) _mm_mul_ps(x, _mm_set1_ps(s)) +#define VREV(x) _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3)) +typedef __m128 f4; +#if defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) +#define minimp3_cpuid __cpuid +#else /* defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) */ +static __inline__ __attribute__((always_inline)) void minimp3_cpuid(int CPUInfo[], const int InfoType) +{ +#if defined(__PIC__) + __asm__ __volatile__( +#if defined(__x86_64__) + "push %%rbx\n" + "cpuid\n" + "xchgl %%ebx, %1\n" + "pop %%rbx\n" +#else /* defined(__x86_64__) */ + "xchgl %%ebx, %1\n" + "cpuid\n" + "xchgl %%ebx, %1\n" +#endif /* defined(__x86_64__) */ + : "=a" (CPUInfo[0]), "=r" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3]) + : "a" (InfoType)); +#else /* defined(__PIC__) */ + __asm__ __volatile__( + "cpuid" + : "=a" (CPUInfo[0]), "=b" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3]) + : "a" (InfoType)); +#endif /* defined(__PIC__)*/ +} +#endif /* defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) */ +static int have_simd(void) +{ +#ifdef MINIMP3_ONLY_SIMD + return 1; +#else /* MINIMP3_ONLY_SIMD */ + static int g_have_simd; + int CPUInfo[4]; +#ifdef MINIMP3_TEST + static int g_counter; + if (g_counter++ > 100) + return 0; +#endif /* MINIMP3_TEST */ + if (g_have_simd) + goto end; + minimp3_cpuid(CPUInfo, 0); + g_have_simd = 1; + if (CPUInfo[0] > 0) + { + minimp3_cpuid(CPUInfo, 1); + g_have_simd = (CPUInfo[3] & (1 << 26)) + 1; /* SSE2 */ + } +end: + return g_have_simd - 1; +#endif /* MINIMP3_ONLY_SIMD */ +} +#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) +#include +#define HAVE_SSE 0 +#define HAVE_SIMD 1 +#define VSTORE vst1q_f32 +#define VLD vld1q_f32 +#define VSET vmovq_n_f32 +#define VADD vaddq_f32 +#define VSUB vsubq_f32 +#define VMUL vmulq_f32 +#define VMAC(a, x, y) vmlaq_f32(a, x, y) +#define VMSB(a, x, y) vmlsq_f32(a, x, y) +#define VMUL_S(x, s) vmulq_f32(x, vmovq_n_f32(s)) +#define VREV(x) vcombine_f32(vget_high_f32(vrev64q_f32(x)), vget_low_f32(vrev64q_f32(x))) +typedef float32x4_t f4; +static int have_simd() +{ /* TODO: detect neon for !MINIMP3_ONLY_SIMD */ + return 1; +} +#else /* SIMD checks... */ +#define HAVE_SSE 0 +#define HAVE_SIMD 0 +#ifdef MINIMP3_ONLY_SIMD +#error MINIMP3_ONLY_SIMD used, but SSE/NEON not enabled +#endif /* MINIMP3_ONLY_SIMD */ +#endif /* SIMD checks... */ +#else /* !defined(MINIMP3_NO_SIMD) */ +#define HAVE_SIMD 0 +#endif /* !defined(MINIMP3_NO_SIMD) */ + +#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) +#define HAVE_ARMV6 1 +static __inline__ __attribute__((always_inline)) int32_t minimp3_clip_int16_arm(int32_t a) +{ + int32_t x = 0; + __asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a)); + return x; +} +#else +#define HAVE_ARMV6 0 +#endif + +typedef struct +{ + const uint8_t *buf; + int pos, limit; +} bs_t; + +typedef struct +{ + float scf[3*64]; + uint8_t total_bands, stereo_bands, bitalloc[64], scfcod[64]; +} L12_scale_info; + +typedef struct +{ + uint8_t tab_offset, code_tab_width, band_count; +} L12_subband_alloc_t; + +typedef struct +{ + const uint8_t *sfbtab; + uint16_t part_23_length, big_values, scalefac_compress; + uint8_t global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb; + uint8_t table_select[3], region_count[3], subblock_gain[3]; + uint8_t preflag, scalefac_scale, count1_table, scfsi; +} L3_gr_info_t; + +typedef struct +{ + bs_t bs; + uint8_t maindata[MAX_BITRESERVOIR_BYTES + MAX_L3_FRAME_PAYLOAD_BYTES]; + L3_gr_info_t gr_info[4]; + float grbuf[2][576], scf[40], syn[18 + 15][2*32]; + uint8_t ist_pos[2][39]; +} mp3dec_scratch_t; + +static void bs_init(bs_t *bs, const uint8_t *data, int bytes) +{ + bs->buf = data; + bs->pos = 0; + bs->limit = bytes*8; +} + +static uint32_t get_bits(bs_t *bs, int n) +{ + uint32_t next, cache = 0, s = bs->pos & 7; + int shl = n + s; + const uint8_t *p = bs->buf + (bs->pos >> 3); + if ((bs->pos += n) > bs->limit) + return 0; + next = *p++ & (255 >> s); + while ((shl -= 8) > 0) + { + cache |= next << shl; + next = *p++; + } + return cache | (next >> -shl); +} + +static int hdr_valid(const uint8_t *h) +{ + return h[0] == 0xff && + ((h[1] & 0xF0) == 0xf0 || (h[1] & 0xFE) == 0xe2) && + (HDR_GET_LAYER(h) != 0) && + (HDR_GET_BITRATE(h) != 15) && + (HDR_GET_SAMPLE_RATE(h) != 3); +} + +static int hdr_compare(const uint8_t *h1, const uint8_t *h2) +{ + return hdr_valid(h2) && + ((h1[1] ^ h2[1]) & 0xFE) == 0 && + ((h1[2] ^ h2[2]) & 0x0C) == 0 && + !(HDR_IS_FREE_FORMAT(h1) ^ HDR_IS_FREE_FORMAT(h2)); +} + +static unsigned hdr_bitrate_kbps(const uint8_t *h) +{ + static const uint8_t halfrate[2][3][15] = { + { { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,16,24,28,32,40,48,56,64,72,80,88,96,112,128 } }, + { { 0,16,20,24,28,32,40,48,56,64,80,96,112,128,160 }, { 0,16,24,28,32,40,48,56,64,80,96,112,128,160,192 }, { 0,16,32,48,64,80,96,112,128,144,160,176,192,208,224 } }, + }; + return 2*halfrate[!!HDR_TEST_MPEG1(h)][HDR_GET_LAYER(h) - 1][HDR_GET_BITRATE(h)]; +} + +static unsigned hdr_sample_rate_hz(const uint8_t *h) +{ + static const unsigned g_hz[3] = { 44100, 48000, 32000 }; + return g_hz[HDR_GET_SAMPLE_RATE(h)] >> (int)!HDR_TEST_MPEG1(h) >> (int)!HDR_TEST_NOT_MPEG25(h); +} + +static unsigned hdr_frame_samples(const uint8_t *h) +{ + return HDR_IS_LAYER_1(h) ? 384 : (1152 >> (int)HDR_IS_FRAME_576(h)); +} + +static int hdr_frame_bytes(const uint8_t *h, int free_format_size) +{ + int frame_bytes = hdr_frame_samples(h)*hdr_bitrate_kbps(h)*125/hdr_sample_rate_hz(h); + if (HDR_IS_LAYER_1(h)) + { + frame_bytes &= ~3; /* slot align */ + } + return frame_bytes ? frame_bytes : free_format_size; +} + +static int hdr_padding(const uint8_t *h) +{ + return HDR_TEST_PADDING(h) ? (HDR_IS_LAYER_1(h) ? 4 : 1) : 0; +} + +#ifndef MINIMP3_ONLY_MP3 +static const L12_subband_alloc_t *L12_subband_alloc_table(const uint8_t *hdr, L12_scale_info *sci) +{ + const L12_subband_alloc_t *alloc; + int mode = HDR_GET_STEREO_MODE(hdr); + int nbands, stereo_bands = (mode == MODE_MONO) ? 0 : (mode == MODE_JOINT_STEREO) ? (HDR_GET_STEREO_MODE_EXT(hdr) << 2) + 4 : 32; + + if (HDR_IS_LAYER_1(hdr)) + { + static const L12_subband_alloc_t g_alloc_L1[] = { { 76, 4, 32 } }; + alloc = g_alloc_L1; + nbands = 32; + } else if (!HDR_TEST_MPEG1(hdr)) + { + static const L12_subband_alloc_t g_alloc_L2M2[] = { { 60, 4, 4 }, { 44, 3, 7 }, { 44, 2, 19 } }; + alloc = g_alloc_L2M2; + nbands = 30; + } else + { + static const L12_subband_alloc_t g_alloc_L2M1[] = { { 0, 4, 3 }, { 16, 4, 8 }, { 32, 3, 12 }, { 40, 2, 7 } }; + int sample_rate_idx = HDR_GET_SAMPLE_RATE(hdr); + unsigned kbps = hdr_bitrate_kbps(hdr) >> (int)(mode != MODE_MONO); + if (!kbps) /* free-format */ + { + kbps = 192; + } + + alloc = g_alloc_L2M1; + nbands = 27; + if (kbps < 56) + { + static const L12_subband_alloc_t g_alloc_L2M1_lowrate[] = { { 44, 4, 2 }, { 44, 3, 10 } }; + alloc = g_alloc_L2M1_lowrate; + nbands = sample_rate_idx == 2 ? 12 : 8; + } else if (kbps >= 96 && sample_rate_idx != 1) + { + nbands = 30; + } + } + + sci->total_bands = (uint8_t)nbands; + sci->stereo_bands = (uint8_t)MINIMP3_MIN(stereo_bands, nbands); + + return alloc; +} + +static void L12_read_scalefactors(bs_t *bs, uint8_t *pba, uint8_t *scfcod, int bands, float *scf) +{ + static const float g_deq_L12[18*3] = { +#define DQ(x) 9.53674316e-07f/x, 7.56931807e-07f/x, 6.00777173e-07f/x + DQ(3),DQ(7),DQ(15),DQ(31),DQ(63),DQ(127),DQ(255),DQ(511),DQ(1023),DQ(2047),DQ(4095),DQ(8191),DQ(16383),DQ(32767),DQ(65535),DQ(3),DQ(5),DQ(9) + }; + int i, m; + for (i = 0; i < bands; i++) + { + float s = 0; + int ba = *pba++; + int mask = ba ? 4 + ((19 >> scfcod[i]) & 3) : 0; + for (m = 4; m; m >>= 1) + { + if (mask & m) + { + int b = get_bits(bs, 6); + s = g_deq_L12[ba*3 - 6 + b % 3]*(1 << 21 >> b/3); + } + *scf++ = s; + } + } +} + +static void L12_read_scale_info(const uint8_t *hdr, bs_t *bs, L12_scale_info *sci) +{ + static const uint8_t g_bitalloc_code_tab[] = { + 0,17, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16, + 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,16, + 0,17,18, 3,19,4,5,16, + 0,17,18,16, + 0,17,18,19, 4,5,6, 7,8, 9,10,11,12,13,14,15, + 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,14, + 0, 2, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16 + }; + const L12_subband_alloc_t *subband_alloc = L12_subband_alloc_table(hdr, sci); + + int i, k = 0, ba_bits = 0; + const uint8_t *ba_code_tab = g_bitalloc_code_tab; + + for (i = 0; i < sci->total_bands; i++) + { + uint8_t ba; + if (i == k) + { + k += subband_alloc->band_count; + ba_bits = subband_alloc->code_tab_width; + ba_code_tab = g_bitalloc_code_tab + subband_alloc->tab_offset; + subband_alloc++; + } + ba = ba_code_tab[get_bits(bs, ba_bits)]; + sci->bitalloc[2*i] = ba; + if (i < sci->stereo_bands) + { + ba = ba_code_tab[get_bits(bs, ba_bits)]; + } + sci->bitalloc[2*i + 1] = sci->stereo_bands ? ba : 0; + } + + for (i = 0; i < 2*sci->total_bands; i++) + { + sci->scfcod[i] = sci->bitalloc[i] ? HDR_IS_LAYER_1(hdr) ? 2 : get_bits(bs, 2) : 6; + } + + L12_read_scalefactors(bs, sci->bitalloc, sci->scfcod, sci->total_bands*2, sci->scf); + + for (i = sci->stereo_bands; i < sci->total_bands; i++) + { + sci->bitalloc[2*i + 1] = 0; + } +} + +static int L12_dequantize_granule(float *grbuf, bs_t *bs, L12_scale_info *sci, int group_size) +{ + int i, j, k, choff = 576; + for (j = 0; j < 4; j++) + { + float *dst = grbuf + group_size*j; + for (i = 0; i < 2*sci->total_bands; i++) + { + int ba = sci->bitalloc[i]; + if (ba != 0) + { + if (ba < 17) + { + int half = (1 << (ba - 1)) - 1; + for (k = 0; k < group_size; k++) + { + dst[k] = (float)((int)get_bits(bs, ba) - half); + } + } else + { + unsigned mod = (2 << (ba - 17)) + 1; /* 3, 5, 9 */ + unsigned code = get_bits(bs, mod + 2 - (mod >> 3)); /* 5, 7, 10 */ + for (k = 0; k < group_size; k++, code /= mod) + { + dst[k] = (float)((int)(code % mod - mod/2)); + } + } + } + dst += choff; + choff = 18 - choff; + } + } + return group_size*4; +} + +static void L12_apply_scf_384(L12_scale_info *sci, const float *scf, float *dst) +{ + int i, k; + memcpy(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float)); + for (i = 0; i < sci->total_bands; i++, dst += 18, scf += 6) + { + for (k = 0; k < 12; k++) + { + dst[k + 0] *= scf[0]; + dst[k + 576] *= scf[3]; + } + } +} +#endif /* MINIMP3_ONLY_MP3 */ + +static int L3_read_side_info(bs_t *bs, L3_gr_info_t *gr, const uint8_t *hdr) +{ + static const uint8_t g_scf_long[8][23] = { + { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, + { 12,12,12,12,12,12,16,20,24,28,32,40,48,56,64,76,90,2,2,2,2,2,0 }, + { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, + { 6,6,6,6,6,6,8,10,12,14,16,18,22,26,32,38,46,54,62,70,76,36,0 }, + { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, + { 4,4,4,4,4,4,6,6,8,8,10,12,16,20,24,28,34,42,50,54,76,158,0 }, + { 4,4,4,4,4,4,6,6,6,8,10,12,16,18,22,28,34,40,46,54,54,192,0 }, + { 4,4,4,4,4,4,6,6,8,10,12,16,20,24,30,38,46,56,68,84,102,26,0 } + }; + static const uint8_t g_scf_short[8][40] = { + { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 8,8,8,8,8,8,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 }, + { 4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 }, + { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,32,32,32,44,44,44,12,12,12,0 }, + { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 }, + { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 }, + { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 } + }; + static const uint8_t g_scf_mixed[8][40] = { + { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 12,12,12,4,4,4,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 }, + { 6,6,6,6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 }, + { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,32,32,32,44,44,44,12,12,12,0 }, + { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, + { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 }, + { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 }, + { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 } + }; + + unsigned tables, scfsi = 0; + int main_data_begin, part_23_sum = 0; + int sr_idx = HDR_GET_MY_SAMPLE_RATE(hdr); sr_idx -= (sr_idx != 0); + int gr_count = HDR_IS_MONO(hdr) ? 1 : 2; + + if (HDR_TEST_MPEG1(hdr)) + { + gr_count *= 2; + main_data_begin = get_bits(bs, 9); + scfsi = get_bits(bs, 7 + gr_count); + } else + { + main_data_begin = get_bits(bs, 8 + gr_count) >> gr_count; + } + + do + { + if (HDR_IS_MONO(hdr)) + { + scfsi <<= 4; + } + gr->part_23_length = (uint16_t)get_bits(bs, 12); + part_23_sum += gr->part_23_length; + gr->big_values = (uint16_t)get_bits(bs, 9); + if (gr->big_values > 288) + { + return -1; + } + gr->global_gain = (uint8_t)get_bits(bs, 8); + gr->scalefac_compress = (uint16_t)get_bits(bs, HDR_TEST_MPEG1(hdr) ? 4 : 9); + gr->sfbtab = g_scf_long[sr_idx]; + gr->n_long_sfb = 22; + gr->n_short_sfb = 0; + if (get_bits(bs, 1)) + { + gr->block_type = (uint8_t)get_bits(bs, 2); + if (!gr->block_type) + { + return -1; + } + gr->mixed_block_flag = (uint8_t)get_bits(bs, 1); + gr->region_count[0] = 7; + gr->region_count[1] = 255; + if (gr->block_type == SHORT_BLOCK_TYPE) + { + scfsi &= 0x0F0F; + if (!gr->mixed_block_flag) + { + gr->region_count[0] = 8; + gr->sfbtab = g_scf_short[sr_idx]; + gr->n_long_sfb = 0; + gr->n_short_sfb = 39; + } else + { + gr->sfbtab = g_scf_mixed[sr_idx]; + gr->n_long_sfb = HDR_TEST_MPEG1(hdr) ? 8 : 6; + gr->n_short_sfb = 30; + } + } + tables = get_bits(bs, 10); + tables <<= 5; + gr->subblock_gain[0] = (uint8_t)get_bits(bs, 3); + gr->subblock_gain[1] = (uint8_t)get_bits(bs, 3); + gr->subblock_gain[2] = (uint8_t)get_bits(bs, 3); + } else + { + gr->block_type = 0; + gr->mixed_block_flag = 0; + tables = get_bits(bs, 15); + gr->region_count[0] = (uint8_t)get_bits(bs, 4); + gr->region_count[1] = (uint8_t)get_bits(bs, 3); + gr->region_count[2] = 255; + } + gr->table_select[0] = (uint8_t)(tables >> 10); + gr->table_select[1] = (uint8_t)((tables >> 5) & 31); + gr->table_select[2] = (uint8_t)((tables) & 31); + gr->preflag = HDR_TEST_MPEG1(hdr) ? get_bits(bs, 1) : (gr->scalefac_compress >= 500); + gr->scalefac_scale = (uint8_t)get_bits(bs, 1); + gr->count1_table = (uint8_t)get_bits(bs, 1); + gr->scfsi = (uint8_t)((scfsi >> 12) & 15); + scfsi <<= 4; + gr++; + } while(--gr_count); + + if (part_23_sum + bs->pos > bs->limit + main_data_begin*8) + { + return -1; + } + + return main_data_begin; +} + +static void L3_read_scalefactors(uint8_t *scf, uint8_t *ist_pos, const uint8_t *scf_size, const uint8_t *scf_count, bs_t *bitbuf, int scfsi) +{ + int i, k; + for (i = 0; i < 4 && scf_count[i]; i++, scfsi *= 2) + { + int cnt = scf_count[i]; + if (scfsi & 8) + { + memcpy(scf, ist_pos, cnt); + } else + { + int bits = scf_size[i]; + if (!bits) + { + memset(scf, 0, cnt); + memset(ist_pos, 0, cnt); + } else + { + int max_scf = (scfsi < 0) ? (1 << bits) - 1 : -1; + for (k = 0; k < cnt; k++) + { + int s = get_bits(bitbuf, bits); + ist_pos[k] = (s == max_scf ? -1 : s); + scf[k] = s; + } + } + } + ist_pos += cnt; + scf += cnt; + } + scf[0] = scf[1] = scf[2] = 0; +} + +static float L3_ldexp_q2(float y, int exp_q2) +{ + static const float g_expfrac[4] = { 9.31322575e-10f,7.83145814e-10f,6.58544508e-10f,5.53767716e-10f }; + int e; + do + { + e = MINIMP3_MIN(30*4, exp_q2); + y *= g_expfrac[e & 3]*(1 << 30 >> (e >> 2)); + } while ((exp_q2 -= e) > 0); + return y; +} + +static void L3_decode_scalefactors(const uint8_t *hdr, uint8_t *ist_pos, bs_t *bs, const L3_gr_info_t *gr, float *scf, int ch) +{ + static const uint8_t g_scf_partitions[3][28] = { + { 6,5,5, 5,6,5,5,5,6,5, 7,3,11,10,0,0, 7, 7, 7,0, 6, 6,6,3, 8, 8,5,0 }, + { 8,9,6,12,6,9,9,9,6,9,12,6,15,18,0,0, 6,15,12,0, 6,12,9,6, 6,18,9,0 }, + { 9,9,6,12,9,9,9,9,9,9,12,6,18,18,0,0,12,12,12,0,12, 9,9,6,15,12,9,0 } + }; + const uint8_t *scf_partition = g_scf_partitions[!!gr->n_short_sfb + !gr->n_long_sfb]; + uint8_t scf_size[4], iscf[40]; + int i, scf_shift = gr->scalefac_scale + 1, gain_exp, scfsi = gr->scfsi; + float gain; + + if (HDR_TEST_MPEG1(hdr)) + { + static const uint8_t g_scfc_decode[16] = { 0,1,2,3, 12,5,6,7, 9,10,11,13, 14,15,18,19 }; + int part = g_scfc_decode[gr->scalefac_compress]; + scf_size[1] = scf_size[0] = (uint8_t)(part >> 2); + scf_size[3] = scf_size[2] = (uint8_t)(part & 3); + } else + { + static const uint8_t g_mod[6*4] = { 5,5,4,4,5,5,4,1,4,3,1,1,5,6,6,1,4,4,4,1,4,3,1,1 }; + int k, modprod, sfc, ist = HDR_TEST_I_STEREO(hdr) && ch; + sfc = gr->scalefac_compress >> ist; + for (k = ist*3*4; sfc >= 0; sfc -= modprod, k += 4) + { + for (modprod = 1, i = 3; i >= 0; i--) + { + scf_size[i] = (uint8_t)(sfc / modprod % g_mod[k + i]); + modprod *= g_mod[k + i]; + } + } + scf_partition += k; + scfsi = -16; + } + L3_read_scalefactors(iscf, ist_pos, scf_size, scf_partition, bs, scfsi); + + if (gr->n_short_sfb) + { + int sh = 3 - scf_shift; + for (i = 0; i < gr->n_short_sfb; i += 3) + { + iscf[gr->n_long_sfb + i + 0] += gr->subblock_gain[0] << sh; + iscf[gr->n_long_sfb + i + 1] += gr->subblock_gain[1] << sh; + iscf[gr->n_long_sfb + i + 2] += gr->subblock_gain[2] << sh; + } + } else if (gr->preflag) + { + static const uint8_t g_preamp[10] = { 1,1,1,1,2,2,3,3,3,2 }; + for (i = 0; i < 10; i++) + { + iscf[11 + i] += g_preamp[i]; + } + } + + gain_exp = gr->global_gain + BITS_DEQUANTIZER_OUT*4 - 210 - (HDR_IS_MS_STEREO(hdr) ? 2 : 0); + gain = L3_ldexp_q2(1 << (MAX_SCFI/4), MAX_SCFI - gain_exp); + for (i = 0; i < (int)(gr->n_long_sfb + gr->n_short_sfb); i++) + { + scf[i] = L3_ldexp_q2(gain, iscf[i] << scf_shift); + } +} + +static const float g_pow43[129 + 16] = { + 0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f, + 0,1,2.519842f,4.326749f,6.349604f,8.549880f,10.902724f,13.390518f,16.000000f,18.720754f,21.544347f,24.463781f,27.473142f,30.567351f,33.741992f,36.993181f,40.317474f,43.711787f,47.173345f,50.699631f,54.288352f,57.937408f,61.644865f,65.408941f,69.227979f,73.100443f,77.024898f,81.000000f,85.024491f,89.097188f,93.216975f,97.382800f,101.593667f,105.848633f,110.146801f,114.487321f,118.869381f,123.292209f,127.755065f,132.257246f,136.798076f,141.376907f,145.993119f,150.646117f,155.335327f,160.060199f,164.820202f,169.614826f,174.443577f,179.305980f,184.201575f,189.129918f,194.090580f,199.083145f,204.107210f,209.162385f,214.248292f,219.364564f,224.510845f,229.686789f,234.892058f,240.126328f,245.389280f,250.680604f,256.000000f,261.347174f,266.721841f,272.123723f,277.552547f,283.008049f,288.489971f,293.998060f,299.532071f,305.091761f,310.676898f,316.287249f,321.922592f,327.582707f,333.267377f,338.976394f,344.709550f,350.466646f,356.247482f,362.051866f,367.879608f,373.730522f,379.604427f,385.501143f,391.420496f,397.362314f,403.326427f,409.312672f,415.320884f,421.350905f,427.402579f,433.475750f,439.570269f,445.685987f,451.822757f,457.980436f,464.158883f,470.357960f,476.577530f,482.817459f,489.077615f,495.357868f,501.658090f,507.978156f,514.317941f,520.677324f,527.056184f,533.454404f,539.871867f,546.308458f,552.764065f,559.238575f,565.731879f,572.243870f,578.774440f,585.323483f,591.890898f,598.476581f,605.080431f,611.702349f,618.342238f,625.000000f,631.675540f,638.368763f,645.079578f +}; + +static float L3_pow_43(int x) +{ + float frac; + int sign, mult = 256; + + if (x < 129) + { + return g_pow43[16 + x]; + } + + if (x < 1024) + { + mult = 16; + x <<= 3; + } + + sign = 2*x & 64; + frac = (float)((x & 63) - sign) / ((x & ~63) + sign); + return g_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; +} + +static void L3_huffman(float *dst, bs_t *bs, const L3_gr_info_t *gr_info, const float *scf, int layer3gr_limit) +{ + static const int16_t tabs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 785,785,785,785,784,784,784,784,513,513,513,513,513,513,513,513,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256, + -255,1313,1298,1282,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,290,288, + -255,1313,1298,1282,769,769,769,769,529,529,529,529,529,529,529,529,528,528,528,528,528,528,528,528,512,512,512,512,512,512,512,512,290,288, + -253,-318,-351,-367,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,819,818,547,547,275,275,275,275,561,560,515,546,289,274,288,258, + -254,-287,1329,1299,1314,1312,1057,1057,1042,1042,1026,1026,784,784,784,784,529,529,529,529,529,529,529,529,769,769,769,769,768,768,768,768,563,560,306,306,291,259, + -252,-413,-477,-542,1298,-575,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-383,-399,1107,1092,1106,1061,849,849,789,789,1104,1091,773,773,1076,1075,341,340,325,309,834,804,577,577,532,532,516,516,832,818,803,816,561,561,531,531,515,546,289,289,288,258, + -252,-429,-493,-559,1057,1057,1042,1042,529,529,529,529,529,529,529,529,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,-382,1077,-415,1106,1061,1104,849,849,789,789,1091,1076,1029,1075,834,834,597,581,340,340,339,324,804,833,532,532,832,772,818,803,817,787,816,771,290,290,290,290,288,258, + -253,-349,-414,-447,-463,1329,1299,-479,1314,1312,1057,1057,1042,1042,1026,1026,785,785,785,785,784,784,784,784,769,769,769,769,768,768,768,768,-319,851,821,-335,836,850,805,849,341,340,325,336,533,533,579,579,564,564,773,832,578,548,563,516,321,276,306,291,304,259, + -251,-572,-733,-830,-863,-879,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,1396,1351,1381,1366,1395,1335,1380,-559,1334,1138,1138,1063,1063,1350,1392,1031,1031,1062,1062,1364,1363,1120,1120,1333,1348,881,881,881,881,375,374,359,373,343,358,341,325,791,791,1123,1122,-703,1105,1045,-719,865,865,790,790,774,774,1104,1029,338,293,323,308,-799,-815,833,788,772,818,803,816,322,292,307,320,561,531,515,546,289,274,288,258, + -251,-525,-605,-685,-765,-831,-846,1298,1057,1057,1312,1282,785,785,785,785,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,1399,1398,1383,1367,1382,1396,1351,-511,1381,1366,1139,1139,1079,1079,1124,1124,1364,1349,1363,1333,882,882,882,882,807,807,807,807,1094,1094,1136,1136,373,341,535,535,881,775,867,822,774,-591,324,338,-671,849,550,550,866,864,609,609,293,336,534,534,789,835,773,-751,834,804,308,307,833,788,832,772,562,562,547,547,305,275,560,515,290,290, + -252,-397,-477,-557,-622,-653,-719,-735,-750,1329,1299,1314,1057,1057,1042,1042,1312,1282,1024,1024,785,785,785,785,784,784,784,784,769,769,769,769,-383,1127,1141,1111,1126,1140,1095,1110,869,869,883,883,1079,1109,882,882,375,374,807,868,838,881,791,-463,867,822,368,263,852,837,836,-543,610,610,550,550,352,336,534,534,865,774,851,821,850,805,593,533,579,564,773,832,578,578,548,548,577,577,307,276,306,291,516,560,259,259, + -250,-2107,-2507,-2764,-2909,-2974,-3007,-3023,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-767,-1052,-1213,-1277,-1358,-1405,-1469,-1535,-1550,-1582,-1614,-1647,-1662,-1694,-1726,-1759,-1774,-1807,-1822,-1854,-1886,1565,-1919,-1935,-1951,-1967,1731,1730,1580,1717,-1983,1729,1564,-1999,1548,-2015,-2031,1715,1595,-2047,1714,-2063,1610,-2079,1609,-2095,1323,1323,1457,1457,1307,1307,1712,1547,1641,1700,1699,1594,1685,1625,1442,1442,1322,1322,-780,-973,-910,1279,1278,1277,1262,1276,1261,1275,1215,1260,1229,-959,974,974,989,989,-943,735,478,478,495,463,506,414,-1039,1003,958,1017,927,942,987,957,431,476,1272,1167,1228,-1183,1256,-1199,895,895,941,941,1242,1227,1212,1135,1014,1014,490,489,503,487,910,1013,985,925,863,894,970,955,1012,847,-1343,831,755,755,984,909,428,366,754,559,-1391,752,486,457,924,997,698,698,983,893,740,740,908,877,739,739,667,667,953,938,497,287,271,271,683,606,590,712,726,574,302,302,738,736,481,286,526,725,605,711,636,724,696,651,589,681,666,710,364,467,573,695,466,466,301,465,379,379,709,604,665,679,316,316,634,633,436,436,464,269,424,394,452,332,438,363,347,408,393,448,331,422,362,407,392,421,346,406,391,376,375,359,1441,1306,-2367,1290,-2383,1337,-2399,-2415,1426,1321,-2431,1411,1336,-2447,-2463,-2479,1169,1169,1049,1049,1424,1289,1412,1352,1319,-2495,1154,1154,1064,1064,1153,1153,416,390,360,404,403,389,344,374,373,343,358,372,327,357,342,311,356,326,1395,1394,1137,1137,1047,1047,1365,1392,1287,1379,1334,1364,1349,1378,1318,1363,792,792,792,792,1152,1152,1032,1032,1121,1121,1046,1046,1120,1120,1030,1030,-2895,1106,1061,1104,849,849,789,789,1091,1076,1029,1090,1060,1075,833,833,309,324,532,532,832,772,818,803,561,561,531,560,515,546,289,274,288,258, + -250,-1179,-1579,-1836,-1996,-2124,-2253,-2333,-2413,-2477,-2542,-2574,-2607,-2622,-2655,1314,1313,1298,1312,1282,785,785,785,785,1040,1040,1025,1025,768,768,768,768,-766,-798,-830,-862,-895,-911,-927,-943,-959,-975,-991,-1007,-1023,-1039,-1055,-1070,1724,1647,-1103,-1119,1631,1767,1662,1738,1708,1723,-1135,1780,1615,1779,1599,1677,1646,1778,1583,-1151,1777,1567,1737,1692,1765,1722,1707,1630,1751,1661,1764,1614,1736,1676,1763,1750,1645,1598,1721,1691,1762,1706,1582,1761,1566,-1167,1749,1629,767,766,751,765,494,494,735,764,719,749,734,763,447,447,748,718,477,506,431,491,446,476,461,505,415,430,475,445,504,399,460,489,414,503,383,474,429,459,502,502,746,752,488,398,501,473,413,472,486,271,480,270,-1439,-1455,1357,-1471,-1487,-1503,1341,1325,-1519,1489,1463,1403,1309,-1535,1372,1448,1418,1476,1356,1462,1387,-1551,1475,1340,1447,1402,1386,-1567,1068,1068,1474,1461,455,380,468,440,395,425,410,454,364,467,466,464,453,269,409,448,268,432,1371,1473,1432,1417,1308,1460,1355,1446,1459,1431,1083,1083,1401,1416,1458,1445,1067,1067,1370,1457,1051,1051,1291,1430,1385,1444,1354,1415,1400,1443,1082,1082,1173,1113,1186,1066,1185,1050,-1967,1158,1128,1172,1097,1171,1081,-1983,1157,1112,416,266,375,400,1170,1142,1127,1065,793,793,1169,1033,1156,1096,1141,1111,1155,1080,1126,1140,898,898,808,808,897,897,792,792,1095,1152,1032,1125,1110,1139,1079,1124,882,807,838,881,853,791,-2319,867,368,263,822,852,837,866,806,865,-2399,851,352,262,534,534,821,836,594,594,549,549,593,593,533,533,848,773,579,579,564,578,548,563,276,276,577,576,306,291,516,560,305,305,275,259, + -251,-892,-2058,-2620,-2828,-2957,-3023,-3039,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,-559,1530,-575,-591,1528,1527,1407,1526,1391,1023,1023,1023,1023,1525,1375,1268,1268,1103,1103,1087,1087,1039,1039,1523,-604,815,815,815,815,510,495,509,479,508,463,507,447,431,505,415,399,-734,-782,1262,-815,1259,1244,-831,1258,1228,-847,-863,1196,-879,1253,987,987,748,-767,493,493,462,477,414,414,686,669,478,446,461,445,474,429,487,458,412,471,1266,1264,1009,1009,799,799,-1019,-1276,-1452,-1581,-1677,-1757,-1821,-1886,-1933,-1997,1257,1257,1483,1468,1512,1422,1497,1406,1467,1496,1421,1510,1134,1134,1225,1225,1466,1451,1374,1405,1252,1252,1358,1480,1164,1164,1251,1251,1238,1238,1389,1465,-1407,1054,1101,-1423,1207,-1439,830,830,1248,1038,1237,1117,1223,1148,1236,1208,411,426,395,410,379,269,1193,1222,1132,1235,1221,1116,976,976,1192,1162,1177,1220,1131,1191,963,963,-1647,961,780,-1663,558,558,994,993,437,408,393,407,829,978,813,797,947,-1743,721,721,377,392,844,950,828,890,706,706,812,859,796,960,948,843,934,874,571,571,-1919,690,555,689,421,346,539,539,944,779,918,873,932,842,903,888,570,570,931,917,674,674,-2575,1562,-2591,1609,-2607,1654,1322,1322,1441,1441,1696,1546,1683,1593,1669,1624,1426,1426,1321,1321,1639,1680,1425,1425,1305,1305,1545,1668,1608,1623,1667,1592,1638,1666,1320,1320,1652,1607,1409,1409,1304,1304,1288,1288,1664,1637,1395,1395,1335,1335,1622,1636,1394,1394,1319,1319,1606,1621,1392,1392,1137,1137,1137,1137,345,390,360,375,404,373,1047,-2751,-2767,-2783,1062,1121,1046,-2799,1077,-2815,1106,1061,789,789,1105,1104,263,355,310,340,325,354,352,262,339,324,1091,1076,1029,1090,1060,1075,833,833,788,788,1088,1028,818,818,803,803,561,561,531,531,816,771,546,546,289,274,288,258, + -253,-317,-381,-446,-478,-509,1279,1279,-811,-1179,-1451,-1756,-1900,-2028,-2189,-2253,-2333,-2414,-2445,-2511,-2526,1313,1298,-2559,1041,1041,1040,1040,1025,1025,1024,1024,1022,1007,1021,991,1020,975,1019,959,687,687,1018,1017,671,671,655,655,1016,1015,639,639,758,758,623,623,757,607,756,591,755,575,754,559,543,543,1009,783,-575,-621,-685,-749,496,-590,750,749,734,748,974,989,1003,958,988,973,1002,942,987,957,972,1001,926,986,941,971,956,1000,910,985,925,999,894,970,-1071,-1087,-1102,1390,-1135,1436,1509,1451,1374,-1151,1405,1358,1480,1420,-1167,1507,1494,1389,1342,1465,1435,1450,1326,1505,1310,1493,1373,1479,1404,1492,1464,1419,428,443,472,397,736,526,464,464,486,457,442,471,484,482,1357,1449,1434,1478,1388,1491,1341,1490,1325,1489,1463,1403,1309,1477,1372,1448,1418,1433,1476,1356,1462,1387,-1439,1475,1340,1447,1402,1474,1324,1461,1371,1473,269,448,1432,1417,1308,1460,-1711,1459,-1727,1441,1099,1099,1446,1386,1431,1401,-1743,1289,1083,1083,1160,1160,1458,1445,1067,1067,1370,1457,1307,1430,1129,1129,1098,1098,268,432,267,416,266,400,-1887,1144,1187,1082,1173,1113,1186,1066,1050,1158,1128,1143,1172,1097,1171,1081,420,391,1157,1112,1170,1142,1127,1065,1169,1049,1156,1096,1141,1111,1155,1080,1126,1154,1064,1153,1140,1095,1048,-2159,1125,1110,1137,-2175,823,823,1139,1138,807,807,384,264,368,263,868,838,853,791,867,822,852,837,866,806,865,790,-2319,851,821,836,352,262,850,805,849,-2399,533,533,835,820,336,261,578,548,563,577,532,532,832,772,562,562,547,547,305,275,560,515,290,290,288,258 }; + static const uint8_t tab32[] = { 130,162,193,209,44,28,76,140,9,9,9,9,9,9,9,9,190,254,222,238,126,94,157,157,109,61,173,205 }; + static const uint8_t tab33[] = { 252,236,220,204,188,172,156,140,124,108,92,76,60,44,28,12 }; + static const int16_t tabindex[2*16] = { 0,32,64,98,0,132,180,218,292,364,426,538,648,746,0,1126,1460,1460,1460,1460,1460,1460,1460,1460,1842,1842,1842,1842,1842,1842,1842,1842 }; + static const uint8_t g_linbits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,8,10,13,4,5,6,7,8,9,11,13 }; + +#define PEEK_BITS(n) (bs_cache >> (32 - n)) +#define FLUSH_BITS(n) { bs_cache <<= (n); bs_sh += (n); } +#define CHECK_BITS while (bs_sh >= 0) { bs_cache |= (uint32_t)*bs_next_ptr++ << bs_sh; bs_sh -= 8; } +#define BSPOS ((bs_next_ptr - bs->buf)*8 - 24 + bs_sh) + + float one = 0.0f; + int ireg = 0, big_val_cnt = gr_info->big_values; + const uint8_t *sfb = gr_info->sfbtab; + const uint8_t *bs_next_ptr = bs->buf + bs->pos/8; + uint32_t bs_cache = (((bs_next_ptr[0]*256u + bs_next_ptr[1])*256u + bs_next_ptr[2])*256u + bs_next_ptr[3]) << (bs->pos & 7); + int pairs_to_decode, np, bs_sh = (bs->pos & 7) - 8; + bs_next_ptr += 4; + + while (big_val_cnt > 0) + { + int tab_num = gr_info->table_select[ireg]; + int sfb_cnt = gr_info->region_count[ireg++]; + const int16_t *codebook = tabs + tabindex[tab_num]; + int linbits = g_linbits[tab_num]; + if (linbits) + { + do + { + np = *sfb++ / 2; + pairs_to_decode = MINIMP3_MIN(big_val_cnt, np); + one = *scf++; + do + { + int j, w = 5; + int leaf = codebook[PEEK_BITS(w)]; + while (leaf < 0) + { + FLUSH_BITS(w); + w = leaf & 7; + leaf = codebook[PEEK_BITS(w) - (leaf >> 3)]; + } + FLUSH_BITS(leaf >> 8); + + for (j = 0; j < 2; j++, dst++, leaf >>= 4) + { + int lsb = leaf & 0x0F; + if (lsb == 15) + { + lsb += PEEK_BITS(linbits); + FLUSH_BITS(linbits); + CHECK_BITS; + *dst = one*L3_pow_43(lsb)*((int32_t)bs_cache < 0 ? -1: 1); + } else + { + *dst = g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + } + FLUSH_BITS(lsb ? 1 : 0); + } + CHECK_BITS; + } while (--pairs_to_decode); + } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + } else + { + do + { + np = *sfb++ / 2; + pairs_to_decode = MINIMP3_MIN(big_val_cnt, np); + one = *scf++; + do + { + int j, w = 5; + int leaf = codebook[PEEK_BITS(w)]; + while (leaf < 0) + { + FLUSH_BITS(w); + w = leaf & 7; + leaf = codebook[PEEK_BITS(w) - (leaf >> 3)]; + } + FLUSH_BITS(leaf >> 8); + + for (j = 0; j < 2; j++, dst++, leaf >>= 4) + { + int lsb = leaf & 0x0F; + *dst = g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; + FLUSH_BITS(lsb ? 1 : 0); + } + CHECK_BITS; + } while (--pairs_to_decode); + } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); + } + } + + for (np = 1 - big_val_cnt;; dst += 4) + { + const uint8_t *codebook_count1 = (gr_info->count1_table) ? tab33 : tab32; + int leaf = codebook_count1[PEEK_BITS(4)]; + if (!(leaf & 8)) + { + leaf = codebook_count1[(leaf >> 3) + (bs_cache << 4 >> (32 - (leaf & 3)))]; + } + FLUSH_BITS(leaf & 7); + if (BSPOS > layer3gr_limit) + { + break; + } +#define RELOAD_SCALEFACTOR if (!--np) { np = *sfb++/2; if (!np) break; one = *scf++; } +#define DEQ_COUNT1(s) if (leaf & (128 >> s)) { dst[s] = ((int32_t)bs_cache < 0) ? -one : one; FLUSH_BITS(1) } + RELOAD_SCALEFACTOR; + DEQ_COUNT1(0); + DEQ_COUNT1(1); + RELOAD_SCALEFACTOR; + DEQ_COUNT1(2); + DEQ_COUNT1(3); + CHECK_BITS; + } + + bs->pos = layer3gr_limit; +} + +static void L3_midside_stereo(float *left, int n) +{ + int i = 0; + float *right = left + 576; +#if HAVE_SIMD + if (have_simd()) for (; i < n - 3; i += 4) + { + f4 vl = VLD(left + i); + f4 vr = VLD(right + i); + VSTORE(left + i, VADD(vl, vr)); + VSTORE(right + i, VSUB(vl, vr)); + } +#endif /* HAVE_SIMD */ + for (; i < n; i++) + { + float a = left[i]; + float b = right[i]; + left[i] = a + b; + right[i] = a - b; + } +} + +static void L3_intensity_stereo_band(float *left, int n, float kl, float kr) +{ + int i; + for (i = 0; i < n; i++) + { + left[i + 576] = left[i]*kr; + left[i] = left[i]*kl; + } +} + +static void L3_stereo_top_band(const float *right, const uint8_t *sfb, int nbands, int max_band[3]) +{ + int i, k; + + max_band[0] = max_band[1] = max_band[2] = -1; + + for (i = 0; i < nbands; i++) + { + for (k = 0; k < sfb[i]; k += 2) + { + if (right[k] != 0 || right[k + 1] != 0) + { + max_band[i % 3] = i; + break; + } + } + right += sfb[i]; + } +} + +static void L3_stereo_process(float *left, const uint8_t *ist_pos, const uint8_t *sfb, const uint8_t *hdr, int max_band[3], int mpeg2_sh) +{ + static const float g_pan[7*2] = { 0,1,0.21132487f,0.78867513f,0.36602540f,0.63397460f,0.5f,0.5f,0.63397460f,0.36602540f,0.78867513f,0.21132487f,1,0 }; + unsigned i, max_pos = HDR_TEST_MPEG1(hdr) ? 7 : 64; + + for (i = 0; sfb[i]; i++) + { + unsigned ipos = ist_pos[i]; + if ((int)i > max_band[i % 3] && ipos < max_pos) + { + float kl, kr, s = HDR_TEST_MS_STEREO(hdr) ? 1.41421356f : 1; + if (HDR_TEST_MPEG1(hdr)) + { + kl = g_pan[2*ipos]; + kr = g_pan[2*ipos + 1]; + } else + { + kl = 1; + kr = L3_ldexp_q2(1, (ipos + 1) >> 1 << mpeg2_sh); + if (ipos & 1) + { + kl = kr; + kr = 1; + } + } + L3_intensity_stereo_band(left, sfb[i], kl*s, kr*s); + } else if (HDR_TEST_MS_STEREO(hdr)) + { + L3_midside_stereo(left, sfb[i]); + } + left += sfb[i]; + } +} + +static void L3_intensity_stereo(float *left, uint8_t *ist_pos, const L3_gr_info_t *gr, const uint8_t *hdr) +{ + int max_band[3], n_sfb = gr->n_long_sfb + gr->n_short_sfb; + int i, max_blocks = gr->n_short_sfb ? 3 : 1; + + L3_stereo_top_band(left + 576, gr->sfbtab, n_sfb, max_band); + if (gr->n_long_sfb) + { + max_band[0] = max_band[1] = max_band[2] = MINIMP3_MAX(MINIMP3_MAX(max_band[0], max_band[1]), max_band[2]); + } + for (i = 0; i < max_blocks; i++) + { + int default_pos = HDR_TEST_MPEG1(hdr) ? 3 : 0; + int itop = n_sfb - max_blocks + i; + int prev = itop - max_blocks; + ist_pos[itop] = max_band[i] >= prev ? default_pos : ist_pos[prev]; + } + L3_stereo_process(left, ist_pos, gr->sfbtab, hdr, max_band, gr[1].scalefac_compress & 1); +} + +static void L3_reorder(float *grbuf, float *scratch, const uint8_t *sfb) +{ + int i, len; + float *src = grbuf, *dst = scratch; + + for (;0 != (len = *sfb); sfb += 3, src += 2*len) + { + for (i = 0; i < len; i++, src++) + { + *dst++ = src[0*len]; + *dst++ = src[1*len]; + *dst++ = src[2*len]; + } + } + memcpy(grbuf, scratch, (dst - scratch)*sizeof(float)); +} + +static void L3_antialias(float *grbuf, int nbands) +{ + static const float g_aa[2][8] = { + {0.85749293f,0.88174200f,0.94962865f,0.98331459f,0.99551782f,0.99916056f,0.99989920f,0.99999316f}, + {0.51449576f,0.47173197f,0.31337745f,0.18191320f,0.09457419f,0.04096558f,0.01419856f,0.00369997f} + }; + + for (; nbands > 0; nbands--, grbuf += 18) + { + int i = 0; +#if HAVE_SIMD + if (have_simd()) for (; i < 8; i += 4) + { + f4 vu = VLD(grbuf + 18 + i); + f4 vd = VLD(grbuf + 14 - i); + f4 vc0 = VLD(g_aa[0] + i); + f4 vc1 = VLD(g_aa[1] + i); + vd = VREV(vd); + VSTORE(grbuf + 18 + i, VSUB(VMUL(vu, vc0), VMUL(vd, vc1))); + vd = VADD(VMUL(vu, vc1), VMUL(vd, vc0)); + VSTORE(grbuf + 14 - i, VREV(vd)); + } +#endif /* HAVE_SIMD */ +#ifndef MINIMP3_ONLY_SIMD + for(; i < 8; i++) + { + float u = grbuf[18 + i]; + float d = grbuf[17 - i]; + grbuf[18 + i] = u*g_aa[0][i] - d*g_aa[1][i]; + grbuf[17 - i] = u*g_aa[1][i] + d*g_aa[0][i]; + } +#endif /* MINIMP3_ONLY_SIMD */ + } +} + +static void L3_dct3_9(float *y) +{ + float s0, s1, s2, s3, s4, s5, s6, s7, s8, t0, t2, t4; + + s0 = y[0]; s2 = y[2]; s4 = y[4]; s6 = y[6]; s8 = y[8]; + t0 = s0 + s6*0.5f; + s0 -= s6; + t4 = (s4 + s2)*0.93969262f; + t2 = (s8 + s2)*0.76604444f; + s6 = (s4 - s8)*0.17364818f; + s4 += s8 - s2; + + s2 = s0 - s4*0.5f; + y[4] = s4 + s0; + s8 = t0 - t2 + s6; + s0 = t0 - t4 + t2; + s4 = t0 + t4 - s6; + + s1 = y[1]; s3 = y[3]; s5 = y[5]; s7 = y[7]; + + s3 *= 0.86602540f; + t0 = (s5 + s1)*0.98480775f; + t4 = (s5 - s7)*0.34202014f; + t2 = (s1 + s7)*0.64278761f; + s1 = (s1 - s5 - s7)*0.86602540f; + + s5 = t0 - s3 - t2; + s7 = t4 - s3 - t0; + s3 = t4 + s3 - t2; + + y[0] = s4 - s7; + y[1] = s2 + s1; + y[2] = s0 - s3; + y[3] = s8 + s5; + y[5] = s8 - s5; + y[6] = s0 + s3; + y[7] = s2 - s1; + y[8] = s4 + s7; +} + +static void L3_imdct36(float *grbuf, float *overlap, const float *window, int nbands) +{ + int i, j; + static const float g_twid9[18] = { + 0.73727734f,0.79335334f,0.84339145f,0.88701083f,0.92387953f,0.95371695f,0.97629601f,0.99144486f,0.99904822f,0.67559021f,0.60876143f,0.53729961f,0.46174861f,0.38268343f,0.30070580f,0.21643961f,0.13052619f,0.04361938f + }; + + for (j = 0; j < nbands; j++, grbuf += 18, overlap += 9) + { + float co[9], si[9]; + co[0] = -grbuf[0]; + si[0] = grbuf[17]; + for (i = 0; i < 4; i++) + { + si[8 - 2*i] = grbuf[4*i + 1] - grbuf[4*i + 2]; + co[1 + 2*i] = grbuf[4*i + 1] + grbuf[4*i + 2]; + si[7 - 2*i] = grbuf[4*i + 4] - grbuf[4*i + 3]; + co[2 + 2*i] = -(grbuf[4*i + 3] + grbuf[4*i + 4]); + } + L3_dct3_9(co); + L3_dct3_9(si); + + si[1] = -si[1]; + si[3] = -si[3]; + si[5] = -si[5]; + si[7] = -si[7]; + + i = 0; + +#if HAVE_SIMD + if (have_simd()) for (; i < 8; i += 4) + { + f4 vovl = VLD(overlap + i); + f4 vc = VLD(co + i); + f4 vs = VLD(si + i); + f4 vr0 = VLD(g_twid9 + i); + f4 vr1 = VLD(g_twid9 + 9 + i); + f4 vw0 = VLD(window + i); + f4 vw1 = VLD(window + 9 + i); + f4 vsum = VADD(VMUL(vc, vr1), VMUL(vs, vr0)); + VSTORE(overlap + i, VSUB(VMUL(vc, vr0), VMUL(vs, vr1))); + VSTORE(grbuf + i, VSUB(VMUL(vovl, vw0), VMUL(vsum, vw1))); + vsum = VADD(VMUL(vovl, vw1), VMUL(vsum, vw0)); + VSTORE(grbuf + 14 - i, VREV(vsum)); + } +#endif /* HAVE_SIMD */ + for (; i < 9; i++) + { + float ovl = overlap[i]; + float sum = co[i]*g_twid9[9 + i] + si[i]*g_twid9[0 + i]; + overlap[i] = co[i]*g_twid9[0 + i] - si[i]*g_twid9[9 + i]; + grbuf[i] = ovl*window[0 + i] - sum*window[9 + i]; + grbuf[17 - i] = ovl*window[9 + i] + sum*window[0 + i]; + } + } +} + +static void L3_idct3(float x0, float x1, float x2, float *dst) +{ + float m1 = x1*0.86602540f; + float a1 = x0 - x2*0.5f; + dst[1] = x0 + x2; + dst[0] = a1 + m1; + dst[2] = a1 - m1; +} + +static void L3_imdct12(float *x, float *dst, float *overlap) +{ + static const float g_twid3[6] = { 0.79335334f,0.92387953f,0.99144486f, 0.60876143f,0.38268343f,0.13052619f }; + float co[3], si[3]; + int i; + + L3_idct3(-x[0], x[6] + x[3], x[12] + x[9], co); + L3_idct3(x[15], x[12] - x[9], x[6] - x[3], si); + si[1] = -si[1]; + + for (i = 0; i < 3; i++) + { + float ovl = overlap[i]; + float sum = co[i]*g_twid3[3 + i] + si[i]*g_twid3[0 + i]; + overlap[i] = co[i]*g_twid3[0 + i] - si[i]*g_twid3[3 + i]; + dst[i] = ovl*g_twid3[2 - i] - sum*g_twid3[5 - i]; + dst[5 - i] = ovl*g_twid3[5 - i] + sum*g_twid3[2 - i]; + } +} + +static void L3_imdct_short(float *grbuf, float *overlap, int nbands) +{ + for (;nbands > 0; nbands--, overlap += 9, grbuf += 18) + { + float tmp[18]; + memcpy(tmp, grbuf, sizeof(tmp)); + memcpy(grbuf, overlap, 6*sizeof(float)); + L3_imdct12(tmp, grbuf + 6, overlap + 6); + L3_imdct12(tmp + 1, grbuf + 12, overlap + 6); + L3_imdct12(tmp + 2, overlap, overlap + 6); + } +} + +static void L3_change_sign(float *grbuf) +{ + int b, i; + for (b = 0, grbuf += 18; b < 32; b += 2, grbuf += 36) + for (i = 1; i < 18; i += 2) + grbuf[i] = -grbuf[i]; +} + +static void L3_imdct_gr(float *grbuf, float *overlap, unsigned block_type, unsigned n_long_bands) +{ + static const float g_mdct_window[2][18] = { + { 0.99904822f,0.99144486f,0.97629601f,0.95371695f,0.92387953f,0.88701083f,0.84339145f,0.79335334f,0.73727734f,0.04361938f,0.13052619f,0.21643961f,0.30070580f,0.38268343f,0.46174861f,0.53729961f,0.60876143f,0.67559021f }, + { 1,1,1,1,1,1,0.99144486f,0.92387953f,0.79335334f,0,0,0,0,0,0,0.13052619f,0.38268343f,0.60876143f } + }; + if (n_long_bands) + { + L3_imdct36(grbuf, overlap, g_mdct_window[0], n_long_bands); + grbuf += 18*n_long_bands; + overlap += 9*n_long_bands; + } + if (block_type == SHORT_BLOCK_TYPE) + L3_imdct_short(grbuf, overlap, 32 - n_long_bands); + else + L3_imdct36(grbuf, overlap, g_mdct_window[block_type == STOP_BLOCK_TYPE], 32 - n_long_bands); +} + +static void L3_save_reservoir(mp3dec_t *h, mp3dec_scratch_t *s) +{ + int pos = (s->bs.pos + 7)/8u; + int remains = s->bs.limit/8u - pos; + if (remains > MAX_BITRESERVOIR_BYTES) + { + pos += remains - MAX_BITRESERVOIR_BYTES; + remains = MAX_BITRESERVOIR_BYTES; + } + if (remains > 0) + { + memmove(h->reserv_buf, s->maindata + pos, remains); + } + h->reserv = remains; +} + +static int L3_restore_reservoir(mp3dec_t *h, bs_t *bs, mp3dec_scratch_t *s, int main_data_begin) +{ + int frame_bytes = (bs->limit - bs->pos)/8; + int bytes_have = MINIMP3_MIN(h->reserv, main_data_begin); + memcpy(s->maindata, h->reserv_buf + MINIMP3_MAX(0, h->reserv - main_data_begin), MINIMP3_MIN(h->reserv, main_data_begin)); + memcpy(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes); + bs_init(&s->bs, s->maindata, bytes_have + frame_bytes); + return h->reserv >= main_data_begin; +} + +static void L3_decode(mp3dec_t *h, mp3dec_scratch_t *s, L3_gr_info_t *gr_info, int nch) +{ + int ch; + + for (ch = 0; ch < nch; ch++) + { + int layer3gr_limit = s->bs.pos + gr_info[ch].part_23_length; + L3_decode_scalefactors(h->header, s->ist_pos[ch], &s->bs, gr_info + ch, s->scf, ch); + L3_huffman(s->grbuf[ch], &s->bs, gr_info + ch, s->scf, layer3gr_limit); + } + + if (HDR_TEST_I_STEREO(h->header)) + { + L3_intensity_stereo(s->grbuf[0], s->ist_pos[1], gr_info, h->header); + } else if (HDR_IS_MS_STEREO(h->header)) + { + L3_midside_stereo(s->grbuf[0], 576); + } + + for (ch = 0; ch < nch; ch++, gr_info++) + { + int aa_bands = 31; + int n_long_bands = (gr_info->mixed_block_flag ? 2 : 0) << (int)(HDR_GET_MY_SAMPLE_RATE(h->header) == 2); + + if (gr_info->n_short_sfb) + { + aa_bands = n_long_bands - 1; + L3_reorder(s->grbuf[ch] + n_long_bands*18, s->syn[0], gr_info->sfbtab + gr_info->n_long_sfb); + } + + L3_antialias(s->grbuf[ch], aa_bands); + L3_imdct_gr(s->grbuf[ch], h->mdct_overlap[ch], gr_info->block_type, n_long_bands); + L3_change_sign(s->grbuf[ch]); + } +} + +static void mp3d_DCT_II(float *grbuf, int n) +{ + static const float g_sec[24] = { + 10.19000816f,0.50060302f,0.50241929f,3.40760851f,0.50547093f,0.52249861f,2.05778098f,0.51544732f,0.56694406f,1.48416460f,0.53104258f,0.64682180f,1.16943991f,0.55310392f,0.78815460f,0.97256821f,0.58293498f,1.06067765f,0.83934963f,0.62250412f,1.72244716f,0.74453628f,0.67480832f,5.10114861f + }; + int i, k = 0; +#if HAVE_SIMD + if (have_simd()) for (; k < n; k += 4) + { + f4 t[4][8], *x; + float *y = grbuf + k; + + for (x = t[0], i = 0; i < 8; i++, x++) + { + f4 x0 = VLD(&y[i*18]); + f4 x1 = VLD(&y[(15 - i)*18]); + f4 x2 = VLD(&y[(16 + i)*18]); + f4 x3 = VLD(&y[(31 - i)*18]); + f4 t0 = VADD(x0, x3); + f4 t1 = VADD(x1, x2); + f4 t2 = VMUL_S(VSUB(x1, x2), g_sec[3*i + 0]); + f4 t3 = VMUL_S(VSUB(x0, x3), g_sec[3*i + 1]); + x[0] = VADD(t0, t1); + x[8] = VMUL_S(VSUB(t0, t1), g_sec[3*i + 2]); + x[16] = VADD(t3, t2); + x[24] = VMUL_S(VSUB(t3, t2), g_sec[3*i + 2]); + } + for (x = t[0], i = 0; i < 4; i++, x += 8) + { + f4 x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt; + xt = VSUB(x0, x7); x0 = VADD(x0, x7); + x7 = VSUB(x1, x6); x1 = VADD(x1, x6); + x6 = VSUB(x2, x5); x2 = VADD(x2, x5); + x5 = VSUB(x3, x4); x3 = VADD(x3, x4); + x4 = VSUB(x0, x3); x0 = VADD(x0, x3); + x3 = VSUB(x1, x2); x1 = VADD(x1, x2); + x[0] = VADD(x0, x1); + x[4] = VMUL_S(VSUB(x0, x1), 0.70710677f); + x5 = VADD(x5, x6); + x6 = VMUL_S(VADD(x6, x7), 0.70710677f); + x7 = VADD(x7, xt); + x3 = VMUL_S(VADD(x3, x4), 0.70710677f); + x5 = VSUB(x5, VMUL_S(x7, 0.198912367f)); /* rotate by PI/8 */ + x7 = VADD(x7, VMUL_S(x5, 0.382683432f)); + x5 = VSUB(x5, VMUL_S(x7, 0.198912367f)); + x0 = VSUB(xt, x6); xt = VADD(xt, x6); + x[1] = VMUL_S(VADD(xt, x7), 0.50979561f); + x[2] = VMUL_S(VADD(x4, x3), 0.54119611f); + x[3] = VMUL_S(VSUB(x0, x5), 0.60134488f); + x[5] = VMUL_S(VADD(x0, x5), 0.89997619f); + x[6] = VMUL_S(VSUB(x4, x3), 1.30656302f); + x[7] = VMUL_S(VSUB(xt, x7), 2.56291556f); + } + + if (k > n - 3) + { +#if HAVE_SSE +#define VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v) +#else /* HAVE_SSE */ +#define VSAVE2(i, v) vst1_f32((float32_t *)&y[i*18], vget_low_f32(v)) +#endif /* HAVE_SSE */ + for (i = 0; i < 7; i++, y += 4*18) + { + f4 s = VADD(t[3][i], t[3][i + 1]); + VSAVE2(0, t[0][i]); + VSAVE2(1, VADD(t[2][i], s)); + VSAVE2(2, VADD(t[1][i], t[1][i + 1])); + VSAVE2(3, VADD(t[2][1 + i], s)); + } + VSAVE2(0, t[0][7]); + VSAVE2(1, VADD(t[2][7], t[3][7])); + VSAVE2(2, t[1][7]); + VSAVE2(3, t[3][7]); + } else + { +#define VSAVE4(i, v) VSTORE(&y[i*18], v) + for (i = 0; i < 7; i++, y += 4*18) + { + f4 s = VADD(t[3][i], t[3][i + 1]); + VSAVE4(0, t[0][i]); + VSAVE4(1, VADD(t[2][i], s)); + VSAVE4(2, VADD(t[1][i], t[1][i + 1])); + VSAVE4(3, VADD(t[2][1 + i], s)); + } + VSAVE4(0, t[0][7]); + VSAVE4(1, VADD(t[2][7], t[3][7])); + VSAVE4(2, t[1][7]); + VSAVE4(3, t[3][7]); + } + } else +#endif /* HAVE_SIMD */ +#ifdef MINIMP3_ONLY_SIMD + {} /* for HAVE_SIMD=1, MINIMP3_ONLY_SIMD=1 case we do not need non-intrinsic "else" branch */ +#else /* MINIMP3_ONLY_SIMD */ + for (; k < n; k++) + { + float t[4][8], *x, *y = grbuf + k; + + for (x = t[0], i = 0; i < 8; i++, x++) + { + float x0 = y[i*18]; + float x1 = y[(15 - i)*18]; + float x2 = y[(16 + i)*18]; + float x3 = y[(31 - i)*18]; + float t0 = x0 + x3; + float t1 = x1 + x2; + float t2 = (x1 - x2)*g_sec[3*i + 0]; + float t3 = (x0 - x3)*g_sec[3*i + 1]; + x[0] = t0 + t1; + x[8] = (t0 - t1)*g_sec[3*i + 2]; + x[16] = t3 + t2; + x[24] = (t3 - t2)*g_sec[3*i + 2]; + } + for (x = t[0], i = 0; i < 4; i++, x += 8) + { + float x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt; + xt = x0 - x7; x0 += x7; + x7 = x1 - x6; x1 += x6; + x6 = x2 - x5; x2 += x5; + x5 = x3 - x4; x3 += x4; + x4 = x0 - x3; x0 += x3; + x3 = x1 - x2; x1 += x2; + x[0] = x0 + x1; + x[4] = (x0 - x1)*0.70710677f; + x5 = x5 + x6; + x6 = (x6 + x7)*0.70710677f; + x7 = x7 + xt; + x3 = (x3 + x4)*0.70710677f; + x5 -= x7*0.198912367f; /* rotate by PI/8 */ + x7 += x5*0.382683432f; + x5 -= x7*0.198912367f; + x0 = xt - x6; xt += x6; + x[1] = (xt + x7)*0.50979561f; + x[2] = (x4 + x3)*0.54119611f; + x[3] = (x0 - x5)*0.60134488f; + x[5] = (x0 + x5)*0.89997619f; + x[6] = (x4 - x3)*1.30656302f; + x[7] = (xt - x7)*2.56291556f; + + } + for (i = 0; i < 7; i++, y += 4*18) + { + y[0*18] = t[0][i]; + y[1*18] = t[2][i] + t[3][i] + t[3][i + 1]; + y[2*18] = t[1][i] + t[1][i + 1]; + y[3*18] = t[2][i + 1] + t[3][i] + t[3][i + 1]; + } + y[0*18] = t[0][7]; + y[1*18] = t[2][7] + t[3][7]; + y[2*18] = t[1][7]; + y[3*18] = t[3][7]; + } +#endif /* MINIMP3_ONLY_SIMD */ +} + +#ifndef MINIMP3_FLOAT_OUTPUT +static int16_t mp3d_scale_pcm(float sample) +{ +#if HAVE_ARMV6 + int32_t s32 = (int32_t)(sample + .5f); + s32 -= (s32 < 0); + int16_t s = (int16_t)minimp3_clip_int16_arm(s32); +#else + if (sample >= 32766.5) return (int16_t) 32767; + if (sample <= -32767.5) return (int16_t)-32768; + int16_t s = (int16_t)(sample + .5f); + s -= (s < 0); /* away from zero, to be compliant */ +#endif + return s; +} +#else /* MINIMP3_FLOAT_OUTPUT */ +static float mp3d_scale_pcm(float sample) +{ + return sample*(1.f/32768.f); +} +#endif /* MINIMP3_FLOAT_OUTPUT */ + +static void mp3d_synth_pair(mp3d_sample_t *pcm, int nch, const float *z) +{ + float a; + a = (z[14*64] - z[ 0]) * 29; + a += (z[ 1*64] + z[13*64]) * 213; + a += (z[12*64] - z[ 2*64]) * 459; + a += (z[ 3*64] + z[11*64]) * 2037; + a += (z[10*64] - z[ 4*64]) * 5153; + a += (z[ 5*64] + z[ 9*64]) * 6574; + a += (z[ 8*64] - z[ 6*64]) * 37489; + a += z[ 7*64] * 75038; + pcm[0] = mp3d_scale_pcm(a); + + z += 2; + a = z[14*64] * 104; + a += z[12*64] * 1567; + a += z[10*64] * 9727; + a += z[ 8*64] * 64019; + a += z[ 6*64] * -9975; + a += z[ 4*64] * -45; + a += z[ 2*64] * 146; + a += z[ 0*64] * -5; + pcm[16*nch] = mp3d_scale_pcm(a); +} + +static void mp3d_synth(float *xl, mp3d_sample_t *dstl, int nch, float *lins) +{ + int i; + float *xr = xl + 576*(nch - 1); + mp3d_sample_t *dstr = dstl + (nch - 1); + + static const float g_win[] = { + -1,26,-31,208,218,401,-519,2063,2000,4788,-5517,7134,5959,35640,-39336,74992, + -1,24,-35,202,222,347,-581,2080,1952,4425,-5879,7640,5288,33791,-41176,74856, + -1,21,-38,196,225,294,-645,2087,1893,4063,-6237,8092,4561,31947,-43006,74630, + -1,19,-41,190,227,244,-711,2085,1822,3705,-6589,8492,3776,30112,-44821,74313, + -1,17,-45,183,228,197,-779,2075,1739,3351,-6935,8840,2935,28289,-46617,73908, + -1,16,-49,176,228,153,-848,2057,1644,3004,-7271,9139,2037,26482,-48390,73415, + -2,14,-53,169,227,111,-919,2032,1535,2663,-7597,9389,1082,24694,-50137,72835, + -2,13,-58,161,224,72,-991,2001,1414,2330,-7910,9592,70,22929,-51853,72169, + -2,11,-63,154,221,36,-1064,1962,1280,2006,-8209,9750,-998,21189,-53534,71420, + -2,10,-68,147,215,2,-1137,1919,1131,1692,-8491,9863,-2122,19478,-55178,70590, + -3,9,-73,139,208,-29,-1210,1870,970,1388,-8755,9935,-3300,17799,-56778,69679, + -3,8,-79,132,200,-57,-1283,1817,794,1095,-8998,9966,-4533,16155,-58333,68692, + -4,7,-85,125,189,-83,-1356,1759,605,814,-9219,9959,-5818,14548,-59838,67629, + -4,7,-91,117,177,-106,-1428,1698,402,545,-9416,9916,-7154,12980,-61289,66494, + -5,6,-97,111,163,-127,-1498,1634,185,288,-9585,9838,-8540,11455,-62684,65290 + }; + float *zlin = lins + 15*64; + const float *w = g_win; + + zlin[4*15] = xl[18*16]; + zlin[4*15 + 1] = xr[18*16]; + zlin[4*15 + 2] = xl[0]; + zlin[4*15 + 3] = xr[0]; + + zlin[4*31] = xl[1 + 18*16]; + zlin[4*31 + 1] = xr[1 + 18*16]; + zlin[4*31 + 2] = xl[1]; + zlin[4*31 + 3] = xr[1]; + + mp3d_synth_pair(dstr, nch, lins + 4*15 + 1); + mp3d_synth_pair(dstr + 32*nch, nch, lins + 4*15 + 64 + 1); + mp3d_synth_pair(dstl, nch, lins + 4*15); + mp3d_synth_pair(dstl + 32*nch, nch, lins + 4*15 + 64); + +#if HAVE_SIMD + if (have_simd()) for (i = 14; i >= 0; i--) + { +#define VLOAD(k) f4 w0 = VSET(*w++); f4 w1 = VSET(*w++); f4 vz = VLD(&zlin[4*i - 64*k]); f4 vy = VLD(&zlin[4*i - 64*(15 - k)]); +#define V0(k) { VLOAD(k) b = VADD(VMUL(vz, w1), VMUL(vy, w0)) ; a = VSUB(VMUL(vz, w0), VMUL(vy, w1)); } +#define V1(k) { VLOAD(k) b = VADD(b, VADD(VMUL(vz, w1), VMUL(vy, w0))); a = VADD(a, VSUB(VMUL(vz, w0), VMUL(vy, w1))); } +#define V2(k) { VLOAD(k) b = VADD(b, VADD(VMUL(vz, w1), VMUL(vy, w0))); a = VADD(a, VSUB(VMUL(vy, w1), VMUL(vz, w0))); } + f4 a, b; + zlin[4*i] = xl[18*(31 - i)]; + zlin[4*i + 1] = xr[18*(31 - i)]; + zlin[4*i + 2] = xl[1 + 18*(31 - i)]; + zlin[4*i + 3] = xr[1 + 18*(31 - i)]; + zlin[4*i + 64] = xl[1 + 18*(1 + i)]; + zlin[4*i + 64 + 1] = xr[1 + 18*(1 + i)]; + zlin[4*i - 64 + 2] = xl[18*(1 + i)]; + zlin[4*i - 64 + 3] = xr[18*(1 + i)]; + + V0(0) V2(1) V1(2) V2(3) V1(4) V2(5) V1(6) V2(7) + + { +#ifndef MINIMP3_FLOAT_OUTPUT +#if HAVE_SSE + static const f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; + static const f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; + __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)), + _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min))); + dstr[(15 - i)*nch] = _mm_extract_epi16(pcm8, 1); + dstr[(17 + i)*nch] = _mm_extract_epi16(pcm8, 5); + dstl[(15 - i)*nch] = _mm_extract_epi16(pcm8, 0); + dstl[(17 + i)*nch] = _mm_extract_epi16(pcm8, 4); + dstr[(47 - i)*nch] = _mm_extract_epi16(pcm8, 3); + dstr[(49 + i)*nch] = _mm_extract_epi16(pcm8, 7); + dstl[(47 - i)*nch] = _mm_extract_epi16(pcm8, 2); + dstl[(49 + i)*nch] = _mm_extract_epi16(pcm8, 6); +#else /* HAVE_SSE */ + int16x4_t pcma, pcmb; + a = VADD(a, VSET(0.5f)); + b = VADD(b, VSET(0.5f)); + pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, VSET(0))))); + pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, VSET(0))))); + vst1_lane_s16(dstr + (15 - i)*nch, pcma, 1); + vst1_lane_s16(dstr + (17 + i)*nch, pcmb, 1); + vst1_lane_s16(dstl + (15 - i)*nch, pcma, 0); + vst1_lane_s16(dstl + (17 + i)*nch, pcmb, 0); + vst1_lane_s16(dstr + (47 - i)*nch, pcma, 3); + vst1_lane_s16(dstr + (49 + i)*nch, pcmb, 3); + vst1_lane_s16(dstl + (47 - i)*nch, pcma, 2); + vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2); +#endif /* HAVE_SSE */ + +#else /* MINIMP3_FLOAT_OUTPUT */ + + static const f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f }; + a = VMUL(a, g_scale); + b = VMUL(b, g_scale); +#if HAVE_SSE + _mm_store_ss(dstr + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1))); + _mm_store_ss(dstr + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 1, 1, 1))); + _mm_store_ss(dstl + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0))); + _mm_store_ss(dstl + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 0, 0, 0))); + _mm_store_ss(dstr + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3))); + _mm_store_ss(dstr + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 3, 3, 3))); + _mm_store_ss(dstl + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2))); + _mm_store_ss(dstl + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(2, 2, 2, 2))); +#else /* HAVE_SSE */ + vst1q_lane_f32(dstr + (15 - i)*nch, a, 1); + vst1q_lane_f32(dstr + (17 + i)*nch, b, 1); + vst1q_lane_f32(dstl + (15 - i)*nch, a, 0); + vst1q_lane_f32(dstl + (17 + i)*nch, b, 0); + vst1q_lane_f32(dstr + (47 - i)*nch, a, 3); + vst1q_lane_f32(dstr + (49 + i)*nch, b, 3); + vst1q_lane_f32(dstl + (47 - i)*nch, a, 2); + vst1q_lane_f32(dstl + (49 + i)*nch, b, 2); +#endif /* HAVE_SSE */ +#endif /* MINIMP3_FLOAT_OUTPUT */ + } + } else +#endif /* HAVE_SIMD */ +#ifdef MINIMP3_ONLY_SIMD + {} /* for HAVE_SIMD=1, MINIMP3_ONLY_SIMD=1 case we do not need non-intrinsic "else" branch */ +#else /* MINIMP3_ONLY_SIMD */ + for (i = 14; i >= 0; i--) + { +#define LOAD(k) float w0 = *w++; float w1 = *w++; float *vz = &zlin[4*i - k*64]; float *vy = &zlin[4*i - (15 - k)*64]; +#define S0(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] = vz[j]*w1 + vy[j]*w0, a[j] = vz[j]*w0 - vy[j]*w1; } +#define S1(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vz[j]*w0 - vy[j]*w1; } +#define S2(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vy[j]*w1 - vz[j]*w0; } + float a[4], b[4]; + + zlin[4*i] = xl[18*(31 - i)]; + zlin[4*i + 1] = xr[18*(31 - i)]; + zlin[4*i + 2] = xl[1 + 18*(31 - i)]; + zlin[4*i + 3] = xr[1 + 18*(31 - i)]; + zlin[4*(i + 16)] = xl[1 + 18*(1 + i)]; + zlin[4*(i + 16) + 1] = xr[1 + 18*(1 + i)]; + zlin[4*(i - 16) + 2] = xl[18*(1 + i)]; + zlin[4*(i - 16) + 3] = xr[18*(1 + i)]; + + S0(0) S2(1) S1(2) S2(3) S1(4) S2(5) S1(6) S2(7) + + dstr[(15 - i)*nch] = mp3d_scale_pcm(a[1]); + dstr[(17 + i)*nch] = mp3d_scale_pcm(b[1]); + dstl[(15 - i)*nch] = mp3d_scale_pcm(a[0]); + dstl[(17 + i)*nch] = mp3d_scale_pcm(b[0]); + dstr[(47 - i)*nch] = mp3d_scale_pcm(a[3]); + dstr[(49 + i)*nch] = mp3d_scale_pcm(b[3]); + dstl[(47 - i)*nch] = mp3d_scale_pcm(a[2]); + dstl[(49 + i)*nch] = mp3d_scale_pcm(b[2]); + } +#endif /* MINIMP3_ONLY_SIMD */ +} + +static void mp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int nch, mp3d_sample_t *pcm, float *lins) +{ + int i; + for (i = 0; i < nch; i++) + { + mp3d_DCT_II(grbuf + 576*i, nbands); + } + + memcpy(lins, qmf_state, sizeof(float)*15*64); + + for (i = 0; i < nbands; i += 2) + { + mp3d_synth(grbuf + i, pcm + 32*nch*i, nch, lins + i*64); + } +#ifndef MINIMP3_NONSTANDARD_BUT_LOGICAL + if (nch == 1) + { + for (i = 0; i < 15*64; i += 2) + { + qmf_state[i] = lins[nbands*64 + i]; + } + } else +#endif /* MINIMP3_NONSTANDARD_BUT_LOGICAL */ + { + memcpy(qmf_state, lins + nbands*64, sizeof(float)*15*64); + } +} + +static int mp3d_match_frame(const uint8_t *hdr, int mp3_bytes, int frame_bytes) +{ + int i, nmatch; + for (i = 0, nmatch = 0; nmatch < MAX_FRAME_SYNC_MATCHES; nmatch++) + { + i += hdr_frame_bytes(hdr + i, frame_bytes) + hdr_padding(hdr + i); + if (i + HDR_SIZE > mp3_bytes) + return nmatch > 0; + if (!hdr_compare(hdr, hdr + i)) + return 0; + } + return 1; +} + +static int mp3d_find_frame(const uint8_t *mp3, int mp3_bytes, int *free_format_bytes, int *ptr_frame_bytes) +{ + int i, k; + for (i = 0; i < mp3_bytes - HDR_SIZE; i++, mp3++) + { + if (hdr_valid(mp3)) + { + int frame_bytes = hdr_frame_bytes(mp3, *free_format_bytes); + int frame_and_padding = frame_bytes + hdr_padding(mp3); + + for (k = HDR_SIZE; !frame_bytes && k < MAX_FREE_FORMAT_FRAME_SIZE && i + 2*k < mp3_bytes - HDR_SIZE; k++) + { + if (hdr_compare(mp3, mp3 + k)) + { + int fb = k - hdr_padding(mp3); + int nextfb = fb + hdr_padding(mp3 + k); + if (i + k + nextfb + HDR_SIZE > mp3_bytes || !hdr_compare(mp3, mp3 + k + nextfb)) + continue; + frame_and_padding = k; + frame_bytes = fb; + *free_format_bytes = fb; + } + } + if ((frame_bytes && i + frame_and_padding <= mp3_bytes && + mp3d_match_frame(mp3, mp3_bytes - i, frame_bytes)) || + (!i && frame_and_padding == mp3_bytes)) + { + *ptr_frame_bytes = frame_and_padding; + return i; + } + *free_format_bytes = 0; + } + } + *ptr_frame_bytes = 0; + return mp3_bytes; +} + +void mp3dec_init(mp3dec_t *dec) +{ + dec->header[0] = 0; +} + +int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_sample_t *pcm, mp3dec_frame_info_t *info) +{ + int i = 0, igr, frame_size = 0, success = 1; + const uint8_t *hdr; + bs_t bs_frame[1]; + mp3dec_scratch_t scratch; + if (mp3_bytes > 4 && dec->header[0] == 0xff && hdr_compare(dec->header, mp3)) + { + frame_size = hdr_frame_bytes(mp3, dec->free_format_bytes) + hdr_padding(mp3); + if (frame_size != mp3_bytes && (frame_size + HDR_SIZE > mp3_bytes || !hdr_compare(mp3, mp3 + frame_size))) + { + frame_size = 0; + } + } + if (!frame_size) + { + memset(dec, 0, sizeof(mp3dec_t)); + i = mp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size); + if (!frame_size || i + frame_size > mp3_bytes) + { + info->frame_bytes = i; + return 0; + } + } + + hdr = mp3 + i; + memcpy(dec->header, hdr, HDR_SIZE); + info->frame_bytes = i + frame_size; + info->frame_offset = i; + info->channels = HDR_IS_MONO(hdr) ? 1 : 2; + info->hz = hdr_sample_rate_hz(hdr); + info->layer = 4 - HDR_GET_LAYER(hdr); + info->bitrate_kbps = hdr_bitrate_kbps(hdr); + + if (!pcm) + { + return hdr_frame_samples(hdr); + } + + bs_init(bs_frame, hdr + HDR_SIZE, frame_size - HDR_SIZE); + if (HDR_IS_CRC(hdr)) + { + get_bits(bs_frame, 16); + } + + if (info->layer == 3) + { + int main_data_begin = L3_read_side_info(bs_frame, scratch.gr_info, hdr); + if (main_data_begin < 0 || bs_frame->pos > bs_frame->limit) + { + mp3dec_init(dec); + return 0; + } + success = L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin); + if (success) + { + for (igr = 0; igr < (HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm += 576*info->channels) + { + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels); + mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, pcm, scratch.syn[0]); + } + } + L3_save_reservoir(dec, &scratch); + } else + { +#ifdef MINIMP3_ONLY_MP3 + return 0; +#else /* MINIMP3_ONLY_MP3 */ + L12_scale_info sci[1]; + L12_read_scale_info(hdr, bs_frame, sci); + + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + for (i = 0, igr = 0; igr < 3; igr++) + { + if (12 == (i += L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1))) + { + i = 0; + L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]); + mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, pcm, scratch.syn[0]); + memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); + pcm += 384*info->channels; + } + if (bs_frame->pos > bs_frame->limit) + { + mp3dec_init(dec); + return 0; + } + } +#endif /* MINIMP3_ONLY_MP3 */ + } + return success*hdr_frame_samples(dec->header); +} + +#ifdef MINIMP3_FLOAT_OUTPUT +void mp3dec_f32_to_s16(const float *in, int16_t *out, int num_samples) +{ + int i = 0; +#if HAVE_SIMD + int aligned_count = num_samples & ~7; + for(; i < aligned_count; i += 8) + { + static const f4 g_scale = { 32768.0f, 32768.0f, 32768.0f, 32768.0f }; + f4 a = VMUL(VLD(&in[i ]), g_scale); + f4 b = VMUL(VLD(&in[i+4]), g_scale); +#if HAVE_SSE + static const f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; + static const f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; + __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)), + _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min))); + out[i ] = _mm_extract_epi16(pcm8, 0); + out[i+1] = _mm_extract_epi16(pcm8, 1); + out[i+2] = _mm_extract_epi16(pcm8, 2); + out[i+3] = _mm_extract_epi16(pcm8, 3); + out[i+4] = _mm_extract_epi16(pcm8, 4); + out[i+5] = _mm_extract_epi16(pcm8, 5); + out[i+6] = _mm_extract_epi16(pcm8, 6); + out[i+7] = _mm_extract_epi16(pcm8, 7); +#else /* HAVE_SSE */ + int16x4_t pcma, pcmb; + a = VADD(a, VSET(0.5f)); + b = VADD(b, VSET(0.5f)); + pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, VSET(0))))); + pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, VSET(0))))); + vst1_lane_s16(out+i , pcma, 0); + vst1_lane_s16(out+i+1, pcma, 1); + vst1_lane_s16(out+i+2, pcma, 2); + vst1_lane_s16(out+i+3, pcma, 3); + vst1_lane_s16(out+i+4, pcmb, 0); + vst1_lane_s16(out+i+5, pcmb, 1); + vst1_lane_s16(out+i+6, pcmb, 2); + vst1_lane_s16(out+i+7, pcmb, 3); +#endif /* HAVE_SSE */ + } +#endif /* HAVE_SIMD */ + for(; i < num_samples; i++) + { + float sample = in[i] * 32768.0f; + if (sample >= 32766.5) + out[i] = (int16_t) 32767; + else if (sample <= -32767.5) + out[i] = (int16_t)-32768; + else + { + int16_t s = (int16_t)(sample + .5f); + s -= (s < 0); /* away from zero, to be compliant */ + out[i] = s; + } + } +} +#endif /* MINIMP3_FLOAT_OUTPUT */ +#endif /* MINIMP3_IMPLEMENTATION && !_MINIMP3_IMPLEMENTATION_GUARD */ diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp b/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp new file mode 100755 index 00000000..d8a42c24 --- /dev/null +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp @@ -0,0 +1,324 @@ +#define LOG_TAG "Minimp3DecoderPlugin" + +#include "minimp3_decoder_plugin.h" +#include +#include +#include +#include "utils/constants.h" +#include "utils/memory_helper.h" + +#include "plugin/common/plugin_audio_tags.h" +#include "plugin/common/plugin_buffer.h" +#include "plugin/interface/codec_plugin.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +namespace { + Status RegisterDecoderPlugins(const std::shared_ptr& reg); + const uint32_t BUFFER_ITEM_CNT = 6; + void UpdatePluginDefinition(CodecPluginDef& definition); +} + +Minimp3DecoderPlugin::Minimp3DecoderPlugin(std::string name) + : CodecPlugin(std::move(name)), + mp3Parameter_(), + outBufferQ_("adecPluginQueue", BUFFER_ITEM_CNT) +{ + memset(&mp3DecoderAttr_, 0, sizeof(AudioDecoderMp3Attr)); + MEDIA_LOG_I("Minimp3DecoderPlugin, plugin name: %s", pluginName_.c_str()); +} + +Minimp3DecoderPlugin::~Minimp3DecoderPlugin() +{ + MEDIA_LOG_I("~Minimp3DecoderPlugin, plugin name: %s", pluginName_.c_str()); +} + +Status Minimp3DecoderPlugin::Init() +{ + minimp3DecoderImpl_ = Minimp3GetOpt(); + AudioDecoderMp3Open(NULL); + state_ = State::INITIALIZED; + mp3Parameter_[Tag::REQUIRED_OUT_BUFFER_CNT] = (uint32_t)BUFFER_ITEM_CNT; + return Status::OK; +} + +Status Minimp3DecoderPlugin::Deinit() +{ + AudioDecoderMp3Close(); + state_ = State::DESTROYED; + return Status::OK; +} + +Status Minimp3DecoderPlugin::SetParameter(Tag tag, const ValueType& value) +{ + mp3Parameter_.insert(std::make_pair(tag, value)); + return Status::OK; +} + +Status Minimp3DecoderPlugin::GetParameter(Tag tag, ValueType& value) +{ + auto res = mp3Parameter_.find(tag); + if (res != mp3Parameter_.end()) { + value = res->second; + return Status::OK; + } + return Status::ERROR_INVALID_PARAMETER; +} + +Status Minimp3DecoderPlugin::Prepare() +{ + if (state_ != State::INITIALIZED && state_ != State::PREPARED) { + return Status::ERROR_WRONG_STATE; + } + + state_ = State::PREPARED; + outBufferQ_.SetActive(true); + + return Status::OK; +} + +Status Minimp3DecoderPlugin::Reset() +{ + mp3Parameter_.clear(); + outBufferQ_.Clear(); + state_ = State::INITIALIZED; + return Status::OK; +} + +Status Minimp3DecoderPlugin::Start() +{ + state_ = State::RUNNING; + outBufferQ_.SetActive(true); + + return Status::OK; +} + +Status Minimp3DecoderPlugin::Stop() +{ + state_ = State::INITIALIZED; + outBufferQ_.SetActive(false); + return Status::OK; +} + +bool Minimp3DecoderPlugin::IsParameterSupported(Tag tag) +{ + return true; +} + +std::shared_ptr Minimp3DecoderPlugin::GetAllocator() +{ + return NULL; +} + +Status Minimp3DecoderPlugin::SetCallback(const std::shared_ptr& cb) +{ + return Status::OK; +} + +Status Minimp3DecoderPlugin::QueueOutputBuffer(const std::shared_ptr& outputBuffers, int32_t timeoutMs) +{ + MEDIA_LOG_I("queue out put"); + (void)timeoutMs; + outBufferQ_.Push(outputBuffers); + + return Status::OK; +} + +Status Minimp3DecoderPlugin::SendDataFromBufferLocked(const std::shared_ptr& inputBuffer) +{ + if (state_ != State::RUNNING) { + MEDIA_LOG_W("queue input buffer in wrong state"); + return Status::ERROR_WRONG_STATE; + } + + bool eos = false; + std::shared_ptr outBuffer; + outBuffer = outBufferQ_.Pop(); + if (inputBuffer == nullptr || (inputBuffer->flag & BUFFER_FLAG_EOS) != 0) { + eos = true; + outBuffer->GetMemory()->Reset(); + outBuffer->flag = BUFFER_FLAG_EOS; + } else { + if (outBuffer == nullptr || outBuffer->IsEmpty()) { + return Status::OK; + } + int ret = AudioDecoderMp3Process(inputBuffer, outBuffer); + if (ret != 0) { + outBufferQ_.Push(outBuffer); + } else { + NotifyOutputBufferDone(outBuffer); + } + } + if (eos) { + MEDIA_LOG_I("eos received"); + NotifyOutputBufferDone(outBuffer); + return Status::END_OF_STREAM; + } + + return Status::OK; +} + +Status Minimp3DecoderPlugin::SendDataFromBuffer(const std::shared_ptr& inputBuffer) +{ + if (inputBuffer->IsEmpty() && !(inputBuffer->flag & BUFFER_FLAG_EOS)) { + MEDIA_LOG_E("decoder does not support fd buffer"); + return Status::ERROR_INVALID_DATA; + } + + Status ret = SendDataFromBufferLocked(inputBuffer); + NotifyInputBufferDone(inputBuffer); + + return ret; +} + +Status Minimp3DecoderPlugin::QueueInputBuffer(const std::shared_ptr& inputBuffer, int32_t timeoutMs) +{ + MEDIA_LOG_D("queue input buffer"); + (void)timeoutMs; + Status status = SendDataFromBuffer(inputBuffer); + if (status != Status::OK) { + return status; + } + return Status::OK; +} + +Status Minimp3DecoderPlugin::Flush() +{ + return Status::OK; +} + +Status Minimp3DecoderPlugin::SetDataCallback(const std::weak_ptr& dataCallback) +{ + dataCb_ = dataCallback; + return Status::OK; +} + +void Minimp3DecoderPlugin::NotifyInputBufferDone(const std::shared_ptr& input) +{ + auto ptr = dataCb_.lock(); + if (ptr != nullptr) { + ptr->OnInputBufferDone(input); + } +} + +void Minimp3DecoderPlugin::NotifyOutputBufferDone(const std::shared_ptr& output) +{ + auto ptr = dataCb_.lock(); + if (ptr != nullptr) { + ptr->OnOutputBufferDone(output); + } +} + +void Minimp3DecoderPlugin::AudioDecoderMp3Open(void *userData) +{ + Mp3DecoderSample *pcmData = (Mp3DecoderSample*)calloc(MP3_MAX_SAMPLES_PER_FRAME, sizeof(Mp3DecoderSample)); + if (pcmData == nullptr) { + goto exit; + } + mp3DecoderAttr_.userData = userData; + mp3DecoderAttr_.pcm = pcmData; + + Minimp3WrapperMp3decInit(&mp3DecoderAttr_.mp3DecoderHandle); + +exit: + return; +} + +int Minimp3DecoderPlugin::AudioDecoderMp3Close() +{ + if (mp3DecoderAttr_.pcm) { + free(mp3DecoderAttr_.pcm); + mp3DecoderAttr_.pcm = NULL; + } + return 0; +} + +int Minimp3DecoderPlugin::AudioDecoderMp3Process(std::shared_ptr inBuffer, std::shared_ptr outBuffer) +{ + auto inData = inBuffer->GetMemory(); + auto outData = outBuffer->GetMemory(); + int ret = -1; + Minimp3WrapperMp3decFrameInfo frameInfo; + int sampleCount = minimp3DecoderImpl_.decoderFrame(&mp3DecoderAttr_.mp3DecoderHandle, inData->GetReadOnlyData(), inData->GetSize(), mp3DecoderAttr_.pcm, &frameInfo); + if (sampleCount > 0) { + if (frameInfo.frame_bytes) { + ret = 0; + uint32_t pcmLength = sampleCount * sizeof(Mp3DecoderSample) * frameInfo.channels; + if (pcmLength == 0 || pcmLength >= 16 * 1024) { + return -1; + } + + if (outData->GetCapacity() >= pcmLength) { + outData->Write((uint8_t *)mp3DecoderAttr_.pcm, pcmLength); + MEDIA_LOG_I("pcmLength = %d", pcmLength); + } else { + MEDIA_LOG_W("not enough buffer memory"); + return -1; + } + } + } else if (sampleCount == 0) { + ret = 2; + } else { + ret = -1; + } + + return ret; +} + +namespace { + std::shared_ptr Minimp3DecoderCreator(const std::string& name) + { + return std::make_shared(name); + } + + Status RegisterDecoderPlugins(const std::shared_ptr& reg) + { + MEDIA_LOG_D("RegisterPlugins called."); + if (!reg) { + MEDIA_LOG_E("RegisterPlugins failed due to null pointer for reg."); + return Status::ERROR_INVALID_PARAMETER; + } + + CodecPluginDef definition; + definition.name = "Minimp3DecoderPlugin"; + definition.codecType = CodecType::AUDIO_DECODER; + definition.rank = 100; + definition.creator = Minimp3DecoderCreator, UpdatePluginDefinition(definition); + if (reg->AddPlugin(definition) != Status::OK) { + MEDIA_LOG_W("register minimp3 decoder plugin failed"); + } + return Status::OK; + } + + void UpdatePluginDefinition(CodecPluginDef& definition) + { + Capability cap("audio/unknown"); + cap.SetMime(OHOS::Media::MEDIA_MIME_AUDIO_MPEG) + .AppendFixedKey(Capability::Key::AUDIO_MPEG_VERSION, 1) + .AppendIntervalKey(Capability::Key::AUDIO_MPEG_LAYER, 3, 3); // 3 + + MEDIA_LOG_W("UpdatePluginDefinition\n"); + DiscreteCapability values = {8000, 16000, 22050, 44100, 48000}; + cap.AppendDiscreteKeys(Capability::Key::AUDIO_SAMPLE_RATE, values); + + DiscreteCapability channelLayoutValues; + channelLayoutValues.push_back(AudioChannelLayout::MONO); + cap.AppendDiscreteKeys(Capability::Key::AUDIO_CHANNEL_LAYOUT, channelLayoutValues); + + DiscreteCapability sampleFmtValues = {AudioSampleFormat::S32, AudioSampleFormat::S16}; + cap.AppendDiscreteKeys(Capability::Key::AUDIO_SAMPLE_FORMAT, sampleFmtValues); + + definition.inCaps.push_back(cap); + } + + void UnRegisterAudioDecoderPlugin() + { + return; + } +} + +PLUGIN_DEFINITION(Minimp3Decoder, LicenseType::LGPL, RegisterDecoderPlugins, [] {}); +} +} +} \ No newline at end of file diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.h b/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.h new file mode 100755 index 00000000..357b2904 --- /dev/null +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.h @@ -0,0 +1,113 @@ +#if 1 +#ifndef HISTREAMER_MINIMP3_DECODER_PLUGIN_H +#define HISTREAMER_MINIMP3_DECODER_PLUGIN_H + +#include +#include +#include "utils/blocking_queue.h" +#include "plugin/interface/codec_plugin.h" +#include "plugin/common/plugin_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "minimp3_wrapper.h" + +#ifdef __cplusplus +}; +#endif + +typedef Minimp3WrapperMp3dec Mp3DecoderHandle; +typedef Minimp3WrapperMp3dSample Mp3DecoderSample; + +#define MP3_MAX_SAMPLES_PER_FRAME (1152 * 2) + +typedef struct +{ + uint32_t usedInputLength; + uint8_t *packetBuffer; + uint32_t packetLength; +} AudioDecoderRst; + +typedef struct +{ + Mp3DecoderHandle mp3DecoderHandle; + Mp3DecoderSample *pcm; + AudioDecoderRst *rst; + void *userData; +} AudioDecoderMp3Attr; + +namespace OHOS { +namespace Media { +namespace Plugin { +class Minimp3DecoderPlugin : public CodecPlugin { +public: + explicit Minimp3DecoderPlugin(std::string name); + + ~Minimp3DecoderPlugin() override; + + Status Init() override; + + Status Deinit() override; + + Status Prepare() override; + + Status Reset() override; + + Status Start() override; + + Status Stop() override; + + bool IsParameterSupported(Tag tag) override; + + Status GetParameter(Tag tag, ValueType& value) override; + + Status SetParameter(Tag tag, const ValueType& value) override; + + std::shared_ptr GetAllocator() override; + + Status SetCallback(const std::shared_ptr& cb) override; + + Status SendDataFromBufferLocked(const std::shared_ptr& inputBuffer); + + Status SendDataFromBuffer(const std::shared_ptr& inputBuffer); + + bool ReceiveBuffer(Status& status); + + Status QueueInputBuffer(const std::shared_ptr& inputBuffer, int32_t timeoutMs) override; + + Status QueueOutputBuffer(const std::shared_ptr& outputBuffers, int32_t timeoutMs) override; + + Status Flush() override; + + Status SetDataCallback(const std::weak_ptr& dataCallback) override; + + void NotifyInputBufferDone(const std::shared_ptr& input); + + void NotifyOutputBufferDone(const std::shared_ptr& output); + +private: + + void AudioDecoderMp3Open(void *userData); + + int AudioDecoderMp3Close(); + + int AudioDecoderMp3Process(std::shared_ptr inBuffer, std::shared_ptr outBuffer); + + int AudioDecoderMp3FreePacket(uint8_t *packet); + + AudioDecoderMp3Attr mp3DecoderAttr_; + Minimp3DemuxerOp minimp3DecoderImpl_; + std::map mp3Parameter_ {}; + State state_ {State::CREATED}; + std::weak_ptr dataCb_ {}; + OHOS::Media::BlockingQueue> outBufferQ_; +}; +} // namespace Plugin +} // namespace Media +} // namespace OHOS + +#endif // HISTREAMER_MINIMP3_DECODER_PLUGIN_H + +#endif diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp new file mode 100755 index 00000000..a7b1d83d --- /dev/null +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp @@ -0,0 +1,523 @@ +#define LOG_TAG "Minimp3DemuxerPlugin" + +#define MP3_MAX_SAMPLES_PER_FRAME (1152 * 2) +#define MP3_SEEK_DISCARD_ITEMS (2) +#define ID3_DETECT_SIZE 10 + +#include "minimp3_demuxer_plugin.h" +#include +#include +#include +#include +#include "core/plugin_manager.h" +#include "foundation/log.h" +#include "utils/memory_helper.h" +#include "osal/thread/scoped_lock.h" +#include "plugin/common/plugin_buffer.h" + +namespace OHOS { +namespace Media { +namespace Plugin { +namespace { + +int Sniff(const std::string& name, std::shared_ptr dataSource); +Status RegisterPlugins(const std::shared_ptr& reg); +void UpdatePluginDefinition(CodecPluginDef& definition); + +} + +Minimp3DemuxerPlugin::Minimp3DemuxerPlugin(std::string name) + : DemuxerPlugin(std::move(name)), + ioContext_(), + mediaIOBuf_(nullptr), + mediaIOSize_(12 * 1024), + readFrameBuf_(nullptr) +{ + memset(&mp3DemuxerAttr_, 0, sizeof(AudioDemuxerMp3Attr)); + memset(&mp3DemuxerRst_, 0, sizeof(AudioDemuxerRst)); + MEDIA_LOG_I("Minimp3DemuxerPlugin, plugin name: %s", pluginName_.c_str()); +} + +Minimp3DemuxerPlugin::~Minimp3DemuxerPlugin() +{ + MEDIA_LOG_I("~Minimp3DemuxerPlugin"); +} + +Status Minimp3DemuxerPlugin::SetDataSource(const std::shared_ptr& source) +{ + ioContext_.dataSource = source; + return Status::OK; +} + +Status Minimp3DemuxerPlugin::GetMediaInfo(MediaInfo& mediaInfo) +{ + int status = -1; + auto buffer = std::make_shared(); + auto bufData = buffer->AllocMemory(nullptr, mediaIOSize_); + int processLoop = 1; + while(processLoop) { + auto result = ioContext_.dataSource->ReadAt(ioContext_.offset, buffer, static_cast(mediaIOSize_)); + int realReadLen = bufData->Read(mediaIOBuf_, mediaIOSize_); + status = AudioDemuxerMp3Prepare(mediaIOBuf_, realReadLen); + switch(status) { + case AUDIO_DEMUXER_PREPARE_NEED_MORE_DATA: + ioContext_.offset = mp3DemuxerRst_.usedInputLength; + processLoop = 1; + break; + case AUDIO_DEMUXER_SUCCESS: + ioContext_.offset = mp3DemuxerRst_.usedInputLength; + + mediaInfo.tracks.resize(1); + mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_RATE, (uint32_t)mp3DemuxerRst_.frameSampleRate} ); + mediaInfo.tracks[0].insert({Tag::MEDIA_BITRATE, (uint32_t)mp3DemuxerRst_.frameBitrateKbps} ); + mediaInfo.tracks[0].insert({Tag::AUDIO_CHANNELS, (uint32_t)mp3DemuxerRst_.frameChannels} ); + mediaInfo.tracks[0].insert({Tag::STREAM_INDEX, (uint32_t)0} ); + mediaInfo.tracks[0].insert({Tag::MIME, std::string(MEDIA_MIME_AUDIO_MPEG)} ); + mediaInfo.tracks[0].insert({Tag::AUDIO_MPEG_VERSION, static_cast(1)} ); + mediaInfo.tracks[0].insert({Tag::AUDIO_MPEG_LAYER, static_cast(3)} ); // 3 + mediaInfo.tracks[0].insert({Tag::AUDIO_CHANNEL_LAYOUT, AudioChannelLayout::MONO} ); + mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_FORMAT, AudioSampleFormat::S16} ); + mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_PRE_FRAME, static_cast(1152)} ); + + processLoop = 0; + break; + case AUDIO_DEMUXER_ERROR: + // MEDIA_LOG_I("AUDIO_DEMUXER_ERROR"); + case AUDIO_DEMUXER_PREPARE_UNMATCHED_FORMAT: + default: + processLoop = 0; + free(mediaIOBuf_); + mediaIOBuf_ = nullptr; + MEDIA_LOG_I("AUDIO_DEMUXER_PREPARE_UNMATCHED_FORMAT %d", status); + return Status::ERROR_UNKNOWN; + } + } + free(mediaIOBuf_); + mediaIOBuf_ = nullptr; + return Status::OK; +} + +Status Minimp3DemuxerPlugin::ReadFrame(Buffer& info, int32_t timeOutMs) +{ + int status = -1; + auto buffer = std::make_shared(); + auto bufData = buffer->AllocMemory(nullptr, mediaIOSize_); + auto result = ioContext_.dataSource->ReadAt(ioContext_.offset, buffer, static_cast(mediaIOSize_)); + if (result != Status::OK) { + ioContext_.eos = true; + ioContext_.offset = 0; + return result; + } + int realReadLen = bufData->Read(readFrameBuf_, mediaIOSize_); + status = AudioDemuxerMp3Process(readFrameBuf_, realReadLen); + auto mp3FrameData = info.AllocMemory(nullptr, mp3DemuxerRst_.frameLength); + switch(status) { + case AUDIO_DEMUXER_SUCCESS: + ioContext_.offset = mp3DemuxerRst_.usedInputLength; + mp3FrameData->Write(mp3DemuxerRst_.frameBuffer, mp3DemuxerRst_.frameLength); + if (mp3DemuxerRst_.frameBuffer) { + free(mp3DemuxerRst_.frameBuffer); + mp3DemuxerRst_.frameBuffer = nullptr; + } + break; + case AUDIO_DEMUXER_ERROR: + default: + if (mp3DemuxerRst_.frameBuffer) { + free(mp3DemuxerRst_.frameBuffer); + mp3DemuxerRst_.frameBuffer = nullptr; + } + return Status::ERROR_UNKNOWN; + } + return Status::OK; +} + +Status Minimp3DemuxerPlugin::SeekTo(int32_t trackId, int64_t timeStampUs, SeekMode mode) +{ + uint64_t pos = 0; + uint32_t targetTtimeS = (uint32_t)(timeStampUs / 1000); + AudioDemuxerMp3GetSeekPosition(targetTtimeS, &pos); + mp3DemuxerRst_.usedInputLength = pos; + + return Status::OK; +} + +Status Minimp3DemuxerPlugin::Init() +{ + mediaIOBuf_ = (uint8_t*)malloc(mediaIOSize_); + if (mediaIOBuf_ == nullptr) { + goto error_exit; + } + readFrameBuf_ = (uint8_t*)malloc(mediaIOSize_); + if (readFrameBuf_ == nullptr) { + goto error_exit; + } + + minimp3DemuxerImpl_ = Minimp3GetOpt(); + AudioDemuxerMp3Open(nullptr); + return Status::OK; + +error_exit: + + if (mediaIOBuf_) { + free(mediaIOBuf_); + mediaIOBuf_ = nullptr; + } + if (readFrameBuf_) { + free(readFrameBuf_); + readFrameBuf_ = nullptr; + } + return Status::ERROR_NO_MEMORY; +} + +Status Minimp3DemuxerPlugin::Deinit() +{ + if (mediaIOBuf_) { + free(mediaIOBuf_); + mediaIOBuf_ = NULL; + } + + if (readFrameBuf_) { + free(readFrameBuf_); + readFrameBuf_ = NULL; + } + + return Status::OK; +} + +Status Minimp3DemuxerPlugin::Prepare() +{ + return Status::OK; +} + +Status Minimp3DemuxerPlugin::Reset() +{ + ioContext_.eos = false; + ioContext_.dataSource.reset(); + ioContext_.offset = 0; + return Status::OK; +} + +Status Minimp3DemuxerPlugin::Start() +{ + return Status::OK; +} + +Status Minimp3DemuxerPlugin::Stop() +{ + return Status::OK; +} + +bool Minimp3DemuxerPlugin::IsParameterSupported(Tag tag) +{ + return false; +} + +Status Minimp3DemuxerPlugin::GetParameter(Tag tag, ValueType &value) +{ + return Status::ERROR_UNIMPLEMENTED; +} + +Status Minimp3DemuxerPlugin::SetParameter(Tag tag, const ValueType &value) +{ + return Status::ERROR_UNIMPLEMENTED; +} + +std::shared_ptr Minimp3DemuxerPlugin::GetAllocator() +{ + return nullptr; +} + +Status Minimp3DemuxerPlugin::SetCallback(const std::shared_ptr& cb) +{ + return Status::OK; +} + +size_t Minimp3DemuxerPlugin::GetTrackCount() +{ + return 0; +} +Status Minimp3DemuxerPlugin::SelectTrack(int32_t trackId) +{ + return Status::OK; +} +Status Minimp3DemuxerPlugin::UnselectTrack(int32_t trackId) +{ + return Status::OK; +} +Status Minimp3DemuxerPlugin::GetSelectedTracks(std::vector& trackIds) +{ + return Status::OK; +} + +void Minimp3DemuxerPlugin::AudioDemuxerMp3IgnoreTailZero(uint8_t *data, uint32_t *dataLen) +{ + if ((data == NULL) || (dataLen == NULL) || (*dataLen == 0)) { + return; + } + + uint32_t len = *dataLen; + uint8_t *ptr = data + len - 1; + + do { + if (*ptr == 0) { + ptr--; + len--; + } else { + break; + } + } while (len); + + *dataLen = len; +} + +int Minimp3DemuxerPlugin::AudioDemuxerMp3IterateCallback(void *userData, const uint8_t *frame, int frameSize, int freeFormatBytes, size_t bufSize, uint64_t offset, Mp3DemuxerFrameInfo *info) +{ + AudioDemuxerMp3Attr *mp3Demuxer = (AudioDemuxerMp3Attr *)userData; + AudioDemuxerRst *rst = mp3Demuxer->rst; + uint64_t usedInputLength = 0; + + if (mp3Demuxer->internalRemainLen >= frameSize) { + usedInputLength = offset + frameSize; + } else { + usedInputLength = offset; + } + + if (frameSize == 0) { + rst->usedInputLength = 0; + rst->frameBuffer = NULL; + rst->frameLength = 0; + return 0; + } + + if (frameSize >= 16 * 1024) { + return AUDIO_DEMUXER_ERROR; + } + + uint8_t *rstFrame = (uint8_t *)calloc(frameSize, sizeof(uint8_t)); + if (!rstFrame) { + return AUDIO_DEMUXER_ERROR; + } + + memcpy(rstFrame, frame, frameSize); + rst->frameBuffer = rstFrame; + rst->frameLength = frameSize; + rst->frameBitrateKbps = info->bitrate_kbps; + rst->frameChannels = info->channels; + rst->frameSampleRate = info->hz; + rst->usedInputLength += usedInputLength; + return 1; +} + +int Minimp3DemuxerPlugin::AudioDemuxerMp3ProbeDecodeCheck(Mp3DemuxerFrameInfo *info) +{ + if (!info) { + return -1; + } + + if (!(info->layer == 1 || info->layer == 2 || info->layer == 3)) { + return -1; + } + + if (!(info->bitrate_kbps == 8 || info->bitrate_kbps == 16 || info->bitrate_kbps == 24 || info->bitrate_kbps == 32 || + info->bitrate_kbps == 40 || info->bitrate_kbps == 48 || info->bitrate_kbps == 56 || info->bitrate_kbps == 64 || + info->bitrate_kbps == 80 || info->bitrate_kbps == 96 || info->bitrate_kbps == 112 || info->bitrate_kbps == 128 || + info->bitrate_kbps == 144 || info->bitrate_kbps == 160 || info->bitrate_kbps == 176 || info->bitrate_kbps == 192 || + info->bitrate_kbps == 224 || info->bitrate_kbps == 256 || info->bitrate_kbps == 288 || info->bitrate_kbps == 320 || + info->bitrate_kbps == 352 || info->bitrate_kbps == 384 || info->bitrate_kbps == 416 || info->bitrate_kbps == 448)) { + return -1; + } + + if (!(info->hz == 8000 || info->hz == 11025 || info->hz == 12000 || + info->hz == 16000 || info->hz == 22050 || info->hz == 24000 || + info->hz == 32000 || info->hz == 44100 || info->hz == 48000)) { + return -1; + } + return 0; +} + +int Minimp3DemuxerPlugin::AudioDemuxerMp3IterateCallbackForPrepare(void *userData, const uint8_t *frame, int frameSize, int freeFormatBytes, size_t bufSize, + uint64_t offset, Mp3DemuxerFrameInfo *info) +{ + int sampleCount = 0; + Mp3DemuxerFrameInfo frameInfo; + + AudioDemuxerMp3Attr *mp3Demuxer = (AudioDemuxerMp3Attr *) userData; + AudioDemuxerRst *rst = mp3Demuxer->rst; + rst->frameBitrateKbps = info->bitrate_kbps; + rst->frameChannels = info->channels; + rst->frameSampleRate = info->hz; + + return 1; +} + +void Minimp3DemuxerPlugin::AudioDemuxerMp3Open(AudioDemuxerUserArg *userArg) +{ + AudioDemuxerUserArg *arg = userArg; + mp3DemuxerAttr_.userArg = userArg; + minimp3DemuxerImpl_.init(&mp3DemuxerAttr_.mp3DemuxerHandle); + return; +} + +int Minimp3DemuxerPlugin::AudioDemuxerMp3Close() +{ + if (mp3DemuxerAttr_.rst) { + free(mp3DemuxerAttr_.rst); + } + return 0; +} + +size_t Minimp3DemuxerPlugin::AudioDemuxerMp3GetId3v2Size(const uint8_t *buf, size_t bufSize) +{ + if (bufSize >= ID3_DETECT_SIZE && !memcmp(buf, "ID3", 3) && !((buf[5] & 15) || (buf[6] & 0x80) || (buf[7] & 0x80) || (buf[8] & 0x80) || (buf[9] & 0x80))) { + size_t id3v2Size = (((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f)) + 10; + if ((buf[5] & 16)) { + id3v2Size += 10; + } + return id3v2Size; + } + return 0; +} + +int Minimp3DemuxerPlugin::AudioDemuxerMp3Prepare(uint8_t *buf, uint32_t len) +{ + if ((buf == NULL) || (len <= 0)) { + MEDIA_LOG_I("%s arg error", __func__); + return -1; + } + int ret; + + if (mp3DemuxerAttr_.id3v2SkipFlag == 0) { + if (mp3DemuxerAttr_.id3v2Offset == 0) { + if (len < ID3_DETECT_SIZE) { + mp3DemuxerRst_.usedInputLength = 0; + return AUDIO_DEMUXER_PREPARE_NEED_MORE_DATA; + } else { + mp3DemuxerAttr_.id3v2Size = AudioDemuxerMp3GetId3v2Size(buf, len); + mp3DemuxerAttr_.id3v2Offset = mp3DemuxerAttr_.id3v2Size; + } + } + + if (mp3DemuxerAttr_.id3v2Offset) { + MEDIA_LOG_I("mp3 id3v2Offset = %d, input data len %d", mp3DemuxerAttr_.id3v2Offset, len); + if (len >= mp3DemuxerAttr_.id3v2Offset) { + mp3DemuxerRst_.usedInputLength = mp3DemuxerAttr_.id3v2Offset; + mp3DemuxerAttr_.id3v2SkipFlag = 1; + len -= mp3DemuxerAttr_.id3v2Offset; + buf += mp3DemuxerAttr_.id3v2Offset; + mp3DemuxerAttr_.id3v2Offset = 0; + } else { + mp3DemuxerRst_.usedInputLength = len; + mp3DemuxerAttr_.id3v2Offset = mp3DemuxerAttr_.id3v2Offset - len; + return AUDIO_DEMUXER_PREPARE_NEED_MORE_DATA; + } + } + } + mp3DemuxerAttr_.rst = &mp3DemuxerRst_; + mp3DemuxerAttr_.internalRemainLen = len; + ret = minimp3DemuxerImpl_.iterateBuf(buf, len, AudioDemuxerMp3IterateCallbackForPrepare, &mp3DemuxerAttr_); + if (ret != 1) { + if (mp3DemuxerAttr_.id3v2SkipFlag) { + return AUDIO_DEMUXER_PREPARE_NEED_MORE_DATA; + } + return AUDIO_DEMUXER_PREPARE_UNMATCHED_FORMAT; + } + + mp3DemuxerAttr_.bitRate = mp3DemuxerRst_.frameBitrateKbps; + mp3DemuxerAttr_.sampleRate = mp3DemuxerRst_.frameSampleRate; + mp3DemuxerAttr_.channelNum = mp3DemuxerRst_.frameChannels; + MEDIA_LOG_I("mp3 file: sample_rate %d, channels %d, bitrate %d kbps", mp3DemuxerRst_.frameSampleRate, mp3DemuxerRst_.frameChannels, mp3DemuxerRst_.frameBitrateKbps); + MEDIA_LOG_I("mp3 file: file_size = %d, id3v2_size = %d", mp3DemuxerAttr_.fileSize, mp3DemuxerAttr_.id3v2Size); + return AUDIO_DEMUXER_SUCCESS; +} + +int Minimp3DemuxerPlugin::AudioDemuxerMp3Process(uint8_t *buf, uint32_t len) +{ + if ((buf == NULL) || (len <= 0)) { + MEDIA_LOG_I("%s arg error", __func__); + return AUDIO_DEMUXER_ERROR; + } + int ret = 0; + uint32_t processLen = len; + AudioDemuxerMp3IgnoreTailZero(buf, &processLen); + mp3DemuxerAttr_.rst = &mp3DemuxerRst_; + mp3DemuxerAttr_.internalRemainLen = processLen; + ret = minimp3DemuxerImpl_.iterateBuf(buf, processLen, AudioDemuxerMp3IterateCallback, &mp3DemuxerAttr_); + + if (mp3DemuxerAttr_.mp3SeekFlag == 1 && mp3DemuxerAttr_.discardItemCount < MP3_SEEK_DISCARD_ITEMS) { + memset(mp3DemuxerRst_.frameBuffer, 0, mp3DemuxerRst_.frameLength); + mp3DemuxerAttr_.discardItemCount++; + } else { + mp3DemuxerAttr_.discardItemCount = 0; + mp3DemuxerAttr_.mp3SeekFlag = 0; + } + if (ret == 0 || ret == 1) { + return AUDIO_DEMUXER_SUCCESS; + } else { + return AUDIO_DEMUXER_ERROR; + } +} + +int Minimp3DemuxerPlugin::AudioDemuxerMp3FreeFrame(uint8_t *frame) +{ + if (frame) { + free(frame); + return 0; + } else { + return -1; + } +} + +int Minimp3DemuxerPlugin::AudioDemuxerMp3Seek( uint32_t pos, uint8_t *buf, uint32_t len, AudioDemuxerRst *rst) +{ + return 0; +} + +int Minimp3DemuxerPlugin::AudioDemuxerMp3GetSeekPosition(uint32_t targetTtimeS, uint64_t *pos) +{ + if (!pos) { + MEDIA_LOG_I("pos NULL error"); + return AUDIO_DEMUXER_ERROR; + } + uint32_t targetPos = targetTtimeS * mp3DemuxerAttr_.bitRate * 1000 / 8 + mp3DemuxerAttr_.id3v2Size; + *pos = (uint64_t)targetPos; + mp3DemuxerAttr_.mp3SeekFlag = 1; + return 0; +} + +namespace { + + int Sniff(const std::string& name, std::shared_ptr dataSource) + { + return 100; + } + + Status RegisterPlugins(const std::shared_ptr& reg) + { + MEDIA_LOG_D("RegisterPlugins called."); + if (!reg) { + MEDIA_LOG_E("RegisterPlugins failed due to null pointer for reg."); + return Status::ERROR_INVALID_PARAMETER; + } + + std::string pluginName = "Minimp3DemuxerPlugin"; + DemuxerPluginDef regInfo; + regInfo.name = pluginName; + regInfo.description = "adapter for minimp3 demuxer plugin"; + regInfo.rank = 100; + regInfo.creator = [](const std::string &name) -> std::shared_ptr { + return std::make_shared(name); + }; + regInfo.sniffer = Sniff; + auto rtv = reg->AddPlugin(regInfo); + if (rtv != Status::OK) { + MEDIA_LOG_E("RegisterPlugins AddPlugin failed with return %d", static_cast(rtv)); + } + return Status::OK; + } +} + +PLUGIN_DEFINITION(Minimp3Demuxer, LicenseType::LGPL, RegisterPlugins, [] {}); + +} +} +} \ No newline at end of file diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h new file mode 100755 index 00000000..627ede93 --- /dev/null +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h @@ -0,0 +1,140 @@ +#ifndef MINIMP3_DEMUXER_PLUGIN_H +#define MINIMP3_DEMUXER_PLUGIN_H + +#include +#include +#include + +#include "utils/type_define.h" +#include "core/plugin_register.h" +#include "interface/demuxer_plugin.h" +#include "thread/mutex.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include "minimp3_wrapper.h" + +#ifdef __cplusplus +} +#endif + +typedef Minimp3WrapperMp3dec Mp3DemuxerHandle; +typedef Minimp3WrapperMp3dSample Mp3DemuxerSampleAttr; +typedef Minimp3WrapperMp3decFrameInfo Mp3DemuxerFrameInfo; + +typedef enum +{ + AUDIO_DEMUXER_PREPARE_UNMATCHED_FORMAT = -2, + AUDIO_DEMUXER_ERROR = -1, + AUDIO_DEMUXER_SUCCESS = 0, + AUDIO_DEMUXER_PROCESS_NEED_MORE_DATA, + AUDIO_DEMUXER_PREPARE_NEED_MORE_DATA, + AUDIO_DEMUXER_PREPARE_NEED_SEEK, + AUDIO_DEMUXER_SEEK_NEED_MORE_DATA, +} AudioDemuxerStatus; + +typedef struct +{ + uint32_t fileSize; + void *priv; +} AudioDemuxerUserArg; + +typedef struct +{ + uint64_t usedInputLength; + uint8_t *frameBuffer; + uint32_t frameLength; + uint64_t inputNeedOffsetSize; + + uint32_t frameBitrateKbps; + uint32_t frameSampleRate; + uint8_t frameChannels; +} AudioDemuxerRst; + +typedef struct +{ + Mp3DemuxerHandle mp3DemuxerHandle; + AudioDemuxerRst *rst; + void *userArg; + uint32_t internalRemainLen; + uint32_t fileSize; + uint32_t bitRate; + uint32_t sampleRate; + uint8_t channelNum; + + uint8_t id3v2SkipFlag; + uint32_t id3v2Size; + uint32_t id3v2Offset; + + uint32_t seekOffset; + + uint8_t mp3SeekFlag; + uint8_t discardItemCount; + + Mp3DemuxerSampleAttr *preparePcmBuf; +} AudioDemuxerMp3Attr; + +namespace OHOS { +namespace Media { +namespace Plugin { +class Minimp3DemuxerPlugin : public DemuxerPlugin { +public: + Minimp3DemuxerPlugin *g_Plugin; + explicit Minimp3DemuxerPlugin(std::string name); + ~Minimp3DemuxerPlugin() override; + Status Init() override; + Status Deinit() override; + Status Prepare() override; + Status Reset() override; + Status Start() override; + Status Stop() override; + bool IsParameterSupported(Tag tag) override; + Status GetParameter(Tag tag, ValueType& value) override; + Status SetParameter(Tag tag, const ValueType& value) override; + std::shared_ptr GetAllocator() override; + Status SetCallback(const std::shared_ptr& cb) override; + + Status SetDataSource(const std::shared_ptr& source) override; + Status GetMediaInfo(MediaInfo& mediaInfo) override; + Status ReadFrame(Buffer& info, int32_t timeOutMs) override; + Status SeekTo(int32_t trackId, int64_t timeStampUs, SeekMode mode) override; + + size_t GetTrackCount() override; + Status SelectTrack(int32_t trackId) override; + Status UnselectTrack(int32_t trackId) override; + Status GetSelectedTracks(std::vector& trackIds) override; + static int AudioDemuxerMp3IterateCallbackForPrepare(void *userData, const uint8_t *frame, int frameSize, int freeFormatBytes, size_t bufSize, uint64_t offset, Mp3DemuxerFrameInfo *info); +private: + struct IOContext { + std::shared_ptr dataSource {nullptr}; + int64_t offset {0}; + bool eos {false}; + }; + void AudioDemuxerMp3IgnoreTailZero( uint8_t *data, uint32_t *dataLen); + static int AudioDemuxerMp3IterateCallback(void *userData, const uint8_t *frame, int frameSize, int freeFormatBytes, size_t bufSize, uint64_t offset, Mp3DemuxerFrameInfo *info); + int AudioDemuxerMp3ProbeDecodeCheck(Mp3DemuxerFrameInfo *info); + + void AudioDemuxerMp3Open(AudioDemuxerUserArg *userArg); + int AudioDemuxerMp3Close(); + size_t AudioDemuxerMp3GetId3v2Size(const uint8_t *buf, size_t bufSize); + int AudioDemuxerMp3Prepare(uint8_t *buf, uint32_t len); + int AudioDemuxerMp3Process(uint8_t *buf, uint32_t len); + int AudioDemuxerMp3FreeFrame(uint8_t *frame); + int AudioDemuxerMp3Seek( uint32_t pos, uint8_t *buf, uint32_t len, AudioDemuxerRst *rst); + int AudioDemuxerMp3GetSeekPosition(uint32_t targetTtimeS, uint64_t *pos); + + int mediaIOSize_; + uint8_t *mediaIOBuf_; + uint8_t *readFrameBuf_; + IOContext ioContext_; + AudioDemuxerRst mp3DemuxerRst_; + Minimp3DemuxerOp minimp3DemuxerImpl_; + AudioDemuxerMp3Attr mp3DemuxerAttr_; +}; +} // namespace Plugin +} // namespace Media +} // namespace OHOS + +#endif // MINIMP3_DEMUXER_PLUGIN_H \ No newline at end of file diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_ex.h b/engine/plugin/plugins/minimp3_adapter/minimp3_ex.h new file mode 100755 index 00000000..17ba5ae6 --- /dev/null +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_ex.h @@ -0,0 +1,1393 @@ +#ifndef MINIMP3_EXT_H +#define MINIMP3_EXT_H +/* + https://github.com/lieff/minimp3 + To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. + This software is distributed without any warranty. + See . +*/ +#include "minimp3.h" + +/* flags for mp3dec_ex_open_* functions */ +#define MP3D_SEEK_TO_BYTE 0 /* mp3dec_ex_seek seeks to byte in stream */ +#define MP3D_SEEK_TO_SAMPLE 1 /* mp3dec_ex_seek precisely seeks to sample using index (created during duration calculation scan or when mp3dec_ex_seek called) */ +#define MP3D_DO_NOT_SCAN 2 /* do not scan whole stream for duration if vbrtag not found, mp3dec_ex_t::samples will be filled only if mp3dec_ex_t::vbr_tag_found == 1 */ +#ifdef MINIMP3_ALLOW_MONO_STEREO_TRANSITION +#define MP3D_ALLOW_MONO_STEREO_TRANSITION 4 +#define MP3D_FLAGS_MASK 7 +#else +#define MP3D_FLAGS_MASK 3 +#endif + +/* compile-time config */ +#define MINIMP3_PREDECODE_FRAMES 2 /* frames to pre-decode and skip after seek (to fill internal structures) */ +/*#define MINIMP3_SEEK_IDX_LINEAR_SEARCH*/ /* define to use linear index search instead of binary search on seek */ +#define MINIMP3_IO_SIZE (128*1024) /* io buffer size for streaming functions, must be greater than MINIMP3_BUF_SIZE */ +#define MINIMP3_BUF_SIZE (16*1024) /* buffer which can hold minimum 10 consecutive mp3 frames (~16KB) worst case */ +/*#define MINIMP3_SCAN_LIMIT (256*1024)*/ /* how many bytes will be scanned to search first valid mp3 frame, to prevent stall on large non-mp3 files */ +#define MINIMP3_ENABLE_RING 0 /* WIP enable hardware magic ring buffer if available, to make less input buffer memmove(s) in callback IO mode */ + +/* return error codes */ +#define MP3D_E_PARAM -1 +#define MP3D_E_MEMORY -2 +#define MP3D_E_IOERROR -3 +#define MP3D_E_USER -4 /* can be used to stop processing from callbacks without indicating specific error */ +#define MP3D_E_DECODE -5 /* decode error which can't be safely skipped, such as sample rate, layer and channels change */ + +typedef struct +{ + mp3d_sample_t *buffer; + size_t samples; /* channels included, byte size = samples*sizeof(mp3d_sample_t) */ + int channels, hz, layer, avg_bitrate_kbps; +} mp3dec_file_info_t; + +typedef struct +{ + const uint8_t *buffer; + size_t size; +} mp3dec_map_info_t; + +typedef struct +{ + uint64_t sample; + uint64_t offset; +} mp3dec_frame_t; + +typedef struct +{ + mp3dec_frame_t *frames; + size_t num_frames, capacity; +} mp3dec_index_t; + +typedef size_t (*MP3D_READ_CB)(void *buf, size_t size, void *user_data); +typedef int (*MP3D_SEEK_CB)(uint64_t position, void *user_data); + +typedef struct +{ + MP3D_READ_CB read; + void *read_data; + MP3D_SEEK_CB seek; + void *seek_data; +} mp3dec_io_t; + +typedef struct +{ + mp3dec_t mp3d; + mp3dec_map_info_t file; + mp3dec_io_t *io; + mp3dec_index_t index; + uint64_t offset, samples, detected_samples, cur_sample, start_offset, end_offset; + mp3dec_frame_info_t info; + mp3d_sample_t buffer[MINIMP3_MAX_SAMPLES_PER_FRAME]; + size_t input_consumed, input_filled; + int is_file, flags, vbr_tag_found, indexes_built; + int free_format_bytes; + int buffer_samples, buffer_consumed, to_skip, start_delay; + int last_error; +} mp3dec_ex_t; + +typedef int (*MP3D_ITERATE_CB)(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t buf_size, uint64_t offset, mp3dec_frame_info_t *info); +typedef int (*MP3D_PROGRESS_CB)(void *user_data, size_t file_size, uint64_t offset, mp3dec_frame_info_t *info); + +#ifdef __cplusplus +extern "C" { +#endif + +/* detect mp3/mpa format */ +int mp3dec_detect_buf(const uint8_t *buf, size_t buf_size); +int mp3dec_detect_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size); +/* decode whole buffer block */ +int mp3dec_load_buf(mp3dec_t *dec, const uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); +int mp3dec_load_cb(mp3dec_t *dec, mp3dec_io_t *io, uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); +/* iterate through frames */ +int mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data); +int mp3dec_iterate_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data); +/* streaming decoder with seeking capability */ +int mp3dec_ex_open_buf(mp3dec_ex_t *dec, const uint8_t *buf, size_t buf_size, int flags); +int mp3dec_ex_open_cb(mp3dec_ex_t *dec, mp3dec_io_t *io, int flags); +void mp3dec_ex_close(mp3dec_ex_t *dec); +int mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position); +size_t mp3dec_ex_read_frame(mp3dec_ex_t *dec, mp3d_sample_t **buf, mp3dec_frame_info_t *frame_info, size_t max_samples); +size_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples); +#ifndef MINIMP3_NO_STDIO +/* stdio versions of file detect, load, iterate and stream */ +int mp3dec_detect(const char *file_name); +int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); +int mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data); +int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int flags); +#ifdef _WIN32 +int mp3dec_detect_w(const wchar_t *file_name); +int mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); +int mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data); +int mp3dec_ex_open_w(mp3dec_ex_t *dec, const wchar_t *file_name, int flags); +#endif +#endif + +#ifdef __cplusplus +} +#endif +#endif /*MINIMP3_EXT_H*/ + +#ifdef MINIMP3_IMPLEMENTATION +#include + +static void mp3dec_skip_id3v1(const uint8_t *buf, size_t *pbuf_size) +{ + size_t buf_size = *pbuf_size; +#ifndef MINIMP3_NOSKIP_ID3V1 + if (buf_size >= 128 && !memcmp(buf + buf_size - 128, "TAG", 3)) + { + buf_size -= 128; + if (buf_size >= 227 && !memcmp(buf + buf_size - 227, "TAG+", 4)) + buf_size -= 227; + } +#endif +#ifndef MINIMP3_NOSKIP_APEV2 + if (buf_size > 32 && !memcmp(buf + buf_size - 32, "APETAGEX", 8)) + { + buf_size -= 32; + const uint8_t *tag = buf + buf_size + 8 + 4; + uint32_t tag_size = (uint32_t)(tag[3] << 24) | (tag[2] << 16) | (tag[1] << 8) | tag[0]; + if (buf_size >= tag_size) + buf_size -= tag_size; + } +#endif + *pbuf_size = buf_size; +} + +static size_t mp3dec_skip_id3v2(const uint8_t *buf, size_t buf_size) +{ +#define MINIMP3_ID3_DETECT_SIZE 10 +#ifndef MINIMP3_NOSKIP_ID3V2 + if (buf_size >= MINIMP3_ID3_DETECT_SIZE && !memcmp(buf, "ID3", 3) && !((buf[5] & 15) || (buf[6] & 0x80) || (buf[7] & 0x80) || (buf[8] & 0x80) || (buf[9] & 0x80))) + { + size_t id3v2size = (((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f)) + 10; + if ((buf[5] & 16)) + id3v2size += 10; /* footer */ + return id3v2size; + } +#endif + return 0; +} + +static void mp3dec_skip_id3(const uint8_t **pbuf, size_t *pbuf_size) +{ + uint8_t *buf = (uint8_t *)(*pbuf); + size_t buf_size = *pbuf_size; + size_t id3v2size = mp3dec_skip_id3v2(buf, buf_size); + if (id3v2size) + { + if (id3v2size >= buf_size) + id3v2size = buf_size; + buf += id3v2size; + buf_size -= id3v2size; + } + mp3dec_skip_id3v1(buf, &buf_size); + *pbuf = (const uint8_t *)buf; + *pbuf_size = buf_size; +} + +static int mp3dec_check_vbrtag(const uint8_t *frame, int frame_size, uint32_t *frames, int *delay, int *padding) +{ + static const char g_xing_tag[4] = { 'X', 'i', 'n', 'g' }; + static const char g_info_tag[4] = { 'I', 'n', 'f', 'o' }; +#define FRAMES_FLAG 1 +#define BYTES_FLAG 2 +#define TOC_FLAG 4 +#define VBR_SCALE_FLAG 8 + /* Side info offsets after header: + / Mono Stereo + / MPEG1 17 32 + / MPEG2 & 2.5 9 17*/ + bs_t bs[1]; + L3_gr_info_t gr_info[4]; + bs_init(bs, frame + HDR_SIZE, frame_size - HDR_SIZE); + if (HDR_IS_CRC(frame)) + get_bits(bs, 16); + if (L3_read_side_info(bs, gr_info, frame) < 0) + return 0; /* side info corrupted */ + + const uint8_t *tag = frame + HDR_SIZE + bs->pos/8; + if (memcmp(g_xing_tag, tag, 4) && memcmp(g_info_tag, tag, 4)) + return 0; + int flags = tag[7]; + if (!((flags & FRAMES_FLAG))) + return -1; + tag += 8; + *frames = (uint32_t)(tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8) | tag[3]; + tag += 4; + if (flags & BYTES_FLAG) + tag += 4; + if (flags & TOC_FLAG) + tag += 100; + if (flags & VBR_SCALE_FLAG) + tag += 4; + *delay = *padding = 0; + if (*tag) + { /* extension, LAME, Lavc, etc. Should be the same structure. */ + tag += 21; + if (tag - frame + 14 >= frame_size) + return 0; + *delay = ((tag[0] << 4) | (tag[1] >> 4)) + (528 + 1); + *padding = (((tag[1] & 0xF) << 8) | tag[2]) - (528 + 1); + } + return 1; +} + +int mp3dec_detect_buf(const uint8_t *buf, size_t buf_size) +{ + return mp3dec_detect_cb(0, (uint8_t *)buf, buf_size); +} + +int mp3dec_detect_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size) +{ + if (!buf || (size_t)-1 == buf_size || (io && buf_size < MINIMP3_BUF_SIZE)) + return MP3D_E_PARAM; + size_t filled = buf_size; + if (io) + { + if (io->seek(0, io->seek_data)) + return MP3D_E_IOERROR; + filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (filled > MINIMP3_ID3_DETECT_SIZE) + return MP3D_E_IOERROR; + } + if (filled < MINIMP3_ID3_DETECT_SIZE) + return MP3D_E_USER; /* too small, can't be mp3/mpa */ + if (mp3dec_skip_id3v2(buf, filled)) + return 0; /* id3v2 tag is enough evidence */ + if (io) + { + size_t readed = io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (readed > (buf_size - MINIMP3_ID3_DETECT_SIZE)) + return MP3D_E_IOERROR; + filled += readed; + if (filled < MINIMP3_BUF_SIZE) + mp3dec_skip_id3v1(buf, &filled); + } else + { + mp3dec_skip_id3v1(buf, &filled); + if (filled > MINIMP3_BUF_SIZE) + filled = MINIMP3_BUF_SIZE; + } + int free_format_bytes, frame_size; + mp3d_find_frame(buf, filled, &free_format_bytes, &frame_size); + if (frame_size) + return 0; /* MAX_FRAME_SYNC_MATCHES consecutive frames found */ + return MP3D_E_USER; +} + +int mp3dec_load_buf(mp3dec_t *dec, const uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + return mp3dec_load_cb(dec, 0, (uint8_t *)buf, buf_size, info, progress_cb, user_data); +} + +int mp3dec_load_cb(mp3dec_t *dec, mp3dec_io_t *io, uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + if (!dec || !buf || !info || (size_t)-1 == buf_size || (io && buf_size < MINIMP3_BUF_SIZE)) + return MP3D_E_PARAM; + uint64_t detected_samples = 0; + size_t orig_buf_size = buf_size; + int to_skip = 0; + mp3dec_frame_info_t frame_info; + memset(info, 0, sizeof(*info)); + memset(&frame_info, 0, sizeof(frame_info)); + + /* skip id3 */ + size_t filled = 0, consumed = 0; + int eof = 0, ret = 0; + if (io) + { + if (io->seek(0, io->seek_data)) + return MP3D_E_IOERROR; + filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (filled > MINIMP3_ID3_DETECT_SIZE) + return MP3D_E_IOERROR; + if (MINIMP3_ID3_DETECT_SIZE != filled) + return 0; + size_t id3v2size = mp3dec_skip_id3v2(buf, filled); + if (id3v2size) + { + if (io->seek(id3v2size, io->seek_data)) + return MP3D_E_IOERROR; + filled = io->read(buf, buf_size, io->read_data); + if (filled > buf_size) + return MP3D_E_IOERROR; + } else + { + size_t readed = io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (readed > (buf_size - MINIMP3_ID3_DETECT_SIZE)) + return MP3D_E_IOERROR; + filled += readed; + } + if (filled < MINIMP3_BUF_SIZE) + mp3dec_skip_id3v1(buf, &filled); + } else + { + mp3dec_skip_id3((const uint8_t **)&buf, &buf_size); + if (!buf_size) + return 0; + } + /* try to make allocation size assumption by first frame or vbr tag */ + mp3dec_init(dec); + int samples; + do + { + uint32_t frames; + int i, delay, padding, free_format_bytes = 0, frame_size = 0; + const uint8_t *hdr; + if (io) + { + if (!eof && filled - consumed < MINIMP3_BUF_SIZE) + { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ + memmove(buf, buf + consumed, filled - consumed); + filled -= consumed; + consumed = 0; + size_t readed = io->read(buf + filled, buf_size - filled, io->read_data); + if (readed > (buf_size - filled)) + return MP3D_E_IOERROR; + if (readed != (buf_size - filled)) + eof = 1; + filled += readed; + if (eof) + mp3dec_skip_id3v1(buf, &filled); + } + i = mp3d_find_frame(buf + consumed, filled - consumed, &free_format_bytes, &frame_size); + consumed += i; + hdr = buf + consumed; + } else + { + i = mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size); + buf += i; + buf_size -= i; + hdr = buf; + } + if (i && !frame_size) + continue; + if (!frame_size) + return 0; + frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2; + frame_info.hz = hdr_sample_rate_hz(hdr); + frame_info.layer = 4 - HDR_GET_LAYER(hdr); + frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr); + frame_info.frame_bytes = frame_size; + samples = hdr_frame_samples(hdr)*frame_info.channels; + if (3 != frame_info.layer) + break; + int ret = mp3dec_check_vbrtag(hdr, frame_size, &frames, &delay, &padding); + if (ret > 0) + { + padding *= frame_info.channels; + to_skip = delay*frame_info.channels; + detected_samples = samples*(uint64_t)frames; + if (detected_samples >= (uint64_t)to_skip) + detected_samples -= to_skip; + if (padding > 0 && detected_samples >= (uint64_t)padding) + detected_samples -= padding; + if (!detected_samples) + return 0; + } + if (ret) + { + if (io) + { + consumed += frame_size; + } else + { + buf += frame_size; + buf_size -= frame_size; + } + } + break; + } while(1); + size_t allocated = MINIMP3_MAX_SAMPLES_PER_FRAME*sizeof(mp3d_sample_t); + if (detected_samples) + allocated += detected_samples*sizeof(mp3d_sample_t); + else + allocated += (buf_size/frame_info.frame_bytes)*samples*sizeof(mp3d_sample_t); + info->buffer = (mp3d_sample_t*)malloc(allocated); + if (!info->buffer) + return MP3D_E_MEMORY; + /* save info */ + info->channels = frame_info.channels; + info->hz = frame_info.hz; + info->layer = frame_info.layer; + /* decode all frames */ + size_t avg_bitrate_kbps = 0, frames = 0; + do + { + if ((allocated - info->samples*sizeof(mp3d_sample_t)) < MINIMP3_MAX_SAMPLES_PER_FRAME*sizeof(mp3d_sample_t)) + { + allocated *= 2; + mp3d_sample_t *alloc_buf = (mp3d_sample_t*)realloc(info->buffer, allocated); + if (!alloc_buf) + return MP3D_E_MEMORY; + info->buffer = alloc_buf; + } + if (io) + { + if (!eof && filled - consumed < MINIMP3_BUF_SIZE) + { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ + memmove(buf, buf + consumed, filled - consumed); + filled -= consumed; + consumed = 0; + size_t readed = io->read(buf + filled, buf_size - filled, io->read_data); + if (readed != (buf_size - filled)) + eof = 1; + filled += readed; + if (eof) + mp3dec_skip_id3v1(buf, &filled); + } + samples = mp3dec_decode_frame(dec, buf + consumed, filled - consumed, info->buffer + info->samples, &frame_info); + consumed += frame_info.frame_bytes; + } else + { + samples = mp3dec_decode_frame(dec, buf, MINIMP3_MIN(buf_size, (size_t)INT_MAX), info->buffer + info->samples, &frame_info); + buf += frame_info.frame_bytes; + buf_size -= frame_info.frame_bytes; + } + if (samples) + { + if (info->hz != frame_info.hz || info->layer != frame_info.layer) + { + ret = MP3D_E_DECODE; + break; + } + if (info->channels && info->channels != frame_info.channels) + { +#ifdef MINIMP3_ALLOW_MONO_STEREO_TRANSITION + info->channels = 0; /* mark file with mono-stereo transition */ +#else + ret = MP3D_E_DECODE; + break; +#endif + } + samples *= frame_info.channels; + if (to_skip) + { + size_t skip = MINIMP3_MIN(samples, to_skip); + to_skip -= skip; + samples -= skip; + memmove(info->buffer, info->buffer + skip, samples*sizeof(mp3d_sample_t)); + } + info->samples += samples; + avg_bitrate_kbps += frame_info.bitrate_kbps; + frames++; + if (progress_cb) + { + ret = progress_cb(user_data, orig_buf_size, orig_buf_size - buf_size, &frame_info); + if (ret) + break; + } + } + } while (frame_info.frame_bytes); + if (detected_samples && info->samples > detected_samples) + info->samples = detected_samples; /* cut padding */ + /* reallocate to normal buffer size */ + if (allocated != info->samples*sizeof(mp3d_sample_t)) + { + mp3d_sample_t *alloc_buf = (mp3d_sample_t*)realloc(info->buffer, info->samples*sizeof(mp3d_sample_t)); + if (!alloc_buf && info->samples) + return MP3D_E_MEMORY; + info->buffer = alloc_buf; + } + if (frames) + info->avg_bitrate_kbps = avg_bitrate_kbps/frames; + return ret; +} + +int mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data) +{ + const uint8_t *orig_buf = buf; + if (!buf || (size_t)-1 == buf_size || !callback) + return MP3D_E_PARAM; + /* skip id3 */ + mp3dec_skip_id3(&buf, &buf_size); + mp3dec_frame_info_t frame_info; + memset(&frame_info, 0, sizeof(frame_info)); + do + { + int free_format_bytes = 0, frame_size = 0, ret; + int i = mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size); + buf += i; + buf_size -= i; + if (i && !frame_size) + continue; + if (!frame_size) + break; + const uint8_t *hdr = buf; + frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2; + frame_info.hz = hdr_sample_rate_hz(hdr); + frame_info.layer = 4 - HDR_GET_LAYER(hdr); + frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr); + frame_info.frame_bytes = frame_size; + + if (callback) + { + if ((ret = callback(user_data, hdr, frame_size, free_format_bytes, buf_size, hdr - orig_buf, &frame_info))){ + return ret; + } + } + buf += frame_size; + buf_size -= frame_size; + } while (1); + return 0; +} + +int mp3dec_iterate_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data) +{ + if (!io || !buf || (size_t)-1 == buf_size || buf_size < MINIMP3_BUF_SIZE || !callback) + return MP3D_E_PARAM; + size_t filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data), consumed = 0; + uint64_t readed = 0; + mp3dec_frame_info_t frame_info; + int eof = 0; + memset(&frame_info, 0, sizeof(frame_info)); + if (filled > MINIMP3_ID3_DETECT_SIZE) + return MP3D_E_IOERROR; + if (MINIMP3_ID3_DETECT_SIZE != filled) + return 0; + size_t id3v2size = mp3dec_skip_id3v2(buf, filled); + if (id3v2size) + { + if (io->seek(id3v2size, io->seek_data)) + return MP3D_E_IOERROR; + filled = io->read(buf, buf_size, io->read_data); + if (filled > buf_size) + return MP3D_E_IOERROR; + readed += id3v2size; + } else + { + size_t readed = io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data); + if (readed > (buf_size - MINIMP3_ID3_DETECT_SIZE)) + return MP3D_E_IOERROR; + filled += readed; + } + if (filled < MINIMP3_BUF_SIZE) + mp3dec_skip_id3v1(buf, &filled); + do + { + int free_format_bytes = 0, frame_size = 0, ret; + int i = mp3d_find_frame(buf + consumed, filled - consumed, &free_format_bytes, &frame_size); + if (i && !frame_size) + { + consumed += i; + continue; + } + if (!frame_size) + break; + const uint8_t *hdr = buf + consumed + i; + frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2; + frame_info.hz = hdr_sample_rate_hz(hdr); + frame_info.layer = 4 - HDR_GET_LAYER(hdr); + frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr); + frame_info.frame_bytes = frame_size; + + readed += i; + if (callback) + { + if ((ret = callback(user_data, hdr, frame_size, free_format_bytes, filled - consumed, readed, &frame_info))) + return ret; + } + readed += frame_size; + consumed += i + frame_size; + if (!eof && filled - consumed < MINIMP3_BUF_SIZE) + { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ + memmove(buf, buf + consumed, filled - consumed); + filled -= consumed; + consumed = 0; + size_t readed = io->read(buf + filled, buf_size - filled, io->read_data); + if (readed > (buf_size - filled)) + return MP3D_E_IOERROR; + if (readed != (buf_size - filled)) + eof = 1; + filled += readed; + if (eof) + mp3dec_skip_id3v1(buf, &filled); + } + } while (1); + return 0; +} + +static int mp3dec_load_index(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t buf_size, uint64_t offset, mp3dec_frame_info_t *info) +{ + mp3dec_frame_t *idx_frame; + mp3dec_ex_t *dec = (mp3dec_ex_t *)user_data; + if (!dec->index.frames && !dec->start_offset) + { /* detect VBR tag and try to avoid full scan */ + uint32_t frames; + int delay, padding; + dec->info = *info; + dec->start_offset = dec->offset = offset; + dec->end_offset = offset + buf_size; + dec->free_format_bytes = free_format_bytes; /* should not change */ + if (3 == dec->info.layer) + { + int ret = mp3dec_check_vbrtag(frame, frame_size, &frames, &delay, &padding); + if (ret) + dec->start_offset = dec->offset = offset + frame_size; + if (ret > 0) + { + padding *= info->channels; + dec->start_delay = dec->to_skip = delay*info->channels; + dec->samples = hdr_frame_samples(frame)*info->channels*(uint64_t)frames; + if (dec->samples >= (uint64_t)dec->start_delay) + dec->samples -= dec->start_delay; + if (padding > 0 && dec->samples >= (uint64_t)padding) + dec->samples -= padding; + dec->detected_samples = dec->samples; + dec->vbr_tag_found = 1; + return MP3D_E_USER; + } else if (ret < 0) + return 0; + } + } + if (dec->flags & MP3D_DO_NOT_SCAN) + return MP3D_E_USER; + if (dec->index.num_frames + 1 > dec->index.capacity) + { + if (!dec->index.capacity) + dec->index.capacity = 4096; + else + dec->index.capacity *= 2; + mp3dec_frame_t *alloc_buf = (mp3dec_frame_t *)realloc((void*)dec->index.frames, sizeof(mp3dec_frame_t)*dec->index.capacity); + if (!alloc_buf) + return MP3D_E_MEMORY; + dec->index.frames = alloc_buf; + } + idx_frame = &dec->index.frames[dec->index.num_frames++]; + idx_frame->offset = offset; + idx_frame->sample = dec->samples; + if (!dec->buffer_samples && dec->index.num_frames < 256) + { /* for some cutted mp3 frames, bit-reservoir not filled and decoding can't be started from first frames */ + /* try to decode up to 255 first frames till samples starts to decode */ + dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, frame, MINIMP3_MIN(buf_size, (size_t)INT_MAX), dec->buffer, info); + dec->samples += dec->buffer_samples*info->channels; + } else + dec->samples += hdr_frame_samples(frame)*info->channels; + return 0; +} + +int mp3dec_ex_open_buf(mp3dec_ex_t *dec, const uint8_t *buf, size_t buf_size, int flags) +{ + if (!dec || !buf || (size_t)-1 == buf_size || (flags & (~MP3D_FLAGS_MASK))) + return MP3D_E_PARAM; + memset(dec, 0, sizeof(*dec)); + dec->file.buffer = buf; + dec->file.size = buf_size; + dec->flags = flags; + mp3dec_init(&dec->mp3d); + int ret = mp3dec_iterate_buf(dec->file.buffer, dec->file.size, mp3dec_load_index, dec); + if (ret && MP3D_E_USER != ret) + return ret; + mp3dec_init(&dec->mp3d); + dec->buffer_samples = 0; + dec->indexes_built = !(dec->vbr_tag_found || (flags & MP3D_DO_NOT_SCAN)); + dec->flags &= (~MP3D_DO_NOT_SCAN); + return 0; +} + +#ifndef MINIMP3_SEEK_IDX_LINEAR_SEARCH +static size_t mp3dec_idx_binary_search(mp3dec_index_t *idx, uint64_t position) +{ + size_t end = idx->num_frames, start = 0, index = 0; + while (start <= end) + { + size_t mid = (start + end) / 2; + if (idx->frames[mid].sample >= position) + { /* move left side. */ + if (idx->frames[mid].sample == position) + return mid; + end = mid - 1; + } else + { /* move to right side */ + index = mid; + start = mid + 1; + if (start == idx->num_frames) + break; + } + } + return index; +} +#endif + +int mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position) +{ + size_t i; + if (!dec) + return MP3D_E_PARAM; + if (!(dec->flags & MP3D_SEEK_TO_SAMPLE)) + { + if (dec->io) + { + dec->offset = position; + } else + { + dec->offset = MINIMP3_MIN(position, dec->file.size); + } + dec->cur_sample = 0; + goto do_exit; + } + dec->cur_sample = position; + position += dec->start_delay; + if (0 == position) + { /* optimize seek to zero, no index needed */ +seek_zero: + dec->offset = dec->start_offset; + dec->to_skip = 0; + goto do_exit; + } + if (!dec->indexes_built) + { /* no index created yet (vbr tag used to calculate track length or MP3D_DO_NOT_SCAN open flag used) */ + dec->indexes_built = 1; + dec->samples = 0; + dec->buffer_samples = 0; + if (dec->io) + { + if (dec->io->seek(dec->start_offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + int ret = mp3dec_iterate_cb(dec->io, (uint8_t *)dec->file.buffer, dec->file.size, mp3dec_load_index, dec); + if (ret && MP3D_E_USER != ret) + return ret; + } else + { + int ret = mp3dec_iterate_buf(dec->file.buffer + dec->start_offset, dec->file.size - dec->start_offset, mp3dec_load_index, dec); + if (ret && MP3D_E_USER != ret) + return ret; + } + for (i = 0; i < dec->index.num_frames; i++) + dec->index.frames[i].offset += dec->start_offset; + dec->samples = dec->detected_samples; + } + if (!dec->index.frames) + goto seek_zero; /* no frames in file - seek to zero */ +#ifdef MINIMP3_SEEK_IDX_LINEAR_SEARCH + for (i = 0; i < dec->index.num_frames; i++) + { + if (dec->index.frames[i].sample >= position) + break; + } +#else + i = mp3dec_idx_binary_search(&dec->index, position); +#endif + if (i) + { + int to_fill_bytes = 511; + int skip_frames = MINIMP3_PREDECODE_FRAMES +#ifdef MINIMP3_SEEK_IDX_LINEAR_SEARCH + + ((dec->index.frames[i].sample == position) ? 0 : 1) +#endif + ; + i -= MINIMP3_MIN(i, (size_t)skip_frames); + if (3 == dec->info.layer) + { + while (i && to_fill_bytes) + { /* make sure bit-reservoir is filled when we start decoding */ + bs_t bs[1]; + L3_gr_info_t gr_info[4]; + int frame_bytes, frame_size; + const uint8_t *hdr; + if (dec->io) + { + hdr = dec->file.buffer; + if (dec->io->seek(dec->index.frames[i - 1].offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + size_t readed = dec->io->read((uint8_t *)hdr, HDR_SIZE, dec->io->read_data); + if (readed != HDR_SIZE) + return MP3D_E_IOERROR; + frame_size = hdr_frame_bytes(hdr, dec->free_format_bytes) + hdr_padding(hdr); + readed = dec->io->read((uint8_t *)hdr + HDR_SIZE, frame_size - HDR_SIZE, dec->io->read_data); + if (readed != (size_t)(frame_size - HDR_SIZE)) + return MP3D_E_IOERROR; + bs_init(bs, hdr + HDR_SIZE, frame_size - HDR_SIZE); + } else + { + hdr = dec->file.buffer + dec->index.frames[i - 1].offset; + frame_size = hdr_frame_bytes(hdr, dec->free_format_bytes) + hdr_padding(hdr); + bs_init(bs, hdr + HDR_SIZE, frame_size - HDR_SIZE); + } + if (HDR_IS_CRC(hdr)) + get_bits(bs, 16); + i--; + if (L3_read_side_info(bs, gr_info, hdr) < 0) + break; /* frame not decodable, we can start from here */ + frame_bytes = (bs->limit - bs->pos)/8; + to_fill_bytes -= MINIMP3_MIN(to_fill_bytes, frame_bytes); + } + } + } + dec->offset = dec->index.frames[i].offset; + dec->to_skip = position - dec->index.frames[i].sample; + while ((i + 1) < dec->index.num_frames && !dec->index.frames[i].sample && !dec->index.frames[i + 1].sample) + { /* skip not decodable first frames */ + const uint8_t *hdr; + if (dec->io) + { + hdr = dec->file.buffer; + if (dec->io->seek(dec->index.frames[i].offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + size_t readed = dec->io->read((uint8_t *)hdr, HDR_SIZE, dec->io->read_data); + if (readed != HDR_SIZE) + return MP3D_E_IOERROR; + } else + hdr = dec->file.buffer + dec->index.frames[i].offset; + dec->to_skip += hdr_frame_samples(hdr)*dec->info.channels; + i++; + } +do_exit: + if (dec->io) + { + if (dec->io->seek(dec->offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + } + dec->buffer_samples = 0; + dec->buffer_consumed = 0; + dec->input_consumed = 0; + dec->input_filled = 0; + dec->last_error = 0; + mp3dec_init(&dec->mp3d); + return 0; +} + +size_t mp3dec_ex_read_frame(mp3dec_ex_t *dec, mp3d_sample_t **buf, mp3dec_frame_info_t *frame_info, size_t max_samples) +{ + if (!dec || !buf || !frame_info) + { + if (dec) + dec->last_error = MP3D_E_PARAM; + return 0; + } + if (dec->detected_samples && dec->cur_sample >= dec->detected_samples) + return 0; /* at end of stream */ + if (dec->last_error) + return 0; /* error eof state, seek can reset it */ + *buf = NULL; + uint64_t end_offset = dec->end_offset ? dec->end_offset : dec->file.size; + int eof = 0; + while (dec->buffer_consumed == dec->buffer_samples) + { + const uint8_t *dec_buf; + if (dec->io) + { + if (!eof && (dec->input_filled - dec->input_consumed) < MINIMP3_BUF_SIZE) + { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ + memmove((uint8_t*)dec->file.buffer, (uint8_t*)dec->file.buffer + dec->input_consumed, dec->input_filled - dec->input_consumed); + dec->input_filled -= dec->input_consumed; + dec->input_consumed = 0; + size_t readed = dec->io->read((uint8_t*)dec->file.buffer + dec->input_filled, dec->file.size - dec->input_filled, dec->io->read_data); + if (readed > (dec->file.size - dec->input_filled)) + { + dec->last_error = MP3D_E_IOERROR; + readed = 0; + } + if (readed != (dec->file.size - dec->input_filled)) + eof = 1; + dec->input_filled += readed; + if (eof) + mp3dec_skip_id3v1((uint8_t*)dec->file.buffer, &dec->input_filled); + } + dec_buf = dec->file.buffer + dec->input_consumed; + if (!(dec->input_filled - dec->input_consumed)) + return 0; + dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, dec_buf, dec->input_filled - dec->input_consumed, dec->buffer, frame_info); + dec->input_consumed += frame_info->frame_bytes; + } else + { + dec_buf = dec->file.buffer + dec->offset; + uint64_t buf_size = end_offset - dec->offset; + if (!buf_size) + return 0; + dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, dec_buf, MINIMP3_MIN(buf_size, (uint64_t)INT_MAX), dec->buffer, frame_info); + } + dec->buffer_consumed = 0; + if (dec->info.hz != frame_info->hz || dec->info.layer != frame_info->layer) + { +return_e_decode: + dec->last_error = MP3D_E_DECODE; + return 0; + } + if (dec->buffer_samples) + { + dec->buffer_samples *= frame_info->channels; + if (dec->to_skip) + { + size_t skip = MINIMP3_MIN(dec->buffer_samples, dec->to_skip); + dec->buffer_consumed += skip; + dec->to_skip -= skip; + } + if ( +#ifdef MINIMP3_ALLOW_MONO_STEREO_TRANSITION + !(dec->flags & MP3D_ALLOW_MONO_STEREO_TRANSITION) && +#endif + dec->buffer_consumed != dec->buffer_samples && dec->info.channels != frame_info->channels) + { + goto return_e_decode; + } + } else if (dec->to_skip) + { /* In mp3 decoding not always can start decode from any frame because of bit reservoir, + count skip samples for such frames */ + int frame_samples = hdr_frame_samples(dec_buf)*frame_info->channels; + dec->to_skip -= MINIMP3_MIN(frame_samples, dec->to_skip); + } + dec->offset += frame_info->frame_bytes; + } + size_t out_samples = MINIMP3_MIN((size_t)(dec->buffer_samples - dec->buffer_consumed), max_samples); + if (dec->detected_samples) + { /* count decoded samples to properly cut padding */ + if (dec->cur_sample + out_samples >= dec->detected_samples) + out_samples = dec->detected_samples - dec->cur_sample; + } + dec->cur_sample += out_samples; + *buf = dec->buffer + dec->buffer_consumed; + dec->buffer_consumed += out_samples; + return out_samples; +} + +size_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples) +{ + if (!dec || !buf) + { + if (dec) + dec->last_error = MP3D_E_PARAM; + return 0; + } + mp3dec_frame_info_t frame_info; + memset(&frame_info, 0, sizeof(frame_info)); + size_t samples_requested = samples; + while (samples) + { + mp3d_sample_t *buf_frame = NULL; + size_t read_samples = mp3dec_ex_read_frame(dec, &buf_frame, &frame_info, samples); + if (!read_samples) + { + break; + } + memcpy(buf, buf_frame, read_samples * sizeof(mp3d_sample_t)); + buf += read_samples; + samples -= read_samples; + } + return samples_requested - samples; +} + +int mp3dec_ex_open_cb(mp3dec_ex_t *dec, mp3dec_io_t *io, int flags) +{ + if (!dec || !io || (flags & (~MP3D_FLAGS_MASK))) + return MP3D_E_PARAM; + memset(dec, 0, sizeof(*dec)); +#ifdef MINIMP3_HAVE_RING + int ret; + if (ret = mp3dec_open_ring(&dec->file, MINIMP3_IO_SIZE)) + return ret; +#else + dec->file.size = MINIMP3_IO_SIZE; + dec->file.buffer = (const uint8_t*)malloc(dec->file.size); + if (!dec->file.buffer) + return MP3D_E_MEMORY; +#endif + dec->flags = flags; + dec->io = io; + mp3dec_init(&dec->mp3d); + if (io->seek(0, io->seek_data)) + return MP3D_E_IOERROR; + int ret = mp3dec_iterate_cb(io, (uint8_t *)dec->file.buffer, dec->file.size, mp3dec_load_index, dec); + if (ret && MP3D_E_USER != ret) + return ret; + if (dec->io->seek(dec->start_offset, dec->io->seek_data)) + return MP3D_E_IOERROR; + mp3dec_init(&dec->mp3d); + dec->buffer_samples = 0; + dec->indexes_built = !(dec->vbr_tag_found || (flags & MP3D_DO_NOT_SCAN)); + dec->flags &= (~MP3D_DO_NOT_SCAN); + return 0; +} + + +#ifndef MINIMP3_NO_STDIO + +#if defined(__linux__) || defined(__FreeBSD__) +#include +#include +#include +#include +#include +#include +#if !defined(_GNU_SOURCE) +#include +#include +#endif +#if !defined(MAP_POPULATE) && defined(__linux__) +#define MAP_POPULATE 0x08000 +#elif !defined(MAP_POPULATE) +#define MAP_POPULATE 0 +#endif + +static void mp3dec_close_file(mp3dec_map_info_t *map_info) +{ + if (map_info->buffer && MAP_FAILED != map_info->buffer) + munmap((void *)map_info->buffer, map_info->size); + map_info->buffer = 0; + map_info->size = 0; +} + +static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info) +{ + if (!file_name) + return MP3D_E_PARAM; + int file; + struct stat st; + memset(map_info, 0, sizeof(*map_info)); +retry_open: + file = open(file_name, O_RDONLY); + if (file < 0 && (errno == EAGAIN || errno == EINTR)) + goto retry_open; + if (file < 0 || fstat(file, &st) < 0) + { + close(file); + return MP3D_E_IOERROR; + } + + map_info->size = st.st_size; +retry_mmap: + map_info->buffer = (const uint8_t *)mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, file, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap; + close(file); + if (MAP_FAILED == map_info->buffer) + return MP3D_E_IOERROR; + return 0; +} + +#if MINIMP3_ENABLE_RING && defined(__linux__) && defined(_GNU_SOURCE) +#define MINIMP3_HAVE_RING +static void mp3dec_close_ring(mp3dec_map_info_t *map_info) +{ +#if defined(__linux__) && defined(_GNU_SOURCE) + if (map_info->buffer && MAP_FAILED != map_info->buffer) + munmap((void *)map_info->buffer, map_info->size*2); +#else + if (map_info->buffer) + { + shmdt(map_info->buffer); + shmdt(map_info->buffer + map_info->size); + } +#endif + map_info->buffer = 0; + map_info->size = 0; +} + +static int mp3dec_open_ring(mp3dec_map_info_t *map_info, size_t size) +{ + int memfd, page_size; +#if defined(__linux__) && defined(_GNU_SOURCE) + void *buffer; + int res; +#endif + memset(map_info, 0, sizeof(*map_info)); + +#ifdef _SC_PAGESIZE + page_size = sysconf(_SC_PAGESIZE); +#else + page_size = getpagesize(); +#endif + map_info->size = (size + page_size - 1)/page_size*page_size; + +#if defined(__linux__) && defined(_GNU_SOURCE) + memfd = memfd_create("mp3_ring", 0); + if (memfd < 0) + return MP3D_E_MEMORY; + +retry_ftruncate: + res = ftruncate(memfd, map_info->size); + if (res && (errno == EAGAIN || errno == EINTR)) + goto retry_ftruncate; + if (res) + goto error; + +retry_mmap: + map_info->buffer = (const uint8_t *)mmap(NULL, map_info->size*2, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap; + if (MAP_FAILED == map_info->buffer || !map_info->buffer) + goto error; +retry_mmap2: + buffer = mmap((void *)map_info->buffer, map_info->size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, memfd, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap2; + if (MAP_FAILED == map_info->buffer || buffer != (void *)map_info->buffer) + goto error; +retry_mmap3: + buffer = mmap((void *)map_info->buffer + map_info->size, map_info->size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, memfd, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap3; + if (MAP_FAILED == map_info->buffer || buffer != (void *)(map_info->buffer + map_info->size)) + goto error; + + close(memfd); + return 0; +error: + close(memfd); + mp3dec_close_ring(map_info); + return MP3D_E_MEMORY; +#else + memfd = shmget(IPC_PRIVATE, map_info->size, IPC_CREAT | 0700); + if (memfd < 0) + return MP3D_E_MEMORY; +retry_mmap: + map_info->buffer = (const uint8_t *)mmap(NULL, map_info->size*2, PROT_NONE, MAP_PRIVATE, -1, 0); + if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) + goto retry_mmap; + if (MAP_FAILED == map_info->buffer) + goto error; + if (map_info->buffer != shmat(memfd, map_info->buffer, 0)) + goto error; + if ((map_info->buffer + map_info->size) != shmat(memfd, map_info->buffer + map_info->size, 0)) + goto error; + if (shmctl(memfd, IPC_RMID, NULL) < 0) + return MP3D_E_MEMORY; + return 0; +error: + shmctl(memfd, IPC_RMID, NULL); + mp3dec_close_ring(map_info); + return MP3D_E_MEMORY; +#endif +} +#endif /*MINIMP3_ENABLE_RING*/ +#elif defined(_WIN32) +#include + +static void mp3dec_close_file(mp3dec_map_info_t *map_info) +{ + if (map_info->buffer) + UnmapViewOfFile(map_info->buffer); + map_info->buffer = 0; + map_info->size = 0; +} + +static int mp3dec_open_file_h(HANDLE file, mp3dec_map_info_t *map_info) +{ + memset(map_info, 0, sizeof(*map_info)); + + HANDLE mapping = NULL; + LARGE_INTEGER s; + s.LowPart = GetFileSize(file, (DWORD*)&s.HighPart); + if (s.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) + goto error; + map_info->size = s.QuadPart; + + mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL); + if (!mapping) + goto error; + map_info->buffer = (const uint8_t*)MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, s.QuadPart); + CloseHandle(mapping); + if (!map_info->buffer) + goto error; + + CloseHandle(file); + return 0; +error: + mp3dec_close_file(map_info); + CloseHandle(file); + return MP3D_E_IOERROR; +} + +static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info) +{ + if (!file_name) + return MP3D_E_PARAM; + HANDLE file = CreateFileA(file_name, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if (INVALID_HANDLE_VALUE == file) + return MP3D_E_IOERROR; + return mp3dec_open_file_h(file, map_info); +} + +static int mp3dec_open_file_w(const wchar_t *file_name, mp3dec_map_info_t *map_info) +{ + if (!file_name) + return MP3D_E_PARAM; + HANDLE file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); + if (INVALID_HANDLE_VALUE == file) + return MP3D_E_IOERROR; + return mp3dec_open_file_h(file, map_info); +} +#else +#include + +static void mp3dec_close_file(mp3dec_map_info_t *map_info) +{ + if (map_info->buffer) + free((void *)map_info->buffer); + map_info->buffer = 0; + map_info->size = 0; +} + +static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info) +{ + if (!file_name) + return MP3D_E_PARAM; + memset(map_info, 0, sizeof(*map_info)); + FILE *file = fopen(file_name, "rb"); + if (!file) + return MP3D_E_IOERROR; + int res = MP3D_E_IOERROR; + long size = -1; + if (fseek(file, 0, SEEK_END)) + goto error; + size = ftell(file); + if (size < 0) + goto error; + map_info->size = (size_t)size; + if (fseek(file, 0, SEEK_SET)) + goto error; + map_info->buffer = (uint8_t *)malloc(map_info->size); + if (!map_info->buffer) + { + res = MP3D_E_MEMORY; + goto error; + } + if (fread((void *)map_info->buffer, 1, map_info->size, file) != map_info->size) + goto error; + fclose(file); + return 0; +error: + mp3dec_close_file(map_info); + fclose(file); + return res; +} +#endif + +static int mp3dec_detect_mapinfo(mp3dec_map_info_t *map_info) +{ + int ret = mp3dec_detect_buf(map_info->buffer, map_info->size); + mp3dec_close_file(map_info); + return ret; +} + +static int mp3dec_load_mapinfo(mp3dec_t *dec, mp3dec_map_info_t *map_info, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + int ret = mp3dec_load_buf(dec, map_info->buffer, map_info->size, info, progress_cb, user_data); + mp3dec_close_file(map_info); + return ret; +} + +static int mp3dec_iterate_mapinfo(mp3dec_map_info_t *map_info, MP3D_ITERATE_CB callback, void *user_data) +{ + int ret = mp3dec_iterate_buf(map_info->buffer, map_info->size, callback, user_data); + mp3dec_close_file(map_info); + return ret; +} + +static int mp3dec_ex_open_mapinfo(mp3dec_ex_t *dec, int flags) +{ + int ret = mp3dec_ex_open_buf(dec, dec->file.buffer, dec->file.size, flags); + dec->is_file = 1; + if (ret) + mp3dec_ex_close(dec); + return ret; +} + +int mp3dec_detect(const char *file_name) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file(file_name, &map_info))) + return ret; + return mp3dec_detect_mapinfo(&map_info); +} + +int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file(file_name, &map_info))) + return ret; + return mp3dec_load_mapinfo(dec, &map_info, info, progress_cb, user_data); +} + +int mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file(file_name, &map_info))) + return ret; + return mp3dec_iterate_mapinfo(&map_info, callback, user_data); +} + +int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int flags) +{ + int ret; + if (!dec) + return MP3D_E_PARAM; + if ((ret = mp3dec_open_file(file_name, &dec->file))) + return ret; + return mp3dec_ex_open_mapinfo(dec, flags); +} + +void mp3dec_ex_close(mp3dec_ex_t *dec) +{ +#ifdef MINIMP3_HAVE_RING + if (dec->io) + mp3dec_close_ring(&dec->file); +#else + if (dec->io && dec->file.buffer) + free((void*)dec->file.buffer); +#endif + if (dec->is_file) + mp3dec_close_file(&dec->file); + if (dec->index.frames) + free(dec->index.frames); + memset(dec, 0, sizeof(*dec)); +} + +#ifdef _WIN32 +int mp3dec_detect_w(const wchar_t *file_name) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file_w(file_name, &map_info))) + return ret; + return mp3dec_detect_mapinfo(&map_info); +} + +int mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file_w(file_name, &map_info))) + return ret; + return mp3dec_load_mapinfo(dec, &map_info, info, progress_cb, user_data); +} + +int mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data) +{ + int ret; + mp3dec_map_info_t map_info; + if ((ret = mp3dec_open_file_w(file_name, &map_info))) + return ret; + return mp3dec_iterate_mapinfo(&map_info, callback, user_data); +} + +int mp3dec_ex_open_w(mp3dec_ex_t *dec, const wchar_t *file_name, int flags) +{ + int ret; + if ((ret = mp3dec_open_file_w(file_name, &dec->file))) + return ret; + return mp3dec_ex_open_mapinfo(dec, flags); +} +#endif +#else /* MINIMP3_NO_STDIO */ +void mp3dec_ex_close(mp3dec_ex_t *dec) +{ +#ifdef MINIMP3_HAVE_RING + if (dec->io) + mp3dec_close_ring(&dec->file); +#else + if (dec->io && dec->file.buffer) + free((void*)dec->file.buffer); +#endif + if (dec->index.frames) + free(dec->index.frames); + memset(dec, 0, sizeof(*dec)); +} +#endif + +#endif /*MINIMP3_IMPLEMENTATION*/ diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_wrapper.c b/engine/plugin/plugins/minimp3_adapter/minimp3_wrapper.c new file mode 100755 index 00000000..65d66493 --- /dev/null +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_wrapper.c @@ -0,0 +1,52 @@ +#define MINIMP3_IMPLEMENTATION +#define MAX_FRAME_SYNC_MATCHES 3 +#include "minimp3.h" +#include "minimp3_ex.h" +#undef MINIMP3_IMPLEMENTATION + +#include "minimp3_wrapper.h" + +void Minimp3WrapperMp3decInit(Minimp3WrapperMp3dec *dec) +{ + mp3dec_init(dec); +} + +int Minimp3WrapperMp3decDecodeFrame(Minimp3WrapperMp3dec *dec, const uint8_t *mp3, int mp3Bytes, Minimp3WrapperMp3dSample *pcm, Minimp3WrapperMp3decFrameInfo *info) +{ + return mp3dec_decode_frame(dec, mp3, mp3Bytes, pcm, info); +} + +int Minimp3WrapperMp3decDetectBuf(const uint8_t *buf, size_t bufSize) +{ + return mp3dec_detect_buf(buf, bufSize); +} + +int Minimp3WrapperMp3decDetectCb(Minimp3WrapperMp3decIO *io, uint8_t *buf, size_t bufSize) +{ + return mp3dec_detect_cb(io, buf, bufSize); +} + +int Minimp3WrapperMp3decIterateBuf(const uint8_t *buf, size_t bufSize, MINIMP3_WRAPPER_MP3D_ITERATE_CB callback, void *userData) +{ + return mp3dec_iterate_buf(buf, bufSize, callback, userData); +} + +int Minimp3WrapperMp3decIterateCb(Minimp3WrapperMp3decIO *io, uint8_t *buf, size_t bufSize, MINIMP3_WRAPPER_MP3D_ITERATE_CB callback, void *userData) +{ + return mp3dec_iterate_cb(io, buf, bufSize, callback, userData); +} + +Minimp3DemuxerOp minimp3DemuxerOp = +{ + .init = Minimp3WrapperMp3decInit, + .decoderFrame = Minimp3WrapperMp3decDecodeFrame, + .detecBuf = Minimp3WrapperMp3decDetectBuf, + .detecCb = Minimp3WrapperMp3decDetectCb, + .iterateBuf = Minimp3WrapperMp3decIterateBuf, + .iterateCb = Minimp3WrapperMp3decIterateCb +}; + +Minimp3DemuxerOp Minimp3GetOpt() +{ + return minimp3DemuxerOp; +} \ No newline at end of file diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_wrapper.h b/engine/plugin/plugins/minimp3_adapter/minimp3_wrapper.h new file mode 100755 index 00000000..4dbdc6f9 --- /dev/null +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_wrapper.h @@ -0,0 +1,51 @@ +#ifndef __MINIMP3_WRAPPER_H__ +#define __MINIMP3_WRAPPER_H__ + +#include "minimp3.h" +#include "minimp3_ex.h" + +typedef mp3dec_t Minimp3WrapperMp3dec; +typedef mp3d_sample_t Minimp3WrapperMp3dSample; +typedef mp3dec_frame_info_t Minimp3WrapperMp3decFrameInfo; +typedef mp3dec_io_t Minimp3WrapperMp3decIO; +typedef MP3D_ITERATE_CB MINIMP3_WRAPPER_MP3D_ITERATE_CB; + +#ifdef __cplusplus +extern "C" +{ +#endif + + typedef struct { + void (*init)(Minimp3WrapperMp3dec *dec); + + int (*decoderFrame)(Minimp3WrapperMp3dec *dec, const uint8_t *mp3, int mp3Bytes, Minimp3WrapperMp3dSample *pcm, Minimp3WrapperMp3decFrameInfo *info); + + int (*detecBuf)(const uint8_t *buf, size_t bufSize); + + int (*detecCb)(Minimp3WrapperMp3decIO *io, uint8_t *buf, size_t bufSize); + + int (*iterateBuf)(const uint8_t *buf, size_t bufSize, MINIMP3_WRAPPER_MP3D_ITERATE_CB callback, void *userData); + + int (*iterateCb)(Minimp3WrapperMp3decIO *io, uint8_t *buf, size_t bufSize, MINIMP3_WRAPPER_MP3D_ITERATE_CB callback, void *userData); + + } Minimp3DemuxerOp; + + void Minimp3WrapperMp3decInit(Minimp3WrapperMp3dec *dec); + + int Minimp3WrapperMp3decDecodeFrame(Minimp3WrapperMp3dec *dec, const uint8_t *mp3, int mp3Bytes, Minimp3WrapperMp3dSample *pcm, Minimp3WrapperMp3decFrameInfo *info); + + int Minimp3WrapperMp3decDetectBuf(const uint8_t *buf, size_t bufSize); + + int Minimp3WrapperMp3decDetectCb(Minimp3WrapperMp3decIO *io, uint8_t *buf, size_t bufSize); + + int Minimp3WrapperMp3decIterateBuf(const uint8_t *buf, size_t bufSize, MINIMP3_WRAPPER_MP3D_ITERATE_CB callback, void *userData); + + int Minimp3WrapperMp3decIterateCb(Minimp3WrapperMp3decIO *io, uint8_t *buf, size_t bufSize, MINIMP3_WRAPPER_MP3D_ITERATE_CB callback, void *userData); + + Minimp3DemuxerOp Minimp3GetOpt(); + +#ifdef __cplusplus +} +#endif + +#endif \ No newline at end of file -- Gitee From 2b05c674e101ee2cc77b3bbb08dc5ef6d165cc37 Mon Sep 17 00:00:00 2001 From: zhangtl Date: Thu, 28 Oct 2021 19:51:55 +0800 Subject: [PATCH 15/22] minimp3 plugin optimization Signed-off-by: zhangtl Change-Id: I5b2b74d3f4bb712f06f8948572a4a28e2b13bb97 --- .../plugin/plugins/minimp3_adapter/minimp3.h | 2 +- .../minimp3_decoder_plugin.cpp | 80 ++-- .../minimp3_adapter/minimp3_decoder_plugin.h | 7 +- .../minimp3_demuxer_plugin.cpp | 398 ++++++++++-------- .../minimp3_adapter/minimp3_demuxer_plugin.h | 19 +- .../plugins/minimp3_adapter/minimp3_ex.h | 1 + 6 files changed, 268 insertions(+), 239 deletions(-) diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3.h b/engine/plugin/plugins/minimp3_adapter/minimp3.h index e4f2b740..f2666f82 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3.h +++ b/engine/plugin/plugins/minimp3_adapter/minimp3.h @@ -12,7 +12,7 @@ typedef struct { - int frame_bytes, frame_offset, channels, hz, layer, bitrate_kbps; + int frame_bytes, frame_offset, channels, hz, layer, bitrate_kbps, samples_per_frame; } mp3dec_frame_info_t; typedef struct diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp b/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp index d8a42c24..c6dc4b99 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp @@ -15,6 +15,7 @@ namespace OHOS { namespace Media { namespace Plugin { namespace { + constexpr uint32_t mp3MaxSamplePerFrame = 2304; //(1152 * 2) Status RegisterDecoderPlugins(const std::shared_ptr& reg); const uint32_t BUFFER_ITEM_CNT = 6; void UpdatePluginDefinition(CodecPluginDef& definition); @@ -25,7 +26,7 @@ Minimp3DecoderPlugin::Minimp3DecoderPlugin(std::string name) mp3Parameter_(), outBufferQ_("adecPluginQueue", BUFFER_ITEM_CNT) { - memset(&mp3DecoderAttr_, 0, sizeof(AudioDecoderMp3Attr)); + memset_s(&mp3DecoderAttr_, sizeof(mp3DecoderAttr_), 0x00, sizeof(AudioDecoderMp3Attr)); MEDIA_LOG_I("Minimp3DecoderPlugin, plugin name: %s", pluginName_.c_str()); } @@ -37,7 +38,7 @@ Minimp3DecoderPlugin::~Minimp3DecoderPlugin() Status Minimp3DecoderPlugin::Init() { minimp3DecoderImpl_ = Minimp3GetOpt(); - AudioDecoderMp3Open(NULL); + AudioDecoderMp3Open(nullptr); state_ = State::INITIALIZED; mp3Parameter_[Tag::REQUIRED_OUT_BUFFER_CNT] = (uint32_t)BUFFER_ITEM_CNT; return Status::OK; @@ -108,7 +109,7 @@ bool Minimp3DecoderPlugin::IsParameterSupported(Tag tag) std::shared_ptr Minimp3DecoderPlugin::GetAllocator() { - return NULL; + return nullptr; } Status Minimp3DecoderPlugin::SetCallback(const std::shared_ptr& cb) @@ -138,13 +139,13 @@ Status Minimp3DecoderPlugin::SendDataFromBufferLocked(const std::shared_ptrflag & BUFFER_FLAG_EOS) != 0) { eos = true; outBuffer->GetMemory()->Reset(); - outBuffer->flag = BUFFER_FLAG_EOS; + outBuffer->flag |= BUFFER_FLAG_EOS; } else { if (outBuffer == nullptr || outBuffer->IsEmpty()) { return Status::OK; } - int ret = AudioDecoderMp3Process(inputBuffer, outBuffer); - if (ret != 0) { + Status ret = AudioDecoderMp3Process(inputBuffer, outBuffer); + if (ret != Status::OK) { outBufferQ_.Push(outBuffer); } else { NotifyOutputBufferDone(outBuffer); @@ -174,7 +175,7 @@ Status Minimp3DecoderPlugin::SendDataFromBuffer(const std::shared_ptr& i Status Minimp3DecoderPlugin::QueueInputBuffer(const std::shared_ptr& inputBuffer, int32_t timeoutMs) { - MEDIA_LOG_D("queue input buffer"); + MEDIA_LOG_I("queue input buffer"); (void)timeoutMs; Status status = SendDataFromBuffer(inputBuffer); if (status != Status::OK) { @@ -212,58 +213,59 @@ void Minimp3DecoderPlugin::NotifyOutputBufferDone(const std::shared_ptr& void Minimp3DecoderPlugin::AudioDecoderMp3Open(void *userData) { - Mp3DecoderSample *pcmData = (Mp3DecoderSample*)calloc(MP3_MAX_SAMPLES_PER_FRAME, sizeof(Mp3DecoderSample)); + Mp3DecoderSample *pcmData = (Mp3DecoderSample*)calloc(mp3MaxSamplePerFrame, sizeof(Mp3DecoderSample)); if (pcmData == nullptr) { - goto exit; + return; } mp3DecoderAttr_.userData = userData; mp3DecoderAttr_.pcm = pcmData; Minimp3WrapperMp3decInit(&mp3DecoderAttr_.mp3DecoderHandle); - -exit: - return; } int Minimp3DecoderPlugin::AudioDecoderMp3Close() { if (mp3DecoderAttr_.pcm) { free(mp3DecoderAttr_.pcm); - mp3DecoderAttr_.pcm = NULL; + mp3DecoderAttr_.pcm = nullptr; } return 0; } -int Minimp3DecoderPlugin::AudioDecoderMp3Process(std::shared_ptr inBuffer, std::shared_ptr outBuffer) +Status Minimp3DecoderPlugin::AudioDecoderMp3Process(std::shared_ptr inBuffer, std::shared_ptr outBuffer) { auto inData = inBuffer->GetMemory(); auto outData = outBuffer->GetMemory(); - int ret = -1; Minimp3WrapperMp3decFrameInfo frameInfo; - int sampleCount = minimp3DecoderImpl_.decoderFrame(&mp3DecoderAttr_.mp3DecoderHandle, inData->GetReadOnlyData(), inData->GetSize(), mp3DecoderAttr_.pcm, &frameInfo); + uint32_t samplesPerFrame; + uint32_t channels; + if (mp3Parameter_.find(Tag::AUDIO_CHANNELS) != mp3Parameter_.end()) { + channels = AnyCast((mp3Parameter_.find(Tag::AUDIO_CHANNELS))->second); + MEDIA_LOG_D("channels = %d", channels); + } + + if (mp3Parameter_.find(Tag::AUDIO_SAMPLE_PER_FRAME) != mp3Parameter_.end()) { + samplesPerFrame = AnyCast(mp3Parameter_.find(Tag::AUDIO_SAMPLE_PER_FRAME)->second); + } + if (samplesPerFrame != 384 && samplesPerFrame != 576 && samplesPerFrame != 1152) { + return Status::ERROR_INVALID_PARAMETER; + } + MEDIA_LOG_D("channels = %d samplesPerFrame = %d", channels, samplesPerFrame); + uint32_t probePcmLength = samplesPerFrame * sizeof(Mp3DecoderSample) * channels; + if (outData->GetCapacity() < probePcmLength) { + return Status::ERROR_UNKNOWN; + } + int16_t *pcmPtr = (int16_t *)outData->GetWritableData(probePcmLength, 0); + int sampleCount = minimp3DecoderImpl_.decoderFrame(&mp3DecoderAttr_.mp3DecoderHandle, inData->GetReadOnlyData(), inData->GetSize(), pcmPtr, &frameInfo); if (sampleCount > 0) { if (frameInfo.frame_bytes) { - ret = 0; - uint32_t pcmLength = sampleCount * sizeof(Mp3DecoderSample) * frameInfo.channels; - if (pcmLength == 0 || pcmLength >= 16 * 1024) { - return -1; - } - - if (outData->GetCapacity() >= pcmLength) { - outData->Write((uint8_t *)mp3DecoderAttr_.pcm, pcmLength); - MEDIA_LOG_I("pcmLength = %d", pcmLength); - } else { - MEDIA_LOG_W("not enough buffer memory"); - return -1; - } + return Status::OK; } } else if (sampleCount == 0) { - ret = 2; + return Status::ERROR_NOT_ENOUGH_DATA; } else { - ret = -1; + return Status::ERROR_UNKNOWN; } - - return ret; } namespace { @@ -274,9 +276,9 @@ namespace { Status RegisterDecoderPlugins(const std::shared_ptr& reg) { - MEDIA_LOG_D("RegisterPlugins called."); + MEDIA_LOG_I("RegisterPlugins called."); if (!reg) { - MEDIA_LOG_E("RegisterPlugins failed due to null pointer for reg."); + MEDIA_LOG_E("RegisterPlugins failed due to nullptr pointer for reg."); return Status::ERROR_INVALID_PARAMETER; } @@ -296,14 +298,12 @@ namespace { Capability cap("audio/unknown"); cap.SetMime(OHOS::Media::MEDIA_MIME_AUDIO_MPEG) .AppendFixedKey(Capability::Key::AUDIO_MPEG_VERSION, 1) - .AppendIntervalKey(Capability::Key::AUDIO_MPEG_LAYER, 3, 3); // 3 + .AppendIntervalKey(Capability::Key::AUDIO_MPEG_LAYER, 1, 3); // 3 - MEDIA_LOG_W("UpdatePluginDefinition\n"); - DiscreteCapability values = {8000, 16000, 22050, 44100, 48000}; + DiscreteCapability values = {8000, 16000, 22050, 44100, 48000, 32000}; cap.AppendDiscreteKeys(Capability::Key::AUDIO_SAMPLE_RATE, values); - DiscreteCapability channelLayoutValues; - channelLayoutValues.push_back(AudioChannelLayout::MONO); + DiscreteCapability channelLayoutValues = {AudioChannelLayout::MONO, AudioChannelLayout::STEREO}; cap.AppendDiscreteKeys(Capability::Key::AUDIO_CHANNEL_LAYOUT, channelLayoutValues); DiscreteCapability sampleFmtValues = {AudioSampleFormat::S32, AudioSampleFormat::S16}; diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.h b/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.h index 357b2904..d05443e9 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.h +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.h @@ -1,4 +1,3 @@ -#if 1 #ifndef HISTREAMER_MINIMP3_DECODER_PLUGIN_H #define HISTREAMER_MINIMP3_DECODER_PLUGIN_H @@ -93,7 +92,7 @@ private: int AudioDecoderMp3Close(); - int AudioDecoderMp3Process(std::shared_ptr inBuffer, std::shared_ptr outBuffer); + Status AudioDecoderMp3Process(std::shared_ptr inBuffer, std::shared_ptr outBuffer); int AudioDecoderMp3FreePacket(uint8_t *packet); @@ -108,6 +107,4 @@ private: } // namespace Media } // namespace OHOS -#endif // HISTREAMER_MINIMP3_DECODER_PLUGIN_H - -#endif +#endif // HISTREAMER_MINIMP3_DECODER_PLUGIN_H \ No newline at end of file diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp index a7b1d83d..faba8713 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp @@ -1,9 +1,5 @@ #define LOG_TAG "Minimp3DemuxerPlugin" -#define MP3_MAX_SAMPLES_PER_FRAME (1152 * 2) -#define MP3_SEEK_DISCARD_ITEMS (2) -#define ID3_DETECT_SIZE 10 - #include "minimp3_demuxer_plugin.h" #include #include @@ -19,22 +15,36 @@ namespace OHOS { namespace Media { namespace Plugin { namespace { - +constexpr uint32_t maxSamplesPerFrame = 1152 * 2; +constexpr uint32_t Mp3SeekDiscardItems = 2; +constexpr uint32_t Id3DetectSize = 10; +constexpr uint32_t probeReadLength = 16 * 1024; +AudioDemuxerMp3Attr mp3ProbeAttr; +AudioDemuxerRst mp3ProbeRst; +std::vector infoLayer = {1, 2, 3}; +std::vector infoSampleRate = {8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000}; +std::vector infoBitrateKbps = {8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 288, 320, 352, 384, 416, 448}; +size_t AudioDecmuxerMp3Id3v2SizeCalculate(const uint8_t *buf); +bool AudioDemuxerMp3HasId3v2(const uint8_t *buf); +size_t AudioDemuxerMp3GetId3v2Size(const uint8_t *buf, size_t bufSize); +int AudioDemuxerMp3ProbeDecodeCheck(Mp3DemuxerFrameInfo *info); +int AudioDemuxerMp3IterateCallbackForProbe(void *userData, const uint8_t *frame, int frameSize, int freeFormatBytes, size_t bufSize, + uint64_t offset, Mp3DemuxerFrameInfo *info); +Status AudioDemuxerMp3Probe(AudioDemuxerMp3Attr *mp3DemuxerAttr, uint8_t *inputBuffer, uint32_t inputLength, AudioDemuxerRst *mp3DemuxerRst); int Sniff(const std::string& name, std::shared_ptr dataSource); -Status RegisterPlugins(const std::shared_ptr& reg); +Status RegisterPlugin(const std::shared_ptr& reg); void UpdatePluginDefinition(CodecPluginDef& definition); - } Minimp3DemuxerPlugin::Minimp3DemuxerPlugin(std::string name) : DemuxerPlugin(std::move(name)), ioContext_(), - mediaIOBuf_(nullptr), - mediaIOSize_(12 * 1024), - readFrameBuf_(nullptr) + mediaIOSize_(12 * 1024) { - memset(&mp3DemuxerAttr_, 0, sizeof(AudioDemuxerMp3Attr)); - memset(&mp3DemuxerRst_, 0, sizeof(AudioDemuxerRst)); + memset_s(&mp3DemuxerAttr_, sizeof(mp3DemuxerAttr_), 0x00, sizeof(AudioDemuxerMp3Attr)); + memset_s(&mp3DemuxerRst_, sizeof(mp3DemuxerRst_), 0x00, sizeof(AudioDemuxerRst)); + memset_s(&mp3ProbeAttr, sizeof(mp3ProbeAttr), 0x00, sizeof(AudioDemuxerMp3Attr)); + memset_s(&mp3ProbeRst, sizeof(mp3ProbeRst), 0x00, sizeof(AudioDemuxerRst)); MEDIA_LOG_I("Minimp3DemuxerPlugin, plugin name: %s", pluginName_.c_str()); } @@ -51,55 +61,58 @@ Status Minimp3DemuxerPlugin::SetDataSource(const std::shared_ptr& so Status Minimp3DemuxerPlugin::GetMediaInfo(MediaInfo& mediaInfo) { - int status = -1; + Status status = Status::ERROR_UNKNOWN; auto buffer = std::make_shared(); auto bufData = buffer->AllocMemory(nullptr, mediaIOSize_); int processLoop = 1; + uint8_t *inputDataPtr = nullptr; while(processLoop) { auto result = ioContext_.dataSource->ReadAt(ioContext_.offset, buffer, static_cast(mediaIOSize_)); - int realReadLen = bufData->Read(mediaIOBuf_, mediaIOSize_); - status = AudioDemuxerMp3Prepare(mediaIOBuf_, realReadLen); + inputDataPtr = (uint8_t *)bufData->GetReadOnlyData(); + status = AudioDemuxerMp3Prepare(&mp3DemuxerAttr_, inputDataPtr, bufData->GetSize(), &mp3DemuxerRst_); switch(status) { - case AUDIO_DEMUXER_PREPARE_NEED_MORE_DATA: + case Status::ERROR_NOT_ENOUGH_DATA: ioContext_.offset = mp3DemuxerRst_.usedInputLength; processLoop = 1; break; - case AUDIO_DEMUXER_SUCCESS: + case Status::OK: ioContext_.offset = mp3DemuxerRst_.usedInputLength; mediaInfo.tracks.resize(1); - mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_RATE, (uint32_t)mp3DemuxerRst_.frameSampleRate} ); - mediaInfo.tracks[0].insert({Tag::MEDIA_BITRATE, (uint32_t)mp3DemuxerRst_.frameBitrateKbps} ); - mediaInfo.tracks[0].insert({Tag::AUDIO_CHANNELS, (uint32_t)mp3DemuxerRst_.frameChannels} ); - mediaInfo.tracks[0].insert({Tag::STREAM_INDEX, (uint32_t)0} ); - mediaInfo.tracks[0].insert({Tag::MIME, std::string(MEDIA_MIME_AUDIO_MPEG)} ); - mediaInfo.tracks[0].insert({Tag::AUDIO_MPEG_VERSION, static_cast(1)} ); - mediaInfo.tracks[0].insert({Tag::AUDIO_MPEG_LAYER, static_cast(3)} ); // 3 - mediaInfo.tracks[0].insert({Tag::AUDIO_CHANNEL_LAYOUT, AudioChannelLayout::MONO} ); - mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_FORMAT, AudioSampleFormat::S16} ); - mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_PRE_FRAME, static_cast(1152)} ); + if (mp3DemuxerRst_.frameChannels == 1) { + mediaInfo.tracks[0].insert({Tag::AUDIO_CHANNEL_LAYOUT, AudioChannelLayout::MONO} ); + } else { + mediaInfo.tracks[0].insert({Tag::AUDIO_CHANNEL_LAYOUT, AudioChannelLayout::STEREO} ); + } + mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_RATE, (uint32_t)mp3DemuxerRst_.frameSampleRate} ); + mediaInfo.tracks[0].insert({Tag::MEDIA_BITRATE, (uint32_t)mp3DemuxerRst_.frameBitrateKbps} ); + mediaInfo.tracks[0].insert({Tag::AUDIO_CHANNELS, (uint32_t)mp3DemuxerRst_.frameChannels} ); + mediaInfo.tracks[0].insert({Tag::STREAM_INDEX, (uint32_t)0} ); + mediaInfo.tracks[0].insert({Tag::MIME, std::string(MEDIA_MIME_AUDIO_MPEG)} ); + mediaInfo.tracks[0].insert({Tag::AUDIO_MPEG_VERSION, static_cast(1)} ); + mediaInfo.tracks[0].insert({Tag::AUDIO_MPEG_LAYER, (uint32_t)(mp3DemuxerRst_.audioLayer)} ); // 3 + mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_FORMAT, AudioSampleFormat::S16} ); + mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_PER_FRAME, (uint32_t)(mp3DemuxerRst_.samplesPerFrame)}); processLoop = 0; break; - case AUDIO_DEMUXER_ERROR: - // MEDIA_LOG_I("AUDIO_DEMUXER_ERROR"); - case AUDIO_DEMUXER_PREPARE_UNMATCHED_FORMAT: + case Status::ERROR_UNSUPPORTED_FORMAT: + return Status::ERROR_UNSUPPORTED_FORMAT; + case Status::ERROR_UNKNOWN: default: processLoop = 0; - free(mediaIOBuf_); - mediaIOBuf_ = nullptr; MEDIA_LOG_I("AUDIO_DEMUXER_PREPARE_UNMATCHED_FORMAT %d", status); return Status::ERROR_UNKNOWN; } } - free(mediaIOBuf_); - mediaIOBuf_ = nullptr; + return Status::OK; } -Status Minimp3DemuxerPlugin::ReadFrame(Buffer& info, int32_t timeOutMs) +Status Minimp3DemuxerPlugin::ReadFrame(Buffer& OutBuffer, int32_t timeOutMs) { int status = -1; + std::shared_ptr mp3FrameData; auto buffer = std::make_shared(); auto bufData = buffer->AllocMemory(nullptr, mediaIOSize_); auto result = ioContext_.dataSource->ReadAt(ioContext_.offset, buffer, static_cast(mediaIOSize_)); @@ -108,9 +121,15 @@ Status Minimp3DemuxerPlugin::ReadFrame(Buffer& info, int32_t timeOutMs) ioContext_.offset = 0; return result; } - int realReadLen = bufData->Read(readFrameBuf_, mediaIOSize_); - status = AudioDemuxerMp3Process(readFrameBuf_, realReadLen); - auto mp3FrameData = info.AllocMemory(nullptr, mp3DemuxerRst_.frameLength); + + uint8_t *inputPtr = (uint8_t *)bufData->GetReadOnlyData(); + status = AudioDemuxerMp3Process(inputPtr, bufData->GetSize()); + + if (OutBuffer.IsEmpty()) { + mp3FrameData = OutBuffer.AllocMemory(nullptr, mp3DemuxerRst_.frameLength); + } else { + mp3FrameData = OutBuffer.GetMemory(); + } switch(status) { case AUDIO_DEMUXER_SUCCESS: ioContext_.offset = mp3DemuxerRst_.usedInputLength; @@ -128,13 +147,14 @@ Status Minimp3DemuxerPlugin::ReadFrame(Buffer& info, int32_t timeOutMs) } return Status::ERROR_UNKNOWN; } + return Status::OK; } Status Minimp3DemuxerPlugin::SeekTo(int32_t trackId, int64_t timeStampUs, SeekMode mode) { uint64_t pos = 0; - uint32_t targetTtimeS = (uint32_t)(timeStampUs / 1000); + uint32_t targetTtimeS = (uint32_t)(timeStampUs / (1000 * 1000)); AudioDemuxerMp3GetSeekPosition(targetTtimeS, &pos); mp3DemuxerRst_.usedInputLength = pos; @@ -143,44 +163,14 @@ Status Minimp3DemuxerPlugin::SeekTo(int32_t trackId, int64_t timeStampUs, SeekMo Status Minimp3DemuxerPlugin::Init() { - mediaIOBuf_ = (uint8_t*)malloc(mediaIOSize_); - if (mediaIOBuf_ == nullptr) { - goto error_exit; - } - readFrameBuf_ = (uint8_t*)malloc(mediaIOSize_); - if (readFrameBuf_ == nullptr) { - goto error_exit; - } - minimp3DemuxerImpl_ = Minimp3GetOpt(); AudioDemuxerMp3Open(nullptr); - return Status::OK; - -error_exit: - if (mediaIOBuf_) { - free(mediaIOBuf_); - mediaIOBuf_ = nullptr; - } - if (readFrameBuf_) { - free(readFrameBuf_); - readFrameBuf_ = nullptr; - } - return Status::ERROR_NO_MEMORY; + return Status::OK; } Status Minimp3DemuxerPlugin::Deinit() { - if (mediaIOBuf_) { - free(mediaIOBuf_); - mediaIOBuf_ = NULL; - } - - if (readFrameBuf_) { - free(readFrameBuf_); - readFrameBuf_ = NULL; - } - return Status::OK; } @@ -251,7 +241,7 @@ Status Minimp3DemuxerPlugin::GetSelectedTracks(std::vector& trackIds) void Minimp3DemuxerPlugin::AudioDemuxerMp3IgnoreTailZero(uint8_t *data, uint32_t *dataLen) { - if ((data == NULL) || (dataLen == NULL) || (*dataLen == 0)) { + if ((data == nullptr) || (dataLen == nullptr) || (*dataLen == 0)) { return; } @@ -284,7 +274,7 @@ int Minimp3DemuxerPlugin::AudioDemuxerMp3IterateCallback(void *userData, const u if (frameSize == 0) { rst->usedInputLength = 0; - rst->frameBuffer = NULL; + rst->frameBuffer = nullptr; rst->frameLength = 0; return 0; } @@ -308,46 +298,10 @@ int Minimp3DemuxerPlugin::AudioDemuxerMp3IterateCallback(void *userData, const u return 1; } -int Minimp3DemuxerPlugin::AudioDemuxerMp3ProbeDecodeCheck(Mp3DemuxerFrameInfo *info) -{ - if (!info) { - return -1; - } - - if (!(info->layer == 1 || info->layer == 2 || info->layer == 3)) { - return -1; - } - - if (!(info->bitrate_kbps == 8 || info->bitrate_kbps == 16 || info->bitrate_kbps == 24 || info->bitrate_kbps == 32 || - info->bitrate_kbps == 40 || info->bitrate_kbps == 48 || info->bitrate_kbps == 56 || info->bitrate_kbps == 64 || - info->bitrate_kbps == 80 || info->bitrate_kbps == 96 || info->bitrate_kbps == 112 || info->bitrate_kbps == 128 || - info->bitrate_kbps == 144 || info->bitrate_kbps == 160 || info->bitrate_kbps == 176 || info->bitrate_kbps == 192 || - info->bitrate_kbps == 224 || info->bitrate_kbps == 256 || info->bitrate_kbps == 288 || info->bitrate_kbps == 320 || - info->bitrate_kbps == 352 || info->bitrate_kbps == 384 || info->bitrate_kbps == 416 || info->bitrate_kbps == 448)) { - return -1; - } - - if (!(info->hz == 8000 || info->hz == 11025 || info->hz == 12000 || - info->hz == 16000 || info->hz == 22050 || info->hz == 24000 || - info->hz == 32000 || info->hz == 44100 || info->hz == 48000)) { - return -1; - } - return 0; -} - int Minimp3DemuxerPlugin::AudioDemuxerMp3IterateCallbackForPrepare(void *userData, const uint8_t *frame, int frameSize, int freeFormatBytes, size_t bufSize, uint64_t offset, Mp3DemuxerFrameInfo *info) { - int sampleCount = 0; - Mp3DemuxerFrameInfo frameInfo; - - AudioDemuxerMp3Attr *mp3Demuxer = (AudioDemuxerMp3Attr *) userData; - AudioDemuxerRst *rst = mp3Demuxer->rst; - rst->frameBitrateKbps = info->bitrate_kbps; - rst->frameChannels = info->channels; - rst->frameSampleRate = info->hz; - - return 1; + return AudioDemuxerMp3IterateCallbackForProbe(userData, frame, frameSize, freeFormatBytes, bufSize, offset, info); } void Minimp3DemuxerPlugin::AudioDemuxerMp3Open(AudioDemuxerUserArg *userArg) @@ -360,79 +314,17 @@ void Minimp3DemuxerPlugin::AudioDemuxerMp3Open(AudioDemuxerUserArg *userArg) int Minimp3DemuxerPlugin::AudioDemuxerMp3Close() { - if (mp3DemuxerAttr_.rst) { - free(mp3DemuxerAttr_.rst); - } return 0; } -size_t Minimp3DemuxerPlugin::AudioDemuxerMp3GetId3v2Size(const uint8_t *buf, size_t bufSize) +Status Minimp3DemuxerPlugin::AudioDemuxerMp3Prepare(AudioDemuxerMp3Attr *mp3DemuxerAttr, uint8_t *buf, uint32_t len, AudioDemuxerRst *mp3DemuxerRst) { - if (bufSize >= ID3_DETECT_SIZE && !memcmp(buf, "ID3", 3) && !((buf[5] & 15) || (buf[6] & 0x80) || (buf[7] & 0x80) || (buf[8] & 0x80) || (buf[9] & 0x80))) { - size_t id3v2Size = (((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f)) + 10; - if ((buf[5] & 16)) { - id3v2Size += 10; - } - return id3v2Size; - } - return 0; -} - -int Minimp3DemuxerPlugin::AudioDemuxerMp3Prepare(uint8_t *buf, uint32_t len) -{ - if ((buf == NULL) || (len <= 0)) { - MEDIA_LOG_I("%s arg error", __func__); - return -1; - } - int ret; - - if (mp3DemuxerAttr_.id3v2SkipFlag == 0) { - if (mp3DemuxerAttr_.id3v2Offset == 0) { - if (len < ID3_DETECT_SIZE) { - mp3DemuxerRst_.usedInputLength = 0; - return AUDIO_DEMUXER_PREPARE_NEED_MORE_DATA; - } else { - mp3DemuxerAttr_.id3v2Size = AudioDemuxerMp3GetId3v2Size(buf, len); - mp3DemuxerAttr_.id3v2Offset = mp3DemuxerAttr_.id3v2Size; - } - } - - if (mp3DemuxerAttr_.id3v2Offset) { - MEDIA_LOG_I("mp3 id3v2Offset = %d, input data len %d", mp3DemuxerAttr_.id3v2Offset, len); - if (len >= mp3DemuxerAttr_.id3v2Offset) { - mp3DemuxerRst_.usedInputLength = mp3DemuxerAttr_.id3v2Offset; - mp3DemuxerAttr_.id3v2SkipFlag = 1; - len -= mp3DemuxerAttr_.id3v2Offset; - buf += mp3DemuxerAttr_.id3v2Offset; - mp3DemuxerAttr_.id3v2Offset = 0; - } else { - mp3DemuxerRst_.usedInputLength = len; - mp3DemuxerAttr_.id3v2Offset = mp3DemuxerAttr_.id3v2Offset - len; - return AUDIO_DEMUXER_PREPARE_NEED_MORE_DATA; - } - } - } - mp3DemuxerAttr_.rst = &mp3DemuxerRst_; - mp3DemuxerAttr_.internalRemainLen = len; - ret = minimp3DemuxerImpl_.iterateBuf(buf, len, AudioDemuxerMp3IterateCallbackForPrepare, &mp3DemuxerAttr_); - if (ret != 1) { - if (mp3DemuxerAttr_.id3v2SkipFlag) { - return AUDIO_DEMUXER_PREPARE_NEED_MORE_DATA; - } - return AUDIO_DEMUXER_PREPARE_UNMATCHED_FORMAT; - } - - mp3DemuxerAttr_.bitRate = mp3DemuxerRst_.frameBitrateKbps; - mp3DemuxerAttr_.sampleRate = mp3DemuxerRst_.frameSampleRate; - mp3DemuxerAttr_.channelNum = mp3DemuxerRst_.frameChannels; - MEDIA_LOG_I("mp3 file: sample_rate %d, channels %d, bitrate %d kbps", mp3DemuxerRst_.frameSampleRate, mp3DemuxerRst_.frameChannels, mp3DemuxerRst_.frameBitrateKbps); - MEDIA_LOG_I("mp3 file: file_size = %d, id3v2_size = %d", mp3DemuxerAttr_.fileSize, mp3DemuxerAttr_.id3v2Size); - return AUDIO_DEMUXER_SUCCESS; + return AudioDemuxerMp3Probe(mp3DemuxerAttr, buf, len, mp3DemuxerRst); } int Minimp3DemuxerPlugin::AudioDemuxerMp3Process(uint8_t *buf, uint32_t len) { - if ((buf == NULL) || (len <= 0)) { + if ((buf == nullptr) || (len <= 0)) { MEDIA_LOG_I("%s arg error", __func__); return AUDIO_DEMUXER_ERROR; } @@ -443,8 +335,8 @@ int Minimp3DemuxerPlugin::AudioDemuxerMp3Process(uint8_t *buf, uint32_t len) mp3DemuxerAttr_.internalRemainLen = processLen; ret = minimp3DemuxerImpl_.iterateBuf(buf, processLen, AudioDemuxerMp3IterateCallback, &mp3DemuxerAttr_); - if (mp3DemuxerAttr_.mp3SeekFlag == 1 && mp3DemuxerAttr_.discardItemCount < MP3_SEEK_DISCARD_ITEMS) { - memset(mp3DemuxerRst_.frameBuffer, 0, mp3DemuxerRst_.frameLength); + if (mp3DemuxerAttr_.mp3SeekFlag == 1 && mp3DemuxerAttr_.discardItemCount < Mp3SeekDiscardItems) { + memset_s(mp3DemuxerRst_.frameBuffer, sizeof(mp3DemuxerRst_.frameBuffer), 0x00, mp3DemuxerRst_.frameLength); mp3DemuxerAttr_.discardItemCount++; } else { mp3DemuxerAttr_.discardItemCount = 0; @@ -475,7 +367,7 @@ int Minimp3DemuxerPlugin::AudioDemuxerMp3Seek( uint32_t pos, uint8_t *buf, uint3 int Minimp3DemuxerPlugin::AudioDemuxerMp3GetSeekPosition(uint32_t targetTtimeS, uint64_t *pos) { if (!pos) { - MEDIA_LOG_I("pos NULL error"); + MEDIA_LOG_I("pos nullptr error"); return AUDIO_DEMUXER_ERROR; } uint32_t targetPos = targetTtimeS * mp3DemuxerAttr_.bitRate * 1000 / 8 + mp3DemuxerAttr_.id3v2Size; @@ -486,16 +378,158 @@ int Minimp3DemuxerPlugin::AudioDemuxerMp3GetSeekPosition(uint32_t targetTtimeS, namespace { + size_t AudioDecmuxerMp3Id3v2SizeCalculate(const uint8_t *buf) + { + return (((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f)) + 10; + } + + bool AudioDemuxerMp3HasId3v2(const uint8_t *buf) + { + return !memcmp(buf, "ID3", 3) && !((buf[5] & 15) || (buf[6] & 0x80) || (buf[7] & 0x80) || (buf[8] & 0x80) || (buf[9] & 0x80)); + } + + size_t AudioDemuxerMp3GetId3v2Size(const uint8_t *buf, size_t bufSize) + { + if (bufSize >= Id3DetectSize && AudioDemuxerMp3HasId3v2(buf)) { + size_t id3v2Size = AudioDecmuxerMp3Id3v2SizeCalculate(buf); + if ((buf[5] & 16)) { + id3v2Size += 10; + } + return id3v2Size; + } + return 0; + } + + int AudioDemuxerMp3ProbeDecodeCheck(Mp3DemuxerFrameInfo *info) + { + if (!info) { + return -1; + } + + std::vector::iterator it; + it = find (infoLayer.begin(), infoLayer.end(), info->layer); + if (it == infoLayer.end()) { + return -1; + } + + it = find (infoSampleRate.begin(), infoSampleRate.end(), info->hz); + if (it == infoSampleRate.end()) { + return -1; + } + + it = find (infoBitrateKbps.begin(), infoBitrateKbps.end(), info->bitrate_kbps); + if (it == infoBitrateKbps.end()) { + return -1; + } + + return 0; + } + + int AudioDemuxerMp3IterateCallbackForProbe(void *userData, const uint8_t *frame, int frameSize, int freeFormatBytes, size_t bufSize, + uint64_t offset, Mp3DemuxerFrameInfo *info) + { + int sampleCount; + Minimp3WrapperMp3decFrameInfo frameInfo; + AudioDemuxerMp3Attr *mp3Demuxer = (AudioDemuxerMp3Attr *) userData; + AudioDemuxerRst *rst = mp3Demuxer->rst; + rst->frameBitrateKbps = info->bitrate_kbps; + rst->frameChannels = info->channels; + rst->frameSampleRate = info->hz; + rst->audioLayer = info->layer; + rst->samplesPerFrame = info->samples_per_frame; + sampleCount = Minimp3WrapperMp3decDecodeFrame(&mp3Demuxer->mp3DemuxerHandle, frame, frameSize, mp3Demuxer->probePcmBuf, &frameInfo); + if (sampleCount <= 0 && 0 != AudioDemuxerMp3ProbeDecodeCheck(info)) { + return -1; + } + + return 1; + } + + Status AudioDemuxerMp3Probe(AudioDemuxerMp3Attr *mp3DemuxerAttr, uint8_t *inputBuffer, uint32_t inputLength, AudioDemuxerRst *mp3DemuxerRst) + { + if ((inputBuffer == nullptr) || (inputLength <= 0)) { + MEDIA_LOG_I("%s arg error", __func__); + return Status::ERROR_INVALID_PARAMETER; + } + int ret; + + if (mp3DemuxerAttr->id3v2SkipFlag == 0) { + if (mp3DemuxerAttr->id3v2Offset == 0) { + if (inputLength < Id3DetectSize) { + mp3DemuxerRst->usedInputLength = 0; + return Status::ERROR_NOT_ENOUGH_DATA; + } else { + mp3DemuxerAttr->id3v2Size = AudioDemuxerMp3GetId3v2Size(inputBuffer, inputLength); + mp3DemuxerAttr->id3v2Offset = mp3DemuxerAttr->id3v2Size; + } + } + + if (mp3DemuxerAttr->id3v2Offset) { + MEDIA_LOG_D("mp3 id3v2Offset = %d, input data inputLength %d", mp3DemuxerAttr->id3v2Offset, inputLength); + if (inputLength >= mp3DemuxerAttr->id3v2Offset) { + mp3DemuxerRst->usedInputLength = mp3DemuxerAttr->id3v2Offset; + mp3DemuxerAttr->id3v2SkipFlag = 1; + inputLength -= mp3DemuxerAttr->id3v2Offset; + inputBuffer += mp3DemuxerAttr->id3v2Offset; + mp3DemuxerAttr->id3v2Offset = 0; + } else { + mp3DemuxerRst->usedInputLength = inputLength; + mp3DemuxerAttr->id3v2Offset = mp3DemuxerAttr->id3v2Offset - inputLength; + return Status::ERROR_NOT_ENOUGH_DATA; + } + } + } + mp3DemuxerAttr->rst = mp3DemuxerRst; + mp3DemuxerAttr->internalRemainLen = inputLength; + ret = Minimp3WrapperMp3decIterateBuf(inputBuffer, inputLength, AudioDemuxerMp3IterateCallbackForProbe, mp3DemuxerAttr); + if (ret != 1) { + if (mp3DemuxerAttr->id3v2SkipFlag) { + return Status::ERROR_NOT_ENOUGH_DATA; + } + return Status::ERROR_UNSUPPORTED_FORMAT; + } + + return Status::OK; + } + int Sniff(const std::string& name, std::shared_ptr dataSource) { + Status status = Status::ERROR_UNKNOWN; + auto buffer = std::make_shared(); + auto bufData = buffer->AllocMemory(nullptr, probeReadLength); + int processLoop = 1; + uint8_t *inputDataPtr = nullptr; + int offset = 0; + while(processLoop) { + auto result = dataSource->ReadAt(offset, buffer, static_cast(probeReadLength)); + inputDataPtr = (uint8_t *)bufData->GetReadOnlyData(); + status = AudioDemuxerMp3Probe(&mp3ProbeAttr, inputDataPtr, bufData->GetSize(), &mp3ProbeRst); + switch(status) { + case Status::ERROR_NOT_ENOUGH_DATA: + offset = mp3ProbeRst.usedInputLength; + processLoop = 1; + break; + case Status::OK: + offset = mp3ProbeRst.usedInputLength; + processLoop = 0; + break; + case Status::ERROR_UNSUPPORTED_FORMAT: + return 0; + case Status::ERROR_UNKNOWN: + default: + processLoop = 0; + MEDIA_LOG_I("AUDIO_DEMUXER_PREPARE_UNMATCHED_FORMAT %d", status); + return 0; + } + } return 100; } - Status RegisterPlugins(const std::shared_ptr& reg) + Status RegisterPlugin(const std::shared_ptr& reg) { - MEDIA_LOG_D("RegisterPlugins called."); + MEDIA_LOG_I("RegisterPlugin called."); if (!reg) { - MEDIA_LOG_E("RegisterPlugins failed due to null pointer for reg."); + MEDIA_LOG_I("RegisterPlugin failed due to nullptr pointer for reg."); return Status::ERROR_INVALID_PARAMETER; } @@ -510,13 +544,13 @@ namespace { regInfo.sniffer = Sniff; auto rtv = reg->AddPlugin(regInfo); if (rtv != Status::OK) { - MEDIA_LOG_E("RegisterPlugins AddPlugin failed with return %d", static_cast(rtv)); + MEDIA_LOG_I("RegisterPlugin AddPlugin failed with return %d", static_cast(rtv)); } return Status::OK; } } -PLUGIN_DEFINITION(Minimp3Demuxer, LicenseType::LGPL, RegisterPlugins, [] {}); +PLUGIN_DEFINITION(Minimp3Demuxer, LicenseType::LGPL, RegisterPlugin, [] {}); } } diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h index 627ede93..a6d7af15 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h @@ -51,6 +51,8 @@ typedef struct uint32_t frameBitrateKbps; uint32_t frameSampleRate; uint8_t frameChannels; + uint8_t audioLayer; + uint32_t samplesPerFrame; } AudioDemuxerRst; typedef struct @@ -73,7 +75,7 @@ typedef struct uint8_t mp3SeekFlag; uint8_t discardItemCount; - Mp3DemuxerSampleAttr *preparePcmBuf; + Mp3DemuxerSampleAttr *probePcmBuf; } AudioDemuxerMp3Attr; namespace OHOS { @@ -81,7 +83,6 @@ namespace Media { namespace Plugin { class Minimp3DemuxerPlugin : public DemuxerPlugin { public: - Minimp3DemuxerPlugin *g_Plugin; explicit Minimp3DemuxerPlugin(std::string name); ~Minimp3DemuxerPlugin() override; Status Init() override; @@ -98,36 +99,32 @@ public: Status SetDataSource(const std::shared_ptr& source) override; Status GetMediaInfo(MediaInfo& mediaInfo) override; - Status ReadFrame(Buffer& info, int32_t timeOutMs) override; + Status ReadFrame(Buffer& OutBuffer, int32_t timeOutMs) override; Status SeekTo(int32_t trackId, int64_t timeStampUs, SeekMode mode) override; size_t GetTrackCount() override; Status SelectTrack(int32_t trackId) override; Status UnselectTrack(int32_t trackId) override; Status GetSelectedTracks(std::vector& trackIds) override; - static int AudioDemuxerMp3IterateCallbackForPrepare(void *userData, const uint8_t *frame, int frameSize, int freeFormatBytes, size_t bufSize, uint64_t offset, Mp3DemuxerFrameInfo *info); + private: struct IOContext { std::shared_ptr dataSource {nullptr}; int64_t offset {0}; bool eos {false}; }; - void AudioDemuxerMp3IgnoreTailZero( uint8_t *data, uint32_t *dataLen); + void AudioDemuxerMp3IgnoreTailZero(uint8_t *data, uint32_t *dataLen); static int AudioDemuxerMp3IterateCallback(void *userData, const uint8_t *frame, int frameSize, int freeFormatBytes, size_t bufSize, uint64_t offset, Mp3DemuxerFrameInfo *info); - int AudioDemuxerMp3ProbeDecodeCheck(Mp3DemuxerFrameInfo *info); - + static int AudioDemuxerMp3IterateCallbackForPrepare(void *userData, const uint8_t *frame, int frameSize, int freeFormatBytes, size_t bufSize, uint64_t offset, Mp3DemuxerFrameInfo *info); void AudioDemuxerMp3Open(AudioDemuxerUserArg *userArg); int AudioDemuxerMp3Close(); - size_t AudioDemuxerMp3GetId3v2Size(const uint8_t *buf, size_t bufSize); - int AudioDemuxerMp3Prepare(uint8_t *buf, uint32_t len); + Status AudioDemuxerMp3Prepare(AudioDemuxerMp3Attr *mp3DemuxerAttr, uint8_t *inputBuffer, uint32_t inputLength, AudioDemuxerRst *mp3DemuxerRst); int AudioDemuxerMp3Process(uint8_t *buf, uint32_t len); int AudioDemuxerMp3FreeFrame(uint8_t *frame); int AudioDemuxerMp3Seek( uint32_t pos, uint8_t *buf, uint32_t len, AudioDemuxerRst *rst); int AudioDemuxerMp3GetSeekPosition(uint32_t targetTtimeS, uint64_t *pos); int mediaIOSize_; - uint8_t *mediaIOBuf_; - uint8_t *readFrameBuf_; IOContext ioContext_; AudioDemuxerRst mp3DemuxerRst_; Minimp3DemuxerOp minimp3DemuxerImpl_; diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_ex.h b/engine/plugin/plugins/minimp3_adapter/minimp3_ex.h index 17ba5ae6..36a1d97a 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_ex.h +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_ex.h @@ -521,6 +521,7 @@ int mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB call frame_info.layer = 4 - HDR_GET_LAYER(hdr); frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr); frame_info.frame_bytes = frame_size; + frame_info.samples_per_frame = hdr_frame_samples(hdr); if (callback) { -- Gitee From b2cab2279f524ffd872566bdae8e397d3f5e593a Mon Sep 17 00:00:00 2001 From: zhangtl Date: Fri, 29 Oct 2021 17:17:05 +0800 Subject: [PATCH 16/22] [minimp3_plugin] fix non-standard parameter of function ReadFrame Signed-off-by: zhangtl Change-Id: I0e53e81d7269f12107928859e75d7a92de5aabd8 --- .../plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp | 8 ++++---- .../plugins/minimp3_adapter/minimp3_demuxer_plugin.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp index faba8713..77d81d96 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp @@ -109,7 +109,7 @@ Status Minimp3DemuxerPlugin::GetMediaInfo(MediaInfo& mediaInfo) return Status::OK; } -Status Minimp3DemuxerPlugin::ReadFrame(Buffer& OutBuffer, int32_t timeOutMs) +Status Minimp3DemuxerPlugin::ReadFrame(Buffer& outBuffer, int32_t timeOutMs) { int status = -1; std::shared_ptr mp3FrameData; @@ -125,10 +125,10 @@ Status Minimp3DemuxerPlugin::ReadFrame(Buffer& OutBuffer, int32_t timeOutMs) uint8_t *inputPtr = (uint8_t *)bufData->GetReadOnlyData(); status = AudioDemuxerMp3Process(inputPtr, bufData->GetSize()); - if (OutBuffer.IsEmpty()) { - mp3FrameData = OutBuffer.AllocMemory(nullptr, mp3DemuxerRst_.frameLength); + if (outBuffer.IsEmpty()) { + mp3FrameData = outBuffer.AllocMemory(nullptr, mp3DemuxerRst_.frameLength); } else { - mp3FrameData = OutBuffer.GetMemory(); + mp3FrameData = outBuffer.GetMemory(); } switch(status) { case AUDIO_DEMUXER_SUCCESS: diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h index a6d7af15..b5aca5d6 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h @@ -99,7 +99,7 @@ public: Status SetDataSource(const std::shared_ptr& source) override; Status GetMediaInfo(MediaInfo& mediaInfo) override; - Status ReadFrame(Buffer& OutBuffer, int32_t timeOutMs) override; + Status ReadFrame(Buffer& outBuffer, int32_t timeOutMs) override; Status SeekTo(int32_t trackId, int64_t timeStampUs, SeekMode mode) override; size_t GetTrackCount() override; -- Gitee From 5b0bdf9e33cce96bb52b48eb9b3e1790519b1af1 Mon Sep 17 00:00:00 2001 From: zhangtl Date: Thu, 4 Nov 2021 10:46:58 +0800 Subject: [PATCH 17/22] [minimp3_plugin] fix 2 channels play error Signed-off-by: zhangtl Change-Id: I59305fd7f18de5ba32c89b249bf6e514156879c5 --- .../plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp | 3 ++- .../plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp b/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp index c6dc4b99..277ccc55 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp @@ -306,10 +306,11 @@ namespace { DiscreteCapability channelLayoutValues = {AudioChannelLayout::MONO, AudioChannelLayout::STEREO}; cap.AppendDiscreteKeys(Capability::Key::AUDIO_CHANNEL_LAYOUT, channelLayoutValues); - DiscreteCapability sampleFmtValues = {AudioSampleFormat::S32, AudioSampleFormat::S16}; + DiscreteCapability sampleFmtValues = {AudioSampleFormat::S32, AudioSampleFormat::S16, AudioSampleFormat::S16P}; cap.AppendDiscreteKeys(Capability::Key::AUDIO_SAMPLE_FORMAT, sampleFmtValues); definition.inCaps.push_back(cap); + definition.outCaps.emplace_back(Capability(OHOS::Media::MEDIA_MIME_AUDIO_RAW)); } void UnRegisterAudioDecoderPlugin() diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp index 77d81d96..52ca73d3 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp @@ -91,7 +91,7 @@ Status Minimp3DemuxerPlugin::GetMediaInfo(MediaInfo& mediaInfo) mediaInfo.tracks[0].insert({Tag::MIME, std::string(MEDIA_MIME_AUDIO_MPEG)} ); mediaInfo.tracks[0].insert({Tag::AUDIO_MPEG_VERSION, static_cast(1)} ); mediaInfo.tracks[0].insert({Tag::AUDIO_MPEG_LAYER, (uint32_t)(mp3DemuxerRst_.audioLayer)} ); // 3 - mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_FORMAT, AudioSampleFormat::S16} ); + mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_FORMAT, AudioSampleFormat::S16P} ); mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_PER_FRAME, (uint32_t)(mp3DemuxerRst_.samplesPerFrame)}); processLoop = 0; @@ -488,7 +488,7 @@ namespace { } return Status::ERROR_UNSUPPORTED_FORMAT; } - + MEDIA_LOG_I("bitrate_kbps = %d info->channels = %d info->hz = %d", (uint32_t)mp3DemuxerRst->frameBitrateKbps, (uint32_t)mp3DemuxerRst->frameChannels, (uint32_t)mp3DemuxerRst->frameSampleRate); return Status::OK; } -- Gitee From 43da1c2904f0fb0c40bd6f3dad68d82882496cff Mon Sep 17 00:00:00 2001 From: zhangtl Date: Thu, 4 Nov 2021 16:31:53 +0800 Subject: [PATCH 18/22] [minimp3_plugin] modify STREAM_INDEX to TRACK_ID Signed-off-by: zhangtl --- .../plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp index 52ca73d3..8496855e 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp @@ -87,7 +87,7 @@ Status Minimp3DemuxerPlugin::GetMediaInfo(MediaInfo& mediaInfo) mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_RATE, (uint32_t)mp3DemuxerRst_.frameSampleRate} ); mediaInfo.tracks[0].insert({Tag::MEDIA_BITRATE, (uint32_t)mp3DemuxerRst_.frameBitrateKbps} ); mediaInfo.tracks[0].insert({Tag::AUDIO_CHANNELS, (uint32_t)mp3DemuxerRst_.frameChannels} ); - mediaInfo.tracks[0].insert({Tag::STREAM_INDEX, (uint32_t)0} ); + mediaInfo.tracks[0].insert({Tag::TRACK_ID, (uint32_t)0} ); mediaInfo.tracks[0].insert({Tag::MIME, std::string(MEDIA_MIME_AUDIO_MPEG)} ); mediaInfo.tracks[0].insert({Tag::AUDIO_MPEG_VERSION, static_cast(1)} ); mediaInfo.tracks[0].insert({Tag::AUDIO_MPEG_LAYER, (uint32_t)(mp3DemuxerRst_.audioLayer)} ); // 3 -- Gitee From a1a0326a6612c43af2fd118b674e289e0db3c014 Mon Sep 17 00:00:00 2001 From: zhangtl Date: Mon, 8 Nov 2021 15:27:13 +0800 Subject: [PATCH 19/22] [minimp3_plugin] add fileSize_ for future usage Signed-off-by: zhangtl --- .../plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp | 10 ++++++++-- .../plugins/minimp3_adapter/minimp3_demuxer_plugin.h | 3 ++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp index 8496855e..3b12283f 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp @@ -39,7 +39,8 @@ void UpdatePluginDefinition(CodecPluginDef& definition); Minimp3DemuxerPlugin::Minimp3DemuxerPlugin(std::string name) : DemuxerPlugin(std::move(name)), ioContext_(), - mediaIOSize_(12 * 1024) + mediaIOSize_(12 * 1024), + fileSize_(0) { memset_s(&mp3DemuxerAttr_, sizeof(mp3DemuxerAttr_), 0x00, sizeof(AudioDemuxerMp3Attr)); memset_s(&mp3DemuxerRst_, sizeof(mp3DemuxerRst_), 0x00, sizeof(AudioDemuxerRst)); @@ -56,6 +57,10 @@ Minimp3DemuxerPlugin::~Minimp3DemuxerPlugin() Status Minimp3DemuxerPlugin::SetDataSource(const std::shared_ptr& source) { ioContext_.dataSource = source; + if (ioContext_.dataSource != nullptr) { + ioContext_.dataSource->GetSize(fileSize_); + } + MEDIA_LOG_I("fileSize_ %d", fileSize_); return Status::OK; } @@ -91,7 +96,7 @@ Status Minimp3DemuxerPlugin::GetMediaInfo(MediaInfo& mediaInfo) mediaInfo.tracks[0].insert({Tag::MIME, std::string(MEDIA_MIME_AUDIO_MPEG)} ); mediaInfo.tracks[0].insert({Tag::AUDIO_MPEG_VERSION, static_cast(1)} ); mediaInfo.tracks[0].insert({Tag::AUDIO_MPEG_LAYER, (uint32_t)(mp3DemuxerRst_.audioLayer)} ); // 3 - mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_FORMAT, AudioSampleFormat::S16P} ); + mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_FORMAT, AudioSampleFormat::S16P} ); mediaInfo.tracks[0].insert({Tag::AUDIO_SAMPLE_PER_FRAME, (uint32_t)(mp3DemuxerRst_.samplesPerFrame)}); processLoop = 0; @@ -119,6 +124,7 @@ Status Minimp3DemuxerPlugin::ReadFrame(Buffer& outBuffer, int32_t timeOutMs) if (result != Status::OK) { ioContext_.eos = true; ioContext_.offset = 0; + MEDIA_LOG_I("result is %d", result); return result; } diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h index b5aca5d6..10a8d6a6 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.h @@ -124,7 +124,8 @@ private: int AudioDemuxerMp3Seek( uint32_t pos, uint8_t *buf, uint32_t len, AudioDemuxerRst *rst); int AudioDemuxerMp3GetSeekPosition(uint32_t targetTtimeS, uint64_t *pos); - int mediaIOSize_; + int mediaIOSize_; + size_t fileSize_; IOContext ioContext_; AudioDemuxerRst mp3DemuxerRst_; Minimp3DemuxerOp minimp3DemuxerImpl_; -- Gitee From 879af4306152a1c20be401b3d338b77a39f8f346 Mon Sep 17 00:00:00 2001 From: zhangtl Date: Mon, 8 Nov 2021 21:34:16 +0800 Subject: [PATCH 20/22] [minimp3_plugin] add mp3 seek Signed-off-by: zhangtl --- .../minimp3_adapter/minimp3_demuxer_plugin.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp index 3b12283f..30d5b113 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp @@ -161,8 +161,11 @@ Status Minimp3DemuxerPlugin::SeekTo(int32_t trackId, int64_t timeStampUs, SeekMo { uint64_t pos = 0; uint32_t targetTtimeS = (uint32_t)(timeStampUs / (1000 * 1000)); - AudioDemuxerMp3GetSeekPosition(targetTtimeS, &pos); - mp3DemuxerRst_.usedInputLength = pos; + if (0 == AudioDemuxerMp3GetSeekPosition(targetTtimeS, &pos)) { + mp3DemuxerRst_.usedInputLength = pos; + } else { + return Status::ERROR_INVALID_PARAMETER; + } return Status::OK; } @@ -377,6 +380,10 @@ int Minimp3DemuxerPlugin::AudioDemuxerMp3GetSeekPosition(uint32_t targetTtimeS, return AUDIO_DEMUXER_ERROR; } uint32_t targetPos = targetTtimeS * mp3DemuxerAttr_.bitRate * 1000 / 8 + mp3DemuxerAttr_.id3v2Size; + if (targetPos > mp3_demuxer->file_size) { + *pos = 0; + return -1; + } *pos = (uint64_t)targetPos; mp3DemuxerAttr_.mp3SeekFlag = 1; return 0; -- Gitee From 3bc4367821545489b3c00c8de4bffb728b8a7263 Mon Sep 17 00:00:00 2001 From: zhangtl Date: Tue, 9 Nov 2021 10:09:34 +0800 Subject: [PATCH 21/22] [minimp3_plugin] modify seek in mp3 Signed-off-by: zhangtl --- .../plugins/minimp3_adapter/minimp3_decoder_plugin.cpp | 10 ---------- .../plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp | 3 ++- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp b/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp index 277ccc55..2dd36750 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_decoder_plugin.cpp @@ -213,22 +213,12 @@ void Minimp3DecoderPlugin::NotifyOutputBufferDone(const std::shared_ptr& void Minimp3DecoderPlugin::AudioDecoderMp3Open(void *userData) { - Mp3DecoderSample *pcmData = (Mp3DecoderSample*)calloc(mp3MaxSamplePerFrame, sizeof(Mp3DecoderSample)); - if (pcmData == nullptr) { - return; - } mp3DecoderAttr_.userData = userData; - mp3DecoderAttr_.pcm = pcmData; - Minimp3WrapperMp3decInit(&mp3DecoderAttr_.mp3DecoderHandle); } int Minimp3DecoderPlugin::AudioDecoderMp3Close() { - if (mp3DecoderAttr_.pcm) { - free(mp3DecoderAttr_.pcm); - mp3DecoderAttr_.pcm = nullptr; - } return 0; } diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp index 30d5b113..1a9d49ba 100755 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp +++ b/engine/plugin/plugins/minimp3_adapter/minimp3_demuxer_plugin.cpp @@ -60,6 +60,7 @@ Status Minimp3DemuxerPlugin::SetDataSource(const std::shared_ptr& so if (ioContext_.dataSource != nullptr) { ioContext_.dataSource->GetSize(fileSize_); } + mp3DemuxerAttr_.fileSize = fileSize_; MEDIA_LOG_I("fileSize_ %d", fileSize_); return Status::OK; } @@ -380,7 +381,7 @@ int Minimp3DemuxerPlugin::AudioDemuxerMp3GetSeekPosition(uint32_t targetTtimeS, return AUDIO_DEMUXER_ERROR; } uint32_t targetPos = targetTtimeS * mp3DemuxerAttr_.bitRate * 1000 / 8 + mp3DemuxerAttr_.id3v2Size; - if (targetPos > mp3_demuxer->file_size) { + if (targetPos > mp3DemuxerAttr_.fileSize) { *pos = 0; return -1; } -- Gitee From 7c168fe5add887b1de94cf2e2dabc75f83f65861 Mon Sep 17 00:00:00 2001 From: Chen Guodong Date: Tue, 9 Nov 2021 16:47:14 +0800 Subject: [PATCH 22/22] remove mp3 library headers. Signed-off-by: Chen Guodong --- .../plugin/plugins/minimp3_adapter/minimp3.h | 1854 ----------------- .../plugins/minimp3_adapter/minimp3_ex.h | 1394 ------------- 2 files changed, 3248 deletions(-) delete mode 100755 engine/plugin/plugins/minimp3_adapter/minimp3.h delete mode 100755 engine/plugin/plugins/minimp3_adapter/minimp3_ex.h diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3.h b/engine/plugin/plugins/minimp3_adapter/minimp3.h deleted file mode 100755 index f2666f82..00000000 --- a/engine/plugin/plugins/minimp3_adapter/minimp3.h +++ /dev/null @@ -1,1854 +0,0 @@ -#ifndef MINIMP3_H -#define MINIMP3_H -/* - https://github.com/lieff/minimp3 - To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. - This software is distributed without any warranty. - See . -*/ -#include - -#define MINIMP3_MAX_SAMPLES_PER_FRAME (1152*2) - -typedef struct -{ - int frame_bytes, frame_offset, channels, hz, layer, bitrate_kbps, samples_per_frame; -} mp3dec_frame_info_t; - -typedef struct -{ - float mdct_overlap[2][9*32], qmf_state[15*2*32]; - int reserv, free_format_bytes; - unsigned char header[4], reserv_buf[511]; -} mp3dec_t; - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -void mp3dec_init(mp3dec_t *dec); -#ifndef MINIMP3_FLOAT_OUTPUT -typedef int16_t mp3d_sample_t; -#else /* MINIMP3_FLOAT_OUTPUT */ -typedef float mp3d_sample_t; -void mp3dec_f32_to_s16(const float *in, int16_t *out, int num_samples); -#endif /* MINIMP3_FLOAT_OUTPUT */ -int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_sample_t *pcm, mp3dec_frame_info_t *info); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* MINIMP3_H */ -#if defined(MINIMP3_IMPLEMENTATION) && !defined(_MINIMP3_IMPLEMENTATION_GUARD) -#define _MINIMP3_IMPLEMENTATION_GUARD - -#include -#include - -#define MAX_FREE_FORMAT_FRAME_SIZE 2304 /* more than ISO spec's */ -#ifndef MAX_FRAME_SYNC_MATCHES -#define MAX_FRAME_SYNC_MATCHES 10 -#endif /* MAX_FRAME_SYNC_MATCHES */ - -#define MAX_L3_FRAME_PAYLOAD_BYTES MAX_FREE_FORMAT_FRAME_SIZE /* MUST be >= 320000/8/32000*1152 = 1440 */ - -#define MAX_BITRESERVOIR_BYTES 511 -#define SHORT_BLOCK_TYPE 2 -#define STOP_BLOCK_TYPE 3 -#define MODE_MONO 3 -#define MODE_JOINT_STEREO 1 -#define HDR_SIZE 4 -#define HDR_IS_MONO(h) (((h[3]) & 0xC0) == 0xC0) -#define HDR_IS_MS_STEREO(h) (((h[3]) & 0xE0) == 0x60) -#define HDR_IS_FREE_FORMAT(h) (((h[2]) & 0xF0) == 0) -#define HDR_IS_CRC(h) (!((h[1]) & 1)) -#define HDR_TEST_PADDING(h) ((h[2]) & 0x2) -#define HDR_TEST_MPEG1(h) ((h[1]) & 0x8) -#define HDR_TEST_NOT_MPEG25(h) ((h[1]) & 0x10) -#define HDR_TEST_I_STEREO(h) ((h[3]) & 0x10) -#define HDR_TEST_MS_STEREO(h) ((h[3]) & 0x20) -#define HDR_GET_STEREO_MODE(h) (((h[3]) >> 6) & 3) -#define HDR_GET_STEREO_MODE_EXT(h) (((h[3]) >> 4) & 3) -#define HDR_GET_LAYER(h) (((h[1]) >> 1) & 3) -#define HDR_GET_BITRATE(h) ((h[2]) >> 4) -#define HDR_GET_SAMPLE_RATE(h) (((h[2]) >> 2) & 3) -#define HDR_GET_MY_SAMPLE_RATE(h) (HDR_GET_SAMPLE_RATE(h) + (((h[1] >> 3) & 1) + ((h[1] >> 4) & 1))*3) -#define HDR_IS_FRAME_576(h) ((h[1] & 14) == 2) -#define HDR_IS_LAYER_1(h) ((h[1] & 6) == 6) - -#define BITS_DEQUANTIZER_OUT -1 -#define MAX_SCF (255 + BITS_DEQUANTIZER_OUT*4 - 210) -#define MAX_SCFI ((MAX_SCF + 3) & ~3) - -#define MINIMP3_MIN(a, b) ((a) > (b) ? (b) : (a)) -#define MINIMP3_MAX(a, b) ((a) < (b) ? (b) : (a)) - -#if !defined(MINIMP3_NO_SIMD) - -#if !defined(MINIMP3_ONLY_SIMD) && (defined(_M_X64) || defined(__x86_64__) || defined(__aarch64__) || defined(_M_ARM64)) -/* x64 always have SSE2, arm64 always have neon, no need for generic code */ -#define MINIMP3_ONLY_SIMD -#endif /* SIMD checks... */ - -#if (defined(_MSC_VER) && (defined(_M_IX86) || defined(_M_X64))) || ((defined(__i386__) || defined(__x86_64__)) && defined(__SSE2__)) -#if defined(_MSC_VER) -#include -#endif /* defined(_MSC_VER) */ -#include -#define HAVE_SSE 1 -#define HAVE_SIMD 1 -#define VSTORE _mm_storeu_ps -#define VLD _mm_loadu_ps -#define VSET _mm_set1_ps -#define VADD _mm_add_ps -#define VSUB _mm_sub_ps -#define VMUL _mm_mul_ps -#define VMAC(a, x, y) _mm_add_ps(a, _mm_mul_ps(x, y)) -#define VMSB(a, x, y) _mm_sub_ps(a, _mm_mul_ps(x, y)) -#define VMUL_S(x, s) _mm_mul_ps(x, _mm_set1_ps(s)) -#define VREV(x) _mm_shuffle_ps(x, x, _MM_SHUFFLE(0, 1, 2, 3)) -typedef __m128 f4; -#if defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) -#define minimp3_cpuid __cpuid -#else /* defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) */ -static __inline__ __attribute__((always_inline)) void minimp3_cpuid(int CPUInfo[], const int InfoType) -{ -#if defined(__PIC__) - __asm__ __volatile__( -#if defined(__x86_64__) - "push %%rbx\n" - "cpuid\n" - "xchgl %%ebx, %1\n" - "pop %%rbx\n" -#else /* defined(__x86_64__) */ - "xchgl %%ebx, %1\n" - "cpuid\n" - "xchgl %%ebx, %1\n" -#endif /* defined(__x86_64__) */ - : "=a" (CPUInfo[0]), "=r" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3]) - : "a" (InfoType)); -#else /* defined(__PIC__) */ - __asm__ __volatile__( - "cpuid" - : "=a" (CPUInfo[0]), "=b" (CPUInfo[1]), "=c" (CPUInfo[2]), "=d" (CPUInfo[3]) - : "a" (InfoType)); -#endif /* defined(__PIC__)*/ -} -#endif /* defined(_MSC_VER) || defined(MINIMP3_ONLY_SIMD) */ -static int have_simd(void) -{ -#ifdef MINIMP3_ONLY_SIMD - return 1; -#else /* MINIMP3_ONLY_SIMD */ - static int g_have_simd; - int CPUInfo[4]; -#ifdef MINIMP3_TEST - static int g_counter; - if (g_counter++ > 100) - return 0; -#endif /* MINIMP3_TEST */ - if (g_have_simd) - goto end; - minimp3_cpuid(CPUInfo, 0); - g_have_simd = 1; - if (CPUInfo[0] > 0) - { - minimp3_cpuid(CPUInfo, 1); - g_have_simd = (CPUInfo[3] & (1 << 26)) + 1; /* SSE2 */ - } -end: - return g_have_simd - 1; -#endif /* MINIMP3_ONLY_SIMD */ -} -#elif defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64) -#include -#define HAVE_SSE 0 -#define HAVE_SIMD 1 -#define VSTORE vst1q_f32 -#define VLD vld1q_f32 -#define VSET vmovq_n_f32 -#define VADD vaddq_f32 -#define VSUB vsubq_f32 -#define VMUL vmulq_f32 -#define VMAC(a, x, y) vmlaq_f32(a, x, y) -#define VMSB(a, x, y) vmlsq_f32(a, x, y) -#define VMUL_S(x, s) vmulq_f32(x, vmovq_n_f32(s)) -#define VREV(x) vcombine_f32(vget_high_f32(vrev64q_f32(x)), vget_low_f32(vrev64q_f32(x))) -typedef float32x4_t f4; -static int have_simd() -{ /* TODO: detect neon for !MINIMP3_ONLY_SIMD */ - return 1; -} -#else /* SIMD checks... */ -#define HAVE_SSE 0 -#define HAVE_SIMD 0 -#ifdef MINIMP3_ONLY_SIMD -#error MINIMP3_ONLY_SIMD used, but SSE/NEON not enabled -#endif /* MINIMP3_ONLY_SIMD */ -#endif /* SIMD checks... */ -#else /* !defined(MINIMP3_NO_SIMD) */ -#define HAVE_SIMD 0 -#endif /* !defined(MINIMP3_NO_SIMD) */ - -#if defined(__ARM_ARCH) && (__ARM_ARCH >= 6) && !defined(__aarch64__) && !defined(_M_ARM64) -#define HAVE_ARMV6 1 -static __inline__ __attribute__((always_inline)) int32_t minimp3_clip_int16_arm(int32_t a) -{ - int32_t x = 0; - __asm__ ("ssat %0, #16, %1" : "=r"(x) : "r"(a)); - return x; -} -#else -#define HAVE_ARMV6 0 -#endif - -typedef struct -{ - const uint8_t *buf; - int pos, limit; -} bs_t; - -typedef struct -{ - float scf[3*64]; - uint8_t total_bands, stereo_bands, bitalloc[64], scfcod[64]; -} L12_scale_info; - -typedef struct -{ - uint8_t tab_offset, code_tab_width, band_count; -} L12_subband_alloc_t; - -typedef struct -{ - const uint8_t *sfbtab; - uint16_t part_23_length, big_values, scalefac_compress; - uint8_t global_gain, block_type, mixed_block_flag, n_long_sfb, n_short_sfb; - uint8_t table_select[3], region_count[3], subblock_gain[3]; - uint8_t preflag, scalefac_scale, count1_table, scfsi; -} L3_gr_info_t; - -typedef struct -{ - bs_t bs; - uint8_t maindata[MAX_BITRESERVOIR_BYTES + MAX_L3_FRAME_PAYLOAD_BYTES]; - L3_gr_info_t gr_info[4]; - float grbuf[2][576], scf[40], syn[18 + 15][2*32]; - uint8_t ist_pos[2][39]; -} mp3dec_scratch_t; - -static void bs_init(bs_t *bs, const uint8_t *data, int bytes) -{ - bs->buf = data; - bs->pos = 0; - bs->limit = bytes*8; -} - -static uint32_t get_bits(bs_t *bs, int n) -{ - uint32_t next, cache = 0, s = bs->pos & 7; - int shl = n + s; - const uint8_t *p = bs->buf + (bs->pos >> 3); - if ((bs->pos += n) > bs->limit) - return 0; - next = *p++ & (255 >> s); - while ((shl -= 8) > 0) - { - cache |= next << shl; - next = *p++; - } - return cache | (next >> -shl); -} - -static int hdr_valid(const uint8_t *h) -{ - return h[0] == 0xff && - ((h[1] & 0xF0) == 0xf0 || (h[1] & 0xFE) == 0xe2) && - (HDR_GET_LAYER(h) != 0) && - (HDR_GET_BITRATE(h) != 15) && - (HDR_GET_SAMPLE_RATE(h) != 3); -} - -static int hdr_compare(const uint8_t *h1, const uint8_t *h2) -{ - return hdr_valid(h2) && - ((h1[1] ^ h2[1]) & 0xFE) == 0 && - ((h1[2] ^ h2[2]) & 0x0C) == 0 && - !(HDR_IS_FREE_FORMAT(h1) ^ HDR_IS_FREE_FORMAT(h2)); -} - -static unsigned hdr_bitrate_kbps(const uint8_t *h) -{ - static const uint8_t halfrate[2][3][15] = { - { { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,4,8,12,16,20,24,28,32,40,48,56,64,72,80 }, { 0,16,24,28,32,40,48,56,64,72,80,88,96,112,128 } }, - { { 0,16,20,24,28,32,40,48,56,64,80,96,112,128,160 }, { 0,16,24,28,32,40,48,56,64,80,96,112,128,160,192 }, { 0,16,32,48,64,80,96,112,128,144,160,176,192,208,224 } }, - }; - return 2*halfrate[!!HDR_TEST_MPEG1(h)][HDR_GET_LAYER(h) - 1][HDR_GET_BITRATE(h)]; -} - -static unsigned hdr_sample_rate_hz(const uint8_t *h) -{ - static const unsigned g_hz[3] = { 44100, 48000, 32000 }; - return g_hz[HDR_GET_SAMPLE_RATE(h)] >> (int)!HDR_TEST_MPEG1(h) >> (int)!HDR_TEST_NOT_MPEG25(h); -} - -static unsigned hdr_frame_samples(const uint8_t *h) -{ - return HDR_IS_LAYER_1(h) ? 384 : (1152 >> (int)HDR_IS_FRAME_576(h)); -} - -static int hdr_frame_bytes(const uint8_t *h, int free_format_size) -{ - int frame_bytes = hdr_frame_samples(h)*hdr_bitrate_kbps(h)*125/hdr_sample_rate_hz(h); - if (HDR_IS_LAYER_1(h)) - { - frame_bytes &= ~3; /* slot align */ - } - return frame_bytes ? frame_bytes : free_format_size; -} - -static int hdr_padding(const uint8_t *h) -{ - return HDR_TEST_PADDING(h) ? (HDR_IS_LAYER_1(h) ? 4 : 1) : 0; -} - -#ifndef MINIMP3_ONLY_MP3 -static const L12_subband_alloc_t *L12_subband_alloc_table(const uint8_t *hdr, L12_scale_info *sci) -{ - const L12_subband_alloc_t *alloc; - int mode = HDR_GET_STEREO_MODE(hdr); - int nbands, stereo_bands = (mode == MODE_MONO) ? 0 : (mode == MODE_JOINT_STEREO) ? (HDR_GET_STEREO_MODE_EXT(hdr) << 2) + 4 : 32; - - if (HDR_IS_LAYER_1(hdr)) - { - static const L12_subband_alloc_t g_alloc_L1[] = { { 76, 4, 32 } }; - alloc = g_alloc_L1; - nbands = 32; - } else if (!HDR_TEST_MPEG1(hdr)) - { - static const L12_subband_alloc_t g_alloc_L2M2[] = { { 60, 4, 4 }, { 44, 3, 7 }, { 44, 2, 19 } }; - alloc = g_alloc_L2M2; - nbands = 30; - } else - { - static const L12_subband_alloc_t g_alloc_L2M1[] = { { 0, 4, 3 }, { 16, 4, 8 }, { 32, 3, 12 }, { 40, 2, 7 } }; - int sample_rate_idx = HDR_GET_SAMPLE_RATE(hdr); - unsigned kbps = hdr_bitrate_kbps(hdr) >> (int)(mode != MODE_MONO); - if (!kbps) /* free-format */ - { - kbps = 192; - } - - alloc = g_alloc_L2M1; - nbands = 27; - if (kbps < 56) - { - static const L12_subband_alloc_t g_alloc_L2M1_lowrate[] = { { 44, 4, 2 }, { 44, 3, 10 } }; - alloc = g_alloc_L2M1_lowrate; - nbands = sample_rate_idx == 2 ? 12 : 8; - } else if (kbps >= 96 && sample_rate_idx != 1) - { - nbands = 30; - } - } - - sci->total_bands = (uint8_t)nbands; - sci->stereo_bands = (uint8_t)MINIMP3_MIN(stereo_bands, nbands); - - return alloc; -} - -static void L12_read_scalefactors(bs_t *bs, uint8_t *pba, uint8_t *scfcod, int bands, float *scf) -{ - static const float g_deq_L12[18*3] = { -#define DQ(x) 9.53674316e-07f/x, 7.56931807e-07f/x, 6.00777173e-07f/x - DQ(3),DQ(7),DQ(15),DQ(31),DQ(63),DQ(127),DQ(255),DQ(511),DQ(1023),DQ(2047),DQ(4095),DQ(8191),DQ(16383),DQ(32767),DQ(65535),DQ(3),DQ(5),DQ(9) - }; - int i, m; - for (i = 0; i < bands; i++) - { - float s = 0; - int ba = *pba++; - int mask = ba ? 4 + ((19 >> scfcod[i]) & 3) : 0; - for (m = 4; m; m >>= 1) - { - if (mask & m) - { - int b = get_bits(bs, 6); - s = g_deq_L12[ba*3 - 6 + b % 3]*(1 << 21 >> b/3); - } - *scf++ = s; - } - } -} - -static void L12_read_scale_info(const uint8_t *hdr, bs_t *bs, L12_scale_info *sci) -{ - static const uint8_t g_bitalloc_code_tab[] = { - 0,17, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16, - 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,16, - 0,17,18, 3,19,4,5,16, - 0,17,18,16, - 0,17,18,19, 4,5,6, 7,8, 9,10,11,12,13,14,15, - 0,17,18, 3,19,4,5, 6,7, 8, 9,10,11,12,13,14, - 0, 2, 3, 4, 5,6,7, 8,9,10,11,12,13,14,15,16 - }; - const L12_subband_alloc_t *subband_alloc = L12_subband_alloc_table(hdr, sci); - - int i, k = 0, ba_bits = 0; - const uint8_t *ba_code_tab = g_bitalloc_code_tab; - - for (i = 0; i < sci->total_bands; i++) - { - uint8_t ba; - if (i == k) - { - k += subband_alloc->band_count; - ba_bits = subband_alloc->code_tab_width; - ba_code_tab = g_bitalloc_code_tab + subband_alloc->tab_offset; - subband_alloc++; - } - ba = ba_code_tab[get_bits(bs, ba_bits)]; - sci->bitalloc[2*i] = ba; - if (i < sci->stereo_bands) - { - ba = ba_code_tab[get_bits(bs, ba_bits)]; - } - sci->bitalloc[2*i + 1] = sci->stereo_bands ? ba : 0; - } - - for (i = 0; i < 2*sci->total_bands; i++) - { - sci->scfcod[i] = sci->bitalloc[i] ? HDR_IS_LAYER_1(hdr) ? 2 : get_bits(bs, 2) : 6; - } - - L12_read_scalefactors(bs, sci->bitalloc, sci->scfcod, sci->total_bands*2, sci->scf); - - for (i = sci->stereo_bands; i < sci->total_bands; i++) - { - sci->bitalloc[2*i + 1] = 0; - } -} - -static int L12_dequantize_granule(float *grbuf, bs_t *bs, L12_scale_info *sci, int group_size) -{ - int i, j, k, choff = 576; - for (j = 0; j < 4; j++) - { - float *dst = grbuf + group_size*j; - for (i = 0; i < 2*sci->total_bands; i++) - { - int ba = sci->bitalloc[i]; - if (ba != 0) - { - if (ba < 17) - { - int half = (1 << (ba - 1)) - 1; - for (k = 0; k < group_size; k++) - { - dst[k] = (float)((int)get_bits(bs, ba) - half); - } - } else - { - unsigned mod = (2 << (ba - 17)) + 1; /* 3, 5, 9 */ - unsigned code = get_bits(bs, mod + 2 - (mod >> 3)); /* 5, 7, 10 */ - for (k = 0; k < group_size; k++, code /= mod) - { - dst[k] = (float)((int)(code % mod - mod/2)); - } - } - } - dst += choff; - choff = 18 - choff; - } - } - return group_size*4; -} - -static void L12_apply_scf_384(L12_scale_info *sci, const float *scf, float *dst) -{ - int i, k; - memcpy(dst + 576 + sci->stereo_bands*18, dst + sci->stereo_bands*18, (sci->total_bands - sci->stereo_bands)*18*sizeof(float)); - for (i = 0; i < sci->total_bands; i++, dst += 18, scf += 6) - { - for (k = 0; k < 12; k++) - { - dst[k + 0] *= scf[0]; - dst[k + 576] *= scf[3]; - } - } -} -#endif /* MINIMP3_ONLY_MP3 */ - -static int L3_read_side_info(bs_t *bs, L3_gr_info_t *gr, const uint8_t *hdr) -{ - static const uint8_t g_scf_long[8][23] = { - { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, - { 12,12,12,12,12,12,16,20,24,28,32,40,48,56,64,76,90,2,2,2,2,2,0 }, - { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, - { 6,6,6,6,6,6,8,10,12,14,16,18,22,26,32,38,46,54,62,70,76,36,0 }, - { 6,6,6,6,6,6,8,10,12,14,16,20,24,28,32,38,46,52,60,68,58,54,0 }, - { 4,4,4,4,4,4,6,6,8,8,10,12,16,20,24,28,34,42,50,54,76,158,0 }, - { 4,4,4,4,4,4,6,6,6,8,10,12,16,18,22,28,34,40,46,54,54,192,0 }, - { 4,4,4,4,4,4,6,6,8,10,12,16,20,24,30,38,46,56,68,84,102,26,0 } - }; - static const uint8_t g_scf_short[8][40] = { - { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, - { 8,8,8,8,8,8,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 }, - { 4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 }, - { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,32,32,32,44,44,44,12,12,12,0 }, - { 4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, - { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 }, - { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 }, - { 4,4,4,4,4,4,4,4,4,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 } - }; - static const uint8_t g_scf_mixed[8][40] = { - { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, - { 12,12,12,4,4,4,8,8,8,12,12,12,16,16,16,20,20,20,24,24,24,28,28,28,36,36,36,2,2,2,2,2,2,2,2,2,26,26,26,0 }, - { 6,6,6,6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,14,14,14,18,18,18,26,26,26,32,32,32,42,42,42,18,18,18,0 }, - { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,32,32,32,44,44,44,12,12,12,0 }, - { 6,6,6,6,6,6,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,24,24,24,30,30,30,40,40,40,18,18,18,0 }, - { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,10,10,10,12,12,12,14,14,14,18,18,18,22,22,22,30,30,30,56,56,56,0 }, - { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,6,6,6,10,10,10,12,12,12,14,14,14,16,16,16,20,20,20,26,26,26,66,66,66,0 }, - { 4,4,4,4,4,4,6,6,4,4,4,6,6,6,8,8,8,12,12,12,16,16,16,20,20,20,26,26,26,34,34,34,42,42,42,12,12,12,0 } - }; - - unsigned tables, scfsi = 0; - int main_data_begin, part_23_sum = 0; - int sr_idx = HDR_GET_MY_SAMPLE_RATE(hdr); sr_idx -= (sr_idx != 0); - int gr_count = HDR_IS_MONO(hdr) ? 1 : 2; - - if (HDR_TEST_MPEG1(hdr)) - { - gr_count *= 2; - main_data_begin = get_bits(bs, 9); - scfsi = get_bits(bs, 7 + gr_count); - } else - { - main_data_begin = get_bits(bs, 8 + gr_count) >> gr_count; - } - - do - { - if (HDR_IS_MONO(hdr)) - { - scfsi <<= 4; - } - gr->part_23_length = (uint16_t)get_bits(bs, 12); - part_23_sum += gr->part_23_length; - gr->big_values = (uint16_t)get_bits(bs, 9); - if (gr->big_values > 288) - { - return -1; - } - gr->global_gain = (uint8_t)get_bits(bs, 8); - gr->scalefac_compress = (uint16_t)get_bits(bs, HDR_TEST_MPEG1(hdr) ? 4 : 9); - gr->sfbtab = g_scf_long[sr_idx]; - gr->n_long_sfb = 22; - gr->n_short_sfb = 0; - if (get_bits(bs, 1)) - { - gr->block_type = (uint8_t)get_bits(bs, 2); - if (!gr->block_type) - { - return -1; - } - gr->mixed_block_flag = (uint8_t)get_bits(bs, 1); - gr->region_count[0] = 7; - gr->region_count[1] = 255; - if (gr->block_type == SHORT_BLOCK_TYPE) - { - scfsi &= 0x0F0F; - if (!gr->mixed_block_flag) - { - gr->region_count[0] = 8; - gr->sfbtab = g_scf_short[sr_idx]; - gr->n_long_sfb = 0; - gr->n_short_sfb = 39; - } else - { - gr->sfbtab = g_scf_mixed[sr_idx]; - gr->n_long_sfb = HDR_TEST_MPEG1(hdr) ? 8 : 6; - gr->n_short_sfb = 30; - } - } - tables = get_bits(bs, 10); - tables <<= 5; - gr->subblock_gain[0] = (uint8_t)get_bits(bs, 3); - gr->subblock_gain[1] = (uint8_t)get_bits(bs, 3); - gr->subblock_gain[2] = (uint8_t)get_bits(bs, 3); - } else - { - gr->block_type = 0; - gr->mixed_block_flag = 0; - tables = get_bits(bs, 15); - gr->region_count[0] = (uint8_t)get_bits(bs, 4); - gr->region_count[1] = (uint8_t)get_bits(bs, 3); - gr->region_count[2] = 255; - } - gr->table_select[0] = (uint8_t)(tables >> 10); - gr->table_select[1] = (uint8_t)((tables >> 5) & 31); - gr->table_select[2] = (uint8_t)((tables) & 31); - gr->preflag = HDR_TEST_MPEG1(hdr) ? get_bits(bs, 1) : (gr->scalefac_compress >= 500); - gr->scalefac_scale = (uint8_t)get_bits(bs, 1); - gr->count1_table = (uint8_t)get_bits(bs, 1); - gr->scfsi = (uint8_t)((scfsi >> 12) & 15); - scfsi <<= 4; - gr++; - } while(--gr_count); - - if (part_23_sum + bs->pos > bs->limit + main_data_begin*8) - { - return -1; - } - - return main_data_begin; -} - -static void L3_read_scalefactors(uint8_t *scf, uint8_t *ist_pos, const uint8_t *scf_size, const uint8_t *scf_count, bs_t *bitbuf, int scfsi) -{ - int i, k; - for (i = 0; i < 4 && scf_count[i]; i++, scfsi *= 2) - { - int cnt = scf_count[i]; - if (scfsi & 8) - { - memcpy(scf, ist_pos, cnt); - } else - { - int bits = scf_size[i]; - if (!bits) - { - memset(scf, 0, cnt); - memset(ist_pos, 0, cnt); - } else - { - int max_scf = (scfsi < 0) ? (1 << bits) - 1 : -1; - for (k = 0; k < cnt; k++) - { - int s = get_bits(bitbuf, bits); - ist_pos[k] = (s == max_scf ? -1 : s); - scf[k] = s; - } - } - } - ist_pos += cnt; - scf += cnt; - } - scf[0] = scf[1] = scf[2] = 0; -} - -static float L3_ldexp_q2(float y, int exp_q2) -{ - static const float g_expfrac[4] = { 9.31322575e-10f,7.83145814e-10f,6.58544508e-10f,5.53767716e-10f }; - int e; - do - { - e = MINIMP3_MIN(30*4, exp_q2); - y *= g_expfrac[e & 3]*(1 << 30 >> (e >> 2)); - } while ((exp_q2 -= e) > 0); - return y; -} - -static void L3_decode_scalefactors(const uint8_t *hdr, uint8_t *ist_pos, bs_t *bs, const L3_gr_info_t *gr, float *scf, int ch) -{ - static const uint8_t g_scf_partitions[3][28] = { - { 6,5,5, 5,6,5,5,5,6,5, 7,3,11,10,0,0, 7, 7, 7,0, 6, 6,6,3, 8, 8,5,0 }, - { 8,9,6,12,6,9,9,9,6,9,12,6,15,18,0,0, 6,15,12,0, 6,12,9,6, 6,18,9,0 }, - { 9,9,6,12,9,9,9,9,9,9,12,6,18,18,0,0,12,12,12,0,12, 9,9,6,15,12,9,0 } - }; - const uint8_t *scf_partition = g_scf_partitions[!!gr->n_short_sfb + !gr->n_long_sfb]; - uint8_t scf_size[4], iscf[40]; - int i, scf_shift = gr->scalefac_scale + 1, gain_exp, scfsi = gr->scfsi; - float gain; - - if (HDR_TEST_MPEG1(hdr)) - { - static const uint8_t g_scfc_decode[16] = { 0,1,2,3, 12,5,6,7, 9,10,11,13, 14,15,18,19 }; - int part = g_scfc_decode[gr->scalefac_compress]; - scf_size[1] = scf_size[0] = (uint8_t)(part >> 2); - scf_size[3] = scf_size[2] = (uint8_t)(part & 3); - } else - { - static const uint8_t g_mod[6*4] = { 5,5,4,4,5,5,4,1,4,3,1,1,5,6,6,1,4,4,4,1,4,3,1,1 }; - int k, modprod, sfc, ist = HDR_TEST_I_STEREO(hdr) && ch; - sfc = gr->scalefac_compress >> ist; - for (k = ist*3*4; sfc >= 0; sfc -= modprod, k += 4) - { - for (modprod = 1, i = 3; i >= 0; i--) - { - scf_size[i] = (uint8_t)(sfc / modprod % g_mod[k + i]); - modprod *= g_mod[k + i]; - } - } - scf_partition += k; - scfsi = -16; - } - L3_read_scalefactors(iscf, ist_pos, scf_size, scf_partition, bs, scfsi); - - if (gr->n_short_sfb) - { - int sh = 3 - scf_shift; - for (i = 0; i < gr->n_short_sfb; i += 3) - { - iscf[gr->n_long_sfb + i + 0] += gr->subblock_gain[0] << sh; - iscf[gr->n_long_sfb + i + 1] += gr->subblock_gain[1] << sh; - iscf[gr->n_long_sfb + i + 2] += gr->subblock_gain[2] << sh; - } - } else if (gr->preflag) - { - static const uint8_t g_preamp[10] = { 1,1,1,1,2,2,3,3,3,2 }; - for (i = 0; i < 10; i++) - { - iscf[11 + i] += g_preamp[i]; - } - } - - gain_exp = gr->global_gain + BITS_DEQUANTIZER_OUT*4 - 210 - (HDR_IS_MS_STEREO(hdr) ? 2 : 0); - gain = L3_ldexp_q2(1 << (MAX_SCFI/4), MAX_SCFI - gain_exp); - for (i = 0; i < (int)(gr->n_long_sfb + gr->n_short_sfb); i++) - { - scf[i] = L3_ldexp_q2(gain, iscf[i] << scf_shift); - } -} - -static const float g_pow43[129 + 16] = { - 0,-1,-2.519842f,-4.326749f,-6.349604f,-8.549880f,-10.902724f,-13.390518f,-16.000000f,-18.720754f,-21.544347f,-24.463781f,-27.473142f,-30.567351f,-33.741992f,-36.993181f, - 0,1,2.519842f,4.326749f,6.349604f,8.549880f,10.902724f,13.390518f,16.000000f,18.720754f,21.544347f,24.463781f,27.473142f,30.567351f,33.741992f,36.993181f,40.317474f,43.711787f,47.173345f,50.699631f,54.288352f,57.937408f,61.644865f,65.408941f,69.227979f,73.100443f,77.024898f,81.000000f,85.024491f,89.097188f,93.216975f,97.382800f,101.593667f,105.848633f,110.146801f,114.487321f,118.869381f,123.292209f,127.755065f,132.257246f,136.798076f,141.376907f,145.993119f,150.646117f,155.335327f,160.060199f,164.820202f,169.614826f,174.443577f,179.305980f,184.201575f,189.129918f,194.090580f,199.083145f,204.107210f,209.162385f,214.248292f,219.364564f,224.510845f,229.686789f,234.892058f,240.126328f,245.389280f,250.680604f,256.000000f,261.347174f,266.721841f,272.123723f,277.552547f,283.008049f,288.489971f,293.998060f,299.532071f,305.091761f,310.676898f,316.287249f,321.922592f,327.582707f,333.267377f,338.976394f,344.709550f,350.466646f,356.247482f,362.051866f,367.879608f,373.730522f,379.604427f,385.501143f,391.420496f,397.362314f,403.326427f,409.312672f,415.320884f,421.350905f,427.402579f,433.475750f,439.570269f,445.685987f,451.822757f,457.980436f,464.158883f,470.357960f,476.577530f,482.817459f,489.077615f,495.357868f,501.658090f,507.978156f,514.317941f,520.677324f,527.056184f,533.454404f,539.871867f,546.308458f,552.764065f,559.238575f,565.731879f,572.243870f,578.774440f,585.323483f,591.890898f,598.476581f,605.080431f,611.702349f,618.342238f,625.000000f,631.675540f,638.368763f,645.079578f -}; - -static float L3_pow_43(int x) -{ - float frac; - int sign, mult = 256; - - if (x < 129) - { - return g_pow43[16 + x]; - } - - if (x < 1024) - { - mult = 16; - x <<= 3; - } - - sign = 2*x & 64; - frac = (float)((x & 63) - sign) / ((x & ~63) + sign); - return g_pow43[16 + ((x + sign) >> 6)]*(1.f + frac*((4.f/3) + frac*(2.f/9)))*mult; -} - -static void L3_huffman(float *dst, bs_t *bs, const L3_gr_info_t *gr_info, const float *scf, int layer3gr_limit) -{ - static const int16_t tabs[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 785,785,785,785,784,784,784,784,513,513,513,513,513,513,513,513,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256, - -255,1313,1298,1282,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,290,288, - -255,1313,1298,1282,769,769,769,769,529,529,529,529,529,529,529,529,528,528,528,528,528,528,528,528,512,512,512,512,512,512,512,512,290,288, - -253,-318,-351,-367,785,785,785,785,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,819,818,547,547,275,275,275,275,561,560,515,546,289,274,288,258, - -254,-287,1329,1299,1314,1312,1057,1057,1042,1042,1026,1026,784,784,784,784,529,529,529,529,529,529,529,529,769,769,769,769,768,768,768,768,563,560,306,306,291,259, - -252,-413,-477,-542,1298,-575,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-383,-399,1107,1092,1106,1061,849,849,789,789,1104,1091,773,773,1076,1075,341,340,325,309,834,804,577,577,532,532,516,516,832,818,803,816,561,561,531,531,515,546,289,289,288,258, - -252,-429,-493,-559,1057,1057,1042,1042,529,529,529,529,529,529,529,529,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,-382,1077,-415,1106,1061,1104,849,849,789,789,1091,1076,1029,1075,834,834,597,581,340,340,339,324,804,833,532,532,832,772,818,803,817,787,816,771,290,290,290,290,288,258, - -253,-349,-414,-447,-463,1329,1299,-479,1314,1312,1057,1057,1042,1042,1026,1026,785,785,785,785,784,784,784,784,769,769,769,769,768,768,768,768,-319,851,821,-335,836,850,805,849,341,340,325,336,533,533,579,579,564,564,773,832,578,548,563,516,321,276,306,291,304,259, - -251,-572,-733,-830,-863,-879,1041,1041,784,784,784,784,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,1396,1351,1381,1366,1395,1335,1380,-559,1334,1138,1138,1063,1063,1350,1392,1031,1031,1062,1062,1364,1363,1120,1120,1333,1348,881,881,881,881,375,374,359,373,343,358,341,325,791,791,1123,1122,-703,1105,1045,-719,865,865,790,790,774,774,1104,1029,338,293,323,308,-799,-815,833,788,772,818,803,816,322,292,307,320,561,531,515,546,289,274,288,258, - -251,-525,-605,-685,-765,-831,-846,1298,1057,1057,1312,1282,785,785,785,785,784,784,784,784,769,769,769,769,512,512,512,512,512,512,512,512,1399,1398,1383,1367,1382,1396,1351,-511,1381,1366,1139,1139,1079,1079,1124,1124,1364,1349,1363,1333,882,882,882,882,807,807,807,807,1094,1094,1136,1136,373,341,535,535,881,775,867,822,774,-591,324,338,-671,849,550,550,866,864,609,609,293,336,534,534,789,835,773,-751,834,804,308,307,833,788,832,772,562,562,547,547,305,275,560,515,290,290, - -252,-397,-477,-557,-622,-653,-719,-735,-750,1329,1299,1314,1057,1057,1042,1042,1312,1282,1024,1024,785,785,785,785,784,784,784,784,769,769,769,769,-383,1127,1141,1111,1126,1140,1095,1110,869,869,883,883,1079,1109,882,882,375,374,807,868,838,881,791,-463,867,822,368,263,852,837,836,-543,610,610,550,550,352,336,534,534,865,774,851,821,850,805,593,533,579,564,773,832,578,578,548,548,577,577,307,276,306,291,516,560,259,259, - -250,-2107,-2507,-2764,-2909,-2974,-3007,-3023,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-767,-1052,-1213,-1277,-1358,-1405,-1469,-1535,-1550,-1582,-1614,-1647,-1662,-1694,-1726,-1759,-1774,-1807,-1822,-1854,-1886,1565,-1919,-1935,-1951,-1967,1731,1730,1580,1717,-1983,1729,1564,-1999,1548,-2015,-2031,1715,1595,-2047,1714,-2063,1610,-2079,1609,-2095,1323,1323,1457,1457,1307,1307,1712,1547,1641,1700,1699,1594,1685,1625,1442,1442,1322,1322,-780,-973,-910,1279,1278,1277,1262,1276,1261,1275,1215,1260,1229,-959,974,974,989,989,-943,735,478,478,495,463,506,414,-1039,1003,958,1017,927,942,987,957,431,476,1272,1167,1228,-1183,1256,-1199,895,895,941,941,1242,1227,1212,1135,1014,1014,490,489,503,487,910,1013,985,925,863,894,970,955,1012,847,-1343,831,755,755,984,909,428,366,754,559,-1391,752,486,457,924,997,698,698,983,893,740,740,908,877,739,739,667,667,953,938,497,287,271,271,683,606,590,712,726,574,302,302,738,736,481,286,526,725,605,711,636,724,696,651,589,681,666,710,364,467,573,695,466,466,301,465,379,379,709,604,665,679,316,316,634,633,436,436,464,269,424,394,452,332,438,363,347,408,393,448,331,422,362,407,392,421,346,406,391,376,375,359,1441,1306,-2367,1290,-2383,1337,-2399,-2415,1426,1321,-2431,1411,1336,-2447,-2463,-2479,1169,1169,1049,1049,1424,1289,1412,1352,1319,-2495,1154,1154,1064,1064,1153,1153,416,390,360,404,403,389,344,374,373,343,358,372,327,357,342,311,356,326,1395,1394,1137,1137,1047,1047,1365,1392,1287,1379,1334,1364,1349,1378,1318,1363,792,792,792,792,1152,1152,1032,1032,1121,1121,1046,1046,1120,1120,1030,1030,-2895,1106,1061,1104,849,849,789,789,1091,1076,1029,1090,1060,1075,833,833,309,324,532,532,832,772,818,803,561,561,531,560,515,546,289,274,288,258, - -250,-1179,-1579,-1836,-1996,-2124,-2253,-2333,-2413,-2477,-2542,-2574,-2607,-2622,-2655,1314,1313,1298,1312,1282,785,785,785,785,1040,1040,1025,1025,768,768,768,768,-766,-798,-830,-862,-895,-911,-927,-943,-959,-975,-991,-1007,-1023,-1039,-1055,-1070,1724,1647,-1103,-1119,1631,1767,1662,1738,1708,1723,-1135,1780,1615,1779,1599,1677,1646,1778,1583,-1151,1777,1567,1737,1692,1765,1722,1707,1630,1751,1661,1764,1614,1736,1676,1763,1750,1645,1598,1721,1691,1762,1706,1582,1761,1566,-1167,1749,1629,767,766,751,765,494,494,735,764,719,749,734,763,447,447,748,718,477,506,431,491,446,476,461,505,415,430,475,445,504,399,460,489,414,503,383,474,429,459,502,502,746,752,488,398,501,473,413,472,486,271,480,270,-1439,-1455,1357,-1471,-1487,-1503,1341,1325,-1519,1489,1463,1403,1309,-1535,1372,1448,1418,1476,1356,1462,1387,-1551,1475,1340,1447,1402,1386,-1567,1068,1068,1474,1461,455,380,468,440,395,425,410,454,364,467,466,464,453,269,409,448,268,432,1371,1473,1432,1417,1308,1460,1355,1446,1459,1431,1083,1083,1401,1416,1458,1445,1067,1067,1370,1457,1051,1051,1291,1430,1385,1444,1354,1415,1400,1443,1082,1082,1173,1113,1186,1066,1185,1050,-1967,1158,1128,1172,1097,1171,1081,-1983,1157,1112,416,266,375,400,1170,1142,1127,1065,793,793,1169,1033,1156,1096,1141,1111,1155,1080,1126,1140,898,898,808,808,897,897,792,792,1095,1152,1032,1125,1110,1139,1079,1124,882,807,838,881,853,791,-2319,867,368,263,822,852,837,866,806,865,-2399,851,352,262,534,534,821,836,594,594,549,549,593,593,533,533,848,773,579,579,564,578,548,563,276,276,577,576,306,291,516,560,305,305,275,259, - -251,-892,-2058,-2620,-2828,-2957,-3023,-3039,1041,1041,1040,1040,769,769,769,769,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,-511,-527,-543,-559,1530,-575,-591,1528,1527,1407,1526,1391,1023,1023,1023,1023,1525,1375,1268,1268,1103,1103,1087,1087,1039,1039,1523,-604,815,815,815,815,510,495,509,479,508,463,507,447,431,505,415,399,-734,-782,1262,-815,1259,1244,-831,1258,1228,-847,-863,1196,-879,1253,987,987,748,-767,493,493,462,477,414,414,686,669,478,446,461,445,474,429,487,458,412,471,1266,1264,1009,1009,799,799,-1019,-1276,-1452,-1581,-1677,-1757,-1821,-1886,-1933,-1997,1257,1257,1483,1468,1512,1422,1497,1406,1467,1496,1421,1510,1134,1134,1225,1225,1466,1451,1374,1405,1252,1252,1358,1480,1164,1164,1251,1251,1238,1238,1389,1465,-1407,1054,1101,-1423,1207,-1439,830,830,1248,1038,1237,1117,1223,1148,1236,1208,411,426,395,410,379,269,1193,1222,1132,1235,1221,1116,976,976,1192,1162,1177,1220,1131,1191,963,963,-1647,961,780,-1663,558,558,994,993,437,408,393,407,829,978,813,797,947,-1743,721,721,377,392,844,950,828,890,706,706,812,859,796,960,948,843,934,874,571,571,-1919,690,555,689,421,346,539,539,944,779,918,873,932,842,903,888,570,570,931,917,674,674,-2575,1562,-2591,1609,-2607,1654,1322,1322,1441,1441,1696,1546,1683,1593,1669,1624,1426,1426,1321,1321,1639,1680,1425,1425,1305,1305,1545,1668,1608,1623,1667,1592,1638,1666,1320,1320,1652,1607,1409,1409,1304,1304,1288,1288,1664,1637,1395,1395,1335,1335,1622,1636,1394,1394,1319,1319,1606,1621,1392,1392,1137,1137,1137,1137,345,390,360,375,404,373,1047,-2751,-2767,-2783,1062,1121,1046,-2799,1077,-2815,1106,1061,789,789,1105,1104,263,355,310,340,325,354,352,262,339,324,1091,1076,1029,1090,1060,1075,833,833,788,788,1088,1028,818,818,803,803,561,561,531,531,816,771,546,546,289,274,288,258, - -253,-317,-381,-446,-478,-509,1279,1279,-811,-1179,-1451,-1756,-1900,-2028,-2189,-2253,-2333,-2414,-2445,-2511,-2526,1313,1298,-2559,1041,1041,1040,1040,1025,1025,1024,1024,1022,1007,1021,991,1020,975,1019,959,687,687,1018,1017,671,671,655,655,1016,1015,639,639,758,758,623,623,757,607,756,591,755,575,754,559,543,543,1009,783,-575,-621,-685,-749,496,-590,750,749,734,748,974,989,1003,958,988,973,1002,942,987,957,972,1001,926,986,941,971,956,1000,910,985,925,999,894,970,-1071,-1087,-1102,1390,-1135,1436,1509,1451,1374,-1151,1405,1358,1480,1420,-1167,1507,1494,1389,1342,1465,1435,1450,1326,1505,1310,1493,1373,1479,1404,1492,1464,1419,428,443,472,397,736,526,464,464,486,457,442,471,484,482,1357,1449,1434,1478,1388,1491,1341,1490,1325,1489,1463,1403,1309,1477,1372,1448,1418,1433,1476,1356,1462,1387,-1439,1475,1340,1447,1402,1474,1324,1461,1371,1473,269,448,1432,1417,1308,1460,-1711,1459,-1727,1441,1099,1099,1446,1386,1431,1401,-1743,1289,1083,1083,1160,1160,1458,1445,1067,1067,1370,1457,1307,1430,1129,1129,1098,1098,268,432,267,416,266,400,-1887,1144,1187,1082,1173,1113,1186,1066,1050,1158,1128,1143,1172,1097,1171,1081,420,391,1157,1112,1170,1142,1127,1065,1169,1049,1156,1096,1141,1111,1155,1080,1126,1154,1064,1153,1140,1095,1048,-2159,1125,1110,1137,-2175,823,823,1139,1138,807,807,384,264,368,263,868,838,853,791,867,822,852,837,866,806,865,790,-2319,851,821,836,352,262,850,805,849,-2399,533,533,835,820,336,261,578,548,563,577,532,532,832,772,562,562,547,547,305,275,560,515,290,290,288,258 }; - static const uint8_t tab32[] = { 130,162,193,209,44,28,76,140,9,9,9,9,9,9,9,9,190,254,222,238,126,94,157,157,109,61,173,205 }; - static const uint8_t tab33[] = { 252,236,220,204,188,172,156,140,124,108,92,76,60,44,28,12 }; - static const int16_t tabindex[2*16] = { 0,32,64,98,0,132,180,218,292,364,426,538,648,746,0,1126,1460,1460,1460,1460,1460,1460,1460,1460,1842,1842,1842,1842,1842,1842,1842,1842 }; - static const uint8_t g_linbits[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,2,3,4,6,8,10,13,4,5,6,7,8,9,11,13 }; - -#define PEEK_BITS(n) (bs_cache >> (32 - n)) -#define FLUSH_BITS(n) { bs_cache <<= (n); bs_sh += (n); } -#define CHECK_BITS while (bs_sh >= 0) { bs_cache |= (uint32_t)*bs_next_ptr++ << bs_sh; bs_sh -= 8; } -#define BSPOS ((bs_next_ptr - bs->buf)*8 - 24 + bs_sh) - - float one = 0.0f; - int ireg = 0, big_val_cnt = gr_info->big_values; - const uint8_t *sfb = gr_info->sfbtab; - const uint8_t *bs_next_ptr = bs->buf + bs->pos/8; - uint32_t bs_cache = (((bs_next_ptr[0]*256u + bs_next_ptr[1])*256u + bs_next_ptr[2])*256u + bs_next_ptr[3]) << (bs->pos & 7); - int pairs_to_decode, np, bs_sh = (bs->pos & 7) - 8; - bs_next_ptr += 4; - - while (big_val_cnt > 0) - { - int tab_num = gr_info->table_select[ireg]; - int sfb_cnt = gr_info->region_count[ireg++]; - const int16_t *codebook = tabs + tabindex[tab_num]; - int linbits = g_linbits[tab_num]; - if (linbits) - { - do - { - np = *sfb++ / 2; - pairs_to_decode = MINIMP3_MIN(big_val_cnt, np); - one = *scf++; - do - { - int j, w = 5; - int leaf = codebook[PEEK_BITS(w)]; - while (leaf < 0) - { - FLUSH_BITS(w); - w = leaf & 7; - leaf = codebook[PEEK_BITS(w) - (leaf >> 3)]; - } - FLUSH_BITS(leaf >> 8); - - for (j = 0; j < 2; j++, dst++, leaf >>= 4) - { - int lsb = leaf & 0x0F; - if (lsb == 15) - { - lsb += PEEK_BITS(linbits); - FLUSH_BITS(linbits); - CHECK_BITS; - *dst = one*L3_pow_43(lsb)*((int32_t)bs_cache < 0 ? -1: 1); - } else - { - *dst = g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; - } - FLUSH_BITS(lsb ? 1 : 0); - } - CHECK_BITS; - } while (--pairs_to_decode); - } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); - } else - { - do - { - np = *sfb++ / 2; - pairs_to_decode = MINIMP3_MIN(big_val_cnt, np); - one = *scf++; - do - { - int j, w = 5; - int leaf = codebook[PEEK_BITS(w)]; - while (leaf < 0) - { - FLUSH_BITS(w); - w = leaf & 7; - leaf = codebook[PEEK_BITS(w) - (leaf >> 3)]; - } - FLUSH_BITS(leaf >> 8); - - for (j = 0; j < 2; j++, dst++, leaf >>= 4) - { - int lsb = leaf & 0x0F; - *dst = g_pow43[16 + lsb - 16*(bs_cache >> 31)]*one; - FLUSH_BITS(lsb ? 1 : 0); - } - CHECK_BITS; - } while (--pairs_to_decode); - } while ((big_val_cnt -= np) > 0 && --sfb_cnt >= 0); - } - } - - for (np = 1 - big_val_cnt;; dst += 4) - { - const uint8_t *codebook_count1 = (gr_info->count1_table) ? tab33 : tab32; - int leaf = codebook_count1[PEEK_BITS(4)]; - if (!(leaf & 8)) - { - leaf = codebook_count1[(leaf >> 3) + (bs_cache << 4 >> (32 - (leaf & 3)))]; - } - FLUSH_BITS(leaf & 7); - if (BSPOS > layer3gr_limit) - { - break; - } -#define RELOAD_SCALEFACTOR if (!--np) { np = *sfb++/2; if (!np) break; one = *scf++; } -#define DEQ_COUNT1(s) if (leaf & (128 >> s)) { dst[s] = ((int32_t)bs_cache < 0) ? -one : one; FLUSH_BITS(1) } - RELOAD_SCALEFACTOR; - DEQ_COUNT1(0); - DEQ_COUNT1(1); - RELOAD_SCALEFACTOR; - DEQ_COUNT1(2); - DEQ_COUNT1(3); - CHECK_BITS; - } - - bs->pos = layer3gr_limit; -} - -static void L3_midside_stereo(float *left, int n) -{ - int i = 0; - float *right = left + 576; -#if HAVE_SIMD - if (have_simd()) for (; i < n - 3; i += 4) - { - f4 vl = VLD(left + i); - f4 vr = VLD(right + i); - VSTORE(left + i, VADD(vl, vr)); - VSTORE(right + i, VSUB(vl, vr)); - } -#endif /* HAVE_SIMD */ - for (; i < n; i++) - { - float a = left[i]; - float b = right[i]; - left[i] = a + b; - right[i] = a - b; - } -} - -static void L3_intensity_stereo_band(float *left, int n, float kl, float kr) -{ - int i; - for (i = 0; i < n; i++) - { - left[i + 576] = left[i]*kr; - left[i] = left[i]*kl; - } -} - -static void L3_stereo_top_band(const float *right, const uint8_t *sfb, int nbands, int max_band[3]) -{ - int i, k; - - max_band[0] = max_band[1] = max_band[2] = -1; - - for (i = 0; i < nbands; i++) - { - for (k = 0; k < sfb[i]; k += 2) - { - if (right[k] != 0 || right[k + 1] != 0) - { - max_band[i % 3] = i; - break; - } - } - right += sfb[i]; - } -} - -static void L3_stereo_process(float *left, const uint8_t *ist_pos, const uint8_t *sfb, const uint8_t *hdr, int max_band[3], int mpeg2_sh) -{ - static const float g_pan[7*2] = { 0,1,0.21132487f,0.78867513f,0.36602540f,0.63397460f,0.5f,0.5f,0.63397460f,0.36602540f,0.78867513f,0.21132487f,1,0 }; - unsigned i, max_pos = HDR_TEST_MPEG1(hdr) ? 7 : 64; - - for (i = 0; sfb[i]; i++) - { - unsigned ipos = ist_pos[i]; - if ((int)i > max_band[i % 3] && ipos < max_pos) - { - float kl, kr, s = HDR_TEST_MS_STEREO(hdr) ? 1.41421356f : 1; - if (HDR_TEST_MPEG1(hdr)) - { - kl = g_pan[2*ipos]; - kr = g_pan[2*ipos + 1]; - } else - { - kl = 1; - kr = L3_ldexp_q2(1, (ipos + 1) >> 1 << mpeg2_sh); - if (ipos & 1) - { - kl = kr; - kr = 1; - } - } - L3_intensity_stereo_band(left, sfb[i], kl*s, kr*s); - } else if (HDR_TEST_MS_STEREO(hdr)) - { - L3_midside_stereo(left, sfb[i]); - } - left += sfb[i]; - } -} - -static void L3_intensity_stereo(float *left, uint8_t *ist_pos, const L3_gr_info_t *gr, const uint8_t *hdr) -{ - int max_band[3], n_sfb = gr->n_long_sfb + gr->n_short_sfb; - int i, max_blocks = gr->n_short_sfb ? 3 : 1; - - L3_stereo_top_band(left + 576, gr->sfbtab, n_sfb, max_band); - if (gr->n_long_sfb) - { - max_band[0] = max_band[1] = max_band[2] = MINIMP3_MAX(MINIMP3_MAX(max_band[0], max_band[1]), max_band[2]); - } - for (i = 0; i < max_blocks; i++) - { - int default_pos = HDR_TEST_MPEG1(hdr) ? 3 : 0; - int itop = n_sfb - max_blocks + i; - int prev = itop - max_blocks; - ist_pos[itop] = max_band[i] >= prev ? default_pos : ist_pos[prev]; - } - L3_stereo_process(left, ist_pos, gr->sfbtab, hdr, max_band, gr[1].scalefac_compress & 1); -} - -static void L3_reorder(float *grbuf, float *scratch, const uint8_t *sfb) -{ - int i, len; - float *src = grbuf, *dst = scratch; - - for (;0 != (len = *sfb); sfb += 3, src += 2*len) - { - for (i = 0; i < len; i++, src++) - { - *dst++ = src[0*len]; - *dst++ = src[1*len]; - *dst++ = src[2*len]; - } - } - memcpy(grbuf, scratch, (dst - scratch)*sizeof(float)); -} - -static void L3_antialias(float *grbuf, int nbands) -{ - static const float g_aa[2][8] = { - {0.85749293f,0.88174200f,0.94962865f,0.98331459f,0.99551782f,0.99916056f,0.99989920f,0.99999316f}, - {0.51449576f,0.47173197f,0.31337745f,0.18191320f,0.09457419f,0.04096558f,0.01419856f,0.00369997f} - }; - - for (; nbands > 0; nbands--, grbuf += 18) - { - int i = 0; -#if HAVE_SIMD - if (have_simd()) for (; i < 8; i += 4) - { - f4 vu = VLD(grbuf + 18 + i); - f4 vd = VLD(grbuf + 14 - i); - f4 vc0 = VLD(g_aa[0] + i); - f4 vc1 = VLD(g_aa[1] + i); - vd = VREV(vd); - VSTORE(grbuf + 18 + i, VSUB(VMUL(vu, vc0), VMUL(vd, vc1))); - vd = VADD(VMUL(vu, vc1), VMUL(vd, vc0)); - VSTORE(grbuf + 14 - i, VREV(vd)); - } -#endif /* HAVE_SIMD */ -#ifndef MINIMP3_ONLY_SIMD - for(; i < 8; i++) - { - float u = grbuf[18 + i]; - float d = grbuf[17 - i]; - grbuf[18 + i] = u*g_aa[0][i] - d*g_aa[1][i]; - grbuf[17 - i] = u*g_aa[1][i] + d*g_aa[0][i]; - } -#endif /* MINIMP3_ONLY_SIMD */ - } -} - -static void L3_dct3_9(float *y) -{ - float s0, s1, s2, s3, s4, s5, s6, s7, s8, t0, t2, t4; - - s0 = y[0]; s2 = y[2]; s4 = y[4]; s6 = y[6]; s8 = y[8]; - t0 = s0 + s6*0.5f; - s0 -= s6; - t4 = (s4 + s2)*0.93969262f; - t2 = (s8 + s2)*0.76604444f; - s6 = (s4 - s8)*0.17364818f; - s4 += s8 - s2; - - s2 = s0 - s4*0.5f; - y[4] = s4 + s0; - s8 = t0 - t2 + s6; - s0 = t0 - t4 + t2; - s4 = t0 + t4 - s6; - - s1 = y[1]; s3 = y[3]; s5 = y[5]; s7 = y[7]; - - s3 *= 0.86602540f; - t0 = (s5 + s1)*0.98480775f; - t4 = (s5 - s7)*0.34202014f; - t2 = (s1 + s7)*0.64278761f; - s1 = (s1 - s5 - s7)*0.86602540f; - - s5 = t0 - s3 - t2; - s7 = t4 - s3 - t0; - s3 = t4 + s3 - t2; - - y[0] = s4 - s7; - y[1] = s2 + s1; - y[2] = s0 - s3; - y[3] = s8 + s5; - y[5] = s8 - s5; - y[6] = s0 + s3; - y[7] = s2 - s1; - y[8] = s4 + s7; -} - -static void L3_imdct36(float *grbuf, float *overlap, const float *window, int nbands) -{ - int i, j; - static const float g_twid9[18] = { - 0.73727734f,0.79335334f,0.84339145f,0.88701083f,0.92387953f,0.95371695f,0.97629601f,0.99144486f,0.99904822f,0.67559021f,0.60876143f,0.53729961f,0.46174861f,0.38268343f,0.30070580f,0.21643961f,0.13052619f,0.04361938f - }; - - for (j = 0; j < nbands; j++, grbuf += 18, overlap += 9) - { - float co[9], si[9]; - co[0] = -grbuf[0]; - si[0] = grbuf[17]; - for (i = 0; i < 4; i++) - { - si[8 - 2*i] = grbuf[4*i + 1] - grbuf[4*i + 2]; - co[1 + 2*i] = grbuf[4*i + 1] + grbuf[4*i + 2]; - si[7 - 2*i] = grbuf[4*i + 4] - grbuf[4*i + 3]; - co[2 + 2*i] = -(grbuf[4*i + 3] + grbuf[4*i + 4]); - } - L3_dct3_9(co); - L3_dct3_9(si); - - si[1] = -si[1]; - si[3] = -si[3]; - si[5] = -si[5]; - si[7] = -si[7]; - - i = 0; - -#if HAVE_SIMD - if (have_simd()) for (; i < 8; i += 4) - { - f4 vovl = VLD(overlap + i); - f4 vc = VLD(co + i); - f4 vs = VLD(si + i); - f4 vr0 = VLD(g_twid9 + i); - f4 vr1 = VLD(g_twid9 + 9 + i); - f4 vw0 = VLD(window + i); - f4 vw1 = VLD(window + 9 + i); - f4 vsum = VADD(VMUL(vc, vr1), VMUL(vs, vr0)); - VSTORE(overlap + i, VSUB(VMUL(vc, vr0), VMUL(vs, vr1))); - VSTORE(grbuf + i, VSUB(VMUL(vovl, vw0), VMUL(vsum, vw1))); - vsum = VADD(VMUL(vovl, vw1), VMUL(vsum, vw0)); - VSTORE(grbuf + 14 - i, VREV(vsum)); - } -#endif /* HAVE_SIMD */ - for (; i < 9; i++) - { - float ovl = overlap[i]; - float sum = co[i]*g_twid9[9 + i] + si[i]*g_twid9[0 + i]; - overlap[i] = co[i]*g_twid9[0 + i] - si[i]*g_twid9[9 + i]; - grbuf[i] = ovl*window[0 + i] - sum*window[9 + i]; - grbuf[17 - i] = ovl*window[9 + i] + sum*window[0 + i]; - } - } -} - -static void L3_idct3(float x0, float x1, float x2, float *dst) -{ - float m1 = x1*0.86602540f; - float a1 = x0 - x2*0.5f; - dst[1] = x0 + x2; - dst[0] = a1 + m1; - dst[2] = a1 - m1; -} - -static void L3_imdct12(float *x, float *dst, float *overlap) -{ - static const float g_twid3[6] = { 0.79335334f,0.92387953f,0.99144486f, 0.60876143f,0.38268343f,0.13052619f }; - float co[3], si[3]; - int i; - - L3_idct3(-x[0], x[6] + x[3], x[12] + x[9], co); - L3_idct3(x[15], x[12] - x[9], x[6] - x[3], si); - si[1] = -si[1]; - - for (i = 0; i < 3; i++) - { - float ovl = overlap[i]; - float sum = co[i]*g_twid3[3 + i] + si[i]*g_twid3[0 + i]; - overlap[i] = co[i]*g_twid3[0 + i] - si[i]*g_twid3[3 + i]; - dst[i] = ovl*g_twid3[2 - i] - sum*g_twid3[5 - i]; - dst[5 - i] = ovl*g_twid3[5 - i] + sum*g_twid3[2 - i]; - } -} - -static void L3_imdct_short(float *grbuf, float *overlap, int nbands) -{ - for (;nbands > 0; nbands--, overlap += 9, grbuf += 18) - { - float tmp[18]; - memcpy(tmp, grbuf, sizeof(tmp)); - memcpy(grbuf, overlap, 6*sizeof(float)); - L3_imdct12(tmp, grbuf + 6, overlap + 6); - L3_imdct12(tmp + 1, grbuf + 12, overlap + 6); - L3_imdct12(tmp + 2, overlap, overlap + 6); - } -} - -static void L3_change_sign(float *grbuf) -{ - int b, i; - for (b = 0, grbuf += 18; b < 32; b += 2, grbuf += 36) - for (i = 1; i < 18; i += 2) - grbuf[i] = -grbuf[i]; -} - -static void L3_imdct_gr(float *grbuf, float *overlap, unsigned block_type, unsigned n_long_bands) -{ - static const float g_mdct_window[2][18] = { - { 0.99904822f,0.99144486f,0.97629601f,0.95371695f,0.92387953f,0.88701083f,0.84339145f,0.79335334f,0.73727734f,0.04361938f,0.13052619f,0.21643961f,0.30070580f,0.38268343f,0.46174861f,0.53729961f,0.60876143f,0.67559021f }, - { 1,1,1,1,1,1,0.99144486f,0.92387953f,0.79335334f,0,0,0,0,0,0,0.13052619f,0.38268343f,0.60876143f } - }; - if (n_long_bands) - { - L3_imdct36(grbuf, overlap, g_mdct_window[0], n_long_bands); - grbuf += 18*n_long_bands; - overlap += 9*n_long_bands; - } - if (block_type == SHORT_BLOCK_TYPE) - L3_imdct_short(grbuf, overlap, 32 - n_long_bands); - else - L3_imdct36(grbuf, overlap, g_mdct_window[block_type == STOP_BLOCK_TYPE], 32 - n_long_bands); -} - -static void L3_save_reservoir(mp3dec_t *h, mp3dec_scratch_t *s) -{ - int pos = (s->bs.pos + 7)/8u; - int remains = s->bs.limit/8u - pos; - if (remains > MAX_BITRESERVOIR_BYTES) - { - pos += remains - MAX_BITRESERVOIR_BYTES; - remains = MAX_BITRESERVOIR_BYTES; - } - if (remains > 0) - { - memmove(h->reserv_buf, s->maindata + pos, remains); - } - h->reserv = remains; -} - -static int L3_restore_reservoir(mp3dec_t *h, bs_t *bs, mp3dec_scratch_t *s, int main_data_begin) -{ - int frame_bytes = (bs->limit - bs->pos)/8; - int bytes_have = MINIMP3_MIN(h->reserv, main_data_begin); - memcpy(s->maindata, h->reserv_buf + MINIMP3_MAX(0, h->reserv - main_data_begin), MINIMP3_MIN(h->reserv, main_data_begin)); - memcpy(s->maindata + bytes_have, bs->buf + bs->pos/8, frame_bytes); - bs_init(&s->bs, s->maindata, bytes_have + frame_bytes); - return h->reserv >= main_data_begin; -} - -static void L3_decode(mp3dec_t *h, mp3dec_scratch_t *s, L3_gr_info_t *gr_info, int nch) -{ - int ch; - - for (ch = 0; ch < nch; ch++) - { - int layer3gr_limit = s->bs.pos + gr_info[ch].part_23_length; - L3_decode_scalefactors(h->header, s->ist_pos[ch], &s->bs, gr_info + ch, s->scf, ch); - L3_huffman(s->grbuf[ch], &s->bs, gr_info + ch, s->scf, layer3gr_limit); - } - - if (HDR_TEST_I_STEREO(h->header)) - { - L3_intensity_stereo(s->grbuf[0], s->ist_pos[1], gr_info, h->header); - } else if (HDR_IS_MS_STEREO(h->header)) - { - L3_midside_stereo(s->grbuf[0], 576); - } - - for (ch = 0; ch < nch; ch++, gr_info++) - { - int aa_bands = 31; - int n_long_bands = (gr_info->mixed_block_flag ? 2 : 0) << (int)(HDR_GET_MY_SAMPLE_RATE(h->header) == 2); - - if (gr_info->n_short_sfb) - { - aa_bands = n_long_bands - 1; - L3_reorder(s->grbuf[ch] + n_long_bands*18, s->syn[0], gr_info->sfbtab + gr_info->n_long_sfb); - } - - L3_antialias(s->grbuf[ch], aa_bands); - L3_imdct_gr(s->grbuf[ch], h->mdct_overlap[ch], gr_info->block_type, n_long_bands); - L3_change_sign(s->grbuf[ch]); - } -} - -static void mp3d_DCT_II(float *grbuf, int n) -{ - static const float g_sec[24] = { - 10.19000816f,0.50060302f,0.50241929f,3.40760851f,0.50547093f,0.52249861f,2.05778098f,0.51544732f,0.56694406f,1.48416460f,0.53104258f,0.64682180f,1.16943991f,0.55310392f,0.78815460f,0.97256821f,0.58293498f,1.06067765f,0.83934963f,0.62250412f,1.72244716f,0.74453628f,0.67480832f,5.10114861f - }; - int i, k = 0; -#if HAVE_SIMD - if (have_simd()) for (; k < n; k += 4) - { - f4 t[4][8], *x; - float *y = grbuf + k; - - for (x = t[0], i = 0; i < 8; i++, x++) - { - f4 x0 = VLD(&y[i*18]); - f4 x1 = VLD(&y[(15 - i)*18]); - f4 x2 = VLD(&y[(16 + i)*18]); - f4 x3 = VLD(&y[(31 - i)*18]); - f4 t0 = VADD(x0, x3); - f4 t1 = VADD(x1, x2); - f4 t2 = VMUL_S(VSUB(x1, x2), g_sec[3*i + 0]); - f4 t3 = VMUL_S(VSUB(x0, x3), g_sec[3*i + 1]); - x[0] = VADD(t0, t1); - x[8] = VMUL_S(VSUB(t0, t1), g_sec[3*i + 2]); - x[16] = VADD(t3, t2); - x[24] = VMUL_S(VSUB(t3, t2), g_sec[3*i + 2]); - } - for (x = t[0], i = 0; i < 4; i++, x += 8) - { - f4 x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt; - xt = VSUB(x0, x7); x0 = VADD(x0, x7); - x7 = VSUB(x1, x6); x1 = VADD(x1, x6); - x6 = VSUB(x2, x5); x2 = VADD(x2, x5); - x5 = VSUB(x3, x4); x3 = VADD(x3, x4); - x4 = VSUB(x0, x3); x0 = VADD(x0, x3); - x3 = VSUB(x1, x2); x1 = VADD(x1, x2); - x[0] = VADD(x0, x1); - x[4] = VMUL_S(VSUB(x0, x1), 0.70710677f); - x5 = VADD(x5, x6); - x6 = VMUL_S(VADD(x6, x7), 0.70710677f); - x7 = VADD(x7, xt); - x3 = VMUL_S(VADD(x3, x4), 0.70710677f); - x5 = VSUB(x5, VMUL_S(x7, 0.198912367f)); /* rotate by PI/8 */ - x7 = VADD(x7, VMUL_S(x5, 0.382683432f)); - x5 = VSUB(x5, VMUL_S(x7, 0.198912367f)); - x0 = VSUB(xt, x6); xt = VADD(xt, x6); - x[1] = VMUL_S(VADD(xt, x7), 0.50979561f); - x[2] = VMUL_S(VADD(x4, x3), 0.54119611f); - x[3] = VMUL_S(VSUB(x0, x5), 0.60134488f); - x[5] = VMUL_S(VADD(x0, x5), 0.89997619f); - x[6] = VMUL_S(VSUB(x4, x3), 1.30656302f); - x[7] = VMUL_S(VSUB(xt, x7), 2.56291556f); - } - - if (k > n - 3) - { -#if HAVE_SSE -#define VSAVE2(i, v) _mm_storel_pi((__m64 *)(void*)&y[i*18], v) -#else /* HAVE_SSE */ -#define VSAVE2(i, v) vst1_f32((float32_t *)&y[i*18], vget_low_f32(v)) -#endif /* HAVE_SSE */ - for (i = 0; i < 7; i++, y += 4*18) - { - f4 s = VADD(t[3][i], t[3][i + 1]); - VSAVE2(0, t[0][i]); - VSAVE2(1, VADD(t[2][i], s)); - VSAVE2(2, VADD(t[1][i], t[1][i + 1])); - VSAVE2(3, VADD(t[2][1 + i], s)); - } - VSAVE2(0, t[0][7]); - VSAVE2(1, VADD(t[2][7], t[3][7])); - VSAVE2(2, t[1][7]); - VSAVE2(3, t[3][7]); - } else - { -#define VSAVE4(i, v) VSTORE(&y[i*18], v) - for (i = 0; i < 7; i++, y += 4*18) - { - f4 s = VADD(t[3][i], t[3][i + 1]); - VSAVE4(0, t[0][i]); - VSAVE4(1, VADD(t[2][i], s)); - VSAVE4(2, VADD(t[1][i], t[1][i + 1])); - VSAVE4(3, VADD(t[2][1 + i], s)); - } - VSAVE4(0, t[0][7]); - VSAVE4(1, VADD(t[2][7], t[3][7])); - VSAVE4(2, t[1][7]); - VSAVE4(3, t[3][7]); - } - } else -#endif /* HAVE_SIMD */ -#ifdef MINIMP3_ONLY_SIMD - {} /* for HAVE_SIMD=1, MINIMP3_ONLY_SIMD=1 case we do not need non-intrinsic "else" branch */ -#else /* MINIMP3_ONLY_SIMD */ - for (; k < n; k++) - { - float t[4][8], *x, *y = grbuf + k; - - for (x = t[0], i = 0; i < 8; i++, x++) - { - float x0 = y[i*18]; - float x1 = y[(15 - i)*18]; - float x2 = y[(16 + i)*18]; - float x3 = y[(31 - i)*18]; - float t0 = x0 + x3; - float t1 = x1 + x2; - float t2 = (x1 - x2)*g_sec[3*i + 0]; - float t3 = (x0 - x3)*g_sec[3*i + 1]; - x[0] = t0 + t1; - x[8] = (t0 - t1)*g_sec[3*i + 2]; - x[16] = t3 + t2; - x[24] = (t3 - t2)*g_sec[3*i + 2]; - } - for (x = t[0], i = 0; i < 4; i++, x += 8) - { - float x0 = x[0], x1 = x[1], x2 = x[2], x3 = x[3], x4 = x[4], x5 = x[5], x6 = x[6], x7 = x[7], xt; - xt = x0 - x7; x0 += x7; - x7 = x1 - x6; x1 += x6; - x6 = x2 - x5; x2 += x5; - x5 = x3 - x4; x3 += x4; - x4 = x0 - x3; x0 += x3; - x3 = x1 - x2; x1 += x2; - x[0] = x0 + x1; - x[4] = (x0 - x1)*0.70710677f; - x5 = x5 + x6; - x6 = (x6 + x7)*0.70710677f; - x7 = x7 + xt; - x3 = (x3 + x4)*0.70710677f; - x5 -= x7*0.198912367f; /* rotate by PI/8 */ - x7 += x5*0.382683432f; - x5 -= x7*0.198912367f; - x0 = xt - x6; xt += x6; - x[1] = (xt + x7)*0.50979561f; - x[2] = (x4 + x3)*0.54119611f; - x[3] = (x0 - x5)*0.60134488f; - x[5] = (x0 + x5)*0.89997619f; - x[6] = (x4 - x3)*1.30656302f; - x[7] = (xt - x7)*2.56291556f; - - } - for (i = 0; i < 7; i++, y += 4*18) - { - y[0*18] = t[0][i]; - y[1*18] = t[2][i] + t[3][i] + t[3][i + 1]; - y[2*18] = t[1][i] + t[1][i + 1]; - y[3*18] = t[2][i + 1] + t[3][i] + t[3][i + 1]; - } - y[0*18] = t[0][7]; - y[1*18] = t[2][7] + t[3][7]; - y[2*18] = t[1][7]; - y[3*18] = t[3][7]; - } -#endif /* MINIMP3_ONLY_SIMD */ -} - -#ifndef MINIMP3_FLOAT_OUTPUT -static int16_t mp3d_scale_pcm(float sample) -{ -#if HAVE_ARMV6 - int32_t s32 = (int32_t)(sample + .5f); - s32 -= (s32 < 0); - int16_t s = (int16_t)minimp3_clip_int16_arm(s32); -#else - if (sample >= 32766.5) return (int16_t) 32767; - if (sample <= -32767.5) return (int16_t)-32768; - int16_t s = (int16_t)(sample + .5f); - s -= (s < 0); /* away from zero, to be compliant */ -#endif - return s; -} -#else /* MINIMP3_FLOAT_OUTPUT */ -static float mp3d_scale_pcm(float sample) -{ - return sample*(1.f/32768.f); -} -#endif /* MINIMP3_FLOAT_OUTPUT */ - -static void mp3d_synth_pair(mp3d_sample_t *pcm, int nch, const float *z) -{ - float a; - a = (z[14*64] - z[ 0]) * 29; - a += (z[ 1*64] + z[13*64]) * 213; - a += (z[12*64] - z[ 2*64]) * 459; - a += (z[ 3*64] + z[11*64]) * 2037; - a += (z[10*64] - z[ 4*64]) * 5153; - a += (z[ 5*64] + z[ 9*64]) * 6574; - a += (z[ 8*64] - z[ 6*64]) * 37489; - a += z[ 7*64] * 75038; - pcm[0] = mp3d_scale_pcm(a); - - z += 2; - a = z[14*64] * 104; - a += z[12*64] * 1567; - a += z[10*64] * 9727; - a += z[ 8*64] * 64019; - a += z[ 6*64] * -9975; - a += z[ 4*64] * -45; - a += z[ 2*64] * 146; - a += z[ 0*64] * -5; - pcm[16*nch] = mp3d_scale_pcm(a); -} - -static void mp3d_synth(float *xl, mp3d_sample_t *dstl, int nch, float *lins) -{ - int i; - float *xr = xl + 576*(nch - 1); - mp3d_sample_t *dstr = dstl + (nch - 1); - - static const float g_win[] = { - -1,26,-31,208,218,401,-519,2063,2000,4788,-5517,7134,5959,35640,-39336,74992, - -1,24,-35,202,222,347,-581,2080,1952,4425,-5879,7640,5288,33791,-41176,74856, - -1,21,-38,196,225,294,-645,2087,1893,4063,-6237,8092,4561,31947,-43006,74630, - -1,19,-41,190,227,244,-711,2085,1822,3705,-6589,8492,3776,30112,-44821,74313, - -1,17,-45,183,228,197,-779,2075,1739,3351,-6935,8840,2935,28289,-46617,73908, - -1,16,-49,176,228,153,-848,2057,1644,3004,-7271,9139,2037,26482,-48390,73415, - -2,14,-53,169,227,111,-919,2032,1535,2663,-7597,9389,1082,24694,-50137,72835, - -2,13,-58,161,224,72,-991,2001,1414,2330,-7910,9592,70,22929,-51853,72169, - -2,11,-63,154,221,36,-1064,1962,1280,2006,-8209,9750,-998,21189,-53534,71420, - -2,10,-68,147,215,2,-1137,1919,1131,1692,-8491,9863,-2122,19478,-55178,70590, - -3,9,-73,139,208,-29,-1210,1870,970,1388,-8755,9935,-3300,17799,-56778,69679, - -3,8,-79,132,200,-57,-1283,1817,794,1095,-8998,9966,-4533,16155,-58333,68692, - -4,7,-85,125,189,-83,-1356,1759,605,814,-9219,9959,-5818,14548,-59838,67629, - -4,7,-91,117,177,-106,-1428,1698,402,545,-9416,9916,-7154,12980,-61289,66494, - -5,6,-97,111,163,-127,-1498,1634,185,288,-9585,9838,-8540,11455,-62684,65290 - }; - float *zlin = lins + 15*64; - const float *w = g_win; - - zlin[4*15] = xl[18*16]; - zlin[4*15 + 1] = xr[18*16]; - zlin[4*15 + 2] = xl[0]; - zlin[4*15 + 3] = xr[0]; - - zlin[4*31] = xl[1 + 18*16]; - zlin[4*31 + 1] = xr[1 + 18*16]; - zlin[4*31 + 2] = xl[1]; - zlin[4*31 + 3] = xr[1]; - - mp3d_synth_pair(dstr, nch, lins + 4*15 + 1); - mp3d_synth_pair(dstr + 32*nch, nch, lins + 4*15 + 64 + 1); - mp3d_synth_pair(dstl, nch, lins + 4*15); - mp3d_synth_pair(dstl + 32*nch, nch, lins + 4*15 + 64); - -#if HAVE_SIMD - if (have_simd()) for (i = 14; i >= 0; i--) - { -#define VLOAD(k) f4 w0 = VSET(*w++); f4 w1 = VSET(*w++); f4 vz = VLD(&zlin[4*i - 64*k]); f4 vy = VLD(&zlin[4*i - 64*(15 - k)]); -#define V0(k) { VLOAD(k) b = VADD(VMUL(vz, w1), VMUL(vy, w0)) ; a = VSUB(VMUL(vz, w0), VMUL(vy, w1)); } -#define V1(k) { VLOAD(k) b = VADD(b, VADD(VMUL(vz, w1), VMUL(vy, w0))); a = VADD(a, VSUB(VMUL(vz, w0), VMUL(vy, w1))); } -#define V2(k) { VLOAD(k) b = VADD(b, VADD(VMUL(vz, w1), VMUL(vy, w0))); a = VADD(a, VSUB(VMUL(vy, w1), VMUL(vz, w0))); } - f4 a, b; - zlin[4*i] = xl[18*(31 - i)]; - zlin[4*i + 1] = xr[18*(31 - i)]; - zlin[4*i + 2] = xl[1 + 18*(31 - i)]; - zlin[4*i + 3] = xr[1 + 18*(31 - i)]; - zlin[4*i + 64] = xl[1 + 18*(1 + i)]; - zlin[4*i + 64 + 1] = xr[1 + 18*(1 + i)]; - zlin[4*i - 64 + 2] = xl[18*(1 + i)]; - zlin[4*i - 64 + 3] = xr[18*(1 + i)]; - - V0(0) V2(1) V1(2) V2(3) V1(4) V2(5) V1(6) V2(7) - - { -#ifndef MINIMP3_FLOAT_OUTPUT -#if HAVE_SSE - static const f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; - static const f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; - __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)), - _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min))); - dstr[(15 - i)*nch] = _mm_extract_epi16(pcm8, 1); - dstr[(17 + i)*nch] = _mm_extract_epi16(pcm8, 5); - dstl[(15 - i)*nch] = _mm_extract_epi16(pcm8, 0); - dstl[(17 + i)*nch] = _mm_extract_epi16(pcm8, 4); - dstr[(47 - i)*nch] = _mm_extract_epi16(pcm8, 3); - dstr[(49 + i)*nch] = _mm_extract_epi16(pcm8, 7); - dstl[(47 - i)*nch] = _mm_extract_epi16(pcm8, 2); - dstl[(49 + i)*nch] = _mm_extract_epi16(pcm8, 6); -#else /* HAVE_SSE */ - int16x4_t pcma, pcmb; - a = VADD(a, VSET(0.5f)); - b = VADD(b, VSET(0.5f)); - pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, VSET(0))))); - pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, VSET(0))))); - vst1_lane_s16(dstr + (15 - i)*nch, pcma, 1); - vst1_lane_s16(dstr + (17 + i)*nch, pcmb, 1); - vst1_lane_s16(dstl + (15 - i)*nch, pcma, 0); - vst1_lane_s16(dstl + (17 + i)*nch, pcmb, 0); - vst1_lane_s16(dstr + (47 - i)*nch, pcma, 3); - vst1_lane_s16(dstr + (49 + i)*nch, pcmb, 3); - vst1_lane_s16(dstl + (47 - i)*nch, pcma, 2); - vst1_lane_s16(dstl + (49 + i)*nch, pcmb, 2); -#endif /* HAVE_SSE */ - -#else /* MINIMP3_FLOAT_OUTPUT */ - - static const f4 g_scale = { 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f, 1.0f/32768.0f }; - a = VMUL(a, g_scale); - b = VMUL(b, g_scale); -#if HAVE_SSE - _mm_store_ss(dstr + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(1, 1, 1, 1))); - _mm_store_ss(dstr + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(1, 1, 1, 1))); - _mm_store_ss(dstl + (15 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(0, 0, 0, 0))); - _mm_store_ss(dstl + (17 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(0, 0, 0, 0))); - _mm_store_ss(dstr + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 3, 3, 3))); - _mm_store_ss(dstr + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(3, 3, 3, 3))); - _mm_store_ss(dstl + (47 - i)*nch, _mm_shuffle_ps(a, a, _MM_SHUFFLE(2, 2, 2, 2))); - _mm_store_ss(dstl + (49 + i)*nch, _mm_shuffle_ps(b, b, _MM_SHUFFLE(2, 2, 2, 2))); -#else /* HAVE_SSE */ - vst1q_lane_f32(dstr + (15 - i)*nch, a, 1); - vst1q_lane_f32(dstr + (17 + i)*nch, b, 1); - vst1q_lane_f32(dstl + (15 - i)*nch, a, 0); - vst1q_lane_f32(dstl + (17 + i)*nch, b, 0); - vst1q_lane_f32(dstr + (47 - i)*nch, a, 3); - vst1q_lane_f32(dstr + (49 + i)*nch, b, 3); - vst1q_lane_f32(dstl + (47 - i)*nch, a, 2); - vst1q_lane_f32(dstl + (49 + i)*nch, b, 2); -#endif /* HAVE_SSE */ -#endif /* MINIMP3_FLOAT_OUTPUT */ - } - } else -#endif /* HAVE_SIMD */ -#ifdef MINIMP3_ONLY_SIMD - {} /* for HAVE_SIMD=1, MINIMP3_ONLY_SIMD=1 case we do not need non-intrinsic "else" branch */ -#else /* MINIMP3_ONLY_SIMD */ - for (i = 14; i >= 0; i--) - { -#define LOAD(k) float w0 = *w++; float w1 = *w++; float *vz = &zlin[4*i - k*64]; float *vy = &zlin[4*i - (15 - k)*64]; -#define S0(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] = vz[j]*w1 + vy[j]*w0, a[j] = vz[j]*w0 - vy[j]*w1; } -#define S1(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vz[j]*w0 - vy[j]*w1; } -#define S2(k) { int j; LOAD(k); for (j = 0; j < 4; j++) b[j] += vz[j]*w1 + vy[j]*w0, a[j] += vy[j]*w1 - vz[j]*w0; } - float a[4], b[4]; - - zlin[4*i] = xl[18*(31 - i)]; - zlin[4*i + 1] = xr[18*(31 - i)]; - zlin[4*i + 2] = xl[1 + 18*(31 - i)]; - zlin[4*i + 3] = xr[1 + 18*(31 - i)]; - zlin[4*(i + 16)] = xl[1 + 18*(1 + i)]; - zlin[4*(i + 16) + 1] = xr[1 + 18*(1 + i)]; - zlin[4*(i - 16) + 2] = xl[18*(1 + i)]; - zlin[4*(i - 16) + 3] = xr[18*(1 + i)]; - - S0(0) S2(1) S1(2) S2(3) S1(4) S2(5) S1(6) S2(7) - - dstr[(15 - i)*nch] = mp3d_scale_pcm(a[1]); - dstr[(17 + i)*nch] = mp3d_scale_pcm(b[1]); - dstl[(15 - i)*nch] = mp3d_scale_pcm(a[0]); - dstl[(17 + i)*nch] = mp3d_scale_pcm(b[0]); - dstr[(47 - i)*nch] = mp3d_scale_pcm(a[3]); - dstr[(49 + i)*nch] = mp3d_scale_pcm(b[3]); - dstl[(47 - i)*nch] = mp3d_scale_pcm(a[2]); - dstl[(49 + i)*nch] = mp3d_scale_pcm(b[2]); - } -#endif /* MINIMP3_ONLY_SIMD */ -} - -static void mp3d_synth_granule(float *qmf_state, float *grbuf, int nbands, int nch, mp3d_sample_t *pcm, float *lins) -{ - int i; - for (i = 0; i < nch; i++) - { - mp3d_DCT_II(grbuf + 576*i, nbands); - } - - memcpy(lins, qmf_state, sizeof(float)*15*64); - - for (i = 0; i < nbands; i += 2) - { - mp3d_synth(grbuf + i, pcm + 32*nch*i, nch, lins + i*64); - } -#ifndef MINIMP3_NONSTANDARD_BUT_LOGICAL - if (nch == 1) - { - for (i = 0; i < 15*64; i += 2) - { - qmf_state[i] = lins[nbands*64 + i]; - } - } else -#endif /* MINIMP3_NONSTANDARD_BUT_LOGICAL */ - { - memcpy(qmf_state, lins + nbands*64, sizeof(float)*15*64); - } -} - -static int mp3d_match_frame(const uint8_t *hdr, int mp3_bytes, int frame_bytes) -{ - int i, nmatch; - for (i = 0, nmatch = 0; nmatch < MAX_FRAME_SYNC_MATCHES; nmatch++) - { - i += hdr_frame_bytes(hdr + i, frame_bytes) + hdr_padding(hdr + i); - if (i + HDR_SIZE > mp3_bytes) - return nmatch > 0; - if (!hdr_compare(hdr, hdr + i)) - return 0; - } - return 1; -} - -static int mp3d_find_frame(const uint8_t *mp3, int mp3_bytes, int *free_format_bytes, int *ptr_frame_bytes) -{ - int i, k; - for (i = 0; i < mp3_bytes - HDR_SIZE; i++, mp3++) - { - if (hdr_valid(mp3)) - { - int frame_bytes = hdr_frame_bytes(mp3, *free_format_bytes); - int frame_and_padding = frame_bytes + hdr_padding(mp3); - - for (k = HDR_SIZE; !frame_bytes && k < MAX_FREE_FORMAT_FRAME_SIZE && i + 2*k < mp3_bytes - HDR_SIZE; k++) - { - if (hdr_compare(mp3, mp3 + k)) - { - int fb = k - hdr_padding(mp3); - int nextfb = fb + hdr_padding(mp3 + k); - if (i + k + nextfb + HDR_SIZE > mp3_bytes || !hdr_compare(mp3, mp3 + k + nextfb)) - continue; - frame_and_padding = k; - frame_bytes = fb; - *free_format_bytes = fb; - } - } - if ((frame_bytes && i + frame_and_padding <= mp3_bytes && - mp3d_match_frame(mp3, mp3_bytes - i, frame_bytes)) || - (!i && frame_and_padding == mp3_bytes)) - { - *ptr_frame_bytes = frame_and_padding; - return i; - } - *free_format_bytes = 0; - } - } - *ptr_frame_bytes = 0; - return mp3_bytes; -} - -void mp3dec_init(mp3dec_t *dec) -{ - dec->header[0] = 0; -} - -int mp3dec_decode_frame(mp3dec_t *dec, const uint8_t *mp3, int mp3_bytes, mp3d_sample_t *pcm, mp3dec_frame_info_t *info) -{ - int i = 0, igr, frame_size = 0, success = 1; - const uint8_t *hdr; - bs_t bs_frame[1]; - mp3dec_scratch_t scratch; - if (mp3_bytes > 4 && dec->header[0] == 0xff && hdr_compare(dec->header, mp3)) - { - frame_size = hdr_frame_bytes(mp3, dec->free_format_bytes) + hdr_padding(mp3); - if (frame_size != mp3_bytes && (frame_size + HDR_SIZE > mp3_bytes || !hdr_compare(mp3, mp3 + frame_size))) - { - frame_size = 0; - } - } - if (!frame_size) - { - memset(dec, 0, sizeof(mp3dec_t)); - i = mp3d_find_frame(mp3, mp3_bytes, &dec->free_format_bytes, &frame_size); - if (!frame_size || i + frame_size > mp3_bytes) - { - info->frame_bytes = i; - return 0; - } - } - - hdr = mp3 + i; - memcpy(dec->header, hdr, HDR_SIZE); - info->frame_bytes = i + frame_size; - info->frame_offset = i; - info->channels = HDR_IS_MONO(hdr) ? 1 : 2; - info->hz = hdr_sample_rate_hz(hdr); - info->layer = 4 - HDR_GET_LAYER(hdr); - info->bitrate_kbps = hdr_bitrate_kbps(hdr); - - if (!pcm) - { - return hdr_frame_samples(hdr); - } - - bs_init(bs_frame, hdr + HDR_SIZE, frame_size - HDR_SIZE); - if (HDR_IS_CRC(hdr)) - { - get_bits(bs_frame, 16); - } - - if (info->layer == 3) - { - int main_data_begin = L3_read_side_info(bs_frame, scratch.gr_info, hdr); - if (main_data_begin < 0 || bs_frame->pos > bs_frame->limit) - { - mp3dec_init(dec); - return 0; - } - success = L3_restore_reservoir(dec, bs_frame, &scratch, main_data_begin); - if (success) - { - for (igr = 0; igr < (HDR_TEST_MPEG1(hdr) ? 2 : 1); igr++, pcm += 576*info->channels) - { - memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); - L3_decode(dec, &scratch, scratch.gr_info + igr*info->channels, info->channels); - mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 18, info->channels, pcm, scratch.syn[0]); - } - } - L3_save_reservoir(dec, &scratch); - } else - { -#ifdef MINIMP3_ONLY_MP3 - return 0; -#else /* MINIMP3_ONLY_MP3 */ - L12_scale_info sci[1]; - L12_read_scale_info(hdr, bs_frame, sci); - - memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); - for (i = 0, igr = 0; igr < 3; igr++) - { - if (12 == (i += L12_dequantize_granule(scratch.grbuf[0] + i, bs_frame, sci, info->layer | 1))) - { - i = 0; - L12_apply_scf_384(sci, sci->scf + igr, scratch.grbuf[0]); - mp3d_synth_granule(dec->qmf_state, scratch.grbuf[0], 12, info->channels, pcm, scratch.syn[0]); - memset(scratch.grbuf[0], 0, 576*2*sizeof(float)); - pcm += 384*info->channels; - } - if (bs_frame->pos > bs_frame->limit) - { - mp3dec_init(dec); - return 0; - } - } -#endif /* MINIMP3_ONLY_MP3 */ - } - return success*hdr_frame_samples(dec->header); -} - -#ifdef MINIMP3_FLOAT_OUTPUT -void mp3dec_f32_to_s16(const float *in, int16_t *out, int num_samples) -{ - int i = 0; -#if HAVE_SIMD - int aligned_count = num_samples & ~7; - for(; i < aligned_count; i += 8) - { - static const f4 g_scale = { 32768.0f, 32768.0f, 32768.0f, 32768.0f }; - f4 a = VMUL(VLD(&in[i ]), g_scale); - f4 b = VMUL(VLD(&in[i+4]), g_scale); -#if HAVE_SSE - static const f4 g_max = { 32767.0f, 32767.0f, 32767.0f, 32767.0f }; - static const f4 g_min = { -32768.0f, -32768.0f, -32768.0f, -32768.0f }; - __m128i pcm8 = _mm_packs_epi32(_mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(a, g_max), g_min)), - _mm_cvtps_epi32(_mm_max_ps(_mm_min_ps(b, g_max), g_min))); - out[i ] = _mm_extract_epi16(pcm8, 0); - out[i+1] = _mm_extract_epi16(pcm8, 1); - out[i+2] = _mm_extract_epi16(pcm8, 2); - out[i+3] = _mm_extract_epi16(pcm8, 3); - out[i+4] = _mm_extract_epi16(pcm8, 4); - out[i+5] = _mm_extract_epi16(pcm8, 5); - out[i+6] = _mm_extract_epi16(pcm8, 6); - out[i+7] = _mm_extract_epi16(pcm8, 7); -#else /* HAVE_SSE */ - int16x4_t pcma, pcmb; - a = VADD(a, VSET(0.5f)); - b = VADD(b, VSET(0.5f)); - pcma = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(a), vreinterpretq_s32_u32(vcltq_f32(a, VSET(0))))); - pcmb = vqmovn_s32(vqaddq_s32(vcvtq_s32_f32(b), vreinterpretq_s32_u32(vcltq_f32(b, VSET(0))))); - vst1_lane_s16(out+i , pcma, 0); - vst1_lane_s16(out+i+1, pcma, 1); - vst1_lane_s16(out+i+2, pcma, 2); - vst1_lane_s16(out+i+3, pcma, 3); - vst1_lane_s16(out+i+4, pcmb, 0); - vst1_lane_s16(out+i+5, pcmb, 1); - vst1_lane_s16(out+i+6, pcmb, 2); - vst1_lane_s16(out+i+7, pcmb, 3); -#endif /* HAVE_SSE */ - } -#endif /* HAVE_SIMD */ - for(; i < num_samples; i++) - { - float sample = in[i] * 32768.0f; - if (sample >= 32766.5) - out[i] = (int16_t) 32767; - else if (sample <= -32767.5) - out[i] = (int16_t)-32768; - else - { - int16_t s = (int16_t)(sample + .5f); - s -= (s < 0); /* away from zero, to be compliant */ - out[i] = s; - } - } -} -#endif /* MINIMP3_FLOAT_OUTPUT */ -#endif /* MINIMP3_IMPLEMENTATION && !_MINIMP3_IMPLEMENTATION_GUARD */ diff --git a/engine/plugin/plugins/minimp3_adapter/minimp3_ex.h b/engine/plugin/plugins/minimp3_adapter/minimp3_ex.h deleted file mode 100755 index 36a1d97a..00000000 --- a/engine/plugin/plugins/minimp3_adapter/minimp3_ex.h +++ /dev/null @@ -1,1394 +0,0 @@ -#ifndef MINIMP3_EXT_H -#define MINIMP3_EXT_H -/* - https://github.com/lieff/minimp3 - To the extent possible under law, the author(s) have dedicated all copyright and related and neighboring rights to this software to the public domain worldwide. - This software is distributed without any warranty. - See . -*/ -#include "minimp3.h" - -/* flags for mp3dec_ex_open_* functions */ -#define MP3D_SEEK_TO_BYTE 0 /* mp3dec_ex_seek seeks to byte in stream */ -#define MP3D_SEEK_TO_SAMPLE 1 /* mp3dec_ex_seek precisely seeks to sample using index (created during duration calculation scan or when mp3dec_ex_seek called) */ -#define MP3D_DO_NOT_SCAN 2 /* do not scan whole stream for duration if vbrtag not found, mp3dec_ex_t::samples will be filled only if mp3dec_ex_t::vbr_tag_found == 1 */ -#ifdef MINIMP3_ALLOW_MONO_STEREO_TRANSITION -#define MP3D_ALLOW_MONO_STEREO_TRANSITION 4 -#define MP3D_FLAGS_MASK 7 -#else -#define MP3D_FLAGS_MASK 3 -#endif - -/* compile-time config */ -#define MINIMP3_PREDECODE_FRAMES 2 /* frames to pre-decode and skip after seek (to fill internal structures) */ -/*#define MINIMP3_SEEK_IDX_LINEAR_SEARCH*/ /* define to use linear index search instead of binary search on seek */ -#define MINIMP3_IO_SIZE (128*1024) /* io buffer size for streaming functions, must be greater than MINIMP3_BUF_SIZE */ -#define MINIMP3_BUF_SIZE (16*1024) /* buffer which can hold minimum 10 consecutive mp3 frames (~16KB) worst case */ -/*#define MINIMP3_SCAN_LIMIT (256*1024)*/ /* how many bytes will be scanned to search first valid mp3 frame, to prevent stall on large non-mp3 files */ -#define MINIMP3_ENABLE_RING 0 /* WIP enable hardware magic ring buffer if available, to make less input buffer memmove(s) in callback IO mode */ - -/* return error codes */ -#define MP3D_E_PARAM -1 -#define MP3D_E_MEMORY -2 -#define MP3D_E_IOERROR -3 -#define MP3D_E_USER -4 /* can be used to stop processing from callbacks without indicating specific error */ -#define MP3D_E_DECODE -5 /* decode error which can't be safely skipped, such as sample rate, layer and channels change */ - -typedef struct -{ - mp3d_sample_t *buffer; - size_t samples; /* channels included, byte size = samples*sizeof(mp3d_sample_t) */ - int channels, hz, layer, avg_bitrate_kbps; -} mp3dec_file_info_t; - -typedef struct -{ - const uint8_t *buffer; - size_t size; -} mp3dec_map_info_t; - -typedef struct -{ - uint64_t sample; - uint64_t offset; -} mp3dec_frame_t; - -typedef struct -{ - mp3dec_frame_t *frames; - size_t num_frames, capacity; -} mp3dec_index_t; - -typedef size_t (*MP3D_READ_CB)(void *buf, size_t size, void *user_data); -typedef int (*MP3D_SEEK_CB)(uint64_t position, void *user_data); - -typedef struct -{ - MP3D_READ_CB read; - void *read_data; - MP3D_SEEK_CB seek; - void *seek_data; -} mp3dec_io_t; - -typedef struct -{ - mp3dec_t mp3d; - mp3dec_map_info_t file; - mp3dec_io_t *io; - mp3dec_index_t index; - uint64_t offset, samples, detected_samples, cur_sample, start_offset, end_offset; - mp3dec_frame_info_t info; - mp3d_sample_t buffer[MINIMP3_MAX_SAMPLES_PER_FRAME]; - size_t input_consumed, input_filled; - int is_file, flags, vbr_tag_found, indexes_built; - int free_format_bytes; - int buffer_samples, buffer_consumed, to_skip, start_delay; - int last_error; -} mp3dec_ex_t; - -typedef int (*MP3D_ITERATE_CB)(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t buf_size, uint64_t offset, mp3dec_frame_info_t *info); -typedef int (*MP3D_PROGRESS_CB)(void *user_data, size_t file_size, uint64_t offset, mp3dec_frame_info_t *info); - -#ifdef __cplusplus -extern "C" { -#endif - -/* detect mp3/mpa format */ -int mp3dec_detect_buf(const uint8_t *buf, size_t buf_size); -int mp3dec_detect_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size); -/* decode whole buffer block */ -int mp3dec_load_buf(mp3dec_t *dec, const uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); -int mp3dec_load_cb(mp3dec_t *dec, mp3dec_io_t *io, uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); -/* iterate through frames */ -int mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data); -int mp3dec_iterate_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data); -/* streaming decoder with seeking capability */ -int mp3dec_ex_open_buf(mp3dec_ex_t *dec, const uint8_t *buf, size_t buf_size, int flags); -int mp3dec_ex_open_cb(mp3dec_ex_t *dec, mp3dec_io_t *io, int flags); -void mp3dec_ex_close(mp3dec_ex_t *dec); -int mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position); -size_t mp3dec_ex_read_frame(mp3dec_ex_t *dec, mp3d_sample_t **buf, mp3dec_frame_info_t *frame_info, size_t max_samples); -size_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples); -#ifndef MINIMP3_NO_STDIO -/* stdio versions of file detect, load, iterate and stream */ -int mp3dec_detect(const char *file_name); -int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); -int mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data); -int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int flags); -#ifdef _WIN32 -int mp3dec_detect_w(const wchar_t *file_name); -int mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data); -int mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data); -int mp3dec_ex_open_w(mp3dec_ex_t *dec, const wchar_t *file_name, int flags); -#endif -#endif - -#ifdef __cplusplus -} -#endif -#endif /*MINIMP3_EXT_H*/ - -#ifdef MINIMP3_IMPLEMENTATION -#include - -static void mp3dec_skip_id3v1(const uint8_t *buf, size_t *pbuf_size) -{ - size_t buf_size = *pbuf_size; -#ifndef MINIMP3_NOSKIP_ID3V1 - if (buf_size >= 128 && !memcmp(buf + buf_size - 128, "TAG", 3)) - { - buf_size -= 128; - if (buf_size >= 227 && !memcmp(buf + buf_size - 227, "TAG+", 4)) - buf_size -= 227; - } -#endif -#ifndef MINIMP3_NOSKIP_APEV2 - if (buf_size > 32 && !memcmp(buf + buf_size - 32, "APETAGEX", 8)) - { - buf_size -= 32; - const uint8_t *tag = buf + buf_size + 8 + 4; - uint32_t tag_size = (uint32_t)(tag[3] << 24) | (tag[2] << 16) | (tag[1] << 8) | tag[0]; - if (buf_size >= tag_size) - buf_size -= tag_size; - } -#endif - *pbuf_size = buf_size; -} - -static size_t mp3dec_skip_id3v2(const uint8_t *buf, size_t buf_size) -{ -#define MINIMP3_ID3_DETECT_SIZE 10 -#ifndef MINIMP3_NOSKIP_ID3V2 - if (buf_size >= MINIMP3_ID3_DETECT_SIZE && !memcmp(buf, "ID3", 3) && !((buf[5] & 15) || (buf[6] & 0x80) || (buf[7] & 0x80) || (buf[8] & 0x80) || (buf[9] & 0x80))) - { - size_t id3v2size = (((buf[6] & 0x7f) << 21) | ((buf[7] & 0x7f) << 14) | ((buf[8] & 0x7f) << 7) | (buf[9] & 0x7f)) + 10; - if ((buf[5] & 16)) - id3v2size += 10; /* footer */ - return id3v2size; - } -#endif - return 0; -} - -static void mp3dec_skip_id3(const uint8_t **pbuf, size_t *pbuf_size) -{ - uint8_t *buf = (uint8_t *)(*pbuf); - size_t buf_size = *pbuf_size; - size_t id3v2size = mp3dec_skip_id3v2(buf, buf_size); - if (id3v2size) - { - if (id3v2size >= buf_size) - id3v2size = buf_size; - buf += id3v2size; - buf_size -= id3v2size; - } - mp3dec_skip_id3v1(buf, &buf_size); - *pbuf = (const uint8_t *)buf; - *pbuf_size = buf_size; -} - -static int mp3dec_check_vbrtag(const uint8_t *frame, int frame_size, uint32_t *frames, int *delay, int *padding) -{ - static const char g_xing_tag[4] = { 'X', 'i', 'n', 'g' }; - static const char g_info_tag[4] = { 'I', 'n', 'f', 'o' }; -#define FRAMES_FLAG 1 -#define BYTES_FLAG 2 -#define TOC_FLAG 4 -#define VBR_SCALE_FLAG 8 - /* Side info offsets after header: - / Mono Stereo - / MPEG1 17 32 - / MPEG2 & 2.5 9 17*/ - bs_t bs[1]; - L3_gr_info_t gr_info[4]; - bs_init(bs, frame + HDR_SIZE, frame_size - HDR_SIZE); - if (HDR_IS_CRC(frame)) - get_bits(bs, 16); - if (L3_read_side_info(bs, gr_info, frame) < 0) - return 0; /* side info corrupted */ - - const uint8_t *tag = frame + HDR_SIZE + bs->pos/8; - if (memcmp(g_xing_tag, tag, 4) && memcmp(g_info_tag, tag, 4)) - return 0; - int flags = tag[7]; - if (!((flags & FRAMES_FLAG))) - return -1; - tag += 8; - *frames = (uint32_t)(tag[0] << 24) | (tag[1] << 16) | (tag[2] << 8) | tag[3]; - tag += 4; - if (flags & BYTES_FLAG) - tag += 4; - if (flags & TOC_FLAG) - tag += 100; - if (flags & VBR_SCALE_FLAG) - tag += 4; - *delay = *padding = 0; - if (*tag) - { /* extension, LAME, Lavc, etc. Should be the same structure. */ - tag += 21; - if (tag - frame + 14 >= frame_size) - return 0; - *delay = ((tag[0] << 4) | (tag[1] >> 4)) + (528 + 1); - *padding = (((tag[1] & 0xF) << 8) | tag[2]) - (528 + 1); - } - return 1; -} - -int mp3dec_detect_buf(const uint8_t *buf, size_t buf_size) -{ - return mp3dec_detect_cb(0, (uint8_t *)buf, buf_size); -} - -int mp3dec_detect_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size) -{ - if (!buf || (size_t)-1 == buf_size || (io && buf_size < MINIMP3_BUF_SIZE)) - return MP3D_E_PARAM; - size_t filled = buf_size; - if (io) - { - if (io->seek(0, io->seek_data)) - return MP3D_E_IOERROR; - filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data); - if (filled > MINIMP3_ID3_DETECT_SIZE) - return MP3D_E_IOERROR; - } - if (filled < MINIMP3_ID3_DETECT_SIZE) - return MP3D_E_USER; /* too small, can't be mp3/mpa */ - if (mp3dec_skip_id3v2(buf, filled)) - return 0; /* id3v2 tag is enough evidence */ - if (io) - { - size_t readed = io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data); - if (readed > (buf_size - MINIMP3_ID3_DETECT_SIZE)) - return MP3D_E_IOERROR; - filled += readed; - if (filled < MINIMP3_BUF_SIZE) - mp3dec_skip_id3v1(buf, &filled); - } else - { - mp3dec_skip_id3v1(buf, &filled); - if (filled > MINIMP3_BUF_SIZE) - filled = MINIMP3_BUF_SIZE; - } - int free_format_bytes, frame_size; - mp3d_find_frame(buf, filled, &free_format_bytes, &frame_size); - if (frame_size) - return 0; /* MAX_FRAME_SYNC_MATCHES consecutive frames found */ - return MP3D_E_USER; -} - -int mp3dec_load_buf(mp3dec_t *dec, const uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) -{ - return mp3dec_load_cb(dec, 0, (uint8_t *)buf, buf_size, info, progress_cb, user_data); -} - -int mp3dec_load_cb(mp3dec_t *dec, mp3dec_io_t *io, uint8_t *buf, size_t buf_size, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) -{ - if (!dec || !buf || !info || (size_t)-1 == buf_size || (io && buf_size < MINIMP3_BUF_SIZE)) - return MP3D_E_PARAM; - uint64_t detected_samples = 0; - size_t orig_buf_size = buf_size; - int to_skip = 0; - mp3dec_frame_info_t frame_info; - memset(info, 0, sizeof(*info)); - memset(&frame_info, 0, sizeof(frame_info)); - - /* skip id3 */ - size_t filled = 0, consumed = 0; - int eof = 0, ret = 0; - if (io) - { - if (io->seek(0, io->seek_data)) - return MP3D_E_IOERROR; - filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data); - if (filled > MINIMP3_ID3_DETECT_SIZE) - return MP3D_E_IOERROR; - if (MINIMP3_ID3_DETECT_SIZE != filled) - return 0; - size_t id3v2size = mp3dec_skip_id3v2(buf, filled); - if (id3v2size) - { - if (io->seek(id3v2size, io->seek_data)) - return MP3D_E_IOERROR; - filled = io->read(buf, buf_size, io->read_data); - if (filled > buf_size) - return MP3D_E_IOERROR; - } else - { - size_t readed = io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data); - if (readed > (buf_size - MINIMP3_ID3_DETECT_SIZE)) - return MP3D_E_IOERROR; - filled += readed; - } - if (filled < MINIMP3_BUF_SIZE) - mp3dec_skip_id3v1(buf, &filled); - } else - { - mp3dec_skip_id3((const uint8_t **)&buf, &buf_size); - if (!buf_size) - return 0; - } - /* try to make allocation size assumption by first frame or vbr tag */ - mp3dec_init(dec); - int samples; - do - { - uint32_t frames; - int i, delay, padding, free_format_bytes = 0, frame_size = 0; - const uint8_t *hdr; - if (io) - { - if (!eof && filled - consumed < MINIMP3_BUF_SIZE) - { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ - memmove(buf, buf + consumed, filled - consumed); - filled -= consumed; - consumed = 0; - size_t readed = io->read(buf + filled, buf_size - filled, io->read_data); - if (readed > (buf_size - filled)) - return MP3D_E_IOERROR; - if (readed != (buf_size - filled)) - eof = 1; - filled += readed; - if (eof) - mp3dec_skip_id3v1(buf, &filled); - } - i = mp3d_find_frame(buf + consumed, filled - consumed, &free_format_bytes, &frame_size); - consumed += i; - hdr = buf + consumed; - } else - { - i = mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size); - buf += i; - buf_size -= i; - hdr = buf; - } - if (i && !frame_size) - continue; - if (!frame_size) - return 0; - frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2; - frame_info.hz = hdr_sample_rate_hz(hdr); - frame_info.layer = 4 - HDR_GET_LAYER(hdr); - frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr); - frame_info.frame_bytes = frame_size; - samples = hdr_frame_samples(hdr)*frame_info.channels; - if (3 != frame_info.layer) - break; - int ret = mp3dec_check_vbrtag(hdr, frame_size, &frames, &delay, &padding); - if (ret > 0) - { - padding *= frame_info.channels; - to_skip = delay*frame_info.channels; - detected_samples = samples*(uint64_t)frames; - if (detected_samples >= (uint64_t)to_skip) - detected_samples -= to_skip; - if (padding > 0 && detected_samples >= (uint64_t)padding) - detected_samples -= padding; - if (!detected_samples) - return 0; - } - if (ret) - { - if (io) - { - consumed += frame_size; - } else - { - buf += frame_size; - buf_size -= frame_size; - } - } - break; - } while(1); - size_t allocated = MINIMP3_MAX_SAMPLES_PER_FRAME*sizeof(mp3d_sample_t); - if (detected_samples) - allocated += detected_samples*sizeof(mp3d_sample_t); - else - allocated += (buf_size/frame_info.frame_bytes)*samples*sizeof(mp3d_sample_t); - info->buffer = (mp3d_sample_t*)malloc(allocated); - if (!info->buffer) - return MP3D_E_MEMORY; - /* save info */ - info->channels = frame_info.channels; - info->hz = frame_info.hz; - info->layer = frame_info.layer; - /* decode all frames */ - size_t avg_bitrate_kbps = 0, frames = 0; - do - { - if ((allocated - info->samples*sizeof(mp3d_sample_t)) < MINIMP3_MAX_SAMPLES_PER_FRAME*sizeof(mp3d_sample_t)) - { - allocated *= 2; - mp3d_sample_t *alloc_buf = (mp3d_sample_t*)realloc(info->buffer, allocated); - if (!alloc_buf) - return MP3D_E_MEMORY; - info->buffer = alloc_buf; - } - if (io) - { - if (!eof && filled - consumed < MINIMP3_BUF_SIZE) - { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ - memmove(buf, buf + consumed, filled - consumed); - filled -= consumed; - consumed = 0; - size_t readed = io->read(buf + filled, buf_size - filled, io->read_data); - if (readed != (buf_size - filled)) - eof = 1; - filled += readed; - if (eof) - mp3dec_skip_id3v1(buf, &filled); - } - samples = mp3dec_decode_frame(dec, buf + consumed, filled - consumed, info->buffer + info->samples, &frame_info); - consumed += frame_info.frame_bytes; - } else - { - samples = mp3dec_decode_frame(dec, buf, MINIMP3_MIN(buf_size, (size_t)INT_MAX), info->buffer + info->samples, &frame_info); - buf += frame_info.frame_bytes; - buf_size -= frame_info.frame_bytes; - } - if (samples) - { - if (info->hz != frame_info.hz || info->layer != frame_info.layer) - { - ret = MP3D_E_DECODE; - break; - } - if (info->channels && info->channels != frame_info.channels) - { -#ifdef MINIMP3_ALLOW_MONO_STEREO_TRANSITION - info->channels = 0; /* mark file with mono-stereo transition */ -#else - ret = MP3D_E_DECODE; - break; -#endif - } - samples *= frame_info.channels; - if (to_skip) - { - size_t skip = MINIMP3_MIN(samples, to_skip); - to_skip -= skip; - samples -= skip; - memmove(info->buffer, info->buffer + skip, samples*sizeof(mp3d_sample_t)); - } - info->samples += samples; - avg_bitrate_kbps += frame_info.bitrate_kbps; - frames++; - if (progress_cb) - { - ret = progress_cb(user_data, orig_buf_size, orig_buf_size - buf_size, &frame_info); - if (ret) - break; - } - } - } while (frame_info.frame_bytes); - if (detected_samples && info->samples > detected_samples) - info->samples = detected_samples; /* cut padding */ - /* reallocate to normal buffer size */ - if (allocated != info->samples*sizeof(mp3d_sample_t)) - { - mp3d_sample_t *alloc_buf = (mp3d_sample_t*)realloc(info->buffer, info->samples*sizeof(mp3d_sample_t)); - if (!alloc_buf && info->samples) - return MP3D_E_MEMORY; - info->buffer = alloc_buf; - } - if (frames) - info->avg_bitrate_kbps = avg_bitrate_kbps/frames; - return ret; -} - -int mp3dec_iterate_buf(const uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data) -{ - const uint8_t *orig_buf = buf; - if (!buf || (size_t)-1 == buf_size || !callback) - return MP3D_E_PARAM; - /* skip id3 */ - mp3dec_skip_id3(&buf, &buf_size); - mp3dec_frame_info_t frame_info; - memset(&frame_info, 0, sizeof(frame_info)); - do - { - int free_format_bytes = 0, frame_size = 0, ret; - int i = mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size); - buf += i; - buf_size -= i; - if (i && !frame_size) - continue; - if (!frame_size) - break; - const uint8_t *hdr = buf; - frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2; - frame_info.hz = hdr_sample_rate_hz(hdr); - frame_info.layer = 4 - HDR_GET_LAYER(hdr); - frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr); - frame_info.frame_bytes = frame_size; - frame_info.samples_per_frame = hdr_frame_samples(hdr); - - if (callback) - { - if ((ret = callback(user_data, hdr, frame_size, free_format_bytes, buf_size, hdr - orig_buf, &frame_info))){ - return ret; - } - } - buf += frame_size; - buf_size -= frame_size; - } while (1); - return 0; -} - -int mp3dec_iterate_cb(mp3dec_io_t *io, uint8_t *buf, size_t buf_size, MP3D_ITERATE_CB callback, void *user_data) -{ - if (!io || !buf || (size_t)-1 == buf_size || buf_size < MINIMP3_BUF_SIZE || !callback) - return MP3D_E_PARAM; - size_t filled = io->read(buf, MINIMP3_ID3_DETECT_SIZE, io->read_data), consumed = 0; - uint64_t readed = 0; - mp3dec_frame_info_t frame_info; - int eof = 0; - memset(&frame_info, 0, sizeof(frame_info)); - if (filled > MINIMP3_ID3_DETECT_SIZE) - return MP3D_E_IOERROR; - if (MINIMP3_ID3_DETECT_SIZE != filled) - return 0; - size_t id3v2size = mp3dec_skip_id3v2(buf, filled); - if (id3v2size) - { - if (io->seek(id3v2size, io->seek_data)) - return MP3D_E_IOERROR; - filled = io->read(buf, buf_size, io->read_data); - if (filled > buf_size) - return MP3D_E_IOERROR; - readed += id3v2size; - } else - { - size_t readed = io->read(buf + MINIMP3_ID3_DETECT_SIZE, buf_size - MINIMP3_ID3_DETECT_SIZE, io->read_data); - if (readed > (buf_size - MINIMP3_ID3_DETECT_SIZE)) - return MP3D_E_IOERROR; - filled += readed; - } - if (filled < MINIMP3_BUF_SIZE) - mp3dec_skip_id3v1(buf, &filled); - do - { - int free_format_bytes = 0, frame_size = 0, ret; - int i = mp3d_find_frame(buf + consumed, filled - consumed, &free_format_bytes, &frame_size); - if (i && !frame_size) - { - consumed += i; - continue; - } - if (!frame_size) - break; - const uint8_t *hdr = buf + consumed + i; - frame_info.channels = HDR_IS_MONO(hdr) ? 1 : 2; - frame_info.hz = hdr_sample_rate_hz(hdr); - frame_info.layer = 4 - HDR_GET_LAYER(hdr); - frame_info.bitrate_kbps = hdr_bitrate_kbps(hdr); - frame_info.frame_bytes = frame_size; - - readed += i; - if (callback) - { - if ((ret = callback(user_data, hdr, frame_size, free_format_bytes, filled - consumed, readed, &frame_info))) - return ret; - } - readed += frame_size; - consumed += i + frame_size; - if (!eof && filled - consumed < MINIMP3_BUF_SIZE) - { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ - memmove(buf, buf + consumed, filled - consumed); - filled -= consumed; - consumed = 0; - size_t readed = io->read(buf + filled, buf_size - filled, io->read_data); - if (readed > (buf_size - filled)) - return MP3D_E_IOERROR; - if (readed != (buf_size - filled)) - eof = 1; - filled += readed; - if (eof) - mp3dec_skip_id3v1(buf, &filled); - } - } while (1); - return 0; -} - -static int mp3dec_load_index(void *user_data, const uint8_t *frame, int frame_size, int free_format_bytes, size_t buf_size, uint64_t offset, mp3dec_frame_info_t *info) -{ - mp3dec_frame_t *idx_frame; - mp3dec_ex_t *dec = (mp3dec_ex_t *)user_data; - if (!dec->index.frames && !dec->start_offset) - { /* detect VBR tag and try to avoid full scan */ - uint32_t frames; - int delay, padding; - dec->info = *info; - dec->start_offset = dec->offset = offset; - dec->end_offset = offset + buf_size; - dec->free_format_bytes = free_format_bytes; /* should not change */ - if (3 == dec->info.layer) - { - int ret = mp3dec_check_vbrtag(frame, frame_size, &frames, &delay, &padding); - if (ret) - dec->start_offset = dec->offset = offset + frame_size; - if (ret > 0) - { - padding *= info->channels; - dec->start_delay = dec->to_skip = delay*info->channels; - dec->samples = hdr_frame_samples(frame)*info->channels*(uint64_t)frames; - if (dec->samples >= (uint64_t)dec->start_delay) - dec->samples -= dec->start_delay; - if (padding > 0 && dec->samples >= (uint64_t)padding) - dec->samples -= padding; - dec->detected_samples = dec->samples; - dec->vbr_tag_found = 1; - return MP3D_E_USER; - } else if (ret < 0) - return 0; - } - } - if (dec->flags & MP3D_DO_NOT_SCAN) - return MP3D_E_USER; - if (dec->index.num_frames + 1 > dec->index.capacity) - { - if (!dec->index.capacity) - dec->index.capacity = 4096; - else - dec->index.capacity *= 2; - mp3dec_frame_t *alloc_buf = (mp3dec_frame_t *)realloc((void*)dec->index.frames, sizeof(mp3dec_frame_t)*dec->index.capacity); - if (!alloc_buf) - return MP3D_E_MEMORY; - dec->index.frames = alloc_buf; - } - idx_frame = &dec->index.frames[dec->index.num_frames++]; - idx_frame->offset = offset; - idx_frame->sample = dec->samples; - if (!dec->buffer_samples && dec->index.num_frames < 256) - { /* for some cutted mp3 frames, bit-reservoir not filled and decoding can't be started from first frames */ - /* try to decode up to 255 first frames till samples starts to decode */ - dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, frame, MINIMP3_MIN(buf_size, (size_t)INT_MAX), dec->buffer, info); - dec->samples += dec->buffer_samples*info->channels; - } else - dec->samples += hdr_frame_samples(frame)*info->channels; - return 0; -} - -int mp3dec_ex_open_buf(mp3dec_ex_t *dec, const uint8_t *buf, size_t buf_size, int flags) -{ - if (!dec || !buf || (size_t)-1 == buf_size || (flags & (~MP3D_FLAGS_MASK))) - return MP3D_E_PARAM; - memset(dec, 0, sizeof(*dec)); - dec->file.buffer = buf; - dec->file.size = buf_size; - dec->flags = flags; - mp3dec_init(&dec->mp3d); - int ret = mp3dec_iterate_buf(dec->file.buffer, dec->file.size, mp3dec_load_index, dec); - if (ret && MP3D_E_USER != ret) - return ret; - mp3dec_init(&dec->mp3d); - dec->buffer_samples = 0; - dec->indexes_built = !(dec->vbr_tag_found || (flags & MP3D_DO_NOT_SCAN)); - dec->flags &= (~MP3D_DO_NOT_SCAN); - return 0; -} - -#ifndef MINIMP3_SEEK_IDX_LINEAR_SEARCH -static size_t mp3dec_idx_binary_search(mp3dec_index_t *idx, uint64_t position) -{ - size_t end = idx->num_frames, start = 0, index = 0; - while (start <= end) - { - size_t mid = (start + end) / 2; - if (idx->frames[mid].sample >= position) - { /* move left side. */ - if (idx->frames[mid].sample == position) - return mid; - end = mid - 1; - } else - { /* move to right side */ - index = mid; - start = mid + 1; - if (start == idx->num_frames) - break; - } - } - return index; -} -#endif - -int mp3dec_ex_seek(mp3dec_ex_t *dec, uint64_t position) -{ - size_t i; - if (!dec) - return MP3D_E_PARAM; - if (!(dec->flags & MP3D_SEEK_TO_SAMPLE)) - { - if (dec->io) - { - dec->offset = position; - } else - { - dec->offset = MINIMP3_MIN(position, dec->file.size); - } - dec->cur_sample = 0; - goto do_exit; - } - dec->cur_sample = position; - position += dec->start_delay; - if (0 == position) - { /* optimize seek to zero, no index needed */ -seek_zero: - dec->offset = dec->start_offset; - dec->to_skip = 0; - goto do_exit; - } - if (!dec->indexes_built) - { /* no index created yet (vbr tag used to calculate track length or MP3D_DO_NOT_SCAN open flag used) */ - dec->indexes_built = 1; - dec->samples = 0; - dec->buffer_samples = 0; - if (dec->io) - { - if (dec->io->seek(dec->start_offset, dec->io->seek_data)) - return MP3D_E_IOERROR; - int ret = mp3dec_iterate_cb(dec->io, (uint8_t *)dec->file.buffer, dec->file.size, mp3dec_load_index, dec); - if (ret && MP3D_E_USER != ret) - return ret; - } else - { - int ret = mp3dec_iterate_buf(dec->file.buffer + dec->start_offset, dec->file.size - dec->start_offset, mp3dec_load_index, dec); - if (ret && MP3D_E_USER != ret) - return ret; - } - for (i = 0; i < dec->index.num_frames; i++) - dec->index.frames[i].offset += dec->start_offset; - dec->samples = dec->detected_samples; - } - if (!dec->index.frames) - goto seek_zero; /* no frames in file - seek to zero */ -#ifdef MINIMP3_SEEK_IDX_LINEAR_SEARCH - for (i = 0; i < dec->index.num_frames; i++) - { - if (dec->index.frames[i].sample >= position) - break; - } -#else - i = mp3dec_idx_binary_search(&dec->index, position); -#endif - if (i) - { - int to_fill_bytes = 511; - int skip_frames = MINIMP3_PREDECODE_FRAMES -#ifdef MINIMP3_SEEK_IDX_LINEAR_SEARCH - + ((dec->index.frames[i].sample == position) ? 0 : 1) -#endif - ; - i -= MINIMP3_MIN(i, (size_t)skip_frames); - if (3 == dec->info.layer) - { - while (i && to_fill_bytes) - { /* make sure bit-reservoir is filled when we start decoding */ - bs_t bs[1]; - L3_gr_info_t gr_info[4]; - int frame_bytes, frame_size; - const uint8_t *hdr; - if (dec->io) - { - hdr = dec->file.buffer; - if (dec->io->seek(dec->index.frames[i - 1].offset, dec->io->seek_data)) - return MP3D_E_IOERROR; - size_t readed = dec->io->read((uint8_t *)hdr, HDR_SIZE, dec->io->read_data); - if (readed != HDR_SIZE) - return MP3D_E_IOERROR; - frame_size = hdr_frame_bytes(hdr, dec->free_format_bytes) + hdr_padding(hdr); - readed = dec->io->read((uint8_t *)hdr + HDR_SIZE, frame_size - HDR_SIZE, dec->io->read_data); - if (readed != (size_t)(frame_size - HDR_SIZE)) - return MP3D_E_IOERROR; - bs_init(bs, hdr + HDR_SIZE, frame_size - HDR_SIZE); - } else - { - hdr = dec->file.buffer + dec->index.frames[i - 1].offset; - frame_size = hdr_frame_bytes(hdr, dec->free_format_bytes) + hdr_padding(hdr); - bs_init(bs, hdr + HDR_SIZE, frame_size - HDR_SIZE); - } - if (HDR_IS_CRC(hdr)) - get_bits(bs, 16); - i--; - if (L3_read_side_info(bs, gr_info, hdr) < 0) - break; /* frame not decodable, we can start from here */ - frame_bytes = (bs->limit - bs->pos)/8; - to_fill_bytes -= MINIMP3_MIN(to_fill_bytes, frame_bytes); - } - } - } - dec->offset = dec->index.frames[i].offset; - dec->to_skip = position - dec->index.frames[i].sample; - while ((i + 1) < dec->index.num_frames && !dec->index.frames[i].sample && !dec->index.frames[i + 1].sample) - { /* skip not decodable first frames */ - const uint8_t *hdr; - if (dec->io) - { - hdr = dec->file.buffer; - if (dec->io->seek(dec->index.frames[i].offset, dec->io->seek_data)) - return MP3D_E_IOERROR; - size_t readed = dec->io->read((uint8_t *)hdr, HDR_SIZE, dec->io->read_data); - if (readed != HDR_SIZE) - return MP3D_E_IOERROR; - } else - hdr = dec->file.buffer + dec->index.frames[i].offset; - dec->to_skip += hdr_frame_samples(hdr)*dec->info.channels; - i++; - } -do_exit: - if (dec->io) - { - if (dec->io->seek(dec->offset, dec->io->seek_data)) - return MP3D_E_IOERROR; - } - dec->buffer_samples = 0; - dec->buffer_consumed = 0; - dec->input_consumed = 0; - dec->input_filled = 0; - dec->last_error = 0; - mp3dec_init(&dec->mp3d); - return 0; -} - -size_t mp3dec_ex_read_frame(mp3dec_ex_t *dec, mp3d_sample_t **buf, mp3dec_frame_info_t *frame_info, size_t max_samples) -{ - if (!dec || !buf || !frame_info) - { - if (dec) - dec->last_error = MP3D_E_PARAM; - return 0; - } - if (dec->detected_samples && dec->cur_sample >= dec->detected_samples) - return 0; /* at end of stream */ - if (dec->last_error) - return 0; /* error eof state, seek can reset it */ - *buf = NULL; - uint64_t end_offset = dec->end_offset ? dec->end_offset : dec->file.size; - int eof = 0; - while (dec->buffer_consumed == dec->buffer_samples) - { - const uint8_t *dec_buf; - if (dec->io) - { - if (!eof && (dec->input_filled - dec->input_consumed) < MINIMP3_BUF_SIZE) - { /* keep minimum 10 consecutive mp3 frames (~16KB) worst case */ - memmove((uint8_t*)dec->file.buffer, (uint8_t*)dec->file.buffer + dec->input_consumed, dec->input_filled - dec->input_consumed); - dec->input_filled -= dec->input_consumed; - dec->input_consumed = 0; - size_t readed = dec->io->read((uint8_t*)dec->file.buffer + dec->input_filled, dec->file.size - dec->input_filled, dec->io->read_data); - if (readed > (dec->file.size - dec->input_filled)) - { - dec->last_error = MP3D_E_IOERROR; - readed = 0; - } - if (readed != (dec->file.size - dec->input_filled)) - eof = 1; - dec->input_filled += readed; - if (eof) - mp3dec_skip_id3v1((uint8_t*)dec->file.buffer, &dec->input_filled); - } - dec_buf = dec->file.buffer + dec->input_consumed; - if (!(dec->input_filled - dec->input_consumed)) - return 0; - dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, dec_buf, dec->input_filled - dec->input_consumed, dec->buffer, frame_info); - dec->input_consumed += frame_info->frame_bytes; - } else - { - dec_buf = dec->file.buffer + dec->offset; - uint64_t buf_size = end_offset - dec->offset; - if (!buf_size) - return 0; - dec->buffer_samples = mp3dec_decode_frame(&dec->mp3d, dec_buf, MINIMP3_MIN(buf_size, (uint64_t)INT_MAX), dec->buffer, frame_info); - } - dec->buffer_consumed = 0; - if (dec->info.hz != frame_info->hz || dec->info.layer != frame_info->layer) - { -return_e_decode: - dec->last_error = MP3D_E_DECODE; - return 0; - } - if (dec->buffer_samples) - { - dec->buffer_samples *= frame_info->channels; - if (dec->to_skip) - { - size_t skip = MINIMP3_MIN(dec->buffer_samples, dec->to_skip); - dec->buffer_consumed += skip; - dec->to_skip -= skip; - } - if ( -#ifdef MINIMP3_ALLOW_MONO_STEREO_TRANSITION - !(dec->flags & MP3D_ALLOW_MONO_STEREO_TRANSITION) && -#endif - dec->buffer_consumed != dec->buffer_samples && dec->info.channels != frame_info->channels) - { - goto return_e_decode; - } - } else if (dec->to_skip) - { /* In mp3 decoding not always can start decode from any frame because of bit reservoir, - count skip samples for such frames */ - int frame_samples = hdr_frame_samples(dec_buf)*frame_info->channels; - dec->to_skip -= MINIMP3_MIN(frame_samples, dec->to_skip); - } - dec->offset += frame_info->frame_bytes; - } - size_t out_samples = MINIMP3_MIN((size_t)(dec->buffer_samples - dec->buffer_consumed), max_samples); - if (dec->detected_samples) - { /* count decoded samples to properly cut padding */ - if (dec->cur_sample + out_samples >= dec->detected_samples) - out_samples = dec->detected_samples - dec->cur_sample; - } - dec->cur_sample += out_samples; - *buf = dec->buffer + dec->buffer_consumed; - dec->buffer_consumed += out_samples; - return out_samples; -} - -size_t mp3dec_ex_read(mp3dec_ex_t *dec, mp3d_sample_t *buf, size_t samples) -{ - if (!dec || !buf) - { - if (dec) - dec->last_error = MP3D_E_PARAM; - return 0; - } - mp3dec_frame_info_t frame_info; - memset(&frame_info, 0, sizeof(frame_info)); - size_t samples_requested = samples; - while (samples) - { - mp3d_sample_t *buf_frame = NULL; - size_t read_samples = mp3dec_ex_read_frame(dec, &buf_frame, &frame_info, samples); - if (!read_samples) - { - break; - } - memcpy(buf, buf_frame, read_samples * sizeof(mp3d_sample_t)); - buf += read_samples; - samples -= read_samples; - } - return samples_requested - samples; -} - -int mp3dec_ex_open_cb(mp3dec_ex_t *dec, mp3dec_io_t *io, int flags) -{ - if (!dec || !io || (flags & (~MP3D_FLAGS_MASK))) - return MP3D_E_PARAM; - memset(dec, 0, sizeof(*dec)); -#ifdef MINIMP3_HAVE_RING - int ret; - if (ret = mp3dec_open_ring(&dec->file, MINIMP3_IO_SIZE)) - return ret; -#else - dec->file.size = MINIMP3_IO_SIZE; - dec->file.buffer = (const uint8_t*)malloc(dec->file.size); - if (!dec->file.buffer) - return MP3D_E_MEMORY; -#endif - dec->flags = flags; - dec->io = io; - mp3dec_init(&dec->mp3d); - if (io->seek(0, io->seek_data)) - return MP3D_E_IOERROR; - int ret = mp3dec_iterate_cb(io, (uint8_t *)dec->file.buffer, dec->file.size, mp3dec_load_index, dec); - if (ret && MP3D_E_USER != ret) - return ret; - if (dec->io->seek(dec->start_offset, dec->io->seek_data)) - return MP3D_E_IOERROR; - mp3dec_init(&dec->mp3d); - dec->buffer_samples = 0; - dec->indexes_built = !(dec->vbr_tag_found || (flags & MP3D_DO_NOT_SCAN)); - dec->flags &= (~MP3D_DO_NOT_SCAN); - return 0; -} - - -#ifndef MINIMP3_NO_STDIO - -#if defined(__linux__) || defined(__FreeBSD__) -#include -#include -#include -#include -#include -#include -#if !defined(_GNU_SOURCE) -#include -#include -#endif -#if !defined(MAP_POPULATE) && defined(__linux__) -#define MAP_POPULATE 0x08000 -#elif !defined(MAP_POPULATE) -#define MAP_POPULATE 0 -#endif - -static void mp3dec_close_file(mp3dec_map_info_t *map_info) -{ - if (map_info->buffer && MAP_FAILED != map_info->buffer) - munmap((void *)map_info->buffer, map_info->size); - map_info->buffer = 0; - map_info->size = 0; -} - -static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info) -{ - if (!file_name) - return MP3D_E_PARAM; - int file; - struct stat st; - memset(map_info, 0, sizeof(*map_info)); -retry_open: - file = open(file_name, O_RDONLY); - if (file < 0 && (errno == EAGAIN || errno == EINTR)) - goto retry_open; - if (file < 0 || fstat(file, &st) < 0) - { - close(file); - return MP3D_E_IOERROR; - } - - map_info->size = st.st_size; -retry_mmap: - map_info->buffer = (const uint8_t *)mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE | MAP_POPULATE, file, 0); - if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) - goto retry_mmap; - close(file); - if (MAP_FAILED == map_info->buffer) - return MP3D_E_IOERROR; - return 0; -} - -#if MINIMP3_ENABLE_RING && defined(__linux__) && defined(_GNU_SOURCE) -#define MINIMP3_HAVE_RING -static void mp3dec_close_ring(mp3dec_map_info_t *map_info) -{ -#if defined(__linux__) && defined(_GNU_SOURCE) - if (map_info->buffer && MAP_FAILED != map_info->buffer) - munmap((void *)map_info->buffer, map_info->size*2); -#else - if (map_info->buffer) - { - shmdt(map_info->buffer); - shmdt(map_info->buffer + map_info->size); - } -#endif - map_info->buffer = 0; - map_info->size = 0; -} - -static int mp3dec_open_ring(mp3dec_map_info_t *map_info, size_t size) -{ - int memfd, page_size; -#if defined(__linux__) && defined(_GNU_SOURCE) - void *buffer; - int res; -#endif - memset(map_info, 0, sizeof(*map_info)); - -#ifdef _SC_PAGESIZE - page_size = sysconf(_SC_PAGESIZE); -#else - page_size = getpagesize(); -#endif - map_info->size = (size + page_size - 1)/page_size*page_size; - -#if defined(__linux__) && defined(_GNU_SOURCE) - memfd = memfd_create("mp3_ring", 0); - if (memfd < 0) - return MP3D_E_MEMORY; - -retry_ftruncate: - res = ftruncate(memfd, map_info->size); - if (res && (errno == EAGAIN || errno == EINTR)) - goto retry_ftruncate; - if (res) - goto error; - -retry_mmap: - map_info->buffer = (const uint8_t *)mmap(NULL, map_info->size*2, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); - if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) - goto retry_mmap; - if (MAP_FAILED == map_info->buffer || !map_info->buffer) - goto error; -retry_mmap2: - buffer = mmap((void *)map_info->buffer, map_info->size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, memfd, 0); - if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) - goto retry_mmap2; - if (MAP_FAILED == map_info->buffer || buffer != (void *)map_info->buffer) - goto error; -retry_mmap3: - buffer = mmap((void *)map_info->buffer + map_info->size, map_info->size, PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, memfd, 0); - if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) - goto retry_mmap3; - if (MAP_FAILED == map_info->buffer || buffer != (void *)(map_info->buffer + map_info->size)) - goto error; - - close(memfd); - return 0; -error: - close(memfd); - mp3dec_close_ring(map_info); - return MP3D_E_MEMORY; -#else - memfd = shmget(IPC_PRIVATE, map_info->size, IPC_CREAT | 0700); - if (memfd < 0) - return MP3D_E_MEMORY; -retry_mmap: - map_info->buffer = (const uint8_t *)mmap(NULL, map_info->size*2, PROT_NONE, MAP_PRIVATE, -1, 0); - if (MAP_FAILED == map_info->buffer && (errno == EAGAIN || errno == EINTR)) - goto retry_mmap; - if (MAP_FAILED == map_info->buffer) - goto error; - if (map_info->buffer != shmat(memfd, map_info->buffer, 0)) - goto error; - if ((map_info->buffer + map_info->size) != shmat(memfd, map_info->buffer + map_info->size, 0)) - goto error; - if (shmctl(memfd, IPC_RMID, NULL) < 0) - return MP3D_E_MEMORY; - return 0; -error: - shmctl(memfd, IPC_RMID, NULL); - mp3dec_close_ring(map_info); - return MP3D_E_MEMORY; -#endif -} -#endif /*MINIMP3_ENABLE_RING*/ -#elif defined(_WIN32) -#include - -static void mp3dec_close_file(mp3dec_map_info_t *map_info) -{ - if (map_info->buffer) - UnmapViewOfFile(map_info->buffer); - map_info->buffer = 0; - map_info->size = 0; -} - -static int mp3dec_open_file_h(HANDLE file, mp3dec_map_info_t *map_info) -{ - memset(map_info, 0, sizeof(*map_info)); - - HANDLE mapping = NULL; - LARGE_INTEGER s; - s.LowPart = GetFileSize(file, (DWORD*)&s.HighPart); - if (s.LowPart == INVALID_FILE_SIZE && GetLastError() != NO_ERROR) - goto error; - map_info->size = s.QuadPart; - - mapping = CreateFileMapping(file, NULL, PAGE_READONLY, 0, 0, NULL); - if (!mapping) - goto error; - map_info->buffer = (const uint8_t*)MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, s.QuadPart); - CloseHandle(mapping); - if (!map_info->buffer) - goto error; - - CloseHandle(file); - return 0; -error: - mp3dec_close_file(map_info); - CloseHandle(file); - return MP3D_E_IOERROR; -} - -static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info) -{ - if (!file_name) - return MP3D_E_PARAM; - HANDLE file = CreateFileA(file_name, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); - if (INVALID_HANDLE_VALUE == file) - return MP3D_E_IOERROR; - return mp3dec_open_file_h(file, map_info); -} - -static int mp3dec_open_file_w(const wchar_t *file_name, mp3dec_map_info_t *map_info) -{ - if (!file_name) - return MP3D_E_PARAM; - HANDLE file = CreateFileW(file_name, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0); - if (INVALID_HANDLE_VALUE == file) - return MP3D_E_IOERROR; - return mp3dec_open_file_h(file, map_info); -} -#else -#include - -static void mp3dec_close_file(mp3dec_map_info_t *map_info) -{ - if (map_info->buffer) - free((void *)map_info->buffer); - map_info->buffer = 0; - map_info->size = 0; -} - -static int mp3dec_open_file(const char *file_name, mp3dec_map_info_t *map_info) -{ - if (!file_name) - return MP3D_E_PARAM; - memset(map_info, 0, sizeof(*map_info)); - FILE *file = fopen(file_name, "rb"); - if (!file) - return MP3D_E_IOERROR; - int res = MP3D_E_IOERROR; - long size = -1; - if (fseek(file, 0, SEEK_END)) - goto error; - size = ftell(file); - if (size < 0) - goto error; - map_info->size = (size_t)size; - if (fseek(file, 0, SEEK_SET)) - goto error; - map_info->buffer = (uint8_t *)malloc(map_info->size); - if (!map_info->buffer) - { - res = MP3D_E_MEMORY; - goto error; - } - if (fread((void *)map_info->buffer, 1, map_info->size, file) != map_info->size) - goto error; - fclose(file); - return 0; -error: - mp3dec_close_file(map_info); - fclose(file); - return res; -} -#endif - -static int mp3dec_detect_mapinfo(mp3dec_map_info_t *map_info) -{ - int ret = mp3dec_detect_buf(map_info->buffer, map_info->size); - mp3dec_close_file(map_info); - return ret; -} - -static int mp3dec_load_mapinfo(mp3dec_t *dec, mp3dec_map_info_t *map_info, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) -{ - int ret = mp3dec_load_buf(dec, map_info->buffer, map_info->size, info, progress_cb, user_data); - mp3dec_close_file(map_info); - return ret; -} - -static int mp3dec_iterate_mapinfo(mp3dec_map_info_t *map_info, MP3D_ITERATE_CB callback, void *user_data) -{ - int ret = mp3dec_iterate_buf(map_info->buffer, map_info->size, callback, user_data); - mp3dec_close_file(map_info); - return ret; -} - -static int mp3dec_ex_open_mapinfo(mp3dec_ex_t *dec, int flags) -{ - int ret = mp3dec_ex_open_buf(dec, dec->file.buffer, dec->file.size, flags); - dec->is_file = 1; - if (ret) - mp3dec_ex_close(dec); - return ret; -} - -int mp3dec_detect(const char *file_name) -{ - int ret; - mp3dec_map_info_t map_info; - if ((ret = mp3dec_open_file(file_name, &map_info))) - return ret; - return mp3dec_detect_mapinfo(&map_info); -} - -int mp3dec_load(mp3dec_t *dec, const char *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) -{ - int ret; - mp3dec_map_info_t map_info; - if ((ret = mp3dec_open_file(file_name, &map_info))) - return ret; - return mp3dec_load_mapinfo(dec, &map_info, info, progress_cb, user_data); -} - -int mp3dec_iterate(const char *file_name, MP3D_ITERATE_CB callback, void *user_data) -{ - int ret; - mp3dec_map_info_t map_info; - if ((ret = mp3dec_open_file(file_name, &map_info))) - return ret; - return mp3dec_iterate_mapinfo(&map_info, callback, user_data); -} - -int mp3dec_ex_open(mp3dec_ex_t *dec, const char *file_name, int flags) -{ - int ret; - if (!dec) - return MP3D_E_PARAM; - if ((ret = mp3dec_open_file(file_name, &dec->file))) - return ret; - return mp3dec_ex_open_mapinfo(dec, flags); -} - -void mp3dec_ex_close(mp3dec_ex_t *dec) -{ -#ifdef MINIMP3_HAVE_RING - if (dec->io) - mp3dec_close_ring(&dec->file); -#else - if (dec->io && dec->file.buffer) - free((void*)dec->file.buffer); -#endif - if (dec->is_file) - mp3dec_close_file(&dec->file); - if (dec->index.frames) - free(dec->index.frames); - memset(dec, 0, sizeof(*dec)); -} - -#ifdef _WIN32 -int mp3dec_detect_w(const wchar_t *file_name) -{ - int ret; - mp3dec_map_info_t map_info; - if ((ret = mp3dec_open_file_w(file_name, &map_info))) - return ret; - return mp3dec_detect_mapinfo(&map_info); -} - -int mp3dec_load_w(mp3dec_t *dec, const wchar_t *file_name, mp3dec_file_info_t *info, MP3D_PROGRESS_CB progress_cb, void *user_data) -{ - int ret; - mp3dec_map_info_t map_info; - if ((ret = mp3dec_open_file_w(file_name, &map_info))) - return ret; - return mp3dec_load_mapinfo(dec, &map_info, info, progress_cb, user_data); -} - -int mp3dec_iterate_w(const wchar_t *file_name, MP3D_ITERATE_CB callback, void *user_data) -{ - int ret; - mp3dec_map_info_t map_info; - if ((ret = mp3dec_open_file_w(file_name, &map_info))) - return ret; - return mp3dec_iterate_mapinfo(&map_info, callback, user_data); -} - -int mp3dec_ex_open_w(mp3dec_ex_t *dec, const wchar_t *file_name, int flags) -{ - int ret; - if ((ret = mp3dec_open_file_w(file_name, &dec->file))) - return ret; - return mp3dec_ex_open_mapinfo(dec, flags); -} -#endif -#else /* MINIMP3_NO_STDIO */ -void mp3dec_ex_close(mp3dec_ex_t *dec) -{ -#ifdef MINIMP3_HAVE_RING - if (dec->io) - mp3dec_close_ring(&dec->file); -#else - if (dec->io && dec->file.buffer) - free((void*)dec->file.buffer); -#endif - if (dec->index.frames) - free(dec->index.frames); - memset(dec, 0, sizeof(*dec)); -} -#endif - -#endif /*MINIMP3_IMPLEMENTATION*/ -- Gitee