Files
2026-08-24 10:03:24 +08:00

379 lines
13 KiB
C++

/*
* Copyright (c) 2020 Amlogic, Inc. All rights reserved.
*
* This source code is subject to the terms and conditions defined in the
* file 'LICENSE' which is part of this source code package.
*
* Description:
*/
#define LOG_NDEBUG 0
#define LOG_TAG "AmlMpPlayerDemo"
#include <utils/AmlMpLog.h>
#ifdef ANDROID
#include <android/binder_process.h>
#include <android/binder_manager.h>
#include <log/log.h>
#endif
#include <AmlMpTestSupporter.h>
#include <unistd.h>
#include <getopt.h>
#include "TestUtils.h"
static const char* mName = LOG_TAG;
using namespace aml_mp;
struct Argument
{
std::string url;
int x = 0;
int y = 0;
int viewWidth = -1;
int viewHeight = -1;
int playMode = 0;
int videoMode = 0;
int zorder = 0;
int record = 0;
int crypto = 0;
int uiMode = 0;
int channelId = -1;
int videoErrorRecoveryMode = 0;
uint64_t options = 0;
bool esMode = false;
bool clearTVP = false;
bool timeShift = false;
bool appendMode = false;
};
static int parseCommandArgs(int argc, char* argv[], Argument* argument)
{
static const struct option longopts[] = {
{"help", no_argument, nullptr, 'h'},
{"size", required_argument, nullptr, 's'},
{"pos", required_argument, nullptr, 'p'},
{"playmode", required_argument, nullptr, 'm'},
{"zorder", required_argument, nullptr, 'z'},
{"videomode", required_argument, nullptr, 'v'},
{"record", no_argument, nullptr, 'r'},
{"crypto", no_argument, nullptr, 'c'},
{"ui", no_argument, nullptr, 'u'},
{"id", required_argument, nullptr, 'd'},
{"video-error-recovery-mode", required_argument, nullptr, 'e'},
{"options", required_argument, nullptr, 'o'},
{"esmode", no_argument, nullptr, 'esmd'},
{"cleartvp", no_argument, nullptr, 't'},
{"timeshift", no_argument, nullptr, 'tf'},
{"appendmode", no_argument, nullptr, 'am'},
{nullptr, no_argument, nullptr, 0},
};
int opt, longindex = 0;
while ((opt = getopt_long(argc, argv, "", longopts, &longindex)) != -1) {
//printf("opt = %d\n", opt);
switch (opt) {
case 's':
{
int width, height;
if (sscanf(optarg, "%dx%d", &width, &height) != 2) {
printf("parse %s failed! %s\n", longopts[longindex].name, optarg);
} else {
argument->viewWidth = width;
argument->viewHeight = height;
}
}
break;
case 'p':
{
int x, y;
//printf("optarg:%s\n", optarg);
if (sscanf(optarg, "%dx%d", &x, &y) != 2) {
printf("parse %s failed! %s\n", longopts[longindex].name, optarg);
} else {
argument->x = x;
argument->y = y;
printf("pos:%dx%d\n", x, y);
}
}
break;
case 'm':
{
int playMode = strtol(optarg, nullptr, 0);
if (playMode < 0 || playMode >= AmlMpTestSupporter::PLAY_MODE_MAX) {
playMode = 0;
}
printf("playMode:%d\n", playMode);
argument->playMode = playMode;
}
break;
case 'z':
{
int zorder = strtol(optarg, nullptr, 0);
printf("zorder:%d\n", zorder);
argument->zorder = zorder;
}
break;
case 'v':
{
int videoMode = strtol(optarg, nullptr, 0);
printf("videoMode:%d\n", videoMode);
argument->videoMode = videoMode;
}
break;
case 'r':
{
printf("record mode!\n");
argument->record = true;
}
break;
case 'c':
{
printf("crypto mode!\n");
argument->crypto = true;
}
break;
case 'u':
{
printf("ui mode!\n");
argument->uiMode = true;
}
break;
case 'd':
{
int channelId = strtol(optarg, nullptr, 0);
printf("channel id:%d\n", channelId);
argument->channelId = channelId;
}
break;
case 'e':
{
int tmpMode = strtol(optarg, nullptr, 0);
printf("video error recovery mode: %d(%s)\n", tmpMode, mpVideoErrorRecoveryMode2Str((Aml_MP_VideoErrorRecoveryMode)tmpMode));
argument->videoErrorRecoveryMode = tmpMode;
}
break;
case 'o':
{
uint64_t options = strtoul(optarg, nullptr, 0);
printf("options :0x%" PRIx64 "\n", options);
argument->options = options;
}
break;
case 'esmd':
{
printf("esmode!\n");
argument->esMode = true;
}
break;
case 't':
{
printf("clearTVP\n");
argument->clearTVP = true;
}
break;
case 'tf':
{
printf("timeShift\n");
argument->timeShift = true;
}
break;
case 'am':
{
printf("appendmode\n");
argument->appendMode = true;
}
break;
case 'h':
default:
return -1;
}
}
//printf("optind:%d, argc:%d\n", optind, argc);
if (optind < argc) {
argument->url = argv[argc-1];
printf("url:%s\n", argument->url.c_str());
}
if (argument->uiMode || !argument->url.empty()) {
return 0;
}
return -1;
}
static void showUsage()
{
printf("Usage: amlMpPlayerDemo <options> <url>\n"
"options:\n"
" --size: eg: 1920x1080\n"
" --pos: eg: 0x0\n"
" --zorder: eg: 0\n"
" --videomode: 0: set ANativeWindow\n"
" 1: set video window\n"
" --playmode: 0: set audio param, set video param, start --> stop\n"
" 1: set audio param, set video param, start --> stop audio, stop video\n"
" 2: set audio param, set video param, start audio, start video --> stop\n"
" 3: set audio param, set video param, start audio, start video --> stop audio, stop video\n"
" 4: set audio param, set video param, start video, start audio --> stop audio, stop video\n"
" 5: set audio param, start audio, set video param, start video --> stop audio, stop video\n"
" 6: set video param, start video, set audio param, start audio --> stop video, stop audio\n"
" --record: record mode, record file name is \"" AML_MP_TEST_SUPPORTER_RECORD_FILE "\"\n"
" --crypto crypto mode\n"
" --ui create ui only\n"
" --id specify the corresponding ui channel id\n"
" --video-error-recovery-mode\n"
" 0: default\n"
" 1: drop error frame\n"
" 2: do nothing, display error frame\n"
" --options set options, eg: 3, 3 equals with 0b0011, so it means \"prefer tunerhal\" and \"monitor pid change\"\n"
" 0-bit set 1 means prefer tunerhal: AML_MP_OPTION_PREFER_TUNER_HAL\n"
" 1-bit set 1 means monitor pid change: AML_MP_OPTION_MONITOR_PID_CHANGE\n"
" 2-bit set 1 means prefer CTC: AML_MP_OPTION_PREFER_CTC\n"
" 3-bit set 1 means report subtitle data: AML_MP_OPTION_REPORT_SUBTITLE_DATA\n"
" 4-bit set 1 means retain resource when stop player: AML_MP_OPTION_RETAIN_RESOURCE_IN_STOP\n"
" --esmode enable es mode playback\n"
#ifdef HAVE_SECMEM
" --cleartvp enable cleartvp for es mode playback\n"
#endif
" --timeshift enable timeshift\n"
" --appendmode enable appendmode to save record file with same location for dvr\n"
"\n"
"url format: url?program=xx&demuxid=xx&sourceid=xx&fendid=xx\n"
" DVB-T dvbt://<freq>/<bandwidth>, eg: dvbt://474/8M\n"
" DVB-C dvbc://<freq>/<symbol rate>/<modulation>, eg: dvbc://474/6900/64qam\n"
" DVB-S dvbs://<freq>/<symbol rate>, eg: dvbs://1804/29950\n"
" local file, eg: /data/a.ts\n"
" dvr replay, eg: dvr:/" AML_MP_TEST_SUPPORTER_RECORD_FILE "\n"
" udp source, eg: udp://224.0.0.1:8000\n"
" rtp source, eg: rtp://224.0.0.1:8000\n"
"\n"
);
}
int startPlayback(const sptr<AmlMpTestSupporter>& mpTestSupporter, Argument& argument, const std::string* url = nullptr)
{
int ret = 0;
const std::string& playUrl = url ? *url : argument.url;
mpTestSupporter->setDataSource(playUrl);
ret = mpTestSupporter->prepare(argument.crypto);
if (ret < 0) {
printf("prepare failed!\n");
return -1;
}
MLOGI(">>>> AmlMpPlayerDemo Start\n");
mpTestSupporter->setVideoErrorRecoveryMode(argument.videoErrorRecoveryMode);
mpTestSupporter->setSourceMode(argument.esMode, argument.clearTVP);
ret = mpTestSupporter->startPlay((AmlMpTestSupporter::PlayMode)argument.playMode, true, true, argument.timeShift);
if (ret < 0) {
return -1;
}
MLOGI("<<<< AmlMpPlayerDemo Start\n");
return ret;
}
int main(int argc, char *argv[])
{
Argument argument{};
int ret;
if (parseCommandArgs(argc, argv, &argument) < 0) {
showUsage();
return 0;
}
sptr<AmlMpTestSupporter> mpTestSupporter = new AmlMpTestSupporter;
sptr<AmlMpTestSupporter> mpTestSupporter2 = nullptr;
mpTestSupporter->installSignalHandler(); // must be called before other thread creat
#ifdef ANDROID
ABinderProcess_setThreadPoolMaxThreadCount(32);
ABinderProcess_startThreadPool();
#endif
AmlMpTestSupporter::DisplayParam displayParam;
displayParam.x = argument.x;
displayParam.y = argument.y;
displayParam.width = argument.viewWidth;
displayParam.height = argument.viewHeight;
displayParam.zorder = argument.zorder;
displayParam.videoMode = argument.videoMode;
displayParam.channelId = argument.channelId;
mpTestSupporter->setDisplayParam(displayParam);
if (argument.options) {
mpTestSupporter->addOptions(argument.options);
}
if (argument.uiMode) {
mpTestSupporter->startUIOnly();
} else {
MLOGI("argument.record=%d argument.timeShift=%d\n", argument.record, argument.timeShift);
if (argument.record || argument.timeShift) {
mpTestSupporter->setDataSource(argument.url);
ret = mpTestSupporter->prepare(argument.crypto);
if (ret < 0) {
printf("prepare failed!\n");
return -1;
}
ret = mpTestSupporter->startRecord(true, argument.timeShift, argument.appendMode);
if (ret < 0) {
printf("startRecord failed!\n");
return -1;
}
if (argument.timeShift) {
MLOGI(">>>> TimeshiftRecord START\n");
sleep(2);//wait for 2s data
char recordPathInfo[100];
mpTestSupporter2 = new AmlMpTestSupporter;
mpTestSupporter2->setDisplayParam(displayParam);
if (argument.options) {
mpTestSupporter2->addOptions(argument.options);
}
snprintf(recordPathInfo, 100, "dvr:/%s?demuxid=%d&sourceid=%d", AML_MP_TEST_SUPPORTER_RECORD_FILE,
mpTestSupporter->mDemuxId + 1, mpTestSupporter->mDemuxId + 1);
std::string finalUrl = recordPathInfo;
ret = startPlayback(mpTestSupporter2, argument, &finalUrl);
if (ret < 0) {
printf("mpTestSupporter2 startDVRPlayback failed!\n");
return -1;
}
MLOGI("<<<< TimeshiftRecord START\n");
}
}else {
ret = startPlayback(mpTestSupporter, argument);
if (ret < 0) {
printf("AmlMpPlayerDemo Start failed!\n");
}
}
}
mpTestSupporter->fetchAndProcessCommands();
if (mpTestSupporter2 != nullptr) {
MLOGI("timeShift mpTestSupporter2 destroy\n");
mpTestSupporter2->stop();
mpTestSupporter2.clear();
}
mpTestSupporter->stop();
mpTestSupporter.clear();
MLOGI("exited!");
return 0;
}