1 /*
2 * Copyright (c) 2021-2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define HST_LOG_TAG "Minimp3DecoderPlugin"
17
18 #include "minimp3_decoder_plugin.h"
19 #include <cstring>
20 #include <map>
21 #include <set>
22 #include "foundation/log.h"
23 #include "foundation/utils/constants.h"
24 #include "plugin/common/plugin_audio_tags.h"
25 #include "plugin/common/plugin_caps_builder.h"
26
27 namespace OHOS {
28 namespace Media {
29 namespace Plugin {
30 namespace Minimp3 {
31 namespace {
32 constexpr uint32_t MP3_384_SAMPLES_PER_FRAME = 384; // 384
33 constexpr uint32_t MP3_576_SAMPLES_PER_FRAME = 576; // 576
34 constexpr uint32_t MP3_MAX_SAMPLES_PER_FRAME = 1152; // 1152
35 constexpr uint32_t BUFFER_ITEM_CNT = 6; // 6
36 constexpr uint32_t MAX_RANK = 100; // 100
37 }
38
Minimp3DecoderPlugin(std::string name)39 Minimp3DecoderPlugin::Minimp3DecoderPlugin(std::string name)
40 : CodecPlugin(std::move(name)),
41 samplesPerFrame_(0),
42 channels_(0),
43 mp3Parameter_()
44 {
45 FALSE_LOG(memset_s(&mp3DecoderAttr_, sizeof(mp3DecoderAttr_), 0x00, sizeof(AudioDecoderMp3Attr)) == 0);
46 FALSE_LOG(memset_s(&minimp3DecoderImpl_, sizeof(minimp3DecoderImpl_), 0x00, sizeof(Minimp3DemuxerOp)) == 0);
47 MEDIA_LOG_I("Minimp3DecoderPlugin, plugin name: " PUBLIC_LOG_S, pluginName_.c_str());
48 }
49
~Minimp3DecoderPlugin()50 Minimp3DecoderPlugin::~Minimp3DecoderPlugin()
51 {
52 MEDIA_LOG_I("~Minimp3DecoderPlugin, plugin name: " PUBLIC_LOG_S, pluginName_.c_str());
53 }
54
Init()55 Status Minimp3DecoderPlugin::Init()
56 {
57 minimp3DecoderImpl_ = MiniMp3GetOpt();
58 AudioDecoderMp3Open();
59 mp3Parameter_[Tag::REQUIRED_OUT_BUFFER_CNT] = BUFFER_ITEM_CNT;
60 mp3Parameter_[Tag::AUDIO_SAMPLE_PER_FRAME] = MP3_MAX_SAMPLES_PER_FRAME;
61 return Status::OK;
62 }
63
Deinit()64 Status Minimp3DecoderPlugin::Deinit()
65 {
66 AudioDecoderMp3Close();
67 return Status::OK;
68 }
69
SetParameter(Tag tag,const ValueType & value)70 Status Minimp3DecoderPlugin::SetParameter(Tag tag, const ValueType& value)
71 {
72 mp3Parameter_.insert(std::make_pair(tag, value));
73 return Status::OK;
74 }
75
GetParameter(Tag tag,ValueType & value)76 Status Minimp3DecoderPlugin::GetParameter(Tag tag, ValueType& value)
77 {
78 auto res = mp3Parameter_.find(tag);
79 if (res != mp3Parameter_.end()) {
80 value = res->second;
81 return Status::OK;
82 }
83 return Status::ERROR_INVALID_PARAMETER;
84 }
85
Prepare()86 Status Minimp3DecoderPlugin::Prepare()
87 {
88 if (mp3Parameter_.find(Tag::AUDIO_CHANNELS) != mp3Parameter_.end()) {
89 channels_ = AnyCast<uint32_t>((mp3Parameter_.find(Tag::AUDIO_CHANNELS))->second);
90 }
91 if (mp3Parameter_.find(Tag::AUDIO_SAMPLE_PER_FRAME) != mp3Parameter_.end()) {
92 samplesPerFrame_ = AnyCast<uint32_t>(mp3Parameter_.find(Tag::AUDIO_SAMPLE_PER_FRAME)->second);
93 }
94 if (samplesPerFrame_ != MP3_384_SAMPLES_PER_FRAME && samplesPerFrame_ != MP3_576_SAMPLES_PER_FRAME &&
95 samplesPerFrame_ != MP3_MAX_SAMPLES_PER_FRAME) {
96 return Status::ERROR_INVALID_PARAMETER;
97 }
98 MEDIA_LOG_I("channels_ = " PUBLIC_LOG_D32 " samplesPerFrame_ = " PUBLIC_LOG_D32, channels_, samplesPerFrame_);
99 return Status::OK;
100 }
101
Reset()102 Status Minimp3DecoderPlugin::Reset()
103 {
104 mp3Parameter_.clear();
105 return Status::OK;
106 }
107
Start()108 Status Minimp3DecoderPlugin::Start()
109 {
110 return Status::OK;
111 }
112
Stop()113 Status Minimp3DecoderPlugin::Stop()
114 {
115 return Status::OK;
116 }
117
GetAllocator()118 std::shared_ptr<Allocator> Minimp3DecoderPlugin::GetAllocator()
119 {
120 return nullptr;
121 }
122
SetCallback(Callback * cb)123 Status Minimp3DecoderPlugin::SetCallback(Callback* cb)
124 {
125 return Status::OK;
126 }
127
GetPcmDataProcess(const std::shared_ptr<Buffer> & inputBuffer,std::shared_ptr<Buffer> & outputBuffer)128 Status Minimp3DecoderPlugin::GetPcmDataProcess(const std::shared_ptr<Buffer>& inputBuffer,
129 std::shared_ptr<Buffer>& outputBuffer)
130 {
131 if (inputBuffer == nullptr) {
132 return Status::ERROR_NOT_ENOUGH_DATA;
133 }
134 if (outputBuffer == nullptr || outputBuffer->IsEmpty()) {
135 MEDIA_LOG_W("outputBuffer nullptr warning");
136 return Status::ERROR_INVALID_PARAMETER;
137 }
138 if (inputBuffer->IsEmpty() && (inputBuffer->flag & BUFFER_FLAG_EOS) != 0) {
139 MEDIA_LOG_I("eos received");
140 outputBuffer->GetMemory()->Reset();
141 outputBuffer->flag |= BUFFER_FLAG_EOS;
142 return Status::END_OF_STREAM;
143 }
144 return AudioDecoderMp3Process(inputBuffer_, outputBuffer);
145 }
146
QueueOutputBuffer(const std::shared_ptr<Buffer> & outputBuffers,int32_t timeoutMs)147 Status Minimp3DecoderPlugin::QueueOutputBuffer(const std::shared_ptr<Buffer>& outputBuffers, int32_t timeoutMs)
148 {
149 MEDIA_LOG_DD("queue output buffer");
150 (void)timeoutMs;
151 if (!outputBuffers) {
152 return Status::ERROR_INVALID_PARAMETER;
153 }
154 outputBuffer_ = outputBuffers;
155 return SendOutputBuffer();
156 }
157
SendOutputBuffer()158 Status Minimp3DecoderPlugin::SendOutputBuffer()
159 {
160 MEDIA_LOG_DD("send output buffer");
161 OSAL::ScopedLock lock(ioMutex_);
162 Status status = GetPcmDataProcess(inputBuffer_, outputBuffer_);
163 inputBuffer_.reset();
164 inputBuffer_ = nullptr;
165 if (status == Status::OK || status == Status::END_OF_STREAM) {
166 dataCb_->OnOutputBufferDone(outputBuffer_);
167 }
168 outputBuffer_.reset();
169 outputBuffer_ = nullptr;
170 return status;
171 }
172
QueueInputBuffer(const std::shared_ptr<Buffer> & inputBuffer,int32_t timeoutMs)173 Status Minimp3DecoderPlugin::QueueInputBuffer(const std::shared_ptr<Buffer>& inputBuffer, int32_t timeoutMs)
174 {
175 MEDIA_LOG_DD("queue input buffer");
176 (void)timeoutMs;
177 if (inputBuffer->IsEmpty() && !(inputBuffer->flag & BUFFER_FLAG_EOS)) {
178 MEDIA_LOG_E("decoder does not support fd buffer");
179 return Status::ERROR_INVALID_DATA;
180 } else {
181 inputBuffer_ = inputBuffer;
182 return Status::OK;
183 }
184 }
185
Flush()186 Status Minimp3DecoderPlugin::Flush()
187 {
188 return Status::OK;
189 }
190
SetDataCallback(DataCallback * dataCallback)191 Status Minimp3DecoderPlugin::SetDataCallback(DataCallback* dataCallback)
192 {
193 dataCb_ = dataCallback;
194 return Status::OK;
195 }
196
AudioDecoderMp3Open()197 void Minimp3DecoderPlugin::AudioDecoderMp3Open()
198 {
199 Minimp3WrapperMp3decInit(&mp3DecoderAttr_.mp3DecoderHandle);
200 }
201
AudioDecoderMp3Close()202 int Minimp3DecoderPlugin::AudioDecoderMp3Close()
203 {
204 return 0;
205 }
206
AudioDecoderMp3Process(std::shared_ptr<Buffer> inBuffer,std::shared_ptr<Buffer> outBuffer)207 Status Minimp3DecoderPlugin::AudioDecoderMp3Process(std::shared_ptr<Buffer> inBuffer, std::shared_ptr<Buffer> outBuffer)
208 {
209 auto inData = inBuffer->GetMemory();
210 auto outData = outBuffer->GetMemory();
211 Minimp3WrapperMp3decFrameInfo frameInfo;
212
213 uint32_t probePcmLength = samplesPerFrame_ * sizeof(Mp3DecoderSample) * channels_;
214 if (outData->GetCapacity() < probePcmLength) {
215 return Status::ERROR_UNKNOWN;
216 }
217 int16_t *pcmPtr = (int16_t *)outData->GetWritableAddr(probePcmLength, 0);
218 int sampleCount = minimp3DecoderImpl_.decoderFrame(&mp3DecoderAttr_.mp3DecoderHandle, inData->GetReadOnlyData(),
219 inData->GetSize(), pcmPtr, &frameInfo);
220 outBuffer->pts = inBuffer->pts;
221 if (sampleCount > 0) {
222 if (frameInfo.frame_bytes) {
223 return Status::OK;
224 }
225 } else if (sampleCount == 0) {
226 return Status::OK;
227 }
228 return Status::ERROR_UNKNOWN;
229 }
230
231 namespace {
232 void UpdatePluginDefinition(CodecPluginDef& definition);
Minimp3DecoderCreator(const std::string & name)233 std::shared_ptr<CodecPlugin> Minimp3DecoderCreator(const std::string& name)
234 {
235 return std::make_shared<Minimp3DecoderPlugin>(name);
236 }
237
RegisterDecoderPlugin(const std::shared_ptr<Register> & reg)238 Status RegisterDecoderPlugin(const std::shared_ptr<Register>& reg)
239 {
240 MEDIA_LOG_I("RegisterPlugins called.");
241 if (!reg) {
242 MEDIA_LOG_E("RegisterPlugins failed due to nullptr pointer for reg.");
243 return Status::ERROR_INVALID_PARAMETER;
244 }
245
246 CodecPluginDef definition;
247 definition.name = "Minimp3DecoderPlugin";
248 definition.pluginType = PluginType::AUDIO_DECODER;
249 definition.rank = MAX_RANK;
250 definition.creator = Minimp3DecoderCreator;
251 UpdatePluginDefinition(definition);
252 if (reg->AddPlugin(definition) != Status::OK) {
253 MEDIA_LOG_W("register minimp3 decoder plugin failed");
254 }
255 return Status::OK;
256 }
257
UpdateInCaps(CodecPluginDef & definition)258 void UpdateInCaps(CodecPluginDef& definition)
259 {
260 CapabilityBuilder capBuilder;
261 capBuilder.SetMime(OHOS::Media::MEDIA_MIME_AUDIO_MPEG)
262 .SetAudioMpegVersion(1)
263 .SetAudioMpegLayerRange(1, 3); // 3
264 DiscreteCapability<uint32_t> values = {8000, 16000, 22050, 44100, 48000, 32000}; // 8000, 16000 etc. sample rates
265 capBuilder.SetAudioSampleRateList(values);
266 DiscreteCapability<AudioChannelLayout> channelLayoutValues = {
267 AudioChannelLayout::MONO, AudioChannelLayout::STEREO};
268 capBuilder.SetAudioChannelLayoutList(channelLayoutValues);
269 definition.inCaps.push_back(capBuilder.Build());
270 }
271
UpdateOutCaps(CodecPluginDef & definition)272 void UpdateOutCaps(CodecPluginDef& definition)
273 {
274 CapabilityBuilder capBuilder;
275 capBuilder.SetMime(OHOS::Media::MEDIA_MIME_AUDIO_RAW);
276 capBuilder.SetAudioSampleFormatList({AudioSampleFormat::S16});
277 definition.outCaps.emplace_back(capBuilder.Build());
278 }
279
UpdatePluginDefinition(CodecPluginDef & definition)280 void UpdatePluginDefinition(CodecPluginDef& definition)
281 {
282 UpdateInCaps(definition);
283 UpdateOutCaps(definition);
284 }
285 }
286
__anon8d91ac570302null287 PLUGIN_DEFINITION(Minimp3Decoder, LicenseType::CC0, RegisterDecoderPlugin, [] {});
288 } // namespace Minimp3
289 } // namespace Plugin
290 } // namespace Media
291 } // namespace OHOS