1 /*
2 * Copyright (C) 2024 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 <native_avcodec_audioencoder.h>
17 #include "media_log.h"
18 #include "codec/util/codec_util.h"
19 #include "audio_encoder.h"
20 #include <string>
21 #include "securec.h"
22
23 namespace OHOS {
24 namespace Media {
25 namespace {
26 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = {LOG_CORE, LOG_DOMAIN_VIDEOEDITOR, "AEnc"};
27 }
28
AudioEncoder(uint64_t id,const CodecOnOutData & encodecCallback)29 AudioEncoder::AudioEncoder(uint64_t id, const CodecOnOutData& encodecCallback)
30 : CodecEncoder(id, "audio-encoder"), encodeCallback_(encodecCallback)
31 {
32 pcmInputBufferQueue_ = std::make_shared<PcmBufferQueue>(8); //队列长度为8
33 }
34
~AudioEncoder()35 AudioEncoder::~AudioEncoder()
36 {
37 MEDIA_LOGD("[%{public}s] destruct.", logTag_.c_str());
38 encoderMutex_.lock();
39 if (encoder_) {
40 OH_AudioEncoder_Destroy(encoder_);
41 encoder_ = nullptr;
42 }
43 encoderMutex_.unlock();
44 MEDIA_LOGD("[%{public}s] destruct finish.", logTag_.c_str());
45 }
46
CodecOnErrorInner(OH_AVCodec * codec,int32_t errorCode)47 void AudioEncoder::CodecOnErrorInner(OH_AVCodec* codec, int32_t errorCode)
48 {
49 if (codec == nullptr) {
50 MEDIA_LOGE("[%{public}s] invalid parameter, codec is nullptr.", logTag_.c_str());
51 return;
52 }
53 MEDIA_LOGE("[%{public}s] CodecOnError occurred error: %{public}d.", logTag_.c_str(), errorCode);
54 }
55
CodecOnNewOutputDataInner(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data,OH_AVCodecBufferAttr * attr)56 void AudioEncoder::CodecOnNewOutputDataInner(OH_AVCodec* codec, uint32_t index, OH_AVMemory* data,
57 OH_AVCodecBufferAttr* attr)
58 {
59 if (codec == nullptr || data == nullptr || attr == nullptr) {
60 MEDIA_LOGE("[%{public}s] invalid parameter, codec or data or attr is nullptr.", logTag_.c_str());
61 return;
62 }
63 MEDIA_LOGD("[%{public}s] CodecOnNewOutputData index: %{public}d.", logTag_.c_str(), index);
64 encodeCallback_(codec, index, data, attr);
65 }
66
CodecOnStreamChangedInner(OH_AVFormat * format)67 void AudioEncoder::CodecOnStreamChangedInner(OH_AVFormat* format)
68 {
69 if (format == nullptr) {
70 MEDIA_LOGE("[%{public}s] invalid parameter, format is nullptr.", logTag_.c_str());
71 return;
72 }
73 MEDIA_LOGI("[%{public}s] CodecOnStreamChanged", logTag_.c_str());
74 }
75
CodecOnNeedInputDataInner(OH_AVCodec * codec,uint32_t index,OH_AVMemory * data)76 void AudioEncoder::CodecOnNeedInputDataInner(OH_AVCodec* codec, uint32_t index, OH_AVMemory* data)
77 {
78 if (codec == nullptr || data == nullptr) {
79 MEDIA_LOGE("[%{public}s] CodecOnNeedInputDataInner, invalid parameter.", logTag_.c_str());
80 return;
81 }
82
83 auto pcmData = pcmInputBufferQueue_->Dequeue();
84 if (pcmData == nullptr) {
85 MEDIA_LOGE("[%{public}s] CodecOnNeedInputDataInner, pcmData is nullptr.", logTag_.c_str());
86 return;
87 }
88
89 OH_AVCodecBufferAttr attr {.pts = pcmData->pts, .size = pcmData->dataSize, .offset = 0, .flags = pcmData->flags};
90 if ((attr.flags & AVCODEC_BUFFER_FLAGS_EOS) == AVCODEC_BUFFER_FLAGS_EOS) {
91 MEDIA_LOGI("[%{public}s] audio encode input eof.", logTag_.c_str());
92 } else {
93 if (attr.size <= 0) {
94 // callback error;
95 MEDIA_LOGE("[%{public}s] attr size abnormal, len=%{public}d.", logTag_.c_str(), attr.size);
96 } else if (attr.size > OH_AVMemory_GetSize(data)) {
97 // callback error;
98 MEDIA_LOGE("[%{public}s] attr size bigger than current get size, len=%{public}d.",
99 logTag_.c_str(), OH_AVMemory_GetSize(data));
100 } else {
101 if (EOK != memcpy_s(OH_AVMemory_GetAddr(data),
102 OH_AVMemory_GetSize(data),
103 pcmData->data.get(),
104 attr.size)) {
105 MEDIA_LOGE("[%{public}s] memcpy failed, len=%{public}d.", logTag_.c_str(), attr.size);
106 // callback error;
107 }
108 }
109 }
110
111 VEFError error = PushPcmData(index, attr);
112 if (error != VEFError::ERR_OK) {
113 MEDIA_LOGE("[%{public}s] push pcm data failed with error: %{public}d.", logTag_.c_str(), error);
114 }
115 }
116
PushPcmData(uint32_t index,OH_AVCodecBufferAttr & attr)117 VEFError AudioEncoder::PushPcmData(uint32_t index, OH_AVCodecBufferAttr& attr)
118 {
119 auto errCode = OH_AudioEncoder_PushInputData(encoder_, index, attr);
120 if (errCode != AV_ERR_OK) {
121 MEDIA_LOGE("[%{public}s] push pcm index %{public}u pts %{public}" PRIu64 " size %{public}d"
122 "flags %{public}u ret %{public}s", logTag_.c_str(), index, attr.pts, attr.size, attr.flags,
123 CodecUtil::GetCodecErrorStr(errCode));
124 return VEFError::ERR_INTERNAL_ERROR;
125 }
126 return VEFError::ERR_OK;
127 }
128
CreateEncoder()129 VEFError AudioEncoder::CreateEncoder()
130 {
131 std::lock_guard<ffrt::mutex> lk(encoderMutex_);
132
133 MEDIA_LOGI("[%{public}s] create encoder, audio mime = %{public}s.", logTag_.c_str(), codecMime_.c_str());
134 encoder_ = OH_AudioEncoder_CreateByMime(codecMime_.c_str());
135 if (encoder_ == nullptr) {
136 MEDIA_LOGE("[%{public}s] create audio encoder failed, mime = %{public}s!", logTag_.c_str(), codecMime_.c_str());
137 return VEFError::ERR_INTERNAL_ERROR;
138 }
139
140 auto ret = OH_AudioEncoder_SetCallback(encoder_, GetAVCodecAsyncCallback(), (CodecEncoder*)this);
141 if (ret != AV_ERR_OK) {
142 MEDIA_LOGE("[%{public}s] set callback failed, OH_AudioEncoder_SetCallback return: %{public}d.",
143 logTag_.c_str(), ret);
144 return VEFError::ERR_INTERNAL_ERROR;
145 }
146
147 return VEFError::ERR_OK;
148 }
149
ConfigureEncoder(OH_AVFormat * format)150 VEFError AudioEncoder::ConfigureEncoder(OH_AVFormat* format)
151 {
152 std::lock_guard<ffrt::mutex> lk(encoderMutex_);
153 MEDIA_LOGI("[%{public}s] configure.", logTag_.c_str());
154
155 auto ret = OH_AudioEncoder_Configure(encoder_, format);
156 if (ret != AV_ERR_OK) {
157 MEDIA_LOGE("[%{public}s] configure failed, OH_AudioEncoder_Configure return: %{public}d.", logTag_.c_str(),
158 ret);
159 return VEFError::ERR_INTERNAL_ERROR;
160 }
161
162 MEDIA_LOGI("[%{public}s] configure success.", logTag_.c_str());
163 return VEFError::ERR_OK;
164 }
165
Start()166 VEFError AudioEncoder::Start()
167 {
168 std::lock_guard<ffrt::mutex> lk(encoderMutex_);
169 MEDIA_LOGI("[%{public}s] start encoder.", logTag_.c_str());
170
171 auto ret = OH_AudioEncoder_Prepare(encoder_);
172 if (ret != AV_ERR_OK) {
173 MEDIA_LOGE("[%{public}s] start encoder failed, OH_AudioEncoder_Prepare return: %{public}d.", logTag_.c_str(),
174 ret);
175 return VEFError::ERR_INTERNAL_ERROR;
176 }
177
178 ret = OH_AudioEncoder_Start(encoder_);
179 if (ret != AV_ERR_OK) {
180 MEDIA_LOGE("[%{public}s] start encoder failed, OH_AudioEncoder_Start return: %{public}d.", logTag_.c_str(),
181 ret);
182 return VEFError::ERR_INTERNAL_ERROR;
183 }
184 MEDIA_LOGI("[%{public}s] start encoder success.", logTag_.c_str());
185 return VEFError::ERR_OK;
186 }
187
Stop()188 VEFError AudioEncoder::Stop()
189 {
190 std::lock_guard<ffrt::mutex> lk(encoderMutex_);
191 MEDIA_LOGI("[%{public}s] stop encoder.", logTag_.c_str());
192
193 pcmInputBufferQueue_->CancelDequeue();
194
195 OH_AVErrCode ret = OH_AudioEncoder_Stop(encoder_);
196 if (ret != AV_ERR_OK) {
197 MEDIA_LOGE("[%{public}s] stop encoder failed, OH_AudioEncoder_Stop return: %{public}d.", logTag_.c_str(), ret);
198 return VEFError::ERR_INTERNAL_ERROR;
199 }
200 MEDIA_LOGI("[%{public}s] stop encoder success.", logTag_.c_str());
201 return VEFError::ERR_OK;
202 }
203
Flush()204 VEFError AudioEncoder::Flush()
205 {
206 std::lock_guard<ffrt::mutex> lk(encoderMutex_);
207 MEDIA_LOGI("[%{public}s] flush encoder.", logTag_.c_str());
208 OH_AVErrCode ret = OH_AudioEncoder_Flush(encoder_);
209 if (ret != AV_ERR_OK) {
210 MEDIA_LOGE("[%{public}s] flush encoder failed, OH_AudioEncoder_Flush return: %{public}d.", logTag_.c_str(),
211 ret);
212 return VEFError::ERR_INTERNAL_ERROR;
213 }
214 MEDIA_LOGI("[%{public}s] flush encoder finish.", logTag_.c_str());
215 return VEFError::ERR_OK;
216 }
217
Init(OH_AVFormat * format)218 VEFError AudioEncoder::Init(OH_AVFormat* format)
219 {
220 MEDIA_LOGI("[%{public}s] init encoder.", logTag_.c_str());
221 std::string dumpInfo = OH_AVFormat_DumpInfo(format);
222 MEDIA_LOGI("[%{public}s] initializing encoder, format: %{public}s.", logTag_.c_str(), dumpInfo.c_str());
223
224 const char* mime = nullptr;
225 if (!OH_AVFormat_GetStringValue(format, OH_MD_KEY_CODEC_MIME, &mime)) {
226 MEDIA_LOGE("[%{public}s] get [%{public}s] from audio format failed.", logTag_.c_str(), OH_MD_KEY_CODEC_MIME);
227 return VEFError::ERR_INTERNAL_ERROR;
228 }
229
230 codecMime_ = mime;
231 VEFError error = CreateEncoder();
232 if (error != VEFError::ERR_OK) {
233 MEDIA_LOGE("[%{public}s] init AVCodec-encoder failed with error: %{public}d.", logTag_.c_str(), error);
234 return VEFError::ERR_INTERNAL_ERROR;
235 }
236
237 error = ConfigureEncoder(format);
238 if (error != VEFError::ERR_OK) {
239 MEDIA_LOGE("[%{public}s] configure AVCodec-encoder failed with error: %{public}d.", logTag_.c_str(), error);
240 return VEFError::ERR_INTERNAL_ERROR;
241 }
242 MEDIA_LOGI("[%{public}s] init encoder success.", logTag_.c_str());
243 return VEFError::ERR_OK;
244 }
245
GetPcmInputBufferQueue() const246 std::shared_ptr<PcmBufferQueue> AudioEncoder::GetPcmInputBufferQueue() const
247 {
248 return pcmInputBufferQueue_;
249 }
250 } // namespace Media
251 } // namespace OHOS
252