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