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