• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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