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