1 /*
2  *
3  * Copyright (c) 2021-2021 Huawei Device Co., Ltd.
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define HST_LOG_TAG "FFmpegDemuxerPlugin"
18 
19 // Modify FFMPEG_LOG_DEBUG_ENABLE to 1 to show Ffmpeg log.
20 #define FFMPEG_LOG_DEBUG_ENABLE 0
21 
22 #include "ffmpeg_demuxer_plugin.h"
23 #include <algorithm>
24 #include <cstdio>
25 #include <cstring>
26 #include <new>
27 #include "ffmpeg_track_meta.h"
28 #include "foundation/cpp_ext/memory_ext.h"
29 #include "foundation/log.h"
30 #include "foundation/osal/thread/scoped_lock.h"
31 #include "plugin/common/plugin_buffer.h"
32 #include "plugin/common/plugin_time.h"
33 #include "plugin/core/plugin_manager.h"
34 #include "plugins/ffmpeg_adapter/utils/ffmpeg_utils.h"
35 
36 #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 78, 0) and LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 64, 100)
37 #if LIBAVFORMAT_VERSION_INT != AV_VERSION_INT(58, 76, 100)
38 #include "libavformat/internal.h"
39 #endif
40 #endif
41 
42 namespace OHOS {
43 namespace Media {
44 namespace Plugin {
45 namespace Ffmpeg {
46 namespace {
47 std::map<std::string, std::shared_ptr<AVInputFormat>> g_pluginInputFormat;
48 
49 std::map<AVMediaType, MediaType> g_MediaTypeMap = {
50     {AVMEDIA_TYPE_AUDIO, MediaType::AUDIO},
51     {AVMEDIA_TYPE_VIDEO, MediaType::VIDEO},
52     {AVMEDIA_TYPE_DATA, MediaType::DATA},
53     {AVMEDIA_TYPE_ATTACHMENT, MediaType::ATTACHMENT},
54     {AVMEDIA_TYPE_UNKNOWN, MediaType::UNKNOWN},
55     {AVMEDIA_TYPE_SUBTITLE, MediaType::SUBTITLE}
56 };
57 
58 static const std::map<SeekMode, int32_t> seekModeToFfmpegSeekFlags = {
59     { SeekMode::SEEK_PREVIOUS_SYNC, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_BACKWARD },
60     { SeekMode::SEEK_NEXT_SYNC, AVSEEK_FLAG_FRAME },
61     { SeekMode::SEEK_CLOSEST_SYNC, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_ANY },
62     { SeekMode::SEEK_CLOSEST, AVSEEK_FLAG_FRAME | AVSEEK_FLAG_ANY }
63 };
64 int Sniff(const std::string& pluginName, std::shared_ptr<DataSource> dataSource);
65 
66 Status RegisterPlugins(const std::shared_ptr<Register>& reg);
67 static void FfmpegLogInit();
68 } // namespace
69 
Alloc(size_t size)70 void* FFmpegDemuxerPlugin::DemuxerPluginAllocator::Alloc(size_t size)
71 {
72     if (size == 0) {
73         return nullptr;
74     }
75     return static_cast<void*>(new (std::nothrow) uint8_t[size]);
76 }
77 
Free(void * ptr)78 void FFmpegDemuxerPlugin::DemuxerPluginAllocator::Free(void* ptr) // NOLINT: void*
79 {
80     if (ptr) {
81         auto data = static_cast<uint8_t*>(ptr);
82         delete[] data;
83     }
84 }
85 
FFmpegDemuxerPlugin(std::string name)86 FFmpegDemuxerPlugin::FFmpegDemuxerPlugin(std::string name)
87     : DemuxerPlugin(std::move(name)),
88       ioContext_(),
89       callback_(nullptr),
90       pluginImpl_(nullptr),
91       formatContext_(nullptr),
92       allocator_(std::make_shared<DemuxerPluginAllocator>()),
93       mediaInfo_(nullptr),
94       selectedTrackIds_()
95 {
96     MEDIA_LOG_I("ctor called, plugin name: " PUBLIC_LOG_S, pluginName_.c_str());
97 }
98 
~FFmpegDemuxerPlugin()99 FFmpegDemuxerPlugin::~FFmpegDemuxerPlugin()
100 {
101     MEDIA_LOG_D("dtor called.");
102     pluginImpl_ = nullptr;
103 }
104 
Init()105 Status FFmpegDemuxerPlugin::Init()
106 {
107     MEDIA_LOG_D("Init called.");
108     Reset();
109     FfmpegLogInit();
110     pluginImpl_ = g_pluginInputFormat[pluginName_];
111 
112     return pluginImpl_ ? Status::OK : Status::ERROR_UNSUPPORTED_FORMAT;
113 }
114 
Deinit()115 Status FFmpegDemuxerPlugin::Deinit()
116 {
117     avbsfContext_.reset();
118     vdBitStreamFormat_ = VideoBitStreamFormat{VideoBitStreamFormat::UNKNOWN};
119     return Status::OK;
120 }
121 
Prepare()122 Status FFmpegDemuxerPlugin::Prepare()
123 {
124     InitAVFormatContext();
125     if (formatContext_ == nullptr) {
126         MEDIA_LOG_E("prepare failed due to formatContext init error");
127         return Status::ERROR_UNKNOWN;
128     }
129     return Status::OK;
130 }
131 
Reset()132 Status FFmpegDemuxerPlugin::Reset()
133 {
134     mediaInfo_.reset();
135     ioContext_.offset = 0;
136     ioContext_.eos = false;
137     selectedTrackIds_.clear();
138     avbsfContext_.reset();
139     vdBitStreamFormat_ = VideoBitStreamFormat{VideoBitStreamFormat::UNKNOWN};
140     return Status::OK;
141 }
142 
143 /**
144  * GetParameter no need supported by demuxer
145  * @return return ERROR_UNIMPLEMENTED always.
146  */
GetParameter(Tag tag,ValueType & value)147 Status FFmpegDemuxerPlugin::GetParameter(Tag tag, ValueType& value)
148 {
149     switch (tag) {
150         case Tag::MEDIA_PLAYBACK_SPEED:
151             value = playbackSpeed_;
152             break;
153         default:
154             break;
155     }
156     return Status::OK;
157 }
158 
159 /**
160  * SetParameter no need supported by demuxer
161  * @return return ERROR_UNIMPLEMENTED always.
162  */
SetParameter(Tag tag,const ValueType & value)163 Status FFmpegDemuxerPlugin::SetParameter(Tag tag, const ValueType& value)
164 {
165     switch (tag) {
166         case Tag::MEDIA_PLAYBACK_SPEED:
167             playbackSpeed_ = Plugin::AnyCast<double>(value);
168             break;
169         case Tag::VIDEO_BIT_STREAM_FORMAT:
170             vdBitStreamFormat_ = Plugin::AnyCast<VideoBitStreamFormat>(value);
171             break;
172         default:
173             break;
174     }
175     return Status::OK;
176 }
177 
GetAllocator()178 std::shared_ptr<Allocator> FFmpegDemuxerPlugin::GetAllocator()
179 {
180     return allocator_;
181 }
182 
SetCallback(Callback * cb)183 Status FFmpegDemuxerPlugin::SetCallback(Callback* cb)
184 {
185     callback_ = cb;
186     return Status::OK;
187 }
188 
SetDataSource(const std::shared_ptr<DataSource> & source)189 Status FFmpegDemuxerPlugin::SetDataSource(const std::shared_ptr<DataSource>& source)
190 {
191     ioContext_.dataSource = source;
192     seekable_ = source->GetSeekable();
193     return Status::OK;
194 }
195 
GetMediaInfo(MediaInfo & mediaInfo)196 Status FFmpegDemuxerPlugin::GetMediaInfo(MediaInfo& mediaInfo)
197 {
198     if (!mediaInfo_ && !ParseMediaData()) {
199         return Status::ERROR_WRONG_STATE;
200     }
201     mediaInfo = *mediaInfo_;
202     return Status::OK;
203 }
204 
GetTrackCount()205 size_t FFmpegDemuxerPlugin::GetTrackCount()
206 {
207     size_t trackCnt = 0;
208     if (mediaInfo_) {
209         trackCnt = mediaInfo_->tracks.size();
210     }
211     return trackCnt;
212 }
213 
SelectTrack(int32_t trackId)214 Status FFmpegDemuxerPlugin::SelectTrack(int32_t trackId)
215 {
216     if (!mediaInfo_) {
217         MEDIA_LOG_E("SelectTrack called before GetMediaInfo()...");
218         return Status::ERROR_WRONG_STATE;
219     }
220     if (trackId < 0 || trackId >= static_cast<int32_t>(mediaInfo_->tracks.size())) {
221         MEDIA_LOG_E("SelectTrack called with invalid trackId: " PUBLIC_LOG_D32 ", number of tracks: " PUBLIC_LOG
222                     "d", trackId, static_cast<int>(mediaInfo_->tracks.size()));
223         return Status::ERROR_INVALID_PARAMETER;
224     }
225     OSAL::ScopedLock lock(mutex_);
226     auto it = std::find_if(selectedTrackIds_.begin(), selectedTrackIds_.end(),
227                            [trackId](int32_t streamId) { return trackId == streamId; });
228     if (it == selectedTrackIds_.end()) {
229         selectedTrackIds_.push_back(trackId);
230     }
231     return Status::OK;
232 }
233 
UnselectTrack(int32_t trackId)234 Status FFmpegDemuxerPlugin::UnselectTrack(int32_t trackId)
235 {
236     OSAL::ScopedLock lock(mutex_);
237     auto it = std::find_if(selectedTrackIds_.begin(), selectedTrackIds_.end(),
238                            [trackId](int32_t streamId) { return trackId == streamId; });
239     if (it != selectedTrackIds_.end()) {
240         selectedTrackIds_.erase(it);
241     }
242     return Status::OK;
243 }
244 
GetSelectedTracks(std::vector<int32_t> & trackIds)245 Status FFmpegDemuxerPlugin::GetSelectedTracks(std::vector<int32_t>& trackIds)
246 {
247     OSAL::ScopedLock lock(mutex_);
248     trackIds = selectedTrackIds_;
249     return Status::OK;
250 }
251 
ConvertAVPacketToFrameInfo(const AVStream & avStream,AVPacket & pkt,Buffer & frameInfo)252 bool FFmpegDemuxerPlugin::ConvertAVPacketToFrameInfo(const AVStream& avStream, AVPacket& pkt, Buffer& frameInfo)
253 {
254     frameInfo.trackID = static_cast<uint32_t>(pkt.stream_index);
255     int64_t pts = (pkt.pts > 0) ? pkt.pts : 0;
256     frameInfo.pts = ConvertTimeFromFFmpeg(pts, avStream.time_base);
257     frameInfo.dts = static_cast<uint32_t>(pkt.dts);
258     frameInfo.duration = ConvertTimeFromFFmpeg(pkt.duration, avStream.time_base);
259     frameInfo.GetBufferMeta()->SetMeta(Tag::MEDIA_POSITION, static_cast<uint32_t>(pkt.pos));
260 
261     int frameSize = 0;
262     if (avStream.codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
263         frameSize = pkt.size;
264     } else if (avStream.codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
265         if (avStream.codecpar->codec_id == AV_CODEC_ID_RAWVIDEO) {
266             MEDIA_LOG_W("unsupport raw video");
267             return false;
268         }
269         if (vdBitStreamFormat_ == VideoBitStreamFormat::ANNEXB) {
270             if (!avbsfContext_) {
271                 InitConvertContext(avStream);
272             }
273             if (avbsfContext_) {
274                 ConvertAvcOrHevcToAnnexb(pkt);
275             }
276         }
277         frameSize = pkt.size;
278         frameInfo.ChangeBufferMetaType(BufferMetaType::VIDEO);
279     } else {
280         MEDIA_LOG_W("unsupported codec type: " PUBLIC_LOG_D32, static_cast<int32_t>(avStream.codecpar->codec_type));
281         return false;
282     }
283     auto data = frameInfo.AllocMemory(allocator_, frameSize);
284     if (data) {
285         size_t writeSize = data->Write(pkt.data, frameSize);
286         FALSE_LOG_MSG(writeSize == static_cast<size_t>(frameSize), "Copy data failed.");
287     }
288     return data != nullptr;
289 }
290 
InitConvertContext(const AVStream & avStream)291 void FFmpegDemuxerPlugin::InitConvertContext(const AVStream& avStream)
292 {
293     const AVBitStreamFilter* avBitStreamFilter {nullptr};
294     char codeTag[AV_FOURCC_MAX_STRING_SIZE] {0};
295     av_fourcc_make_string(codeTag, avStream.codecpar->codec_tag);
296     if (strncmp(codeTag, "avc1", strlen("avc1")) == 0) {
297         avBitStreamFilter = av_bsf_get_by_name("h264_mp4toannexb");
298     } else if (strncmp(codeTag, "hevc", strlen("hevc")) == 0) {
299         avBitStreamFilter = av_bsf_get_by_name("hevc_mp4toannexb");
300     }
301     if (avBitStreamFilter && !avbsfContext_) {
302         AVBSFContext* avbsfContext {nullptr};
303         (void)av_bsf_alloc(avBitStreamFilter, &avbsfContext);
304         (void)avcodec_parameters_copy(avbsfContext->par_in, avStream.codecpar);
305         av_bsf_init(avbsfContext);
306         avbsfContext_ = std::shared_ptr<AVBSFContext>(avbsfContext, [](AVBSFContext* ptr) {
307             if (ptr) {
308                 av_bsf_free(&ptr);
309             }
310         });
311     }
312     FALSE_LOG_MSG(avbsfContext_ != nullptr, "the av bit stream convert can't support, codec_tag: " PUBLIC_LOG_S,
313         codeTag);
314 }
315 
ConvertAvcOrHevcToAnnexb(AVPacket & pkt)316 void FFmpegDemuxerPlugin::ConvertAvcOrHevcToAnnexb(AVPacket& pkt)
317 {
318     (void)av_bsf_send_packet(avbsfContext_.get(), &pkt);
319     (void)av_packet_unref(&pkt);
320     (void)av_bsf_receive_packet(avbsfContext_.get(), &pkt);
321 }
322 
ReadFrame(Buffer & info,int32_t timeOutMs)323 Status FFmpegDemuxerPlugin::ReadFrame(Buffer& info, int32_t timeOutMs)
324 {
325     (void)timeOutMs;
326     AVPacket pkt;
327     int res = 0;
328     do {
329         res = av_read_frame(formatContext_.get(), &pkt);
330     } while (res >= 0 && !selectedTrackIds_.empty() && !IsSelectedTrack(pkt.stream_index));
331     Status result = Status::ERROR_UNKNOWN;
332     if (res == 0 && ConvertAVPacketToFrameInfo(*(formatContext_->streams[pkt.stream_index]), pkt, info)) {
333         result = Status::OK;
334     } else {
335         MEDIA_LOG_W("ReadFrame failed, rtv = " PUBLIC_LOG_S, AVStrError(res).c_str());
336     }
337     av_packet_unref(&pkt);
338     return (res != AVERROR_EOF) ? result : Status::END_OF_STREAM;
339 }
340 
341 /**
342  * SeekTo seek operation
343  * @param trackId  -1 for unspecified, >= 0 for specific trackid
344  * @param seekTime
345  * @param mode
346  * @param realSeekTime
347  * @return operation result.
348  */
SeekTo(int32_t trackId,int64_t seekTime,SeekMode mode,int64_t & realSeekTime)349 Status FFmpegDemuxerPlugin::SeekTo(int32_t trackId, int64_t seekTime, SeekMode mode, int64_t& realSeekTime)
350 {
351     if (trackId == -1) {
352         trackId = av_find_default_stream_index(formatContext_.get());
353     }
354     if (trackId < 0 || trackId >= static_cast<int32_t>(formatContext_->nb_streams)) {
355         MEDIA_LOG_E("SeekTo called with invalid trackid = " PUBLIC_LOG_D32 ", nb_streams = " PUBLIC_LOG_D32 ".",
356                     trackId, formatContext_->nb_streams);
357         return Status::ERROR_INVALID_PARAMETER;
358     }
359     FALSE_RETURN_V_MSG_E(seekModeToFfmpegSeekFlags.count(mode), Status::ERROR_INVALID_PARAMETER,
360                          "Unsupported seek mode: " PUBLIC_LOG_U32, static_cast<uint32_t>(mode));
361     int flags = seekModeToFfmpegSeekFlags.at(mode);
362     auto avStream = formatContext_->streams[trackId];
363     int64_t ffTime = ConvertTimeToFFmpeg(seekTime, avStream->time_base);
364     if (avStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
365         if (Plugin::HstTime2Ms(ConvertTimeFromFFmpeg(avStream->duration, avStream->time_base) - seekTime) <= 100 // 100
366             && mode == SeekMode::SEEK_NEXT_SYNC) {
367             flags = seekModeToFfmpegSeekFlags.at(SeekMode::SEEK_PREVIOUS_SYNC);
368         }
369         int keyFrameIdx = av_index_search_timestamp(avStream, ffTime, flags);
370         MEDIA_LOG_I("SeekTo " PUBLIC_LOG_D64 "ns, ffTime: " PUBLIC_LOG_D64 ", key frame index: "
371                     PUBLIC_LOG_D32, realSeekTime, ffTime, keyFrameIdx);
372         if (keyFrameIdx < 0) {
373             keyFrameIdx = av_index_search_timestamp(avStream, ffTime,
374                                                     seekModeToFfmpegSeekFlags.at(SeekMode::SEEK_PREVIOUS_SYNC));
375         }
376         if (keyFrameIdx >= 0) {
377 #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 78, 0)
378             ffTime = avformat_index_get_entry(avStream, keyFrameIdx)->timestamp;
379 #elif LIBAVFORMAT_VERSION_INT == AV_VERSION_INT(58, 76, 100)
380             ffTime = avStream->index_entries[keyFrameIdx].timestamp;
381 #elif LIBAVFORMAT_VERSION_INT > AV_VERSION_INT(58, 64, 100)
382             ffTime = avStream->internal->index_entries[keyFrameIdx].timestamp;
383 #else
384             ffTime = avStream->index_entries[keyFrameIdx].timestamp;
385 #endif
386             if (ffTime < 0) {
387                 ffTime = 0;
388             }
389         }
390     }
391     realSeekTime = ConvertTimeFromFFmpeg(ffTime, avStream->time_base);
392     MEDIA_LOG_I("SeekTo " PUBLIC_LOG_U64 " / " PUBLIC_LOG_D64, ffTime, realSeekTime);
393     auto rtv = av_seek_frame(formatContext_.get(), trackId, ffTime, flags);
394     MEDIA_LOG_I("Av seek finished, return value : " PUBLIC_LOG_D32, rtv);
395     return (rtv >= 0) ? Status::OK : Status::ERROR_UNKNOWN;
396 }
397 
InitAVFormatContext()398 void FFmpegDemuxerPlugin::InitAVFormatContext()
399 {
400     AVFormatContext* formatContext = avformat_alloc_context();
401     if (formatContext == nullptr) {
402         MEDIA_LOG_E("InitAVFormatContext  failed.");
403         return;
404     }
405     formatContext->pb = AllocAVIOContext(AVIO_FLAG_READ);
406     formatContext->flags = static_cast<uint32_t>(formatContext->flags) | static_cast<uint32_t>(AVFMT_FLAG_CUSTOM_IO);
407     int ret = avformat_open_input(&formatContext, nullptr, pluginImpl_.get(), nullptr);
408     if (ret == 0) {
409         formatContext_ = std::shared_ptr<AVFormatContext>(formatContext, [](AVFormatContext* ptr) {
410             if (ptr) {
411                 auto ctx = ptr->pb;
412                 if (ctx) {
413                     av_freep(&ctx->buffer);
414                     av_free(ctx);
415                 }
416                 avformat_close_input(&ptr);
417             }
418         });
419     } else {
420         MEDIA_LOG_E("avformat_open_input using plugin " PUBLIC_LOG_S " failed with return = " PUBLIC_LOG_S,
421                     pluginImpl_->name, AVStrError(ret).c_str());
422     }
423 }
424 
InitCodecContext(const AVStream & avStream)425 std::shared_ptr<AVCodecContext> FFmpegDemuxerPlugin::InitCodecContext(const AVStream& avStream)
426 {
427     auto codecContext = std::shared_ptr<AVCodecContext>(avcodec_alloc_context3(nullptr), [](AVCodecContext* p) {
428         if (p) {
429             avcodec_free_context(&p);
430         }
431     });
432     if (codecContext == nullptr) {
433         MEDIA_LOG_E("cannot create ffmpeg codecContext");
434         return nullptr;
435     }
436     int ret = avcodec_parameters_to_context(codecContext.get(), avStream.codecpar);
437     if (ret < 0) {
438         MEDIA_LOG_E("avcodec_parameters_to_context failed with return = " PUBLIC_LOG_S, AVStrError(ret).c_str());
439         return nullptr;
440     }
441     codecContext->workaround_bugs = static_cast<uint32_t>(codecContext->workaround_bugs) | FF_BUG_AUTODETECT;
442     codecContext->err_recognition = 1;
443     return codecContext;
444 }
445 
AllocAVIOContext(int flags)446 AVIOContext* FFmpegDemuxerPlugin::AllocAVIOContext(int flags)
447 {
448     constexpr int bufferSize = 4096;
449     auto buffer = static_cast<unsigned char*>(av_malloc(bufferSize));
450     if (buffer == nullptr) {
451         MEDIA_LOG_E("AllocAVIOContext failed to av_malloc...");
452         return nullptr;
453     }
454     AVIOContext* avioContext = avio_alloc_context(buffer, bufferSize, flags, static_cast<void*>(&ioContext_),
455                                                   AVReadPacket, AVWritePacket, AVSeek);
456     if (avioContext == nullptr) {
457         MEDIA_LOG_E("AllocAVIOContext failed to avio_alloc_context...");
458         av_free(buffer);
459         return nullptr;
460     }
461     MEDIA_LOG_D("seekable_ is " PUBLIC_LOG_D32, static_cast<int32_t>(seekable_));
462     avioContext->seekable = (seekable_ == Seekable::SEEKABLE) ? AVIO_SEEKABLE_NORMAL : 0;
463     if (!(static_cast<uint32_t>(flags) & static_cast<uint32_t>(AVIO_FLAG_WRITE))) {
464         avioContext->buf_ptr = avioContext->buf_end;
465         avioContext->write_flag = 0;
466     }
467     return avioContext;
468 }
469 
IsSelectedTrack(int32_t trackId)470 bool FFmpegDemuxerPlugin::IsSelectedTrack(int32_t trackId)
471 {
472     return std::any_of(selectedTrackIds_.begin(), selectedTrackIds_.end(),
473                        [trackId](int32_t id) { return id == trackId; });
474 }
475 
SaveFileInfoToMetaInfo(Meta & meta)476 void FFmpegDemuxerPlugin::SaveFileInfoToMetaInfo(Meta& meta)
477 {
478     meta.Clear();
479     AVDictionaryEntry* tag = nullptr;
480     while ((tag = av_dict_get(formatContext_->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
481         InsertMediaTag(meta, tag);
482     }
483     int64_t nanoSec = formatContext_->duration * (HST_SECOND / AV_TIME_BASE);
484     meta.Set<Tag::MEDIA_DURATION>(nanoSec);
485 }
486 
ParseMediaData()487 bool FFmpegDemuxerPlugin::ParseMediaData()
488 {
489     auto formatContext = formatContext_.get();
490     // retrieve stream information
491     auto ret = avformat_find_stream_info(formatContext, nullptr);
492     FALSE_RETURN_V_MSG_E(ret >= 0, false, "avformat_find_stream_info fail : " PUBLIC_LOG_S, AVStrError(ret).c_str());
493     av_dump_format(formatContext, 0, nullptr, false);
494 
495     CppExt::make_unique<MediaInfo>().swap(mediaInfo_);
496     size_t streamCnt = formatContext_->nb_streams;
497     mediaInfo_->general.Clear();
498     mediaInfo_->tracks.reserve(streamCnt);
499     for (size_t i = 0; i < streamCnt; ++i) {
500         auto& avStream = *formatContext_->streams[i];
501         auto codecContext = InitCodecContext(avStream);
502         if (!codecContext) {
503             continue;
504         }
505         Meta track;
506         if (avStream.codecpar->codec_type == AVMEDIA_TYPE_VIDEO
507             && avStream.codecpar->codec_id != AV_CODEC_ID_RAWVIDEO) {
508             if (!codecContext->width ||!codecContext->height) {
509                 continue;
510             }
511             if (avStream.codecpar->codec_id == AV_CODEC_ID_H264) {
512                 track.Set<Tag::VIDEO_BIT_STREAM_FORMAT>(
513                     std::vector<VideoBitStreamFormat>{VideoBitStreamFormat::AVC1, VideoBitStreamFormat::ANNEXB});
514             } else if (avStream.codecpar->codec_id == AV_CODEC_ID_H265) {
515                 track.Set<Tag::VIDEO_BIT_STREAM_FORMAT>(
516                     std::vector<VideoBitStreamFormat>{VideoBitStreamFormat::HEVC, VideoBitStreamFormat::ANNEXB});
517             }
518         }
519         ConvertAVStreamToMetaInfo(avStream, formatContext_, codecContext, track);
520         if (g_MediaTypeMap.find(avStream.codecpar->codec_type) != g_MediaTypeMap.end()) {
521             track.Set<Tag::MEDIA_TYPE>(g_MediaTypeMap[avStream.codecpar->codec_type]);
522         } else {
523             MEDIA_LOG_E("media type not found!");
524         }
525         mediaInfo_->tracks.push_back(std::move(track));
526     }
527     SaveFileInfoToMetaInfo(mediaInfo_->general);
528     return true;
529 }
530 
531 // ffmpeg provide buf, we write data
AVReadPacket(void * opaque,uint8_t * buf,int bufSize)532 int FFmpegDemuxerPlugin::AVReadPacket(void* opaque, uint8_t* buf, int bufSize) // NOLINT
533 {
534     int rtv = -1;
535     auto ioContext = static_cast<IOContext*>(opaque);
536     if (ioContext && ioContext->dataSource) {
537         auto buffer = std::make_shared<Buffer>();
538         auto bufData = buffer->WrapMemory(buf, bufSize, 0);
539         auto result = ioContext->dataSource->ReadAt(ioContext->offset, buffer, static_cast<size_t>(bufSize));
540         MEDIA_LOG_DD("AVReadPacket read data size = " PUBLIC_LOG_D32, static_cast<int>(bufData->GetSize()));
541         if (result == Status::OK) {
542             auto bufferMem = buffer->GetMemory();
543             if (bufferMem == nullptr) {
544                 MEDIA_LOG_E("AVReadPacket buffer GetMemory nullptr");
545                 return -1;
546             }
547             ioContext->offset += static_cast<int64_t>(bufferMem->GetSize());
548             rtv = static_cast<int>(bufferMem->GetSize());
549         } else if (result == Status::END_OF_STREAM) {
550             ioContext->eos = true;
551             rtv = AVERROR_EOF;
552         } else {
553             MEDIA_LOG_E("AVReadPacket failed with rtv = " PUBLIC_LOG_D32, static_cast<int>(result));
554         }
555     }
556     return rtv;
557 }
558 
559 /**
560  * write packet unimplemented.
561  * @return 0
562  */
AVWritePacket(void * opaque,uint8_t * buf,int bufSize)563 int FFmpegDemuxerPlugin::AVWritePacket(void* opaque, uint8_t* buf, int bufSize) // NOLINT: intentionally using void*
564 {
565     (void)opaque;
566     (void)buf;
567     (void)bufSize;
568     return 0;
569 }
570 
AVSeek(void * opaque,int64_t offset,int whence)571 int64_t FFmpegDemuxerPlugin::AVSeek(void* opaque, int64_t offset, int whence) // NOLINT: void*
572 {
573     auto ioContext = static_cast<IOContext*>(opaque);
574     uint64_t newPos = 0;
575     switch (whence) {
576         case SEEK_SET:
577             newPos = static_cast<uint64_t>(offset);
578             ioContext->offset = newPos;
579             MEDIA_LOG_DD("AVSeek whence: " PUBLIC_LOG_D32 ", pos = " PUBLIC_LOG_D64 ", newPos = " PUBLIC_LOG
580                          PRIu64, whence, offset, newPos);
581             break;
582         case SEEK_CUR:
583             newPos = ioContext->offset + offset;
584             MEDIA_LOG_DD("AVSeek whence: " PUBLIC_LOG_D32 ", pos = " PUBLIC_LOG_D64 ", newPos = " PUBLIC_LOG
585                          PRIu64, whence, offset, newPos);
586             break;
587         case SEEK_END:
588         case AVSEEK_SIZE: {
589             uint64_t mediaDataSize = 0;
590             if (ioContext->dataSource->GetSize(mediaDataSize) == Status::OK) {
591                 newPos = mediaDataSize + offset;
592                 MEDIA_LOG_I("AVSeek seek end whence: " PUBLIC_LOG_D32 ", pos = " PUBLIC_LOG_D64,
593                             whence, offset);
594             }
595             break;
596         }
597         default:
598             MEDIA_LOG_E("AVSeek unexpected whence: " PUBLIC_LOG_D32, whence);
599             break;
600     }
601     if (whence != AVSEEK_SIZE) {
602         ioContext->offset = newPos;
603     }
604     MEDIA_LOG_DD("current offset: " PUBLIC_LOG_D64 ", new pos: " PUBLIC_LOG_U64,
605                  ioContext->offset, newPos);
606     return newPos;
607 }
608 
609 namespace {
Sniff(const std::string & pluginName,std::shared_ptr<DataSource> dataSource)610 int Sniff(const std::string& pluginName, std::shared_ptr<DataSource> dataSource)
611 {
612     if (pluginName.empty() || !dataSource) {
613         MEDIA_LOG_E("Sniff failed due to empty plugin name or dataSource invalid.");
614         return 0;
615     }
616     auto plugin = g_pluginInputFormat[pluginName];
617     if (!plugin || !plugin->read_probe) {
618         MEDIA_LOG_DD("Sniff failed due to invalid plugin for " PUBLIC_LOG_S ".", pluginName.c_str());
619         return 0;
620     }
621     size_t bufferSize = 4096;
622     uint64_t fileSize = 0;
623     if (dataSource->GetSize(fileSize) == Status::OK) {
624         bufferSize = (bufferSize < fileSize) ? bufferSize : fileSize;
625     }
626     std::vector<uint8_t> buff(bufferSize);
627     auto bufferInfo = std::make_shared<Buffer>();
628     auto bufData = bufferInfo->WrapMemory(buff.data(), bufferSize, bufferSize);
629     int confidence = 0;
630     if (bufData && dataSource->ReadAt(0, bufferInfo, bufferSize) == Status::OK) {
631         auto bufferInfoMem = bufferInfo->GetMemory();
632         if (bufferInfoMem == nullptr) {
633             MEDIA_LOG_E("Sniff failed due to bufferInfo GetMemory nullptr");
634             return 0;
635         }
636         AVProbeData probeData{"", buff.data(), static_cast<int>(bufferInfoMem->GetSize()), ""};
637         confidence = plugin->read_probe(&probeData);
638     }
639     if (confidence > 0) {
640         MEDIA_LOG_I("Sniff: plugin pluginName = " PUBLIC_LOG_S ", probability = " PUBLIC_LOG_D32 " / 100 ...",
641                     plugin->name, confidence);
642     }
643     return confidence;
644 }
645 
IsInputFormatSupported(const char * name)646 bool IsInputFormatSupported(const char* name)
647 {
648     if (!strcmp(name, "audio_device") || !strncmp(name, "image", 5) ||                 // 5
649         !strcmp(name, "mjpeg") || !strcmp(name, "redir") || !strncmp(name, "u8", 2) || // 2
650         !strncmp(name, "u16", 3) || !strncmp(name, "u24", 3) ||                        // 3
651         !strncmp(name, "u32", 3) ||                                                    // 3
652         !strncmp(name, "s8", 2) || !strncmp(name, "s16", 3) ||                         // 2 3
653         !strncmp(name, "s24", 3) ||                                                    // 3
654         !strncmp(name, "s32", 3) || !strncmp(name, "f32", 3) ||                        // 3
655         !strncmp(name, "f64", 3) ||                                                    // 3
656         !strcmp(name, "mulaw") || !strcmp(name, "alaw")) {
657         return false;
658     }
659 
660     /* no network demuxers */
661     if (!strcmp(name, "sdp") || !strcmp(name, "rtsp") || !strcmp(name, "applehttp")) {
662         return false;
663     }
664     return true;
665 }
666 
RegisterPlugins(const std::shared_ptr<Register> & reg)667 Status RegisterPlugins(const std::shared_ptr<Register>& reg)
668 {
669     MEDIA_LOG_D("RegisterPlugins called.");
670     if (!reg) {
671         MEDIA_LOG_E("RegisterPlugins failed due to null pointer for reg.");
672         return Status::ERROR_INVALID_PARAMETER;
673     }
674     const AVInputFormat* plugin = nullptr;
675     void* i = nullptr;
676     while ((plugin = av_demuxer_iterate(&i))) {
677         MEDIA_LOG_DD("Attempting to handle libav demuxer plugin " PUBLIC_LOG_S " [" PUBLIC_LOG_S "]",
678                      plugin->name, plugin->long_name);
679         /* no emulators */
680         if (plugin->long_name != nullptr) {
681             if (!strncmp(plugin->long_name, "pcm ", 4)) { // 4
682                 continue;
683             }
684         }
685 
686         if (!IsInputFormatSupported(plugin->name)) {
687             continue;
688         }
689 
690         std::string pluginName = "avdemux_" + std::string(plugin->name);
691         ReplaceDelimiter(".,|-<> ", '_', pluginName);
692 
693         DemuxerPluginDef regInfo;
694         regInfo.name = pluginName;
695         regInfo.description = "adapter for ffmpeg demuxer plugin";
696         regInfo.rank = 100; // 100
697         SplitString(plugin->extensions, ',').swap(regInfo.extensions);
698         g_pluginInputFormat[pluginName] =
699             std::shared_ptr<AVInputFormat>(const_cast<AVInputFormat*>(plugin), [](void*) {});
700         regInfo.creator = [](const std::string& name) -> std::shared_ptr<DemuxerPlugin> {
701             return std::make_shared<FFmpegDemuxerPlugin>(name);
702         };
703         regInfo.sniffer = Sniff;
704         auto rtv = reg->AddPlugin(regInfo);
705         if (rtv != Status::OK) {
706             MEDIA_LOG_E("RegisterPlugins AddPlugin failed with return " PUBLIC_LOG_D32, static_cast<int>(rtv));
707         }
708     }
709     return Status::OK;
710 }
711 
712 #if FFMPEG_LOG_DEBUG_ENABLE
713 #ifdef MEDIA_OHOS
FfmpegLogPrint(void * avcl,int level,const char * fmt,va_list vl)714 void FfmpegLogPrint(void* avcl, int level, const char* fmt, va_list vl)
715 {
716     (void)avcl;
717     switch (level) {
718         case AV_LOG_INFO:
719         case AV_LOG_DEBUG:
720             HILOG_DEBUG(LOG_CORE, fmt, vl);
721             break;
722         case AV_LOG_WARNING:
723             HILOG_WARN(LOG_CORE, fmt, vl);
724             break;
725         case AV_LOG_ERROR:
726             HILOG_ERROR(LOG_CORE, fmt, vl);
727             break;
728         case AV_LOG_FATAL:
729             HILOG_FATAL(LOG_CORE, fmt, vl);
730             break;
731     }
732 }
733 #else
FfmpegLogPrint(void * avcl,int level,const char * fmt,va_list vl)734 void FfmpegLogPrint(void* avcl, int level, const char* fmt, va_list vl)
735 {
736     (void)avcl;
737     char buf[500] = {0};  // 500
738     (void)vsnprintf_s(buf, sizeof(buf), fmt, vl);
739     switch (level) {
740         case AV_LOG_WARNING:
741             MEDIA_LOG_W("Ffmpeg Message %d %s", level, buf);
742             break;
743         case AV_LOG_ERROR:
744         case AV_LOG_FATAL:
745             MEDIA_LOG_E("Ffmpeg Message %d %s", level, buf);
746             break;
747         case AV_LOG_INFO:
748         case AV_LOG_DEBUG:
749             MEDIA_LOG_DD("Ffmpeg Message %d %s", level, buf);
750             break;
751         default:
752             break;
753     }
754 }
755 #endif
756 #endif
757 
FfmpegLogInit()758 static void FfmpegLogInit()
759 {
760 #if FFMPEG_LOG_DEBUG_ENABLE
761     av_log_set_callback(FfmpegLogPrint);
762 #endif
763 }
764 } // namespace
765 
__anond0b22ad40b02null766 PLUGIN_DEFINITION(FFmpegDemuxer, LicenseType::LGPL, RegisterPlugins, [] { g_pluginInputFormat.clear(); });
767 } // namespace Ffmpeg
768 } // namespace Plugin
769 } // namespace Media
770 } // namespace OHOS
771