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 <cinttypes>
17 #include <cstdio>
18 #include <fcntl.h>
19 #include <iostream>
20 #include <malloc.h>
21 #include <string>
22 #include <thread>
23 #include <sys/stat.h>
24 #include <fstream>
25 #include <ctime>
26 #include "native_avbuffer.h"
27 #include "inner_demuxer_sample.h"
28 #include "native_avcodec_base.h"
29 #include "meta/format.h"
30 #include "avcodec_errors.h"
31 #include "avcodec_common.h"
32 #include "native_avformat.h"
33 #include "av_common.h"
34 #include <random>
35 #include "avmuxer.h"
36 #include "media_description.h"
37
38 using namespace std;
39 using namespace OHOS::MediaAVCodec;
40 using namespace OHOS::Media;
41 namespace OHOS {
42 namespace MediaAVCodec {
InnerDemuxerSample()43 InnerDemuxerSample::InnerDemuxerSample()
44 {
45 }
46
~InnerDemuxerSample()47 InnerDemuxerSample::~InnerDemuxerSample()
48 {
49 if (fd > 0) {
50 close(fd);
51 fd = 0;
52 }
53 }
54
InitWithFile(const std::string & path,bool local)55 int32_t InnerDemuxerSample::InitWithFile(const std::string &path, bool local)
56 {
57 if (local) {
58 fd = open(path.c_str(), O_RDONLY);
59 int64_t size = GetFileSize(path);
60 this->avsource_ = AVSourceFactory::CreateWithFD(fd, 0, size);
61 } else {
62 this->avsource_ = AVSourceFactory::CreateWithURI(const_cast<char*>(path.data()));
63 }
64 if (!avsource_) {
65 printf("Source is null\n");
66 return -1;
67 }
68 this->demuxer_ = AVDemuxerFactory::CreateWithSource(avsource_);
69 if (!demuxer_) {
70 printf("AVDemuxerFactory::CreateWithSource is failed\n");
71 return -1;
72 }
73 int32_t ret = this->avsource_->GetSourceFormat(source_format_);
74 if (ret != 0) {
75 printf("GetSourceFormat is failed\n");
76 return ret;
77 }
78 source_format_.GetIntValue(OH_MD_KEY_TRACK_COUNT, trackCount);
79 source_format_.GetLongValue(OH_MD_KEY_DURATION, duration);
80 printf("====>total tracks:%d duration:%" PRId64 "\n", trackCount, duration);
81 int32_t trackType = 0;
82 for (int32_t i = 0; i < trackCount; i++) {
83 ret = this->avsource_->GetTrackFormat(track_format_, i);
84 if (ret != 0) {
85 printf("GetTrackFormat is failed\n");
86 return ret;
87 }
88 track_format_.GetIntValue(OH_MD_KEY_TRACK_TYPE, trackType);
89 if (trackType == MEDIA_TYPE_VID) {
90 videoTrackIdx = i;
91 }
92 ret = this->demuxer_->SelectTrackByID(i);
93 if (ret != 0) {
94 printf("SelectTrackByID is failed\n");
95 return ret;
96 }
97 }
98 return ret;
99 }
100
ReadSampleAndSave()101 int32_t InnerDemuxerSample::ReadSampleAndSave()
102 {
103 uint32_t buffersize = 1024 * 1024;
104 std::shared_ptr<AVAllocator> allocator = AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE);
105 avBuffer = OHOS::Media::AVBuffer::CreateAVBuffer(allocator, buffersize);
106 while (!isAudioEosFlagForSave && !isVideoEosFlagForSave) {
107 CheckLoopForSave();
108 }
109 videoIndexPtsList.sort();
110 audioIndexPtsList.sort();
111 return retForSave;
112 }
113
CheckLoopForSave()114 void InnerDemuxerSample::CheckLoopForSave()
115 {
116 for (int32_t i = 0; i < trackCount; i++) {
117 retForSave = this->demuxer_->ReadSampleBuffer(i, avBuffer);
118 if (retForSave != 0) {
119 cout << "ReadSampleBuffer fail ret:" << retForSave << endl;
120 isVideoEosFlagForSave = true;
121 isAudioEosFlagForSave = true;
122 break;
123 }
124 if (avBuffer->flag_ == AVCODEC_BUFFER_FLAG_EOS) {
125 if (i == videoTrackIdx) {
126 isVideoEosFlagForSave = true;
127 } else {
128 isAudioEosFlagForSave = true;
129 }
130 continue;
131 }
132 if (i == videoTrackIdx) {
133 videoIndexPtsList.push_back(avBuffer->pts_);
134 videoIndexForRead ++;
135 if (videoIndexForRead == 1) {
136 videoPtsOffset = avBuffer->pts_;
137 }
138 } else {
139 audioIndexPtsList.push_back(avBuffer->pts_);
140 audioIndexForRead ++;
141 if (audioIndexForRead == 1) {
142 audioPtsOffset = avBuffer->pts_;
143 }
144 }
145 }
146 }
147
CheckPtsFromIndex()148 int32_t InnerDemuxerSample::CheckPtsFromIndex()
149 {
150 int32_t num = 999;
151 for (int32_t i = 0; i < trackCount; i++) {
152 if (retForPts == num) {
153 break;
154 }
155 indexForPts = 0;
156 CheckLoopForPtsFromIndex(i);
157 }
158 cout << "CheckPtsFromIndex ret:" << retForPts << endl;
159 return retForPts;
160 }
161
CheckIndexFromPts()162 int32_t InnerDemuxerSample::CheckIndexFromPts()
163 {
164 int32_t num = 999;
165 for (int32_t i = 0; i < trackCount; i++) {
166 if (retForIndex == num) {
167 break;
168 }
169 listIndex = 0;
170 previousValue = 0;
171 CheckLoopForIndexFromPts(i);
172 }
173 cout << "CheckIndexFromPts ret:" << retForIndex << endl;
174 return retForIndex;
175 }
176
CheckLoopForPtsFromIndex(int32_t trackIndex)177 void InnerDemuxerSample::CheckLoopForPtsFromIndex(int32_t trackIndex)
178 {
179 uint64_t presentationTimeUs = 0;
180 int32_t num = 999;
181 if (trackIndex == videoTrackIdx) {
182 for (const auto &pair : videoIndexPtsList) {
183 retForPts = demuxer_->GetRelativePresentationTimeUsByIndex(trackIndex, indexForPts, presentationTimeUs);
184 if (retForPts != 0) {
185 cout << "GetRelativePresentationTimeUsByIndex fail ret:" << retForPts << endl;
186 break;
187 }
188 if (!((pair - videoPtsOffset - 1) <= presentationTimeUs <= (pair - videoPtsOffset + 1))) {
189 retForPts = num;
190 break;
191 }
192 indexForPts ++;
193 }
194 } else {
195 for (const auto &pair : audioIndexPtsList) {
196 retForPts = demuxer_->GetRelativePresentationTimeUsByIndex(trackIndex, indexForPts, presentationTimeUs);
197 if (retForPts != 0) {
198 cout << "GetRelativePresentationTimeUsByIndex fail ret:" << retForPts << endl;
199 break;
200 }
201 if (!((pair - audioPtsOffset - 1) <= presentationTimeUs <= (pair - audioPtsOffset + 1))) {
202 retForPts = num;
203 break;
204 }
205 indexForPts ++;
206 }
207 }
208 }
CheckLoopForIndexFromPts(int32_t trackIndex)209 void InnerDemuxerSample::CheckLoopForIndexFromPts(int32_t trackIndex)
210 {
211 if (trackIndex == videoTrackIdx) {
212 GetIndexByPtsForVideo(trackIndex);
213 } else {
214 GetIndexByPtsForAudio(trackIndex);
215 }
216 }
217
GetIndexByPtsForVideo(int32_t trackIndex)218 void InnerDemuxerSample::GetIndexByPtsForVideo(int32_t trackIndex)
219 {
220 int division = 2;
221 int value = 1;
222 for (const auto &pair : videoIndexPtsList) {
223 uint64_t tempValue = pair;
224 uint64_t relativePresentationTimeUs = static_cast<uint64_t>(pair - videoPtsOffset);
225 GetIndexFromPtsForVideo(trackIndex, relativePresentationTimeUs, pair, division, value);
226 if (retForIndex != 0) {
227 cout << "video GetIndexByRelativePresentationTimeUs fail ret:" << retForIndex << endl;
228 break;
229 }
230 retForIndex = CheckIndex(indexVideo);
231 if (retForIndex != 0) {
232 break;
233 }
234 previousValue = tempValue;
235 listIndex ++;
236 }
237 }
238
GetIndexByPtsForAudio(int32_t trackIndex)239 void InnerDemuxerSample::GetIndexByPtsForAudio(int32_t trackIndex)
240 {
241 int division = 2;
242 int value = 1;
243 for (const auto &pair : audioIndexPtsList) {
244 uint64_t tempValue = pair;
245 uint64_t relativePresentationTimeUs = static_cast<uint64_t>(pair - audioPtsOffset);
246 GetIndexFromPtsForAudio(trackIndex, relativePresentationTimeUs, pair, division, value);
247 if (retForIndex != 0) {
248 cout << "audio GetIndexByRelativePresentationTimeUs fail ret:" << retForIndex << endl;
249 break;
250 }
251 retForIndex = CheckIndex(indexAudio);
252 if (retForIndex != 0) {
253 break;
254 }
255
256 previousValue = tempValue;
257 listIndex ++;
258 }
259 }
260
GetIndexFromPtsForVideo(int32_t trackIndex,uint64_t relativePresentationTimeUs,int64_t pair,int division,int value)261 void InnerDemuxerSample::GetIndexFromPtsForVideo(int32_t trackIndex,
262 uint64_t relativePresentationTimeUs, int64_t pair, int division, int value)
263 {
264 if (isPtsExist && listIndex != 0) {
265 if (isPtsCloseLeft) {
266 if (division != 0) {
267 retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
268 relativePresentationTimeUs - ((pair - previousValue) / division + value), indexVideo);
269 }
270 } else if (isPtsCloseCenter) {
271 if (division != 0) {
272 retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
273 relativePresentationTimeUs - ((pair - previousValue) / division), indexVideo);
274 }
275 } else {
276 if (division != 0) {
277 retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
278 relativePresentationTimeUs - ((pair - previousValue) / division - value), indexVideo);
279 }
280 }
281 } else {
282 retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
283 relativePresentationTimeUs, indexVideo);
284 }
285 }
286
GetIndexFromPtsForAudio(int32_t trackIndex,uint64_t relativePresentationTimeUs,int64_t pair,int division,int value)287 void InnerDemuxerSample::GetIndexFromPtsForAudio(int32_t trackIndex,
288 uint64_t relativePresentationTimeUs, int64_t pair, int division, int value)
289 {
290 if (isPtsExist && listIndex != 0) {
291 if (isPtsCloseLeft) {
292 if (division != 0) {
293 retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
294 relativePresentationTimeUs - ((pair - previousValue) / division + value), indexAudio);
295 }
296 } else if (isPtsCloseCenter) {
297 if (division != 0) {
298 retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
299 relativePresentationTimeUs - ((pair - previousValue) / division), indexAudio);
300 }
301 } else {
302 if (division != 0) {
303 retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
304 relativePresentationTimeUs - ((pair - previousValue) / division - value), indexAudio);
305 }
306 }
307 } else {
308 retForIndex = demuxer_->GetIndexByRelativePresentationTimeUs(trackIndex,
309 relativePresentationTimeUs, indexAudio);
310 }
311 }
312
CheckIndex(uint32_t index)313 int32_t InnerDemuxerSample::CheckIndex(uint32_t index)
314 {
315 int32_t num = 999;
316 if (isPtsExist) {
317 if (isPtsCloseLeft && listIndex != 0) {
318 if (index != (listIndex -1)) {
319 retForIndex = num;
320 cout << "pts != pair index:" << index << " listIndex - 1 :"<< (listIndex - 1) << endl;
321 }
322 } else if (isPtsCloseCenter && listIndex != 0) {
323 if (index != listIndex && index != (listIndex - 1)) {
324 retForIndex = num;
325 cout << "pts != pair index:" << index << " listIndex - 1 :"<< (listIndex - 1) << endl;
326 }
327 } else {
328 if (index != listIndex) {
329 retForIndex = num;
330 cout << "pts != pair index:" << index << " listIndex:"<< listIndex << endl;
331 }
332 }
333 } else {
334 if (index != listIndex) {
335 retForIndex = num;
336 cout << "pts != pair index:" << index << " listIndex:"<< listIndex << endl;
337 }
338 }
339 return retForIndex;
340 }
CheckHasTimedMeta()341 int32_t InnerDemuxerSample::CheckHasTimedMeta()
342 {
343 int32_t hasMeta = 0;
344 source_format_.GetIntValue(AVSourceFormat::SOURCE_HAS_TIMEDMETA, hasMeta);
345 return hasMeta;
346 }
347
CheckTimedMetaFormat(int32_t trackIndex,int32_t srcTrackIndex)348 int32_t InnerDemuxerSample::CheckTimedMetaFormat(int32_t trackIndex, int32_t srcTrackIndex)
349 {
350 int32_t ret = this->avsource_->GetTrackFormat(track_format_, trackIndex);
351 if (ret != 0) {
352 cout << "get track_format_ fail" << endl;
353 return -1;
354 }
355 int32_t trackType = 0;
356 std::string codecMime = "";
357 std::string timedMetadataKey = "";
358 int32_t srcTrackID = -1;
359 std::string TIMED_METADATA_KEY = "com.openharmony.timed_metadata.test";
360 track_format_.GetIntValue(MediaDescriptionKey::MD_KEY_TRACK_TYPE, trackType);
361 if (trackType != MediaType::MEDIA_TYPE_TIMED_METADATA) {
362 cout << "check MD_KEY_TRACK_TYPE fail" << endl;
363 return -1;
364 }
365 track_format_.GetStringValue(MediaDescriptionKey::MD_KEY_CODEC_MIME, codecMime);
366 if (codecMime != "meta/timed-metadata") {
367 cout << "check codecMime fail" << endl;
368 return -1;
369 }
370 track_format_.GetStringValue(MediaDescriptionKey::MD_KEY_TIMED_METADATA_KEY, timedMetadataKey);
371 if (timedMetadataKey != TIMED_METADATA_KEY) {
372 cout << "check MD_KEY_TIMED_METADATA_KEY fail" << endl;
373 return -1;
374 }
375 track_format_.GetIntValue(MediaDescriptionKey::MD_KEY_TIMED_METADATA_SRC_TRACK_ID, srcTrackID);
376 if (srcTrackID != srcTrackIndex) {
377 cout << "check MD_KEY_TIMED_METADATA_SRC_TRACK_ID fail" << endl;
378 return -1;
379 }
380 return 0;
381 }
382
CheckTimedMeta(int32_t metaTrack)383 int32_t InnerDemuxerSample::CheckTimedMeta(int32_t metaTrack)
384 {
385 uint32_t buffersize = 1024 * 1024;
386 std::shared_ptr<AVAllocator> allocator = AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE);
387 avBuffer = OHOS::Media::AVBuffer::CreateAVBuffer(allocator, buffersize);
388 uint32_t twoHundredAndTen = 210;
389 while (!isVideoEosFlagForMeta && !isMetaEosFlagForMeta && retForMeta == 0) {
390 CheckLoop(metaTrack);
391 }
392 if (videoIndexForMeta != twoHundredAndTen || metaIndexForMeta != twoHundredAndTen) {
393 retForMeta = -1;
394 }
395 return retForMeta;
396 }
397
CheckLoop(int32_t metaTrack)398 void InnerDemuxerSample::CheckLoop(int32_t metaTrack)
399 {
400 int32_t compaseSize = 0;
401 int32_t metaSize = 0;
402 for (int32_t i = 0; i < trackCount; i++) {
403 retForMeta = this->demuxer_->ReadSampleBuffer(i, avBuffer);
404 if (retForMeta != 0) {
405 isVideoEosFlagForMeta = true;
406 isMetaEosFlagForMeta = true;
407 break;
408 }
409 if (avBuffer->flag_ == AVCODEC_BUFFER_FLAG_EOS) {
410 if (i == videoTrackIdx) {
411 isVideoEosFlagForMeta = true;
412 } else if (i == metaTrack) {
413 isMetaEosFlagForMeta = true;
414 }
415 continue;
416 }
417 if (i == videoTrackIdx) {
418 compaseSize = static_cast<int32_t>(avBuffer->memory_->GetSize());
419 if (metaTrack == 0 && metaSize != compaseSize - 1) {
420 retForMeta = -1;
421 break;
422 }
423 videoIndexForMeta ++;
424 } else if (i == metaTrack) {
425 metaSize = static_cast<int32_t>(avBuffer->memory_->GetSize());
426 if (metaTrack != 0 && metaSize != compaseSize - 1) {
427 retForMeta = -1;
428 break;
429 }
430 metaIndexForMeta ++;
431 }
432 }
433 }
434
GetFileSize(const std::string & filePath)435 size_t InnerDemuxerSample::GetFileSize(const std::string& filePath)
436 {
437 size_t fileSize = 0;
438 if (!filePath.empty()) {
439 struct stat fileStatus {};
440 if (stat(filePath.c_str(), &fileStatus) == 0) {
441 fileSize = static_cast<size_t>(fileStatus.st_size);
442 }
443 }
444 return fileSize;
445 }
446 }
447 }