1 /*
2 * Copyright (C) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #define MEDIA_PLUGIN
17 #include <unistd.h>
18 #include <algorithm>
19 #include <malloc.h>
20 #include <string>
21 #include <sstream>
22 #include <map>
23 #include <fstream>
24 #include <chrono>
25 #include <limits>
26 #include "avcodec_trace.h"
27 #include "securec.h"
28 #include "ffmpeg_format_helper.h"
29 #include "ffmpeg_utils.h"
30 #include "buffer/avbuffer.h"
31 #include "plugin/plugin_buffer.h"
32 #include "plugin/plugin_definition.h"
33 #include "common/log.h"
34 #include "meta/video_types.h"
35 #include "avcodec_sysevent.h"
36 #include "ffmpeg_demuxer_plugin.h"
37 #include "meta/format.h"
38 #include "syspara/parameters.h"
39
40 namespace {
41 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_DEMUXER, "FfmpegReferenceParser" };
42 constexpr int64_t REFERENCE_PARSER_TIMEOUT_MS = 10000;
43 const uint32_t REFERENCE_PARSER_PTS_LIST_UPPER_LIMIT = 200000u;
44 }
45
46 namespace OHOS {
47 namespace Media {
48 namespace Plugins {
49 namespace Ffmpeg {
50
IsLessMaxReferenceParserFrames(uint32_t trackIndex)51 bool FFmpegDemuxerPlugin::IsLessMaxReferenceParserFrames(uint32_t trackIndex)
52 {
53 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, false, "AVFormatContext is nullptr");
54 AVStream *avStream = formatContext_->streams[trackIndex];
55 FALSE_RETURN_V_MSG_E(avStream != nullptr, false, "Avstream is nullptr");
56 FALSE_RETURN_V_MSG_E(avStream->stts_data != nullptr && avStream->stts_count != 0, false,
57 "AVStream->stts_data is empty");
58 uint32_t frames = 0u;
59 for (auto i = 0u; i < avStream->stts_count; i++) {
60 FALSE_RETURN_V_MSG_E(frames <= UINT32_MAX - avStream->stts_data[i].count, false, "Frame count exceeds limit");
61 frames += avStream->stts_data[i].count;
62 FALSE_RETURN_V_MSG_E(frames <= REFERENCE_PARSER_PTS_LIST_UPPER_LIMIT, false, "Frame count exceeds limit");
63 }
64 return true;
65 }
66
ParserBoxInfo()67 void FFmpegDemuxerPlugin::ParserBoxInfo()
68 {
69 if (!IsRefParserSupported()) {
70 return;
71 }
72 AVStream *videoStream = GetVideoStream();
73 FALSE_RETURN_MSG(videoStream != nullptr, "Video stream is nullptr");
74 if (videoStream->avg_frame_rate.den == 0 || videoStream->avg_frame_rate.num == 0) {
75 fps_ = videoStream->r_frame_rate.num / (double)videoStream->r_frame_rate.den;
76 } else {
77 fps_ = videoStream->avg_frame_rate.num / (double)videoStream->avg_frame_rate.den;
78 }
79 struct KeyFrameNode *keyFramePosInfo = nullptr;
80 if (av_get_key_frame_pos_from_stream(videoStream, &keyFramePosInfo) == 0) {
81 struct KeyFrameNode *cur = keyFramePosInfo;
82 while (cur != nullptr) {
83 IFramePos_.emplace_back(cur->pos);
84 cur = cur->next;
85 }
86 av_destory_key_frame_pos_list(keyFramePosInfo);
87 }
88 FALSE_RETURN_MSG(GetPresentationTimeUsFromFfmpegMOV(
89 GET_ALL_FRAME_PTS, parserRefVideoStreamIdx_, 0, 0) == Status::OK, "get all frame pts failed.");
90 MEDIA_LOG_I("Success parse, fps: " PUBLIC_LOG_F ", IFramePos size: " PUBLIC_LOG_ZU, fps_, IFramePos_.size());
91 }
92
GetVideoStream()93 AVStream *FFmpegDemuxerPlugin::GetVideoStream()
94 {
95 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, nullptr, "AVFormatContext is nullptr");
96 if (parserRefVideoStreamIdx_ < 0 || parserRefVideoStreamIdx_ >= static_cast<int32_t>(formatContext_->nb_streams)) {
97 int32_t streamIdx = av_find_best_stream(formatContext_.get(), AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
98 FALSE_RETURN_V_MSG_E(streamIdx >= 0 && streamIdx < static_cast<int32_t>(formatContext_->nb_streams), nullptr,
99 "Can not find video stream, streamIdx " PUBLIC_LOG_D32 ", nb_streams " PUBLIC_LOG_U32,
100 streamIdx, formatContext_->nb_streams);
101 parserRefVideoStreamIdx_ = streamIdx;
102 }
103 return formatContext_->streams[static_cast<uint32_t>(parserRefVideoStreamIdx_)];
104 }
105
IsMultiVideoTrack()106 bool FFmpegDemuxerPlugin::IsMultiVideoTrack()
107 {
108 bool hasVideo = false;
109 for (uint32_t trackIndex = 0; trackIndex < formatContext_->nb_streams; ++trackIndex) {
110 auto avStream = formatContext_->streams[trackIndex];
111 if (avStream == nullptr || avStream->codecpar == nullptr) {
112 MEDIA_LOG_W("Track " PUBLIC_LOG_D32 " info is nullptr", trackIndex);
113 continue;
114 }
115 if (avStream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
116 FFmpegFormatHelper::IsVideoCodecId(avStream->codecpar->codec_id)) {
117 if (hasVideo) {
118 return true;
119 }
120 hasVideo = true;
121 }
122 }
123 return false;
124 }
125
IsRefParserSupported()126 bool FFmpegDemuxerPlugin::IsRefParserSupported()
127 {
128 std::shared_ptr<AVFormatContext> formatContext = parserRefFormatContext_ != nullptr ?
129 parserRefFormatContext_ : formatContext_;
130 FALSE_RETURN_V_MSG_E(formatContext != nullptr, false, "AVFormatContext is nullptr");
131 FileType type = FFmpegFormatHelper::GetFileTypeByName(*formatContext);
132 FALSE_RETURN_V_MSG_W(type == FileType::MP4 || type == FileType::MOV, false,
133 "RefParser unsupported file type " PUBLIC_LOG_U32, type);
134 FALSE_RETURN_V_MSG_W(!IsMultiVideoTrack(), false, "multi-video-tracks video is unsupported!");
135 FALSE_RETURN_V_MSG_W(ParserRefCheckVideoValid(GetVideoStream()) == Status::OK, false,
136 "RefParser unsupported stream type");
137 return true;
138 }
139
ParserRefUpdatePos(int64_t timeStampMs,bool isForward)140 Status FFmpegDemuxerPlugin::ParserRefUpdatePos(int64_t timeStampMs, bool isForward)
141 {
142 FALSE_RETURN_V_MSG_E(IsRefParserSupported(), Status::ERROR_UNSUPPORTED_FORMAT, "Unsupported ref parser");
143 int64_t clipTimeStampMs = std::max(timeStampMs, static_cast<int64_t>(0));
144 if (IFramePos_.size() == 0 || referenceParser_ == nullptr) {
145 MEDIA_LOG_W("Parse failed, size: " PUBLIC_LOG_ZU, IFramePos_.size());
146 pendingSeekMsTime_ = clipTimeStampMs;
147 updatePosIsForward_ = isForward;
148 return Status::OK;
149 }
150 int32_t gopId = 0;
151 FALSE_RETURN_V_MSG_E(GetGopIdFromSeekPos(clipTimeStampMs, gopId) == Status::OK,
152 Status::ERROR_UNKNOWN, "GetGopIdFromSeekPos failed.");
153 GopLayerInfo gopLayerInfo;
154 Status ret = GetGopLayerInfo(gopId, gopLayerInfo);
155 if (ret == Status::ERROR_AGAIN && gopId != parserCurGopId_) {
156 pendingSeekMsTime_ = clipTimeStampMs;
157 parserState_ = false;
158 MEDIA_LOG_I("Pending time: " PUBLIC_LOG_D64, pendingSeekMsTime_);
159 }
160 updatePosIsForward_ = isForward;
161 return Status::OK;
162 }
163
InitIoContext()164 Status FFmpegDemuxerPlugin::InitIoContext()
165 {
166 parserRefIoContext_.dataSource = ioContext_.dataSource;
167 parserRefIoContext_.offset = 0;
168 parserRefIoContext_.eos = false;
169 parserRefIoContext_.initCompleted = true;
170 FALSE_RETURN_V_MSG_E(parserRefIoContext_.dataSource != nullptr, Status::ERROR_UNKNOWN, "Data source is nullptr");
171 if (parserRefIoContext_.dataSource->GetSeekable() == Plugins::Seekable::SEEKABLE) {
172 parserRefIoContext_.dataSource->GetSize(parserRefIoContext_.fileSize);
173 } else {
174 parserRefIoContext_.fileSize = -1;
175 MEDIA_LOG_E("Not support online video");
176 return Status::ERROR_INVALID_OPERATION;
177 }
178 return Status::OK;
179 }
180
ParserRefCheckVideoValid(const AVStream * videoStream)181 Status FFmpegDemuxerPlugin::ParserRefCheckVideoValid(const AVStream *videoStream)
182 {
183 if (videoStream == nullptr || videoStream->codecpar == nullptr) {
184 MEDIA_LOG_D("videoStream or codecpar is nullptr: video track id " PUBLIC_LOG_D32, parserRefVideoStreamIdx_);
185 return Status::ERROR_UNKNOWN;
186 }
187 FALSE_RETURN_V_MSG_E(
188 videoStream->codecpar->codec_id == AV_CODEC_ID_HEVC || videoStream->codecpar->codec_id == AV_CODEC_ID_H264,
189 Status::ERROR_UNSUPPORTED_FORMAT, "Codec type not support " PUBLIC_LOG_D32, videoStream->codecpar->codec_id);
190 return Status::OK;
191 }
192
ParserRefInit()193 Status FFmpegDemuxerPlugin::ParserRefInit()
194 {
195 parserRefStartTime_ = std::chrono::duration_cast<std::chrono::milliseconds>(
196 std::chrono::system_clock::now().time_since_epoch()).count();
197 std::string suffix = std::to_string(parserRefStartTime_) + "_" + std::to_string(IFramePos_.size());
198 MediaAVCodec::AVCodecTrace trace("ParserRefCost_1_" + suffix);
199 MEDIA_LOG_I("Parser ref start time: " PUBLIC_LOG_D64, parserRefStartTime_);
200 FALSE_RETURN_V_MSG_E(IFramePos_.size() > 0 && fps_ > 0, Status::ERROR_UNKNOWN,
201 "Init failed, IFramePos size:" PUBLIC_LOG_ZU ", fps:" PUBLIC_LOG_F, IFramePos_.size(), fps_);
202 FALSE_RETURN_V_MSG_E(InitIoContext() == Status::OK, Status::ERROR_UNKNOWN, "Init IOContext failed");
203 parserRefFormatContext_ = InitAVFormatContext(&parserRefIoContext_);
204 FALSE_RETURN_V_MSG_E(parserRefFormatContext_ != nullptr, Status::ERROR_UNKNOWN, "AVFormatContext is nullptr");
205 FALSE_RETURN_V_MSG_E(IsRefParserSupported(), Status::ERROR_UNSUPPORTED_FORMAT, "Unsupported ref parser");
206 for (uint32_t trackIndex = 0; trackIndex < parserRefFormatContext_->nb_streams; trackIndex++) {
207 AVStream *stream = parserRefFormatContext_->streams[trackIndex];
208 FALSE_RETURN_V_MSG_E(stream != nullptr && stream->codecpar != nullptr, Status::ERROR_UNKNOWN,
209 "AVStream or codecpar is nullptr, track " PUBLIC_LOG_U32, trackIndex);
210 if (stream->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
211 stream->discard = AVDISCARD_ALL;
212 }
213 }
214 AVStream *videoStream = GetVideoStream();
215 FALSE_RETURN_V_MSG_E(videoStream != nullptr && videoStream->codecpar != nullptr, Status::ERROR_UNKNOWN,
216 "AVStream or codecpar is nullptr");
217 processingIFrame_.assign(IFramePos_.begin(), IFramePos_.end());
218 CodecType codecType = videoStream->codecpar->codec_id == AV_CODEC_ID_HEVC ? CodecType::H265 : CodecType::H264;
219 referenceParser_ = ReferenceParserManager::Create(codecType, IFramePos_);
220 FALSE_RETURN_V_MSG_E(referenceParser_ != nullptr, Status::ERROR_NULL_POINTER, "Reference is nullptr");
221 ParserSdtpInfo *sc = (ParserSdtpInfo *)videoStream->priv_data;
222 if (sc->sdtpCount > 0 && sc->sdtpData != nullptr) {
223 MEDIA_LOG_E("Sdtp exist: " PUBLIC_LOG_D32, sc->sdtpCount);
224 if (referenceParser_->ParserSdtpData(sc->sdtpData, sc->sdtpCount) == Status::OK) {
225 isSdtpExist_ = true;
226 return Status::END_OF_STREAM;
227 }
228 }
229 return referenceParser_->ParserExtraData(videoStream->codecpar->extradata, videoStream->codecpar->extradata_size);
230 }
231
InsertIframePtsMap(AVPacket * pkt,int32_t gopId,int32_t trackIdx,std::unordered_map<int32_t,int64_t> & iFramePtsMap)232 static void InsertIframePtsMap(AVPacket *pkt, int32_t gopId, int32_t trackIdx,
233 std::unordered_map<int32_t, int64_t> &iFramePtsMap)
234 {
235 bool validCheck = (pkt != nullptr) && (pkt->stream_index == trackIdx) &&
236 (pkt->flags == AV_PKT_FLAG_KEY) && (gopId != -1); // -1 disable
237 if (validCheck && (iFramePtsMap.find(gopId) == iFramePtsMap.end())) {
238 iFramePtsMap.insert(std::pair<int32_t, int64_t>(gopId, pkt->pts));
239 }
240 }
241
ParserRefInfoLoop(AVPacket * pkt,uint32_t curStreamId)242 Status FFmpegDemuxerPlugin::ParserRefInfoLoop(AVPacket *pkt, uint32_t curStreamId)
243 {
244 std::unique_lock<std::mutex> sLock(syncMutex_);
245 int ffmpegRet = av_read_frame(parserRefFormatContext_.get(), pkt);
246 sLock.unlock();
247 if (ffmpegRet < 0 && ffmpegRet != AVERROR_EOF) {
248 MEDIA_LOG_E("Call av_read_frame failed:" PUBLIC_LOG_S ", retry:" PUBLIC_LOG_D32,
249 AVStrError(ffmpegRet).c_str(), int(parserRefIoContext_.retry));
250 if (parserRefIoContext_.retry) {
251 parserRefFormatContext_->pb->eof_reached = 0;
252 parserRefFormatContext_->pb->error = 0;
253 parserRefIoContext_.retry = false;
254 return Status::ERROR_AGAIN;
255 }
256 return Status::ERROR_UNKNOWN;
257 }
258 InsertIframePtsMap(pkt, parserCurGopId_, parserRefVideoStreamIdx_, iFramePtsMap_);
259 FALSE_RETURN_V_MSG_D(pkt->stream_index == parserRefVideoStreamIdx_ || ffmpegRet == AVERROR_EOF, Status::OK,
260 "eos or not video");
261 int64_t dts = AvTime2Us(
262 ConvertTimeFromFFmpeg(pkt->dts, parserRefFormatContext_->streams[parserRefVideoStreamIdx_]->time_base));
263 Status result = referenceParser_->ParserNalUnits(pkt->data, pkt->size, curStreamId, dts);
264 FALSE_RETURN_V_MSG_E(result == Status::OK, Status::ERROR_UNKNOWN, "parse nal units error!");
265 int32_t iFramePosSize = static_cast<int32_t>(IFramePos_.size());
266 if (ffmpegRet == AVERROR_EOF || result != Status::OK ||
267 (parserCurGopId_ + 1 < iFramePosSize && curStreamId == IFramePos_[parserCurGopId_ + 1] - 1)) { // 处理完一个GOP
268 MEDIA_LOG_I("IFramePos: " PUBLIC_LOG_ZU ", processingIFrame: " PUBLIC_LOG_ZU ", curStreamId: " PUBLIC_LOG_U32
269 ", curGopId: " PUBLIC_LOG_U32, IFramePos_.size(), processingIFrame_.size(), curStreamId, parserCurGopId_);
270 processingIFrame_.remove(IFramePos_[parserCurGopId_]);
271 if (processingIFrame_.size() == 0) {
272 parserCurGopId_ = -1;
273 return Status::OK;
274 }
275 int32_t tmpGopId = parserCurGopId_;
276 int32_t searchCnt = 0;
277 while (formatContext_ != nullptr && std::find(processingIFrame_.begin(), processingIFrame_.end(),
278 IFramePos_[parserCurGopId_]) == processingIFrame_.end()) {
279 if (updatePosIsForward_) {
280 parserCurGopId_ = (parserCurGopId_ + 1) % iFramePosSize;
281 } else {
282 parserCurGopId_ = parserCurGopId_ == 0 ? iFramePosSize - 1 : parserCurGopId_ - 1;
283 }
284 searchCnt++;
285 FALSE_RETURN_V_MSG_E(searchCnt < iFramePosSize, Status::ERROR_UNKNOWN, "Cannot find gop");
286 }
287 if (formatContext_ == nullptr || tmpGopId + 1 != parserCurGopId_ || !updatePosIsForward_) {
288 return Status::END_OF_STREAM;
289 }
290 }
291 return Status::OK;
292 }
293
GetGopIdFromSeekPos(int64_t seekMs,int32_t & gopId)294 Status FFmpegDemuxerPlugin::GetGopIdFromSeekPos(int64_t seekMs, int32_t &gopId)
295 {
296 FALSE_RETURN_V_MSG_E(seekMs >= 0L, Status::ERROR_INVALID_PARAMETER, "SeekMs is less than 0");
297 AVStream *st = parserRefFormatContext_->streams[parserRefVideoStreamIdx_];
298 FALSE_RETURN_V_MSG_E(st != nullptr, Status::ERROR_UNKNOWN, "AVStream is nullptr");
299 uint32_t frameId = 0U;
300 Status ret = SeekMs2FrameId(seekMs, frameId);
301 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "SeekMs2FrameId failed, seekMs=" PUBLIC_LOG_D64, seekMs);
302 gopId = std::upper_bound(IFramePos_.begin(), IFramePos_.end(), frameId) - IFramePos_.begin();
303 if (gopId > 0) {
304 --gopId;
305 }
306 return Status::OK;
307 }
308
SelectProGopId()309 Status FFmpegDemuxerPlugin::SelectProGopId()
310 {
311 AVStream *st = parserRefFormatContext_->streams[parserRefVideoStreamIdx_];
312 FALSE_RETURN_V_MSG_E(st != nullptr, Status::ERROR_UNKNOWN, "AVStream is nullptr");
313 if (pendingSeekMsTime_ >= 0) {
314 FALSE_RETURN_V_MSG_E(GetGopIdFromSeekPos(pendingSeekMsTime_, parserCurGopId_) == Status::OK,
315 Status::ERROR_UNKNOWN, "GetGopIdFromSeekPos failed");
316 pendingSeekMsTime_ = -1;
317 }
318 int64_t ptsSeek;
319 if (iFramePtsMap_.find(parserCurGopId_) != iFramePtsMap_.end()) { // if I frame pts had got before decoding
320 ptsSeek = iFramePtsMap_[parserCurGopId_];
321 MEDIA_LOG_D("get I frame pts from which had been decoded");
322 } else {
323 int32_t iFramePosSize = static_cast<int32_t>(IFramePos_.size());
324 int64_t dtsCur = CalculateTimeByFrameIndex(st, IFramePos_[parserCurGopId_]);
325 if (parserCurGopId_ + 1 < iFramePosSize) {
326 int64_t dtsNext = CalculateTimeByFrameIndex(st, IFramePos_[parserCurGopId_ + 1]);
327 ptsSeek = dtsCur + (dtsNext - dtsCur) / 2; // 2 middle between cur gop and next gop
328 } else {
329 ptsSeek = INT64_MAX; // seek last gop
330 }
331 MEDIA_LOG_D("get I frame pts from simulated dts");
332 }
333 auto ret = av_seek_frame(parserRefFormatContext_.get(), parserRefVideoStreamIdx_, ptsSeek, AVSEEK_FLAG_BACKWARD);
334 FALSE_RETURN_V_MSG_E(ret >= 0, Status::ERROR_UNKNOWN,
335 "Call av_seek_frame failed, err: " PUBLIC_LOG_S, AVStrError(ret).c_str());
336 return Status::OK;
337 }
338
ParserRefInfo()339 Status FFmpegDemuxerPlugin::ParserRefInfo()
340 {
341 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::OK, "AVFormatContext is nullptr");
342 if (!isInit_) {
343 isInit_ = true;
344 Status ret = ParserRefInit();
345 if (ret == Status::END_OF_STREAM) {
346 return Status::OK;
347 }
348 if (ret != Status::OK) {
349 return Status::ERROR_UNKNOWN;
350 }
351 }
352 int64_t duration = std::chrono::duration_cast<std::chrono::milliseconds>(
353 std::chrono::system_clock::now().time_since_epoch()).count() - parserRefStartTime_;
354 std::string suffix = std::to_string(duration) + "_" + std::to_string(parserCurGopId_);
355 MediaAVCodec::AVCodecTrace trace("ParserRefCost_2_" + suffix);
356 FALSE_RETURN_V_MSG_W(duration < REFERENCE_PARSER_TIMEOUT_MS, Status::ERROR_UNKNOWN, "Reference parser timeout");
357 FALSE_RETURN_V_MSG(parserCurGopId_ != -1, Status::OK, "Reference parser end"); // 参考关系解析完毕
358 FALSE_RETURN_V_MSG_E(SelectProGopId() == Status::OK, Status::ERROR_UNKNOWN, "Call selectProGopId failed");
359 uint32_t curStreamId = IFramePos_[parserCurGopId_];
360 MEDIA_LOG_I("curStreamId: " PUBLIC_LOG_U32 ", parserCurGopId: " PUBLIC_LOG_D32 ", IFramePos size: " PUBLIC_LOG_ZU
361 ", processingIFrame_ size: " PUBLIC_LOG_ZU ", duration: " PUBLIC_LOG_D64, curStreamId, parserCurGopId_,
362 IFramePos_.size(), processingIFrame_.size(), duration);
363 AVPacket *pkt = av_packet_alloc();
364 while (formatContext_ != nullptr && parserState_ && parserCurGopId_ != -1) {
365 Status rlt = ParserRefInfoLoop(pkt, curStreamId);
366 duration = std::chrono::duration_cast<std::chrono::milliseconds>(
367 std::chrono::system_clock::now().time_since_epoch()).count() - parserRefStartTime_;
368 suffix = std::to_string(duration) + "_" + std::to_string(parserCurGopId_) + "_" + std::to_string(curStreamId);
369 MediaAVCodec::AVCodecTrace traceInLoop("ParserRefCost_3_" + suffix);
370 FALSE_RETURN_V_MSG_W(duration < REFERENCE_PARSER_TIMEOUT_MS, Status::ERROR_UNKNOWN, "Reference parser timeout");
371 if (rlt != Status::OK) {
372 av_packet_unref(pkt);
373 av_packet_free(&pkt);
374 parserState_ = true;
375 return rlt;
376 }
377 if (pkt->stream_index == parserRefVideoStreamIdx_) {
378 curStreamId++;
379 }
380 av_packet_unref(pkt);
381 }
382
383 av_packet_free(&pkt);
384 parserState_ = true;
385 return Status::ERROR_AGAIN;
386 }
387
GetFrameLayerInfo(std::shared_ptr<AVBuffer> videoSample,FrameLayerInfo & frameLayerInfo)388 Status FFmpegDemuxerPlugin::GetFrameLayerInfo(std::shared_ptr<AVBuffer> videoSample, FrameLayerInfo &frameLayerInfo)
389 {
390 FALSE_RETURN_V_MSG_W(referenceParser_ != nullptr, Status::ERROR_NULL_POINTER, "Reference is nullptr");
391 MEDIA_LOG_D("In, dts: " PUBLIC_LOG_D64, videoSample->dts_);
392 if (isSdtpExist_) {
393 uint32_t frameId = 0;
394 Status ret = Dts2FrameId(videoSample->dts_, frameId);
395 FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "Dts2FrameId failed");
396 return referenceParser_->GetFrameLayerInfo(frameId, frameLayerInfo);
397 }
398 return referenceParser_->GetFrameLayerInfo(videoSample->dts_, frameLayerInfo);
399 }
400
GetFrameLayerInfo(uint32_t frameId,FrameLayerInfo & frameLayerInfo)401 Status FFmpegDemuxerPlugin::GetFrameLayerInfo(uint32_t frameId, FrameLayerInfo &frameLayerInfo)
402 {
403 FALSE_RETURN_V_MSG_W(referenceParser_ != nullptr, Status::ERROR_NULL_POINTER, "Reference is nullptr");
404 MEDIA_LOG_D("In, dts: " PUBLIC_LOG_U32, frameId);
405 return referenceParser_->GetFrameLayerInfo(frameId, frameLayerInfo);
406 }
407
GetGopLayerInfo(uint32_t gopId,GopLayerInfo & gopLayerInfo)408 Status FFmpegDemuxerPlugin::GetGopLayerInfo(uint32_t gopId, GopLayerInfo &gopLayerInfo)
409 {
410 FALSE_RETURN_V_MSG_W(referenceParser_ != nullptr, Status::ERROR_NULL_POINTER, "Reference is nullptr");
411 MEDIA_LOG_D("In, gopId: " PUBLIC_LOG_U32, gopId);
412 return referenceParser_->GetGopLayerInfo(gopId, gopLayerInfo);
413 }
414
GetIFramePos(std::vector<uint32_t> & IFramePos)415 Status FFmpegDemuxerPlugin::GetIFramePos(std::vector<uint32_t> &IFramePos)
416 {
417 FALSE_RETURN_V_MSG_E(IFramePos_.size() > 0, Status::ERROR_UNKNOWN, "IFramePos size is 0");
418 IFramePos = IFramePos_;
419 return Status::OK;
420 }
421
Dts2FrameId(int64_t dts,uint32_t & frameId)422 Status FFmpegDemuxerPlugin::Dts2FrameId(int64_t dts, uint32_t &frameId)
423 {
424 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "formatContext_ is nullptr");
425 auto avStream = formatContext_->streams[parserRefVideoStreamIdx_];
426 int64_t ffTimeDts = ConvertTimeToFFmpegByUs(dts, avStream->time_base);
427 int32_t tmpFrameId = av_index_search_timestamp(avStream, ffTimeDts, AVSEEK_FLAG_ANY);
428 FALSE_RETURN_V_MSG_E(tmpFrameId >= 0, Status::ERROR_OUT_OF_RANGE, "find nearest frame failed");
429 frameId = static_cast<uint32_t>(tmpFrameId);
430 MEDIA_LOG_D("dts " PUBLIC_LOG_D64 ", frameId " PUBLIC_LOG_U32, dts, frameId);
431 return Status::OK;
432 }
433
SeekMs2FrameId(int64_t seekMs,uint32_t & frameId)434 Status FFmpegDemuxerPlugin::SeekMs2FrameId(int64_t seekMs, uint32_t &frameId)
435 {
436 FALSE_RETURN_V_MSG_E(seekMs >= 0L, Status::ERROR_INVALID_PARAMETER, "SeekMs is less than 0");
437 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "formatContext_ is nullptr");
438 auto avStream = formatContext_->streams[parserRefVideoStreamIdx_];
439 FALSE_RETURN_V_MSG_E(avStream != nullptr, Status::ERROR_NULL_POINTER, "AVStream is nullptr");
440 FALSE_RETURN_V_MSG_E(avStream->stts_data != nullptr && avStream->stts_count != 0,
441 Status::ERROR_NULL_POINTER, "AVStream->stts_data is empty");
442 int64_t pts = seekMs * 1000; // 1000 for ms to us
443 auto iter = pts2DtsMap_.upper_bound(pts);
444 if (iter != pts2DtsMap_.begin()) {
445 --iter;
446 }
447 int64_t dts = iter->second;
448 MEDIA_LOG_D("seekMs " PUBLIC_LOG_D64 ", pts " PUBLIC_LOG_D64 ", mapSize " PUBLIC_LOG_ZU ", dts " PUBLIC_LOG_D64,
449 seekMs, pts, pts2DtsMap_.size(), dts);
450 return Dts2FrameId(dts, frameId);
451 }
452
FrameId2SeekMs(uint32_t frameId,int64_t & seekMs)453 Status FFmpegDemuxerPlugin::FrameId2SeekMs(uint32_t frameId, int64_t &seekMs)
454 {
455 FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::ERROR_NULL_POINTER, "formatContext_ is nullptr");
456 AVStream *st = formatContext_->streams[parserRefVideoStreamIdx_];
457 FALSE_RETURN_V_MSG_E(st != nullptr, Status::ERROR_NULL_POINTER, "AVStream is nullptr");
458 int64_t ffTimeDts = CalculateTimeByFrameIndex(st, static_cast<int32_t>(frameId));
459 int64_t dts = AvTime2Us(ConvertTimeFromFFmpeg(ffTimeDts, st->time_base));
460 auto it = std::find_if(pts2DtsMap_.begin(), pts2DtsMap_.end(), DtsFinder(dts));
461 FALSE_RETURN_V_MSG_E(it != pts2DtsMap_.end(), Status::ERROR_UNKNOWN, "find pts failed, frameId "
462 PUBLIC_LOG_U32 ", dts " PUBLIC_LOG_D64, frameId, dts);
463 seekMs = it->first / 1000; // 1000 for ms to us
464 MEDIA_LOG_D("frameId " PUBLIC_LOG_U32 ", dts " PUBLIC_LOG_D64 ", seekMs " PUBLIC_LOG_D64, frameId, dts, seekMs);
465 return Status::OK;
466 }
467
468 } // namespace Ffmpeg
469 } // namespace Plugins
470 } // namespace Media
471 } // namespace OHOS