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 #if defined(RECORDER_SUPPORT) && defined(VIDEO_SUPPORT)
17 
18 #define HST_LOG_TAG "FfmpegVideoEncoderPlugin"
19 
20 #include "video_ffmpeg_encoder_plugin.h"
21 #include <cstring>
22 #include <map>
23 #include <set>
24 #include "ffmpeg_vid_enc_config.h"
25 #include "plugin/common/plugin_attr_desc.h"
26 #include "plugin/common/plugin_caps_builder.h"
27 #include "plugin/common/plugin_time.h"
28 #include "plugins/ffmpeg_adapter/utils/ffmpeg_utils.h"
29 
30 namespace {
31 // register plugins
32 using namespace OHOS::Media::Plugin;
33 using namespace Ffmpeg;
34 void UpdatePluginDefinition(const AVCodec* codec, CodecPluginDef& definition);
35 
36 std::map<std::string, std::shared_ptr<const AVCodec>> codecMap;
37 
38 const size_t BUFFER_QUEUE_SIZE = 6;
39 const size_t DEFAULT_ALIGN = 16;
40 
41 std::set<AVCodecID> supportedCodec = {AV_CODEC_ID_H264};
42 
RegisterVideoEncoderPlugins(const std::shared_ptr<Register> & reg)43 Status RegisterVideoEncoderPlugins(const std::shared_ptr<Register>& reg)
44 {
45     const AVCodec* codec = nullptr;
46     void* iter = nullptr;
47     MEDIA_LOG_I("registering video encoders");
48     while ((codec = av_codec_iterate(&iter))) {
49         if (!av_codec_is_encoder(codec) || codec->type != AVMEDIA_TYPE_VIDEO) {
50             continue;
51         }
52         std::string iterCodec(codec->name);
53         if (iterCodec.find("264") != std::string::npos && iterCodec != "libx264") {
54             continue;
55         }
56         if (supportedCodec.find(codec->id) == supportedCodec.end()) {
57             MEDIA_LOG_DD("codec %s(%s) is not supported right now", codec->name, codec->long_name);
58             continue;
59         }
60         CodecPluginDef definition;
61         definition.name = "video_encoder_" + std::string(codec->name);
62         definition.pluginType = PluginType::VIDEO_ENCODER;
63         definition.rank = 100; // 100
64         definition.creator = [](const std::string& name) -> std::shared_ptr<CodecPlugin> {
65             return std::make_shared<VideoFfmpegEncoderPlugin>(name);
66         };
67         UpdatePluginDefinition(codec, definition);
68         // do not delete the codec in the deleter
69         codecMap[definition.name] = std::shared_ptr<AVCodec>(const_cast<AVCodec*>(codec), [](void* ptr) {});
70         if (reg->AddPlugin(definition) != Status::OK) {
71             MEDIA_LOG_W("register plugin %s(%s) failed", codec->name, codec->long_name);
72         }
73     }
74     return Status::OK;
75 }
76 
UnRegisterVideoEncoderPlugins()77 void UnRegisterVideoEncoderPlugins()
78 {
79     codecMap.clear();
80 }
81 
UpdateInCaps(const AVCodec * codec,CodecPluginDef & definition)82 void UpdateInCaps(const AVCodec* codec, CodecPluginDef& definition)
83 {
84     CapabilityBuilder capBuilder;
85     capBuilder.SetMime(OHOS::Media::MEDIA_MIME_VIDEO_RAW);
86     if (codec->pix_fmts != nullptr) {
87         DiscreteCapability<VideoPixelFormat> values;
88         for (uint32_t index = 0; codec->pix_fmts[index] != -1; ++index) {
89             values.push_back(ConvertPixelFormatFromFFmpeg(codec->pix_fmts[index]));
90         }
91         if (!values.empty()) {
92             capBuilder.SetVideoPixelFormatList(values);
93         }
94     } else {
95         capBuilder.SetVideoPixelFormatList({VideoPixelFormat::YUV420P});
96     }
97     definition.inCaps.push_back(capBuilder.Build());
98 }
99 
UpdateOutCaps(const AVCodec * codec,CodecPluginDef & definition)100 void UpdateOutCaps(const AVCodec* codec, CodecPluginDef& definition)
101 {
102     CapabilityBuilder capBuilder;
103     capBuilder.SetMime("video/unknown");
104     switch (codec->id) {
105         case AV_CODEC_ID_H264:
106             capBuilder.SetMime(OHOS::Media::MEDIA_MIME_VIDEO_H264);
107             break;
108         default:
109             MEDIA_LOG_I("codec is not supported right now");
110             break;
111     }
112     definition.outCaps.push_back(capBuilder.Build());
113 }
114 
UpdatePluginDefinition(const AVCodec * codec,CodecPluginDef & definition)115 void UpdatePluginDefinition(const AVCodec* codec, CodecPluginDef& definition)
116 {
117     UpdateInCaps(codec, definition);
118     UpdateOutCaps(codec, definition);
119 }
120 } // namespace
121 
122 PLUGIN_DEFINITION(FFmpegVideoEncoders, LicenseType::LGPL, RegisterVideoEncoderPlugins, UnRegisterVideoEncoderPlugins);
123 
124 namespace OHOS {
125 namespace Media {
126 namespace Plugin {
127 namespace Ffmpeg {
VideoFfmpegEncoderPlugin(std::string name)128 VideoFfmpegEncoderPlugin::VideoFfmpegEncoderPlugin(std::string name)
129     : CodecPlugin(std::move(name)), outBufferQ_("vencPluginQueue", BUFFER_QUEUE_SIZE)
130 {
131 }
132 
Init()133 Status VideoFfmpegEncoderPlugin::Init()
134 {
135     OSAL::ScopedLock lock(avMutex_);
136     auto iter = codecMap.find(pluginName_);
137     FALSE_RETURN_V_MSG_E(iter != codecMap.end(), Status::ERROR_UNSUPPORTED_FORMAT,
138                       "cannot find codec with name " PUBLIC_LOG_S, pluginName_.c_str());
139     avCodec_ = iter->second;
140     cachedFrame_ = std::shared_ptr<AVFrame>(av_frame_alloc(), [](AVFrame* fp) { av_frame_free(&fp); });
141     cachedPacket_ = std::make_shared<AVPacket>();
142     vencParams_[Tag::REQUIRED_OUT_BUFFER_CNT] = (uint32_t)BUFFER_QUEUE_SIZE;
143     if (!encodeTask_) {
144         encodeTask_ = std::make_shared<OHOS::Media::OSAL::Task>("videoFfmpegEncThread");
145         encodeTask_->RegisterHandler([this] { ReceiveBuffer(); });
146     }
147     state_ = State::INITIALIZED;
148     MEDIA_LOG_I("Init success");
149     return Status::OK;
150 }
151 
Deinit()152 Status VideoFfmpegEncoderPlugin::Deinit()
153 {
154     OSAL::ScopedLock l(avMutex_);
155     avCodec_.reset();
156     cachedFrame_.reset();
157     cachedPacket_.reset();
158     ResetLocked();
159     if (encodeTask_) {
160         encodeTask_->Stop();
161         encodeTask_.reset();
162     }
163     state_ = State::DESTROYED;
164     return Status::OK;
165 }
166 
SetParameter(Tag tag,const ValueType & value)167 Status VideoFfmpegEncoderPlugin::SetParameter(Tag tag, const ValueType& value)
168 {
169     OSAL::ScopedLock l(parameterMutex_);
170     vencParams_.insert(std::make_pair(tag, value));
171     return Status::OK;
172 }
173 
GetParameter(Tag tag,ValueType & value)174 Status VideoFfmpegEncoderPlugin::GetParameter(Tag tag, ValueType& value)
175 {
176     {
177         OSAL::ScopedLock l(parameterMutex_);
178         auto res = vencParams_.find(tag);
179         if (res != vencParams_.end()) {
180             value = res->second;
181             return Status::OK;
182         }
183     }
184     OSAL::ScopedLock lock(avMutex_);
185     FALSE_RETURN_V_MSG_E(avCodecContext_ != nullptr, Status::ERROR_WRONG_STATE, "codec context is null");
186     return GetVideoEncoderParameters(*avCodecContext_, tag, value);
187 }
188 
189 template <typename T>
FindInParameterMapThenAssignLocked(Tag tag,T & assign)190 void VideoFfmpegEncoderPlugin::FindInParameterMapThenAssignLocked(Tag tag, T& assign)
191 {
192     auto iter = vencParams_.find(tag);
193     if (iter != vencParams_.end() && Plugin::Any::IsSameTypeWith<T>(iter->second)) {
194         assign = Plugin::AnyCast<T>(iter->second);
195     } else {
196         MEDIA_LOG_W("parameter %d is not found or type mismatch", static_cast<int32_t>(tag));
197     }
198 }
199 
CreateCodecContext()200 Status VideoFfmpegEncoderPlugin::CreateCodecContext()
201 {
202     auto context = avcodec_alloc_context3(avCodec_.get());
203     FALSE_RETURN_V_MSG_E(context != nullptr, Status::ERROR_UNKNOWN, "cannot allocate codec context");
204 
205     avCodecContext_ = std::shared_ptr<AVCodecContext>(context, [](AVCodecContext* ptr) {
206         if (ptr != nullptr) {
207             if (ptr->extradata) {
208                 av_free(ptr->extradata);
209                 ptr->extradata = nullptr;
210             }
211             avcodec_free_context(&ptr);
212         }
213     });
214     MEDIA_LOG_I("Create ffmpeg codec context success");
215     return Status::OK;
216 }
217 
InitCodecContext()218 void VideoFfmpegEncoderPlugin::InitCodecContext()
219 {
220     avCodecContext_->codec_type = AVMEDIA_TYPE_VIDEO;
221     FindInParameterMapThenAssignLocked<std::uint32_t>(Tag::VIDEO_WIDTH, width_);
222     FindInParameterMapThenAssignLocked<std::uint32_t>(Tag::VIDEO_HEIGHT, height_);
223     FindInParameterMapThenAssignLocked<uint32_t>(Tag::VIDEO_FRAME_RATE, frameRate_);
224     FindInParameterMapThenAssignLocked<Plugin::VideoPixelFormat>(Tag::VIDEO_PIXEL_FORMAT, pixelFormat_);
225     MEDIA_LOG_D("width: " PUBLIC_LOG_U32 ", height: " PUBLIC_LOG_U32 ", pixelFormat: " PUBLIC_LOG_S ", frameRate_: "
226                 PUBLIC_LOG_U32, width_, height_, GetVideoPixelFormatNameStr(pixelFormat_), frameRate_);
227     ConfigVideoEncoder(*avCodecContext_, vencParams_);
228 }
229 
DeinitCodecContext()230 void VideoFfmpegEncoderPlugin::DeinitCodecContext()
231 {
232     if (avCodecContext_ == nullptr) {
233         return;
234     }
235     if (avCodecContext_->extradata) {
236         av_free(avCodecContext_->extradata);
237         avCodecContext_->extradata = nullptr;
238     }
239     avCodecContext_->extradata_size = 0;
240     avCodecContext_->opaque = nullptr;
241     avCodecContext_->width = 0;
242     avCodecContext_->height = 0;
243     avCodecContext_->time_base.den = 0;
244     avCodecContext_->time_base.num = 0;
245     avCodecContext_->ticks_per_frame = 0;
246     avCodecContext_->sample_aspect_ratio.num = 0;
247     avCodecContext_->sample_aspect_ratio.den = 0;
248     avCodecContext_->get_buffer2 = nullptr;
249 }
250 
OpenCodecContext()251 Status VideoFfmpegEncoderPlugin::OpenCodecContext()
252 {
253     const AVCodec* venc = avcodec_find_encoder(avCodecContext_->codec_id);
254     if (venc == nullptr) {
255         MEDIA_LOG_E("Codec: " PUBLIC_LOG_D32 " is not found", static_cast<int32_t>(avCodecContext_->codec_id));
256         DeinitCodecContext();
257         return Status::ERROR_INVALID_PARAMETER;
258     }
259     auto res = avcodec_open2(avCodecContext_.get(), avCodec_.get(), nullptr);
260     if (res != 0) {
261         MEDIA_LOG_E("avcodec open error " PUBLIC_LOG_S " when start encoder ", AVStrError(res).c_str());
262         DeinitCodecContext();
263         return Status::ERROR_UNKNOWN;
264     }
265     MEDIA_LOG_I("Open ffmpeg codec context success");
266     return Status::OK;
267 }
268 
CloseCodecContext()269 Status VideoFfmpegEncoderPlugin::CloseCodecContext()
270 {
271     Status ret = Status::OK;
272     if (avCodecContext_ != nullptr) {
273         auto res = avcodec_close(avCodecContext_.get());
274         if (res != 0) {
275             DeinitCodecContext();
276             MEDIA_LOG_E("avcodec close error " PUBLIC_LOG_S " when stop encoder", AVStrError(res).c_str());
277             ret = Status::ERROR_UNKNOWN;
278         }
279         avCodecContext_.reset();
280     }
281     return ret;
282 }
283 
Prepare()284 Status VideoFfmpegEncoderPlugin::Prepare()
285 {
286     {
287         OSAL::ScopedLock l(avMutex_);
288         FALSE_RETURN_V(state_ == State::INITIALIZED || state_ == State::PREPARED, Status::ERROR_WRONG_STATE);
289         FALSE_RETURN_V_MSG_E(CreateCodecContext() == Status::OK, Status::ERROR_UNKNOWN, "Create codec context fail");
290         {
291             OSAL::ScopedLock lock(parameterMutex_);
292             InitCodecContext();
293         }
294 #ifdef DUMP_RAW_DATA
295         dumpFd_ = fopen("./enc_out.es", "wb");
296 #endif
297         state_ = State::PREPARED;
298     }
299     outBufferQ_.SetActive(true);
300     MEDIA_LOG_I("Prepare success");
301     return Status::OK;
302 }
303 
ResetLocked()304 Status VideoFfmpegEncoderPlugin::ResetLocked()
305 {
306     {
307         OSAL::ScopedLock lock(parameterMutex_);
308         vencParams_.clear();
309     }
310     avCodecContext_.reset();
311     outBufferQ_.Clear();
312 #ifdef DUMP_RAW_DATA
313     if (dumpFd_) {
314         std::fclose(dumpFd_);
315         dumpFd_ = nullptr;
316     }
317 #endif
318     state_ = State::INITIALIZED;
319     return Status::OK;
320 }
321 
Reset()322 Status VideoFfmpegEncoderPlugin::Reset()
323 {
324     OSAL::ScopedLock l(avMutex_);
325     return ResetLocked();
326 }
327 
Start()328 Status VideoFfmpegEncoderPlugin::Start()
329 {
330     {
331         OSAL::ScopedLock lock(avMutex_);
332         FALSE_RETURN_V(state_ == State::PREPARED, Status::ERROR_WRONG_STATE);
333         FALSE_RETURN_V_MSG_E(OpenCodecContext() == Status::OK, Status::ERROR_UNKNOWN, "Open codec context fail");
334         state_ = State::RUNNING;
335     }
336     outBufferQ_.SetActive(true);
337     encodeTask_->Start();
338     MEDIA_LOG_I("Start success");
339     return Status::OK;
340 }
341 
Stop()342 Status VideoFfmpegEncoderPlugin::Stop()
343 {
344     Status ret = Status::OK;
345     {
346         OSAL::ScopedLock lock(avMutex_);
347         ret = CloseCodecContext();
348 #ifdef DUMP_RAW_DATA
349         if (dumpFd_) {
350             std::fclose(dumpFd_);
351             dumpFd_ = nullptr;
352         }
353 #endif
354         state_ = State::INITIALIZED;
355     }
356     outBufferQ_.SetActive(false);
357     encodeTask_->Stop();
358     MEDIA_LOG_I("Stop success");
359     return ret;
360 }
361 
QueueOutputBuffer(const std::shared_ptr<Buffer> & outputBuffer,int32_t timeoutMs)362 Status VideoFfmpegEncoderPlugin::QueueOutputBuffer(const std::shared_ptr<Buffer>& outputBuffer, int32_t timeoutMs)
363 {
364     MEDIA_LOG_DD("queue output buffer");
365     if (outputBuffer) {
366         outBufferQ_.Push(outputBuffer);
367         return Status::OK;
368     }
369     return Status::ERROR_INVALID_PARAMETER;
370 }
371 
Flush()372 Status VideoFfmpegEncoderPlugin::Flush()
373 {
374     OSAL::ScopedLock l(avMutex_);
375     if (avCodecContext_ != nullptr) {
376         // flush avcodec buffers
377     }
378     return Status::OK;
379 }
380 
QueueInputBuffer(const std::shared_ptr<Buffer> & inputBuffer,int32_t timeoutMs)381 Status VideoFfmpegEncoderPlugin::QueueInputBuffer(const std::shared_ptr<Buffer>& inputBuffer, int32_t timeoutMs)
382 {
383     MEDIA_LOG_DD("queue input buffer");
384     FALSE_RETURN_V_MSG_E(!inputBuffer->IsEmpty() || (inputBuffer->flag & BUFFER_FLAG_EOS),
385         Status::ERROR_INVALID_DATA, "encoder does not support fd buffer");
386     Status ret = Status::OK;
387     {
388         OSAL::ScopedLock lock(avMutex_);
389         ret = SendBufferLocked(inputBuffer);
390     }
391     NotifyInputBufferDone(inputBuffer);
392     return ret;
393 }
394 
FillAvFrame(const std::shared_ptr<Buffer> & inputBuffer)395 Status VideoFfmpegEncoderPlugin::FillAvFrame(const std::shared_ptr<Buffer>& inputBuffer)
396 {
397     if (inputBuffer->GetMemory() == nullptr) {
398         return Status::ERROR_NULL_POINTER;
399     }
400     const uint8_t *data = inputBuffer->GetMemory()->GetReadOnlyData();
401     auto bufferMeta = inputBuffer->GetBufferMeta();
402     FALSE_RETURN_V_MSG_W(bufferMeta != nullptr && bufferMeta->GetType() == BufferMetaType::VIDEO,
403         Status::ERROR_INVALID_PARAMETER, "invalid buffer meta");
404     std::shared_ptr<VideoBufferMeta> videoMeta = std::reinterpret_pointer_cast<VideoBufferMeta>(bufferMeta);
405     FALSE_RETURN_V_MSG_W(pixelFormat_ == videoMeta->videoPixelFormat, Status::ERROR_INVALID_PARAMETER,
406         "pixel format change");
407     cachedFrame_->format = ConvertPixelFormatToFFmpeg(videoMeta->videoPixelFormat);
408     cachedFrame_->width = static_cast<int>(videoMeta->width);
409     cachedFrame_->height = static_cast<int>(videoMeta->height);
410     if (!videoMeta->stride.empty()) {
411         for (uint32_t i = 0; i < videoMeta->planes; i++) {
412             cachedFrame_->linesize[i] = static_cast<int32_t>(videoMeta->stride[i]);
413         }
414     }
415     int32_t ySize = cachedFrame_->linesize[0] * AlignUp(cachedFrame_->height, DEFAULT_ALIGN);
416     // AV_PIX_FMT_YUV420P: linesize[0] = linesize[1] * 2, AV_PIX_FMT_NV12: linesize[0] = linesize[1]
417     int32_t uvSize = cachedFrame_->linesize[1] * AlignUp(cachedFrame_->height, DEFAULT_ALIGN) / 2; // 2
418     if (cachedFrame_->format == AV_PIX_FMT_YUV420P) {
419         cachedFrame_->data[0] = const_cast<uint8_t *>(data);
420         cachedFrame_->data[1] = cachedFrame_->data[0] + ySize;
421         cachedFrame_->data[2] = cachedFrame_->data[1] + uvSize; // 2: plane 2
422     } else if ((cachedFrame_->format == AV_PIX_FMT_NV12) || (cachedFrame_->format == AV_PIX_FMT_NV21)) {
423         cachedFrame_->data[0] = const_cast<uint8_t *>(data);
424         cachedFrame_->data[1] = cachedFrame_->data[0] + ySize;
425     } else {
426         MEDIA_LOG_E("Unsupported pixel format: " PUBLIC_LOG_D32, cachedFrame_->format);
427         return Status::ERROR_UNSUPPORTED_FORMAT;
428     }
429     cachedFrame_->pts = ConvertTimeToFFmpeg(
430         static_cast<uint64_t>(HstTime2Us(inputBuffer->pts)) / avCodecContext_->ticks_per_frame,
431         avCodecContext_->time_base);
432     MEDIA_LOG_D("hst pts: " PUBLIC_LOG_U64 " ns, ffmpeg pts: " PUBLIC_LOG_D64
433                 " us, den: " PUBLIC_LOG_D32 ", num: " PUBLIC_LOG_D32,
434                 inputBuffer->pts, cachedFrame_->pts, avCodecContext_->time_base.den, avCodecContext_->time_base.num);
435     return Status::OK;
436 }
437 
SendBufferLocked(const std::shared_ptr<Buffer> & inputBuffer)438 Status VideoFfmpegEncoderPlugin::SendBufferLocked(const std::shared_ptr<Buffer>& inputBuffer)
439 {
440     FALSE_RETURN_V_MSG_E(state_ == State::RUNNING,
441         Status::ERROR_WRONG_STATE, "queue input buffer in wrong state");
442     bool isEos = false;
443     if (inputBuffer == nullptr || (inputBuffer->flag & BUFFER_FLAG_EOS) != 0) {
444         isEos = true;
445     } else {
446         auto res = FillAvFrame(inputBuffer);
447         FALSE_RETURN_V(res == Status::OK, res);
448     }
449     AVFrame *frame = nullptr;
450     if (!isEos) {
451         frame = cachedFrame_.get();
452     }
453     auto ret = avcodec_send_frame(avCodecContext_.get(), frame);
454     if (ret < 0) {
455         MEDIA_LOG_D("send buffer error " PUBLIC_LOG_S, AVStrError(ret).c_str());
456         return (ret == AVERROR_EOF) ? Status::END_OF_STREAM : Status::ERROR_NO_MEMORY;
457     }
458     if (frame) {
459         av_frame_unref(cachedFrame_.get());
460     }
461     return Status::OK;
462 }
463 
FillFrameBuffer(const std::shared_ptr<Buffer> & packetBuffer)464 Status VideoFfmpegEncoderPlugin::FillFrameBuffer(const std::shared_ptr<Buffer>& packetBuffer)
465 {
466     FALSE_RETURN_V_MSG_E(cachedPacket_->data != nullptr, Status::ERROR_UNKNOWN,
467                          "avcodec_receive_packet() packet data is empty");
468     auto frameBufferMem = packetBuffer->GetMemory();
469     if (frameBufferMem == nullptr) {
470         return Status::ERROR_NULL_POINTER;
471     }
472     FALSE_RETURN_V_MSG_E(frameBufferMem->Write(cachedPacket_->data, cachedPacket_->size, 0) ==
473                          static_cast<size_t>(cachedPacket_->size), Status::ERROR_UNKNOWN,
474                          "copy packet data to buffer fail");
475     if (static_cast<uint32_t>(cachedPacket_->flags) & AV_PKT_FLAG_KEY) {
476         MEDIA_LOG_D("It is key frame");
477         packetBuffer->flag |= BUFFER_FLAG_KEY_FRAME;
478     }
479     packetBuffer->pts =
480             static_cast<int64_t>(ConvertTimeFromFFmpeg(cachedPacket_->pts, avCodecContext_->time_base));
481     packetBuffer->dts =
482             static_cast<int64_t>(ConvertTimeFromFFmpeg(cachedPacket_->dts, avCodecContext_->time_base));
483 #ifdef DUMP_RAW_DATA
484     if (dumpFd_) {
485         std::fwrite(reinterpret_cast<const char *>(cachedPacket_->data), 1, cachedPacket_->size, dumpFd_);
486     }
487 #endif
488     MEDIA_LOG_D("receive one pkt, hst pts: " PUBLIC_LOG_U64 " ns, ffmpeg pts: " PUBLIC_LOG_D64
489                 " us, duration: " PUBLIC_LOG_D64 ", pos: " PUBLIC_LOG_D64,
490                 packetBuffer->pts, cachedPacket_->pts, cachedPacket_->duration, cachedPacket_->pos);
491     return Status::OK;
492 }
493 
ReceiveBufferLocked(const std::shared_ptr<Buffer> & packetBuffer)494 Status VideoFfmpegEncoderPlugin::ReceiveBufferLocked(const std::shared_ptr<Buffer>& packetBuffer)
495 {
496     FALSE_RETURN_V_MSG_E(state_ == State::RUNNING, Status::ERROR_WRONG_STATE,
497         "encode task in wrong state");
498     Status status;
499     auto ret = avcodec_receive_packet(avCodecContext_.get(), cachedPacket_.get());
500     if (ret >= 0) {
501         status = FillFrameBuffer(packetBuffer);
502     } else if (ret == AVERROR_EOF) {
503         MEDIA_LOG_I("eos received");
504         if (packetBuffer->GetMemory() == nullptr) {
505             return Status::ERROR_NULL_POINTER;
506         }
507         packetBuffer->GetMemory()->Reset();
508         packetBuffer->flag |= BUFFER_FLAG_EOS;
509         avcodec_flush_buffers(avCodecContext_.get());
510         status = Status::END_OF_STREAM;
511     } else {
512         MEDIA_LOG_D("video encoder receive error: " PUBLIC_LOG_S, AVStrError(ret).c_str());
513         status = Status::ERROR_TIMED_OUT;
514     }
515     av_frame_unref(cachedFrame_.get());
516     return status;
517 }
518 
ReceiveBuffer()519 void VideoFfmpegEncoderPlugin::ReceiveBuffer()
520 {
521     std::shared_ptr<Buffer> packetBuffer = outBufferQ_.Pop();
522     FALSE_RETURN_MSG(packetBuffer != nullptr && !packetBuffer->IsEmpty() &&
523         packetBuffer->GetBufferMeta()->GetType() == BufferMetaType::VIDEO,
524         "cannot fetch valid buffer to output");
525     Status status;
526     {
527         OSAL::ScopedLock lock(avMutex_);
528         status = ReceiveBufferLocked(packetBuffer);
529     }
530     if (status == Status::OK || status == Status::END_OF_STREAM) {
531         NotifyOutputBufferDone(packetBuffer);
532     } else {
533         outBufferQ_.Push(packetBuffer);
534     }
535 }
536 
NotifyInputBufferDone(const std::shared_ptr<Buffer> & input)537 void VideoFfmpegEncoderPlugin::NotifyInputBufferDone(const std::shared_ptr<Buffer>& input)
538 {
539     if (dataCb_ != nullptr) {
540         dataCb_->OnInputBufferDone(const_cast<std::shared_ptr<Buffer>&>(input));
541     }
542 }
543 
NotifyOutputBufferDone(const std::shared_ptr<Buffer> & output)544 void VideoFfmpegEncoderPlugin::NotifyOutputBufferDone(const std::shared_ptr<Buffer>& output)
545 {
546     if (dataCb_ != nullptr) {
547         dataCb_->OnOutputBufferDone(const_cast<std::shared_ptr<Buffer>&>(output));
548     }
549 }
550 
GetAllocator()551 std::shared_ptr<Allocator> VideoFfmpegEncoderPlugin::GetAllocator()
552 {
553     return nullptr;
554 }
555 } // namespace Ffmpeg
556 } // namespace Plugin
557 } // namespace Media
558 } // namespace OHOS
559 #endif
560