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