• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "Ffmpeg_Au_Encoder"
17 
18 #include "audio_ffmpeg_encoder_plugin.h"
19 #include <cstring>
20 #include <map>
21 #include <set>
22 #include "ffmpeg_au_enc_config.h"
23 #include "plugin/common/plugin_caps_builder.h"
24 #include "plugins/ffmpeg_adapter/utils/ffmpeg_utils.h"
25 
26 namespace {
27 // register plugins
28 using namespace OHOS::Media::Plugin;
29 using namespace Ffmpeg;
30 void UpdatePluginDefinition(const AVCodec* codec, CodecPluginDef& definition);
31 
32 std::map<std::string, std::shared_ptr<const AVCodec>> codecMap;
33 const size_t BUFFER_QUEUE_SIZE = 6;
34 std::set<AVCodecID> g_supportedCodec = {AV_CODEC_ID_AAC, AV_CODEC_ID_AAC_LATM};
35 
AuFfmpegEncoderCreator(const std::string & name)36 std::shared_ptr<CodecPlugin> AuFfmpegEncoderCreator(const std::string& name)
37 {
38     return std::make_shared<AudioFfmpegEncoderPlugin>(name);
39 }
40 
RegisterAudioEncoderPlugins(const std::shared_ptr<Register> & reg)41 Status RegisterAudioEncoderPlugins(const std::shared_ptr<Register>& reg)
42 {
43     const AVCodec* codec = nullptr;
44     void* ite = nullptr;
45     MEDIA_LOG_I("registering audio encoders");
46     while ((codec = av_codec_iterate(&ite))) {
47         if (!av_codec_is_encoder(codec) || codec->type != AVMEDIA_TYPE_AUDIO) {
48             continue;
49         }
50         if (g_supportedCodec.find(codec->id) == g_supportedCodec.end()) {
51             MEDIA_LOG_DD("codec " PUBLIC_LOG_S "(" PUBLIC_LOG_S ") is not supported right now",
52                          codec->name, codec->long_name);
53             continue;
54         }
55         CodecPluginDef definition;
56         definition.name = "ffmpegAuEnc_" + std::string(codec->name);
57         definition.codecType = CodecType::AUDIO_ENCODER;
58         definition.rank = 100; // 100
59         definition.creator = AuFfmpegEncoderCreator;
60         UpdatePluginDefinition(codec, definition);
61         // do not delete the codec in the deleter
62         codecMap[definition.name] = std::shared_ptr<AVCodec>(const_cast<AVCodec*>(codec), [](void* ptr) {});
63         if (reg->AddPlugin(definition) != Status::OK) {
64             MEDIA_LOG_W("register plugin " PUBLIC_LOG_S "(" PUBLIC_LOG_S ") failed", codec->name, codec->long_name);
65         }
66     }
67     return Status::OK;
68 }
69 
UnRegisterAudioEncoderPlugin()70 void UnRegisterAudioEncoderPlugin()
71 {
72     codecMap.clear();
73 }
74 
UpdateInCaps(const AVCodec * codec,CodecPluginDef & definition)75 void UpdateInCaps(const AVCodec* codec, CodecPluginDef& definition)
76 {
77     CapabilityBuilder capBuilder;
78     capBuilder.SetMime(OHOS::Media::MEDIA_MIME_AUDIO_RAW);
79     if (codec->supported_samplerates != nullptr) {
80         DiscreteCapability<uint32_t> values;
81         size_t index = 0;
82         for (; codec->supported_samplerates[index] != 0; ++index) {
83             values.push_back(codec->supported_samplerates[index]);
84         }
85         if (index) {
86             capBuilder.SetAudioSampleRateList(values);
87         }
88     }
89     definition.inCaps.push_back(capBuilder.Build());
90 }
91 
UpdateOutCaps(const AVCodec * codec,CodecPluginDef & definition)92 void UpdateOutCaps(const AVCodec* codec, CodecPluginDef& definition)
93 {
94     CapabilityBuilder capBuilder;
95     switch (codec->id) {
96         case AV_CODEC_ID_AAC:
97             capBuilder.SetMime(OHOS::Media::MEDIA_MIME_AUDIO_AAC)
98                 .SetAudioMpegVersion(4) // 4
99                 .SetAudioAacProfile(AudioAacProfile::LC)
100                 .SetAudioAacStreamFormat(AudioAacStreamFormat::MP4ADTS);
101             break;
102         case AV_CODEC_ID_AAC_LATM:
103             capBuilder.SetMime(OHOS::Media::MEDIA_MIME_AUDIO_AAC_LATM)
104                 .SetAudioMpegVersion(4)  // 4
105                 .SetAudioAacStreamFormat(AudioAacStreamFormat::MP4LOAS);
106             break;
107         default:
108             MEDIA_LOG_I("codec is not supported right now");
109     }
110     definition.outCaps.push_back(capBuilder.Build());
111 }
112 
UpdatePluginDefinition(const AVCodec * codec,CodecPluginDef & definition)113 void UpdatePluginDefinition(const AVCodec* codec, CodecPluginDef& definition)
114 {
115     UpdateInCaps(codec, definition);
116     UpdateOutCaps(codec, definition);
117 }
118 } // namespace
119 PLUGIN_DEFINITION(FFmpegAudioEncoders, LicenseType::LGPL, RegisterAudioEncoderPlugins, UnRegisterAudioEncoderPlugin);
120 
121 namespace OHOS {
122 namespace Media {
123 namespace Plugin {
124 namespace Ffmpeg {
AudioFfmpegEncoderPlugin(std::string name)125 AudioFfmpegEncoderPlugin::AudioFfmpegEncoderPlugin(std::string name) : CodecPlugin(std::move(name)), prev_pts_(0)
126 {
127 }
128 
~AudioFfmpegEncoderPlugin()129 AudioFfmpegEncoderPlugin::~AudioFfmpegEncoderPlugin()
130 {
131     OSAL::ScopedLock lock(avMutex_);
132     OSAL::ScopedLock lock1(parameterMutex_);
133     DeInitLocked();
134 }
135 
Init()136 Status AudioFfmpegEncoderPlugin::Init()
137 {
138     auto ite = codecMap.find(pluginName_);
139     if (ite == codecMap.end()) {
140         MEDIA_LOG_W("cannot find codec with name " PUBLIC_LOG_S, pluginName_.c_str());
141         return Status::ERROR_UNSUPPORTED_FORMAT;
142     }
143     OSAL::ScopedLock lock(avMutex_);
144     avCodec_ = ite->second;
145     cachedFrame_ = std::shared_ptr<AVFrame>(av_frame_alloc(), [](AVFrame* frame) { av_frame_free(&frame);});
146     return Status::OK;
147 }
148 
Deinit()149 Status AudioFfmpegEncoderPlugin::Deinit()
150 {
151     OSAL::ScopedLock lock(avMutex_);
152     OSAL::ScopedLock lock1(parameterMutex_);
153     return DeInitLocked();
154 }
155 
DeInitLocked()156 Status AudioFfmpegEncoderPlugin::DeInitLocked()
157 {
158     ResetLocked();
159     avCodec_.reset();
160     cachedFrame_.reset();
161     return Status::OK;
162 }
163 
SetParameter(Tag tag,const ValueType & value)164 Status AudioFfmpegEncoderPlugin::SetParameter(Tag tag, const ValueType& value)
165 {
166     OSAL::ScopedLock lock(parameterMutex_);
167     audioParameter_.insert(std::make_pair(tag, value));
168     return Status::OK;
169 }
170 
GetParameter(Tag tag,ValueType & value)171 Status AudioFfmpegEncoderPlugin::GetParameter(Tag tag, ValueType& value)
172 {
173     if (tag == Tag::REQUIRED_OUT_BUFFER_CNT) {
174         value = static_cast<uint32_t>(BUFFER_QUEUE_SIZE);
175         return Status::OK;
176     }
177     OSAL::ScopedLock lock(avMutex_);
178     if (avCodecContext_ == nullptr) {
179         return Status::ERROR_WRONG_STATE;
180     }
181     return GetAudioEncoderParameters(*avCodecContext_, tag, value);
182 }
183 
Prepare()184 Status AudioFfmpegEncoderPlugin::Prepare()
185 {
186     {
187         OSAL::ScopedLock lock(avMutex_);
188         if (avCodec_ == nullptr) {
189             return Status::ERROR_WRONG_STATE;
190         }
191         auto context = avcodec_alloc_context3(avCodec_.get());
192         FALSE_RETURN_V_MSG_E(context != nullptr, Status::ERROR_UNKNOWN, "cannot allocate codec context");
193         avCodecContext_ = std::shared_ptr<AVCodecContext>(context, [](AVCodecContext* ptr) {
194             if (ptr != nullptr) {
195                 if (ptr->extradata) {
196                     av_free(ptr->extradata);
197                     ptr->extradata = nullptr;
198                 }
199                 avcodec_free_context(&ptr);
200             }
201         });
202         {
203             OSAL::ScopedLock lock1(parameterMutex_);
204             ConfigAudioEncoder(*avCodecContext_, audioParameter_);
205         }
206 
207         if (!avCodecContext_->time_base.den) {
208             avCodecContext_->time_base.den = avCodecContext_->sample_rate;
209             avCodecContext_->time_base.num = 1;
210             avCodecContext_->ticks_per_frame = 1;
211         }
212 
213         avCodecContext_->workaround_bugs =
214             static_cast<uint32_t>(avCodecContext_->workaround_bugs) | static_cast<uint32_t>(FF_BUG_AUTODETECT);
215     }
216     return Status::OK;
217 }
218 
ResetLocked()219 Status AudioFfmpegEncoderPlugin::ResetLocked()
220 {
221     audioParameter_.clear();
222     avCodecContext_.reset();
223     return Status::OK;
224 }
225 
Reset()226 Status AudioFfmpegEncoderPlugin::Reset()
227 {
228     OSAL::ScopedLock lock(avMutex_);
229     OSAL::ScopedLock lock1(parameterMutex_);
230     return ResetLocked();
231 }
232 
CheckReformat()233 bool AudioFfmpegEncoderPlugin::CheckReformat()
234 {
235     if (avCodec_ == nullptr || avCodecContext_ == nullptr) {
236         return false;
237     }
238     for (size_t index = 0; avCodec_->sample_fmts[index] != AV_SAMPLE_FMT_NONE; ++index) {
239         if (avCodec_->sample_fmts[index] == avCodecContext_->sample_fmt) {
240             return false;
241         }
242     }
243     return true;
244 }
245 
Start()246 Status AudioFfmpegEncoderPlugin::Start()
247 {
248     OSAL::ScopedLock lock(avMutex_);
249     if (avCodecContext_ == nullptr) {
250         return Status::ERROR_WRONG_STATE;
251     }
252     needReformat_ = CheckReformat();
253     if (needReformat_) {
254         srcFmt_ = avCodecContext_->sample_fmt;
255         // always use the first fmt
256         avCodecContext_->sample_fmt = avCodec_->sample_fmts[0];
257     }
258     auto res = avcodec_open2(avCodecContext_.get(), avCodec_.get(), nullptr);
259     FALSE_RETURN_V_MSG_E(res == 0, Status::ERROR_UNKNOWN, "avcodec open error " PUBLIC_LOG_S " when start encoder",
260                       AVStrError(res).c_str());
261     FALSE_RETURN_V_MSG_E(avCodecContext_->frame_size > 0, Status::ERROR_UNKNOWN, "frame_size unknown");
262     fullInputFrameSize_ = (uint32_t)av_samples_get_buffer_size(nullptr, avCodecContext_->channels,
263         avCodecContext_->frame_size, srcFmt_, 1);
264     srcBytesPerSample_ = av_get_bytes_per_sample(srcFmt_) * avCodecContext_->channels;
265     if (needReformat_) {
266         Ffmpeg::ResamplePara resamplePara = {
267             static_cast<uint32_t>(avCodecContext_->channels),
268             static_cast<uint32_t>(avCodecContext_->sample_rate),
269             0,
270             static_cast<int64_t>(avCodecContext_->channel_layout),
271             srcFmt_,
272             static_cast<uint32_t>(avCodecContext_->frame_size),
273             avCodecContext_->sample_fmt,
274         };
275         resample_ = std::make_shared<Ffmpeg::Resample>();
276         FALSE_RETURN_V_MSG(resample_->Init(resamplePara) == Status::OK, Status::ERROR_UNKNOWN, "Resample init error");
277     }
278     SetParameter(Tag::AUDIO_SAMPLE_PER_FRAME, static_cast<uint32_t>(avCodecContext_->frame_size));
279     return Status::OK;
280 }
281 
Stop()282 Status AudioFfmpegEncoderPlugin::Stop()
283 {
284     Status ret = Status::OK;
285     {
286         OSAL::ScopedLock lock(avMutex_);
287         if (avCodecContext_ != nullptr) {
288             auto res = avcodec_close(avCodecContext_.get());
289             FALSE_RETURN_V_MSG_E(res == 0, Status::ERROR_UNKNOWN,
290                 "avcodec close error " PUBLIC_LOG_S " when stop encoder", AVStrError(res).c_str());
291             avCodecContext_.reset();
292         }
293         if (outBuffer_) {
294             outBuffer_.reset();
295         }
296     }
297     return ret;
298 }
299 
Flush()300 Status AudioFfmpegEncoderPlugin::Flush()
301 {
302     MEDIA_LOG_I("Flush entered.");
303     OSAL::ScopedLock lock(avMutex_);
304     if (avCodecContext_ != nullptr) {
305         avcodec_flush_buffers(avCodecContext_.get());
306     }
307     MEDIA_LOG_I("Flush exit.");
308     return Status::OK;
309 }
310 
QueueInputBuffer(const std::shared_ptr<Buffer> & inputBuffer,int32_t timeoutMs)311 Status AudioFfmpegEncoderPlugin::QueueInputBuffer(const std::shared_ptr<Buffer>& inputBuffer, int32_t timeoutMs)
312 {
313     MEDIA_LOG_DD("queue input buffer");
314     (void)timeoutMs;
315     if (inputBuffer->IsEmpty() && !(inputBuffer->flag & BUFFER_FLAG_EOS)) {
316         MEDIA_LOG_E("encoder does not support fd buffer");
317         return Status::ERROR_INVALID_DATA;
318     }
319     Status ret = Status::OK;
320     {
321         OSAL::ScopedLock lock(avMutex_);
322         if (avCodecContext_ == nullptr) {
323             return Status::ERROR_WRONG_STATE;
324         }
325         ret = SendBufferLocked(inputBuffer);
326     }
327     return ret;
328 }
329 
QueueOutputBuffer(const std::shared_ptr<Buffer> & outputBuffer,int32_t timeoutMs)330 Status AudioFfmpegEncoderPlugin::QueueOutputBuffer(const std::shared_ptr<Buffer>& outputBuffer, int32_t timeoutMs)
331 {
332     MEDIA_LOG_DD("queue output buffer");
333     (void)timeoutMs;
334     if (!outputBuffer) {
335         return Status::ERROR_INVALID_PARAMETER;
336     }
337     outBuffer_ = outputBuffer;
338     return SendOutputBuffer();
339 }
340 
SendOutputBuffer()341 Status AudioFfmpegEncoderPlugin::SendOutputBuffer()
342 {
343     MEDIA_LOG_DD("send output buffer");
344     Status status = ReceiveBuffer();
345     if (status == Status::OK || status == Status::END_OF_STREAM) {
346         dataCallback_->OnOutputBufferDone(outBuffer_);
347     }
348     outBuffer_.reset();
349     return status;
350 }
351 
FillInFrameCache(const std::shared_ptr<Memory> & mem)352 void AudioFfmpegEncoderPlugin::FillInFrameCache(const std::shared_ptr<Memory>& mem)
353 {
354     uint8_t* sampleData = nullptr;
355     int32_t nbSamples = 0;
356     auto srcBuffer = mem->GetReadOnlyData();
357     auto destBuffer = const_cast<uint8_t*>(srcBuffer);
358     auto srcLength = mem->GetSize();
359     auto destLength = srcLength;
360     if (needReformat_ && resample_) {
361         FALSE_LOG(resample_->Convert(srcBuffer, srcLength, destBuffer, destLength) == Status::OK);
362         if (destLength) {
363             sampleData = destBuffer;
364             nbSamples = destLength / av_get_bytes_per_sample(avCodecContext_->sample_fmt) / avCodecContext_->channels;
365         }
366     } else {
367         sampleData = destBuffer;
368         nbSamples = destLength / srcBytesPerSample_;
369     }
370     cachedFrame_->format = avCodecContext_->sample_fmt;
371     cachedFrame_->sample_rate = avCodecContext_->sample_rate;
372     cachedFrame_->channels = avCodecContext_->channels;
373     cachedFrame_->channel_layout = avCodecContext_->channel_layout;
374     cachedFrame_->nb_samples = nbSamples;
375     if (av_sample_fmt_is_planar(avCodecContext_->sample_fmt) && avCodecContext_->channels > 1) {
376         if (avCodecContext_->channels > AV_NUM_DATA_POINTERS) {
377             av_freep(cachedFrame_->extended_data);
378             cachedFrame_->extended_data = static_cast<uint8_t**>(av_malloc_array(avCodecContext_->channels,
379                 sizeof(uint8_t *)));
380         } else {
381             cachedFrame_->extended_data = cachedFrame_->data;
382         }
383         cachedFrame_->extended_data[0] = sampleData;
384         cachedFrame_->linesize[0] = nbSamples * av_get_bytes_per_sample(avCodecContext_->sample_fmt);
385         for (int i = 1; i < avCodecContext_->channels; i++) {
386             cachedFrame_->extended_data[i] = cachedFrame_->extended_data[i-1] + cachedFrame_->linesize[0];
387         }
388     } else {
389         cachedFrame_->data[0] = sampleData;
390         cachedFrame_->extended_data = cachedFrame_->data;
391         cachedFrame_->linesize[0] = nbSamples * av_get_bytes_per_sample(avCodecContext_->sample_fmt) *
392             avCodecContext_->channels;
393     }
394 }
395 
SendBufferLocked(const std::shared_ptr<Buffer> & inputBuffer)396 Status AudioFfmpegEncoderPlugin::SendBufferLocked(const std::shared_ptr<Buffer>& inputBuffer)
397 {
398     bool eos = false;
399     if (inputBuffer == nullptr || (inputBuffer->flag & BUFFER_FLAG_EOS) != 0) {
400         // eos buffer
401         eos = true;
402     } else {
403         auto inputMemory = inputBuffer->GetMemory();
404         FALSE_RETURN_V_MSG_W(inputMemory->GetSize() == fullInputFrameSize_, Status::ERROR_NOT_ENOUGH_DATA,
405             "Not enough data, input: " PUBLIC_LOG_ZU ", fullInputFrameSize: " PUBLIC_LOG_U32,
406             inputMemory->GetSize(), fullInputFrameSize_);
407         FillInFrameCache(inputMemory);
408     }
409     AVFrame* inputFrame = nullptr;
410     if (!eos) {
411         inputFrame = cachedFrame_.get();
412     }
413     auto ret = avcodec_send_frame(avCodecContext_.get(), inputFrame);
414     if (!eos && inputFrame) {
415         av_frame_unref(inputFrame);
416     }
417     if (ret == 0) {
418         return Status::OK;
419     } else if (ret == AVERROR_EOF) {
420         return Status::END_OF_STREAM;
421     } else if (ret == AVERROR(EAGAIN)) {
422         return Status::ERROR_AGAIN;
423     } else {
424         MEDIA_LOG_E("send buffer error " PUBLIC_LOG_S, AVStrError(ret).c_str());
425         return Status::ERROR_UNKNOWN;
426     }
427 }
428 
ReceiveFrameSucc(const std::shared_ptr<Buffer> & ioInfo,const std::shared_ptr<AVPacket> & packet)429 Status AudioFfmpegEncoderPlugin::ReceiveFrameSucc(const std::shared_ptr<Buffer>& ioInfo,
430                                                   const std::shared_ptr<AVPacket>& packet)
431 {
432     auto ioInfoMem = ioInfo->GetMemory();
433     FALSE_RETURN_V_MSG_W(ioInfoMem->GetCapacity() >= static_cast<size_t>(packet->size),
434                          Status::ERROR_NO_MEMORY, "buffer size is not enough");
435     ioInfoMem->Write(packet->data, packet->size);
436     // how get perfect pts with upstream pts ?
437     ioInfo->duration = ConvertTimeFromFFmpeg(packet->duration, avCodecContext_->time_base);
438     ioInfo->pts = (UINT64_MAX - prev_pts_ < packet->duration) ?
439                   (ioInfo->duration - (UINT64_MAX - prev_pts_)) :
440                   (prev_pts_ + ioInfo->duration);
441     prev_pts_ = ioInfo->pts;
442     return Status::OK;
443 }
444 
ReceiveBufferLocked(const std::shared_ptr<Buffer> & ioInfo)445 Status AudioFfmpegEncoderPlugin::ReceiveBufferLocked(const std::shared_ptr<Buffer>& ioInfo)
446 {
447     Status status;
448     std::shared_ptr<AVPacket> packet = std::make_shared<AVPacket>();
449     auto ret = avcodec_receive_packet(avCodecContext_.get(), packet.get());
450     if (ret >= 0) {
451         MEDIA_LOG_DD("receive one frame");
452         status = ReceiveFrameSucc(ioInfo, packet);
453     } else if (ret == AVERROR_EOF) {
454         MEDIA_LOG_I("eos received");
455         ioInfo->GetMemory()->Reset();
456         ioInfo->flag = BUFFER_FLAG_EOS;
457         status = Status::END_OF_STREAM;
458     } else if (ret == AVERROR(EAGAIN)) {
459         status = Status::ERROR_NOT_ENOUGH_DATA;
460     } else {
461         MEDIA_LOG_E("audio encoder receive error: " PUBLIC_LOG_S, AVStrError(ret).c_str());
462         status = Status::ERROR_UNKNOWN;
463     }
464     av_frame_unref(cachedFrame_.get());
465     return status;
466 }
467 
ReceiveBuffer()468 Status AudioFfmpegEncoderPlugin::ReceiveBuffer()
469 {
470     std::shared_ptr<Buffer> ioInfo = outBuffer_;
471     if ((ioInfo == nullptr) || ioInfo->IsEmpty() ||
472         (ioInfo->GetBufferMeta()->GetType() != BufferMetaType::AUDIO)) {
473         MEDIA_LOG_W("cannot fetch valid buffer to output");
474         return Status::ERROR_NO_MEMORY;
475     }
476     Status status = Status::OK;
477     {
478         OSAL::ScopedLock l(avMutex_);
479         if (avCodecContext_ == nullptr) {
480             return Status::ERROR_WRONG_STATE;
481         }
482         status = ReceiveBufferLocked(ioInfo);
483     }
484     return status;
485 }
486 
GetAllocator()487 std::shared_ptr<Allocator> AudioFfmpegEncoderPlugin::GetAllocator()
488 {
489     return nullptr;
490 }
491 } // namespace Ffmpeg
492 } // namespace Plugin
493 } // namespace Media
494 } // namespace OHOS