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