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