• 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 #include "ffmpeg_demuxer_plugin.h"
20 #include <algorithm>
21 #include <cstdio>
22 #include <cstring>
23 #include <new>
24 #include "ffmpeg_track_meta.h"
25 #include "foundation/log.h"
26 #include "osal/thread/scoped_lock.h"
27 #include "plugin/common/plugin_buffer.h"
28 #include "plugin/common/plugin_time.h"
29 #include "plugin/core/plugin_manager.h"
30 #include "plugins/ffmpeg_adapter/utils/ffmpeg_utils.h"
31 #include "utils/memory_helper.h"
32 
33 #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT(58, 78, 0) and LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 64, 100)
34 #include "libavformat/internal.h"
35 #endif
36 
37 namespace OHOS {
38 namespace Media {
39 namespace Plugin {
40 namespace Ffmpeg {
41 namespace {
42 std::map<std::string, std::shared_ptr<AVInputFormat>> g_pluginInputFormat;
43 
44 int Sniff(const std::string& pluginName, std::shared_ptr<DataSource> dataSource);
45 
46 Status RegisterPlugins(const std::shared_ptr<Register>& reg);
47 
48 int ConvertSeekModeToFFmpeg(SeekMode mode);
49 } // namespace
50 
Alloc(size_t size)51 void* FFmpegDemuxerPlugin::DemuxerPluginAllocator::Alloc(size_t size)
52 {
53     if (size == 0) {
54         return nullptr;
55     }
56     return static_cast<void*>(new (std::nothrow) uint8_t[size]);
57 }
58 
Free(void * ptr)59 void FFmpegDemuxerPlugin::DemuxerPluginAllocator::Free(void* ptr) // NOLINT: void*
60 {
61     if (ptr) {
62         auto data = static_cast<uint8_t*>(ptr);
63         delete[] data;
64     }
65 }
66 
FFmpegDemuxerPlugin(std::string name)67 FFmpegDemuxerPlugin::FFmpegDemuxerPlugin(std::string name)
68     : DemuxerPlugin(std::move(name)),
69       ioContext_(),
70       callback_(nullptr),
71       pluginImpl_(nullptr),
72       formatContext_(nullptr),
73       allocator_(std::make_shared<DemuxerPluginAllocator>()),
74       mediaInfo_(nullptr),
75       selectedTrackIds_()
76 {
77     MEDIA_LOG_I("ctor called, plugin name: %" PUBLIC_LOG "s", pluginName_.c_str());
78 }
79 
~FFmpegDemuxerPlugin()80 FFmpegDemuxerPlugin::~FFmpegDemuxerPlugin()
81 {
82     MEDIA_LOG_D("dtor called.");
83     pluginImpl_ = nullptr;
84 }
85 
Init()86 Status FFmpegDemuxerPlugin::Init()
87 {
88     MEDIA_LOG_D("Init called.");
89     Reset();
90     pluginImpl_ = g_pluginInputFormat[pluginName_];
91 
92     return pluginImpl_ ? Status::OK : Status::ERROR_UNSUPPORTED_FORMAT;
93 }
94 
Deinit()95 Status FFmpegDemuxerPlugin::Deinit()
96 {
97     return Status::OK;
98 }
99 
Prepare()100 Status FFmpegDemuxerPlugin::Prepare()
101 {
102     InitAVFormatContext();
103     if (formatContext_ == nullptr) {
104         MEDIA_LOG_E("prepare failed due to formatContext init error");
105         return Status::ERROR_UNKNOWN;
106     }
107     return Status::OK;
108 }
109 
Reset()110 Status FFmpegDemuxerPlugin::Reset()
111 {
112     mediaInfo_.reset();
113     ioContext_.offset = 0;
114     ioContext_.eos = false;
115     selectedTrackIds_.clear();
116     return Status::OK;
117 }
118 
Start()119 Status FFmpegDemuxerPlugin::Start()
120 {
121     return Status::OK;
122 }
123 
Stop()124 Status FFmpegDemuxerPlugin::Stop()
125 {
126     return Status::OK;
127 }
128 
129 /**
130  * IsParameterSupported no need supported by demuxer
131  * @return return false always.
132  */
IsParameterSupported(Tag tag)133 bool FFmpegDemuxerPlugin::IsParameterSupported(Tag tag)
134 {
135     (void)tag;
136     return false;
137 }
138 
139 /**
140  * GetParameter no need supported by demuxer
141  * @return return ERROR_UNIMPLEMENTED always.
142  */
GetParameter(Tag tag,ValueType & value)143 Status FFmpegDemuxerPlugin::GetParameter(Tag tag, ValueType& value)
144 {
145     (void)tag;
146     (void)value;
147     return Status::ERROR_UNIMPLEMENTED;
148 }
149 
150 /**
151  * SetParameter no need supported by demuxer
152  * @return return ERROR_UNIMPLEMENTED always.
153  */
SetParameter(Tag tag,const ValueType & value)154 Status FFmpegDemuxerPlugin::SetParameter(Tag tag, const ValueType& value)
155 {
156     (void)tag;
157     (void)value;
158     return Status::ERROR_UNIMPLEMENTED;
159 }
160 
GetAllocator()161 std::shared_ptr<Allocator> FFmpegDemuxerPlugin::GetAllocator()
162 {
163     return allocator_;
164 }
165 
SetCallback(Callback * cb)166 Status FFmpegDemuxerPlugin::SetCallback(Callback* cb)
167 {
168     callback_ = cb;
169     return Status::OK;
170 }
171 
SetDataSource(const std::shared_ptr<DataSource> & source)172 Status FFmpegDemuxerPlugin::SetDataSource(const std::shared_ptr<DataSource>& source)
173 {
174     ioContext_.dataSource = source;
175     return Status::OK;
176 }
177 
GetMediaInfo(MediaInfo & mediaInfo)178 Status FFmpegDemuxerPlugin::GetMediaInfo(MediaInfo& mediaInfo)
179 {
180     if (!mediaInfo_ && !ParseMediaData()) {
181         return Status::ERROR_WRONG_STATE;
182     }
183     mediaInfo = *mediaInfo_;
184     return Status::OK;
185 }
186 
GetTrackCount()187 size_t FFmpegDemuxerPlugin::GetTrackCount()
188 {
189     size_t trackCnt = 0;
190     if (mediaInfo_) {
191         trackCnt = mediaInfo_->tracks.size();
192     }
193     return trackCnt;
194 }
195 
SelectTrack(int32_t trackId)196 Status FFmpegDemuxerPlugin::SelectTrack(int32_t trackId)
197 {
198     if (!mediaInfo_) {
199         MEDIA_LOG_E("SelectTrack called before GetMediaInfo()...");
200         return Status::ERROR_WRONG_STATE;
201     }
202     if (trackId < 0 || trackId >= static_cast<int32_t>(mediaInfo_->tracks.size())) {
203         MEDIA_LOG_E("SelectTrack called with invalid trackId: %" PUBLIC_LOG "d, number of tracks: %" PUBLIC_LOG
204                     "d", trackId, static_cast<int>(mediaInfo_->tracks.size()));
205         return Status::ERROR_INVALID_PARAMETER;
206     }
207     OSAL::ScopedLock lock(mutex_);
208     auto it = std::find_if(selectedTrackIds_.begin(), selectedTrackIds_.end(),
209                            [trackId](int32_t streamId) { return trackId == streamId; });
210     if (it == selectedTrackIds_.end()) {
211         selectedTrackIds_.push_back(trackId);
212     }
213     return Status::OK;
214 }
215 
UnselectTrack(int32_t trackId)216 Status FFmpegDemuxerPlugin::UnselectTrack(int32_t trackId)
217 {
218     OSAL::ScopedLock lock(mutex_);
219     auto it = std::find_if(selectedTrackIds_.begin(), selectedTrackIds_.end(),
220                            [trackId](int32_t streamId) { return trackId == streamId; });
221     if (it != selectedTrackIds_.end()) {
222         selectedTrackIds_.erase(it);
223     }
224     return Status::OK;
225 }
226 
GetSelectedTracks(std::vector<int32_t> & trackIds)227 Status FFmpegDemuxerPlugin::GetSelectedTracks(std::vector<int32_t>& trackIds)
228 {
229     OSAL::ScopedLock lock(mutex_);
230     trackIds = selectedTrackIds_;
231     return Status::OK;
232 }
233 
ConvertAVPacketToFrameInfo(const AVStream & avStream,const AVPacket & pkt,Buffer & frameInfo)234 bool FFmpegDemuxerPlugin::ConvertAVPacketToFrameInfo(const AVStream& avStream, const AVPacket& pkt, Buffer& frameInfo)
235 {
236     frameInfo.trackID = static_cast<uint32_t>(pkt.stream_index);
237     int64_t pts = (pkt.pts > 0) ? pkt.pts : 0;
238     frameInfo.pts = ConvertTimeFromFFmpeg(pts, avStream.time_base);
239     frameInfo.dts = static_cast<uint32_t>(pkt.dts);
240     frameInfo.duration = ConvertTimeFromFFmpeg(pkt.duration, avStream.time_base);
241     frameInfo.GetBufferMeta()->SetMeta(Tag::MEDIA_POSITION, static_cast<uint32_t>(pkt.pos));
242 
243     int frameSize = 0;
244     if (avStream.codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
245         frameSize = pkt.size;
246     } else if (avStream.codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
247         if (avStream.codecpar->codec_id == AV_CODEC_ID_RAWVIDEO) {
248             MEDIA_LOG_W("unsupport raw video");
249             return false;
250         }
251         frameSize = pkt.size;
252     } else {
253         MEDIA_LOG_W("unsupported codec type: %" PUBLIC_LOG "d", static_cast<int32_t>(avStream.codecpar->codec_type));
254         return false;
255     }
256     auto data = frameInfo.AllocMemory(allocator_, frameSize);
257     if (data) {
258         size_t writeSize = data->Write(pkt.data, frameSize);
259         ASSERT_CONDITION(writeSize == frameSize, "Copy data failed.");
260     }
261     return data != nullptr;
262 }
263 
ReadFrame(Buffer & info,int32_t timeOutMs)264 Status FFmpegDemuxerPlugin::ReadFrame(Buffer& info, int32_t timeOutMs)
265 {
266     (void)timeOutMs;
267     AVPacket pkt;
268     int res = 0;
269     do {
270         res = av_read_frame(formatContext_.get(), &pkt);
271     } while (res >= 0 && !selectedTrackIds_.empty() && !IsSelectedTrack(pkt.stream_index));
272     Status result = Status::ERROR_UNKNOWN;
273     if (res == 0 && ConvertAVPacketToFrameInfo(*(formatContext_->streams[pkt.stream_index]), pkt, info)) {
274         result = Status::OK;
275     } else {
276         MEDIA_LOG_W("ReadFrame failed, rtv = %" PUBLIC_LOG "s", AVStrError(res).c_str());
277     }
278     av_packet_unref(&pkt);
279     return (res != AVERROR_EOF) ? result : Status::END_OF_STREAM;
280 }
281 
282 /**
283  * SeekTo seek operation
284  * @param trackId  -1 for unspecified, >= 0 for specific trackid
285  * @param hstTime
286  * @param mode
287  * @return operation result.
288  */
SeekTo(int32_t trackId,int64_t hstTime,SeekMode mode)289 Status FFmpegDemuxerPlugin::SeekTo(int32_t trackId, int64_t hstTime, SeekMode mode)
290 {
291     if (trackId == -1) {
292         trackId = av_find_default_stream_index(formatContext_.get());
293     }
294     if (trackId < 0 || trackId >= static_cast<int32_t>(formatContext_->nb_streams)) {
295         MEDIA_LOG_E("SeekTo called with invalid trackid = %" PUBLIC_LOG "d, nb_streams = %" PUBLIC_LOG "d.",
296                     trackId, formatContext_->nb_streams);
297         return Status::ERROR_INVALID_PARAMETER;
298     }
299     auto avStream = formatContext_->streams[trackId];
300     int64_t ffTime = ConvertTimeToFFmpeg(hstTime, avStream->time_base);
301     if (avStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
302         int keyFrameIdx = av_index_search_timestamp(avStream, ffTime, ConvertSeekModeToFFmpeg(mode));
303         MEDIA_LOG_I("SeekTo %" PUBLIC_LOG PRId64 "ns, ffTime: %" PUBLIC_LOG PRId64 ", key frame index: %"
304                     PUBLIC_LOG "d", hstTime, ffTime, keyFrameIdx);
305         if (keyFrameIdx >= 0) {
306 #if LIBAVFORMAT_VERSION_INT >= AV_VERSION_INT(58, 78, 0)
307             ffTime = avformat_index_get_entry(avStream, keyFrameIdx)->timestamp;
308 #elif LIBAVFORMAT_VERSION_INT > AV_VERSION_INT(58, 64, 100)
309             ffTime = avStream->internal->index_entries[keyFrameIdx].timestamp;
310 #else
311             ffTime = avStream->index_entries[keyFrameIdx].timestamp;
312 #endif
313         }
314     }
315     auto newTime = ConvertTimeFromFFmpeg(ffTime, avStream->time_base);
316     MEDIA_LOG_I("SeekTo %" PUBLIC_LOG PRIu64 " / %" PUBLIC_LOG PRId64 ", ffTime: %" PUBLIC_LOG PRId64,
317                 newTime, hstTime, ffTime);
318     auto rtv = av_seek_frame(formatContext_.get(), trackId, ffTime, ConvertSeekModeToFFmpeg(mode));
319     if (rtv < 0) {
320         MEDIA_LOG_E("seek failed, return value: %" PUBLIC_LOG "d", rtv);
321     }
322     return (rtv >= 0) ? Status::OK : Status::ERROR_UNKNOWN;
323 }
324 
InitAVFormatContext()325 void FFmpegDemuxerPlugin::InitAVFormatContext()
326 {
327     AVFormatContext* formatContext = avformat_alloc_context();
328     if (formatContext == nullptr) {
329         return;
330     }
331     formatContext->pb = AllocAVIOContext(AVIO_FLAG_READ);
332     formatContext->flags = static_cast<uint32_t>(formatContext->flags) | static_cast<uint32_t>(AVFMT_FLAG_CUSTOM_IO);
333     formatContext_ = std::shared_ptr<AVFormatContext>(formatContext, [](AVFormatContext* ptr) {
334         if (ptr) {
335             auto ctx = ptr->pb;
336             if (ctx) {
337                 av_freep(&ctx->buffer);
338                 av_free(ctx);
339             }
340             avformat_close_input(&ptr);
341         }
342     });
343 }
344 
InitCodecContext(const AVStream & avStream)345 std::shared_ptr<AVCodecContext> FFmpegDemuxerPlugin::InitCodecContext(const AVStream& avStream)
346 {
347     auto codecContext = std::shared_ptr<AVCodecContext>(avcodec_alloc_context3(nullptr), [](AVCodecContext* p) {
348         if (p) {
349             avcodec_free_context(&p);
350         }
351     });
352     if (codecContext == nullptr) {
353         MEDIA_LOG_E("cannot create ffmpeg codecContext");
354         return nullptr;
355     }
356     int ret = avcodec_parameters_to_context(codecContext.get(), avStream.codecpar);
357     if (ret < 0) {
358         MEDIA_LOG_E("avcodec_parameters_to_context failed with return = %" PUBLIC_LOG "s", AVStrError(ret).c_str());
359         return nullptr;
360     }
361     codecContext->workaround_bugs = static_cast<uint32_t>(codecContext->workaround_bugs) | FF_BUG_AUTODETECT;
362     codecContext->err_recognition = 1;
363     return codecContext;
364 }
365 
AllocAVIOContext(int flags)366 AVIOContext* FFmpegDemuxerPlugin::AllocAVIOContext(int flags)
367 {
368     constexpr int bufferSize = 4096;
369     auto buffer = static_cast<unsigned char*>(av_malloc(bufferSize));
370     if (buffer == nullptr) {
371         MEDIA_LOG_E("AllocAVIOContext failed to av_malloc...");
372         return nullptr;
373     }
374     AVIOContext* avioContext = avio_alloc_context(buffer, bufferSize, flags, static_cast<void*>(&ioContext_),
375                                                   AVReadPacket, AVWritePacket, AVSeek);
376     if (avioContext == nullptr) {
377         MEDIA_LOG_E("AllocAVIOContext failed to avio_alloc_context...");
378         av_free(buffer);
379         return nullptr;
380     }
381     avioContext->seekable = AVIO_SEEKABLE_NORMAL;
382     if (!(static_cast<uint32_t>(flags) & static_cast<uint32_t>(AVIO_FLAG_WRITE))) {
383         avioContext->buf_ptr = avioContext->buf_end;
384         avioContext->write_flag = 0;
385     }
386     return avioContext;
387 }
388 
IsSelectedTrack(int32_t trackId)389 bool FFmpegDemuxerPlugin::IsSelectedTrack(int32_t trackId)
390 {
391     return std::any_of(selectedTrackIds_.begin(), selectedTrackIds_.end(),
392                        [trackId](int32_t id) { return id == trackId; });
393 }
394 
SaveFileInfoToMetaInfo(TagMap & meta)395 void FFmpegDemuxerPlugin::SaveFileInfoToMetaInfo(TagMap& meta)
396 {
397     meta.clear();
398     AVDictionaryEntry* tag = nullptr;
399     while ((tag = av_dict_get(formatContext_->metadata, "", tag, AV_DICT_IGNORE_SUFFIX))) {
400         Tag target;
401         auto found = FindTagByAvMetaName(tag->key, target);
402         if (!found) {
403             continue;
404         }
405         if (target != Media::Plugin::Tag::MEDIA_DATE) {
406             meta.insert({target, std::string(tag->value)});
407         } else {
408             uint32_t year = 0;
409             uint32_t month = 0;
410             uint32_t day = 0;
411             if (sscanf_s(tag->value, "%04u-%02u-%02u", &year, &month, &day) == 3) { // 3
412                 meta.insert({Tag::MEDIA_DATE, RemoveDelimiter(tag->value, '-')});
413             }
414         }
415     }
416     int64_t nanoSec = formatContext_->duration * (HST_SECOND / AV_TIME_BASE);
417     meta.insert({Tag::MEDIA_DURATION, static_cast<uint64_t>(nanoSec)});
418 }
419 
ParseMediaData()420 bool FFmpegDemuxerPlugin::ParseMediaData()
421 {
422     auto formatContext = formatContext_.get();
423     int ret = avformat_open_input(&formatContext, nullptr, pluginImpl_.get(), nullptr);
424     if (ret != 0) {
425         MEDIA_LOG_E("avformat_open_input using plugin %" PUBLIC_LOG "s failed with return = %" PUBLIC_LOG "s",
426                     pluginImpl_->name, AVStrError(ret).c_str());
427         return false;
428     }
429     // retrieve stream information
430     avformat_find_stream_info(formatContext, nullptr);
431     av_dump_format(formatContext, 0, nullptr, false);
432 
433     MemoryHelper::make_unique<MediaInfo>().swap(mediaInfo_);
434     size_t streamCnt = formatContext_->nb_streams;
435     mediaInfo_->general.clear();
436     mediaInfo_->tracks.resize(streamCnt);
437     for (size_t i = 0; i < streamCnt; ++i) {
438         auto& avStream = *formatContext_->streams[i];
439         auto codecContext = InitCodecContext(avStream);
440         if (codecContext == nullptr) {
441             continue;
442         }
443         ConvertAVStreamToMetaInfo(avStream, codecContext, mediaInfo_->tracks[i]);
444     }
445     SaveFileInfoToMetaInfo(mediaInfo_->general);
446     return true;
447 }
448 
449 // ffmpeg provide buf, we write data
AVReadPacket(void * opaque,uint8_t * buf,int bufSize)450 int FFmpegDemuxerPlugin::AVReadPacket(void* opaque, uint8_t* buf, int bufSize) // NOLINT
451 {
452     int rtv = -1;
453     auto ioContext = static_cast<IOContext*>(opaque);
454     if (ioContext && ioContext->dataSource) {
455         auto buffer = std::make_shared<Buffer>();
456         auto bufData = buffer->WrapMemory(buf, bufSize, bufSize);
457         auto result = ioContext->dataSource->ReadAt(ioContext->offset, buffer, static_cast<size_t>(bufSize));
458         MEDIA_LOG_D("AVReadPacket read data size = %" PUBLIC_LOG "d", static_cast<int>(bufData->GetSize()));
459         if (result == Status::OK) {
460             ioContext->offset += buffer->GetMemory()->GetSize();
461             rtv = buffer->GetMemory()->GetSize();
462         } else if (result == Status::END_OF_STREAM) {
463             ioContext->eos = true;
464             rtv = AVERROR_EOF;
465         } else {
466             MEDIA_LOG_E("AVReadPacket failed with rtv = %" PUBLIC_LOG "d", static_cast<int>(result));
467         }
468     }
469     return rtv;
470 }
471 
472 /**
473  * write packet unimplemented.
474  * @return 0
475  */
AVWritePacket(void * opaque,uint8_t * buf,int bufSize)476 int FFmpegDemuxerPlugin::AVWritePacket(void* opaque, uint8_t* buf, int bufSize) // NOLINT: intentionally using void*
477 {
478     (void)opaque;
479     (void)buf;
480     (void)bufSize;
481     return 0;
482 }
483 
AVSeek(void * opaque,int64_t offset,int whence)484 int64_t FFmpegDemuxerPlugin::AVSeek(void* opaque, int64_t offset, int whence) // NOLINT: void*
485 {
486     auto ioContext = static_cast<IOContext*>(opaque);
487     uint64_t newPos = 0;
488     switch (whence) {
489         case SEEK_SET:
490             newPos = static_cast<uint64_t>(offset);
491             ioContext->offset = newPos;
492             MEDIA_LOG_I("AVSeek whence: %" PUBLIC_LOG "d, pos = %" PUBLIC_LOG PRId64 ", newPos = %" PUBLIC_LOG
493                         PRIu64, whence, offset, newPos);
494             break;
495         case SEEK_CUR:
496             newPos = ioContext->offset + offset;
497             MEDIA_LOG_I("AVSeek whence: %" PUBLIC_LOG "d, pos = %" PUBLIC_LOG PRId64 ", newPos = %" PUBLIC_LOG
498                         PRIu64, whence, offset, newPos);
499             break;
500         case SEEK_END:
501         case AVSEEK_SIZE: {
502             size_t mediaDataSize = 0;
503             if (ioContext->dataSource->GetSize(mediaDataSize) == Status::OK) {
504                 newPos = mediaDataSize + offset;
505                 MEDIA_LOG_I("AVSeek seek end whence: %" PUBLIC_LOG "d, pos = %" PUBLIC_LOG PRId64,
506                             whence, offset);
507             }
508             break;
509         }
510         default:
511             MEDIA_LOG_E("AVSeek unexpected whence: %" PUBLIC_LOG "d", whence);
512             break;
513     }
514     if (whence != AVSEEK_SIZE) {
515         ioContext->offset = newPos;
516     }
517     MEDIA_LOG_I("current offset: %" PUBLIC_LOG PRId64 ", new pos: %" PUBLIC_LOG PRIu64,
518                 ioContext->offset, newPos);
519     return newPos;
520 }
521 
522 namespace {
ConvertSeekModeToFFmpeg(SeekMode mode)523 int ConvertSeekModeToFFmpeg(SeekMode mode)
524 {
525     int seekFlag = AVSEEK_FLAG_BACKWARD;
526     switch (mode) {
527         case SeekMode::BACKWARD:
528             seekFlag = AVSEEK_FLAG_BACKWARD;
529             break;
530         case SeekMode::FORWARD:
531             seekFlag = 0;
532             break;
533         case SeekMode::FRAME:
534             seekFlag = AVSEEK_FLAG_FRAME;
535             break;
536         case SeekMode::ANY:
537             seekFlag = AVSEEK_FLAG_ANY;
538             break;
539         default:
540             MEDIA_LOG_W("unsupported seekmode: %" PUBLIC_LOG "d, using backward mode instead.",
541                         static_cast<int>(mode));
542             break;
543     }
544     return seekFlag;
545 }
546 
Sniff(const std::string & pluginName,std::shared_ptr<DataSource> dataSource)547 int Sniff(const std::string& pluginName, std::shared_ptr<DataSource> dataSource)
548 {
549     if (pluginName.empty() || !dataSource) {
550         MEDIA_LOG_E("Sniff failed due to empty plugin name or dataSource invalid.");
551         return 0;
552     }
553     auto plugin = g_pluginInputFormat[pluginName];
554     if (!plugin || !plugin->read_probe) {
555         MEDIA_LOG_D("Sniff failed due to invalid plugin for %" PUBLIC_LOG "s.", pluginName.c_str());
556         return 0;
557     }
558     size_t bufferSize = 4096;
559     size_t fileSize = 0;
560     if (dataSource->GetSize(fileSize) == Status::OK) {
561         bufferSize = (bufferSize < fileSize) ? bufferSize : fileSize;
562     }
563     std::vector<uint8_t> buff(bufferSize);
564     auto bufferInfo = std::make_shared<Buffer>();
565     auto bufData = bufferInfo->WrapMemory(buff.data(), bufferSize, bufferSize);
566     int confidence = 0;
567     if (dataSource->ReadAt(0, bufferInfo, bufferSize) == Status::OK) {
568         AVProbeData probeData{"", buff.data(), static_cast<int>(bufferInfo->GetMemory()->GetSize()), ""};
569         confidence = plugin->read_probe(&probeData);
570     }
571     MEDIA_LOG_D("Sniff: plugin pluginName = %" PUBLIC_LOG "s, probability = %" PUBLIC_LOG "d / 100 ...",
572                 plugin->name, confidence);
573     return confidence;
574 }
575 
IsInputFormatSupported(const char * name)576 bool IsInputFormatSupported(const char* name)
577 {
578     if (!strcmp(name, "audio_device") || !strncmp(name, "image", 5) ||                 // 5
579         !strcmp(name, "mjpeg") || !strcmp(name, "redir") || !strncmp(name, "u8", 2) || // 2
580         !strncmp(name, "u16", 3) || !strncmp(name, "u24", 3) ||                        // 3
581         !strncmp(name, "u32", 3) ||                                                    // 3
582         !strncmp(name, "s8", 2) || !strncmp(name, "s16", 3) ||                         // 2 3
583         !strncmp(name, "s24", 3) ||                                                    // 3
584         !strncmp(name, "s32", 3) || !strncmp(name, "f32", 3) ||                        // 3
585         !strncmp(name, "f64", 3) ||                                                    // 3
586         !strcmp(name, "mulaw") || !strcmp(name, "alaw")) {
587         return false;
588     }
589 
590     /* no network demuxers */
591     if (!strcmp(name, "sdp") || !strcmp(name, "rtsp") || !strcmp(name, "applehttp")) {
592         return false;
593     }
594     return true;
595 }
596 
RegisterPlugins(const std::shared_ptr<Register> & reg)597 Status RegisterPlugins(const std::shared_ptr<Register>& reg)
598 {
599     MEDIA_LOG_D("RegisterPlugins called.");
600     if (!reg) {
601         MEDIA_LOG_E("RegisterPlugins failed due to null pointer for reg.");
602         return Status::ERROR_INVALID_PARAMETER;
603     }
604     const AVInputFormat* plugin = nullptr;
605     void* i = nullptr;
606     while ((plugin = av_demuxer_iterate(&i))) {
607         MEDIA_LOG_D("Attempting to handle libav demuxer plugin %" PUBLIC_LOG "s [%" PUBLIC_LOG "s]",
608                     plugin->name, plugin->long_name);
609         /* no emulators */
610         if (plugin->long_name != nullptr) {
611             if (!strncmp(plugin->long_name, "pcm ", 4)) { // 4
612                 continue;
613             }
614         }
615 
616         if (!IsInputFormatSupported(plugin->name)) {
617             continue;
618         }
619 
620         std::string pluginName = "avdemux_" + std::string(plugin->name);
621         ReplaceDelimiter(".,|-<> ", '_', pluginName);
622 
623         DemuxerPluginDef regInfo;
624         regInfo.name = pluginName;
625         regInfo.description = "adapter for ffmpeg demuxer plugin";
626         regInfo.rank = 100; // 100
627         SplitString(plugin->extensions, ',').swap(regInfo.extensions);
628         g_pluginInputFormat[pluginName] =
629             std::shared_ptr<AVInputFormat>(const_cast<AVInputFormat*>(plugin), [](void*) {});
630         regInfo.creator = [](const std::string& name) -> std::shared_ptr<DemuxerPlugin> {
631             return std::make_shared<FFmpegDemuxerPlugin>(name);
632         };
633         regInfo.sniffer = Sniff;
634         auto rtv = reg->AddPlugin(regInfo);
635         if (rtv != Status::OK) {
636             MEDIA_LOG_E("RegisterPlugins AddPlugin failed with return %" PUBLIC_LOG "d", static_cast<int>(rtv));
637         }
638     }
639     return Status::OK;
640 }
641 } // namespace
642 
__anond459671f0a02null643 PLUGIN_DEFINITION(FFmpegDemuxer, LicenseType::LGPL, RegisterPlugins, [] { g_pluginInputFormat.clear(); });
644 } // namespace Ffmpeg
645 } // namespace Plugin
646 } // namespace Media
647 } // namespace OHOS
648