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 }