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 "plugin/common/plugin_caps_builder.h"
25 #include "plugin/common/plugin_time.h"
26 #include "plugins/ffmpeg_adapter/utils/ffmpeg_utils.h"
27 #include "ffmpeg_vid_enc_config.h"
28 #include "pipeline/core/plugin_attr_desc.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.codecType = CodecType::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() && typeid(T) == iter->second.Type()) {
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_, Pipeline::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 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 const uint8_t *data = inputBuffer->GetMemory()->GetReadOnlyData();
398 auto bufferMeta = inputBuffer->GetBufferMeta();
399 FALSE_RETURN_V_MSG_W(bufferMeta != nullptr && bufferMeta->GetType() == BufferMetaType::VIDEO,
400 Status::ERROR_INVALID_PARAMETER, "invalid buffer meta");
401 std::shared_ptr<VideoBufferMeta> videoMeta = std::dynamic_pointer_cast<VideoBufferMeta>(bufferMeta);
402 FALSE_RETURN_V_MSG_W(pixelFormat_ == videoMeta->videoPixelFormat, Status::ERROR_INVALID_PARAMETER,
403 "pixel format change");
404 cachedFrame_->format = ConvertPixelFormatToFFmpeg(videoMeta->videoPixelFormat);
405 cachedFrame_->width = videoMeta->width;
406 cachedFrame_->height = videoMeta->height;
407 if (!videoMeta->stride.empty()) {
408 for (uint32_t i = 0; i < videoMeta->planes; i++) {
409 cachedFrame_->linesize[i] = static_cast<int32_t>(videoMeta->stride[i]);
410 }
411 }
412 int32_t ySize = cachedFrame_->linesize[0] * AlignUp(cachedFrame_->height, DEFAULT_ALIGN);
413 // AV_PIX_FMT_YUV420P: linesize[0] = linesize[1] * 2, AV_PIX_FMT_NV12: linesize[0] = linesize[1]
414 int32_t uvSize = cachedFrame_->linesize[1] * AlignUp(cachedFrame_->height, DEFAULT_ALIGN) / 2; // 2
415 if (cachedFrame_->format == AV_PIX_FMT_YUV420P) {
416 cachedFrame_->data[0] = const_cast<uint8_t *>(data);
417 cachedFrame_->data[1] = cachedFrame_->data[0] + ySize;
418 cachedFrame_->data[2] = cachedFrame_->data[1] + uvSize; // 2: plane 2
419 } else if ((cachedFrame_->format == AV_PIX_FMT_NV12) || (cachedFrame_->format == AV_PIX_FMT_NV21)) {
420 cachedFrame_->data[0] = const_cast<uint8_t *>(data);
421 cachedFrame_->data[1] = cachedFrame_->data[0] + ySize;
422 } else {
423 MEDIA_LOG_E("Unsupported pixel format: " PUBLIC_LOG_D32, cachedFrame_->format);
424 return Status::ERROR_UNSUPPORTED_FORMAT;
425 }
426 cachedFrame_->pts = ConvertTimeToFFmpeg(
427 static_cast<uint64_t>(HstTime2Us(inputBuffer->pts)) / avCodecContext_->ticks_per_frame,
428 avCodecContext_->time_base);
429 MEDIA_LOG_D("hst pts: " PUBLIC_LOG_U64 " ns, ffmpeg pts: " PUBLIC_LOG_D64
430 " us, den: " PUBLIC_LOG_D32 ", num: " PUBLIC_LOG_D32,
431 inputBuffer->pts, cachedFrame_->pts, avCodecContext_->time_base.den, avCodecContext_->time_base.num);
432 return Status::OK;
433 }
434
SendBufferLocked(const std::shared_ptr<Buffer> & inputBuffer)435 Status VideoFfmpegEncoderPlugin::SendBufferLocked(const std::shared_ptr<Buffer>& inputBuffer)
436 {
437 FALSE_RETURN_V_MSG_E(state_ == State::RUNNING,
438 Status::ERROR_WRONG_STATE, "queue input buffer in wrong state");
439 bool isEos = false;
440 if (inputBuffer == nullptr || (inputBuffer->flag & BUFFER_FLAG_EOS) != 0) {
441 isEos = true;
442 } else {
443 auto res = FillAvFrame(inputBuffer);
444 FALSE_RETURN_V(res == Status::OK, res);
445 }
446 AVFrame *frame = nullptr;
447 if (!isEos) {
448 frame = cachedFrame_.get();
449 }
450 auto ret = avcodec_send_frame(avCodecContext_.get(), frame);
451 if (ret < 0) {
452 MEDIA_LOG_D("send buffer error " PUBLIC_LOG_S, AVStrError(ret).c_str());
453 return (ret == AVERROR_EOF) ? Status::END_OF_STREAM : Status::ERROR_NO_MEMORY;
454 }
455 if (frame) {
456 av_frame_unref(cachedFrame_.get());
457 }
458 return Status::OK;
459 }
460
FillFrameBuffer(const std::shared_ptr<Buffer> & packetBuffer)461 Status VideoFfmpegEncoderPlugin::FillFrameBuffer(const std::shared_ptr<Buffer>& packetBuffer)
462 {
463 FALSE_RETURN_V_MSG_E(cachedPacket_->data != nullptr, Status::ERROR_UNKNOWN,
464 "avcodec_receive_packet() packet data is empty");
465 auto frameBufferMem = packetBuffer->GetMemory();
466 FALSE_RETURN_V_MSG_E(frameBufferMem->Write(cachedPacket_->data, cachedPacket_->size, 0) ==
467 static_cast<size_t>(cachedPacket_->size), Status::ERROR_UNKNOWN,
468 "copy packet data to buffer fail");
469 if (cachedPacket_->flags & AV_PKT_FLAG_KEY) {
470 MEDIA_LOG_D("It is key frame");
471 packetBuffer->flag |= BUFFER_FLAG_KEY_FRAME;
472 }
473 packetBuffer->pts =
474 static_cast<uint64_t>(ConvertTimeFromFFmpeg(cachedPacket_->pts, avCodecContext_->time_base));
475 packetBuffer->dts =
476 static_cast<uint64_t>(ConvertTimeFromFFmpeg(cachedPacket_->dts, avCodecContext_->time_base));
477 #ifdef DUMP_RAW_DATA
478 if (dumpFd_) {
479 std::fwrite(reinterpret_cast<const char *>(cachedPacket_->data), 1, cachedPacket_->size, dumpFd_);
480 }
481 #endif
482 MEDIA_LOG_D("receive one pkt, hst pts: " PUBLIC_LOG_U64 " ns, ffmpeg pts: " PUBLIC_LOG_D64
483 " us, duration: " PUBLIC_LOG_D64 ", pos: " PUBLIC_LOG_D64,
484 packetBuffer->pts, cachedPacket_->pts, cachedPacket_->duration, cachedPacket_->pos);
485 return Status::OK;
486 }
487
ReceiveBufferLocked(const std::shared_ptr<Buffer> & packetBuffer)488 Status VideoFfmpegEncoderPlugin::ReceiveBufferLocked(const std::shared_ptr<Buffer>& packetBuffer)
489 {
490 FALSE_RETURN_V_MSG_E(state_ == State::RUNNING, Status::ERROR_WRONG_STATE,
491 "encode task in wrong state");
492 Status status;
493 auto ret = avcodec_receive_packet(avCodecContext_.get(), cachedPacket_.get());
494 if (ret >= 0) {
495 status = FillFrameBuffer(packetBuffer);
496 } else if (ret == AVERROR_EOF) {
497 MEDIA_LOG_I("eos received");
498 packetBuffer->GetMemory()->Reset();
499 packetBuffer->flag |= BUFFER_FLAG_EOS;
500 avcodec_flush_buffers(avCodecContext_.get());
501 status = Status::END_OF_STREAM;
502 } else {
503 MEDIA_LOG_D("video encoder receive error: " PUBLIC_LOG_S, AVStrError(ret).c_str());
504 status = Status::ERROR_TIMED_OUT;
505 }
506 av_frame_unref(cachedFrame_.get());
507 return status;
508 }
509
ReceiveBuffer()510 void VideoFfmpegEncoderPlugin::ReceiveBuffer()
511 {
512 std::shared_ptr<Buffer> packetBuffer = outBufferQ_.Pop();
513 FALSE_RETURN_MSG(packetBuffer != nullptr && !packetBuffer->IsEmpty() &&
514 packetBuffer->GetBufferMeta()->GetType() == BufferMetaType::VIDEO,
515 "cannot fetch valid buffer to output");
516 Status status;
517 {
518 OSAL::ScopedLock lock(avMutex_);
519 status = ReceiveBufferLocked(packetBuffer);
520 }
521 if (status == Status::OK || status == Status::END_OF_STREAM) {
522 NotifyOutputBufferDone(packetBuffer);
523 } else {
524 outBufferQ_.Push(packetBuffer);
525 }
526 }
527
NotifyInputBufferDone(const std::shared_ptr<Buffer> & input)528 void VideoFfmpegEncoderPlugin::NotifyInputBufferDone(const std::shared_ptr<Buffer>& input)
529 {
530 if (dataCb_ != nullptr) {
531 dataCb_->OnInputBufferDone(const_cast<std::shared_ptr<Buffer>&>(input));
532 }
533 }
534
NotifyOutputBufferDone(const std::shared_ptr<Buffer> & output)535 void VideoFfmpegEncoderPlugin::NotifyOutputBufferDone(const std::shared_ptr<Buffer>& output)
536 {
537 if (dataCb_ != nullptr) {
538 dataCb_->OnOutputBufferDone(const_cast<std::shared_ptr<Buffer>&>(output));
539 }
540 }
541
GetAllocator()542 std::shared_ptr<Allocator> VideoFfmpegEncoderPlugin::GetAllocator()
543 {
544 return nullptr;
545 }
546 } // namespace Ffmpeg
547 } // namespace Plugin
548 } // namespace Media
549 } // namespace OHOS
550 #endif
551