1 /*
2 * Copyright (C) 2023 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 <cstdio>
17 #include <fcntl.h>
18 #include <iostream>
19 #include <malloc.h>
20 #include <string>
21 #include <thread>
22 #include <sys/stat.h>
23
24 #include "avcodec_common.h"
25 #include "avsharedmemorybase.h"
26 #include "media_description.h"
27 #include "native_avcodec_base.h"
28 #include "native_avformat.h"
29 #include "native_avmagic.h"
30 #include "native_avmemory.h"
31
32 #include "capi_demo/avdemuxer_demo.h"
33 #include "capi_demo/avsource_demo.h"
34 #include "demo_log.h"
35 #include "inner_demo/inner_demuxer_demo.h"
36 #include "inner_demo/inner_source_demo.h"
37 #include "server_demo/file_server_demo.h"
38
39 #include "avdemuxer_demo_runner.h"
40
41 using namespace std;
42 using namespace OHOS::MediaAVCodec;
43
44 static int64_t g_seekTime = 1000;
45 static int64_t g_startTime = 0;
46 static int64_t g_loopTime = 20;
47 static uint32_t g_maxThreadNum = 16;
48 static vector<string> g_filelist = {"AAC_44100hz_2c.aac", "ALAC_44100hz_2c.m4a",
49 "FLAC_44100hz_2c.flac", "h264_720x480_aac_44100hz_2c.mp4",
50 "h264_aac_moovlast.mp4", "h265_720x480_aac_44100hz_2c.mp4",
51 "MPEG_44100hz_2c.mp3", "MPEGTS_V1920x1080_A44100hz_2c.ts",
52 "OGG_44100hz_2c.ogg", "WAV_44100hz_2c.wav"};
53
RunNativeDemuxer(const std::string & filePath,const std::string & fileMode)54 static void RunNativeDemuxer(const std::string &filePath, const std::string &fileMode)
55 {
56 auto avSourceDemo = std::make_shared<AVSourceDemo>();
57 if (fileMode == "0") {
58 int32_t fd = open(filePath.c_str(), O_RDONLY);
59 if (fd < 0) {
60 printf("open file failed\n");
61 return;
62 }
63 size_t filesize = avSourceDemo->GetFileSize(filePath);
64 avSourceDemo->CreateWithFD(fd, 0, filesize);
65 }
66 if (fileMode == "1") {
67 avSourceDemo->CreateWithURI((char *)(filePath.c_str()));
68 }
69 auto avDemuxerDemo = std::make_shared<AVDemuxerDemo>();
70 OH_AVSource *av_source = avSourceDemo->GetAVSource();
71 avDemuxerDemo->CreateWithSource(av_source);
72 int32_t trackCount = 0;
73 int64_t duration = 0;
74 OH_AVFormat *oh_avformat = avSourceDemo->GetSourceFormat();
75 // 北向获取sourceformat
76 OH_AVFormat_GetIntValue(oh_avformat, OH_MD_KEY_TRACK_COUNT, &trackCount);
77 OH_AVFormat_GetLongValue(oh_avformat, OH_MD_KEY_DURATION, &duration);
78 printf("====>total tracks:%d\n", trackCount);
79 printf("====>duration:%" PRId64 "\n", duration);
80 // 添加轨道
81 for (int32_t i = 0; i < trackCount; i++) {
82 avDemuxerDemo->SelectTrackByID(i);
83 }
84 // 创建memory
85 uint32_t buffersize = 10 * 1024 * 1024;
86 OH_AVMemory *sampleMem = OH_AVMemory_Create(buffersize);
87 // demuxer run
88 avDemuxerDemo->ReadAllSamples(sampleMem, trackCount);
89 // 测试seek功能
90 printf("seek to 1s,mode:SEEK_MODE_NEXT_SYNC\n");
91 avDemuxerDemo->SeekToTime(g_seekTime, OH_AVSeekMode::SEEK_MODE_NEXT_SYNC);
92 avDemuxerDemo->ReadAllSamples(sampleMem, trackCount);
93 printf("seek to 1s,mode:SEEK_MODE_PREVIOUS_SYNC\n");
94 avDemuxerDemo->SeekToTime(g_seekTime, OH_AVSeekMode::SEEK_MODE_PREVIOUS_SYNC);
95 avDemuxerDemo->ReadAllSamples(sampleMem, trackCount);
96 printf("seek to 1s,mode:SEEK_MODE_CLOSEST_SYNC\n");
97 avDemuxerDemo->SeekToTime(g_seekTime, OH_AVSeekMode::SEEK_MODE_CLOSEST_SYNC);
98 avDemuxerDemo->ReadAllSamples(sampleMem, trackCount);
99 printf("seek to 0s,mode:SEEK_MODE_CLOSEST_SYNC\n");
100 avDemuxerDemo->SeekToTime(g_startTime, OH_AVSeekMode::SEEK_MODE_CLOSEST_SYNC);
101 avDemuxerDemo->ReadAllSamples(sampleMem, trackCount);
102 OH_AVMemory_Destroy(sampleMem);
103 avDemuxerDemo->Destroy();
104 avSourceDemo->Destroy();
105 }
106
RunInnerSourceDemuxer(const std::string & filePath,const std::string & fileMode)107 static void RunInnerSourceDemuxer(const std::string &filePath, const std::string &fileMode)
108 {
109 auto innerSourceDemo = std::make_shared<InnerSourceDemo>();
110 if (fileMode == "0") {
111 int32_t fd = open(filePath.c_str(), O_RDONLY);
112 if (fd < 0) {
113 printf("open file failed\n");
114 return;
115 }
116 size_t filesize = innerSourceDemo->GetFileSize(filePath);
117 innerSourceDemo->CreateWithFD(fd, 0, filesize);
118 }
119 if (fileMode == "1") {
120 innerSourceDemo->CreateWithURI(filePath);
121 }
122 auto innerDemuxerDemo = std::make_shared<InnerDemuxerDemo>();
123 innerDemuxerDemo->CreateWithSource(innerSourceDemo->avsource_);
124 int32_t trackCount = 0;
125 int64_t duration = 0;
126 Format source_format = innerSourceDemo->GetSourceFormat();
127 source_format.GetIntValue(MediaDescriptionKey::MD_KEY_TRACK_COUNT, trackCount);
128 source_format.GetLongValue(MediaDescriptionKey::MD_KEY_DURATION, duration);
129 printf("====>duration:%" PRId64 "\n", duration);
130 printf("====>total tracks:%d\n", trackCount);
131 // 添加轨道
132 for (int32_t i = 0; i < trackCount; i++) {
133 innerDemuxerDemo->SelectTrackByID(i);
134 }
135 // 去掉轨道
136 innerDemuxerDemo->UnselectTrackByID(0);
137 innerDemuxerDemo->SelectTrackByID(0);
138 uint32_t buffersize = 1024 * 1024;
139 std::shared_ptr<AVSharedMemoryBase> sharedMemory =
140 std::make_shared<AVSharedMemoryBase>(buffersize, AVSharedMemory::FLAGS_READ_WRITE, "userBuffer");
141 sharedMemory->Init();
142 // demuxer run
143 innerDemuxerDemo->ReadAllSamples(sharedMemory, trackCount);
144 // 测试seek功能
145 printf("seek to 1s,mode:SEEK_MODE_NEXT_SYNC\n");
146 innerDemuxerDemo->SeekToTime(g_seekTime, AVSeekMode::SEEK_MODE_NEXT_SYNC);
147 innerDemuxerDemo->ReadAllSamples(sharedMemory, trackCount);
148 printf("seek to 1s,mode:SEEK_MODE_PREVIOUS_SYNC\n");
149 innerDemuxerDemo->SeekToTime(g_seekTime, AVSeekMode::SEEK_MODE_PREVIOUS_SYNC);
150 innerDemuxerDemo->ReadAllSamples(sharedMemory, trackCount);
151 printf("seek to 1s,mode:SEEK_MODE_CLOSEST_SYNC\n");
152 innerDemuxerDemo->SeekToTime(g_seekTime, AVSeekMode::SEEK_MODE_CLOSEST_SYNC);
153 innerDemuxerDemo->ReadAllSamples(sharedMemory, trackCount);
154 printf("seek to 0s,mode:SEEK_MODE_CLOSEST_SYNC\n");
155 innerDemuxerDemo->SeekToTime(g_startTime, AVSeekMode::SEEK_MODE_CLOSEST_SYNC);
156 innerDemuxerDemo->ReadAllSamples(sharedMemory, trackCount);
157 innerDemuxerDemo->Destroy();
158 }
159
RunNativeDemuxerLoop(const std::string & filePath,const std::string & fileMode)160 static void RunNativeDemuxerLoop(const std::string &filePath, const std::string &fileMode)
161 {
162 time_t startTime = 0;
163 time_t curTime = 0;
164 (void)time(&startTime);
165 (void)time(&curTime);
166 while (difftime(curTime, startTime) < g_loopTime) {
167 RunNativeDemuxer(filePath, fileMode);
168 (void)time(&curTime);
169 }
170 return;
171 }
172
RunInnerSourceDemuxerLoop(const std::string & filePath,const std::string & fileMode)173 static void RunInnerSourceDemuxerLoop(const std::string &filePath, const std::string &fileMode)
174 {
175 time_t startTime = 0;
176 time_t curTime = 0;
177 (void)time(&startTime);
178 (void)time(&curTime);
179 while (difftime(curTime, startTime) < g_loopTime) {
180 RunInnerSourceDemuxer(filePath, fileMode);
181 (void)time(&curTime);
182 }
183 return;
184 }
185
RunNativeDemuxerMulti(const std::string & filePath,const std::string & fileMode)186 static void RunNativeDemuxerMulti(const std::string &filePath, const std::string &fileMode)
187 {
188 vector<thread> vecThread;
189 for (uint32_t i = 0; i < g_maxThreadNum; ++i) {
190 vecThread.emplace_back(RunNativeDemuxerLoop, filePath, fileMode);
191 }
192 for (thread &val : vecThread) {
193 val.join();
194 }
195 return;
196 }
197
RunInnerSourceDemuxerMulti(const std::string & filePath,const std::string & fileMode)198 static void RunInnerSourceDemuxerMulti(const std::string &filePath, const std::string &fileMode)
199 {
200 vector<thread> vecThread;
201 for (uint32_t i = 0; i < g_maxThreadNum; ++i) {
202 vecThread.emplace_back(RunInnerSourceDemuxerLoop, filePath, fileMode);
203 }
204 for (thread &val : vecThread) {
205 val.join();
206 }
207 return;
208 }
209
RunNativeDemuxerAllFormat(const std::string & fileMode)210 static void RunNativeDemuxerAllFormat(const std::string &fileMode)
211 {
212 string pathRoot;
213 if (fileMode == "0") {
214 pathRoot = "/data/test/media/";
215 } else if (fileMode == "1") {
216 pathRoot = "http://127.0.0.1:46666/";
217 }
218 int64_t groupNum = g_filelist.size() / g_maxThreadNum;
219 groupNum = (g_loopTime % g_maxThreadNum) == 0 ? groupNum : (groupNum + 1);
220 int64_t looptime = g_loopTime / groupNum;
221 std::mutex mutexPrint;
222 auto loopfunc = [pathRoot, looptime, fileMode, &mutexPrint](uint32_t i) {
223 const string filePath = pathRoot + g_filelist[i];
224 time_t startTime = 0;
225 time_t curTime = 0;
226 (void)time(&startTime);
227 (void)time(&curTime);
228 while (difftime(curTime, startTime) < looptime) {
229 RunNativeDemuxer(filePath, fileMode);
230 (void)time(&curTime);
231 }
232 unique_lock<mutex> lock(mutexPrint);
233 cout << filePath << " loop done" << endl;
234 };
235 for (uint32_t index = 0; index < g_filelist.size(); index += g_maxThreadNum) {
236 vector<thread> vecThread;
237 for (uint32_t i = 0; (i < g_maxThreadNum) && ((index + i) < g_filelist.size()); ++i) {
238 vecThread.emplace_back(loopfunc, index + i);
239 }
240 for (thread &val : vecThread) {
241 val.join();
242 }
243 }
244 return;
245 }
246
AVSourceDemuxerDemoCase(void)247 void AVSourceDemuxerDemoCase(void)
248 {
249 cout << "Please select a demuxer demo(default native demuxer demo): " << endl;
250 cout << "0:native_demuxer" << endl;
251 cout << "1:ffmpeg_demuxer" << endl;
252 cout << "2:native_demuxer loop" << endl;
253 cout << "3:ffmpeg_demuxer loop" << endl;
254 cout << "4:native_demuxer multithread" << endl;
255 cout << "5:ffmpeg_demuxer multithread" << endl;
256 cout << "6:native_demuxer all format" << endl;
257 string mode;
258 string fileMode;
259 string filePath;
260 std::unique_ptr<FileServerDemo> server = nullptr;
261 (void)getline(cin, mode);
262 cout << "Please select file path (0) or uri (1)" << endl;
263 (void)getline(cin, fileMode);
264 if (fileMode == "1") {
265 server = std::make_unique<FileServerDemo>();
266 server->StartServer();
267 }
268 if (mode != "6") {
269 cout << "Please input file path or uri:" << endl;
270 (void)getline(cin, filePath);
271 }
272 if (mode >= "2" && mode <= "6") {
273 cout << "Please set the time spent:" << endl;
274 cin >> g_loopTime;
275 }
276 if (mode == "0" || mode == "") {
277 RunNativeDemuxer(filePath, fileMode);
278 } else if (mode == "1") {
279 RunInnerSourceDemuxer(filePath, fileMode);
280 } else if (mode == "2") {
281 RunNativeDemuxerLoop(filePath, fileMode);
282 } else if (mode == "3") {
283 RunInnerSourceDemuxerLoop(filePath, fileMode);
284 } else if (mode == "4") {
285 RunNativeDemuxerMulti(filePath, fileMode);
286 } else if (mode == "5") {
287 RunInnerSourceDemuxerMulti(filePath, fileMode);
288 } else if (mode == "6") {
289 RunNativeDemuxerAllFormat(fileMode);
290 } else {
291 printf("select 0 or 1\n");
292 }
293 if (fileMode == "1") {
294 server->StopServer();
295 }
296 }