Files
BPI-CM9-Linux/aml-comp/multimedia/aml_mp_sdk/tests/amlMpMediaPlayerDemo/AmlMpMediaPlayerDemo.cpp
T

2565 lines
86 KiB
C++
Raw Normal View History

2026-08-13 11:28:40 +08:00
/*
* 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 "AmlMpMediaPlayerDemo"
#include <utils/AmlMpLog.h>
#include <utils/AmlMpUtils.h>
#include <unistd.h>
#include <getopt.h>
#include "TestUtils.h"
#include <Aml_MP/Aml_MediaPlayer.h>
#include <string>
#include <vector>
#include <inttypes.h>
#include <signal.h>
#include <thread>
#include "../amlMpTestSupporter/TestModule.h"
#include <../../mediaplayer/AmlMediaPlayerBase.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <poll.h>
#include <termios.h>
#include <errno.h>
#include <iostream>
#include <stdexcept>
#include <Aml_MP/Cas.h>
//srand
#include <stdlib.h>
#include <time.h>
///////////////////////////////////////////////////////////////////////////////
//
struct Argument;
struct AmlMpMediaPlayerDemo;
struct playerRoster;
//func
static int tty_reset(int fd);
static int tty_cbreak(int fd);
//Track info
static void printCurTrackInfo(Aml_MP_TrackInfo *trackInfo, Aml_MP_MediaInfo* mediaInfo, Aml_MP_StreamType streamType);
static int getNextTrack(Aml_MP_TrackInfo *trackInfo, Aml_MP_MediaInfo* mediaInfo, Aml_MP_StreamType streamType);
static void printMediaInfo(Aml_MP_MediaInfo *mediaInfo);
//Multi
static int multiPlaybackThread(int id, bool isMain);
static int createMultiPlayback(int id, AML_MP_MEDIAPLAYER* player, struct Argument* argument, AmlMpMediaPlayerDemo* commandsProcess);
static int destroyMultiPlayback(int id);
static void closeMultiPlayback(int id);
static void closeAllMultiPlayback();
//utils
static int isUrlValid(const std::string url, std::string& urlHead, std::string& urlFile);
static int startingPlayCheck();
//callback func
static const char* mediaPlayerMediaErrorType2Str(Aml_MP_MediaPlayerMediaErrorType type);
void demoCallback(void* userData, Aml_MP_MediaPlayerEventType event, int64_t param);
//info
static void showOption();
static void showUsage();
///////////////////////////////////////////////////////////////////////////////
//static
static const char* mName = LOG_TAG;
using namespace aml_mp;
///////////////////////////////////////////////////////////////////////////////
//define
#define WRESET "\033[0m"
#define RED "\033[31m"
#define GREEN "\033[32m"
#define TTY_RESET_FD(fd) \
do { \
if (tty_reset(fd) < 0) { \
printf("\n tty_reset error\n"); \
} \
} while (0)
#define TTY_CBREAK_FD(fd) \
do { \
if (tty_cbreak(fd) < 0) { \
printf("\n tty_cbreak error\n"); \
} \
} while (0)
static bool AMMP_DEBUG_MODE_ENABLE = false;
#define TERMINAL_DEBUG(fmt, ...) \
do { \
if (AMMP_DEBUG_MODE_ENABLE) { \
printf("[%s:%d] " fmt , __FUNCTION__, __LINE__, ##__VA_ARGS__); \
} \
} while (0)
#define TERMINAL_ERROR(fmt, ...) \
do { \
printf(RED "---------------------------ERROR---------------------------\n" WRESET); \
printf(RED "-----------------------------------------------------------\n" WRESET); \
printf(RED fmt "\n", ##__VA_ARGS__); \
printf(RED "-----------------------------------------------------------\n" WRESET); \
printf(RED "---------------------------ERROR---------------------------\n" WRESET); \
} while (0)
#define MIN(A, B) ( (A) > (B) ? (B) : (A) )
#define MAX(A, B) ( (A) > (B) ? (A) : (B) )
#define MEDIAPLAYERDEMO_MAIN (0)
#define MEDIAPLAYERDEMO_PIP (1)
#define ENUM_TO_STR(e) case e: return TO_STR(e); break
#define TO_STR(v) #v
///////////////////////////////////////////////////////////////////////////////
//Argument
//coverity[definition]
struct Argument
{
std::string url;
int x = 0;
int y = 0;
int viewWidth = 0;
int viewHeight = 0;
int channelId = -1;
bool onlyVideo = false;
bool onlyAudio = false;
int tunnelId = -1;
int loopMode = 0;
bool noSignalHandler = 0;
std::string licenseUrl;
uint64_t options = 0;
bool noAutoExit = false;
};
///////////////////////////////////////////////////////////////////////////////
//playerRoster
#define MaxPlayerNum 4
struct playerRoster
{
static playerRoster& instance() {
static playerRoster sInstance;
return sInstance;
}
int registerAll(AML_MP_MEDIAPLAYER player, int id, const struct Argument* argument, const struct AmlMpMediaPlayerDemo* demo) {
if (id < 0 || id >= MaxPlayerNum || argument == NULL) {
printf("%s invalid, id:%d, argument:%p, demo:%p \n", __FUNCTION__, id, argument, demo);
return -1;
}
mLock.lock();
mPlayers[id] = player;
mPlayerArgument[id].url = argument->url;
mPlayerArgument[id].x = argument->x;
mPlayerArgument[id].y = argument->y;
mPlayerArgument[id].viewWidth = argument->viewWidth;
mPlayerArgument[id].viewHeight = argument->viewHeight;
mPlayerArgument[id].channelId = argument->channelId;
mPlayerArgument[id].onlyVideo = argument->onlyVideo;
mPlayerArgument[id].onlyAudio = argument->onlyAudio;
mPlayerArgument[id].tunnelId = argument->tunnelId;
mPlayerArgument[id].loopMode = argument->loopMode;
mPlayerArgument[id].noSignalHandler = argument->noSignalHandler;
mPlayerArgument[id].licenseUrl = argument->licenseUrl;
mPlayerArgument[id].options = argument->options;
mPlayerArgument[id].noAutoExit = argument->noAutoExit;
mPlayerPlayerDemo[id] = const_cast<struct AmlMpMediaPlayerDemo*>(demo);
if (NULL != player) {
++mPlayerHandlerCount;
}
mLock.unlock();
return id;
}
int registerPlayerArgument(int id, const struct Argument* argument) {
if (id < 0 || id >= MaxPlayerNum || argument == NULL) {
printf("%s invalid, id:%d, argument:%p \n", __FUNCTION__, id, argument);
return -1;
}
mLock.lock();
mPlayerArgument[id].url = argument->url;
mPlayerArgument[id].x = argument->x;
mPlayerArgument[id].y = argument->y;
mPlayerArgument[id].viewWidth = argument->viewWidth;
mPlayerArgument[id].viewHeight = argument->viewHeight;
mPlayerArgument[id].channelId = argument->channelId;
mPlayerArgument[id].onlyVideo = argument->onlyVideo;
mPlayerArgument[id].onlyAudio = argument->onlyAudio;
mPlayerArgument[id].tunnelId = argument->tunnelId;
mPlayerArgument[id].loopMode = argument->loopMode;
mPlayerArgument[id].noSignalHandler = argument->noSignalHandler;
mPlayerArgument[id].licenseUrl = argument->licenseUrl;
mPlayerArgument[id].options = argument->options;
mPlayerArgument[id].noAutoExit = argument->noAutoExit;
mLock.unlock();
return id;
}
int registerPlayerThreadHandle(int id, std::thread thread) {
if (id < 0 || id >= MaxPlayerNum) {
printf("%s invalid, id:%d\n", __FUNCTION__, id);
return -1;
}
mLock.lock();
mThread[id] = std::move(thread);
mLock.unlock();
return id;
}
int unregisterPlayer(AML_MP_MEDIAPLAYER player) {
if (player == NULL) {
printf("%s player invalid, player=%p \n", __FUNCTION__, player);
return -1;
}
mLock.lock();
for (size_t i = 0; i < MaxPlayerNum; ++i) {
if (player == mPlayers[i]) {
mPlayers[i] = NULL;
//memset(&mPlayerArgument[i], 0, sizeof(struct Argument));
mPlayerPlayerDemo[i] = NULL;
if (mPlayerHandlerCount > 0) {
--mPlayerHandlerCount;
}
break;
}
}
mLock.unlock();
return 0;
}
bool isMultiPlayerExist(int id) {
bool isExist = false;
if (id < 0 || id >= MaxPlayerNum ) {
printf("%s invalid, id:%d,\n", __FUNCTION__, id);
return isExist;
}
mLock.lock();
if (NULL != mPlayers[id]) {
isExist = true;
}
mLock.unlock();
return isExist;
}
void getPlayerHandle(int id, AML_MP_MEDIAPLAYER *player) {
if (id < 0 || id >= MaxPlayerNum) {
printf("%s invalid, id:%d \n", __FUNCTION__, id);
return;
}
mLock.lock();
if (mPlayers[id] != NULL) {
*player = mPlayers[id];
}
mLock.unlock();
}
void getPlayerArgument(int id, struct Argument** argument) {
if (id < 0 || id >= MaxPlayerNum) {
printf("%s invalid, id:%d \n", __FUNCTION__, id);
return;
}
mLock.lock();
*argument = (&mPlayerArgument[id]);
mLock.unlock();
}
void getPlayerDemoHandle(int id, struct AmlMpMediaPlayerDemo** playerDemo) {
if (id < 0 || id >= MaxPlayerNum) {
printf("%s invalid, id:%d \n", __FUNCTION__, id);
return;
}
mLock.lock();
if (NULL != mPlayerPlayerDemo[id]) {
*playerDemo = (mPlayerPlayerDemo[id]);
}
mLock.unlock();
}
void getPlayerThreadHandle(int id, std::thread** thread) {
if (id < 0 || id >= MaxPlayerNum) {
printf("%s invalid, id:%d \n", __FUNCTION__, id);
return;
}
mLock.lock();
*thread = (&mThread[id]);
mLock.unlock();
}
int playerHandlerCount() {
int count = 0;
mLock.lock();
count = mPlayerHandlerCount;
mLock.unlock();
return count;
}
private:
playerRoster() {
for (int i = 0; i < MaxPlayerNum; ++i) {
mPlayers[i] = NULL;
mPlayerArgument[i].url = "";
mPlayerArgument[i].x = -1;
mPlayerArgument[i].y = -1;
mPlayerArgument[i].viewWidth = -1;
mPlayerArgument[i].viewHeight = -1;
mPlayerArgument[i].channelId = -1;
mPlayerArgument[i].onlyVideo = false;
mPlayerArgument[i].onlyAudio = false;
mPlayerArgument[i].tunnelId = -1;
mPlayerArgument[i].loopMode = 0;
mPlayerArgument[i].noSignalHandler = 0;
mPlayerArgument[i].licenseUrl = "";
mPlayerArgument[i].options = 0;
mPlayerArgument[i].noAutoExit = 0;
mPlayerPlayerDemo[i] = NULL;
mPlayerHandlerCount = 0;
}
}
std::mutex mLock;
int mPlayerHandlerCount = 0;
AML_MP_MEDIAPLAYER mPlayers[MaxPlayerNum];
struct Argument mPlayerArgument[MaxPlayerNum];
struct AmlMpMediaPlayerDemo* mPlayerPlayerDemo[MaxPlayerNum];
std::thread mThread[MaxPlayerNum];
playerRoster(const playerRoster&) = delete;
playerRoster& operator=(const playerRoster&) = delete;
};
///////////////////////////////////////////////////////////////////////////////
//AmlMpMediaPlayerCommandProcessor
struct AmlMpMediaPlayerCommandProcessor : CommandProcessor
{
AmlMpMediaPlayerCommandProcessor(const std::string& prompt = ">");
~AmlMpMediaPlayerCommandProcessor();
virtual int fetchAndProcessCommands();
private:
AmlMpMediaPlayerCommandProcessor(const AmlMpMediaPlayerCommandProcessor&) = delete;
AmlMpMediaPlayerCommandProcessor& operator=(const AmlMpMediaPlayerCommandProcessor&) = delete;
};
AmlMpMediaPlayerCommandProcessor::AmlMpMediaPlayerCommandProcessor(const std::string& prompt)
: CommandProcessor(prompt)
{
MLOGI();
}
AmlMpMediaPlayerCommandProcessor::~AmlMpMediaPlayerCommandProcessor()
{
MLOGI();
}
int AmlMpMediaPlayerCommandProcessor::fetchAndProcessCommands()
{
try {
bool prompt = false;
std::string lastCommand = "-1";
for (;;) {
// 检查mInterrupter是否有效
if (mInterrupter && mInterrupter()) {
break;
}
if (tcgetpgrp(0) != getpid()) {
usleep(10 * 1000);
continue;
}
if (prompt) {
prompt = false;
fprintf(stderr, "%s", mPrompt.c_str());
}
struct pollfd fds;
fds.fd = STDIN_FILENO;
fds.events = POLL_IN;
fds.revents = 0;
// change the wait time from 1s to 100ms to avoid
// the situation that the signal change is not detected in time
int ret = ::poll(&fds, 1, 100);
if (ret < 0) {
//printf("poll STDIN_FILENO failed! %d\n", -errno);
} else if (ret > 0) {
if (fds.revents & POLL_ERR) {
MLOGE("poll error!");
continue;
} else if (!(fds.revents & POLL_IN)) {
continue;
}
prompt = true;
char buffer[100]{0};
int len = ::read(STDIN_FILENO, buffer, sizeof(buffer));
if (len <= 0) {
MLOGE("read failed! %d", -errno);
continue;
}
if (len > -1)
buffer[(len < 100 ? len : 99)] = '\0';
{
//debug
TERMINAL_DEBUG("read buf:%s, %d, size:%d\n", buffer, buffer[0], len);
int i = 0;
for (i = 0; i < len; i++) {
TERMINAL_DEBUG("%c(%d)\n", buffer[i], buffer[i]);
}
}
//check for whitespace characters
std::string buf(buffer);
size_t b = 0;
size_t e = buf.size();
while (b < e) {
if (isspace(buf[b]) || iscntrl(buf[b])) ++b;
else if (isspace(buf[e]) || iscntrl(buf[e])) --e;
else break;
}
TERMINAL_DEBUG("read b:%zu, e:%zu\n", b, e);
if (b < e) {
buf = buf.substr(b, e - b + 1);
lastCommand = buf;
} else if (b == e && buf.size() > 0) {
//direct choice buf[0] - safe access with bounds checking
buf = std::string(1, buf[0]);
} else {
continue;
}
// Safe split with empty result handling
std::vector<std::string> args = split(buf);
if (!args.empty()) {
mCommandVisitor(args);
}
}
}
} catch (const std::bad_function_call& e) {
MLOGE("Bad function call exception: %s", e.what());
} catch (const std::length_error& e) {
MLOGE("Length error exception: %s", e.what());
} catch (const std::exception& e) {
MLOGE("Standard exception: %s", e.what());
} catch (...) {
MLOGE("Unknown exception caught");
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
//AmlMpMediaPlayerDemo
static const int forwardRateFactorMap[] = {
8,
16,
32,
64,
1,
};
static const int rewindRateFactorMap[] = {
-8,
-16,
-32,
-64,
};
struct AmlMpMediaPlayerDemo : public TestModule
{
AmlMpMediaPlayerDemo(int id);
~AmlMpMediaPlayerDemo();
int fetchAndProcessCommands();
virtual void* getCommandHandle() const;
void setCommandHandle(void * handle);
int waitPreparedEvent();
void broadcast(bool result);
static int installSignalHandler();
public:
bool mQuitPending = false;
int mId;
private:
AML_MP_MEDIAPLAYER mPlayer = NULL;
std::condition_variable mCondition;
std::mutex mMutex;
bool mPrepared = false;
protected:
const TestModule::Command* getCommandTable() const;
bool processCommand(const std::vector<std::string>& args);
private:
//Rewind Forward
char mRewindStateIndex = 0, mForwardStateIndex = 0;
bool isRewindOrForward = false;
std::string RewindOrForward = "";
void resetRewindAndForwardState() { mRewindStateIndex = 0; mForwardStateIndex = 0; }
private:
sptr<CommandProcessor> mCommandProcessor;
static std::thread mSignalHandleThread;
};
std::thread AmlMpMediaPlayerDemo::mSignalHandleThread;
AmlMpMediaPlayerDemo::AmlMpMediaPlayerDemo(int id)
: mId(id)
{
MLOGI("mId:%d", mId);
}
AmlMpMediaPlayerDemo::~AmlMpMediaPlayerDemo()
{
MLOGI();
}
int AmlMpMediaPlayerDemo::fetchAndProcessCommands()
{
char promptBuf[50];
snprintf(promptBuf, sizeof(promptBuf), "AmlMpMediaPlayerDemo (press 'h' for help) > ");
mCommandProcessor = new AmlMpMediaPlayerCommandProcessor(promptBuf);
if (mCommandProcessor == nullptr) {
return -1;
}
mCommandProcessor->setCommandVisitor(std::bind(&AmlMpMediaPlayerDemo::processCommand, this, std::placeholders::_1));
mCommandProcessor->setInterrupter([this]() {return mQuitPending;});
return mCommandProcessor->fetchAndProcessCommands();
}
bool AmlMpMediaPlayerDemo::processCommand(const std::vector<std::string>& args)
{
try {
bool ret = true;
if (args.empty()) {
MLOGE("%s, %d: args is empty", __FUNCTION__, __LINE__);
return false;
}
std::string cmd = *args.begin();
if (cmd == "q") {
MLOGI("%s,%d set mQuitPending = true", __FUNCTION__, __LINE__);
//mQuitPending = true;
Argument* argument = nullptr;
playerRoster::instance().getPlayerArgument(MEDIAPLAYERDEMO_MAIN, &argument);
if (argument && argument->loopMode) {
TERMINAL_DEBUG("q command, reset loop mode!\n");
argument->loopMode = 0;
}
closeAllMultiPlayback();
} else {
if (isRewindOrForward && (RewindOrForward != cmd || (cmd.compare("<") && cmd.compare(">")))) {
isRewindOrForward = false;
resetRewindAndForwardState();
}
if (">" == cmd) {
isRewindOrForward = true;
//coverity[copy_assignment_call]
RewindOrForward = cmd;
mRewindStateIndex = 0;
const_cast<std::vector<std::string>&>(args).emplace_back(std::to_string(forwardRateFactorMap[mForwardStateIndex]));
if (++mForwardStateIndex >= sizeof(forwardRateFactorMap) / sizeof(forwardRateFactorMap[0])) {
mForwardStateIndex = 0;
}
} else if ("<" == cmd) {
isRewindOrForward = true;
//coverity[copy_assignment_call]
RewindOrForward = cmd;
mForwardStateIndex = 0;
const_cast<std::vector<std::string>&>(args).emplace_back(std::to_string(rewindRateFactorMap[mRewindStateIndex]));
if (++mRewindStateIndex >= sizeof(rewindRateFactorMap) / sizeof(rewindRateFactorMap[0])) {
mRewindStateIndex = 0;
}
}
{//debug
int i = 0, size = args.size();
TERMINAL_DEBUG("processCommand: size:%d\n", size);
for (size_t j = 0; j < args.size(); j++) {
const std::string& pStr = args[j];
TERMINAL_DEBUG("%s\n", pStr.c_str());
}
}
TestModule::processCommand(args);
}
return ret;
} catch (const std::length_error& e) {
MLOGE("Length error exception in processCommand: %s", e.what());
return false;
} catch (const std::exception& e) {
MLOGE("Standard exception in processCommand: %s", e.what());
return false;
} catch (...) {
MLOGE("Unknown exception caught in processCommand");
return false;
}
}
///////////////////////////////////////////////////////////////////////////////
static void save2BitmapFile(const char *filename, uint32_t *bitmap, int w, int h) {
FILE *f;
char fname[100];
snprintf(fname, sizeof(fname), "%s.ppm", filename);
f = fopen(fname, "w");
if (!f) {
ALOGE("Error cannot open file %s!", fname);
return;
}
fprintf(f, "P6\n" "%d %d\n" "%d\n", w, h, 255);
for (int y = 0; y < h; y++) {
for (int x = 0; x < w; x++) {
int v = bitmap[y * w + x];
putc((v >> 16) & 0xff, f);
putc((v >> 8) & 0xff, f);
putc((v >> 0) & 0xff, f);
}
}
printf("save2BitmapFile filename:%s\n", filename);
fclose(f);
}
static Aml_MP_MediaPlayerInvokeReply* newMediaPlayerInvokeReply(void)
{
Aml_MP_MediaPlayerInvokeReply* ptr = new Aml_MP_MediaPlayerInvokeReply;
if (ptr == nullptr) {
printf("new Aml_MP_MediaPlayerInvokeReply fail\n");
return nullptr;
}
memset(ptr, 0, sizeof(Aml_MP_MediaPlayerInvokeReply));
return ptr;
}
static void delMediaPlayerInvokeReply(Aml_MP_MediaPlayerInvokeReply *ptr)
{
if (ptr == nullptr) {
return;
}
delete ptr;
return;
}
static struct TestModule::Command g_commandTable[] = {
{
"h", 0, "help",
[](AML_MP_MEDIAPLAYER player __unused, const std::vector<std::string>& args __unused) -> int {
showOption();//TestModule::printCommands(g_commandTable, true);
return 0;
}
},
{
"p", 0, "pause player",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = Aml_MP_MediaPlayer_Pause(player);
printf("call pause player, ret:%d\n", ret);
return ret;
}
},
{
"r", 0, "resume player",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = Aml_MP_MediaPlayer_Resume(player);
printf("call resume player, ret:%d\n", ret);
return ret;
}
},
/*
{
"u", 0, "set data source",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
TTY_RESET_FD(STDIN_FILENO);
printf("call setdatasource,url address: ");
int ret=0;
std::string urlStr;
const char* url;
try {
std::getline (std::cin, urlStr);
url = urlStr.c_str();
} catch (const std::invalid_argument & ia) {
printf("Invalid argument: %s. \n", ia.what());
}
if (url < 0) {
ret = -1;
goto exit;
}
ret = Aml_MP_MediaPlayer_SetDataSource(player, url);
exit:
printf("call set data source:%s ret: %d\n", url, ret);
TTY_CBREAK_FD(STDIN_FILENO);
return ret;
}
},
*/
{
"d", 0, "hide video",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = Aml_MP_MediaPlayer_HideVideo(player);
printf("call hide video, ret : %d\n",ret);
return ret;
}
},
{
"D", 0, "show video",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = Aml_MP_MediaPlayer_ShowVideo(player);
printf("call show video,ret : %d\n",ret);
return ret;
}
},
{
"t", 0, "hide Subtitle",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = Aml_MP_MediaPlayer_HideSubtitle(player);
printf("call hide Subtitle, ret : %d\n",ret);
return ret;
}
},
{
"T", 0, "show Subtitle",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = Aml_MP_MediaPlayer_ShowSubtitle(player);
printf("call show Subtitle,ret : %d\n",ret);
return ret;
}
},
{
"K", 0, "call seek",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
TTY_RESET_FD(STDIN_FILENO);
printf("call seek, press position [milliseconds] : ");
int ret = 0;
std::string msecStr;
int msec = -1;
try {
std::getline (std::cin, msecStr);
msec = std::stoi(msecStr);
} catch (const std::invalid_argument & ia) {
printf("Invalid argument: %s. \n", ia.what());
msec = -1;
} catch (const std::length_error & ia) {
printf("length_error: %s. \n", ia.what());
msec = -1;
}
if (msec < 0) {
ret = -1;
goto exit;
}
ret = Aml_MP_MediaPlayer_SeekTo(player, msec);
exit:
printf("call seek, msec:%d, ret:%d\n", msec, ret);
TTY_CBREAK_FD(STDIN_FILENO);
return ret;
}
},
{
"v", 0, "get volume",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
float volume = -1;
int ret = Aml_MP_MediaPlayer_GetVolume(player, &volume);
printf("Current volume: %f, ret: %d\n", volume, ret);
return ret;
}
},
{
"V", 0, "set volume",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
TTY_RESET_FD(STDIN_FILENO);
printf("set volume, press volume [0 ~ 100] : ");
int ret = 0;
std::string volumeStr;
float volume = -1;
try {
std::getline (std::cin, volumeStr);
volume = std::stof(volumeStr);
} catch (const std::invalid_argument & ia) {
printf("Invalid argument: %s. \n", ia.what());
volume = -1;
} catch (const std::length_error & ia) {
printf("length_error: %s. \n", ia.what());
volume = -1;
}
if (volume < 0 || volume > 100) {
ret = -1;
goto exit;
}
ret = Aml_MP_MediaPlayer_SetVolume(player, volume);
exit:
printf("set volume: %f, ret: %d\n", volume, ret);
TTY_CBREAK_FD(STDIN_FILENO);
return ret;
}
},
{
"F", 0, "set Fast rate",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
TTY_RESET_FD(STDIN_FILENO);
printf("call set Fast rate, press rate [0.25/0.5/1/1.25/1.5/2] : ");
int ret = 0;
std::string rateStr;
float rate = -1;
try {
std::getline (std::cin, rateStr);
rate = std::stof(rateStr);
} catch (const std::invalid_argument & ia) {
printf("Invalid argument: %s. \n", ia.what());
rate = -1;
} catch (const std::length_error & ia) {
printf("length_error: %s. \n", ia.what());
rate = -1;
}
if (rate < 0 || rate > 2) {
ret = -1;
goto exit;
}
ret = Aml_MP_MediaPlayer_SetPlaybackRate(player, rate);
exit:
printf("call set Fast rate, rate:%f, ret:%d\n", rate, ret);
TTY_CBREAK_FD(STDIN_FILENO);
return ret;
}
},
{
"W", 0, "set video window",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
TTY_RESET_FD(STDIN_FILENO);
int ret = 0;
std::string xStr;
std::string yStr;
std::string widthStr;
std::string heightStr;
int x = -1;
int y = -1;
int width = -1;
int height = -1;
try {
printf("call set video window, press X pos : ");
std::getline (std::cin, xStr);
printf("call set video window, press Y pos : ");
std::getline (std::cin, yStr);
printf("call set video window, press width pos : ");
std::getline (std::cin, widthStr);
printf("call set video window, press height pos : ");
std::getline (std::cin, heightStr);
x = std::stoi(xStr);
y = std::stoi(yStr);
width = std::stoi(widthStr);
height = std::stoi(heightStr);
} catch (const std::invalid_argument & ia) {
printf("Invalid argument: %s. \n", ia.what());
x = -1;
} catch (const std::length_error & ia) {
printf("length_error: %s. \n", ia.what());
x = -1;
}
if (x < 0 || y < 0 || width < 0 || height < 0) {
ret = -1;
goto exit;
}
ret = Aml_MP_MediaPlayer_SetVideoWindow(player, x, y, width, height);
exit:
printf("call set video window, x:%d, y:%d, width:%d, height:%d, ret:%d\n",x, y, width, height, ret);
TTY_CBREAK_FD(STDIN_FILENO);
return ret;
}
},
{
"sOnlyHint", 0, "set only hint",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = 0;
if (args.size() < 2) {
printf("Error: missing parameter for set only hint\n");
return -1;
}
try {
Aml_MP_MediaPlayerOnlyHintType type = (Aml_MP_MediaPlayerOnlyHintType)atoi(args.at(1).c_str());
ret = Aml_MP_MediaPlayer_SetParameter(player, AML_MP_MEDIAPLAYER_PARAMETER_ONLYHINT_TYPE, (void*)&type);
printf("AML_MP_MEDIAPLAYER_PARAMETER_ONLYHINT_TYPE set type: %d, ret: %d\n", type, ret);
} catch (const std::out_of_range& e) {
printf("out_of_range exception : %s", e.what());
}
return ret;
}
},
/*
{
"y", 0, "set AVSync Source",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = 0;
Aml_MP_MediaPlayerAVSyncSource syncSource;
memset(&syncSource, 0, sizeof(Aml_MP_MediaPlayerAVSyncSource));
syncSource = AML_MP_AVSYNC_SOURCE_VIDEO;
ret = Aml_MP_MediaPlayer_SetAVSyncSource(player,syncSource);
printf("AML_MP_AVSYNC_SOURCE_VIDEO set SyncSource: 0x%x,ret: %d\n\n", syncSource, ret);
return ret;
}
},
*/
{
"M", 0, "set mute umute",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
TTY_RESET_FD(STDIN_FILENO);
printf("call set mute/umute, press mute/umute [1/0] : ");
int ret = 0;
std::string muteStr;
int mute = -1;
try {
std::getline (std::cin, muteStr);
mute = std::stoi(muteStr, NULL, 10);
} catch (const std::invalid_argument & ia) {
printf("Invalid argument: %s. \n", ia.what());
mute = -1;
} catch (const std::length_error & ia) {
printf("length_error: %s. \n", ia.what());
mute = -1;
}
if (mute < 0 || mute > 1) {
ret = -1;
goto exit;
}
ret = Aml_MP_MediaPlayer_SetMute(player, mute);
exit:
printf("Set mute: %d, ret: %d\n", mute, ret);
TTY_CBREAK_FD(STDIN_FILENO);
return ret;
}
},
{
"<", 0, "set Rewind",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
TTY_RESET_FD(STDIN_FILENO);
int ret = -1;
float rewind = 0;
if (args.size() >= 2) {
try {
rewind = stof(args.at(1));
} catch (const std::out_of_range & ia) {
printf("out_of_range exception %s.", ia.what());
}
}
if (rewind >= 0) {
goto exit;
}
if (-1 == rewind) {
rewind = 1;//maybe we need speed=1
}
ret = Aml_MP_MediaPlayer_SetPlaybackRate(player, rewind);
exit:
printf("call set Rewind, rateFactor:%f, ret:%d\n", rewind, ret);
TTY_CBREAK_FD(STDIN_FILENO);
return ret;
}
},
{
">", 0, "set Forward",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
TTY_RESET_FD(STDIN_FILENO);
int ret = -1;
float forward = 0;
if (args.size() >= 2) {
try {
forward = stof(args.at(1));
} catch (const std::out_of_range & ia) {
printf("out_of_range exception %s.", ia.what());
}
}
if (forward <= 0) {
goto exit;
}
ret = Aml_MP_MediaPlayer_SetPlaybackRate(player, forward);
exit:
printf("call set Forward, rateFactor:%f, ret:%d\n", forward, ret);
TTY_CBREAK_FD(STDIN_FILENO);
return ret;
}
},
{
"a", 0, "Get Audio Info Channels",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = 0;
printf("\n\n Available Audios : \n");
Aml_MP_MediaPlayerInvokeRequest trackRequest;
//the size of Aml_MP_MediaPlayerInvokeReply is 14416 bytes.
//so we not use stack memory, use heap memory.
Aml_MP_MediaPlayerInvokeReply *trackReply = newMediaPlayerInvokeReply();
if (trackReply == nullptr) {
return -1;
}
memset(&trackRequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
trackRequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_GET_TRACK_INFO;
ret = Aml_MP_MediaPlayer_Invoke(player, &trackRequest, trackReply);
Aml_MP_MediaPlayerInvokeRequest mediaRequest;
Aml_MP_MediaPlayerInvokeReply *mediaReply = newMediaPlayerInvokeReply();
if (mediaReply == nullptr) {
delMediaPlayerInvokeReply(trackReply);
return -1;
}
memset(&mediaRequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
mediaRequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_GET_MEDIA_INFO;
//coverity[value_overwrite]
ret = Aml_MP_MediaPlayer_Invoke(player, &mediaRequest, mediaReply);
printCurTrackInfo(&(trackReply->u.trackInfo), &(mediaReply->u.mediaInfo), AML_MP_STREAM_TYPE_AUDIO);
delMediaPlayerInvokeReply(trackReply);
delMediaPlayerInvokeReply(mediaReply);
return ret;
}
},
{
"A", 0, "Set Next Audio component",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = 0;
Aml_MP_MediaPlayerInvokeRequest selectrequest;
Aml_MP_MediaPlayerInvokeReply *selectreply = nullptr;
Aml_MP_MediaPlayerInvokeRequest trackRequest;
Aml_MP_MediaPlayerInvokeReply *trackReply = newMediaPlayerInvokeReply();
if (trackReply == nullptr) {
return -1;
}
memset(&trackRequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
trackRequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_GET_TRACK_INFO;
ret = Aml_MP_MediaPlayer_Invoke(player, &trackRequest, trackReply);
Aml_MP_MediaPlayerInvokeRequest mediaRequest;
Aml_MP_MediaPlayerInvokeReply *mediaReply = newMediaPlayerInvokeReply();
if (mediaReply == nullptr) {
delMediaPlayerInvokeReply(trackReply);
return -1;
}
memset(&mediaRequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
mediaRequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_GET_MEDIA_INFO;
//coverity[value_overwrite]
ret = Aml_MP_MediaPlayer_Invoke(player, &mediaRequest, mediaReply);
int index = getNextTrack(&(trackReply->u.trackInfo), &(mediaReply->u.mediaInfo), AML_MP_STREAM_TYPE_AUDIO);
if (index < 0) {
goto exit;
}
selectreply = newMediaPlayerInvokeReply();
if (selectreply == nullptr) {
delMediaPlayerInvokeReply(trackReply);
delMediaPlayerInvokeReply(mediaReply);
return -1;
}
memset(&selectrequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
selectrequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_SELECT_TRACK;
selectrequest.u.data32 = index;
//coverity[value_overwrite]
ret = Aml_MP_MediaPlayer_Invoke(player, &selectrequest, selectreply);
exit:
printf("Set Next Audio component, ret:%d, index:%d\n", ret, index);
delMediaPlayerInvokeReply(trackReply);
delMediaPlayerInvokeReply(mediaReply);
delMediaPlayerInvokeReply(selectreply);
return ret;
}
},
{
"U", 0, "Unselect CurAudio component",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = 0;
Aml_MP_MediaPlayerInvokeRequest selectrequest;
Aml_MP_MediaPlayerInvokeReply *selectreply = nullptr;
Aml_MP_MediaPlayerInvokeRequest mediaRequest;
Aml_MP_MediaPlayerInvokeReply *mediaReply = newMediaPlayerInvokeReply();
if (mediaReply == nullptr) {
return -1;
}
memset(&mediaRequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
mediaRequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_GET_MEDIA_INFO;
ret = Aml_MP_MediaPlayer_Invoke(player, &mediaRequest, mediaReply);
int index = mediaReply->u.mediaInfo.curAudioIndex;
if (index < 0) {
goto exit;
}
selectreply = newMediaPlayerInvokeReply();
if (selectreply == nullptr) {
delMediaPlayerInvokeReply(mediaReply);
return -1;
}
memset(&selectrequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
selectrequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_UNSELECT_TRACK;
selectrequest.u.data32 = index;
//coverity[value_overwrite]
ret = Aml_MP_MediaPlayer_Invoke(player, &selectrequest, selectreply);
exit:
printf("Unselect Current Audio component, ret:%d, index:%d\n", ret, index);
delMediaPlayerInvokeReply(mediaReply);
delMediaPlayerInvokeReply(selectreply);
return ret;
}
},
{
"s", 0, "Get Subtitles Info channels",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = 0;
printf("\n\n Available Subtitles : \n");
Aml_MP_MediaPlayerInvokeRequest trackRequest;
Aml_MP_MediaPlayerInvokeReply *trackReply = newMediaPlayerInvokeReply();
if (trackReply == nullptr) {
return -1;
}
memset(&trackRequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
trackRequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_GET_TRACK_INFO;
ret = Aml_MP_MediaPlayer_Invoke(player, &trackRequest, trackReply);
Aml_MP_MediaPlayerInvokeRequest mediaRequest;
Aml_MP_MediaPlayerInvokeReply *mediaReply = newMediaPlayerInvokeReply();
if (mediaReply == nullptr) {
delMediaPlayerInvokeReply(trackReply);
return -1;
}
memset(&mediaRequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
mediaRequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_GET_MEDIA_INFO;
//coverity[value_overwrite]
ret = Aml_MP_MediaPlayer_Invoke(player, &mediaRequest, mediaReply);
printCurTrackInfo(&(trackReply->u.trackInfo), &(mediaReply->u.mediaInfo), AML_MP_STREAM_TYPE_SUBTITLE);
delMediaPlayerInvokeReply(trackReply);
delMediaPlayerInvokeReply(mediaReply);
return ret;
}
},
{
"S", 0, "Set Next Subtitle component",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = 0;
Aml_MP_MediaPlayerInvokeRequest selectrequest;
Aml_MP_MediaPlayerInvokeReply *selectreply = nullptr;
Aml_MP_MediaPlayerInvokeRequest trackRequest;
Aml_MP_MediaPlayerInvokeReply *trackReply = newMediaPlayerInvokeReply();
if (trackReply == nullptr) {
return -1;
}
memset(&trackRequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
trackRequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_GET_TRACK_INFO;
ret = Aml_MP_MediaPlayer_Invoke(player, &trackRequest, trackReply);
Aml_MP_MediaPlayerInvokeRequest mediaRequest;
Aml_MP_MediaPlayerInvokeReply *mediaReply = newMediaPlayerInvokeReply();
if (mediaReply == nullptr) {
delMediaPlayerInvokeReply(trackReply);
return -1;
}
memset(&mediaRequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
mediaRequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_GET_MEDIA_INFO;
//coverity[value_overwrite]
ret = Aml_MP_MediaPlayer_Invoke(player, &mediaRequest, mediaReply);
int index = getNextTrack(&(trackReply->u.trackInfo), &(mediaReply->u.mediaInfo), AML_MP_STREAM_TYPE_SUBTITLE);
if (index < 0) {
goto exit;
}
selectreply = newMediaPlayerInvokeReply();
if (selectreply == nullptr) {
delMediaPlayerInvokeReply(trackReply);
delMediaPlayerInvokeReply(mediaReply);
return -1;
}
memset(&selectrequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
selectrequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_SELECT_TRACK;
selectrequest.u.data32 = index;
//coverity[value_overwrite]
ret = Aml_MP_MediaPlayer_Invoke(player, &selectrequest, selectreply);
exit:
printf("Set Next Subtitle component, ret:%d, index:%d\n", ret, index);
delMediaPlayerInvokeReply(trackReply);
delMediaPlayerInvokeReply(mediaReply);
delMediaPlayerInvokeReply(selectreply);
return ret;
}
},
{
"u", 0, "Unselect CurSubtitle component",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = 0;
Aml_MP_MediaPlayerInvokeRequest selectrequest;
Aml_MP_MediaPlayerInvokeReply *selectreply = nullptr;
Aml_MP_MediaPlayerInvokeRequest mediaRequest;
Aml_MP_MediaPlayerInvokeReply *mediaReply = newMediaPlayerInvokeReply();
if (mediaReply == nullptr) {
return -1;
}
memset(&mediaRequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
mediaRequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_GET_MEDIA_INFO;
ret = Aml_MP_MediaPlayer_Invoke(player, &mediaRequest, mediaReply);
int index = mediaReply->u.mediaInfo.curSubIndex;
if (index < 0) {
goto exit;
}
selectreply = newMediaPlayerInvokeReply();
if (selectreply == nullptr) {
delMediaPlayerInvokeReply(mediaReply);
return -1;
}
memset(&selectrequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
selectrequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_UNSELECT_TRACK;
selectrequest.u.data32 = index;
//coverity[value_overwrite]
ret = Aml_MP_MediaPlayer_Invoke(player, &selectrequest, selectreply);
exit:
printf("Unselect Current Audio component, ret:%d, index:%d\n", ret, index);
delMediaPlayerInvokeReply(mediaReply);
delMediaPlayerInvokeReply(selectreply);
return ret;
}
},
{
"n", 0, "get current position",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = 0, position = 0;
ret = Aml_MP_MediaPlayer_GetCurrentPosition(player, &position);
printf("Aml_MP_MediaPlayer_GetCurrentPosition get position: %d(ms), ret: %d\n", position, ret);
return ret;
}
},
{
"N", 0, "get duration",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = 0, duration = 0;
ret = Aml_MP_MediaPlayer_GetDuration(player, &duration);
printf("Aml_MP_MediaPlayer_GetDuration get duration: %d(ms), ret: %d\n", duration, ret);
return ret;
}
},
{
"i", 0, "invoke generic method",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = 0;
Aml_MP_MediaPlayerInvokeRequest trackRequest;
Aml_MP_MediaPlayerInvokeReply *trackReply = newMediaPlayerInvokeReply();
if (trackReply == nullptr) {
return -1;
}
memset(&trackRequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
trackRequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_GET_TRACK_INFO;
ret = Aml_MP_MediaPlayer_Invoke(player, &trackRequest, trackReply);
printf("\nAML_MP_MEDIAPLAYER_INVOKE_ID_GET_TRACK_INFO, reply id:0x%x ret: %d\n",trackReply->requestId, ret);
Aml_MP_MediaPlayerInvokeRequest mediaRequest;
Aml_MP_MediaPlayerInvokeReply *mediaReply = newMediaPlayerInvokeReply();
if (mediaReply == nullptr) {
delMediaPlayerInvokeReply(trackReply);
return -1;
}
memset(&mediaRequest, 0, sizeof(Aml_MP_MediaPlayerInvokeRequest));
mediaRequest.requestId = AML_MP_MEDIAPLAYER_INVOKE_ID_GET_MEDIA_INFO;
//coverity[value_overwrite]
ret = Aml_MP_MediaPlayer_Invoke(player, &mediaRequest, mediaReply);
printf("\nAML_MP_MEDIAPLAYER_INVOKE_ID_GET_MEDIA_INFO,reply id:0x%x ret: %d\n",mediaReply->requestId, ret);
printCurTrackInfo(&(trackReply->u.trackInfo), &(mediaReply->u.mediaInfo), AML_MP_STREAM_TYPE_VIDEO);
printCurTrackInfo(&(trackReply->u.trackInfo), &(mediaReply->u.mediaInfo), AML_MP_STREAM_TYPE_AUDIO);
printCurTrackInfo(&(trackReply->u.trackInfo), &(mediaReply->u.mediaInfo), AML_MP_STREAM_TYPE_SUBTITLE);
printMediaInfo(&(mediaReply->u.mediaInfo));
Aml_MP_MediaPlayerID3Info ID3Info;
memset(&ID3Info, 0, sizeof(Aml_MP_MediaPlayerID3Info));
//coverity[value_overwrite]
ret = Aml_MP_MediaPlayer_GetParameter(player, AML_MP_MEDIAPLAYER_PARAMETER_ID3_INFO, (void*)&ID3Info);
if (ret == 0)
{
printf("ID3Info title: %s\n", ID3Info.title);
printf("ID3Info author: %s\n", ID3Info.author);
printf("ID3Info album: %s\n", ID3Info.album);
printf("ID3Info comment: %s\n", ID3Info.comment);
printf("ID3Info year: %s\n", ID3Info.year);
printf("ID3Info track: %d\n", ID3Info.track);
printf("ID3Info genre: %s\n", ID3Info.genre);
printf("ID3Info copyright: %s\n", ID3Info.copyright);
printf("ID3Info pic_type: %s\n", ID3Info.pic_type);
printf("ID3Info pic_size: %d\n", ID3Info.pic_size);
printf("ID3Info pic_data: %p\n", ID3Info.pic_data);
}
delMediaPlayerInvokeReply(trackReply);
delMediaPlayerInvokeReply(mediaReply);
return ret;
}
},
{
"O", 0, "Open PIP",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
TTY_RESET_FD(STDIN_FILENO);
int ret = -1;
std::thread thread;
struct Argument argument;
printf("Open PIP url : ");
try {
argument.url = "-1";
argument.x = 0;
argument.y = 0;
argument.viewWidth = 960;
argument.viewHeight = 540;
argument.channelId = MEDIAPLAYERDEMO_PIP;//maybe need demux=1
argument.tunnelId = 1;
argument.onlyVideo = false;
argument.onlyAudio = false;
argument.licenseUrl = "";
argument.options = 0;
std::getline (std::cin, argument.url);
if (argument.url.compare("-1") == 0 || playerRoster::instance().isMultiPlayerExist(MEDIAPLAYERDEMO_PIP)) {
ret = -1;
goto exit;
}
playerRoster::instance().registerPlayerArgument(MEDIAPLAYERDEMO_PIP, &argument);//only register argument
playerRoster::instance().registerPlayerThreadHandle(MEDIAPLAYERDEMO_PIP, std::thread(multiPlaybackThread, MEDIAPLAYERDEMO_PIP, false));
ret = 0;
} catch (const std::invalid_argument & ia) {
printf("Invalid argument: %s. \n", ia.what());
} catch (const std::length_error & ia) {
printf("length_error exception : %s. \n", ia.what());
}
exit:
printf("call Open PIP, id:%d ret:%d\n", argument.channelId, ret);
TTY_CBREAK_FD(STDIN_FILENO);
return ret;
}
},
{
"C", 0, "Close PIP",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
try {
closeMultiPlayback(MEDIAPLAYERDEMO_PIP);
printf("call Close PIP\n");
return 0;
} catch (const std::exception& e) {
printf("Error in Close PIP: %s\n", e.what());
return -1;
}
}
},
/*
{
"Y", 0, "call reset",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = Aml_MP_MediaPlayer_Reset(player);
printf("call reset ret: %d\n", ret);
return ret;
}
},
{
"y", 0, "call prepare",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = Aml_MP_MediaPlayer_Prepare(player);
printf("call prepare ret: %d\n", ret);
return ret;
}
},
{
"U", 0, "call start",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = Aml_MP_MediaPlayer_Start(player);
printf("call start ret: %d\n", ret);
return ret;
}
},
{
"u", 0, "call stop",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
int ret = Aml_MP_MediaPlayer_Stop(player);
printf("call stop ret: %d\n", ret);
return ret;
}
},
*/
{
"q", 0, "exit playback",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
printf("exit playback\n");
return 0;
}
},
{
"\n", 0, "\n",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
printf("\n");
return 0;
}
},
{
"cas_ioctl", 0, "trigger CAS ioctl (Interactive mode)",
[](AML_MP_MEDIAPLAYER player, const std::vector<std::string>& args __unused) -> int {
char out_json[8192] = {0};
std::string real_input;
printf("\n===== Trigger CAS Ioctl (Interactive) =====\n");
printf("Please input your JSON string and press Enter:\n> ");
fflush(stdout);
if (!(std::cin >> std::ws && std::getline(std::cin, real_input))) {
std::cin.clear();
printf("Error: Input failed or interrupted.\n");
return -1;
}
if (real_input.length() < 2 || real_input.front() != '{' || real_input.back() != '}') {
printf("Error: Invalid JSON format. Must start with '{' and end with '}'.\n");
return -1;
}
printf("Executing command: %s\n", real_input.c_str());
int ret = Aml_MP_CAS_Ioctl(0, real_input.c_str(), out_json, sizeof(out_json));
if (ret != 0) {
printf("Ioctl execution failed with code: %d\nOutput: %s\n", ret, out_json);
} else {
printf("Execution successful!\nOutput: %s\n", out_json);
}
return ret;
}
},
{nullptr, 0, nullptr, nullptr}
};
const TestModule::Command* AmlMpMediaPlayerDemo::getCommandTable() const
{
return g_commandTable;
}
void* AmlMpMediaPlayerDemo::getCommandHandle() const
{
return mPlayer;
}
void AmlMpMediaPlayerDemo::setCommandHandle(void * handle)
{
if (handle != NULL)
mPlayer = handle;
}
int AmlMpMediaPlayerDemo::waitPreparedEvent()
{
printf("waitPreparedEvent \n");
std::unique_lock<std::mutex> autoLock(mMutex);
mCondition.wait(autoLock);
printf("waitPreparedEvent mPrepared:%d\n", mPrepared);
return (mPrepared == true ? 0 : -1);
}
void AmlMpMediaPlayerDemo::broadcast(bool result)
{
printf("broadcast result:%d\n", result);
std::unique_lock<std::mutex> autoLock(mMutex);
mPrepared = result;
mCondition.notify_all();
}
int AmlMpMediaPlayerDemo::installSignalHandler()
{
int ret = 0;
sigset_t blockSet, oldMask;
sigemptyset(&blockSet);
sigaddset(&blockSet, SIGINT);
sigaddset(&blockSet, SIGQUIT);
ret = pthread_sigmask(SIG_SETMASK, &blockSet, &oldMask);
if (ret != 0) {
MLOGE("pthread_sigmask failed! %d", ret);
return -1;
}
mSignalHandleThread = std::thread([blockSet, oldMask] {
int signo = 0;
int err;
for (;;) {
err = sigwait(&blockSet, &signo);
if (err != 0) {
MLOGE("sigwait error! %d", err);
exit(0);
}
printf("Signal Capture:%s\n", strsignal(signo));
MLOGI("Signal Capture:%s\n", strsignal(signo));
switch (signo) {
case SIGINT:
case SIGQUIT:
{
//quit
//mQuitPending = true;
Argument* argument = nullptr;
playerRoster::instance().getPlayerArgument(MEDIAPLAYERDEMO_MAIN, &argument);
if (argument && argument->loopMode) {
TERMINAL_DEBUG("reset loop mode!\n");
argument->loopMode = 0;
}
closeAllMultiPlayback();
}
break;
default:
break;
}
if (pthread_sigmask(SIG_SETMASK, &oldMask, nullptr) != 0) {
MLOGE("restore sigmask failed!");
}
}
});
mSignalHandleThread.detach();
return ret;
}
///////////////////////////////////////////////////////////////////////////////
//
static void printCurTrackInfo(Aml_MP_TrackInfo *trackInfo, Aml_MP_MediaInfo* mediaInfo, Aml_MP_StreamType streamType)
{
if (trackInfo == NULL || mediaInfo == NULL)
return;
int index = 0;
Aml_MP_TrackInfo *info = trackInfo;
char isSelect[5] = " ";
//printf("nb_streams:%d \n", info->nb_streams);
for (index = 0; index < info->nb_streams; ++index) {
memset(isSelect, 0, sizeof(isSelect));
strncpy(isSelect, " ", 1);
if (info->streamInfo[index].streamType == streamType && streamType == AML_MP_STREAM_TYPE_VIDEO) {
if (index == mediaInfo->curVideoIndex) {
snprintf(isSelect, 5, "%s", ">");
}
printf(" %s array index:%d, actual index:%d [video] id:%d, videoCodec:%d(%s), frameRate:%f, width:%d, height:%d, mine:%s\n"
,isSelect
,index
,info->streamInfo[index].u.vInfo.index
,info->streamInfo[index].u.vInfo.id
,info->streamInfo[index].u.vInfo.videoCodec
,mpCodecId2Str(info->streamInfo[index].u.vInfo.videoCodec)
,info->streamInfo[index].u.vInfo.frameRate
,info->streamInfo[index].u.vInfo.width
,info->streamInfo[index].u.vInfo.height
,info->streamInfo[index].u.vInfo.mine);
} else if (info->streamInfo[index].streamType == streamType && streamType == AML_MP_STREAM_TYPE_AUDIO) {
if (index == mediaInfo->curAudioIndex) {
snprintf(isSelect, 5, "%s", ">");
}
printf(" %s array index:%d, actual index:%d [audio] id:%d, audioCodec:%d(%s), nChannels:%d, nSampleRate:%d, mine:%s, language:%s\n"
,isSelect
,index
,info->streamInfo[index].u.aInfo.index
,info->streamInfo[index].u.aInfo.id
,info->streamInfo[index].u.aInfo.audioCodec
,mpCodecId2Str(info->streamInfo[index].u.aInfo.audioCodec)
,info->streamInfo[index].u.aInfo.nChannels
,info->streamInfo[index].u.aInfo.nSampleRate
,info->streamInfo[index].u.aInfo.mine
,info->streamInfo[index].u.aInfo.language);
} else if (info->streamInfo[index].streamType == streamType && streamType == AML_MP_STREAM_TYPE_SUBTITLE) {
if (index == mediaInfo->curSubIndex) {
snprintf(isSelect, 5, "%s", ">");
}
printf(" %s array index:%d, actual index:%d(0x:%x) [subtitle] id:%d, subtitleCodec:%d(%s), mine:%s, language:%s\n"
,isSelect
,index
,info->streamInfo[index].u.sInfo.index
,info->streamInfo[index].u.sInfo.index
,info->streamInfo[index].u.sInfo.id
,info->streamInfo[index].u.sInfo.subtitleCodec
,mpCodecId2Str(info->streamInfo[index].u.sInfo.subtitleCodec)
,info->streamInfo[index].u.sInfo.mine
,info->streamInfo[index].u.sInfo.language);
} else {
;
}
}
printf("\n");
}
static int getNextTrack(Aml_MP_TrackInfo *trackInfo, Aml_MP_MediaInfo* mediaInfo, Aml_MP_StreamType streamType)
{
if (trackInfo == NULL || mediaInfo == NULL)
return -1;
Aml_MP_TrackInfo *info = trackInfo;
bool isReachFirst = false;
int preTrackIndex = streamType == AML_MP_STREAM_TYPE_VIDEO ? mediaInfo->curVideoIndex :
(streamType == AML_MP_STREAM_TYPE_AUDIO ? mediaInfo->curAudioIndex : mediaInfo->curSubIndex);
int findTrackIndex = preTrackIndex;
if (info->nb_streams > 0) {
do {
if (++findTrackIndex >= info->nb_streams) {
findTrackIndex = 0;
if (isReachFirst) {
//printf("loop again break:%d \n", info->nb_streams);
findTrackIndex = preTrackIndex;
break;
}
isReachFirst = true;
}
if (streamType == info->streamInfo[findTrackIndex].streamType) {
break;
}
} while (1);
}
return findTrackIndex;
}
static void printMediaInfo(Aml_MP_MediaInfo *mediaInfo)
{
if (mediaInfo == NULL)
return;
int index = 0;
Aml_MP_MediaInfo *info = mediaInfo;
printf("[mediaInfo] filename:%s, duration:%" PRId64 ", file_size:%" PRId64 ", bitrate:%" PRId64 ", nb_streams:%d" \
", curVideoIndex:%" PRId64 ", curAudioIndex:%" PRId64 ", curSubIndex:%" PRId64 ", subtitleShowState:%d\n"
,info->filename
,info->duration
,info->file_size
,info->bitrate
,info->nb_streams
,info->curVideoIndex
,info->curAudioIndex
,info->curSubIndex
,info->subtitleShowState);
printf("\n");
}
///////////////////////////////////////////////////////////////////////////////
//serial
static struct termios save_termios;
static int ttysavefd = -1;
static enum { RESET, RAW, CBREAK } ttystate = RESET;
static int tty_cbreak(int fd) /* put terminal into a cbreak mode */
{
int err;
struct termios buf;
if (ttystate != RESET) {
errno = EINVAL;
return(-1);
}
if (tcgetattr(fd, &buf) < 0)
return(-1);
save_termios = buf; /* structure copy */
/*
* Echo off, canonical mode off.
*/
buf.c_lflag &= ~(ECHO | ICANON);
/*
* Case B: 1 byte at a time, no timer.
*/
buf.c_cc[VMIN] = 1;
buf.c_cc[VTIME] = 0;
if (tcsetattr(fd, TCSAFLUSH, &buf) < 0)
return(-1);
/*
* Verify that the changes stuck. tcsetattr can return 0 on
* partial success.
*/
if (tcgetattr(fd, &buf) < 0) {
err = errno;
tcsetattr(fd, TCSAFLUSH, &save_termios);
errno = err;
return(-1);
}
if ((buf.c_lflag & (ECHO | ICANON)) || buf.c_cc[VMIN] != 1 ||
buf.c_cc[VTIME] != 0) {
/*
* Only some of the changes were made. Restore the
* original settings.
*/
tcsetattr(fd, TCSAFLUSH, &save_termios);
errno = EINVAL;
return(-1);
}
ttystate = CBREAK;
ttysavefd = fd;
return(0);
}
static int tty_reset(int fd) /* restore terminal’s mode */
{
if (ttystate == RESET)
return(0);
if (tcsetattr(fd, TCSAFLUSH, &save_termios) < 0)
return(-1);
ttystate = RESET;
return(0);
}
///////////////////////////////////////////////////////////////////////////////
//PIP/MAIN
static int multiPlaybackThread(int id, bool isMain)
{
printf("\nAmlMpMediaPlayerDemo:%d ----------play enter! isMain:%d\n", id, isMain);
int ret = -1;
std::string urlHead;
std::string urlFile;
struct Argument* argument = NULL;
AML_MP_MEDIAPLAYER player = NULL;
playerRoster::instance().getPlayerArgument(id, &argument);
if (argument == NULL || argument->url.empty() || 0 != isUrlValid(argument->url, urlHead, urlFile)) {
showUsage();
return ret;
}
sptr<AmlMpMediaPlayerDemo> commandsProcess = new AmlMpMediaPlayerDemo(id);
if (commandsProcess == NULL) {
return ret;
}
//create
ret = createMultiPlayback(id, &player, argument, commandsProcess.get());
if (ret < 0) {
goto error;
}
if (isMain) {
//commands process
printf("\nAmlMpMediaPlayerDemo:%d ----------fetchAndProcessCommands\n", id);
commandsProcess->setCommandHandle(player);
commandsProcess->fetchAndProcessCommands();
} else {
//sleep
do {
std::this_thread::sleep_for(std::chrono::milliseconds(50));
} while (commandsProcess->mQuitPending == false);
}
error:
//destroy
ret = destroyMultiPlayback(id);
printf("\nAmlMpMediaPlayerDemo:%d ----------play exited!\n", id);
return ret;
}
static int createMultiPlayback(int id, AML_MP_MEDIAPLAYER* player, struct Argument* argument, AmlMpMediaPlayerDemo* commandsProcess)
{
if (argument == NULL) {
return -1;
}
//create
Aml_MP_MediaPlayer_Create(player);
//prre-registration
playerRoster::instance().registerAll(*player, id, argument, commandsProcess);//register player/commandsProcess
//only settings
// channelid is used for pip function which start the demo in a different process.
// it means different play channels,0 : main, else pip
if (argument->channelId != -1)
Aml_MP_MediaPlayer_SetParameter(*player, AML_MP_MEDIAPLAYER_PARAMETER_CHANNEL_ID, (void*)(&argument->channelId));
Aml_MP_MediaPlayerOnlyHintType type = AML_MP_MEDIAPLAYER_ONLYNONE;
if (argument->onlyVideo)
type = AML_MP_MEDIAPLAYER_VIDEO_ONLYHIT;
if (argument->onlyAudio)
type = AML_MP_MEDIAPLAYER_AUDIO_ONLYHIT;
Aml_MP_MediaPlayer_SetParameter(*player, AML_MP_MEDIAPLAYER_PARAMETER_ONLYHINT_TYPE, (void*)&type);
if (argument->loopMode == 2) {
Aml_MP_MediaPlayer_SetLooping(*player, argument->loopMode);
}
if (argument->licenseUrl.size() > 0)
Aml_MP_MediaPlayer_SetParameter(*player, AML_MP_MEDIAPLAYER_PARAMETER_SET_LICENSE_URL, (void*)argument->licenseUrl.c_str());
//player options
//Aml_MP_Option
if (argument->options) {
Aml_MP_MediaPlayer_SetParameter(*player, AML_MP_MEDIAPLAYER_PARAMETER_PLAYER_OPTIONS, (void*)(&argument->options));
}
//setdatasource
Aml_MP_MediaPlayer_SetDataSource(*player, argument->url.c_str());
printf("\nAmlMpMediaPlayerDemo:%d ----------url: %s\n", id, argument->url.c_str());
//registerEventCallBack
Aml_MP_MediaPlayer_RegisterEventCallBack(*player, demoCallback, reinterpret_cast<void*>(commandsProcess));
//set video window after setting datasource and before starting, take effect after starting.
//or use --size options when amlMpMediaPlayerDemo
//passing (0, 0, 0, 0) is necessary to enable full-screen display by default.
Aml_MP_MediaPlayer_SetVideoWindow(*player, argument->x, argument->y, argument->viewWidth, argument->viewHeight);
//prepare
Aml_MP_MediaPlayer_PrepareAsync(*player);
int ret = commandsProcess->waitPreparedEvent();
if (ret < 0) {
return ret;
}
int iD = argument->tunnelId == -1 ? 0 : argument->tunnelId;
Aml_MP_MediaPlayer_SetParameter(*player, AML_MP_MEDIAPLAYER_PARAMETER_VIDEO_TUNNEL_ID, (void*)(&iD));
//start
Aml_MP_MediaPlayer_Start(*player);
printf("\nAmlMpMediaPlayerDemo:%d ----------Aml_MP_MediaPlayer_Start\n", id);
return 0;
}
static int destroyMultiPlayback(int id)
{
int ret = -1;
AML_MP_MEDIAPLAYER player = NULL;
playerRoster::instance().getPlayerHandle(id, &player);
if (player != NULL) {
//stop
ret = Aml_MP_MediaPlayer_Stop(player);
//reset
ret = Aml_MP_MediaPlayer_Reset(player);
playerRoster::instance().unregisterPlayer(player);
//destroy
ret= Aml_MP_MediaPlayer_Destroy(player);
printf("\nAmlMpMediaPlayerDemo:%d ----------Aml_MP_MediaPlayer_Destroy\n", id);
} else {
printf("\nAmlMpMediaPlayerDemo:%d ----------is NULl\n", id);
}
return 0;
}
static void closeMultiPlayback(int id)
{
printf("closeMultiPlayback id:%d\n", id);
if (id < 0) {
return;
}
struct AmlMpMediaPlayerDemo* playerDemo = NULL;
playerRoster::instance().getPlayerDemoHandle(id, &playerDemo);
if (playerDemo != NULL)
playerDemo->mQuitPending = true;
//join pip threads
std::thread *thread = NULL;
playerRoster::instance().getPlayerThreadHandle(id, &thread);
if (thread != NULL && thread->joinable()) {
thread->join();
printf("join multiPlaybackThread id:%d\n", id);
}
}
static void closeAllMultiPlayback()
{
//close pip first
closeMultiPlayback(MEDIAPLAYERDEMO_PIP);
closeMultiPlayback(MEDIAPLAYERDEMO_MAIN);
}
///////////////////////////////////////////////////////////////////////////////
static int isUrlValid(const std::string url, std::string& urlHead, std::string& urlFile)
{
int ret = -1;
std::size_t pos = std::string::npos;
urlHead = "-1";
urlFile = "-1";
if ((pos = url.find(":")) != std::string::npos) {
urlHead = url.substr(0, pos);
}
if (urlHead.compare("dclr") == 0) {
//coverity[overflow_const]
urlFile = url.substr(pos + 1);
//if (1 || access(urlFile.c_str(), F_OK) == 0) {
ret = 0;
//}
} else if (urlHead.compare("hclr") == 0 ||
urlHead.compare("vstb") == 0 ||
urlHead.compare("vwch") == 0 ||
urlHead.compare("nwch") == 0 ||
urlHead.compare("wcas") == 0 ||
urlHead.compare("ncas") == 0 ||
urlHead.compare("icas") == 0 ||
urlHead.compare("wdrm") == 0) {
ret = 0;
}
//printf("isUrlValid, ret:%d, url:%s, urlHead:%s, urlHead:%s\n", ret, url.c_str(), urlHead.c_str(), urlFile.c_str());
return ret;
}
static int startingPlayCheck()
{
int ret = 0;
char errorInfo[50] = {0};
#ifndef ANDROID
#define YOCTO_libAmIptvMedia "/usr/lib/libAmIptvMedia.so"
if (access(YOCTO_libAmIptvMedia, F_OK) != 0) {
ret = -1;
strcpy(errorInfo, YOCTO_libAmIptvMedia);
goto EXIT;
}
#define YOCTO_libaml_mp_mediaplayer "/usr/lib/libaml_mp_mediaplayer.so"
if (access(YOCTO_libaml_mp_mediaplayer, F_OK) != 0) {
ret = -1;
strcpy(errorInfo, YOCTO_libaml_mp_mediaplayer);
goto EXIT;
}
#define YOCTO_libaml_mp_sdk "/usr/lib/libaml_mp_sdk.so"
if (access(YOCTO_libaml_mp_sdk, F_OK) != 0) {
ret = -1;
strcpy(errorInfo, YOCTO_libaml_mp_sdk);
goto EXIT;
}
#define YOCTO_libffmpeg_ctc "/usr/lib/libffmpeg_ctc.so"
if (access(YOCTO_libffmpeg_ctc, F_OK) != 0) {
ret = -1;
strcpy(errorInfo, YOCTO_libffmpeg_ctc);
goto EXIT;
}
#endif
return ret;
//coverity[unreachable]
EXIT:
TERMINAL_ERROR("%s%s", errorInfo, " No Exist!!!");
return ret;
}
///////////////////////////////////////////////////////////////////////////////
//Command Line
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'},
{"channelId", required_argument, nullptr, 'c'},
{"debug", required_argument, nullptr, 'd'},
{"onlyVideo", no_argument, nullptr, 'V'},
{"onlyAudio", no_argument, nullptr, 'A'},
{"id", required_argument, nullptr, 't'},
{"loopMode", required_argument, nullptr, 'L'},
{"noSignalHandler", no_argument, nullptr, 'S'},
{"licenseUrl", required_argument, nullptr, 'l'},
{"options", required_argument, nullptr, 'o'},
{"loopMode", required_argument, nullptr, 'L'},
{"noSignalHandler", no_argument, nullptr, 'S'},
{"noAutoExit", no_argument, nullptr, 'E'},
{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;
printf("size:%dx%d\n", width, 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 'c':
{
int channelId = strtol(optarg, nullptr, 0);
printf("channel id:%d\n", channelId);
argument->channelId = channelId;
}
break;
case 'd':
{
int debuglevel = strtol(optarg, nullptr, 0);
printf("debug level:%d\n", debuglevel);
AMMP_DEBUG_MODE_ENABLE = (bool)debuglevel;
}
break;
case 'V':
{
argument->onlyVideo = true;
printf("onlyVideo\n");
}
break;
case 'A':
{
argument->onlyAudio = true;
printf("onlyAudio\n");
}
break;
case 't':
{
int tunnelId = strtol(optarg, nullptr, 0);
printf("tunnel id:%d\n", tunnelId);
argument->tunnelId = tunnelId;
}
break;
case 'L':
{
int loopMode = strtol(optarg, nullptr, 0);
printf("loop mode:%d\n", loopMode);
argument->loopMode = loopMode;
}
break;
case 'S':
{
printf("no signal handler will be installed!\n");
argument->noSignalHandler = true;
}
break;
case 'l':
{
argument->licenseUrl = std::string(optarg);
printf("licenseUrl:%s\n", argument->licenseUrl.c_str());
}
break;
case 'o':
{
uint64_t options = strtoul(optarg, nullptr, 0);
printf("options :0x%" PRIx64 "\n", options);
argument->options = options;
}
break;
case 'E':
{
printf("noAutoExit is set!\n");
argument->noAutoExit = 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());
}
return 0;
}
static const char* mediaPlayerMediaErrorType2Str(Aml_MP_MediaPlayerMediaErrorType type)
{
switch (type) {
ENUM_TO_STR(AML_MP_MEDIAPLAYER_MEDIA_ERROR_UNKNOWN);
ENUM_TO_STR(AML_MP_MEDIAPLAYER_MEDIA_ERROR_HTTP_BAD_REQUEST);
ENUM_TO_STR(AML_MP_MEDIAPLAYER_MEDIA_ERROR_HTTP_UNAUTHORIZED);
ENUM_TO_STR(AML_MP_MEDIAPLAYER_MEDIA_ERROR_HTTP_FORBIDDEN);
ENUM_TO_STR(AML_MP_MEDIAPLAYER_MEDIA_ERROR_HTTP_NOT_FOUND);
ENUM_TO_STR(AML_MP_MEDIAPLAYER_MEDIA_ERROR_HTTP_OTHER_4XX);
ENUM_TO_STR(AML_MP_MEDIAPLAYER_MEDIA_ERROR_HTTP_SERVER_ERROR);
ENUM_TO_STR(AML_MP_MEDIAPLAYER_MEDIA_ERROR_ENOENT);
ENUM_TO_STR(AML_MP_MEDIAPLAYER_MEDIA_ERROR_ETIMEDOUT);
ENUM_TO_STR(AML_MP_MEDIAPLAYER_MEDIA_ERROR_EIO);
ENUM_TO_STR(AML_MP_MEDIAPLAYER_MEDIA_ERROR_INVALID_KEY);
ENUM_TO_STR(AML_MP_MEDIAPLAYER_MEDIA_ERROR_LICENSE_ERR);
ENUM_TO_STR(AML_MP_MEDIAPLAYER_MEDIA_ERROR_DECRYPT_FAILED);
default:
return "unknowmn media error type";
}
}
void demoCallback(void* userData, Aml_MP_MediaPlayerEventType event, int64_t param)
{
try {
AmlMpMediaPlayerDemo* demo = (AmlMpMediaPlayerDemo*)(userData);
struct Argument* argument = NULL;
switch (event) {
case AML_MP_PLAYER_EVENT_SUBTITLE_DATA:
{
Aml_MP_SubtitleData *subtitleData = (Aml_MP_SubtitleData *)param;
static char cnt = 0;
++cnt;
cnt &= 0x7;
if (subtitleData) {
char bitmapFileName[50];
// Safe snprintf with bounds checking to avoid potential std::length_error
int result = snprintf(bitmapFileName, sizeof(bitmapFileName), "%s-%d", "/data/subtitle", cnt);
if (result < 0 || result >= (int)sizeof(bitmapFileName)) {
printf("Warning: snprintf failed or truncated in subtitle data event\n");
break;
}
char *data = const_cast<char *>(subtitleData->data);
save2BitmapFile(bitmapFileName, (uint32_t *)data, subtitleData->width, subtitleData->height);
}
break;
}
case AML_MP_MEDIAPLAYER_EVENT_PLAYBACK_COMPLETE:
{
if (demo == nullptr) {
break;
}
playerRoster::instance().getPlayerArgument(demo->mId, &argument);
if (argument == NULL || !argument->noAutoExit) {
closeMultiPlayback(demo->mId);
}
printf("%s at #%d AML_MP_MEDIAPLAYER_EVENT_PLAYBACK_COMPLETE, id:%d, noAutoExit:%d\n",__FUNCTION__,__LINE__, demo->mId, argument == NULL ? -1 : argument->noAutoExit);
break;
}
case AML_MP_MEDIAPLAYER_EVENT_PLAYBACK_SOF:
{
if (demo == nullptr) {
break;
}
playerRoster::instance().getPlayerArgument(demo->mId, &argument);
if (argument == NULL || !argument->noAutoExit) {
closeMultiPlayback(demo->mId);
}
printf("%s at #%d AML_MP_MEDIAPLAYER_EVENT_PLAYBACK_SOF, id:%d, noAutoExit:%d\n",__FUNCTION__,__LINE__, demo->mId, argument == NULL ? -1 : argument->noAutoExit);
break;
}
case AML_MP_MEDIAPLAYER_EVENT_PREPARED:
{
if (demo) {
demo->broadcast(true);
printf("id:%d\n", demo->mId);
}
printf("%s at #%d AML_MP_MEDIAPLAYER_EVENT_PREPARED\n",__FUNCTION__,__LINE__);
break;
}
case AML_MP_MEDIAPLAYER_EVENT_MEDIA_ERROR:
{
if (demo) {
demo->broadcast(false);
closeMultiPlayback(demo->mId);
printf("%s at #%d AML_MP_MEDIAPLAYER_EVENT_MEDIA_ERROR, id:%d, type:%s\n",__FUNCTION__,__LINE__, demo->mId, mediaPlayerMediaErrorType2Str(static_cast<Aml_MP_MediaPlayerMediaErrorType>(param)));
}
break;
}
case AML_MP_MEDIAPLAYER_EVENT_STOPPED:
{
printf("%s at #%d AML_MP_MEDIAPLAYER_EVENT_STOPPED\n",__FUNCTION__,__LINE__);
if (demo) {
printf("id:%d\n", demo->mId);
}
break;
}
case AML_MP_MEDIAPLAYER_EVENT_FIRST_FRAME_TOGGLED:
{
printf("%s at #%d AML_MP_MEDIAPLAYER_EVENT_FIRST_FRAME_TOGGLE\n",__FUNCTION__,__LINE__);
if (demo) {
printf("id:%d\n", demo->mId);
}
break;
}
case AML_MP_MEDIAPLAYER_EVENT_VIDEO_UNSUPPORT:
{
TERMINAL_ERROR("%s at #%d AML_MP_MEDIAPLAYER_EVENT_VIDEO_UNSUPPORT\n", __FUNCTION__, __LINE__);
if (demo) {
printf("id:%d, format:%" PRId64 "\n", demo->mId, param);
}
break;
}
case AML_MP_MEDIAPLAYER_EVENT_AUDIO_UNSUPPORT:
{
TERMINAL_ERROR("%s at #%d AML_MP_MEDIAPLAYER_EVENT_AUDIO_UNSUPPORT\n", __FUNCTION__, __LINE__);
if (demo) {
printf("id:%d, format:%" PRId64 "\n", demo->mId, param);
}
break;
}
default:
break;
}
} catch (const std::length_error& e) {
printf("Length error exception in demoCallback: %s", e.what());
} catch (const std::exception& e) {
printf("Standard exception in demoCallback: %s", e.what());
} catch (...) {
printf("Unknown exception caught in demoCallback");
}
}
static void showOption()
{
printf(
"AmlMpMediaPlayerDemo\n"
"Type one option\n"
"\n"
"Main:\n"
" o.................Open URL\n"
" c.................Close URL\n"
" +.................Zap To Following URL\n"
" -.................Zap To Previous URL\n"
" CHANNEL LIST\n"
" ------------\n"
" - igmp://239.0.0.185:8208\n"
" - igmp://239.0.0.183:8208\n"
" - igmp://239.0.0.186:8208\n"
" - igmp://239.0.0.177:8208\n"
" - igmp://239.0.0.176:8208\n"
" - igmp://239.0.0.187:8208\n"
" - igmp://239.0.5.246:8208\n"
" - igmp://239.0.5.111:8208\n"
" - igmp://239.0.5.114:8208\n"
" p.................Pause\n"
" r.................Resume\n"
" K.................Seek\n"
" v.................Get Volume\n"
" V.................Set Volume\n"
" F.................Set fast rate\n"
" M.................Set mute\n"
" <.................Rewind -> -x8 -> -x16 -> -x32 -> -x64\n"
" >.................Forward -> x8 -> x16 -> x32 -> x64 -> x1\n"
" a.................Get Audio Info Channels\n"
" A.................Set Next Audio component\n"
" s.................Get Subtitles Info channels\n"
" S.................Set Next Subtitle component\n"
" U.................Unselect CurAudio component\n"
" u.................Unselect CurSubtitle component\n"
" i.................Get Track/Media info\n"
" n.................Get Position [milliseconds]\n"
" N.................Get Duration [milliseconds]\n"
" w.................Get Main Window Position\n"
" W.................Set Main Window Position\n"
" D.................Show Video\n"
" d.................Hide Video\n"
" T.................Show Subtitle\n"
" t.................Hide Subtitle\n"
"\n"
"PIP:\n"
" O.................Open PIP\n"
" C.................Close PIP\n"
" e.................Get PIP Window Position\n"
" E.................Set PIP Window Position\n"
"\n"
" q................ Exit\n"
"\n"
);
}
static void showUsage()
{
printf("Usage: amlMpMediaPlayerDemo <options> <url>\n"
"options:\n"
" --size: eg: 1920x1080\n"
" --pos: eg: 0x0\n"
" --debug: eg: 1\n"
" --channelId: eg: 0 main, others: pip\n"
" --id: specify the corresponding ui channel id\n"
" --onlyVideo \n"
" --onlyAudio \n"
" --loopMode <value> \n"
" 1: wait play completed, then destroy player and recreate player\n"
" 2: seek to beginning internally when play completed\n"
" --noSignalHandler don't install signal handler\n"
" --licenseUrl eg: --licenseUrl=\"https://widevine-proxy.appspot.com/proxy\" \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"
" --loopMode <value> \n"
" 1: wait play completed, then destroy player and recreate player\n"
" 2: seek to beginning internally when play completed\n"
" --noSignalHandler don't install signal handler\n"
" --noAutoExit don't exit at the end of playback\n"
"\n"
"url format:\n"
" clear ts, eg: dclr:http://10.28.8.30:8881/data/a.ts\n"
" clear local file, eg: dclr:/data/a.ts\n"
"\n"
);
}
int main(int argc, char *argv[])
{
// support run in background
signal(SIGTTIN, SIG_IGN);
signal(SIGTTOU, SIG_IGN);
int ret = -1;
try {
if (startingPlayCheck() < 0) {
return ret;
}
Argument argument{};
try {
if (parseCommandArgs(argc, argv, &argument) < 0) {
showUsage();
return ret;
}
} catch (const std::length_error& e) {
printf("Length error in parseCommandArgs: %s\n", e.what());
showUsage();
return ret;
}
if (tty_reset(STDIN_FILENO) < 0) {
printf("\n tty_reset error\n");
return 0;
}
if (tty_cbreak(STDIN_FILENO) < 0) {
printf("\n tty_cbreak error\n");
}
try {
playerRoster::instance().registerPlayerArgument(MEDIAPLAYERDEMO_MAIN, &argument);//only register argument
} catch (const std::length_error& e) {
printf("Length error in registerPlayerArgument: %s\n", e.what());
return ret;
}
if (!argument.noSignalHandler) {
AmlMpMediaPlayerDemo::installSignalHandler();
}
int loopCount = 0;
begin:
try {
ret = multiPlaybackThread(MEDIAPLAYERDEMO_MAIN, true/*isMain*/);
if (ret < 0) {
printf("\n multiPlaybackThread id:%d error\n", (int)MEDIAPLAYERDEMO_MAIN);
}
} catch (const std::length_error& e) {
printf("Length error in multiPlaybackThread: %s\n", e.what());
return ret;
}
{
try {
++loopCount;
Argument* argument = nullptr;
playerRoster::instance().getPlayerArgument(MEDIAPLAYERDEMO_MAIN, &argument);
if (argument && argument->loopMode == 1) {
printf("loop play count:%d\n", loopCount);
goto begin;
}
} catch (const std::length_error& e) {
printf("Length error in getPlayerArgument: %s\n", e.what());
}
}
if (tty_reset(STDIN_FILENO) < 0)
printf("\n tty_reset error\n");
} catch (const std::length_error& e) {
printf("Length error in main: %s\n", e.what());
} catch (const std::exception& e) {
printf("Standard exception in main: %s\n", e.what());
} catch (...) {
printf("Unknown exception in main\n");
}
return ret;
}