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