• 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     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