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 }
44 
45 namespace OHOS {
46 namespace Media {
47 namespace Plugins {
48 namespace Ffmpeg {
49 
ParserBoxInfo()50 void FFmpegDemuxerPlugin::ParserBoxInfo()
51 {
52     if (!IsRefParserSupported()) {
53         return;
54     }
55     AVStream *videoStream = GetVideoStream();
56     FALSE_RETURN_MSG(videoStream != nullptr, "Video stream is nullptr");
57     if (videoStream->avg_frame_rate.den == 0 || videoStream->avg_frame_rate.num == 0) {
58         fps_ = videoStream->r_frame_rate.num / (double)videoStream->r_frame_rate.den;
59     } else {
60         fps_ = videoStream->avg_frame_rate.num / (double)videoStream->avg_frame_rate.den;
61     }
62     struct KeyFrameNode *keyFramePosInfo = nullptr;
63     if (av_get_key_frame_pos_from_stream(videoStream, &keyFramePosInfo) == 0) {
64         struct KeyFrameNode *cur = keyFramePosInfo;
65         while (cur != nullptr) {
66             IFramePos_.emplace_back(cur->pos);
67             cur = cur->next;
68         }
69         av_destory_key_frame_pos_list(keyFramePosInfo);
70     }
71     FALSE_RETURN_MSG(GetPresentationTimeUsFromFfmpegMOV(
72         GET_ALL_FRAME_PTS, parserRefVideoStreamIdx_, 0, 0) == Status::OK, "get all frame pts failed.");
73     ptsListFromZero_.clear();
74     for (size_t ptsIdx = 0; ptsIdx < ptsListOrg_.size(); ptsIdx++) {
75         ptsListFromZero_.emplace_back(ptsListOrg_[ptsIdx] - absolutePTSIndexZero_);
76     }
77     if (ptsListFromZero_.size() > 0) {
78         sort(ptsListFromZero_.begin(), ptsListFromZero_.end());
79     }
80     MEDIA_LOG_I("Success parse, fps: " PUBLIC_LOG_F ", IFramePos size: " PUBLIC_LOG_ZU, fps_, IFramePos_.size());
81 }
82 
GetVideoStream()83 AVStream *FFmpegDemuxerPlugin::GetVideoStream()
84 {
85     FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, nullptr, "AVFormatContext is nullptr");
86     if (parserRefVideoStreamIdx_ < 0 || parserRefVideoStreamIdx_ >= static_cast<int32_t>(formatContext_->nb_streams)) {
87         int32_t streamIdx = av_find_best_stream(formatContext_.get(), AVMEDIA_TYPE_VIDEO, -1, -1, nullptr, 0);
88         FALSE_RETURN_V_MSG_E(streamIdx >= 0 && streamIdx < static_cast<int32_t>(formatContext_->nb_streams), nullptr,
89             "Can not find video stream, streamIdx " PUBLIC_LOG_D32 ", nb_streams " PUBLIC_LOG_U32,
90             streamIdx, formatContext_->nb_streams);
91         parserRefVideoStreamIdx_ = streamIdx;
92     }
93     return formatContext_->streams[static_cast<uint32_t>(parserRefVideoStreamIdx_)];
94 }
95 
IsRefParserSupported()96 bool FFmpegDemuxerPlugin::IsRefParserSupported()
97 {
98     std::shared_ptr<AVFormatContext> formatContext = parserRefFormatContext_ != nullptr ?
99         parserRefFormatContext_ : formatContext_;
100     FALSE_RETURN_V_MSG_E(formatContext != nullptr, false, "AVFormatContext is nullptr");
101     FileType type = FFmpegFormatHelper::GetFileTypeByName(*formatContext);
102     FALSE_RETURN_V_MSG_E(type == FileType::MP4 || type == FileType::MOV, false,
103         "Unsupported file type " PUBLIC_LOG_U32, type);
104     FALSE_RETURN_V_MSG_E(ParserRefCheckVideoValid(GetVideoStream()) == Status::OK, false, "Unsupported stream type");
105     return true;
106 }
107 
ParserRefUpdatePos(int64_t timeStampMs,bool isForward)108 Status FFmpegDemuxerPlugin::ParserRefUpdatePos(int64_t timeStampMs, bool isForward)
109 {
110     FALSE_RETURN_V_MSG_E(IsRefParserSupported(), Status::ERROR_UNSUPPORTED_FORMAT, "Unsupported ref parser");
111     int64_t clipTimeStampMs = std::max(timeStampMs, static_cast<int64_t>(0));
112     if (IFramePos_.size() == 0 || referenceParser_ == nullptr) {
113         MEDIA_LOG_W("Parse failed, size: " PUBLIC_LOG_ZU, IFramePos_.size());
114         pendingSeekMsTime_ = clipTimeStampMs;
115         updatePosIsForward_ = isForward;
116         return Status::OK;
117     }
118     int32_t gopId = 0;
119     FALSE_RETURN_V_MSG_E(GetGopIdFromSeekPos(clipTimeStampMs, gopId) == Status::OK,
120         Status::ERROR_UNKNOWN, "GetGopIdFromSeekPos failed.");
121     GopLayerInfo gopLayerInfo;
122     Status ret = GetGopLayerInfo(gopId, gopLayerInfo);
123     if (ret == Status::ERROR_AGAIN && gopId != parserCurGopId_) {
124         pendingSeekMsTime_ = clipTimeStampMs;
125         parserState_ = false;
126         MEDIA_LOG_I("Pending time: " PUBLIC_LOG_D64, pendingSeekMsTime_);
127     }
128     updatePosIsForward_ = isForward;
129     return Status::OK;
130 }
131 
ParserFirstDts()132 void FFmpegDemuxerPlugin::ParserFirstDts()
133 {
134     AVPacket *pkt = av_packet_alloc();
135     bool isEnd = false;
136     bool isFirst = true;
137     while (!isEnd) {
138         std::unique_lock<std::mutex> sLock(syncMutex_);
139         int ffmpegRet = av_read_frame(parserRefFormatContext_.get(), pkt);
140         sLock.unlock();
141         if (ffmpegRet < 0) {
142             av_packet_unref(pkt);
143             av_packet_free(&pkt);
144             return;
145         }
146         if (pkt->stream_index != parserRefVideoStreamIdx_) {
147             continue;
148         }
149         if (isFirst) {
150             firstDts_ = AvTime2Us(
151                 ConvertTimeFromFFmpeg(pkt->dts, parserRefFormatContext_->streams[parserRefVideoStreamIdx_]->time_base));
152             MEDIA_LOG_I("Success parse, first dts: " PUBLIC_LOG_D64, firstDts_);
153             isFirst = false;
154         }
155         if (pkt->dts < 0) {
156             dtsOffset_++;
157         } else {
158             isEnd = true;
159         }
160         av_packet_unref(pkt);
161     }
162     av_packet_unref(pkt);
163     av_packet_free(&pkt);
164 }
165 
InitIoContext()166 Status FFmpegDemuxerPlugin::InitIoContext()
167 {
168     parserRefIoContext_.dataSource = ioContext_.dataSource;
169     parserRefIoContext_.offset = 0;
170     parserRefIoContext_.eos = false;
171     parserRefIoContext_.initCompleted = true;
172     FALSE_RETURN_V_MSG_E(parserRefIoContext_.dataSource != nullptr, Status::ERROR_UNKNOWN, "Data source is nullptr");
173     if (parserRefIoContext_.dataSource->GetSeekable() == Plugins::Seekable::SEEKABLE) {
174         parserRefIoContext_.dataSource->GetSize(parserRefIoContext_.fileSize);
175     } else {
176         parserRefIoContext_.fileSize = -1;
177         MEDIA_LOG_E("Not support online video");
178         return Status::ERROR_INVALID_OPERATION;
179     }
180     return Status::OK;
181 }
182 
ParserRefCheckVideoValid(const AVStream * videoStream)183 Status FFmpegDemuxerPlugin::ParserRefCheckVideoValid(const AVStream *videoStream)
184 {
185     if (videoStream == nullptr || videoStream->codecpar == nullptr) {
186         MEDIA_LOG_D("videoStream or codecpar is nullptr: video track id " PUBLIC_LOG_D32, parserRefVideoStreamIdx_);
187         return Status::ERROR_UNKNOWN;
188     }
189     FALSE_RETURN_V_MSG_E(
190         videoStream->codecpar->codec_id == AV_CODEC_ID_HEVC || videoStream->codecpar->codec_id == AV_CODEC_ID_H264,
191         Status::ERROR_UNSUPPORTED_FORMAT, "Codec type not support " PUBLIC_LOG_D32, videoStream->codecpar->codec_id);
192     return Status::OK;
193 }
194 
ParserRefInit()195 Status FFmpegDemuxerPlugin::ParserRefInit()
196 {
197     parserRefStartTime_ = std::chrono::duration_cast<std::chrono::milliseconds>(
198         std::chrono::system_clock::now().time_since_epoch()).count();
199     std::string suffix = std::to_string(parserRefStartTime_) + "_" + std::to_string(IFramePos_.size());
200     MediaAVCodec::AVCodecTrace trace("ParserRefCost_1_" + suffix);
201     MEDIA_LOG_I("Parser ref start time: " PUBLIC_LOG_D64, parserRefStartTime_);
202     FALSE_RETURN_V_MSG_E(IFramePos_.size() > 0 && fps_ > 0, Status::ERROR_UNKNOWN,
203                          "Init failed, IFramePos size:" PUBLIC_LOG_ZU ", fps:" PUBLIC_LOG_F, IFramePos_.size(), fps_);
204     FALSE_RETURN_V_MSG_E(InitIoContext() == Status::OK, Status::ERROR_UNKNOWN, "Init IOContext failed");
205     parserRefFormatContext_ = InitAVFormatContext(&parserRefIoContext_);
206     FALSE_RETURN_V_MSG_E(parserRefFormatContext_ != nullptr, Status::ERROR_UNKNOWN, "AVFormatContext is nullptr");
207     FALSE_RETURN_V_MSG_E(IsRefParserSupported(), Status::ERROR_UNSUPPORTED_FORMAT, "Unsupported ref parser");
208     for (uint32_t trackIndex = 0; trackIndex < parserRefFormatContext_->nb_streams; trackIndex++) {
209         AVStream *stream = parserRefFormatContext_->streams[trackIndex];
210         FALSE_RETURN_V_MSG_E(stream != nullptr && stream->codecpar != nullptr, Status::ERROR_UNKNOWN,
211             "AVStream or codecpar is nullptr, track " PUBLIC_LOG_U32, trackIndex);
212         if (stream->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
213             stream->discard = AVDISCARD_ALL;
214         }
215     }
216     AVStream *videoStream = GetVideoStream();
217     FALSE_RETURN_V_MSG_E(videoStream != nullptr && videoStream->codecpar != nullptr, Status::ERROR_UNKNOWN,
218         "AVStream or codecpar is nullptr");
219     processingIFrame_.assign(IFramePos_.begin(), IFramePos_.end());
220     ParserFirstDts();
221     CodecType codecType = videoStream->codecpar->codec_id == AV_CODEC_ID_HEVC ? CodecType::H265 : CodecType::H264;
222     referenceParser_ = ReferenceParserManager::Create(codecType, IFramePos_);
223     FALSE_RETURN_V_MSG_E(referenceParser_ != nullptr, Status::ERROR_NULL_POINTER, "Reference is nullptr");
224     ParserSdtpInfo *sc = (ParserSdtpInfo *)videoStream->priv_data;
225     if (sc->sdtpCount > 0 && sc->sdtpData != nullptr) {
226         MEDIA_LOG_E("Sdtp exist: " PUBLIC_LOG_D32, sc->sdtpCount);
227         if (referenceParser_->ParserSdtpData(sc->sdtpData, sc->sdtpCount) == Status::OK) {
228             isSdtpExist_ = true;
229             return Status::END_OF_STREAM;
230         }
231     }
232     return referenceParser_->ParserExtraData(videoStream->codecpar->extradata, videoStream->codecpar->extradata_size);
233 }
234 
InsertIframePtsMap(AVPacket * pkt,int32_t gopId,int32_t trackIdx,std::unordered_map<int32_t,int64_t> & iFramePtsMap)235 static void InsertIframePtsMap(AVPacket *pkt, int32_t gopId, int32_t trackIdx,
236     std::unordered_map<int32_t, int64_t> &iFramePtsMap)
237 {
238     bool validCheck = (pkt != nullptr) && (pkt->stream_index == trackIdx) &&
239         (pkt->flags == AV_PKT_FLAG_KEY) && (gopId != -1); // -1 disable
240     if (validCheck && (iFramePtsMap.find(gopId) == iFramePtsMap.end())) {
241         iFramePtsMap.insert(std::pair<int32_t, int64_t>(gopId, pkt->pts));
242     }
243 }
244 
ParserRefInfoLoop(AVPacket * pkt,uint32_t curStreamId)245 Status FFmpegDemuxerPlugin::ParserRefInfoLoop(AVPacket *pkt, uint32_t curStreamId)
246 {
247     std::unique_lock<std::mutex> sLock(syncMutex_);
248     int ffmpegRet = av_read_frame(parserRefFormatContext_.get(), pkt);
249     sLock.unlock();
250     if (ffmpegRet < 0 && ffmpegRet != AVERROR_EOF) {
251         MEDIA_LOG_E("Call av_read_frame failed:" PUBLIC_LOG_S ", retry:" PUBLIC_LOG_D32,
252                     AVStrError(ffmpegRet).c_str(), int(parserRefIoContext_.retry));
253         if (parserRefIoContext_.retry) {
254             parserRefFormatContext_->pb->eof_reached = 0;
255             parserRefFormatContext_->pb->error = 0;
256             parserRefIoContext_.retry = false;
257             return Status::ERROR_AGAIN;
258         }
259         return Status::ERROR_UNKNOWN;
260     }
261     InsertIframePtsMap(pkt, parserCurGopId_, parserRefVideoStreamIdx_, iFramePtsMap_);
262     FALSE_RETURN_V_MSG_D(pkt->stream_index == parserRefVideoStreamIdx_ || ffmpegRet == AVERROR_EOF, Status::OK,
263                          "eos or not video");
264     int64_t dts = AvTime2Us(
265         ConvertTimeFromFFmpeg(pkt->dts, parserRefFormatContext_->streams[parserRefVideoStreamIdx_]->time_base));
266     Status result = referenceParser_->ParserNalUnits(pkt->data, pkt->size, curStreamId, dts);
267     FALSE_RETURN_V_MSG_E(result == Status::OK, Status::ERROR_UNKNOWN, "parse nal units error!");
268     int32_t iFramePosSize = static_cast<int32_t>(IFramePos_.size());
269     if (ffmpegRet == AVERROR_EOF || result != Status::OK ||
270         (parserCurGopId_ + 1 < iFramePosSize && curStreamId == IFramePos_[parserCurGopId_ + 1] - 1)) { // 处理完一个GOP
271         MEDIA_LOG_I("IFramePos: " PUBLIC_LOG_ZU ", processingIFrame: " PUBLIC_LOG_ZU ", curStreamId: " PUBLIC_LOG_U32
272             ", curGopId: " PUBLIC_LOG_U32, IFramePos_.size(), processingIFrame_.size(), curStreamId, parserCurGopId_);
273         processingIFrame_.remove(IFramePos_[parserCurGopId_]);
274         if (processingIFrame_.size() == 0) {
275             parserCurGopId_ = -1;
276             return Status::OK;
277         }
278         int32_t tmpGopId = parserCurGopId_;
279         int32_t searchCnt = 0;
280         while (formatContext_ != nullptr && std::find(processingIFrame_.begin(), processingIFrame_.end(),
281                                                       IFramePos_[parserCurGopId_]) == processingIFrame_.end()) {
282             if (updatePosIsForward_) {
283                 parserCurGopId_ = (parserCurGopId_ + 1) % iFramePosSize;
284             } else {
285                 parserCurGopId_ = parserCurGopId_ == 0 ? iFramePosSize - 1 : parserCurGopId_ - 1;
286             }
287             searchCnt++;
288             FALSE_RETURN_V_MSG_E(searchCnt < iFramePosSize, Status::ERROR_UNKNOWN, "Cannot find gop");
289         }
290         if (formatContext_ == nullptr || tmpGopId + 1 != parserCurGopId_ || !updatePosIsForward_) {
291             return Status::END_OF_STREAM;
292         }
293     }
294     return Status::OK;
295 }
296 
GetGopIdFromSeekPos(int64_t seekMs,int32_t & gopId)297 Status FFmpegDemuxerPlugin::GetGopIdFromSeekPos(int64_t seekMs, int32_t &gopId)
298 {
299     AVStream *st = parserRefFormatContext_->streams[parserRefVideoStreamIdx_];
300     FALSE_RETURN_V_MSG_E(st != nullptr, Status::ERROR_UNKNOWN, "AVStream is nullptr");
301     if (seekMs < 0) {
302         seekMs = 0;
303     }
304     int32_t iFrameIdx;
305     if (ptsListFromZero_.size() > 0) {
306         iFrameIdx = std::upper_bound(ptsListFromZero_.begin(), ptsListFromZero_.end(),
307             seekMs * MS_TO_SEC) - ptsListFromZero_.begin() - 1;
308         if (iFrameIdx < 0) {
309             iFrameIdx = static_cast<int32_t>(ptsListFromZero_.size()) - 1;
310         }
311         MEDIA_LOG_D("get I frame iFrameIdx from box parser");
312     } else {
313         int64_t orgPts = ConvertTimeToFFmpegByUs(seekMs * MS_TO_SEC, st->time_base);
314         FALSE_RETURN_V_MSG_E(orgPts >= 0, Status::ERROR_UNKNOWN,
315             "ffmpegTime is negative to seek " PUBLIC_LOG_D64, seekMs);
316         iFrameIdx = av_index_search_timestamp(st, orgPts + CalculateTimeByFrameIndex(st, 0), AVSEEK_FLAG_BACKWARD);
317         FALSE_RETURN_V_MSG_E(iFrameIdx >= 0, Status::ERROR_UNKNOWN,
318             "iFrameIdx is negative to seek " PUBLIC_LOG_D64, seekMs);
319         MEDIA_LOG_D("get I frame iFrameIdx from simulated dts");
320     }
321     gopId = std::upper_bound(IFramePos_.begin(), IFramePos_.end(), iFrameIdx) - IFramePos_.begin() - 1;
322     if (gopId < 0) {
323         gopId = static_cast<int32_t>(IFramePos_.size()) - 1;
324     }
325     return Status::OK;
326 }
327 
SelectProGopId()328 Status FFmpegDemuxerPlugin::SelectProGopId()
329 {
330     AVStream *st = parserRefFormatContext_->streams[parserRefVideoStreamIdx_];
331     FALSE_RETURN_V_MSG_E(st != nullptr, Status::ERROR_UNKNOWN, "AVStream is nullptr");
332     if (pendingSeekMsTime_ >= 0) {
333         FALSE_RETURN_V_MSG_E(GetGopIdFromSeekPos(pendingSeekMsTime_, parserCurGopId_) == Status::OK,
334             Status::ERROR_UNKNOWN, "GetGopIdFromSeekPos failed");
335         pendingSeekMsTime_ = -1;
336     }
337     int64_t ptsSeek;
338     if (iFramePtsMap_.find(parserCurGopId_) != iFramePtsMap_.end()) { // if I frame pts had got before decoding
339         ptsSeek = iFramePtsMap_[parserCurGopId_];
340         MEDIA_LOG_D("get I frame pts from which had been decoded");
341     } else {
342         int32_t iFramePosSize = static_cast<int32_t>(IFramePos_.size());
343         int64_t dtsCur = CalculateTimeByFrameIndex(st, IFramePos_[parserCurGopId_]);
344         if (parserCurGopId_ + 1 < iFramePosSize) {
345             int64_t dtsNext = CalculateTimeByFrameIndex(st, IFramePos_[parserCurGopId_ + 1]);
346             ptsSeek = dtsCur + (dtsNext - dtsCur) / 2; // 2 middle between cur gop and next gop
347         } else {
348             ptsSeek = INT64_MAX; // seek last gop
349         }
350         MEDIA_LOG_D("get I frame pts from simulated dts");
351     }
352     auto ret = av_seek_frame(parserRefFormatContext_.get(), parserRefVideoStreamIdx_, ptsSeek, AVSEEK_FLAG_BACKWARD);
353     FALSE_RETURN_V_MSG_E(ret >= 0, Status::ERROR_UNKNOWN,
354                          "Call av_seek_frame failed, err: " PUBLIC_LOG_S, AVStrError(ret).c_str());
355     return Status::OK;
356 }
357 
ParserRefInfo()358 Status FFmpegDemuxerPlugin::ParserRefInfo()
359 {
360     FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::OK, "AVFormatContext is nullptr");
361     if (!isInit_) {
362         isInit_ = true;
363         Status ret = ParserRefInit();
364         if (ret == Status::END_OF_STREAM) {
365             return Status::OK;
366         }
367         if (ret != Status::OK) {
368             return Status::ERROR_UNKNOWN;
369         }
370     }
371     int64_t duration = std::chrono::duration_cast<std::chrono::milliseconds>(
372         std::chrono::system_clock::now().time_since_epoch()).count() - parserRefStartTime_;
373     std::string suffix = std::to_string(duration) + "_" + std::to_string(parserCurGopId_);
374     MediaAVCodec::AVCodecTrace trace("ParserRefCost_2_" + suffix);
375     FALSE_RETURN_V_MSG_W(duration < REFERENCE_PARSER_TIMEOUT_MS, Status::ERROR_UNKNOWN, "Reference parser timeout");
376     FALSE_RETURN_V_MSG(parserCurGopId_ != -1, Status::OK, "Reference parser end"); // 参考关系解析完毕
377     FALSE_RETURN_V_MSG_E(SelectProGopId() == Status::OK, Status::ERROR_UNKNOWN, "Call selectProGopId failed");
378     uint32_t curStreamId = IFramePos_[parserCurGopId_];
379     MEDIA_LOG_I("curStreamId: " PUBLIC_LOG_U32 ", parserCurGopId: " PUBLIC_LOG_D32 ", IFramePos size: " PUBLIC_LOG_ZU
380         ", processingIFrame_ size: " PUBLIC_LOG_ZU ", duration: " PUBLIC_LOG_D64, curStreamId, parserCurGopId_,
381         IFramePos_.size(), processingIFrame_.size(), duration);
382     AVPacket *pkt = av_packet_alloc();
383     while (formatContext_ != nullptr && parserState_ && parserCurGopId_ != -1) {
384         Status rlt = ParserRefInfoLoop(pkt, curStreamId);
385         duration = std::chrono::duration_cast<std::chrono::milliseconds>(
386             std::chrono::system_clock::now().time_since_epoch()).count() - parserRefStartTime_;
387         suffix = std::to_string(duration) + "_" + std::to_string(parserCurGopId_) + "_" + std::to_string(curStreamId);
388         MediaAVCodec::AVCodecTrace traceInLoop("ParserRefCost_3_" + suffix);
389         FALSE_RETURN_V_MSG_W(duration < REFERENCE_PARSER_TIMEOUT_MS, Status::ERROR_UNKNOWN, "Reference parser timeout");
390         if (rlt != Status::OK) {
391             av_packet_unref(pkt);
392             av_packet_free(&pkt);
393             parserState_ = true;
394             return rlt;
395         }
396         if (pkt->stream_index == parserRefVideoStreamIdx_) {
397             curStreamId++;
398         }
399         av_packet_unref(pkt);
400     }
401 
402     av_packet_free(&pkt);
403     parserState_ = true;
404     return Status::ERROR_AGAIN;
405 }
406 
GetFrameLayerInfo(std::shared_ptr<AVBuffer> videoSample,FrameLayerInfo & frameLayerInfo)407 Status FFmpegDemuxerPlugin::GetFrameLayerInfo(std::shared_ptr<AVBuffer> videoSample, FrameLayerInfo &frameLayerInfo)
408 {
409     FALSE_RETURN_V_MSG_E(referenceParser_ != nullptr, Status::ERROR_NULL_POINTER, "Reference is nullptr");
410     MEDIA_LOG_D("In, dts: " PUBLIC_LOG_D64, videoSample->dts_);
411     if (isSdtpExist_) {
412         int64_t ffmpegDts = ConvertTimeToFFmpegByUs(
413             videoSample->dts_, parserRefFormatContext_->streams[parserRefVideoStreamIdx_]->time_base);
414         int32_t frameId = av_index_search_timestamp(
415             parserRefFormatContext_->streams[parserRefVideoStreamIdx_], ffmpegDts, AVSEEK_FLAG_ANY);
416         FALSE_RETURN_V_MSG_E(frameId >= 0, Status::ERROR_UNKNOWN, "Can not find frameId");
417         MEDIA_LOG_D("Get frameId: " PUBLIC_LOG_U32, frameId);
418         return referenceParser_->GetFrameLayerInfo(static_cast<uint32_t>(frameId), frameLayerInfo);
419     }
420     return referenceParser_->GetFrameLayerInfo(videoSample->dts_, frameLayerInfo);
421 }
422 
GetFrameLayerInfo(uint32_t frameId,FrameLayerInfo & frameLayerInfo)423 Status FFmpegDemuxerPlugin::GetFrameLayerInfo(uint32_t frameId, FrameLayerInfo &frameLayerInfo)
424 {
425     FALSE_RETURN_V_MSG_E(referenceParser_ != nullptr, Status::ERROR_NULL_POINTER, "Reference is nullptr");
426     MEDIA_LOG_D("In, dts: " PUBLIC_LOG_U32, frameId);
427     return referenceParser_->GetFrameLayerInfo(frameId, frameLayerInfo);
428 }
429 
GetGopLayerInfo(uint32_t gopId,GopLayerInfo & gopLayerInfo)430 Status FFmpegDemuxerPlugin::GetGopLayerInfo(uint32_t gopId, GopLayerInfo &gopLayerInfo)
431 {
432     FALSE_RETURN_V_MSG_E(referenceParser_ != nullptr, Status::ERROR_NULL_POINTER, "Reference is nullptr");
433     MEDIA_LOG_D("In, gopId: " PUBLIC_LOG_U32, gopId);
434     return referenceParser_->GetGopLayerInfo(gopId, gopLayerInfo);
435 }
436 
GetIFramePos(std::vector<uint32_t> & IFramePos)437 Status FFmpegDemuxerPlugin::GetIFramePos(std::vector<uint32_t> &IFramePos)
438 {
439     FALSE_RETURN_V_MSG_E(IFramePos_.size() > 0, Status::ERROR_UNKNOWN, "IFramePos size is 0");
440     IFramePos = IFramePos_;
441     return Status::OK;
442 }
443 
Dts2FrameId(int64_t dts,uint32_t & frameId,bool offset)444 Status FFmpegDemuxerPlugin::Dts2FrameId(int64_t dts, uint32_t &frameId, bool offset)
445 {
446     FALSE_RETURN_V_MSG_E(formatContext_ != nullptr, Status::OK, "AVFormatContext is nullptr");
447     int64_t ffmpegDts = ConvertTimeToFFmpegByUs(dts, formatContext_->streams[parserRefVideoStreamIdx_]->time_base);
448     int32_t tmpFrameId = av_index_search_timestamp(
449         formatContext_->streams[parserRefVideoStreamIdx_], ffmpegDts, AVSEEK_FLAG_ANY);
450     if (tmpFrameId >= 0) {
451         frameId = static_cast<uint32_t>(tmpFrameId);
452         if (!offset) {
453             frameId += dtsOffset_;
454         }
455     } else if (dts >= firstDts_) {
456         if (formatContext_->streams[parserRefVideoStreamIdx_]->nb_frames < 1) {
457             MEDIA_LOG_E("FrameId sub overflow");
458             return Status::ERROR_UNKNOWN;
459         }
460         frameId = static_cast<uint32_t>(formatContext_->streams[parserRefVideoStreamIdx_]->nb_frames) - 1;
461     } else {
462         frameId = 0;
463     }
464 
465     MEDIA_LOG_D("Out, frameId: " PUBLIC_LOG_D32 ", dts: " PUBLIC_LOG_D64, frameId, dts);
466     return Status::OK;
467 }
468 
469 } // namespace Ffmpeg
470 } // namespace Plugins
471 } // namespace Media
472 } // namespace OHOS