Merge branch 'CR_6852_wave5_v4l2_Som.Qin' into 'jh7110-devel'

CR 6852 v4l2_dec_test: add v4l2_dec_test for wave511 v4l2 decoder

See merge request sdk/buildroot!122
This commit is contained in:
andy.hu
2023-08-07 06:29:51 +00:00
5 changed files with 900 additions and 0 deletions
+1
View File
@@ -2,3 +2,4 @@ blacklist xrp
blacklist e24
blacklist starfive_mailbox_test
blacklist starfive_mailbox
blacklist wave5
+1
View File
@@ -13,3 +13,4 @@ source "package/starfive/stfisp_setfile/Config.in.host"
source "package/starfive/img-gpu-powervr/Config.in"
source "package/starfive/drm_test/Config.in"
source "package/starfive/pm/Config.in"
source "package/starfive/v4l2_dec_test/Config.in"
+14
View File
@@ -0,0 +1,14 @@
config BR2_PACKAGE_V4L2_DEC_TEST
bool "v4l2 decode test"
depends on BR2_PACKAGE_SF_OMX_IL && BR2_PACKAGE_FFMPEG
depends on BR2_TOOLCHAIN_HAS_THREADS # libv4l
depends on BR2_USE_MMU # libv4l
depends on !BR2_STATIC_LIBS # libv4l
depends on BR2_INSTALL_LIBSTDCPP # libv4l
depends on BR2_TOOLCHAIN_HEADERS_AT_LEAST_3_0 # libv4l
select BR2_PACKAGE_LIBV4L
help
v4l2 decoder package
comment "v4l2 decoder package requires ffmpeg implementation"
depends on !BR2_PACKAGE_FFMPEG
@@ -0,0 +1,861 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright (C) 2021 StarFive Technology Co., Ltd.
*/
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <getopt.h>
#include <fcntl.h>
#include "libavformat/avformat.h"
#include "libavcodec/avcodec.h"
#include <libv4l2.h>
#include <poll.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/ioctl.h>
#include <sys/msg.h>
#include <sys/mman.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <sys/stat.h>
#include <time.h>
#include <asm/types.h>
#include <linux/videodev2.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <malloc.h>
#define MAX_BUF_CNT 10
#define BUFCOUNT 5
#define MAX_PLANES 3
#define MAX_VIDEO_CNT 24
#define VPU_DEC_DRV_NAME "wave5-dec"
#define CLEAR(x) memset (&(x), 0, sizeof (x))
#define PCLEAR(x) memset ((x), 0, sizeof (*x))
//typedef enum __bool { false = 0, true = 1, } bool;
typedef struct v4l2_buffer v4l2_buffer;
typedef enum IOMethod {
IO_METHOD_MMAP,
IO_METHOD_USERPTR,
IO_METHOD_DMABUF,
IO_METHOD_READ
} IOMethod;
typedef struct buffer {
void* start[MAX_PLANES];
size_t length[MAX_PLANES];
int dmabuf_fd[MAX_PLANES];
int index;
}buffer;
typedef struct DecodeTestContext
{
int fd;
IOMethod io_mthd; // IO_METHOD_MMAP
enum v4l2_memory mem_type;
char sOutputFilePath[256];
char sInputFilePath[256];
char sOutputFormat[64];
uint32_t ScaleWidth;
uint32_t ScaleHeight;
uint32_t StreamFormat;
uint32_t format;
uint32_t n_inputbuffers;
uint32_t n_outputbuffers;
uint32_t inputBufSize;
uint32_t outputBufSize;
uint32_t width; // = 1920;
uint32_t height; // = 1080;
v4l2_buffer InputV4L2BufArray[MAX_BUF_CNT];
v4l2_buffer OutputV4L2BufArray[MAX_BUF_CNT];
buffer InputBufArray[MAX_BUF_CNT];
buffer OutputBufArray[MAX_BUF_CNT];
AVFormatContext *avContext;
int32_t video_stream_idx;
} DecodeTestContext;
DecodeTestContext *decodeTestContext;
struct v4l2_plane *gInput_v4l2_plane;
struct v4l2_plane *gOutput_v4l2_plane;
static char devPath[16];
static int32_t FillInputBuffer(DecodeTestContext *decodeTestContext, struct v4l2_buffer *buf, int32_t pIndex);
static bool justQuit = false;
static bool bitsteamEnd = false;
static bool testFPS =false;
static FILE *fb = NULL;
static int xioctl(int fd, int request, void* argp)
{
int r;
// TODO: the orign is v4l2_ioctl()
do r = ioctl(fd, request, argp);
while (-1 == r && EINTR == errno);
return r;
}
static void convert_v4l2_mem_type(int iomthd, enum v4l2_memory *mem_type)
{
if (iomthd < IO_METHOD_MMAP || iomthd > IO_METHOD_READ) {
printf("iomthd %d out of range\n", iomthd);
return;
}
switch (iomthd) {
case IO_METHOD_MMAP:
*mem_type = V4L2_MEMORY_MMAP;
break;
case IO_METHOD_USERPTR:
*mem_type = V4L2_MEMORY_USERPTR;
break;
case IO_METHOD_DMABUF:
*mem_type = V4L2_MEMORY_DMABUF;
break;
case IO_METHOD_READ:
*mem_type = 0; // not use memory machanism
break;
default:
*mem_type = 0; // not use memory machanism
break;
}
}
static void help()
{
printf("v4l2_dec_test - v4l2 hardware decode unit test case\r\n\r\n");
printf("Usage:\r\n\r\n");
printf("./v4l2_dec_test -i <input file> input file\r\n");
printf(" -o <output file> output file\r\n");
printf(" -f <format> i420/nv12/nv21\r\n");
printf(" --scaleW=<width> (optional) scale width down. ceil32(width/8) <= scaledW <= width\r\n");
printf(" --scaleH=<heitht> (optional) scale height down, ceil8(height/8) <= scaledH <= height\r\n\r\n");
printf("./v4l2_dec_test --help: show this message\r\n");
}
static void signal_handle(int sig)
{
printf("[%s,%d]: receive sig=%d \n", __FUNCTION__, __LINE__, sig);
justQuit = true;
}
static int32_t FillInputBuffer(DecodeTestContext *decodeTestContext, struct v4l2_buffer *buf, int32_t pIndex)
{
AVFormatContext *avFormatContext = decodeTestContext->avContext;
AVPacket *avpacket;
int32_t error = 0;
avpacket = av_packet_alloc();
while (error >= 0)
{
error = av_read_frame(avFormatContext, avpacket);
if (avpacket->stream_index == decodeTestContext->video_stream_idx)
break;
printf("get audio frame\n");
}
if (error < 0)
{
if (error == AVERROR_EOF || avFormatContext->pb->eof_reached)
{
printf("get stream eos\n");
buf->m.planes[pIndex].bytesused = 0;
return 0;
}
else
{
printf("%s:%d failed to av_read_frame, error: %s\n",
__FUNCTION__, __LINE__, av_err2str(error));
buf->m.planes[pIndex].bytesused = 0;
return 0;
}
}
if (decodeTestContext->InputBufArray[buf->index].length[pIndex] >= avpacket->size){
memcpy(decodeTestContext->InputBufArray[buf->index].start[pIndex], avpacket->data, avpacket->size);
buf->m.planes[pIndex].bytesused = avpacket->size;
return avpacket->size;
}else{
printf("buff size too small %ld<%d\n",decodeTestContext->InputBufArray[buf->index].length[pIndex], avpacket->size);
buf->m.planes[pIndex].bytesused = 0;
return 0;
}
}
static void mainloop()
{
int r, i, j, fps, dec_cnt = 0;
uint64_t diff_time;
struct pollfd* fds = NULL;
struct v4l2_event event;
struct v4l2_format fmt;
struct v4l2_requestbuffers req;
struct v4l2_buffer buf;
struct v4l2_plane planes[MAX_PLANES];
struct timeval tv_old, tv;
enum v4l2_buf_type type;
fds = (struct pollfd*)malloc(sizeof(struct pollfd));
PCLEAR(fds);
fds->fd = decodeTestContext->fd;
fds->events = POLLIN | POLLOUT | POLLPRI;
while (true){
if (justQuit)
break;
r = poll(fds, 1, 3000);
if (-1 == r) {
if (EINTR == errno) {
continue;
}
printf("error in poll %d", errno);
break;
}
if (0 == r) {
printf("poll timeout, %d\n", errno);
break;
}
if (fds->revents & POLLPRI) {
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_DQEVENT, &event)) {
printf("get event fail\n");
break;
}
printf("get event %d\n",event.type);
if (event.type == V4L2_EVENT_SOURCE_CHANGE &&
event.u.src_change.changes == V4L2_EVENT_SRC_CH_RESOLUTION){
printf("request dist buffer\n");
CLEAR(req);
req.count = BUFCOUNT;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
req.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_REQBUFS, &req)) {
printf("%s request buffer fail %d\n", devPath, errno);
break;
}
decodeTestContext->n_outputbuffers = req.count;
printf("get dist q format\n");
CLEAR(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fmt.fmt.pix_mp.field = V4L2_FIELD_NONE;
if (-1 == ioctl(decodeTestContext->fd, VIDIOC_G_FMT, &fmt)) {
printf("VIDIOC_G_FMT fail\n");
break;
}
printf("VIDIOC_G_FMT: type=%d, Fourcc format=%c%c%c%c\n",
fmt.type, fmt.fmt.pix_mp.pixelformat & 0xff,
(fmt.fmt.pix_mp.pixelformat >> 8) &0xff,
(fmt.fmt.pix_mp.pixelformat >> 16) &0xff,
(fmt.fmt.pix_mp.pixelformat >> 24) &0xff);
printf(" \t width=%d, height=%d, field=%d, bytesperline=%d, sizeimage=%d\n",
fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height, fmt.fmt.pix_mp.field,
fmt.fmt.pix_mp.plane_fmt[0].bytesperline, fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
if (fmt.fmt.pix_mp.pixelformat != decodeTestContext->format) {
printf("v4l2 didn't accept format %d. Can't proceed.\n", decodeTestContext->format);
break;
}
/* Note VIDIOC_S_FMT may change width and height. */
if (decodeTestContext->width != fmt.fmt.pix_mp.width) {
decodeTestContext->width = fmt.fmt.pix_mp.width;
printf("Correct image width set to %i by device %s.\n", decodeTestContext->width, devPath);
}
if (decodeTestContext->height != fmt.fmt.pix_mp.height) {
decodeTestContext->height = fmt.fmt.pix_mp.height;
printf("Correct image height set to %i by device %s.\n", decodeTestContext->height, devPath);
}
for (i = 0; i < decodeTestContext->n_outputbuffers; i++) {
decodeTestContext->OutputV4L2BufArray[i].type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
decodeTestContext->OutputV4L2BufArray[i].memory = V4L2_MEMORY_MMAP;
decodeTestContext->OutputV4L2BufArray[i].index = i;
// VIDIOC_PREPARE_BUF
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_PREPARE_BUF, &decodeTestContext->OutputV4L2BufArray[i]))
{
printf("VIDIOC_PREPARE_BUF fail\n");
break;
}
// VIDIOC_PREPARE_BUF end
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_QUERYBUF, &decodeTestContext->OutputV4L2BufArray[i]))
{
printf("VIDIOC_QUERYBUF fail\n");
break;
}
printf("src buffer %d type %d method %d n_plane %d\n",i ,decodeTestContext->OutputV4L2BufArray[i].type,
decodeTestContext->OutputV4L2BufArray[i].memory, decodeTestContext->OutputV4L2BufArray[i].length);
for (j = 0; j < decodeTestContext->OutputV4L2BufArray[i].length; j++){
printf(" plane %d length 0x%x offset 0x%x\n", j,
decodeTestContext->OutputV4L2BufArray[i].m.planes[j].length, decodeTestContext->OutputV4L2BufArray[i].m.planes[j].m.mem_offset);
decodeTestContext->OutputBufArray[i].length[j] = decodeTestContext->OutputV4L2BufArray[i].m.planes[j].length;
decodeTestContext->OutputBufArray[i].start[j] = v4l2_mmap(NULL, /* start anywhere */
decodeTestContext->OutputV4L2BufArray[i].m.planes[j].length, PROT_READ | PROT_WRITE, /* required */
MAP_SHARED, /* recommended */
decodeTestContext->fd, decodeTestContext->OutputV4L2BufArray[i].m.planes[j].m.mem_offset);
if (MAP_FAILED == decodeTestContext->OutputBufArray[i].start[j]) {
printf("map fail %d err %d\n",i, errno);
break;
}
}
}
for (i = 0; i < decodeTestContext->n_outputbuffers; i++){
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_QBUF, &decodeTestContext->OutputV4L2BufArray[i])) {
printf("VIDIOC_QBUF fail\n");
break;
}
}
printf("start dst stream\n");
type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_STREAMON, &type)) {
printf("start dst stream fail\n");
break;
}
}else if (event.type == V4L2_EVENT_EOS){
printf("finished, end\n");
break;
}
}
if (fds->revents & POLLIN) {
CLEAR(buf);
memset(planes, 0, sizeof(struct v4l2_plane) * MAX_PLANES);
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
buf.memory = decodeTestContext->mem_type;
buf.length = MAX_PLANES;
buf.m.planes = planes;
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_DQBUF, &buf)) {
switch (errno) {
case EAGAIN:
continue;
case EIO:
/* Could ignore EIO, see spec. */
/* fall through */
default:
printf("pollin VIDIOC_DQBUF fail\n");
}
}
if (buf.index > decodeTestContext->n_outputbuffers)
{
printf("error capture index %d\n",buf.index);
break;
}
if (testFPS)
{
if (dec_cnt == 0) {
gettimeofday(&tv_old, NULL);
}
if (dec_cnt++ >= 50) {
gettimeofday(&tv, NULL);
diff_time = (tv.tv_sec - tv_old.tv_sec) * 1000 + (tv.tv_usec - tv_old.tv_usec) / 1000;
fps = 1000 * (dec_cnt - 1) / diff_time;
dec_cnt = 0;
printf("Decoding fps: %d \r\n", fps);
}
}
else
{
for (i = 0; i < buf.length; i++){
fwrite(decodeTestContext->OutputBufArray[buf.index].start[i], 1, buf.m.planes[i].bytesused, fb);
}
}
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_QBUF, &buf)) {
printf("VIDIOC_QBUF fail\n");
break;
}
if (buf.flags & V4L2_BUF_FLAG_LAST){
printf("get last buffer\n");
justQuit = true;
}
}
if (fds->revents & POLLOUT) {
CLEAR(buf);
memset(planes, 0, sizeof(struct v4l2_plane) * MAX_PLANES);
buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
buf.memory = decodeTestContext->mem_type;
buf.length = MAX_PLANES;
buf.m.planes = planes;
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_DQBUF, &buf)) {
switch (errno) {
case EAGAIN:
continue;
case EIO:
/* Could ignore EIO, see spec. */
/* fall through */
default:
printf("pollout VIDIOC_DQBUF fail %d\n", errno);
}
}
if (buf.index > decodeTestContext->n_inputbuffers)
{
printf("error out index %d\n",buf.index);
break;
}
//if (bitsteamEnd)
// continue;
if(!FillInputBuffer(decodeTestContext, &buf, 0)){
bitsteamEnd = true;
}
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_QBUF, &buf)) {
printf("VIDIOC_QBUF fail\n");
break;
}
}
}
if (fds) {
free(fds);
fds = NULL;
}
}
int main(int argc, char **argv)
{
printf("=============================\r\n");
int32_t error,i,j;
struct stat st;
struct v4l2_capability cap;
struct v4l2_format fmt;
struct v4l2_requestbuffers req;
struct v4l2_event_subscription argp;
enum v4l2_buf_type type;
decodeTestContext = malloc(sizeof(DecodeTestContext));
gInput_v4l2_plane = malloc(sizeof(struct v4l2_plane) * MAX_BUF_CNT * MAX_PLANES);
gOutput_v4l2_plane = malloc(sizeof(struct v4l2_plane) * MAX_BUF_CNT * MAX_PLANES);
if (!decodeTestContext || !gInput_v4l2_plane || !gInput_v4l2_plane){
return -1;
}
PCLEAR(decodeTestContext);
PCLEAR(gInput_v4l2_plane);
PCLEAR(gOutput_v4l2_plane);
for (i = 0; i < MAX_BUF_CNT; i++){
decodeTestContext->InputV4L2BufArray[i].m.planes = gInput_v4l2_plane + i * MAX_PLANES;
decodeTestContext->OutputV4L2BufArray[i].m.planes = gOutput_v4l2_plane + i * MAX_PLANES;
decodeTestContext->InputV4L2BufArray[i].length = MAX_PLANES;
decodeTestContext->OutputV4L2BufArray[i].length = MAX_PLANES;
}
struct option longOpt[] = {
{"output", required_argument, NULL, 'o'},
{"input", required_argument, NULL, 'i'},
{"format", required_argument, NULL, 'f'},
{"scaleW", required_argument, NULL, 'w'},
{"scaleH", required_argument, NULL, 'h'},
{"test", required_argument, NULL, 't'},
{"help", no_argument, NULL, '0'},
{NULL, no_argument, NULL, 0},
};
char *shortOpt = "i:o:f:w:h:t";
uint32_t c;
int32_t l;
if (argc == 0)
{
help();
return -1;
}
while ((c = getopt_long(argc, argv, shortOpt, longOpt, (int *)&l)) != -1)
{
switch (c)
{
case 'i':
printf("input: %s\r\n", optarg);
if (access(optarg, R_OK) != -1)
{
memcpy(decodeTestContext->sInputFilePath, optarg, strlen(optarg));
}
else
{
printf("input file not exist!\r\n");
return -1;
}
break;
case 'o':
printf("output: %s\r\n", optarg);
memcpy(decodeTestContext->sOutputFilePath, optarg, strlen(optarg));
break;
case 'f':
printf("format: %s\r\n", optarg);
memcpy(decodeTestContext->sOutputFormat, optarg, strlen(optarg));
break;
case 'w':
printf("ScaleWidth: %s\r\n", optarg);
decodeTestContext->ScaleWidth = atoi(optarg);
break;
case 'h':
printf("ScaleHeight: %s\r\n", optarg);
decodeTestContext->ScaleHeight = atoi(optarg);
break;
case 't':
testFPS = true;
break;
case '0':
default:
help();
return -1;
}
}
if (decodeTestContext->sInputFilePath == NULL || decodeTestContext->sOutputFilePath == NULL)
{
help();
return -1;
}
decodeTestContext->io_mthd = IO_METHOD_MMAP; //for now
if (strstr(decodeTestContext->sOutputFormat, "nv12") != NULL)
{
decodeTestContext->format = V4L2_PIX_FMT_NV12M;
}
else if (strstr(decodeTestContext->sOutputFormat, "nv21") != NULL)
{
decodeTestContext->format = V4L2_PIX_FMT_NV21M;
}
else if (strstr(decodeTestContext->sOutputFormat, "i420") != NULL)
{
decodeTestContext->format = V4L2_PIX_FMT_YUV420M;
}
else
{
printf("Unsupported color format!\r\n");
return -1;
}
/*ffmpeg init*/
printf("init ffmpeg\r\n");
AVFormatContext *avContext = NULL;
AVCodecParameters *codecParameters = NULL;
AVInputFormat *avfmt = NULL;
int32_t videoIndex;
if ((avContext = avformat_alloc_context()) == NULL)
{
printf("avformat_alloc_context fail\r\n");
return -1;
}
avContext->flags |= AV_CODEC_FLAG_TRUNCATED;
printf("avformat_open_input\r\n");
if ((error = avformat_open_input(&avContext, decodeTestContext->sInputFilePath, avfmt, NULL)))
{
printf("%s:%d failed to av_open_input_file error(%s), %s\n",
__FILE__, __LINE__, av_err2str(error), decodeTestContext->sInputFilePath);
avformat_free_context(avContext);
return -1;
}
printf("avformat_find_stream_info\r\n");
if ((error = avformat_find_stream_info(avContext, NULL)) < 0)
{
printf("%s:%d failed to avformat_find_stream_info. error(%s)\n",
__FUNCTION__, __LINE__, av_err2str(error));
avformat_close_input(&avContext);
avformat_free_context(avContext);
return -1;
}
printf("av_find_best_stream\r\n");
videoIndex = av_find_best_stream(avContext, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
if (videoIndex < 0)
{
printf("%s:%d failed to av_find_best_stream.\n", __FUNCTION__, __LINE__);
return -1;
}
printf("video index = %d\r\n", videoIndex);
decodeTestContext->video_stream_idx = videoIndex;
decodeTestContext->avContext = avContext;
/*get video info*/
codecParameters = avContext->streams[videoIndex]->codecpar;
printf("codec_id = %d, width = %d, height = %d\r\n", (int)codecParameters->codec_id,
codecParameters->width, codecParameters->height);
decodeTestContext->width = codecParameters->width;
decodeTestContext->height = codecParameters->height;
if (codecParameters->codec_id == AV_CODEC_ID_H264)
{
decodeTestContext->StreamFormat = V4L2_PIX_FMT_H264;
}
else if (codecParameters->codec_id == AV_CODEC_ID_HEVC)
{
decodeTestContext->StreamFormat = V4L2_PIX_FMT_HEVC;
}
else
{
printf("not support stream %d \n",(int)codecParameters->codec_id);
goto end;
}
if (decodeTestContext->ScaleWidth)
{
int scalew = codecParameters->width / decodeTestContext->ScaleWidth;
if (scalew > 8 || scalew < 1)
{
printf("orign width %d scale width %d.\n",codecParameters->width, decodeTestContext->ScaleWidth);
printf("Scaling should be 1 to 1/8 (down-scaling only)! Use input parameter, end.\n");
goto end;
}
}
if (decodeTestContext->ScaleHeight)
{
int scaleh= codecParameters->height / decodeTestContext->ScaleHeight;
if (scaleh > 8 || scaleh < 1)
{
printf("orign height %d scale height %d.\n",codecParameters->height, decodeTestContext->ScaleHeight);
printf("Scaling should be 1 to 1/8 (down-scaling only)! Use input parameter, end.\n");
goto end;
}
}
signal(SIGINT, signal_handle);
/* find video device */
for (i = 0; i < MAX_VIDEO_CNT; i++){
sprintf(devPath, "/dev/video%d", i);
if (-1 == stat(devPath, &st)) {
continue;
}
decodeTestContext->fd = v4l2_open(devPath, O_RDWR /* required */ | O_NONBLOCK, 0);
if (-1 == decodeTestContext->fd) {
printf("Cannot open '%s': %d, %s\n", devPath, errno, strerror(errno));
continue;
}
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_QUERYCAP, &cap)) {
if (EINVAL == errno) {
printf("%s is no V4L2 device\n", devPath);
v4l2_close(decodeTestContext->fd);
continue;
} else {
printf("%s can not VIDIOC_QUERYCAP fail\n", devPath);
v4l2_close(decodeTestContext->fd);
continue;
}
}
if (strncmp((const char *)cap.driver, VPU_DEC_DRV_NAME, 9)) {
v4l2_close(decodeTestContext->fd);
continue;
}
printf("find %s %s\n", VPU_DEC_DRV_NAME, devPath);
break;
}
if (i == MAX_VIDEO_CNT){
printf("can not find decoder, end\n");
goto end;
}
fb = fopen(decodeTestContext->sOutputFilePath, "wb+");
if (!fb)
{
fprintf(stderr, "output file open err or no output file patch %d\n", errno);
goto end;
}
printf("init V4L2 device\n");
switch (decodeTestContext->io_mthd) {
case IO_METHOD_MMAP:
case IO_METHOD_USERPTR:
case IO_METHOD_DMABUF:
if (!(cap.capabilities & V4L2_CAP_STREAMING)) {
printf("%s does not support streaming i/o\n", devPath);
goto end;
}
break;
default:
printf("%s does not specify streaming i/o\n", devPath);
goto end;
break;
}
argp.type = V4L2_EVENT_SOURCE_CHANGE;
argp.id = 0;
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_SUBSCRIBE_EVENT, &argp)) {
printf("VIDIOC_SUBSCRIBE_EVENT fail\n");
goto end;
}
argp.type = V4L2_EVENT_EOS;
argp.id = 0;
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_SUBSCRIBE_EVENT, &argp)) {
printf("VIDIOC_SUBSCRIBE_EVENT fail\n");
goto end;
}
printf("set src q format\n");
fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
fmt.fmt.pix_mp.width = codecParameters->width;
fmt.fmt.pix_mp.height = codecParameters->height;
fmt.fmt.pix_mp.field = V4L2_FIELD_NONE;
fmt.fmt.pix_mp.pixelformat = decodeTestContext->StreamFormat;
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_S_FMT, &fmt)) {
printf("VIDIOC_S_FMT fail\n");
goto end;
}
CLEAR(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fmt.fmt.pix_mp.width = decodeTestContext->ScaleWidth? decodeTestContext->ScaleWidth: codecParameters->width;
fmt.fmt.pix_mp.height = decodeTestContext->ScaleHeight? decodeTestContext->ScaleHeight: codecParameters->height;
fmt.fmt.pix_mp.field = V4L2_FIELD_NONE;
fmt.fmt.pix_mp.pixelformat = decodeTestContext->format;
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_S_FMT, &fmt)) {
printf("VIDIOC_S_FMT fail\n");
goto end;
}
convert_v4l2_mem_type(decodeTestContext->io_mthd, &decodeTestContext->mem_type);
printf("get dist q format\n");
CLEAR(fmt);
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
fmt.fmt.pix_mp.field = V4L2_FIELD_NONE;
if (-1 == ioctl(decodeTestContext->fd, VIDIOC_G_FMT, &fmt)) {
printf("VIDIOC_G_FMT fail\n");
goto end;
}
printf("VIDIOC_G_FMT: type=%d, Fourcc format=%c%c%c%c\n",
fmt.type, fmt.fmt.pix_mp.pixelformat & 0xff,
(fmt.fmt.pix_mp.pixelformat >> 8) &0xff,
(fmt.fmt.pix_mp.pixelformat >> 16) &0xff,
(fmt.fmt.pix_mp.pixelformat >> 24) &0xff);
printf(" \t width=%d, height=%d, field=%d, bytesperline=%d, sizeimage=%d\n",
fmt.fmt.pix_mp.width, fmt.fmt.pix_mp.height, fmt.fmt.pix_mp.field,
fmt.fmt.pix_mp.plane_fmt[0].bytesperline, fmt.fmt.pix_mp.plane_fmt[0].sizeimage);
if (fmt.fmt.pix_mp.pixelformat != decodeTestContext->format) {
printf("v4l2 didn't accept format %d. Can't proceed.\n", decodeTestContext->format);
goto end;
}
/* Note VIDIOC_S_FMT may change width and height. */
if (decodeTestContext->width != fmt.fmt.pix_mp.width) {
decodeTestContext->width = fmt.fmt.pix_mp.width;
printf("Correct image width set to %i by device %s.\n", decodeTestContext->width, devPath);
}
if (decodeTestContext->height != fmt.fmt.pix_mp.height) {
decodeTestContext->height = fmt.fmt.pix_mp.height;
printf("Correct image height set to %i by device %s.\n", decodeTestContext->height,devPath);
}
/* prepare and start v4l2 stream */
printf("request src buffer\n");
CLEAR(req);
req.count = BUFCOUNT;
req.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
req.memory = V4L2_MEMORY_MMAP;
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_REQBUFS, &req)) {
printf("%s request buffer fail %d\n", devPath, errno);
goto end;
}
decodeTestContext->n_inputbuffers = req.count;
for (i = 0; i < decodeTestContext->n_inputbuffers; i++) {
if (bitsteamEnd)
break;
decodeTestContext->InputV4L2BufArray[i].type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
decodeTestContext->InputV4L2BufArray[i].memory = V4L2_MEMORY_MMAP;
decodeTestContext->InputV4L2BufArray[i].index = i;
// test prepare
//if (-1 == xioctl(decodeTestContext->fd, VIDIOC_PREPARE_BUF, &decodeTestContext->InputV4L2BufArray[i]))
//{
// printf("VIDIOC_PREPARE_BUF fail %d\n",errno);
// goto end;
//}
// test prepare end
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_QUERYBUF, &decodeTestContext->InputV4L2BufArray[i]))
{
printf("VIDIOC_QUERYBUF fail %d\n",errno);
goto end;
}
printf("src buffer %d type %d method %d n_plane %d\n",i ,decodeTestContext->InputV4L2BufArray[i].type,
decodeTestContext->InputV4L2BufArray[i].memory, decodeTestContext->InputV4L2BufArray[i].length);
for (j = 0; j < decodeTestContext->InputV4L2BufArray[i].length; j++){
printf(" plane %d length 0x%x offset 0x%x\n", j,
decodeTestContext->InputV4L2BufArray[i].m.planes[j].length, decodeTestContext->InputV4L2BufArray[i].m.planes[j].m.mem_offset);
decodeTestContext->InputBufArray[i].length[j] = decodeTestContext->InputV4L2BufArray[i].m.planes[j].length;
decodeTestContext->InputBufArray[i].start[j] = v4l2_mmap(NULL, /* start anywhere */
decodeTestContext->InputV4L2BufArray[i].m.planes[j].length, PROT_READ | PROT_WRITE, /* required */
MAP_SHARED, /* recommended */
decodeTestContext->fd, decodeTestContext->InputV4L2BufArray[i].m.planes[j].m.mem_offset);
if (MAP_FAILED == decodeTestContext->InputBufArray[i].start[j]) {
printf("map fail %d\n",i);
goto end;
}
}
if(!FillInputBuffer(decodeTestContext, &decodeTestContext->InputV4L2BufArray[i], 0)){
bitsteamEnd = true;
}
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_QBUF, &decodeTestContext->InputV4L2BufArray[i])) {
printf("VIDIOC_QBUF fail\n");
goto end;
}
}
printf("start src stream\n");
type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_STREAMON, &type)) {
printf("start src stream fail\n");
goto end;
}
mainloop();
printf("stop src stream\n");
type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_STREAMOFF, &type)) {
printf("stop src stream fail\n");
goto end;
}
printf("stop dist stream\n");
type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
if (-1 == xioctl(decodeTestContext->fd, VIDIOC_STREAMOFF, &type)) {
printf("stop dist stream fail\n");
goto end;
}
v4l2_close(decodeTestContext->fd);
end:
/*free resource*/
if (fb)
fclose(fb);
avformat_close_input(&avContext);
avformat_free_context(avContext);
}
@@ -0,0 +1,23 @@
################################################################################
#
# v4l2_dec_test
#
################################################################################
V4L2_DEC_TEST_LICENSE = GPL-2.0+
define V4L2_DEC_TEST_BUILD_CMDS
cp package/starfive/v4l2_dec_test/v4l2_dec_test.c $(@D)/
(cd $(@D); $(TARGET_CC) -Wall v4l2_dec_test.c -lv4l2 \
-ldl -lpthread -Wl,--fatal-warning \
-lavformat -lavcodec -lavutil -lswresample \
-o v4l2_dec_test)
endef
define V4L2_DEC_TEST_INSTALL_TARGET_CMDS
$(INSTALL) -m 0777 $(@D)/v4l2_dec_test $(TARGET_DIR)/root/v4l2_dec_test
endef
V4L2_DEC_TEST_DEPENDENCIES = ffmpeg libv4l
$(eval $(generic-package))