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#include <fstream>
24#include <chrono>
25
26#include "avcodec_common.h"
27#include "buffer/avsharedmemorybase.h"
28#include "media_description.h"
29#include "native_avcodec_base.h"
30#include "native_avformat.h"
31#include "native_avmagic.h"
32#include "native_avmemory.h"
33#include "native_avbuffer.h"
34
35#include "capi_demo/avdemuxer_demo.h"
36#include "capi_demo/avsource_demo.h"
37#include "demo_log.h"
38#include "inner_demo/inner_demuxer_demo.h"
39#include "inner_demo/inner_source_demo.h"
40#include "server_demo/file_server_demo.h"
41
42#include "avdemuxer_demo_runner.h"
43#include "media_data_source.h"
44
45using namespace std;
46using namespace OHOS::MediaAVCodec;
47using namespace OHOS::Media;
48
49static int64_t g_seekTime = 1000;
50static int64_t g_startTime = 0;
51static int64_t g_loopTime = 20;
52static uint32_t g_maxThreadNum = 16;
53static vector<string> g_filelist = {"AAC_44100hz_2c.aac",    "ALAC_44100hz_2c.m4a",
54                                    "FLAC_44100hz_2c.flac",  "h264_720x480_aac_44100hz_2c.mp4",
55                                    "h264_aac_moovlast.mp4", "h265_720x480_aac_44100hz_2c.mp4",
56                                    "MPEG_44100hz_2c.mp3",   "MPEGTS_V1920x1080_A44100hz_2c.ts",
57                                    "OGG_44100hz_2c.ogg",    "WAV_44100hz_2c.wav"};
58static std::string g_filePath;
59
60static int32_t AVSourceReadAt(OH_AVBuffer *data, int32_t length, int64_t pos)
61{
62    if (data == nullptr) {
63        printf("AVSourceReadAt : data is nullptr!\n");
64        return MediaDataSourceError::SOURCE_ERROR_IO;
65    }
66
67    std::ifstream infile(g_filePath, std::ofstream::binary);
68    if (!infile.is_open()) {
69        printf("AVSourceReadAt : open file failed! file:%s\n", g_filePath.c_str());
70        return MediaDataSourceError::SOURCE_ERROR_IO;  // 打开文件失败
71    }
72
73    infile.seekg(0, std::ios::end);
74    int64_t fileSize = infile.tellg();
75    if (pos >= fileSize) {
76        printf("AVSourceReadAt : pos over or equals file size!\n");
77        return MediaDataSourceError::SOURCE_ERROR_EOF;  // pos已经是文件末尾位置,无法读取
78    }
79
80    if (pos + length > fileSize) {
81        length = fileSize - pos;    // pos+length长度超过文件大小时,读取从pos到文件末尾的数据
82    }
83
84    infile.seekg(pos, std::ios::beg);
85    if (length <= 0) {
86        printf("AVSourceReadAt : raed length less than zero!\n");
87        return MediaDataSourceError::SOURCE_ERROR_IO;
88    }
89    char* buffer = new char[length];
90    infile.read(buffer, length);
91    infile.close();
92
93    errno_t result = memcpy_s(reinterpret_cast<char *>(OH_AVBuffer_GetAddr(data)),
94        OH_AVBuffer_GetCapacity(data), buffer, length);
95    delete[] buffer;
96    if (result != 0) {
97        printf("memcpy_s failed!");
98        return MediaDataSourceError::SOURCE_ERROR_IO;
99    }
100
101    return length;
102}
103
104static void TestNativeSeek(OH_AVMemory *sampleMem, int32_t trackCount, std::shared_ptr<AVDemuxerDemo> avDemuxerDemo)
105{
106    printf("seek to 1s,mode:SEEK_MODE_NEXT_SYNC\n");
107    avDemuxerDemo->SeekToTime(g_seekTime, OH_AVSeekMode::SEEK_MODE_NEXT_SYNC); // 测试seek功能
108    avDemuxerDemo->ReadAllSamples(sampleMem, trackCount);
109    printf("seek to 1s,mode:SEEK_MODE_PREVIOUS_SYNC\n");
110    avDemuxerDemo->SeekToTime(g_seekTime, OH_AVSeekMode::SEEK_MODE_PREVIOUS_SYNC);
111    avDemuxerDemo->ReadAllSamples(sampleMem, trackCount);
112    printf("seek to 1s,mode:SEEK_MODE_CLOSEST_SYNC\n");
113    avDemuxerDemo->SeekToTime(g_seekTime, OH_AVSeekMode::SEEK_MODE_CLOSEST_SYNC);
114    avDemuxerDemo->ReadAllSamples(sampleMem, trackCount);
115    printf("seek to 0s,mode:SEEK_MODE_CLOSEST_SYNC\n");
116    avDemuxerDemo->SeekToTime(g_startTime, OH_AVSeekMode::SEEK_MODE_CLOSEST_SYNC);
117    avDemuxerDemo->ReadAllSamples(sampleMem, trackCount);
118}
119
120static void ShowSourceDescription(OH_AVFormat *oh_trackformat)
121{
122    int32_t trackType = -1;
123    int64_t duration = -1;
124    const char* mimeType = nullptr;
125    int64_t bitrate = -1;
126    int32_t width = -1;
127    int32_t height = -1;
128    int32_t audioSampleFormat = -1;
129    double keyFrameRate = -1;
130    int32_t profile = -1;
131    int32_t audioChannelCount = -1;
132    int32_t audioSampleRate = -1;
133    OH_AVFormat_GetIntValue(oh_trackformat, OH_MD_KEY_TRACK_TYPE, &trackType);
134    OH_AVFormat_GetLongValue(oh_trackformat, OH_MD_KEY_DURATION, &duration);
135    OH_AVFormat_GetStringValue(oh_trackformat, OH_MD_KEY_CODEC_MIME, &mimeType);
136    OH_AVFormat_GetLongValue(oh_trackformat, OH_MD_KEY_BITRATE, &bitrate);
137    OH_AVFormat_GetIntValue(oh_trackformat, OH_MD_KEY_WIDTH, &width);
138    OH_AVFormat_GetIntValue(oh_trackformat, OH_MD_KEY_HEIGHT, &height);
139    OH_AVFormat_GetIntValue(oh_trackformat, OH_MD_KEY_AUDIO_SAMPLE_FORMAT, &audioSampleFormat);
140    OH_AVFormat_GetDoubleValue(oh_trackformat, OH_MD_KEY_FRAME_RATE, &keyFrameRate);
141    OH_AVFormat_GetIntValue(oh_trackformat, OH_MD_KEY_PROFILE, &profile);
142    OH_AVFormat_GetIntValue(oh_trackformat, OH_MD_KEY_AUD_CHANNEL_COUNT, &audioChannelCount);
143    OH_AVFormat_GetIntValue(oh_trackformat, OH_MD_KEY_AUD_SAMPLE_RATE, &audioSampleRate);
144    printf("===>tracks:%d duration:%" PRId64 " mimeType:%s bitrate:%" PRId64 " width:%d height:%d audioSampleFormat:%d"
145        " keyFrameRate:%.2f profile:%d audioChannelCount:%d audioSampleRate:%d\n", trackType, duration, mimeType,
146        bitrate, width, height, audioSampleFormat, keyFrameRate, profile, audioChannelCount, audioSampleRate);
147}
148
149static void RunNativeDemuxer(const std::string &filePath, const std::string &fileMode)
150{
151    auto avSourceDemo = std::make_shared<AVSourceDemo>();
152    int32_t fd = -1;
153    if (fileMode == "1") {
154        avSourceDemo->CreateWithURI((char *)(filePath.c_str()));
155    } else if (fileMode == "0" || fileMode == "2") {
156        if ((fd = open(filePath.c_str(), O_RDONLY)) < 0) {
157            printf("open file failed\n");
158            return;
159        }
160        int64_t fileSize = avSourceDemo->GetFileSize(filePath);
161        if (fileMode == "0") {
162            avSourceDemo->CreateWithFD(fd, 0, fileSize);
163        } else if (fileMode == "2") {
164            g_filePath = filePath;
165            OH_AVDataSource dataSource = {fileSize, AVSourceReadAt};
166            avSourceDemo->CreateWithDataSource(&dataSource);
167        }
168    }
169
170    auto avDemuxerDemo = std::make_shared<AVDemuxerDemo>();
171    OH_AVSource *av_source = avSourceDemo->GetAVSource();
172    avDemuxerDemo->CreateWithSource(av_source);
173    int32_t trackCount = 0;
174    int64_t duration = 0;
175    OH_AVFormat *oh_avformat = avSourceDemo->GetSourceFormat();
176    OH_AVFormat_GetIntValue(oh_avformat, OH_MD_KEY_TRACK_COUNT, &trackCount); // 北向获取sourceformat
177    OH_AVFormat_GetLongValue(oh_avformat, OH_MD_KEY_DURATION, &duration);
178    printf("====>total tracks:%d duration:%" PRId64 "\n", trackCount, duration);
179    for (int32_t i = 0; i < trackCount; i++) {
180        OH_AVFormat *oh_trackformat = avSourceDemo->GetTrackFormat(i);
181        ShowSourceDescription(oh_trackformat);
182        avDemuxerDemo->SelectTrackByID(i); // 添加轨道
183    }
184    uint32_t buffersize = 10 * 1024 * 1024;
185    OH_AVMemory *sampleMem = OH_AVMemory_Create(buffersize); // 创建memory
186    avDemuxerDemo->ReadAllSamples(sampleMem, trackCount);
187    TestNativeSeek(sampleMem, trackCount, avDemuxerDemo);
188    OH_AVMemory_Destroy(sampleMem);
189    OH_AVFormat_Destroy(oh_avformat);
190    avDemuxerDemo->Destroy();
191    avSourceDemo->Destroy();
192    if (fileMode == "0" && fd > 0) {
193        close(fd);
194    }
195}
196
197static void RunDrmNativeDemuxer(const std::string &filePath, const std::string &fileMode)
198{
199    auto avSourceDemo = std::make_shared<AVSourceDemo>();
200    int32_t fd = -1;
201    if (fileMode == "0") {
202        fd = open(filePath.c_str(), O_RDONLY);
203        if (fd < 0) {
204            printf("open file failed\n");
205            return;
206        }
207        size_t filesize = avSourceDemo->GetFileSize(filePath);
208        avSourceDemo->CreateWithFD(fd, 0, filesize);
209    } else if (fileMode == "1") {
210        avSourceDemo->CreateWithURI((char *)(filePath.c_str()));
211    }
212    auto avDemuxerDemo = std::make_shared<AVDemuxerDemo>();
213    OH_AVSource *av_source = avSourceDemo->GetAVSource();
214    avDemuxerDemo->CreateWithSource(av_source);
215
216    // test drm event callback
217    avDemuxerDemo->SetDrmAppCallback();
218
219    int32_t trackCount = 0;
220    int64_t duration = 0;
221    OH_AVFormat *oh_avformat = avSourceDemo->GetSourceFormat();
222    OH_AVFormat_GetIntValue(oh_avformat, OH_MD_KEY_TRACK_COUNT, &trackCount); // 北向获取sourceformat
223    OH_AVFormat_GetLongValue(oh_avformat, OH_MD_KEY_DURATION, &duration);
224    printf("====>total tracks:%d duration:%" PRId64 "\n", trackCount, duration);
225    for (int32_t i = 0; i < trackCount; i++) {
226        avDemuxerDemo->SelectTrackByID(i); // 添加轨道
227    }
228    uint32_t buffersize = 10 * 1024 * 1024;
229    OH_AVMemory *sampleMem = OH_AVMemory_Create(buffersize); // 创建memory
230    avDemuxerDemo->ReadAllSamples(sampleMem, trackCount);
231    printf("seek to 1s,mode:SEEK_MODE_NEXT_SYNC\n");
232    avDemuxerDemo->SeekToTime(g_seekTime, OH_AVSeekMode::SEEK_MODE_NEXT_SYNC); // 测试seek功能
233    avDemuxerDemo->ReadAllSamples(sampleMem, trackCount);
234
235    // test drm GetMediaKeySystemInfos
236    avDemuxerDemo->GetMediaKeySystemInfo();
237
238    OH_AVMemory_Destroy(sampleMem);
239    OH_AVFormat_Destroy(oh_avformat);
240    avDemuxerDemo->Destroy();
241    avSourceDemo->Destroy();
242    if (fileMode == "0" && fd > 0) {
243        close(fd);
244    }
245}
246
247static void ConvertPtsFrameIndexDemo(std::shared_ptr<InnerDemuxerDemo> innerDemuxerDemo)
248{
249    uint32_t trackIndex = 0;
250    uint64_t relativePresentationTimeUs = 0;    // pts 0
251
252    using clock = std::chrono::high_resolution_clock;
253    auto start = clock::now();
254    auto end = clock::now();
255    std::chrono::duration<double> elapsed = end - start;
256
257    for (uint32_t index = 0; index < 10 ; ++index) { // get first 10 frames
258        start = clock::now();
259        int32_t ret = innerDemuxerDemo->GetRelativePresentationTimeUsByIndex(trackIndex,
260                                                                             index, relativePresentationTimeUs);
261        if (ret != 0) {
262            break;
263        }
264        end = clock::now();
265        elapsed = end - start;
266        printf("GetRelativePresentationTimeUsByIndex, relativePresentationTimeUs = %" PRId64 "\n",
267            relativePresentationTimeUs);
268        printf("Function took %f seconds to run.\n", elapsed.count());
269
270        start = clock::now();
271        ret = innerDemuxerDemo->GetIndexByRelativePresentationTimeUs(trackIndex, relativePresentationTimeUs, index);
272        if (ret != 0) {
273            break;
274        }
275        end = clock::now();
276        elapsed = end - start;
277        printf("GetIndexByRelativePresentationTimeUs, index = %u\n", index);
278        printf("Function took %f seconds to run.\n", elapsed.count());
279    }
280}
281
282static void RunInnerSourceDemuxer(const std::string &filePath, const std::string &fileMode)
283{
284    auto innerSourceDemo = std::make_shared<InnerSourceDemo>();
285    int32_t fd = -1;
286    if (fileMode == "0") {
287        fd = open(filePath.c_str(), O_RDONLY);
288        if (fd < 0) {
289            printf("open file failed\n");
290            return;
291        }
292        size_t filesize = innerSourceDemo->GetFileSize(filePath);
293        innerSourceDemo->CreateWithFD(fd, 0, filesize);
294    } else if (fileMode == "1") {
295        innerSourceDemo->CreateWithURI(filePath);
296    }
297    auto innerDemuxerDemo = std::make_shared<InnerDemuxerDemo>();
298    innerDemuxerDemo->CreateWithSource(innerSourceDemo->avsource_);
299    int32_t trackCount = 0;
300    int64_t duration = 0;
301    Format source_format = innerSourceDemo->GetSourceFormat();
302    source_format.GetIntValue(MediaDescriptionKey::MD_KEY_TRACK_COUNT, trackCount);
303    source_format.GetLongValue(MediaDescriptionKey::MD_KEY_DURATION, duration);
304    printf("====>duration:%" PRId64 " total tracks:%d\n", duration, trackCount);
305    ConvertPtsFrameIndexDemo(innerDemuxerDemo);
306    for (int32_t i = 0; i < trackCount; i++) {
307        innerDemuxerDemo->SelectTrackByID(i); // 添加轨道
308    }
309    innerDemuxerDemo->UnselectTrackByID(0); // 去掉轨道
310    innerDemuxerDemo->SelectTrackByID(0);
311    uint32_t buffersize = 1024 * 1024;
312    std::shared_ptr<AVSharedMemoryBase> sharedMemory =
313        std::make_shared<AVSharedMemoryBase>(buffersize, AVSharedMemory::FLAGS_READ_WRITE, "userBuffer");
314    sharedMemory->Init();
315    innerDemuxerDemo->ReadAllSamples(sharedMemory, trackCount); // demuxer run
316    printf("seek to 1s,mode:SEEK_NEXT_SYNC\n");
317    innerDemuxerDemo->SeekToTime(g_seekTime, SeekMode::SEEK_NEXT_SYNC); // 测试seek功能
318    innerDemuxerDemo->ReadAllSamples(sharedMemory, trackCount);
319    printf("seek to 1s,mode:SEEK_PREVIOUS_SYNC\n");
320    innerDemuxerDemo->SeekToTime(g_seekTime, SeekMode::SEEK_PREVIOUS_SYNC);
321    innerDemuxerDemo->ReadAllSamples(sharedMemory, trackCount);
322    printf("seek to 1s,mode:SEEK_CLOSEST_SYNC\n");
323    innerDemuxerDemo->SeekToTime(g_seekTime, SeekMode::SEEK_CLOSEST_SYNC);
324    innerDemuxerDemo->ReadAllSamples(sharedMemory, trackCount);
325    printf("seek to 0s,mode:SEEK_CLOSEST_SYNC\n");
326    innerDemuxerDemo->SeekToTime(g_startTime, SeekMode::SEEK_CLOSEST_SYNC);
327    innerDemuxerDemo->ReadAllSamples(sharedMemory, trackCount);
328    innerDemuxerDemo->Destroy();
329    if (fileMode == "0" && fd > 0) {
330        close(fd);
331    }
332}
333
334static void RunRefParserDemuxer(const std::string &filePath, const std::string &fileMode)
335{
336    auto innerSourceDemo = std::make_shared<InnerSourceDemo>();
337    int32_t fd = open(filePath.c_str(), O_RDONLY);
338    if (fd < 0) {
339        printf("open file failed\n");
340        return;
341    }
342    innerSourceDemo->CreateWithFD(fd, 0, innerSourceDemo->GetFileSize(filePath));
343    auto innerDemuxerDemo = std::make_shared<InnerDemuxerDemo>();
344    innerDemuxerDemo->CreateWithSource(innerSourceDemo->avsource_);
345    int32_t trackCount = 0;
346    int64_t duration = 0;
347    Format source_format = innerSourceDemo->GetSourceFormat();
348    source_format.GetIntValue(MediaDescriptionKey::MD_KEY_TRACK_COUNT, trackCount);
349    source_format.GetLongValue(MediaDescriptionKey::MD_KEY_DURATION, duration);
350    printf("====>duration:%" PRId64 " total tracks:%d\n", duration, trackCount);
351    int32_t trackType = 0;
352    int32_t videoTrackIdx = 0;
353    for (int32_t i = 0; i < trackCount; i++) {
354        Format trackFormat = innerSourceDemo->GetTrackFormat(i);
355        trackFormat.GetIntValue(MediaDescriptionKey::MD_KEY_TRACK_TYPE, trackType);
356        if (trackType == 1) {                     // 视频轨道
357            innerDemuxerDemo->SelectTrackByID(i); // 添加轨道
358            videoTrackIdx = i;
359        }
360    }
361    uint32_t buffersize = 1024 * 1024;
362    std::shared_ptr<AVAllocator> allocator = AVAllocatorFactory::CreateSharedAllocator(MemoryFlag::MEMORY_READ_WRITE);
363    std::shared_ptr<OHOS::Media::AVBuffer> avBuffer = OHOS::Media::AVBuffer::CreateAVBuffer(allocator, buffersize);
364    innerDemuxerDemo->StartReferenceParser(0);
365    FrameLayerInfo frameLayerInfo;
366    bool isEosFlag = true;
367    while (isEosFlag) {
368        innerDemuxerDemo->ReadSampleBuffer(videoTrackIdx, avBuffer);
369        if (avBuffer->flag_ == AVCODEC_BUFFER_FLAG_EOS) {
370            cout << "read sample end" << endl;
371            isEosFlag = false;
372        }
373        cout << "size: " << avBuffer->memory_->GetSize() << ",pts: " << avBuffer->pts_ << ", dts: " << avBuffer->dts_
374             << endl;
375        innerDemuxerDemo->GetFrameLayerInfo(avBuffer, frameLayerInfo);
376        cout << "isDiscardable: " << frameLayerInfo.isDiscardable << ", gopId: " << frameLayerInfo.gopId
377             << ", layer: " << frameLayerInfo.layer << endl;
378    }
379    innerDemuxerDemo->Destroy();
380    if (fileMode == "0" && fd > 0) {
381        close(fd);
382        fd = -1;
383    }
384}
385
386static void RunNativeDemuxerLoop(const std::string &filePath, const std::string &fileMode)
387{
388    time_t startTime = 0;
389    time_t curTime = 0;
390    (void)time(&startTime);
391    (void)time(&curTime);
392    while (difftime(curTime, startTime) < g_loopTime) {
393        RunNativeDemuxer(filePath, fileMode);
394        (void)time(&curTime);
395    }
396    return;
397}
398
399static void RunInnerSourceDemuxerLoop(const std::string &filePath, const std::string &fileMode)
400{
401    time_t startTime = 0;
402    time_t curTime = 0;
403    (void)time(&startTime);
404    (void)time(&curTime);
405    while (difftime(curTime, startTime) < g_loopTime) {
406        RunInnerSourceDemuxer(filePath, fileMode);
407        (void)time(&curTime);
408    }
409    return;
410}
411
412static void RunNativeDemuxerMulti(const std::string &filePath, const std::string &fileMode)
413{
414    vector<thread> vecThread;
415    for (uint32_t i = 0; i < g_maxThreadNum; ++i) {
416        vecThread.emplace_back(RunNativeDemuxerLoop, filePath, fileMode);
417    }
418    for (thread &val : vecThread) {
419        val.join();
420    }
421    return;
422}
423
424static void RunInnerSourceDemuxerMulti(const std::string &filePath, const std::string &fileMode)
425{
426    vector<thread> vecThread;
427    for (uint32_t i = 0; i < g_maxThreadNum; ++i) {
428        vecThread.emplace_back(RunInnerSourceDemuxerLoop, filePath, fileMode);
429    }
430    for (thread &val : vecThread) {
431        val.join();
432    }
433    return;
434}
435
436static void RunNativeDemuxerAllFormat(const std::string &fileMode)
437{
438    string pathRoot;
439    if (fileMode == "0") {
440        pathRoot = "/data/test/media/";
441    } else if (fileMode == "1") {
442        pathRoot = "http://127.0.0.1:46666/";
443    }
444    int64_t groupNum = g_filelist.size() / g_maxThreadNum;
445    groupNum = (g_loopTime % g_maxThreadNum) == 0 ? groupNum : (groupNum + 1);
446    int64_t looptime = g_loopTime / groupNum;
447    std::mutex mutexPrint;
448    auto loopfunc = [pathRoot, looptime, fileMode, &mutexPrint](uint32_t i) {
449        const string filePath = pathRoot + g_filelist[i];
450        time_t startTime = 0;
451        time_t curTime = 0;
452        (void)time(&startTime);
453        (void)time(&curTime);
454        while (difftime(curTime, startTime) < looptime) {
455            RunNativeDemuxer(filePath, fileMode);
456            (void)time(&curTime);
457        }
458        unique_lock<mutex> lock(mutexPrint);
459        cout << filePath << " loop done" << endl;
460    };
461    for (uint32_t index = 0; index < g_filelist.size(); index += g_maxThreadNum) {
462        vector<thread> vecThread;
463        for (uint32_t i = 0; (i < g_maxThreadNum) && ((index + i) < g_filelist.size()); ++i) {
464            vecThread.emplace_back(loopfunc, index + i);
465        }
466        for (thread &val : vecThread) {
467            val.join();
468        }
469    }
470    return;
471}
472
473void PrintPrompt()
474{
475    cout << "Please select a demuxer demo(default native demuxer demo): " << endl;
476    cout << "0:native_demuxer" << endl;
477    cout << "1:ffmpeg_demuxer" << endl;
478    cout << "2:native_demuxer loop" << endl;
479    cout << "3:ffmpeg_demuxer loop" << endl;
480    cout << "4:native_demuxer multithread" << endl;
481    cout << "5:ffmpeg_demuxer multithread" << endl;
482    cout << "6:native_demuxer all format" << endl;
483    cout << "7:native_demuxer drm test" << endl;
484    cout << "8:ffmpeg_demuxe ref test" << endl;
485}
486
487void AVSourceDemuxerDemoCase(void)
488{
489    PrintPrompt();
490    string mode;
491    string fileMode;
492    string filePath;
493    std::unique_ptr<FileServerDemo> server = nullptr;
494    (void)getline(cin, mode);
495    cout << "Please select file path (0) or uri (1) or dataSource (2)" << endl;
496    (void)getline(cin, fileMode);
497    if (fileMode == "1") {
498        server = std::make_unique<FileServerDemo>();
499        server->StartServer();
500    }
501    if (mode != "6") {
502        cout << "Please input file path or uri:" << endl;
503        (void)getline(cin, filePath);
504    }
505    if (mode >= "2" && mode <= "6") {
506        cout << "Please set the time spent:" << endl;
507        cin >> g_loopTime;
508    }
509    if (mode == "0" || mode == "") {
510        RunNativeDemuxer(filePath, fileMode);
511    } else if (mode == "1") {
512        RunInnerSourceDemuxer(filePath, fileMode);
513    } else if (mode == "2") {
514        RunNativeDemuxerLoop(filePath, fileMode);
515    } else if (mode == "3") {
516        RunInnerSourceDemuxerLoop(filePath, fileMode);
517    } else if (mode == "4") {
518        RunNativeDemuxerMulti(filePath, fileMode);
519    } else if (mode == "5") {
520        RunInnerSourceDemuxerMulti(filePath, fileMode);
521    } else if (mode == "6") {
522        RunNativeDemuxerAllFormat(fileMode);
523    } else if (mode == "7") {
524        RunDrmNativeDemuxer(filePath, fileMode);
525    } else if (mode == "8") {
526        if (fileMode == "0") {
527            RunRefParserDemuxer(filePath, fileMode);
528            return;
529        }
530        printf("only support local file\n");
531    } else {
532        printf("select 0 or 1\n");
533    }
534    if (fileMode == "1") {
535        server->StopServer();
536    }
537}
538