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