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 #include "pts_and_index_conversion.h"
17 
18 #include <algorithm>
19 #include <string>
20 #include "netinet/in.h"
21 #include "avcodec_trace.h"
22 #include "securec.h"
23 #include "common/log.h"
24 #include "meta/video_types.h"
25 
26 namespace {
27 constexpr OHOS::HiviewDFX::HiLogLabel LABEL = { LOG_CORE, LOG_DOMAIN_DEMUXER, "TimeAndIndexConversion" };
28 }
29 
30 namespace OHOS {
31 namespace Media {
32 const uint32_t BOX_HEAD_SIZE = 8;
33 const uint32_t PTS_AND_INDEX_CONVERSION_MAX_FRAMES = 36000;
34 const uint32_t BOX_HEAD_LARGE_SIZE = 16;
TimeAndIndexConversion()35 TimeAndIndexConversion::TimeAndIndexConversion()
36     : source_(std::make_shared<Source>())
37 {
38 };
39 
~TimeAndIndexConversion()40 TimeAndIndexConversion::~TimeAndIndexConversion()
41 {
42 };
43 
SetDataSource(const std::shared_ptr<MediaSource> & source)44 Status TimeAndIndexConversion::SetDataSource(const std::shared_ptr<MediaSource>& source)
45 {
46     MediaAVCodec::AVCODEC_SYNC_TRACE;
47     MEDIA_LOG_I("In");
48     FALSE_RETURN_V_MSG_E(source_ != nullptr, Status::ERROR_NULL_POINTER, "The source_ is nullptr");
49     auto res = source_->SetSource(source);
50     FALSE_RETURN_V_MSG_E(res == Status::OK, res, "Set source failed");
51     Status ret = source_->GetSize(mediaDataSize_);
52     FALSE_RETURN_V_MSG_E(ret == Status::OK, ret, "Get file size failed");
53 
54     if (!IsMP4orMOV()) {
55         MEDIA_LOG_E("Not a valid MP4 or MOV file");
56         return Status::ERROR_UNSUPPORTED_FORMAT;
57     } else {
58         MEDIA_LOG_D("It is a MP4 or MOV file");
59         StartParse();
60         return Status::OK;
61     }
62 };
63 
GetFirstVideoTrackIndex(uint32_t & trackIndex)64 Status TimeAndIndexConversion::GetFirstVideoTrackIndex(uint32_t &trackIndex)
65 {
66     for (auto trakInfo : trakInfoVec_) {
67         if (trakInfo.trakType == TrakType::TRAK_VIDIO) {
68             trackIndex = trakInfo.trakId;
69             return Status::OK;
70         }
71     }
72     return Status::ERROR_INVALID_DATA;
73 }
74 
ReadBufferFromDataSource(size_t bufSize,std::shared_ptr<Buffer> & buffer)75 void TimeAndIndexConversion::ReadBufferFromDataSource(size_t bufSize, std::shared_ptr<Buffer> &buffer)
76 {
77     FALSE_RETURN_MSG(buffer != nullptr, "Buffer is nullptr");
78     auto result = source_->SeekTo(offset_);
79     if (result != Status::OK) {
80         MEDIA_LOG_E("Seek to " PUBLIC_LOG_U64 " fail", offset_);
81         buffer = nullptr;
82         return;
83     }
84     result = source_->Read(0, buffer, offset_, bufSize);
85     if (result != Status::OK) {
86         MEDIA_LOG_E("Buffer read error");
87         buffer = nullptr;
88         return;
89     }
90 }
91 
StartParse()92 void TimeAndIndexConversion::StartParse()
93 {
94     source_->GetSize(fileSize_);
95     MEDIA_LOG_I("fileSize: " PUBLIC_LOG_D64, fileSize_);
96     while (offset_ < fileSize_) {
97         int bufSize = sizeof(uint32_t) + sizeof(uint32_t);
98         auto buffer = std::make_shared<Buffer>();
99         FALSE_RETURN_MSG(buffer != nullptr, "StartParse failed due to read buffer error");
100         std::vector<uint8_t> buff(bufSize);
101         auto bufData = buffer->WrapMemory(buff.data(), bufSize, bufSize);
102         ReadBufferFromDataSource(bufSize, buffer);
103         FALSE_RETURN_MSG(buffer != nullptr, "StartParse failed due to read buffer error");
104         BoxHeader header{0};
105         ReadBoxHeader(buffer, header);
106         FALSE_RETURN_MSG(header.size >= 0, "StartParse failed due to error box size");
107         uint64_t boxSize = static_cast<uint64_t>(header.size);
108         uint32_t headerSize = BOX_HEAD_SIZE;
109         if (boxSize == 1 || boxSize == 0) { // 0 and 1 are used to verify whether there is a large size
110             uint64_t largeSize = 0;
111             ReadLargeSize(buffer, largeSize);
112             boxSize = largeSize;
113             headerSize = BOX_HEAD_LARGE_SIZE;
114         }
115         FALSE_RETURN_MSG(boxSize >= headerSize, "StartParse failed due to error box size");
116         if (strncmp(header.type, BOX_TYPE_MOOV, sizeof(header.type)) == 0) {
117             offset_ += headerSize;
118             ParseMoov(boxSize - headerSize);
119         } else {
120             offset_ += boxSize;
121         }
122     }
123 }
124 
ReadLargeSize(std::shared_ptr<Buffer> buffer,uint64_t & largeSize)125 void TimeAndIndexConversion::ReadLargeSize(std::shared_ptr<Buffer> buffer, uint64_t &largeSize)
126 {
127     offset_ += BOX_HEAD_SIZE;
128     FALSE_RETURN_MSG(buffer != nullptr, "ReadLargeSize failed due to read buffer error");
129     int bufSize = sizeof(uint64_t); // The type of largeSize is uint64_t
130     ReadBufferFromDataSource(bufSize, buffer);
131     FALSE_RETURN_MSG(buffer != nullptr, "ReadLargeSize failed due to read buffer error");
132     auto memory = buffer->GetMemory();
133     FALSE_RETURN_MSG(memory != nullptr, "No memory in buffer");
134     const uint8_t* ptr = memory->GetReadOnlyData();
135     FALSE_RETURN_MSG(ptr != nullptr, "ReadLargeSize failed due to nullptr");
136     size_t size = memory->GetSize();
137     FALSE_RETURN_MSG(size >= sizeof(uint64_t), "Not enough data in buffer to read large size");
138     largeSize = ntohl(*reinterpret_cast<const uint64_t*>(ptr));
139     offset_ -= BOX_HEAD_SIZE;
140 }
141 
ReadBoxHeader(std::shared_ptr<Buffer> buffer,BoxHeader & header)142 void TimeAndIndexConversion::ReadBoxHeader(std::shared_ptr<Buffer> buffer, BoxHeader &header)
143 {
144     auto memory = buffer->GetMemory();
145     FALSE_RETURN_MSG(memory != nullptr, "No memory in buffer");
146     const uint8_t* ptr = memory->GetReadOnlyData();
147     FALSE_RETURN_MSG(ptr != nullptr, "ReadBoxHeader failed due to nullptr");
148     size_t size = memory->GetSize();
149     FALSE_RETURN_MSG(size >= sizeof(header.size) + 4,  // 4 is used to check data
150         "Not enough data in buffer to read BoxHeader");
151     header.size = ntohl(*reinterpret_cast<const uint32_t*>(ptr));
152     header.type[0] = ptr[sizeof(header.size)]; // Get the 1st character of the header
153     header.type[1] = ptr[sizeof(header.size) + 1]; // Get the 2nd character of the header
154     header.type[2] = ptr[sizeof(header.size) + 2]; // Get the 3rd character of the header
155     header.type[3] = ptr[sizeof(header.size) + 3]; // Get the 4th character of the header
156     header.type[4] = '\0'; // Supplement string tail
157 }
158 
IsMP4orMOV()159 bool TimeAndIndexConversion::IsMP4orMOV()
160 {
161     int bufSize = sizeof(uint32_t) + sizeof(uint32_t);
162     auto buffer = std::make_shared<Buffer>();
163     FALSE_RETURN_V_MSG_E(buffer != nullptr, false, "IsMP4orMOV failed due to read buffer error");
164     std::vector<uint8_t> buff(bufSize);
165     auto bufData = buffer->WrapMemory(buff.data(), bufSize, bufSize);
166     ReadBufferFromDataSource(bufSize, buffer);
167     FALSE_RETURN_V_MSG_E(buffer != nullptr, false, "IsMP4orMOV failed due to read buffer error");
168     BoxHeader header{0};
169     ReadBoxHeader(buffer, header);
170     offset_ = 0; // init offset_
171     return strncmp(header.type, BOX_TYPE_FTYP, sizeof(header.type)) == 0;
172 }
173 
ParseMoov(uint32_t boxSize)174 void TimeAndIndexConversion::ParseMoov(uint32_t boxSize)
175 {
176     uint64_t parentSize = offset_ + static_cast<uint64_t>(boxSize);
177     while (offset_ < parentSize) {
178         int bufSize = sizeof(uint32_t) + sizeof(uint32_t);
179         auto buffer = std::make_shared<Buffer>();
180         FALSE_RETURN_MSG(buffer != nullptr, "ParseMoov failed due to read buffer error");
181         std::vector<uint8_t> buff(bufSize);
182         auto bufData = buffer->WrapMemory(buff.data(), bufSize, bufSize);
183         ReadBufferFromDataSource(bufSize, buffer);
184         FALSE_RETURN_MSG(buffer != nullptr, "ParseMoov failed due to read buffer error");
185         BoxHeader header{0};
186         ReadBoxHeader(buffer, header);
187         FALSE_RETURN_MSG(header.size >= 0, "ParseMoov failed due to error box size");
188         uint64_t childBoxSize = static_cast<uint64_t>(header.size);
189         uint32_t headerSize = BOX_HEAD_SIZE;
190         if (childBoxSize == 1 || childBoxSize == 0) { // 0 and 1 are used to verify whether there is a large size
191             uint64_t largeSize = 0;
192             ReadLargeSize(buffer, largeSize);
193             childBoxSize = largeSize;
194             headerSize = BOX_HEAD_LARGE_SIZE;
195         }
196         FALSE_RETURN_MSG(childBoxSize >= headerSize, "ParseMoov failed due to error box size");
197         if (strncmp(header.type, BOX_TYPE_TRAK, sizeof(header.type)) == 0) {
198             offset_ += headerSize;
199             ParseTrak(childBoxSize - headerSize);
200         } else {
201             offset_ += childBoxSize;
202         }
203     }
204 }
205 
ParseTrak(uint32_t boxSize)206 void TimeAndIndexConversion::ParseTrak(uint32_t boxSize)
207 {
208     MEDIA_LOG_D("curTrakInfoIndex_: " PUBLIC_LOG_D32, curTrakInfoIndex_);
209     curTrakInfo_.trakId = curTrakInfoIndex_;
210     ParseBox(boxSize - BOX_HEAD_SIZE);
211     trakInfoVec_.push_back(curTrakInfo_);
212     curTrakInfo_.cttsEntries.clear();
213     curTrakInfo_.sttsEntries.clear();
214     curTrakInfoIndex_++;
215 }
216 
ParseBox(uint32_t boxSize)217 void TimeAndIndexConversion::ParseBox(uint32_t boxSize)
218 {
219     uint64_t parentSize = offset_ + static_cast<uint64_t>(boxSize);
220     while (offset_ < parentSize) {
221         int bufSize = sizeof(uint32_t) + sizeof(uint32_t);
222         auto buffer = std::make_shared<Buffer>();
223         FALSE_RETURN_MSG(buffer != nullptr, "ParseBox failed due to read buffer error");
224         std::vector<uint8_t> buff(bufSize);
225         auto bufData = buffer->WrapMemory(buff.data(), bufSize, bufSize);
226         ReadBufferFromDataSource(bufSize, buffer);
227         FALSE_RETURN_MSG(buffer != nullptr, "ParseBox failed due to read buffer error");
228         BoxHeader header{0};
229         ReadBoxHeader(buffer, header);
230         FALSE_RETURN_MSG(header.size >= 0, "ParseBox failed due to error box size");
231         uint64_t childBoxSize = static_cast<uint64_t>(header.size);
232         uint32_t headerSize = BOX_HEAD_SIZE;
233         if (childBoxSize == 1 || childBoxSize == 0) { // 0 and 1 are used to verify whether there is a large size
234             uint64_t largeSize = 0;
235             ReadLargeSize(buffer, largeSize);
236             childBoxSize = largeSize;
237             headerSize = BOX_HEAD_LARGE_SIZE;
238         }
239         FALSE_RETURN_MSG(childBoxSize >= headerSize, "ParseBox failed due to error box size");
240         auto it = boxParsers.find(std::string(header.type));
241         if (it != boxParsers.end()) {
242             offset_ += headerSize;
243             (this->*(it->second))(childBoxSize - headerSize);
244         } else {
245             offset_ += childBoxSize;
246         }
247     }
248 }
249 
ParseCtts(uint32_t boxSize)250 void TimeAndIndexConversion::ParseCtts(uint32_t boxSize)
251 {
252     auto buffer = std::make_shared<Buffer>();
253     std::vector<uint8_t> buff(boxSize);
254     auto bufData = buffer->WrapMemory(buff.data(), boxSize, boxSize);
255     auto result = source_->Read(0, buffer, offset_, boxSize);
256     FALSE_RETURN_MSG(result == Status::OK, "ParseCtts failed due to read buffer error");
257     auto memory = buffer->GetMemory();
258     FALSE_RETURN_MSG(memory != nullptr, "ParseCtts failed due to no memory in buffer");
259     const uint8_t* ptr = memory->GetReadOnlyData();
260     FALSE_RETURN_MSG(ptr != nullptr, "ParseCtts failed due to nullptr");
261     size_t size = memory->GetSize();
262     if (size < sizeof(uint32_t) * 2) { // 2 is used to check data
263         MEDIA_LOG_E("Not enough data in buffer to read CTTS header");
264         return;
265     }
266     // read versionAndFlags and entryCount
267     uint32_t versionAndFlags = *reinterpret_cast<const uint32_t*>(ptr);
268     MEDIA_LOG_D("versionAndFlags: " PUBLIC_LOG_D32, versionAndFlags);
269     uint32_t entryCount = *reinterpret_cast<const uint32_t*>(ptr + sizeof(uint32_t));
270     entryCount = ntohl(entryCount);
271     // Check if the remaining data is sufficient
272     if (size < sizeof(uint32_t) * 2 + entryCount * sizeof(CTTSEntry)) { // 2 is used to check data
273         return;
274     }
275     std::vector<CTTSEntry> entries(entryCount);
276     const uint8_t* entryPtr = ptr + sizeof(uint32_t) * 2; // 2 is used to skip versionAndFlags and entryCount
277     for (uint32_t i = 0; i < entryCount; ++i) {
278         entries[i].sampleCount = ntohl(*reinterpret_cast<const uint32_t*>(entryPtr));
279         entries[i].sampleOffset = static_cast<int32_t>(ntohl(*reinterpret_cast<const uint32_t*>(entryPtr +
280                                   sizeof(uint32_t))));
281         entryPtr += sizeof(CTTSEntry);
282     }
283     curTrakInfo_.cttsEntries = entries;
284     offset_ += static_cast<uint64_t>(boxSize);
285 }
286 
ParseStts(uint32_t boxSize)287 void TimeAndIndexConversion::ParseStts(uint32_t boxSize)
288 {
289     auto buffer = std::make_shared<Buffer>();
290     std::vector<uint8_t> buff(boxSize);
291     auto bufData = buffer->WrapMemory(buff.data(), boxSize, boxSize);
292     auto result = source_->Read(0, buffer, offset_, boxSize);
293     FALSE_RETURN_MSG(result == Status::OK, "ParseStts failed due to read buffer error");
294     auto memory = buffer->GetMemory();
295     FALSE_RETURN_MSG(memory != nullptr, "ParseStts failed due to no memory in buffer");
296     const uint8_t* ptr = memory->GetReadOnlyData();
297     FALSE_RETURN_MSG(ptr != nullptr, "ParseStts failed due to nullptr");
298     size_t size = memory->GetSize();
299     if (size < sizeof(uint32_t) * 2) { // 2 is used to check data
300         MEDIA_LOG_E("Not enough data in buffer to read STTS header");
301         return;
302     }
303     // read versionAndFlags and entryCount
304     uint32_t versionAndFlags = *reinterpret_cast<const uint32_t*>(ptr);
305     MEDIA_LOG_D("versionAndFlags: " PUBLIC_LOG_D32, versionAndFlags);
306     uint32_t entryCount = *reinterpret_cast<const uint32_t*>(ptr + sizeof(uint32_t));
307     entryCount = ntohl(entryCount);
308     // Check if the remaining data is sufficient
309     if (size < sizeof(uint32_t) * 2 + entryCount * sizeof(STTSEntry)) { // 2 is used to check data
310         return;
311     }
312     std::vector<STTSEntry> entries(entryCount);
313     const uint8_t* entryPtr = ptr + sizeof(uint32_t) * 2; // 2 is used to skip versionAndFlags and entryCount
314     for (uint32_t i = 0; i < entryCount; ++i) {
315         entries[i].sampleCount = ntohl(*reinterpret_cast<const uint32_t*>(entryPtr));
316         entries[i].sampleDelta = ntohl(*reinterpret_cast<const uint32_t*>(entryPtr + sizeof(uint32_t)));
317         entryPtr += sizeof(STTSEntry);
318     }
319     curTrakInfo_.sttsEntries = entries;
320     offset_ += static_cast<uint64_t>(boxSize);
321 }
322 
ParseHdlr(uint32_t boxSize)323 void TimeAndIndexConversion::ParseHdlr(uint32_t boxSize)
324 {
325     auto buffer = std::make_shared<Buffer>();
326     std::vector<uint8_t> buff(boxSize);
327     auto bufData = buffer->WrapMemory(buff.data(), boxSize, boxSize);
328     auto result = source_->Read(0, buffer, offset_, boxSize);
329     FALSE_RETURN_MSG(result == Status::OK, "ParseHdlr failed due to read buffer error");
330     auto memory = buffer->GetMemory();
331     FALSE_RETURN_MSG(memory != nullptr, "ParseHdlr failed due to no memory in buffer");
332     const uint8_t* ptr = memory->GetReadOnlyData();
333     FALSE_RETURN_MSG(ptr != nullptr, "ParseHdlr failed due to nullptr");
334     size_t size = memory->GetSize();
335     if (size < sizeof(uint32_t) * 3) { // 3 is versionAndFlags + entryCount + handlerType
336         MEDIA_LOG_E("Not enough data in buffer to read HDLR header");
337         return;
338     }
339     // skip versionAndFlags
340     ptr += sizeof(uint32_t);
341     // skip reDefined
342     ptr += sizeof(uint32_t);
343     // read handlerType
344     std::string handlerType = "";
345     handlerType.append(std::string(1, static_cast<char>(ptr[0]))); // Get the 1st character of the handlerType
346     handlerType.append(std::string(1, static_cast<char>(ptr[1]))); // Get the 2nd character of the handlerType
347     handlerType.append(std::string(1, static_cast<char>(ptr[2]))); // Get the 3rd character of the handlerType
348     handlerType.append(std::string(1, static_cast<char>(ptr[3]))); // Get the 4th character of the handlerType
349     if (handlerType == "soun") {
350         curTrakInfo_.trakType = TrakType::TRAK_AUDIO;
351     } else if (handlerType == "vide") {
352         curTrakInfo_.trakType = TrakType::TRAK_VIDIO;
353     } else {
354         curTrakInfo_.trakType = TrakType::TRAK_OTHER;
355     }
356     offset_ += static_cast<uint64_t>(boxSize);
357 }
358 
ParseMdhd(uint32_t boxSize)359 void TimeAndIndexConversion::ParseMdhd(uint32_t boxSize)
360 {
361     auto buffer = std::make_shared<Buffer>();
362     std::vector<uint8_t> buff(boxSize);
363     auto bufData = buffer->WrapMemory(buff.data(), boxSize, boxSize);
364     auto result = source_->Read(0, buffer, offset_, boxSize);
365     FALSE_RETURN_MSG(result == Status::OK, "ParseMdhd failed due to read buffer error");
366     auto memory = buffer->GetMemory();
367     FALSE_RETURN_MSG(memory != nullptr, "ParseMdhd failed due to no memory in buffer");
368     const uint8_t* ptr = memory->GetReadOnlyData();
369     FALSE_RETURN_MSG(ptr != nullptr, "ParseMdhd failed due to nullptr");
370     size_t size = memory->GetSize();
371     if (size < sizeof(uint32_t) * 3) { // 3 is used to check for version, flags, and creation_time
372         MEDIA_LOG_E("Not enough data in buffer to read MDHD header");
373         return;
374     }
375     // 读取versionAndFlags,creation_time,modification_time,timeScale,和duration
376     uint32_t versionAndFlags = *reinterpret_cast<const uint32_t*>(ptr);
377     MEDIA_LOG_D("versionAndFlags: " PUBLIC_LOG_D32, versionAndFlags);
378     uint32_t timeScale = *reinterpret_cast<const uint32_t*>(ptr + sizeof(uint32_t) * 3); // 3 is used to check data
379     timeScale = ntohl(timeScale);
380     MEDIA_LOG_D("timeScale: " PUBLIC_LOG_D32, timeScale);
381     curTrakInfo_.timeScale = timeScale;
382     offset_ += static_cast<uint64_t>(boxSize);
383 }
384 
InitPTSandIndexConvert()385 void TimeAndIndexConversion::InitPTSandIndexConvert()
386 {
387     indexToRelativePTSFrameCount_ = 0; // init IndexToRelativePTSFrameCount_
388     relativePTSToIndexPosition_ = 0; // init RelativePTSToIndexPosition_
389     indexToRelativePTSMaxHeap_ = std::priority_queue<int64_t>(); // init IndexToRelativePTSMaxHeap_
390     relativePTSToIndexPTSMin_ = INT64_MAX;
391     relativePTSToIndexPTSMax_ = INT64_MIN;
392     relativePTSToIndexRightDiff_ = INT64_MAX;
393     relativePTSToIndexLeftDiff_ = INT64_MAX;
394     relativePTSToIndexTempDiff_ = INT64_MAX;
395 }
396 
IsWithinPTSAndIndexConversionMaxFrames(uint32_t trackIndex)397 bool TimeAndIndexConversion::IsWithinPTSAndIndexConversionMaxFrames(uint32_t trackIndex)
398 {
399     uint32_t frames = 0;
400     for (auto sttsEntry : trakInfoVec_[trackIndex].sttsEntries) {
401         FALSE_RETURN_V_MSG_E(frames <= UINT32_MAX - sttsEntry.sampleCount, false, "Frame count exceeds limit");
402         frames += sttsEntry.sampleCount;
403         FALSE_RETURN_V_MSG_E(frames <= PTS_AND_INDEX_CONVERSION_MAX_FRAMES, false, "Frame count exceeds limit");
404     }
405     return true;
406 }
407 
GetIndexByRelativePresentationTimeUs(const uint32_t trackIndex,const uint64_t relativePresentationTimeUs,uint32_t & index)408 Status TimeAndIndexConversion::GetIndexByRelativePresentationTimeUs(const uint32_t trackIndex,
409     const uint64_t relativePresentationTimeUs, uint32_t &index)
410 {
411     FALSE_RETURN_V_MSG_E(trackIndex < trakInfoVec_.size(), Status::ERROR_INVALID_DATA, "Track is out of range");
412     bool frameCheck = IsWithinPTSAndIndexConversionMaxFrames(trackIndex);
413     FALSE_RETURN_V_MSG_E(frameCheck, Status::ERROR_INVALID_DATA, "Frame count exceeds limit");
414     InitPTSandIndexConvert();
415     Status ret = GetPresentationTimeUsFromFfmpegMOV(GET_FIRST_PTS, trackIndex,
416         static_cast<int64_t>(relativePresentationTimeUs), index);
417     FALSE_RETURN_V_MSG_E(ret == Status::OK, Status::ERROR_UNKNOWN, "Get pts failed");
418 
419     int64_t absolutePTS = static_cast<int64_t>(relativePresentationTimeUs) + absolutePTSIndexZero_;
420 
421     ret = GetPresentationTimeUsFromFfmpegMOV(RELATIVEPTS_TO_INDEX, trackIndex,
422         absolutePTS, index);
423     FALSE_RETURN_V_MSG_E(ret == Status::OK, Status::ERROR_UNKNOWN, "Get pts failed");
424 
425     if (absolutePTS < relativePTSToIndexPTSMin_ || absolutePTS > relativePTSToIndexPTSMax_) {
426         MEDIA_LOG_E("Pts is out of range");
427         return Status::ERROR_INVALID_DATA;
428     }
429 
430     if (relativePTSToIndexLeftDiff_ == 0 || relativePTSToIndexRightDiff_ == 0) {
431         index = relativePTSToIndexPosition_;
432     } else {
433         index = relativePTSToIndexLeftDiff_ < relativePTSToIndexRightDiff_ ?
434         relativePTSToIndexPosition_ - 1 : relativePTSToIndexPosition_;
435     }
436     return Status::OK;
437 }
438 
GetRelativePresentationTimeUsByIndex(const uint32_t trackIndex,const uint32_t index,uint64_t & relativePresentationTimeUs)439 Status TimeAndIndexConversion::GetRelativePresentationTimeUsByIndex(const uint32_t trackIndex,
440     const uint32_t index, uint64_t &relativePresentationTimeUs)
441 {
442     FALSE_RETURN_V_MSG_E(trackIndex < trakInfoVec_.size(), Status::ERROR_INVALID_DATA, "Track is out of range");
443     bool frameCheck = IsWithinPTSAndIndexConversionMaxFrames(trackIndex);
444     FALSE_RETURN_V_MSG_E(frameCheck, Status::ERROR_INVALID_DATA, "Frame count exceeds limit");
445     InitPTSandIndexConvert();
446     Status ret = GetPresentationTimeUsFromFfmpegMOV(GET_FIRST_PTS, trackIndex,
447         static_cast<int64_t>(relativePresentationTimeUs), index);
448     FALSE_RETURN_V_MSG_E(ret == Status::OK, Status::ERROR_UNKNOWN, "Get pts failed");
449 
450     GetPresentationTimeUsFromFfmpegMOV(INDEX_TO_RELATIVEPTS, trackIndex,
451         static_cast<int64_t>(relativePresentationTimeUs), index);
452     FALSE_RETURN_V_MSG_E(ret == Status::OK, Status::ERROR_UNKNOWN, "Get pts failed");
453 
454     if (index + 1 > indexToRelativePTSFrameCount_) {
455         MEDIA_LOG_E("Index is out of range");
456         return Status::ERROR_INVALID_DATA;
457     }
458 
459     int64_t relativepts = indexToRelativePTSMaxHeap_.top() - absolutePTSIndexZero_;
460     FALSE_RETURN_V_MSG_E(relativepts >= 0, Status::ERROR_INVALID_DATA, "Existence of calculation results less than 0");
461     relativePresentationTimeUs = static_cast<uint64_t>(relativepts);
462 
463     return Status::OK;
464 }
465 
PTSAndIndexConvertSttsAndCttsProcess(IndexAndPTSConvertMode mode,int64_t absolutePTS,uint32_t index)466 Status TimeAndIndexConversion::PTSAndIndexConvertSttsAndCttsProcess(IndexAndPTSConvertMode mode,
467     int64_t absolutePTS, uint32_t index)
468 {
469     uint32_t sttsIndex = 0;
470     uint32_t cttsIndex = 0;
471     int64_t pts = 0; // init pts
472     int64_t dts = 0; // init dts
473     uint32_t sttsCount = trakInfoVec_[curConvertTrakInfoIndex_].sttsEntries.size();
474     uint32_t cttsCount = trakInfoVec_[curConvertTrakInfoIndex_].cttsEntries.size();
475     uint32_t sttsCurNum = trakInfoVec_[curConvertTrakInfoIndex_].sttsEntries[sttsIndex].sampleCount;
476     uint32_t cttsCurNum = trakInfoVec_[curConvertTrakInfoIndex_].cttsEntries[cttsIndex].sampleCount;
477     while (sttsIndex < sttsCount && cttsIndex < cttsCount) {
478         if (cttsCurNum == 0) {
479             cttsIndex++;
480             if (cttsIndex >= cttsCount) {
481                 break;
482             }
483             cttsCurNum = trakInfoVec_[curConvertTrakInfoIndex_].cttsEntries[cttsIndex].sampleCount;
484         }
485         if (cttsCurNum == 0) {
486             break;
487         }
488         cttsCurNum--;
489         if ((INT64_MAX / 1000 / 1000) < // 1000 is used for converting pts to us
490             ((dts + static_cast<int64_t>(trakInfoVec_[curConvertTrakInfoIndex_].cttsEntries[cttsIndex].sampleOffset)) /
491             static_cast<int64_t>(trakInfoVec_[curConvertTrakInfoIndex_].timeScale))) {
492                 MEDIA_LOG_E("pts overflow");
493                 return Status::ERROR_INVALID_DATA;
494         }
495         double timeScaleRate = 1000 * 1000 / // 1000 is used for converting pts to us
496                                 static_cast<double>(trakInfoVec_[curConvertTrakInfoIndex_].timeScale);
497         double ptsTemp = static_cast<double>(dts) +
498             static_cast<double>(trakInfoVec_[curConvertTrakInfoIndex_].cttsEntries[cttsIndex].sampleOffset);
499         pts = static_cast<int64_t>(ptsTemp * timeScaleRate);
500         PTSAndIndexConvertSwitchProcess(mode, pts, absolutePTS, index);
501         if (sttsCurNum == 0) {
502             break;
503         }
504         sttsCurNum--;
505         dts += static_cast<int64_t>(trakInfoVec_[curConvertTrakInfoIndex_].sttsEntries[sttsIndex].sampleDelta);
506         if (sttsCurNum == 0) {
507             sttsIndex++;
508             sttsCurNum = sttsIndex < sttsCount ?
509                          trakInfoVec_[curConvertTrakInfoIndex_].sttsEntries[sttsIndex].sampleCount : 0;
510         }
511     }
512     return Status::OK;
513 }
514 
PTSAndIndexConvertOnlySttsProcess(IndexAndPTSConvertMode mode,int64_t absolutePTS,uint32_t index)515 Status TimeAndIndexConversion::PTSAndIndexConvertOnlySttsProcess(IndexAndPTSConvertMode mode,
516     int64_t absolutePTS, uint32_t index)
517 {
518     uint32_t sttsIndex = 0;
519     int64_t pts = 0; // init pts
520     int64_t dts = 0; // init dts
521     uint32_t sttsCount = trakInfoVec_[curConvertTrakInfoIndex_].sttsEntries.size();
522     uint32_t sttsCurNum = trakInfoVec_[curConvertTrakInfoIndex_].sttsEntries[sttsIndex].sampleCount;
523 
524     while (sttsIndex < sttsCount) {
525         if ((INT64_MAX / 1000 / 1000) < // 1000 is used for converting pts to us
526             (dts / static_cast<int64_t>(trakInfoVec_[curConvertTrakInfoIndex_].timeScale))) {
527                 MEDIA_LOG_E("pts overflow");
528                 return Status::ERROR_INVALID_DATA;
529         }
530         double timeScaleRate = 1000 * 1000 / // 1000 is used for converting pts to us
531                                 static_cast<double>(trakInfoVec_[curConvertTrakInfoIndex_].timeScale);
532         double ptsTemp = static_cast<double>(dts);
533         pts = static_cast<int64_t>(ptsTemp * timeScaleRate);
534         PTSAndIndexConvertSwitchProcess(mode, pts, absolutePTS, index);
535         if (sttsCurNum == 0) {
536             break;
537         }
538         sttsCurNum--;
539         if ((INT64_MAX - dts) <
540             (static_cast<int64_t>(trakInfoVec_[curConvertTrakInfoIndex_].sttsEntries[sttsIndex].sampleDelta))) {
541             MEDIA_LOG_E("dts overflow");
542             return Status::ERROR_INVALID_DATA;
543         }
544         dts += static_cast<int64_t>(trakInfoVec_[curConvertTrakInfoIndex_].sttsEntries[sttsIndex].sampleDelta);
545         if (sttsCurNum == 0) {
546             sttsIndex++;
547             sttsCurNum = sttsIndex < sttsCount ?
548                          trakInfoVec_[curConvertTrakInfoIndex_].sttsEntries[sttsIndex].sampleCount : 0;
549         }
550     }
551     return Status::OK;
552 }
553 
GetPresentationTimeUsFromFfmpegMOV(IndexAndPTSConvertMode mode,uint32_t trackIndex,int64_t absolutePTS,uint32_t index)554 Status TimeAndIndexConversion::GetPresentationTimeUsFromFfmpegMOV(IndexAndPTSConvertMode mode,
555     uint32_t trackIndex, int64_t absolutePTS, uint32_t index)
556 {
557     curConvertTrakInfoIndex_ = trackIndex;
558     FALSE_RETURN_V_MSG_E(trakInfoVec_[curConvertTrakInfoIndex_].timeScale != 0,
559                          Status::ERROR_INVALID_DATA, "timeScale_ is zero");
560     FALSE_RETURN_V_MSG_E(trakInfoVec_[curConvertTrakInfoIndex_].sttsEntries.size(),
561         Status::ERROR_INVALID_DATA, "PTS is empty");
562     return !trakInfoVec_[curConvertTrakInfoIndex_].cttsEntries.size() ?
563         PTSAndIndexConvertOnlySttsProcess(mode, absolutePTS, index) :
564         PTSAndIndexConvertSttsAndCttsProcess(mode, absolutePTS, index);
565 }
566 
PTSAndIndexConvertSwitchProcess(IndexAndPTSConvertMode mode,int64_t pts,int64_t absolutePTS,uint32_t index)567 void TimeAndIndexConversion::PTSAndIndexConvertSwitchProcess(IndexAndPTSConvertMode mode,
568     int64_t pts, int64_t absolutePTS, uint32_t index)
569 {
570     switch (mode) {
571         case GET_FIRST_PTS:
572             absolutePTSIndexZero_ = pts < absolutePTSIndexZero_ ? pts : absolutePTSIndexZero_;
573             break;
574         case INDEX_TO_RELATIVEPTS:
575             IndexToRelativePTSProcess(pts, index);
576             break;
577         case RELATIVEPTS_TO_INDEX:
578             RelativePTSToIndexProcess(pts, absolutePTS);
579             break;
580         default:
581             MEDIA_LOG_E("Wrong mode");
582             break;
583     }
584 }
585 
IndexToRelativePTSProcess(int64_t pts,uint32_t index)586 void TimeAndIndexConversion::IndexToRelativePTSProcess(int64_t pts, uint32_t index)
587 {
588     if (indexToRelativePTSMaxHeap_.size() < index + 1) {
589         indexToRelativePTSMaxHeap_.push(pts);
590     } else {
591         if (pts < indexToRelativePTSMaxHeap_.top()) {
592             indexToRelativePTSMaxHeap_.pop();
593             indexToRelativePTSMaxHeap_.push(pts);
594         }
595     }
596     indexToRelativePTSFrameCount_++;
597 }
598 
RelativePTSToIndexProcess(int64_t pts,int64_t absolutePTS)599 void TimeAndIndexConversion::RelativePTSToIndexProcess(int64_t pts, int64_t absolutePTS)
600 {
601     if (relativePTSToIndexPTSMin_ > pts) {
602         relativePTSToIndexPTSMin_ = pts;
603     }
604     if (relativePTSToIndexPTSMax_ < pts) {
605         relativePTSToIndexPTSMax_ = pts;
606     }
607     relativePTSToIndexTempDiff_ = abs(pts - absolutePTS);
608     if (pts < absolutePTS && relativePTSToIndexTempDiff_ < relativePTSToIndexLeftDiff_) {
609         relativePTSToIndexLeftDiff_ = relativePTSToIndexTempDiff_;
610     }
611     if (pts >= absolutePTS && relativePTSToIndexTempDiff_ < relativePTSToIndexRightDiff_) {
612         relativePTSToIndexRightDiff_ = relativePTSToIndexTempDiff_;
613     }
614     if (pts < absolutePTS) {
615         relativePTSToIndexPosition_++;
616     }
617 }
618 } // namespace Media
619 } // namespace OHOS