package: Move v4l2test to starfive package
1.Create starfive package, and move v4l2test into it. 2.Sync the latest v4l2test package from JH7100. Signed-off-by: mason.huo <mason.huo@starfivetech.com> (cherry-pick commit 87583e4004ba7ceefa317d939ea8004f38eb9570 from jh7110-mm-devel branch)
This commit is contained in:
committed by
changhuang.liang
parent
313e975390
commit
cf9c62a4f1
@@ -0,0 +1,919 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* Copyright (C) 2021 StarFive Technology Co., Ltd.
|
||||
*/
|
||||
|
||||
#include <getopt.h>
|
||||
#include <signal.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <libv4l2.h>
|
||||
#include <poll.h>
|
||||
#include "common.h"
|
||||
#include "yuv.h"
|
||||
#include "convert.h"
|
||||
#include "stf_v4l2.h"
|
||||
#include "stf_framebuffer.h"
|
||||
#include "stf_drm.h"
|
||||
#include "stf_log.h"
|
||||
|
||||
#define FB_DEVICE_NAME "/dev/fb0"
|
||||
#define STFBC_DEVICE_NAME "/dev/stfbcdev"
|
||||
#define DRM_DEVICE_NAME "/dev/dri/card0"
|
||||
#define V4L2_DFT_DEVICE_NAME "/dev/video0"
|
||||
|
||||
typedef struct enum_value_t {
|
||||
int value;
|
||||
const char *name;
|
||||
} enum_value_t;
|
||||
|
||||
static const enum_value_t g_disp_values[] = {
|
||||
{ STF_DISP_NONE, "NONE"},
|
||||
{ STF_DISP_FB, "FB"},
|
||||
{ STF_DISP_DRM, "DRM"}
|
||||
};
|
||||
|
||||
static const enum_value_t g_iomthd_values[] = {
|
||||
{ IO_METHOD_MMAP, "MMAP"},
|
||||
{ IO_METHOD_USERPTR, "USERPTR"},
|
||||
{ IO_METHOD_DMABUF, "DMABUF"},
|
||||
{ IO_METHOD_READ, "READ"}
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
V4l2Param_t v4l2_param;
|
||||
FBParam_t fb_param;
|
||||
DRMParam_t drm_param;
|
||||
|
||||
enum STF_DISP_TYPE disp_type;
|
||||
enum IOMethod io_mthd;
|
||||
int continuous;
|
||||
|
||||
uint8_t jpegQuality;
|
||||
char* jpegFilename;
|
||||
FILE *rec_fp;
|
||||
|
||||
int dmabufs[BUFCOUNT]; // for dmabuf use, mmap not use it
|
||||
} ConfigParam_t;
|
||||
ConfigParam_t *gp_cfg_param = NULL;
|
||||
|
||||
static int g_drm_buf_next_idx = -1;
|
||||
static int g_drm_buf_curr_idx = 0;
|
||||
|
||||
static void alloc_default_config(ConfigParam_t **pp_data)
|
||||
{
|
||||
ConfigParam_t *cfg_param = NULL;
|
||||
cfg_param = malloc(sizeof(*cfg_param));
|
||||
if (!cfg_param) {
|
||||
errno_exit("malloc");
|
||||
}
|
||||
memset(cfg_param, 0, sizeof(*cfg_param));
|
||||
|
||||
cfg_param->disp_type = STF_DISP_NONE;
|
||||
cfg_param->continuous = 0;
|
||||
cfg_param->jpegQuality = 70;
|
||||
cfg_param->io_mthd = IO_METHOD_MMAP;
|
||||
|
||||
cfg_param->v4l2_param.device_name = V4L2_DFT_DEVICE_NAME;
|
||||
cfg_param->v4l2_param.fd = -1;
|
||||
cfg_param->v4l2_param.io_mthd = cfg_param->io_mthd;
|
||||
cfg_param->v4l2_param.width = 1920;
|
||||
cfg_param->v4l2_param.height = 1080;
|
||||
cfg_param->v4l2_param.image_size = cfg_param->v4l2_param.width *
|
||||
cfg_param->v4l2_param.height * 3 / 2;
|
||||
cfg_param->v4l2_param.format = V4L2_PIX_FMT_NV12; // V4L2_PIX_FMT_RGB565
|
||||
cfg_param->v4l2_param.fps = 30;
|
||||
|
||||
// the fb param will be updated after fb init
|
||||
cfg_param->fb_param.fd = -1;
|
||||
cfg_param->fb_param.pixformat = COLOR_YUV420_NV21; // COLOR_RGB565
|
||||
cfg_param->fb_param.width = 1920;
|
||||
cfg_param->fb_param.height = 1080;
|
||||
cfg_param->fb_param.bpp = 16;
|
||||
cfg_param->fb_param.screen_size = cfg_param->fb_param.width *
|
||||
cfg_param->fb_param.height * cfg_param->fb_param.bpp / 8;
|
||||
|
||||
*pp_data = cfg_param;
|
||||
}
|
||||
|
||||
static void check_cfg_params(ConfigParam_t *cfg_param)
|
||||
{
|
||||
LOG(STF_LEVEL_TRACE, "Enter\n");
|
||||
int disp_type = cfg_param->disp_type;
|
||||
int io_mthd = cfg_param->io_mthd;
|
||||
int ret = EXIT_FAILURE;
|
||||
|
||||
assert(disp_type >= STF_DISP_NONE && disp_type <= STF_DISP_DRM);
|
||||
assert(io_mthd >= IO_METHOD_MMAP && io_mthd <= IO_METHOD_READ);
|
||||
|
||||
// when mmap, support display NONE, DRM, FB
|
||||
if (IO_METHOD_MMAP == io_mthd) {
|
||||
ret = EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
// when dmabuf, only support DRM, and not save file
|
||||
if (IO_METHOD_DMABUF == io_mthd
|
||||
&& STF_DISP_DRM == disp_type
|
||||
&& !cfg_param->jpegFilename) {
|
||||
ret = EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
if (EXIT_FAILURE == ret) {
|
||||
LOG(STF_LEVEL_ERR, "Not support: io method is %s, display type is %s\n",
|
||||
g_iomthd_values[io_mthd].name, g_disp_values[disp_type].name);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
LOG(STF_LEVEL_TRACE, "Exit\n");
|
||||
}
|
||||
|
||||
/**
|
||||
SIGINT interput handler
|
||||
*/
|
||||
void StopContCapture(int sig_id) {
|
||||
LOG(STF_LEVEL_INFO, "stoping continuous capture\n");
|
||||
gp_cfg_param->continuous = 0;
|
||||
}
|
||||
|
||||
void InstallSIGINTHandler() {
|
||||
struct sigaction sa;
|
||||
CLEAR(sa);
|
||||
|
||||
sa.sa_handler = StopContCapture;
|
||||
if (sigaction(SIGINT, &sa, 0) != 0) {
|
||||
LOG(STF_LEVEL_ERR, "could not install SIGINT handler, continuous capture disabled\n");
|
||||
gp_cfg_param->continuous = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
process image read, recommand NV21 or NV12
|
||||
TODO: use ffmpeg or opencv to convert the image format
|
||||
*/
|
||||
static void imageProcess(const uint8_t* inbuf, uint8_t* outbuf,
|
||||
struct timeval timestamp)
|
||||
{
|
||||
//timestamp.tv_sec
|
||||
//timestamp.tv_usec
|
||||
int in_width = gp_cfg_param->v4l2_param.width;
|
||||
int in_height = gp_cfg_param->v4l2_param.height;
|
||||
int in_imagesize = gp_cfg_param->v4l2_param.image_size;
|
||||
uint32_t in_format = gp_cfg_param->v4l2_param.format;
|
||||
char* jpegFilename = gp_cfg_param->jpegFilename;
|
||||
int disp_type = gp_cfg_param->disp_type;
|
||||
int new_in_format = 0;
|
||||
int out_format = 0;
|
||||
int out_size = 0;
|
||||
uint8_t* dst = malloc(in_width * in_height * 3);
|
||||
int is_yuv420sp = 0; // NOTE: NV21 or NV12, it is special for starfive framebuffer
|
||||
static int s_frmcnt = 0;
|
||||
|
||||
if (STF_DISP_FB == disp_type) {
|
||||
new_in_format = v4l2fmt_to_fbfmt(in_format);
|
||||
out_format = gp_cfg_param->fb_param.pixformat;
|
||||
out_size = gp_cfg_param->fb_param.screen_size;
|
||||
is_yuv420sp = gp_cfg_param->fb_param.vinfo.grayscale;
|
||||
} else if (STF_DISP_DRM == disp_type) {
|
||||
new_in_format = v4l2fmt_to_drmfmt(in_format);
|
||||
out_format = gp_cfg_param->drm_param.dev_head->drm_format;
|
||||
out_size = gp_cfg_param->drm_param.dev_head->bufs[0].size;
|
||||
}
|
||||
|
||||
LOG(STF_LEVEL_LOG, "in_width=%d, in_height=%d, in_imagesize=%d, out_size=%d, p=%p\n",
|
||||
in_width, in_height, in_imagesize, out_size, inbuf);
|
||||
|
||||
// write jpeg
|
||||
char filename[512];
|
||||
switch (in_format) {
|
||||
case V4L2_PIX_FMT_YUV420:
|
||||
// if (jpegFilename) {
|
||||
// // sprintf(filename, "%d-yuv420-%s", s_frmcnt, jpegFilename);
|
||||
// // YUV420toYUV444(in_width, in_height, inbuf, dst);
|
||||
// // jpegWrite(dst, filename);
|
||||
// sprintf(filename, "raw-%d-yuv420-%s", s_frmcnt, jpegFilename);
|
||||
// write_file(filename, inbuf, in_imagesize);
|
||||
// s_frmcnt++;
|
||||
// }
|
||||
if (gp_cfg_param->jpegFilename && gp_cfg_param->rec_fp) {
|
||||
fwrite(inbuf, in_imagesize, 1, gp_cfg_param->rec_fp);
|
||||
}
|
||||
break;
|
||||
case V4L2_PIX_FMT_YUYV:
|
||||
case V4L2_PIX_FMT_YVYU:
|
||||
// if (jpegFilename) {
|
||||
// // sprintf(filename, "%d-yuv422-%s", s_frmcnt, jpegFilename);
|
||||
// // YUV422toYUV444(in_width, in_height, inbuf, dst);
|
||||
// // jpegWrite(dst, filename);
|
||||
// sprintf(filename, "raw-%d-yuv422-%s", s_frmcnt, jpegFilename);
|
||||
// write_file(filename, inbuf, in_imagesize);
|
||||
// s_frmcnt++;
|
||||
// }
|
||||
if (gp_cfg_param->jpegFilename && gp_cfg_param->rec_fp) {
|
||||
fwrite(inbuf, in_imagesize, 1, gp_cfg_param->rec_fp);
|
||||
}
|
||||
if (out_format == new_in_format) {
|
||||
yuyv_resize(inbuf, outbuf, in_width, in_height);
|
||||
} else if ((STF_DISP_FB == disp_type) && is_yuv420sp) {
|
||||
convert_yuyv_to_nv12(inbuf, outbuf, in_width, in_height, 1);
|
||||
} else if ((STF_DISP_DRM == disp_type) && (out_format == V4L2_PIX_FMT_NV12)) {
|
||||
convert_yuyv_to_nv12(inbuf, outbuf, in_width, in_height, 1);
|
||||
} else {
|
||||
convert_yuyv_to_rgb(inbuf, outbuf, in_width, in_height, 0);
|
||||
}
|
||||
break;
|
||||
case V4L2_PIX_FMT_NV21:
|
||||
// if (gp_cfg_param->jpegFilename) {
|
||||
// // sprintf(filename, "%d-nv21-%s", s_frmcnt, gp_cfg_param->jpegFilename);
|
||||
// // YUV420NV21toYUV444(in_width, in_height, inbuf, dst, 0);
|
||||
// // jpegWrite(dst, filename);
|
||||
// sprintf(filename, "raw-nv21-%s", gp_cfg_param->jpegFilename);
|
||||
// write_file(filename, inbuf, in_imagesize);
|
||||
// s_frmcnt++;
|
||||
// }
|
||||
if (gp_cfg_param->jpegFilename && gp_cfg_param->rec_fp) {
|
||||
fwrite(inbuf, in_imagesize, 1, gp_cfg_param->rec_fp);
|
||||
}
|
||||
LOG(STF_LEVEL_LOG, "out_format=%d, new_in_format=%d, is_yuv420sp=%d\n", out_format,
|
||||
new_in_format, is_yuv420sp);
|
||||
if (outbuf) {
|
||||
if (out_format == new_in_format) {
|
||||
convert_nv21_to_nv12(inbuf, outbuf, in_width, in_height, 0);
|
||||
} else if ((STF_DISP_FB == disp_type) && is_yuv420sp) {
|
||||
convert_nv21_to_nv12(inbuf, outbuf, in_width, in_height, 1);
|
||||
} else {
|
||||
convert_nv21_to_nv12(inbuf, outbuf, in_width, in_height, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case V4L2_PIX_FMT_NV12:
|
||||
// if (jpegFilename) {
|
||||
// // sprintf(filename, "%d-nv12-%s", s_frmcnt, jpegFilename);
|
||||
// // YUV420NV12toYUV444(in_width, in_height, inbuf, dst);
|
||||
// // jpegWrite(dst, filename);
|
||||
// sprintf(filename, "raw-%d-nv12-%s", s_frmcnt, jpegFilename);
|
||||
// write_file(filename, inbuf, in_imagesize);
|
||||
// s_frmcnt++;
|
||||
// }
|
||||
if (gp_cfg_param->jpegFilename && gp_cfg_param->rec_fp) {
|
||||
fwrite(inbuf, in_imagesize, 1, gp_cfg_param->rec_fp);
|
||||
}
|
||||
LOG(STF_LEVEL_DEBUG, "out_format=%d, new_in_format=%d, is_yuv420sp=%d\n", out_format,
|
||||
new_in_format, is_yuv420sp);
|
||||
if (out_format == new_in_format) {
|
||||
convert_nv21_to_nv12(inbuf, outbuf, in_width, in_height, 0);
|
||||
} else if ((STF_DISP_FB == disp_type) && is_yuv420sp) {
|
||||
convert_nv21_to_nv12(inbuf, outbuf, in_width, in_height, 1);
|
||||
} else {
|
||||
convert_nv21_to_rgb(inbuf, outbuf, in_width, in_height, 0);
|
||||
}
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB24:
|
||||
// if (jpegFilename) {
|
||||
// // sprintf(filename, "%d-rgb-%s", s_frmcnt, jpegFilename);
|
||||
// // RGB565toRGB888(in_width, in_height, inbuf, dst);
|
||||
// // write_JPEG_file(filename, inbuf, in_width, in_height, jpegQuality);
|
||||
// sprintf(filename, "raw-%d-rgb-%s", s_frmcnt, jpegFilename);
|
||||
// write_file(filename, inbuf, in_imagesize);
|
||||
// s_frmcnt++;
|
||||
// }
|
||||
if (gp_cfg_param->jpegFilename && gp_cfg_param->rec_fp) {
|
||||
fwrite(inbuf, in_imagesize, 1, gp_cfg_param->rec_fp);
|
||||
}
|
||||
convert_rgb888_to_rgb(inbuf, outbuf, in_width, in_height, 0);
|
||||
break;
|
||||
case V4L2_PIX_FMT_RGB565:
|
||||
// if (jpegFilename) {
|
||||
// // sprintf(filename, "%d-rgb565-%s", s_frmcnt, jpegFilename);
|
||||
// // RGB565toRGB888(in_width, in_height, inbuf, dst);
|
||||
// // write_JPEG_file(filename, dst, in_width, in_height, jpegQuality);
|
||||
// sprintf(filename, "raw-%d-rgb565-%s", s_frmcnt, jpegFilename);
|
||||
// write_file(filename, inbuf, in_imagesize);
|
||||
// s_frmcnt++;
|
||||
// }
|
||||
if (gp_cfg_param->jpegFilename && gp_cfg_param->rec_fp) {
|
||||
fwrite(inbuf, in_imagesize, 1, gp_cfg_param->rec_fp);
|
||||
}
|
||||
if (out_format == new_in_format)
|
||||
convert_rgb565_to_rgb(inbuf, outbuf, in_width, in_height, 0);
|
||||
else if ((STF_DISP_FB == disp_type) && is_yuv420sp)
|
||||
convert_rgb565_to_nv12(inbuf, outbuf, in_width, in_height, 0);
|
||||
else
|
||||
convert_rgb565_to_rgb(inbuf, outbuf, in_width, in_height, 0);
|
||||
break;
|
||||
case V4L2_PIX_FMT_SRGGB12:
|
||||
if (jpegFilename)
|
||||
sprintf(filename, "raw-%d-RGGB12-%s", s_frmcnt, jpegFilename);
|
||||
else
|
||||
sprintf(filename, "raw-%d-RGGB12.raw", s_frmcnt);
|
||||
write_file(filename, inbuf, in_imagesize);
|
||||
RAW12toRAW16(in_width, in_height, inbuf, dst);
|
||||
if (jpegFilename)
|
||||
sprintf(filename, "raw-%d-RGGB16-%s", s_frmcnt, jpegFilename);
|
||||
else
|
||||
sprintf(filename, "raw-%d-RGGB16.raw", s_frmcnt);
|
||||
write_file(filename, (const uint8_t *)dst, in_width * in_height * 2);
|
||||
s_frmcnt++;
|
||||
break;
|
||||
case V4L2_PIX_FMT_SGRBG12:
|
||||
if (jpegFilename)
|
||||
sprintf(filename, "raw-%d-GRBG12-%s", s_frmcnt, jpegFilename);
|
||||
else
|
||||
sprintf(filename, "raw-%d-GRBG12.raw", s_frmcnt);
|
||||
write_file(filename, inbuf, in_imagesize);
|
||||
RAW12toRAW16(in_width, in_height, inbuf, dst);
|
||||
if (jpegFilename)
|
||||
sprintf(filename, "raw-%d-GRBG16-%s", s_frmcnt, jpegFilename);
|
||||
else
|
||||
sprintf(filename, "raw-%d-GRBG16.raw", s_frmcnt);
|
||||
write_file(filename, (const uint8_t *)dst, in_width * in_height * 2);
|
||||
s_frmcnt++;
|
||||
break;
|
||||
case V4L2_PIX_FMT_SGBRG12:
|
||||
if (jpegFilename)
|
||||
sprintf(filename, "raw-%d-GBRG12-%s", s_frmcnt, jpegFilename);
|
||||
else
|
||||
sprintf(filename, "raw-%d-GBRG12.raw", s_frmcnt);
|
||||
write_file(filename, inbuf, in_imagesize);
|
||||
RAW12toRAW16(in_width, in_height, inbuf, dst);
|
||||
if (jpegFilename)
|
||||
sprintf(filename, "raw-%d-GBRG16-%s", s_frmcnt, jpegFilename);
|
||||
else
|
||||
sprintf(filename, "raw-%d-GBRG16.raw", s_frmcnt);
|
||||
write_file(filename, (const uint8_t *)dst, in_width * in_height * 2);
|
||||
s_frmcnt++;
|
||||
break;
|
||||
case V4L2_PIX_FMT_SBGGR12:
|
||||
if (jpegFilename)
|
||||
sprintf(filename, "raw-%d-BGGR12-%s", s_frmcnt, jpegFilename);
|
||||
else
|
||||
sprintf(filename, "raw-%d-BGGR12.raw", s_frmcnt);
|
||||
write_file(filename, inbuf, in_imagesize);
|
||||
RAW12toRAW16(in_width, in_height, inbuf, dst);
|
||||
if (jpegFilename)
|
||||
sprintf(filename, "raw-%d-BGGR16-%s", s_frmcnt, jpegFilename);
|
||||
else
|
||||
sprintf(filename, "raw-%d-BGGR16.raw", s_frmcnt);
|
||||
write_file(filename, (const uint8_t *)dst, in_width * in_height * 2);
|
||||
s_frmcnt++;
|
||||
break;
|
||||
default:
|
||||
LOG(STF_LEVEL_ERR, "unknow in_format\n");
|
||||
break;
|
||||
}
|
||||
|
||||
// free temporary image
|
||||
free(dst);
|
||||
}
|
||||
|
||||
void calc_frame_fps()
|
||||
{
|
||||
static uint32_t frm_cnt = 0;
|
||||
static struct timespec ts_old;
|
||||
struct timespec ts;
|
||||
uint32_t fps = 0;
|
||||
uint32_t diff_ms = 0;
|
||||
|
||||
if (frm_cnt == 0) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts_old);
|
||||
}
|
||||
if (frm_cnt++ >= 50) {
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
diff_ms = (ts.tv_sec - ts_old.tv_sec) * 1000 + (ts.tv_nsec - ts_old.tv_nsec) / 1000000;
|
||||
fps = 1000 * (frm_cnt - 1) / diff_ms;
|
||||
frm_cnt = 0;
|
||||
LOG(STF_LEVEL_INFO, "pipeline display fps=%d\n", fps);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
read single frame
|
||||
*/
|
||||
static int frameRead(void)
|
||||
{
|
||||
struct v4l2_buffer buf;
|
||||
V4l2Param_t *pv4l2_param = &gp_cfg_param->v4l2_param;
|
||||
uint8_t *dst = NULL;
|
||||
|
||||
if (STF_DISP_FB == gp_cfg_param->disp_type) {
|
||||
dst = gp_cfg_param->fb_param.screen_buf;
|
||||
} else if (STF_DISP_DRM == gp_cfg_param->disp_type &&
|
||||
IO_METHOD_DMABUF != gp_cfg_param->io_mthd) {
|
||||
dst = gp_cfg_param->drm_param.dev_head->bufs[0].buf;
|
||||
} else {
|
||||
LOG(STF_LEVEL_LOG, "Not display\n");
|
||||
}
|
||||
|
||||
switch (pv4l2_param->io_mthd) {
|
||||
case IO_METHOD_READ:
|
||||
if (-1 == v4l2_read(pv4l2_param->fd, pv4l2_param->pBuffers[0].start,
|
||||
pv4l2_param->pBuffers[0].length)) {
|
||||
switch (errno) {
|
||||
case EAGAIN:
|
||||
return 0;
|
||||
case EIO:
|
||||
// Could ignore EIO, see spec.
|
||||
// fall through
|
||||
default:
|
||||
errno_exit("read");
|
||||
}
|
||||
}
|
||||
struct timespec ts;
|
||||
struct timeval timestamp;
|
||||
clock_gettime(CLOCK_MONOTONIC,&ts);
|
||||
timestamp.tv_sec = ts.tv_sec;
|
||||
timestamp.tv_usec = ts.tv_nsec/1000;
|
||||
imageProcess((uint8_t *)(pv4l2_param->pBuffers[0].start), dst, timestamp);
|
||||
break;
|
||||
|
||||
case IO_METHOD_MMAP:
|
||||
stf_v4l2_dequeue_buffer(pv4l2_param, &buf);
|
||||
LOG(STF_LEVEL_LOG, "buf.index=%d, n_buffers=%d\n",
|
||||
buf.index, gp_cfg_param->v4l2_param.n_buffers);
|
||||
imageProcess((uint8_t *)(pv4l2_param->pBuffers[buf.index].start), dst, buf.timestamp);
|
||||
stf_v4l2_queue_buffer(pv4l2_param, buf.index);
|
||||
if (STF_DISP_DRM == gp_cfg_param->disp_type) {
|
||||
drmModePageFlip(gp_cfg_param->drm_param.fd, gp_cfg_param->drm_param.dev_head->crtc_id,
|
||||
gp_cfg_param->drm_param.dev_head->bufs[0].fb_id,
|
||||
DRM_MODE_PAGE_FLIP_EVENT, gp_cfg_param->drm_param.dev_head);
|
||||
}
|
||||
LOG(STF_LEVEL_LOG, "buf.index: %d, buf.bytesused=%d\n", buf.index, buf.bytesused);
|
||||
break;
|
||||
|
||||
case IO_METHOD_USERPTR:
|
||||
stf_v4l2_dequeue_buffer(pv4l2_param, &buf);
|
||||
imageProcess((uint8_t *)(buf.m.userptr), dst, buf.timestamp);
|
||||
stf_v4l2_queue_buffer(pv4l2_param, buf.index);
|
||||
break;
|
||||
case IO_METHOD_DMABUF:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* mainloop_select: read frames with select() and process them
|
||||
*/
|
||||
static void mainloop_select(void)
|
||||
{
|
||||
int count, i;
|
||||
uint32_t numberOfTimeouts;
|
||||
|
||||
numberOfTimeouts = 0;
|
||||
count = 3;
|
||||
|
||||
while (count-- > 0) {
|
||||
for (i = 0; i < 1; i++) {
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
int r;
|
||||
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(gp_cfg_param->v4l2_param.fd, &fds);
|
||||
|
||||
/* Timeout. */
|
||||
tv.tv_sec = 1;
|
||||
tv.tv_usec = 0;
|
||||
r = select(gp_cfg_param->v4l2_param.fd + 1, &fds, NULL, NULL, &tv);
|
||||
if (-1 == r) {
|
||||
if (EINTR == errno) {
|
||||
continue;
|
||||
}
|
||||
errno_exit("select");
|
||||
} else if (0 == r) {
|
||||
if (numberOfTimeouts <= 0) {
|
||||
// count++;
|
||||
} else {
|
||||
LOG(STF_LEVEL_ERR, "select timeout\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if (gp_cfg_param->continuous == 1) {
|
||||
count = 3;
|
||||
}
|
||||
|
||||
if (frameRead())
|
||||
break;
|
||||
|
||||
/* EAGAIN - continue select loop. */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void page_flip_handler(int fd, unsigned int frame,
|
||||
unsigned int sec, unsigned int usec,
|
||||
void *data)
|
||||
{
|
||||
struct drm_dev_t *dev = data;
|
||||
|
||||
/* If we have a next buffer, then let's return the current one,
|
||||
* and grab the next one.
|
||||
*/
|
||||
if (g_drm_buf_next_idx > 0) {
|
||||
stf_v4l2_queue_buffer(&gp_cfg_param->v4l2_param, g_drm_buf_curr_idx);
|
||||
g_drm_buf_curr_idx = g_drm_buf_next_idx;
|
||||
g_drm_buf_next_idx = -1;
|
||||
}
|
||||
drmModePageFlip(fd, dev->crtc_id, dev->bufs[g_drm_buf_curr_idx].fb_id,
|
||||
DRM_MODE_PAGE_FLIP_EVENT, dev);
|
||||
}
|
||||
|
||||
static void mainloop()
|
||||
{
|
||||
struct v4l2_buffer buf;
|
||||
int r;
|
||||
int count = 3;
|
||||
drmEventContext ev;
|
||||
struct pollfd* fds = NULL;
|
||||
uint32_t nfds = 0;
|
||||
|
||||
LOG(STF_LEVEL_TRACE, "Enter\n");
|
||||
if (STF_DISP_FB == gp_cfg_param->disp_type ||
|
||||
IO_METHOD_MMAP == gp_cfg_param->io_mthd) {
|
||||
// fb or (drm + mmap)
|
||||
nfds = 1;
|
||||
fds = (struct pollfd*)malloc(sizeof(struct pollfd) * nfds);
|
||||
memset(fds, 0, sizeof(struct pollfd) * nfds);
|
||||
fds[0].fd = gp_cfg_param->v4l2_param.fd;
|
||||
fds[0].events = POLLIN;
|
||||
} else if (STF_DISP_DRM == gp_cfg_param->disp_type &&
|
||||
IO_METHOD_DMABUF == gp_cfg_param->io_mthd) {
|
||||
// (drm + dmabuf)
|
||||
nfds = 2;
|
||||
fds = (struct pollfd*)malloc(sizeof(struct pollfd) * nfds);
|
||||
memset(fds, 0, sizeof(struct pollfd) * nfds);
|
||||
fds[0].fd = gp_cfg_param->v4l2_param.fd;
|
||||
fds[0].events = POLLIN;
|
||||
fds[1].fd = gp_cfg_param->drm_param.fd;
|
||||
fds[1].events = POLLIN;
|
||||
|
||||
memset(&ev, 0, sizeof ev);
|
||||
ev.version = DRM_EVENT_CONTEXT_VERSION;
|
||||
ev.vblank_handler = NULL;
|
||||
ev.page_flip_handler = page_flip_handler;
|
||||
} else {
|
||||
LOG(STF_LEVEL_ERR, "Display type %d and io method type %d not support\n",
|
||||
gp_cfg_param->disp_type, gp_cfg_param->io_mthd);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (!gp_cfg_param->rec_fp && gp_cfg_param->jpegFilename) {
|
||||
gp_cfg_param->rec_fp = fopen(gp_cfg_param->jpegFilename, "w+");
|
||||
if (!gp_cfg_param->rec_fp) {
|
||||
LOG(STF_LEVEL_ERR, "can't open %s\n", gp_cfg_param->jpegFilename);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
while (count-- > 0) {
|
||||
r = poll(fds, nfds, 3000);
|
||||
if (-1 == r) {
|
||||
if (EINTR == errno) {
|
||||
continue;
|
||||
}
|
||||
LOG(STF_LEVEL_ERR, "error in poll %d", errno);
|
||||
break;
|
||||
}
|
||||
if (0 == r) {
|
||||
LOG(STF_LEVEL_ERR, "poll timeout, %d\n", errno);
|
||||
break;
|
||||
}
|
||||
|
||||
if (STF_DISP_FB == gp_cfg_param->disp_type ||
|
||||
IO_METHOD_MMAP == gp_cfg_param->io_mthd) {
|
||||
// fb or (drm + mmap)
|
||||
if (fds[0].revents & POLLIN) {
|
||||
frameRead();
|
||||
calc_frame_fps();
|
||||
}
|
||||
} else if (STF_DISP_DRM == gp_cfg_param->disp_type &&
|
||||
IO_METHOD_DMABUF == gp_cfg_param->io_mthd) {
|
||||
// drm + dmabuf
|
||||
if (fds[0].revents & POLLIN) {
|
||||
int dequeued = stf_v4l2_dequeue_buffer(&gp_cfg_param->v4l2_param, &buf);
|
||||
if (dequeued) {
|
||||
g_drm_buf_next_idx = buf.index;
|
||||
frameRead(); // TODO: add support for save file later
|
||||
calc_frame_fps();
|
||||
}
|
||||
}
|
||||
if (fds[1].revents & POLLIN) {
|
||||
if (g_drm_buf_next_idx > 0) {
|
||||
drmHandleEvent(gp_cfg_param->drm_param.fd, &ev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gp_cfg_param->continuous == 1) {
|
||||
count = 3;
|
||||
}
|
||||
|
||||
usleep(1 * 1000);
|
||||
}
|
||||
|
||||
if (fds) {
|
||||
free(fds);
|
||||
fds = NULL;
|
||||
}
|
||||
|
||||
|
||||
if (gp_cfg_param->rec_fp) {
|
||||
fclose(gp_cfg_param->rec_fp);
|
||||
gp_cfg_param->rec_fp = NULL;
|
||||
}
|
||||
|
||||
|
||||
LOG(STF_LEVEL_TRACE, "Exit\n");
|
||||
}
|
||||
|
||||
static void usage(FILE* fp, int argc, char** argv)
|
||||
{
|
||||
fprintf(fp,
|
||||
"Usage: %s [options]\n\n"
|
||||
"Options:\n"
|
||||
"-d | --device name Video device name [default /dev/video0]\n"
|
||||
"-h | --help Print this message\n"
|
||||
"-o | --output Save raw data to filename\n"
|
||||
//"-q | --quality Set JPEG quality (0-100)\n"
|
||||
"-m | --method Set V4L2 videobuf2 memory type, default 0\n"
|
||||
" 0: IO_METHOD_MMAP\n"
|
||||
" 1: IO_METHOD_USERPTR\n"
|
||||
" 2: IO_METHOD_DMABUF\n"
|
||||
" 3: IO_METHOD_READ\n"
|
||||
"-W | --width Set v4l2 image width, default 1920\n"
|
||||
"-H | --height Set v4l2 image height, default 1080\n"
|
||||
"-X | --left Set v4l2 image crop x start\n"
|
||||
"-Y | --up Set v4l2 image crop y start\n"
|
||||
"-R | --right Set v4l2 image crop x width\n"
|
||||
"-D | --down Set v4l2 image crop y height\n"
|
||||
"-I | --interval Set frame interval (fps) (-1 to skip)\n"
|
||||
"-c | --continuous Do continous capture, stop with SIGINT.\n"
|
||||
"-v | --version Print version\n"
|
||||
"-f | --format image format, default 5\n"
|
||||
" 0: V4L2_PIX_FMT_RGB565\n"
|
||||
" 1: V4L2_PIX_FMT_RGB24\n"
|
||||
" 2: V4L2_PIX_FMT_YUV420\n"
|
||||
" 3: V4L2_PIX_FMT_YUYV\n"
|
||||
" 4: V4L2_PIX_FMT_NV21\n"
|
||||
" 5: V4L2_PIX_FMT_NV12\n"
|
||||
" 6: V4L2_PIX_FMT_YVYU\n"
|
||||
" 7: V4L2_PIX_FMT_SRGGB12\n"
|
||||
" 8: V4L2_PIX_FMT_SGRBG12\n"
|
||||
" 9: V4L2_PIX_FMT_SGBRG12\n"
|
||||
" 10: V4L2_PIX_FMT_SBGGR12\n"
|
||||
" default: V4L2_PIX_FMT_NV12\n"
|
||||
"-t | --distype set display type, default 0\n"
|
||||
" 0: Not display\n"
|
||||
" 1: Use Framebuffer Display\n"
|
||||
" 2: Use DRM Display\n"
|
||||
"-l | --loadfw load stfisp fw image\n"
|
||||
"-s | --g_imagesize print image size\n"
|
||||
"\n"
|
||||
"Eg:\n"
|
||||
"\t drm: v4l2test -d /dev/video2 -f 5 -c -W 1920 -H 1080 -m 2 -t 2\n"
|
||||
"\t fb: v4l2test -d /dev/video2 -f 5 -c -W 1920 -H 1080 -m 0 -t 1\n"
|
||||
"\n"
|
||||
"Open debug log level: \n"
|
||||
"\t export V4L2_DEBUG=3\n"
|
||||
"\t default level 1, level range 0 ~ 7\n"
|
||||
"",
|
||||
argv[0]);
|
||||
}
|
||||
|
||||
static const char short_options [] = "d:ho:q:m:W:H:I:vcf:t:X:Y:R:D:l:s";
|
||||
|
||||
static const struct option long_options [] = {
|
||||
{ "device", required_argument, NULL, 'd' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "output", required_argument, NULL, 'o' },
|
||||
{ "quality", required_argument, NULL, 'q' },
|
||||
{ "method", required_argument, NULL, 'm' },
|
||||
{ "width", required_argument, NULL, 'W' },
|
||||
{ "height", required_argument, NULL, 'H' },
|
||||
{ "left", required_argument, NULL, 'X' },
|
||||
{ "up", required_argument, NULL, 'Y' },
|
||||
{ "right", required_argument, NULL, 'R' },
|
||||
{ "down", required_argument, NULL, 'D' },
|
||||
{ "interval", required_argument, NULL, 'I' },
|
||||
{ "version", no_argument, NULL, 'v' },
|
||||
{ "continuous", no_argument, NULL, 'c' },
|
||||
{ "format", required_argument, NULL, 'f' },
|
||||
{ "distype", required_argument, NULL, 't' },
|
||||
{ "loadfw", required_argument, NULL, 'l' },
|
||||
{ "g_imagesize",no_argument, NULL, 's' },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
void parse_options(int argc, char **argv, ConfigParam_t *cfg_param)
|
||||
{
|
||||
int index, c = 0;
|
||||
int value = 0;
|
||||
|
||||
while ((c = getopt_long(argc, argv, short_options, long_options, &index)) != -1) {
|
||||
switch (c) {
|
||||
case 0: /* getopt_long() flag */
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
cfg_param->v4l2_param.device_name = strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
usage(stdout, argc, argv);
|
||||
exit(EXIT_SUCCESS);
|
||||
|
||||
case 'o':
|
||||
// set jpeg filename
|
||||
cfg_param->jpegFilename = strdup(optarg);
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
// set jpeg quality
|
||||
cfg_param->jpegQuality = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
value = atoi(optarg);
|
||||
if (value < IO_METHOD_MMAP || value > IO_METHOD_READ) {
|
||||
LOG(STF_LEVEL_ERR, "io method %d is out of range [%d, %d]\n", value,
|
||||
IO_METHOD_MMAP, IO_METHOD_READ);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
LOG(STF_LEVEL_INFO, "io method: %s\n", g_iomthd_values[value].name);
|
||||
cfg_param->io_mthd = value;
|
||||
cfg_param->v4l2_param.io_mthd = cfg_param->io_mthd;
|
||||
break;
|
||||
|
||||
case 'W':
|
||||
// set v4l2 width
|
||||
cfg_param->v4l2_param.width = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
// set v4l2 height
|
||||
cfg_param->v4l2_param.height = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'X':
|
||||
// set x start
|
||||
cfg_param->v4l2_param.crop_info.left = atoi(optarg);
|
||||
cfg_param->v4l2_param.crop_flag = 1;
|
||||
break;
|
||||
|
||||
case 'Y':
|
||||
// set y start
|
||||
cfg_param->v4l2_param.crop_info.top = atoi(optarg);
|
||||
cfg_param->v4l2_param.crop_flag = 1;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
// set x width
|
||||
cfg_param->v4l2_param.crop_info.width = atoi(optarg);
|
||||
cfg_param->v4l2_param.crop_flag = 1;
|
||||
break;
|
||||
|
||||
case 'D':
|
||||
// set y height
|
||||
cfg_param->v4l2_param.crop_info.height = atoi(optarg);
|
||||
cfg_param->v4l2_param.crop_flag = 1;
|
||||
break;
|
||||
|
||||
case 'I':
|
||||
// set fps
|
||||
cfg_param->v4l2_param.fps = atoi(optarg);
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
// set flag for continuous capture, interuptible by sigint
|
||||
cfg_param->continuous = 1;
|
||||
InstallSIGINTHandler();
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
printf("Version: %s\n", TEST_VERSION);
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
LOG(STF_LEVEL_INFO, "v4l2 format: %s\n", optarg);
|
||||
value = atoi(optarg);
|
||||
LOG(STF_LEVEL_INFO, "v4l2 format: %d\n", value);
|
||||
switch (value) {
|
||||
case 0:
|
||||
value = V4L2_PIX_FMT_RGB565;
|
||||
break;
|
||||
case 1:
|
||||
value = V4L2_PIX_FMT_RGB24;
|
||||
break;
|
||||
case 2:
|
||||
value = V4L2_PIX_FMT_YUV420;
|
||||
break;
|
||||
case 3:
|
||||
value = V4L2_PIX_FMT_YUYV;
|
||||
break;
|
||||
case 4:
|
||||
value = V4L2_PIX_FMT_NV21;
|
||||
break;
|
||||
case 5:
|
||||
value = V4L2_PIX_FMT_NV12;
|
||||
break;
|
||||
case 6:
|
||||
value = V4L2_PIX_FMT_YVYU;
|
||||
break;
|
||||
case 7:
|
||||
value = V4L2_PIX_FMT_SRGGB12;
|
||||
break;
|
||||
case 8:
|
||||
value = V4L2_PIX_FMT_SGRBG12;
|
||||
break;
|
||||
case 9:
|
||||
value = V4L2_PIX_FMT_SGBRG12;
|
||||
break;
|
||||
case 10:
|
||||
value = V4L2_PIX_FMT_SBGGR12;
|
||||
break;
|
||||
default:
|
||||
value = V4L2_PIX_FMT_RGB565;
|
||||
break;
|
||||
}
|
||||
cfg_param->v4l2_param.format = value;
|
||||
break;
|
||||
|
||||
case 't':
|
||||
value = atoi(optarg);
|
||||
if (value < STF_DISP_NONE || value > STF_DISP_DRM) {
|
||||
LOG(STF_LEVEL_ERR, "Display Type %d is out of range [%d, %d]\n", value,
|
||||
STF_DISP_NONE, STF_DISP_DRM);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
LOG(STF_LEVEL_INFO, "Display Type: %s\n", g_disp_values[value].name);
|
||||
cfg_param->disp_type = value;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
loadfw_start(optarg, &(cfg_param->v4l2_param));
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
case 's':
|
||||
sensor_image_size_info(&(cfg_param->v4l2_param));
|
||||
exit(EXIT_SUCCESS);
|
||||
break;
|
||||
default:
|
||||
usage(stderr, argc, argv);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
init_log();
|
||||
alloc_default_config(&gp_cfg_param);
|
||||
parse_options(argc, argv, gp_cfg_param);
|
||||
check_cfg_params(gp_cfg_param);
|
||||
|
||||
// open and initialize v4l2 device
|
||||
stf_v4l2_open(&gp_cfg_param->v4l2_param, gp_cfg_param->v4l2_param.device_name);
|
||||
stf_v4l2_init(&gp_cfg_param->v4l2_param);
|
||||
|
||||
if (STF_DISP_FB == gp_cfg_param->disp_type) {
|
||||
stf_fb_open(&gp_cfg_param->fb_param, FB_DEVICE_NAME, STFBC_DEVICE_NAME);
|
||||
stf_fb_init(&gp_cfg_param->fb_param, gp_cfg_param->v4l2_param.format);
|
||||
update_videocvt_param(gp_cfg_param->disp_type, gp_cfg_param->fb_param.width,
|
||||
gp_cfg_param->fb_param.height, gp_cfg_param->fb_param.bpp,
|
||||
gp_cfg_param->fb_param.screen_size);
|
||||
|
||||
} else if (STF_DISP_DRM == gp_cfg_param->disp_type) {
|
||||
stf_drm_open(&gp_cfg_param->drm_param, DRM_DEVICE_NAME, gp_cfg_param->io_mthd);
|
||||
stf_drm_init(&gp_cfg_param->drm_param, gp_cfg_param->v4l2_param.width,
|
||||
gp_cfg_param->v4l2_param.height, gp_cfg_param->v4l2_param.format,
|
||||
gp_cfg_param->io_mthd, gp_cfg_param->dmabufs,
|
||||
sizeof(gp_cfg_param->dmabufs) / sizeof(gp_cfg_param->dmabufs[0]));
|
||||
update_videocvt_param(gp_cfg_param->disp_type, gp_cfg_param->drm_param.dev_head->width,
|
||||
gp_cfg_param->drm_param.dev_head->height, 32,
|
||||
gp_cfg_param->drm_param.dev_head->bufs[0].size);
|
||||
|
||||
}
|
||||
|
||||
// prepare and start v4l2 capturing
|
||||
sft_v4l2_prepare_capturing(&gp_cfg_param->v4l2_param, gp_cfg_param->dmabufs, BUFCOUNT);
|
||||
sft_v4l2_start_capturing(&(gp_cfg_param->v4l2_param));
|
||||
|
||||
// process frames
|
||||
mainloop();
|
||||
|
||||
stf_v4l2_stop_capturing(&gp_cfg_param->v4l2_param);
|
||||
stf_v4l2_uninit(&gp_cfg_param->v4l2_param);
|
||||
stf_v4l2_close(&gp_cfg_param->v4l2_param);
|
||||
|
||||
if (STF_DISP_FB == gp_cfg_param->disp_type) {
|
||||
stf_fb_uninit(&gp_cfg_param->fb_param);
|
||||
stf_fb_close(&gp_cfg_param->fb_param);
|
||||
} else if (STF_DISP_DRM == gp_cfg_param->disp_type) {
|
||||
stf_drm_close(&gp_cfg_param->drm_param);
|
||||
}
|
||||
|
||||
deinit_log();
|
||||
free(gp_cfg_param);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user