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