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