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