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