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