1 /*
2 * Copyright (C) 2023 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 #include <set>
17 #include <dlfcn.h>
18 #include "avcodec_errors.h"
19 #include "avcodec_trace.h"
20 #include "avcodec_log.h"
21 #include "media_description.h"
22 #include "avcodec_mime_type.h"
23 #include "ffmpeg_converter.h"
24 #include "avcodec_audio_common.h"
25 #include "securec.h"
26 #include "audio_opus_decoder_plugin.h"
27
28 namespace {
29 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_AUDIO, "AvCodec-AudioOpusDecoderPlugin"};
30 constexpr std::string_view AUDIO_CODEC_NAME = "opus";
31 constexpr int32_t INITVAL = -1;
32 constexpr int64_t TIME_US = 20000;
33 constexpr int32_t MIN_CHANNELS = 1;
34 constexpr int32_t MAX_CHANNELS = 2;
35
36 static const int32_t OPUS_DECODER_SAMPLE_RATE_TABLE[] = {
37 8000, 12000, 16000, 24000, 48000
38 };
39 }
40
41 namespace OHOS {
42 namespace MediaAVCodec {
AudioOpusDecoderPlugin()43 AudioOpusDecoderPlugin::AudioOpusDecoderPlugin()
44 : PluginCodecPtr(nullptr), fbytes(nullptr), len(-1), codeData(nullptr), channels(-1), sampleRate(-1)
45 {
46 ret = 0;
47 handle = dlopen("libav_codec_ext_base.z.so", 1);
48 if (!handle) {
49 ret = -1;
50 AVCODEC_LOGE("AudioOpusDecoderPlugin dlopen error, check .so file exist");
51 }
52 OpusPluginClassCreateFun *PluginCodecCreate =
53 (OpusPluginClassCreateFun *)dlsym(handle, "OpusPluginClassDecoderCreate");
54 if (!PluginCodecCreate) {
55 ret = -1;
56 AVCODEC_LOGE("AudioOpusDecoderPlugin dlsym error, check .so file has this function");
57 }
58 if (ret == 0) {
59 AVCODEC_LOGD("AudioOpusDecoderPlugin dlopen and dlsym success");
60 ret = PluginCodecCreate(&PluginCodecPtr);
61 }
62 }
63
~AudioOpusDecoderPlugin()64 AudioOpusDecoderPlugin::~AudioOpusDecoderPlugin()
65 {
66 Release();
67 }
68
CheckSampleRate(int32_t sampleR)69 static bool CheckSampleRate(int32_t sampleR)
70 {
71 for (auto i : OPUS_DECODER_SAMPLE_RATE_TABLE) {
72 if (i == sampleR) {
73 return true;
74 }
75 }
76 return false;
77 }
78
CheckSampleFormat()79 int32_t AudioOpusDecoderPlugin::CheckSampleFormat()
80 {
81 if (channels < MIN_CHANNELS || channels > MAX_CHANNELS) {
82 AVCODEC_LOGE("AudioOpusDecoderPlugin channels not supported");
83 return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL;
84 }
85 if (!CheckSampleRate(sampleRate)) {
86 AVCODEC_LOGE("AudioOpusDecoderPlugin sampleRate not supported");
87 return AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL;
88 }
89 return AVCodecServiceErrCode::AVCS_ERR_OK;
90 }
91
Init(const Format & format)92 int32_t AudioOpusDecoderPlugin::Init(const Format &format)
93 {
94 CHECK_AND_RETURN_RET_LOG(PluginCodecPtr != nullptr, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL,
95 "AudioOpusDecoderPlugin Init dlopen or dlsym error");
96 channels = INITVAL;
97 sampleRate = INITVAL;
98
99 format.GetIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, channels);
100 format.GetIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, sampleRate);
101
102 format_ = format;
103 format_.PutIntValue(MediaDescriptionKey::MD_KEY_CHANNEL_COUNT, channels);
104 format_.PutIntValue(MediaDescriptionKey::MD_KEY_SAMPLE_RATE, sampleRate);
105 format_.PutStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, AVCodecMimeType::MEDIA_MIMETYPE_AUDIO_OPUS);
106
107 AVCODEC_LOGD("AudioOpusDecoderPlugin parameter channels:%{public}d samplerate:%{public}d", channels, sampleRate);
108 ret = CheckSampleFormat();
109 if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) {
110 AVCODEC_LOGE("AudioOpusDecoderPlugin parameter not supported");
111 return ret;
112 }
113 ret = PluginCodecPtr->SetPluginParameter(CHANNEL, channels);
114 ret = PluginCodecPtr->SetPluginParameter(SAMPLE_RATE, sampleRate);
115 ret = PluginCodecPtr->Init();
116 if (ret != AVCodecServiceErrCode::AVCS_ERR_OK) {
117 return ret;
118 }
119 return AVCodecServiceErrCode::AVCS_ERR_OK;
120 }
121
ProcessSendData(const std::shared_ptr<AudioBufferInfo> & inputBuffer)122 int32_t AudioOpusDecoderPlugin::ProcessSendData(const std::shared_ptr<AudioBufferInfo> &inputBuffer)
123 {
124 CHECK_AND_RETURN_RET_LOG(PluginCodecPtr != nullptr, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL,
125 "AudioOpusDecoderPlugin ProcessSendData dlopen or dlsym error");
126 {
127 std::lock_guard<std::mutex> lock(avMutext_);
128 auto attr = inputBuffer->GetBufferAttr();
129 bool isEos = inputBuffer->CheckIsEos();
130 len = attr.size;
131
132 if ((len <= 0 || (uint32_t) len > inputBuffer->GetBufferSize()) && !isEos) {
133 AVCODEC_LOGE("SendBuffer error buffer size:%{public}d", len);
134 return AVCodecServiceErrCode::AVCS_ERR_INVALID_DATA;
135 }
136 if (!isEos) {
137 auto memory = inputBuffer->GetBuffer();
138 fbytes = memory->GetBase();
139 PluginCodecPtr->ProcessSendData(fbytes, &len);
140 } else {
141 AVCODEC_LOGD("SendBuffer EOS buffer");
142 len = -1;
143 return AVCodecServiceErrCode::AVCS_ERR_END_OF_STREAM;
144 }
145 AVCODEC_LOGD("PCM buffer size:%{public}d", len);
146 }
147 return AVCodecServiceErrCode::AVCS_ERR_OK;
148 }
149
ProcessRecieveData(std::shared_ptr<AudioBufferInfo> & outBuffer)150 int32_t AudioOpusDecoderPlugin::ProcessRecieveData(std::shared_ptr<AudioBufferInfo> &outBuffer)
151 {
152 CHECK_AND_RETURN_RET_LOG(PluginCodecPtr != nullptr, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL,
153 "AudioOpusDecoderPlugin ProcessRecieveData dlopen or dlsym error");
154 {
155 std::lock_guard<std::mutex> lock(avMutext_);
156 if (len > 0) {
157 PluginCodecPtr->ProcessRecieveData(&codeData, len);
158 auto memory = outBuffer->GetBuffer();
159 memory->Write(codeData, len * channels * sizeof(short));
160 auto attr = outBuffer->GetBufferAttr();
161 attr.size = len * channels * sizeof(short);
162 attr.presentationTimeUs = TIME_US;
163 outBuffer->SetBufferAttr(attr);
164 ret = AVCodecServiceErrCode::AVCS_ERR_OK;
165 } else {
166 outBuffer->SetEos(true);
167 ret = AVCodecServiceErrCode::AVCS_ERR_END_OF_STREAM;
168 }
169 }
170 return ret;
171 }
172
Reset()173 int32_t AudioOpusDecoderPlugin::Reset()
174 {
175 std::lock_guard<std::mutex> lock(avMutext_);
176 CHECK_AND_RETURN_RET_LOG(PluginCodecPtr != nullptr, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL,
177 "AudioOpusDecoderPlugin Reset dlopen or dlsym error");
178
179 ret = PluginCodecPtr->Reset();
180 if (ret != 0) {
181 return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN;
182 }
183 return AVCodecServiceErrCode::AVCS_ERR_OK;
184 }
185
Release()186 int32_t AudioOpusDecoderPlugin::Release()
187 {
188 std::lock_guard<std::mutex> lock(avMutext_);
189 CHECK_AND_RETURN_RET_LOG(PluginCodecPtr != nullptr, AVCodecServiceErrCode::AVCS_ERR_OK,
190 "AudioOpusDecoderPlugin Release dlopen or dlsym error");
191
192 ret = PluginCodecPtr->Release();
193 if (ret != 0) {
194 return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN;
195 }
196 delete PluginCodecPtr;
197 PluginCodecPtr = nullptr;
198 if (handle) {
199 dlclose(handle);
200 handle = nullptr;
201 }
202 return AVCodecServiceErrCode::AVCS_ERR_OK;
203 }
204
Flush()205 int32_t AudioOpusDecoderPlugin::Flush()
206 {
207 std::lock_guard<std::mutex> lock(avMutext_);
208 CHECK_AND_RETURN_RET_LOG(PluginCodecPtr != nullptr, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL,
209 "AudioOpusDecoderPlugin Flush dlopen or dlsym error");
210
211 ret = PluginCodecPtr->Flush();
212 if (ret != 0) {
213 return AVCodecServiceErrCode::AVCS_ERR_UNKNOWN;
214 }
215 return AVCodecServiceErrCode::AVCS_ERR_OK;
216 }
217
GetInputBufferSize() const218 int32_t AudioOpusDecoderPlugin::GetInputBufferSize() const
219 {
220 CHECK_AND_RETURN_RET_LOG(PluginCodecPtr != nullptr, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL,
221 "AudioOpusDecoderPlugin Init dlopen or dlsym error");
222
223 return PluginCodecPtr->GetInputBufferSize();
224 }
225
GetOutputBufferSize() const226 int32_t AudioOpusDecoderPlugin::GetOutputBufferSize() const
227 {
228 CHECK_AND_RETURN_RET_LOG(PluginCodecPtr != nullptr, AVCodecServiceErrCode::AVCS_ERR_INVALID_VAL,
229 "AudioOpusDecoderPlugin Init dlopen or dlsym error");
230 return PluginCodecPtr->GetOutputBufferSize();
231 }
232
GetFormat() const233 Format AudioOpusDecoderPlugin::GetFormat() const noexcept
234 {
235 return format_;
236 }
237
GetCodecType() const238 std::string_view AudioOpusDecoderPlugin::GetCodecType() const noexcept
239 {
240 return AUDIO_CODEC_NAME;
241 }
242 } // namespace MediaAVCodec
243 } // namespace OHOS