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