123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919 |
- // 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;
- }
|