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_Muxer"
17
18 #include "ffmpeg_muxer_plugin.h"
19
20 #include <functional>
21 #include <set>
22
23 #include "foundation/log.h"
24 #include "foundation/osal/thread/scoped_lock.h"
25 #include "plugin/interface/plugin_definition.h"
26 #include "plugin/plugins/ffmpeg_adapter/utils/ffmpeg_utils.h"
27 #include "plugin/plugins/ffmpeg_adapter/utils/ffmpeg_codec_map.h"
28
29 namespace {
30 using namespace OHOS::Media::Plugin;
31 using namespace Ffmpeg;
32
__anon62eeeb090202(uint32_t i) 33 std::function<int32_t(uint32_t)> ui2iFunc = [](uint32_t i) {return i;};
34
35 std::map<std::string, std::shared_ptr<AVOutputFormat>> g_pluginOutputFmt;
36
37 std::set<std::string> g_supportedMuxer = {"mp4", "h264"};
38
IsMuxerSupported(const char * name)39 bool IsMuxerSupported(const char* name)
40 {
41 return g_supportedMuxer.count(name) == 1;
42 }
43
UpdatePluginInCapability(AVCodecID codecId,CapabilitySet & capSet)44 bool UpdatePluginInCapability(AVCodecID codecId, CapabilitySet& capSet)
45 {
46 if (codecId != AV_CODEC_ID_NONE) {
47 Capability cap;
48 if (!FFCodecMap::CodecId2Cap(codecId, true, cap)) {
49 return false;
50 } else {
51 capSet.emplace_back(cap);
52 }
53 }
54 return true;
55 }
56
UpdatePluginCapability(const AVOutputFormat * oFmt,MuxerPluginDef & pluginDef)57 bool UpdatePluginCapability(const AVOutputFormat* oFmt, MuxerPluginDef& pluginDef)
58 {
59 if (!FFCodecMap::FormatName2Cap(oFmt->name, pluginDef.outCaps)) {
60 MEDIA_LOG_D(PUBLIC_LOG_S " is not supported now", oFmt->name);
61 return false;
62 }
63 UpdatePluginInCapability(oFmt->audio_codec, pluginDef.inCaps);
64 UpdatePluginInCapability(oFmt->video_codec, pluginDef.inCaps);
65 UpdatePluginInCapability(oFmt->subtitle_codec, pluginDef.inCaps);
66 return true;
67 }
68
RegisterMuxerPlugins(const std::shared_ptr<Register> & reg)69 Status RegisterMuxerPlugins(const std::shared_ptr<Register>& reg)
70 {
71 MEDIA_LOG_D("register muxer plugins.");
72 FALSE_RETURN_V_MSG_E(reg != nullptr, Status::ERROR_INVALID_PARAMETER,
73 "RegisterPlugins failed due to null pointer for reg.");
74 const AVOutputFormat* outputFormat = nullptr;
75 void* ite = nullptr;
76 while ((outputFormat = av_muxer_iterate(&ite))) {
77 MEDIA_LOG_DD("check ffmpeg muxer name: " PUBLIC_LOG_S, outputFormat->name);
78 if (!IsMuxerSupported(outputFormat->name)) {
79 continue;
80 }
81 if (outputFormat->long_name != nullptr) {
82 if (!strncmp(outputFormat->long_name, "raw ", 4)) { // 4
83 continue;
84 }
85 }
86 std::string pluginName = "ffmpegMux_" + std::string(outputFormat->name);
87 ReplaceDelimiter(".,|-<> ", '_', pluginName);
88 MuxerPluginDef def;
89 if (!UpdatePluginCapability(outputFormat, def)) {
90 continue;
91 }
92 def.name = pluginName;
93 def.description = "ffmpeg muxer";
94 def.rank = 100; // 100
95 def.creator = [](const std::string& name) -> std::shared_ptr<MuxerPlugin> {
96 return std::make_shared<FFmpegMuxerPlugin>(name);
97 };
98 if (reg->AddPlugin(def) != Status::OK) {
99 MEDIA_LOG_W("fail to add plugin " PUBLIC_LOG_S, pluginName.c_str());
100 continue;
101 }
102 g_pluginOutputFmt[pluginName] = std::shared_ptr<AVOutputFormat>(const_cast<AVOutputFormat*>(outputFormat),
103 [](AVOutputFormat* ptr) {}); // do not delete
104 }
105 return Status::OK;
106 }
__anon62eeeb090502null107 PLUGIN_DEFINITION(FFmpegMuxers, LicenseType::LGPL, RegisterMuxerPlugins, [] {g_pluginOutputFmt.clear();})
108
SetCodecByMime(const AVOutputFormat * fmt,const std::string & mime,AVStream * stream)109 Status SetCodecByMime(const AVOutputFormat* fmt, const std::string& mime, AVStream* stream)
110 {
111 AVCodecID id = AV_CODEC_ID_NONE;
112 FALSE_RETURN_V_MSG_E(FFCodecMap::Mime2CodecId(mime, id), Status::ERROR_UNSUPPORTED_FORMAT,
113 "mime " PUBLIC_LOG_S " has no corresponding codec id", mime.c_str());
114 auto ptr = avcodec_find_encoder(id);
115 FALSE_RETURN_V_MSG_E(ptr != nullptr, Status::ERROR_UNSUPPORTED_FORMAT,
116 "codec of mime " PUBLIC_LOG_S " is not founder as encoder", mime.c_str());
117 bool matched = true;
118 switch (ptr->type) {
119 case AVMEDIA_TYPE_VIDEO:
120 matched = id == fmt->video_codec;
121 break;
122 case AVMEDIA_TYPE_AUDIO:
123 matched = id == fmt->audio_codec;
124 break;
125 case AVMEDIA_TYPE_SUBTITLE:
126 matched = id == fmt->subtitle_codec;
127 break;
128 default:
129 matched = false;
130 }
131 FALSE_RETURN_V_MSG_E(matched, Status::ERROR_UNSUPPORTED_FORMAT, "codec of mime " PUBLIC_LOG_S
132 " is not matched with " PUBLIC_LOG_S " muxer", mime.c_str(), fmt->name);
133 stream->codecpar->codec_id = id;
134 stream->codecpar->codec_type = ptr->type;
135 return Status::OK;
136 }
137
SetCodecOfTrack(const AVOutputFormat * fmt,AVStream * stream,const TagMap & tagMap)138 Status SetCodecOfTrack(const AVOutputFormat* fmt, AVStream* stream, const TagMap& tagMap)
139 {
140 auto ite = tagMap.Find(Tag::MIME);
141 FALSE_RETURN_V_MSG_E(ite != std::end(tagMap), Status::ERROR_UNSUPPORTED_FORMAT, "mime is missing!");
142 FALSE_RETURN_V(ite->second.SameTypeWith(typeid(std::string)), Status::ERROR_MISMATCHED_TYPE);
143 // todo specially for audio/mpeg audio/mpeg we should check mpegversion and mpeglayer
144
145 return SetCodecByMime(fmt, AnyCast<std::string>(ite->second), stream);
146 }
147
148 template<typename T, typename U>
SetSingleParameter(Tag tag,const TagMap & tagMap,U & target,std::function<U (T)> func)149 Status SetSingleParameter(Tag tag, const TagMap& tagMap, U& target, std::function<U(T)> func)
150 {
151 auto ite = tagMap.Find(tag);
152 if (ite != std::end(tagMap)) {
153 FALSE_RETURN_V_MSG_E(ite->second.SameTypeWith(typeid(T)), Status::ERROR_MISMATCHED_TYPE,
154 "tag " PUBLIC_LOG_U32 " type mismatched", tag);
155 target = func(AnyCast<T>(ite->second));
156 }
157 return Status::OK;
158 }
159
SetParameterOfAuTrack(AVStream * stream,const TagMap & tagMap)160 Status SetParameterOfAuTrack(AVStream* stream, const TagMap& tagMap)
161 {
162 auto ret = SetSingleParameter<AudioSampleFormat, int32_t>(Tag::AUDIO_SAMPLE_FORMAT, tagMap,
163 stream->codecpar->format, ConvP2FfSampleFmt);
164 NOK_RETURN(ret);
165 ret = SetSingleParameter<uint32_t, int32_t>(Tag::AUDIO_CHANNELS, tagMap, stream->codecpar->channels, ui2iFunc);
166 NOK_RETURN(ret);
167 ret = SetSingleParameter<uint32_t, int32_t>(Tag::AUDIO_SAMPLE_RATE, tagMap, stream->codecpar->sample_rate,
168 ui2iFunc);
169 NOK_RETURN(ret);
170 ret = SetSingleParameter<uint32_t, int32_t>(Tag::AUDIO_SAMPLE_PER_FRAME, tagMap, stream->codecpar->frame_size,
171 ui2iFunc);
172 NOK_RETURN(ret);
173 ret = SetSingleParameter<AudioChannelLayout, uint64_t>(Tag::AUDIO_CHANNEL_LAYOUT, tagMap,
174 stream->codecpar->channel_layout, [](AudioChannelLayout layout) {return (uint64_t)layout;});
175 return ret;
176 }
177
SetParameterOfVdTrack(AVStream * stream,const TagMap & tagMap)178 Status SetParameterOfVdTrack(AVStream* stream, const TagMap& tagMap)
179 {
180 auto ret = SetSingleParameter<VideoPixelFormat, int32_t>(Tag::VIDEO_PIXEL_FORMAT, tagMap,
181 stream->codecpar->format, ConvertPixelFormatToFFmpeg);
182 NOK_RETURN(ret);
183 ret = SetSingleParameter<uint32_t, int32_t>(Tag::VIDEO_WIDTH, tagMap, stream->codecpar->width, ui2iFunc);
184 NOK_RETURN(ret);
185 ret = SetSingleParameter<uint32_t, int32_t>(Tag::VIDEO_HEIGHT, tagMap, stream->codecpar->height, ui2iFunc);
186 NOK_RETURN(ret);
187 ret = SetSingleParameter<int64_t, int64_t>(Tag::MEDIA_BITRATE, tagMap, stream->codecpar->bit_rate,
188 [](int64_t bitRate) {return bitRate;});
189 NOK_RETURN(ret);
190 ret = SetSingleParameter<VideoH264Profile, int32_t>(Tag::VIDEO_H264_PROFILE, tagMap, stream->codecpar->profile,
191 ConvH264ProfileToFfmpeg);
192 NOK_RETURN(ret);
193 return SetSingleParameter<uint32_t, int32_t>(Tag::VIDEO_H264_LEVEL, tagMap, stream->codecpar->level,
194 ui2iFunc);
195 }
196
SetParameterOfSubTitleTrack(AVStream * stream,const TagMap & tagMap)197 Status SetParameterOfSubTitleTrack(AVStream* stream, const TagMap& tagMap)
198 {
199 // todo add subtitle
200 MEDIA_LOG_E("should add subtitle tack parameter setter");
201 return Status::ERROR_UNKNOWN;
202 }
203
ResetCodecParameter(AVCodecParameters * par)204 void ResetCodecParameter(AVCodecParameters* par)
205 {
206 av_freep(&par->extradata);
207 (void)memset_s(par, sizeof(*par), 0, sizeof(*par));
208 par->codec_type = AVMEDIA_TYPE_UNKNOWN;
209 par->codec_id = AV_CODEC_ID_NONE;
210 par->format = -1;
211 par->profile = FF_PROFILE_UNKNOWN;
212 par->level = FF_LEVEL_UNKNOWN;
213 par->field_order = AV_FIELD_UNKNOWN;
214 par->color_range = AVCOL_RANGE_UNSPECIFIED;
215 par->color_primaries = AVCOL_PRI_UNSPECIFIED;
216 par->color_trc = AVCOL_TRC_UNSPECIFIED;
217 par->color_space = AVCOL_SPC_UNSPECIFIED;
218 par->chroma_location = AVCHROMA_LOC_UNSPECIFIED;
219 par->sample_aspect_ratio = AVRational {0, 1};
220 }
221
SetTagsOfTrack(const AVOutputFormat * fmt,AVStream * stream,const TagMap & tagMap)222 Status SetTagsOfTrack(const AVOutputFormat* fmt, AVStream* stream, const TagMap& tagMap)
223 {
224 FALSE_RETURN_V(stream != nullptr, Status::ERROR_INVALID_PARAMETER);
225 ResetCodecParameter(stream->codecpar);
226 // firstly mime
227 auto ret = SetCodecOfTrack(fmt, stream, tagMap);
228 NOK_RETURN(ret);
229 if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { // audio
230 ret = SetParameterOfAuTrack(stream, tagMap);
231 } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { // video
232 ret = SetParameterOfVdTrack(stream, tagMap);
233 } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) { // subtitle
234 ret = SetParameterOfSubTitleTrack(stream, tagMap);
235 } else {
236 MEDIA_LOG_W("unknown codec type of stream " PUBLIC_LOG_D32, stream->index);
237 }
238 NOK_RETURN(ret);
239 // others
240 ret = SetSingleParameter<int64_t, int64_t>(Tag::MEDIA_BITRATE, tagMap, stream->codecpar->bit_rate,
241 [](int64_t rate) {return rate;});
242 NOK_RETURN(ret);
243 // extra data
244 auto ite = tagMap.Find(Tag::MEDIA_CODEC_CONFIG);
245 if (ite != std::end(tagMap)) {
246 FALSE_RETURN_V_MSG_E(ite->second.SameTypeWith(typeid(CodecConfig)), Status::ERROR_MISMATCHED_TYPE,
247 "tag " PUBLIC_LOG_D32 " type mismatched", Tag::MEDIA_CODEC_CONFIG);
248 auto codecConfig = AnyCast<CodecConfig>(ite->second);
249 if (!codecConfig.empty()) {
250 auto extraSize = codecConfig.size();
251 stream->codecpar->extradata = static_cast<uint8_t *>(av_mallocz(extraSize + AV_INPUT_BUFFER_PADDING_SIZE));
252 FALSE_RETURN_V(stream->codecpar->extradata != nullptr, Status::ERROR_NO_MEMORY);
253 (void)memcpy_s(stream->codecpar->extradata, extraSize, codecConfig.data(), extraSize);
254 stream->codecpar->extradata_size = extraSize;
255 }
256 }
257 return Status::OK;
258 }
259
SetTagsOfGeneral(AVFormatContext * fmtCtx,const TagMap & tags)260 Status SetTagsOfGeneral(AVFormatContext* fmtCtx, const TagMap& tags)
261 {
262 for (const auto& pair: tags) {
263 std::string metaName;
264 if (!FindAvMetaNameByTag(pair.first, metaName)) {
265 MEDIA_LOG_I("tag " PUBLIC_LOG_U32 " will not written as general meta", pair.first);
266 continue;
267 }
268 if (!pair.second.SameTypeWith(typeid(std::string))) {
269 continue;
270 }
271 auto value = AnyCast<std::string>(pair.second);
272 av_dict_set(&fmtCtx->metadata, metaName.c_str(), value.c_str(), 0);
273 }
274 return Status::OK;
275 }
276 }
277
278 namespace OHOS {
279 namespace Media {
280 namespace Plugin {
281 namespace Ffmpeg {
FFmpegMuxerPlugin(std::string name)282 FFmpegMuxerPlugin::FFmpegMuxerPlugin(std::string name) : MuxerPlugin(std::move(name)) {}
283
~FFmpegMuxerPlugin()284 FFmpegMuxerPlugin::~FFmpegMuxerPlugin()
285 {
286 Release();
287 }
Release()288 Status FFmpegMuxerPlugin::Release()
289 {
290 outputFormat_.reset();
291 cachePacket_.reset();
292 formatContext_.reset();
293 return Status::OK;
294 }
295
InitFormatCtxLocked()296 Status FFmpegMuxerPlugin::InitFormatCtxLocked()
297 {
298 if (formatContext_ == nullptr) {
299 auto ioCtx = InitAvIoCtx();
300 FALSE_RETURN_V(ioCtx != nullptr, Status::ERROR_NO_MEMORY);
301 auto fmt = avformat_alloc_context();
302 FALSE_RETURN_V(fmt != nullptr, Status::ERROR_NO_MEMORY);
303 fmt->pb = ioCtx;
304 fmt->oformat = outputFormat_.get();
305 fmt->flags = static_cast<uint32_t>(fmt->flags) | static_cast<uint32_t>(AVFMT_FLAG_CUSTOM_IO);
306 formatContext_ = std::shared_ptr<AVFormatContext>(fmt, [](AVFormatContext* ptr) {
307 if (ptr) {
308 DeInitAvIoCtx(ptr->pb);
309 avformat_free_context(ptr);
310 }
311 });
312 }
313 return Status::OK;
314 }
315
Init()316 Status FFmpegMuxerPlugin::Init()
317 {
318 MEDIA_LOG_D("Init entered.");
319 FALSE_RETURN_V(g_pluginOutputFmt.count(pluginName_) != 0, Status::ERROR_UNSUPPORTED_FORMAT);
320 outputFormat_ = g_pluginOutputFmt[pluginName_];
321 auto pkt = av_packet_alloc();
322 cachePacket_ = std::shared_ptr<AVPacket> (pkt, [] (AVPacket* packet) {av_packet_free(&packet);});
323 OSAL::ScopedLock lock(fmtMutex_);
324 return InitFormatCtxLocked();
325 }
326
Deinit()327 Status FFmpegMuxerPlugin::Deinit()
328 {
329 return Release();
330 }
331
InitAvIoCtx()332 AVIOContext* FFmpegMuxerPlugin::InitAvIoCtx()
333 {
334 constexpr int bufferSize = 4096; // 4096
335 auto buffer = static_cast<unsigned char*>(av_malloc(bufferSize));
336 FALSE_RETURN_V_MSG_E(buffer != nullptr, nullptr, "AllocAVIOContext failed to av_malloc...");
337 AVIOContext* avioContext = avio_alloc_context(buffer, bufferSize, AVIO_FLAG_WRITE, static_cast<void*>(&ioContext_),
338 IoRead, IoWrite, IoSeek);
339 if (avioContext == nullptr) {
340 MEDIA_LOG_E("AllocAVIOContext failed to avio_alloc_context...");
341 av_free(buffer);
342 return nullptr;
343 }
344 avioContext->seekable = AVIO_SEEKABLE_NORMAL;
345 return avioContext;
346 }
347
DeInitAvIoCtx(AVIOContext * ptr)348 void FFmpegMuxerPlugin::DeInitAvIoCtx(AVIOContext* ptr)
349 {
350 if (ptr != nullptr) {
351 ptr->opaque = nullptr;
352 av_freep(&ptr->buffer);
353 avio_context_free(&ptr);
354 }
355 }
356
Prepare()357 Status FFmpegMuxerPlugin::Prepare()
358 {
359 for (const auto& pair: trackParameters_) {
360 SetTagsOfTrack(outputFormat_.get(), formatContext_->streams[pair.first], pair.second);
361 }
362 SetTagsOfGeneral(formatContext_.get(), generalParameters_);
363 formatContext_->flags |= AVFMT_TS_NONSTRICT;
364 return Status::OK;
365 }
ResetIoCtx(IOContext & ioContext)366 void FFmpegMuxerPlugin::ResetIoCtx(IOContext& ioContext)
367 {
368 ioContext.dataSink_.reset();
369 ioContext.pos_ = 0;
370 ioContext.end_ = 0;
371 }
Reset()372 Status FFmpegMuxerPlugin::Reset()
373 {
374 ResetIoCtx(ioContext_);
375 generalParameters_.Clear();
376 trackParameters_.clear();
377 OSAL::ScopedLock lock(fmtMutex_);
378 if (outputFormat_->deinit) {
379 outputFormat_->deinit(formatContext_.get());
380 }
381 formatContext_.reset();
382 return InitFormatCtxLocked();
383 }
384
GetParameter(Tag tag,ValueType & value)385 Status FFmpegMuxerPlugin::GetParameter(Tag tag, ValueType& value)
386 {
387 return PluginBase::GetParameter(tag, value);
388 }
389
GetTrackParameter(uint32_t trackId,Tag tag,Plugin::ValueType & value)390 Status FFmpegMuxerPlugin::GetTrackParameter(uint32_t trackId, Tag tag, Plugin::ValueType& value)
391 {
392 return Status::ERROR_UNIMPLEMENTED;
393 }
394
SetParameter(Tag tag,const ValueType & value)395 Status FFmpegMuxerPlugin::SetParameter(Tag tag, const ValueType& value)
396 {
397 generalParameters_[tag] = value;
398 return Status::OK;
399 }
400
SetTrackParameter(uint32_t trackId,Tag tag,const Plugin::ValueType & value)401 Status FFmpegMuxerPlugin::SetTrackParameter(uint32_t trackId, Tag tag, const Plugin::ValueType& value)
402 {
403 FALSE_RETURN_V(trackId < formatContext_->nb_streams, Status::ERROR_INVALID_PARAMETER);
404 if (trackParameters_.count(trackId) == 0) {
405 trackParameters_.insert({trackId, Plugin::TagMap()});
406 }
407 trackParameters_[trackId][tag] = value;
408 return Status::OK;
409 }
410
AddTrack(uint32_t & trackId)411 Status FFmpegMuxerPlugin::AddTrack(uint32_t &trackId)
412 {
413 OSAL::ScopedLock lock(fmtMutex_);
414 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_WRONG_STATE, "formatContext_ is NULL");
415 auto st = avformat_new_stream(formatContext_.get(), nullptr);
416 FALSE_RETURN_V_MSG_E(st != nullptr, Status::ERROR_NO_MEMORY, "avformat_new_stream fail");
417 st->codecpar->codec_type = AVMEDIA_TYPE_UNKNOWN;
418 st->codecpar->codec_id = AV_CODEC_ID_NONE;
419 trackId = static_cast<uint32_t>(st->index);
420 return Status::OK;
421 }
422
SetDataSink(const std::shared_ptr<DataSink> & dataSink)423 Status FFmpegMuxerPlugin::SetDataSink(const std::shared_ptr<DataSink>& dataSink)
424 {
425 ioContext_.dataSink_ = dataSink;
426 return Status::OK;
427 }
428
WriteHeader()429 Status FFmpegMuxerPlugin::WriteHeader()
430 {
431 FALSE_RETURN_V(ioContext_.dataSink_ != nullptr && outputFormat_ != nullptr, Status::ERROR_WRONG_STATE);
432 OSAL::ScopedLock lock(fmtMutex_);
433 FALSE_RETURN_V(formatContext_ != nullptr, Status::ERROR_WRONG_STATE);
434 int ret = avformat_write_header(formatContext_.get(), nullptr);
435 FALSE_RETURN_V_MSG_E(ret >= 0, Status::ERROR_UNKNOWN, "failed to write header " PUBLIC_LOG_S,
436 AVStrError(ret).c_str());
437 return Status::OK;
438 }
439
WriteFrame(const std::shared_ptr<Plugin::Buffer> & buffer)440 Status FFmpegMuxerPlugin::WriteFrame(const std::shared_ptr<Plugin::Buffer>& buffer)
441 {
442 FALSE_RETURN_V(buffer != nullptr && !buffer->IsEmpty(), Status::ERROR_INVALID_PARAMETER);
443 uint32_t trackId = buffer->trackID;
444 FALSE_RETURN_V(trackId < formatContext_->nb_streams, Status::ERROR_INVALID_PARAMETER);
445 (void)memset_s(cachePacket_.get(), sizeof(AVPacket), 0, sizeof(AVPacket));
446 auto memory = buffer->GetMemory();
447 cachePacket_->data = const_cast<uint8_t*>(memory->GetReadOnlyData());
448 cachePacket_->size = memory->GetSize();
449 cachePacket_->stream_index = static_cast<int>(trackId);
450 cachePacket_->pts = ConvertTimeToFFmpeg(buffer->pts, formatContext_->streams[trackId]->time_base);
451 cachePacket_->dts = cachePacket_->pts;
452 cachePacket_->flags = 0;
453 if (buffer->flag & BUFFER_FLAG_KEY_FRAME) {
454 MEDIA_LOG_D("It is key frame");
455 cachePacket_->flags |= AV_PKT_FLAG_KEY;
456 }
457 cachePacket_->duration = ConvertTimeToFFmpeg(buffer->duration, formatContext_->streams[trackId]->time_base);
458 auto ret = av_write_frame(formatContext_.get(), cachePacket_.get());
459 if (ret < 0) {
460 MEDIA_LOG_D("failed to write frame " PUBLIC_LOG_S, AVStrError(ret).c_str());
461 av_packet_unref(cachePacket_.get());
462 return Status::ERROR_UNKNOWN;
463 }
464 av_packet_unref(cachePacket_.get());
465 return Status::OK;
466 }
467
WriteTrailer()468 Status FFmpegMuxerPlugin::WriteTrailer()
469 {
470 FALSE_RETURN_V(ioContext_.dataSink_ != nullptr && outputFormat_ != nullptr, Status::ERROR_WRONG_STATE);
471 OSAL::ScopedLock lock(fmtMutex_);
472 FALSE_RETURN_V(formatContext_ != nullptr, Status::ERROR_WRONG_STATE);
473 av_write_frame(formatContext_.get(), nullptr); // flush out cache data
474 int ret = av_write_trailer(formatContext_.get());
475 if (ret != 0) {
476 MEDIA_LOG_E("failed to write trailer " PUBLIC_LOG_S, AVStrError(ret).c_str());
477 }
478 avio_flush(formatContext_->pb);
479 return Status::OK;
480 }
481
SetCallback(Callback * cb)482 Status FFmpegMuxerPlugin::SetCallback(Callback* cb)
483 {
484 return Status::END_OF_STREAM;
485 }
486
GetAllocator()487 std::shared_ptr<Allocator> FFmpegMuxerPlugin::GetAllocator()
488 {
489 return {};
490 }
491
IoRead(void * opaque,uint8_t * buf,int bufSize)492 int32_t FFmpegMuxerPlugin::IoRead(void* opaque, uint8_t* buf, int bufSize)
493 {
494 (void)opaque;
495 (void)buf;
496 (void)bufSize;
497 return 0;
498 }
IoWrite(void * opaque,uint8_t * buf,int bufSize)499 int32_t FFmpegMuxerPlugin::IoWrite(void* opaque, uint8_t* buf, int bufSize)
500 {
501 auto ioCtx = static_cast<IOContext*>(opaque);
502 if (ioCtx && ioCtx->dataSink_) {
503 auto buffer = std::make_shared<Buffer>();
504 auto bufferMem = buffer->AllocMemory(nullptr, bufSize);
505 buffer->GetMemory()->Write(buf, bufSize, 0); // copy to buffer
506 auto res = ioCtx->dataSink_->WriteAt(ioCtx->pos_, buffer);
507 if (res == Status::OK) {
508 ioCtx->pos_ += bufferMem->GetSize();
509 if (ioCtx->pos_ > ioCtx->end_) {
510 ioCtx->end_ = ioCtx->pos_;
511 }
512 return bufferMem->GetSize();
513 }
514 return 0;
515 }
516 return -1;
517 }
518
IoSeek(void * opaque,int64_t offset,int whence)519 int64_t FFmpegMuxerPlugin::IoSeek(void* opaque, int64_t offset, int whence)
520 {
521 auto ioContext = static_cast<IOContext*>(opaque);
522 uint64_t newPos = 0;
523 switch (whence) {
524 case SEEK_SET:
525 newPos = static_cast<uint64_t>(offset);
526 ioContext->pos_ = newPos;
527 MEDIA_LOG_I("AVSeek whence: " PUBLIC_LOG_D32 ", pos = " PUBLIC_LOG_D64 ", newPos = " PUBLIC_LOG_U64,
528 whence, offset, newPos);
529 break;
530 case SEEK_CUR:
531 newPos = ioContext->pos_ + offset;
532 MEDIA_LOG_I("AVSeek whence: " PUBLIC_LOG_D32 ", pos = " PUBLIC_LOG_D64 ", newPos = " PUBLIC_LOG_U64,
533 whence, offset, newPos);
534 break;
535 case SEEK_END:
536 case AVSEEK_SIZE:
537 newPos = ioContext->end_ + offset;
538 MEDIA_LOG_I("AVSeek seek end whence: " PUBLIC_LOG_D32 ", pos = " PUBLIC_LOG_D64, whence, offset);
539 break;
540 default:
541 MEDIA_LOG_E("AVSeek unexpected whence: " PUBLIC_LOG_D32, whence);
542 break;
543 }
544 if (whence != AVSEEK_SIZE) {
545 ioContext->pos_ = newPos;
546 }
547 MEDIA_LOG_DD("current offset: " PUBLIC_LOG_D64 ", new pos: " PUBLIC_LOG_U64, ioContext->pos_, newPos);
548 return newPos;
549 }
550 } // Ffmpeg
551 } // Plugin
552 } // Media
553 } // OHOS