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