Files

854 lines
26 KiB
C++
Raw Permalink 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:
*/
#include <sys/utsname.h>
#include <string>
#include <vector>
#include <atomic>
#include <map>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <chrono>
#include <sys/time.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <stdbool.h>
#include <ctype.h>
#include <unistd.h>
#include <getopt.h>
#include <thread>
#include <sys/mman.h>
#include <AmVideoDecBase.h>
#include <inttypes.h>
static uint32_t kDefaultQueueCount = 32;
using namespace std::chrono_literals;
#define MAX_INSTANCE_MUN 9
#define InputBufferMaxSize (1024 * 1024)
#define ALIGN(x, align) ((x) + (align -1) & (~(align -1)))
#ifndef UNUSED
#define UNUSED(x) (void)(x)
#endif
typedef enum {
VFORMAT_UNKNOWN = -1,
VFORMAT_MPEG12 = 0,
VFORMAT_MPEG4,
VFORMAT_H264,
VFORMAT_MJPEG,
VFORMAT_REAL,
VFORMAT_JPEG,
VFORMAT_VC1,
VFORMAT_AVS,
VFORMAT_SW,
VFORMAT_H264MVC,
VFORMAT_H264_4K2K,
VFORMAT_HEVC,
VFORMAT_H264_ENC,
VFORMAT_JPEG_ENC,
VFORMAT_VP9,
VFORMAT_AVS2,
VFORMAT_AV1,
VFORMAT_AVS3,
VFORMAT_DVES_AVC,
VFORMAT_DVES_HEVC,
VFORMAT_MPEG2TS,
VFORMAT_UNSUPPORT,
VFORMAT_MAX
} vformat_t;
const uint32_t crc32_tab[] = { /* CRC32 feedback table. */
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
static uint32_t crc32_gen(uint32_t crc, const void *buf, size_t size)
{
const uint8_t *p;
p = (const uint8_t *)buf;
while (size--)
crc = crc32_tab[(crc ^ *p++) & 0xFF] ^ (crc >> 8);
return crc;
}
const char* vformat_to_mime(uint32_t vformat) {
switch (vformat) {
case 2:
return "video/avc";
case 11:
return "video/hevc";
case 14:
return "video/x-vnd.on2.vp9";
case 0:
return "video/mpeg2";
case 1:
return "video/mp4v-es";
case 3:
return "video/x-motion-jpeg";
case 6:
return "video/vc1";
case 7:
return "video/avs";
case 15:
return "video/avs2";
case 17:
return "video/avs3";
default:
return "";
}
}
static int get_kernel_version(void)
{
int version, subversion, patchlevel;
struct utsname utsn;
/* Return 0 on failure, and attempt to probe with empty kversion */
if (uname(&utsn)) {
return 0;
}
if (sscanf(utsn.release, "%d.%d.%d",
&version, &subversion, &patchlevel) != 3) {
return 0;
}
return (version << 16) + (subversion << 8) + patchlevel;
}
static int sysfs_cmd_control(const char *path, const char *cmdstr)
{
int fd = open(path, O_CREAT | O_RDWR | O_TRUNC, 0644);
if (fd >= 0) {
write(fd, cmdstr, strlen(cmdstr));
close(fd);
return 0;
}
return -1;
}
class VideoDecPlayerExample {
public:
VideoDecPlayerExample();
virtual ~VideoDecPlayerExample();
int init(uint32_t vFmt, uint32_t width = 1920, uint32_t height = 1080, uint32_t framerate = 24);
void setQueueCount(int32_t queueCount);
void play(const char* iname, const char* sname,const char* oname, int num);
void outputBuffer(const char* oname, int num);
int inputBuffer(uint8_t* buf, uint32_t size, uint64_t timestamp = 0);
void dumpData(char* buf, uint32_t width, uint32_t height, int32_t bitstreamId);
/* Implement callback */
virtual void onOutputFormatChanged(uint32_t requestedNumOfBuffers,
int32_t width, uint32_t height);
virtual void onOutputBufferDone(int32_t pictureBufferId, int64_t bitstreamId,
uint32_t width, uint32_t height);
virtual void onInputBufferDone(int32_t bitstream_buffer_id);
virtual void onUpdateDecInfo(const uint8_t* info, uint32_t isize);
virtual void onFlushDone();
virtual void onResetDone();
virtual void onError(int32_t error);
virtual void onEvent(uint32_t event, void* param, uint32_t paramsize);
class playerCallback : public AmVideoDecCallback {
public:
playerCallback(VideoDecPlayerExample *thiz) : mThis(thiz) {}
virtual ~playerCallback() = default;
virtual void onOutputFormatChanged(uint32_t requestedNumOfBuffers,
int32_t width, uint32_t height) override {
mThis->onOutputFormatChanged(requestedNumOfBuffers, width, height);
}
virtual void onOutputBufferDone(int32_t pictureBufferId, int64_t bitstreamId,
uint32_t width, uint32_t height) override {
mThis->onOutputBufferDone(pictureBufferId, bitstreamId, width, height);
}
virtual void onInputBufferDone(int32_t bitstream_buffer_id) override {
mThis->onInputBufferDone(bitstream_buffer_id);
}
virtual void onUserdataReady(const uint8_t* userdata, uint32_t usize) override {
UNUSED(userdata);
UNUSED(usize);
}
virtual void onUpdateDecInfo(const uint8_t* info, uint32_t isize) override {
mThis->onUpdateDecInfo(info, isize);
}
virtual void onFlushDone() override {
mThis->onFlushDone();
}
virtual void onResetDone() override {
mThis->onResetDone();
}
virtual void onError(int32_t error) override {
mThis->onError(error);
}
virtual void onEvent(uint32_t event, void* param, uint32_t paramsize) override {
mThis->onEvent(event, param, paramsize);
}
private:
VideoDecPlayerExample * const mThis;
};
playerCallback* mCallback;
AmVideoDecBase* mAmVideoDec;
std::mutex mFlushedLock;
std::condition_variable mFlushedCondition;
bool mready;
bool out_flag;
FILE *miFp;
FILE *msFp;
FILE *moFp;
FILE *mcFp;
struct dispWork {
int64_t bitstreamId;
int64_t timestamp;
int32_t pictureBufferId;
uint32_t width;
uint32_t height;
};
/*Ion output for non-bufferqueue*/
struct mapInfo {
void* map_addr;
size_t size;
};
std::vector<struct mapInfo> mmapBuf;
private:
uint64_t getTimeUs(void);
uint64_t getTimeUsFromStart(void);
/* Map: bitstreamId -> timestamp */
std::map<int32_t, uint64_t> mInputWork;
std::map<int32_t, uint8_t*> mInputBuffer;
/* Map: slot -> picturebufferId */
std::map<int32_t, int32_t> mOutputBufferPictureId;
/* Queue: bistreamId -> struct dispwork */
std::queue<dispWork> mDisplayWork;
/* output buffer mmap addr */
std::vector<void*>mMmapAddr;
std::mutex mInputLock;
std::mutex mOutputLock;
std::mutex mDumpLock;
uint32_t mDqWidth;
uint32_t mDqHeight;
uint32_t mInputDoneCount;
uint32_t mOutputDoneCount;
uint32_t mOutputBufferNum;
uint32_t mDumpNum;
uint64_t mStartTime;
uint32_t mbitstreamId;
uint32_t mBufferWidth;
uint32_t mBufferHeight;
};
uint64_t VideoDecPlayerExample::getTimeUs(void) {
struct timeval time;
gettimeofday(&time, NULL);
return time.tv_sec * 1e6 + time.tv_usec;
}
uint64_t VideoDecPlayerExample::getTimeUsFromStart(void) {
struct timeval time;
gettimeofday(&time, NULL);
return time.tv_sec * 1e6 + time.tv_usec - mStartTime;
}
int VideoDecPlayerExample::init(uint32_t vFmt, uint32_t width, uint32_t height, uint32_t framerate) {
int ret = 0;
init_param_t config = {
/* video */256, width, height, framerate, vFmt, 0,
/* audio */0, 2, 44100, 2,
/*pcrid */ 0,
/* display */1, 0, 0, 0,
2, 0, 0, 0, 0, 0, 0, 1};
mAmVideoDec->setQueueCount(kDefaultQueueCount);
ret = mAmVideoDec->initialize(vformat_to_mime(vFmt), (uint8_t*)&config, sizeof(init_param_t), false, true);
if (ret) {
printf("init failed!, ret=%d\n", ret);
return -2;
}
return 0;
}
int VideoDecPlayerExample::inputBuffer(uint8_t* buf, uint32_t size, uint64_t timestamp) {
if (buf == NULL || size == 0) {
printf("please input valid data\n");
return -1;
}
mInputBuffer[mbitstreamId] = buf;
int retry = 500;
int32_t err = 0;
do {
err = mAmVideoDec->queueInputBuffer(mbitstreamId, mInputBuffer[mbitstreamId], 0, size, timestamp);
if (err == -EAGAIN) {
usleep(10000);
} else {
break;
}
} while(err || retry-- > 0);
std::lock_guard<std::mutex> lock(mInputLock);
mInputWork[mbitstreamId] = timestamp;
mbitstreamId++;
return 0;
}
void VideoDecPlayerExample::dumpData(char* buf, uint32_t width, uint32_t height, int32_t bitstreamId) {
std::lock_guard<std::mutex> lock(mDumpLock);
uint32_t y_size = (mBufferHeight* mBufferWidth);
int i = 0;
if (moFp) {
/* save output yuv data */
for (i = 0 ; i < (int)height; i++) {
fwrite(buf + i * mBufferWidth, width, 1, moFp);
}
for (i = 0 ; i < (int)height / 2; i++) {
fwrite(buf + y_size + i * mBufferWidth, width, 1, moFp);
}
fflush(moFp);
fsync(fileno(moFp));
printf("Dump YUV y_size %d, bitstreamId %d\n",
y_size, bitstreamId);
}
if (mcFp) {
/* save output crc data */
int crc_y = 0,crc_uv = 0;
for (i = 0 ; i < (int)height; i++) {
crc_y = crc32_gen(crc_y, (unsigned char const *)(buf + i * mBufferWidth), width);
}
for (i = 0 ; i < (int)height / 2; i++) {
crc_uv = crc32_gen(crc_uv, (unsigned char const *)(buf + y_size + i * mBufferWidth), width);
}
fprintf(mcFp, "%08d: %08x %08x\n", mDumpNum, crc_y, crc_uv);
fflush(mcFp);
fsync(fileno(mcFp));
printf("%08d: %08x %08x\n", mDumpNum, crc_y, crc_uv);
}
mDumpNum++;
}
void VideoDecPlayerExample::outputBuffer(const char* oname, int num) {
int32_t bitstreamId = 0;
int64_t timestamp = 0;
int32_t pictureBufferId = 0;
uint32_t width = 0;
uint32_t height = 0;
if (mDisplayWork.empty()) {
usleep(5000);
return;
}
std::lock_guard<std::mutex> lock(mOutputLock);
dispWork* work = &mDisplayWork.front();
if (work == NULL) {
return ;
}
bitstreamId = work->bitstreamId;
timestamp = work->timestamp;
pictureBufferId = work->pictureBufferId;
width = work->width;
height = work->height;
if (oname != NULL && moFp == NULL && mcFp == NULL) {
char newOName[128];
char newCName[128];
sprintf(newOName, "%s_%d_%d_%d.yuv", oname, num, width, height);
sprintf(newCName, "%s_%d_%d_%d.crc", oname, num, width, height);
moFp = fopen(newOName, "wb");
if (!moFp) {
printf("Unable to open output YUV file\n");
return;
}
setbuf(moFp,NULL);
mcFp = fopen(newCName, "w");
if (!mcFp) {
printf("Unable to open output crc file\n");
return;
}
setbuf(mcFp,NULL);
}
char* vaddr = (char *)mMmapAddr[pictureBufferId];
dumpData(vaddr, width, height, bitstreamId);
mAmVideoDec->queueOutputBuffer(pictureBufferId);
mDisplayWork.pop();
}
AmVideoDecBase* getAmVideoDec(AmVideoDecCallback* callback) {
void *libHandle = dlopen("libmediahal_videodec.so", RTLD_NOW);
if (libHandle == NULL) {
libHandle = dlopen("libmediahal_videodec.system.so", RTLD_NOW);
if (libHandle == NULL) {
printf("unable to dlopen libmediahal_videodec.so: %s\n", dlerror());
return nullptr;
}
}
typedef AmVideoDecBase *(*createAmVideoDecFunc)(AmVideoDecCallback* callback);
createAmVideoDecFunc getAmVideoDec =
(createAmVideoDecFunc)dlsym(libHandle, "AmVideoDec_create");
if (getAmVideoDec == NULL) {
dlclose(libHandle);
libHandle = NULL;
printf("can not create AmVideoDec\n");
return nullptr;
}
AmVideoDecBase* halHanle = (*getAmVideoDec)(callback);
if (libHandle) {
dlclose(libHandle);
libHandle = NULL;
}
printf("getAmVideoDec ok\n");
return halHanle;
}
VideoDecPlayerExample::VideoDecPlayerExample() {
moFp = nullptr;
miFp = nullptr;
mcFp = nullptr;
msFp = nullptr;
mStartTime = getTimeUs();
mInputDoneCount = 0;
mOutputDoneCount = 0;
mOutputBufferNum = 0;
mDumpNum = 0;
mready = false;
out_flag = false;
mbitstreamId = 0;
mCallback = new playerCallback(this);
mAmVideoDec = getAmVideoDec(mCallback);
}
VideoDecPlayerExample::~VideoDecPlayerExample() {
delete mCallback;
delete mAmVideoDec;
if (miFp) {
fclose(miFp);
}
if (msFp) {
fclose(msFp);
}
if (moFp) {
fclose(moFp);
}
if (mcFp) {
fclose(mcFp);
}
std::map<int32_t, uint8_t*>::iterator iter;
iter = mInputBuffer.begin();
while (iter != mInputBuffer.end()) {
free(iter->second);
iter->second = NULL;
iter++;
}
}
void VideoDecPlayerExample::play(const char* iname, const char* sname, const char* oname, int num) {
int end = 0;
int ret = 0;
if (iname == NULL) {
printf("iname is null\n");
return ;
} else {
miFp = fopen(iname, "rb");
if (!miFp) {
printf("open input file error %s!\n",iname);
return;
}
}
if (sname == NULL) {
printf("sname is null\n");
return ;
} else {
msFp = fopen(sname, "rb");
if (!msFp) {
printf("open frame size file error!\n");
return;
}
}
printf("\n*********VideoDec PLAYER DEMO************\n\n");
printf("file %s to be played\n", iname);
std::atomic_bool running(true);
std::thread outputThread([this, &running, oname, num]() {
while (running) {
outputBuffer(oname, num);
}
});
while (1) {
char frame_size_str[32];
char *s_rt;
uint32_t frame_size;
uint8_t * newbuf;
if (mInputBuffer.size() > 50) {
printf("sleep 20000\n");
usleep(20000);
}
memset(frame_size_str, 0, sizeof(frame_size_str));
s_rt = fgets(frame_size_str, 32, msFp);
if (s_rt == NULL) {
break;
}
frame_size = atoi(frame_size_str);
if (frame_size <= InputBufferMaxSize) {
newbuf = (uint8_t *)malloc(frame_size);
if (newbuf == NULL) {
printf("malloc frame size %d fail\n", frame_size);
}
memset(newbuf, 0, frame_size);
ret = fread(newbuf, 1, frame_size, miFp);
printf("read size %d, %x %x %x %x %x %x %x %x ...\n", frame_size,
newbuf[0], newbuf[1], newbuf[2], newbuf[3], newbuf[4], newbuf[5], newbuf[6], newbuf[7]);
if (ret < (int)frame_size) {
printf("read back size %d, less than frame size %d\n", ret, frame_size);
/*coverity[leaked_storage]will free on release free(iter->second);*/
return ;
}
} else {
printf("Error:input frame size(%d) is error!\n",frame_size);
return;
}
ret = inputBuffer(newbuf, frame_size, 0);
if (ret) {
printf("Error:input buffer is error!\n");
return;
}
if (feof(miFp) || feof(msFp)) {
end = 1;
}
if (end) {
break;
}
}
mAmVideoDec->flush();
std::unique_lock <std::mutex> l(mFlushedLock);
while (!mready) {
mFlushedCondition.wait(l);
}
while ((mDisplayWork.size() > 0)) {
usleep(10000);
}
running.store(false);
outputThread.join();
mAmVideoDec->destroy();
}
void VideoDecPlayerExample::onOutputFormatChanged(uint32_t requestedNumOfBuffers,
int32_t width,
uint32_t height) {
printf("onOutputFormatChanged bufnum %d, width %d, height %d\n",
requestedNumOfBuffers,
width,
height);
int mKernelversion = 5;
mKernelversion = get_kernel_version();
mKernelversion = mKernelversion>>16;
printf("mKernelversion %d\n", mKernelversion);
/* resolution change clean resource */
if (mOutputBufferNum > 0) {
printf("resolution change free all buffer, mOutputBufferNum %d\n", mOutputBufferNum);
if (mKernelversion >= 5) {
mAmVideoDec->freeUvmBuffers();
} else {
mAmVideoDec->freeAllIonBuffer();
}
}
if (mKernelversion >= 5) {
mOutputBufferNum = requestedNumOfBuffers;
mDqWidth = width;
mDqHeight = height;
mBufferWidth = ALIGN(width, 64);
mBufferHeight = ALIGN(height, 64);
uint32_t imagesize = (mBufferHeight * mBufferWidth * 3) / 2;
mAmVideoDec->setupOutputBufferNum(mOutputBufferNum);
for (uint32_t i = 0; i < mOutputBufferNum; i++) {
uint8_t* vaddr;
int fd;
mAmVideoDec->allocUvmBuffer(mBufferWidth, mBufferHeight, (void**)&vaddr, i, &fd);
mMmapAddr.push_back((void*)vaddr);
printf("allocUvmBuffer fd %d, size = %d\n", fd, imagesize);
mAmVideoDec->createOutputBuffer(i, fd);
}
} else {
mOutputBufferNum = requestedNumOfBuffers;
mDqWidth = width;
mDqHeight = height;
uint32_t imagesize = (width * height * 3) / 2;
mAmVideoDec->setupOutputBufferNum(mOutputBufferNum);
for (uint32_t i = 0; i < mOutputBufferNum; i++) {
uint8_t* vaddr;
int fd;
mAmVideoDec->allocIonBuffer(imagesize, (void**)&vaddr, &fd);
mMmapAddr.push_back((void*)vaddr);
printf("allocIonBuffer fd %d, size = %d\n", fd, imagesize);
mAmVideoDec->createOutputBuffer(i, fd);
}
}
printf("onOutputFormatChanged out timeUs %" PRId64 "\n", getTimeUsFromStart());
}
void VideoDecPlayerExample::onOutputBufferDone(int32_t pictureBufferId, int64_t bitstreamId,
uint32_t width, uint32_t height) {
printf("onOutputBufferDone this %p, pictureBufferId %d, bitstreamId %" PRId64 ", mInputWork.size %d, In %d, Out %d\n",
this, pictureBufferId, bitstreamId, (int)mInputWork.size(), mInputDoneCount, mOutputDoneCount);
std::lock_guard<std::mutex> lock(mOutputLock);
int64_t timestamp = mInputWork[bitstreamId];
printf("onOutputBufferDone this %p, timestamp %" PRId64 ", width %d, height %d\n",this, timestamp, width, height);
mDisplayWork.push({bitstreamId, timestamp, pictureBufferId, width, height});
mInputWork.erase(bitstreamId);
mOutputDoneCount++;
}
void VideoDecPlayerExample::onInputBufferDone(int32_t bitstreamId) {
printf("%s bitstream_buffer_id:%d\n", __func__, bitstreamId);
std::lock_guard<std::mutex> lock(mInputLock);
mInputBuffer.erase(bitstreamId);
free(mInputBuffer[bitstreamId]);
mInputDoneCount++;
}
void VideoDecPlayerExample::onUpdateDecInfo(const uint8_t* info, uint32_t isize) {
printf("%s info:%s isize:%d\n", __func__, info, isize);
}
void VideoDecPlayerExample::onFlushDone() {
printf("onFlushDone\n");
std::unique_lock <std::mutex> l(mFlushedLock);
mready = true;
mFlushedCondition.notify_all();
}
void VideoDecPlayerExample::onResetDone() {
printf("onResetDone\n");
}
void VideoDecPlayerExample::onError(int32_t error) {
printf("%s error%d\n", __func__, error);
}
void VideoDecPlayerExample::onEvent(uint32_t event, void* param, uint32_t paramsize) {
UNUSED(param);
UNUSED(paramsize);
printf("%s event:%x, %s %d\n", __func__, event, (char*)param, paramsize);
}
static void usage(void)
{
printf("VideoDecPlayer\n");
printf("Usage: EsVideoDecPlayer -i <file> -f <format> -s <frame size> [-n <number>] [-o <out yuv and crc>] [-h <help>]\n");
printf("\n");
printf(" -i, --ifile input es file\n");
printf(" -f, --format video format\n");
printf ("\t\t0:mpeg12\t1:mpeg4\t\t2:h264\t\t3:mjpeg\n\
5:jpeg\t\t6:vcl\t\t7:avs\t\t11:hevc\n\
14:vp9\t\t15:avs2\t\t16:av1\n");
printf(" -s, --size frame size file\n");
printf(" -n, --number instance number\n");
printf(" -o, --output output yuv and crc\n");
printf(" -h, --help usage\n");
}
int main(int argc, char** argv) {
int optionChar = 0;
int optionIndex = 0;
int32_t vFmt = -1;
char* iname = nullptr;
char* sname = nullptr;
char* oname = nullptr;
int num = 1;
if (argc < 7) {
usage();
return -1;
}
const char *shortOptions = "i:f:s:n:o:h";
struct option longOptions[] = {
{ "ifile", required_argument, nullptr, 'i' },
{ "format", required_argument, nullptr, 'f' },
{ "size", required_argument, nullptr, 's' },
{ "number", required_argument, nullptr, 'n' },
{ "output", required_argument, nullptr, 'o' },
{ "help", no_argument, nullptr, 'h'},
{ nullptr, 0, nullptr, 0 },
};
while ((optionChar = getopt_long(argc, argv, shortOptions,longOptions, &optionIndex)) != -1) {
switch (optionChar) {
case 'i':
iname = optarg;
break;
case 'f':
vFmt = atoi(optarg);
break;
case 's':
sname = optarg;
break;
case 'n':
num = atoi(optarg);
break;
case 'o':
oname = optarg;
break;
case 'h':
usage();
exit(-1);
default:
break;
}
}
if (iname == nullptr || vFmt == -1 || sname == nullptr) {
usage();
exit(-1);
}
if (num > MAX_INSTANCE_MUN) {
printf("input instance num is more than 9\n");
exit(-1);
}
sysfs_cmd_control("/sys/module/amvdec_ports/parameters/bypass_vpp", "1");
std::vector<std::thread> threads;
for (int i = 1 ; i <= num ; i++) {
threads.push_back(std::thread([iname, sname, oname, vFmt, i]() {
printf("start player %d\n", i);
VideoDecPlayerExample player;
player.init(vFmt);
printf("iname %s,sname %s,vFmt = %d\n",iname,sname,vFmt);
player.play(iname,sname,oname,i);
}));
}
for (auto& thread : threads) {
thread.join();
}
printf("VideoDecPlayerExample exit\n");
sysfs_cmd_control("/sys/module/amvdec_ports/parameters/bypass_vpp", "0");
return 0;
}