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