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