• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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