meta-digi/meta-digi-dey/recipes-digi/dey-examples/files/v4l2_test/v4l2_still.c

391 lines
13 KiB
C

/*
* Copyright 2004-2010 Freescale Semiconductor, Inc. All rights reserved.
* Copyright 2010 Digi International. All rights reserved.
*/
/*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
/*
* @file v4l2_still.c
*
* @brief Video For Linux 2 driver test application
*
*/
#ifdef __cplusplus
extern "C" {
#endif
/*=======================================================================
INCLUDE FILES
=======================================================================*/
/* Standard Include Files */
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <asm/types.h>
#include <sys/mman.h>
#include <string.h>
#include <malloc.h>
#include "v4l2_defs.h"
#define ipu_fourcc(a,b,c,d)\
(((__u32)(a)<<0)|((__u32)(b)<<8)|((__u32)(c)<<16)|((__u32)(d)<<24))
#define IPU_PIX_FMT_YUYV ipu_fourcc('Y','U','Y','V') /*!< 16 YUV 4:2:2 */
#define IPU_PIX_FMT_UYVY ipu_fourcc('U','Y','V','Y') /*!< 16 YUV 4:2:2 */
#define IPU_PIX_FMT_NV12 ipu_fourcc('N','V','1','2') /* 12 Y/CbCr 4:2:0 */
#define IPU_PIX_FMT_YUV420P ipu_fourcc('I','4','2','0') /*!< 12 YUV 4:2:0 */
#define IPU_PIX_FMT_YUV420P2 ipu_fourcc('Y','U','1','2') /*!< 12 YUV 4:2:0 */
#define IPU_PIX_FMT_YUV422P ipu_fourcc('4','2','2','P') /*!< 16 YUV 4:2:2 */
#define IPU_PIX_FMT_YUV444 ipu_fourcc('Y','4','4','4') /*!< 24 YUV 4:4:4 */
#define IPU_PIX_FMT_RGB565 ipu_fourcc('R','G','B','P') /*!< 16 RGB-5-6-5 */
#define IPU_PIX_FMT_BGR24 ipu_fourcc('B','G','R','3') /*!< 24 BGR-8-8-8 */
#define IPU_PIX_FMT_RGB24 ipu_fourcc('R','G','B','3') /*!< 24 RGB-8-8-8 */
#define IPU_PIX_FMT_BGR32 ipu_fourcc('B','G','R','4') /*!< 32 BGR-8-8-8-8 */
#define IPU_PIX_FMT_BGRA32 ipu_fourcc('B','G','R','A') /*!< 32 BGR-8-8-8-8 */
#define IPU_PIX_FMT_RGB32 ipu_fourcc('R','G','B','4') /*!< 32 RGB-8-8-8-8 */
#define IPU_PIX_FMT_RGBA32 ipu_fourcc('R','G','B','A') /*!< 32 RGB-8-8-8-8 */
#define IPU_PIX_FMT_ABGR32 ipu_fourcc('A','B','G','R') /*!< 32 ABGR-8-8-8-8 */
static int g_convert = 0;
static int g_width = 640;
static int g_height = 480;
static int g_top = 0;
static int g_left = 0;
static unsigned long g_pixelformat = IPU_PIX_FMT_UYVY;
static int g_bpp = 16;
static int g_camera_framerate = 30;
static int g_capture_mode = 0;
static char g_v4l_device[100] = "/dev/video0";
void usage(void)
{
printf("Usage: v4l2_still [-w width] [-h height] [-t top] [-l left] [-f pixformat] [-c] [-m] [-fr]\n"
"-w Image width, 640 by default\n"
"-h Image height, 480 by default\n"
"-t Image top(crop from the source frame), 0 by default\n"
"-l Image left(crop from the source frame), 0 by default\n"
"-f Image pixel format, YUV420, YUV422P, YUYV, UYVY ((default) or YUV444\n"
"-c Convert to YUV420P. This option is valid for interleaved pixel\n"
" formats only - YUYV, UYVY, YUV444\n"
"-m Capture mode, 0-low resolution(default), 1-high resolution \n"
"-d Camera select, /dev/video0, /dev/video1 \n"
"-fr Capture frame rate, 30fps by default\n"
"The output is saved in ./still.uyvy\n"
);
}
/* Convert to YUV420 format */
void fmt_convert(char *dest, char *src, struct v4l2_format *fmt)
{
int row, col, pos = 0;
int bpp, yoff, uoff, voff;
if (fmt->fmt.pix.pixelformat == IPU_PIX_FMT_YUYV) {
bpp = 2;
yoff = 0;
uoff = 1;
voff = 3;
}
else if (fmt->fmt.pix.pixelformat == IPU_PIX_FMT_UYVY) {
bpp = 2;
yoff = 1;
uoff = 0;
voff = 2;
}
else { /* YUV444 */
bpp = 4;
yoff = 0;
uoff = 1;
voff = 2;
}
/* Copy Y */
for (row = 0; row < fmt->fmt.pix.height; row++)
for (col = 0; col < fmt->fmt.pix.width; col++)
dest[pos++] = src[row * fmt->fmt.pix.bytesperline + col * bpp + yoff];
/* Copy U */
for (row = 0; row < fmt->fmt.pix.height; row += 2) {
for (col = 0; col < fmt->fmt.pix.width; col += 2)
dest[pos++] = src[row * fmt->fmt.pix.bytesperline + col * bpp + uoff];
}
/* Copy V */
for (row = 0; row < fmt->fmt.pix.height; row += 2) {
for (col = 0; col < fmt->fmt.pix.width; col += 2)
dest[pos++] = src[row * fmt->fmt.pix.bytesperline + col * bpp + voff];
}
}
int bytes_per_pixel(int fmt)
{
switch (fmt) {
case IPU_PIX_FMT_YUV420P:
case IPU_PIX_FMT_YUV422P:
case IPU_PIX_FMT_NV12:
return 1;
break;
case IPU_PIX_FMT_RGB565:
case IPU_PIX_FMT_YUYV:
case IPU_PIX_FMT_UYVY:
return 2;
break;
case IPU_PIX_FMT_BGR24:
case IPU_PIX_FMT_RGB24:
return 3;
break;
case IPU_PIX_FMT_BGR32:
case IPU_PIX_FMT_BGRA32:
case IPU_PIX_FMT_RGB32:
case IPU_PIX_FMT_RGBA32:
case IPU_PIX_FMT_ABGR32:
return 4;
break;
default:
return 1;
break;
}
return 0;
}
int v4l_capture_setup(int * fd_v4l)
{
struct v4l2_streamparm parm;
struct v4l2_format fmt;
struct v4l2_crop crop;
int ret = 0;
if ((*fd_v4l = open(g_v4l_device, O_RDWR, 0)) < 0)
{
printf("Unable to open %s\n", g_v4l_device);
return -1;
}
parm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
parm.parm.capture.timeperframe.numerator = 1;
parm.parm.capture.timeperframe.denominator = g_camera_framerate;
parm.parm.capture.capturemode = g_capture_mode;
if ((ret = ioctl(*fd_v4l, VIDIOC_S_PARM, &parm)) < 0)
{
printf("VIDIOC_S_PARM failed\n");
return ret;
}
crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
crop.c.left = g_left;
crop.c.top = g_top;
crop.c.width = g_width;
crop.c.height = g_height;
if ((ret = ioctl(*fd_v4l, VIDIOC_S_CROP, &crop)) < 0)
{
printf("set cropping failed\n");
return ret;
}
memset(&fmt, 0, sizeof(fmt));
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.pixelformat = g_pixelformat;
fmt.fmt.pix.width = g_width;
fmt.fmt.pix.height = g_height;
fmt.fmt.pix.sizeimage = fmt.fmt.pix.width * fmt.fmt.pix.height * g_bpp / 8;
fmt.fmt.pix.bytesperline = g_width * bytes_per_pixel(g_pixelformat);
if ((ret = ioctl(*fd_v4l, VIDIOC_S_FMT, &fmt)) < 0)
{
printf("set format failed\n");
return ret;
}
return ret;
}
int v4l_capture_test(int fd_v4l)
{
struct v4l2_format fmt;
int fd_still = 0, ret = 0;
char *buf1, *buf2;
char still_file[100] = "./still.uyvy";
int bytes = 0;
if ((fd_still = open(still_file, O_RDWR | O_CREAT | O_TRUNC, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) < 0)
{
printf("Unable to create y frame recording file\n");
return -1;
}
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
if ((ret = ioctl(fd_v4l, VIDIOC_G_FMT, &fmt)) < 0) {
printf("get format failed\n");
goto exit1;
} else {
printf("\t Width = %d\n", fmt.fmt.pix.width);
printf("\t Height = %d\n", fmt.fmt.pix.height);
printf("\t Image size = %d\n", fmt.fmt.pix.sizeimage);
printf("\t Pixel format = %c%c%c%c\n",
(char)(fmt.fmt.pix.pixelformat & 0xFF),
(char)((fmt.fmt.pix.pixelformat & 0xFF00) >> 8),
(char)((fmt.fmt.pix.pixelformat & 0xFF0000) >> 16),
(char)((fmt.fmt.pix.pixelformat & 0xFF000000) >> 24));
}
buf1 = (char *)malloc(fmt.fmt.pix.sizeimage);
buf2 = (char *)malloc(fmt.fmt.pix.sizeimage);
if (!buf1 || !buf2)
goto exit0;
memset(buf1, 0, fmt.fmt.pix.sizeimage);
memset(buf2, 0, fmt.fmt.pix.sizeimage);
if ((bytes = read(fd_v4l, buf1, fmt.fmt.pix.sizeimage)) != fmt.fmt.pix.sizeimage) {
printf("v4l2 read error.\n");
printf("read %d, expected %d.\n",bytes, fmt.fmt.pix.sizeimage);
goto exit0;
}
if ((g_convert == 1) && (g_pixelformat != IPU_PIX_FMT_YUV422P)
&& (g_pixelformat != IPU_PIX_FMT_YUV420P2)) {
fmt_convert(buf2, buf1, &fmt);
if ((write(fd_still, buf2, fmt.fmt.pix.width * fmt.fmt.pix.height * 3 / 2)) < 0)
goto exit0;
}
else
if ((write(fd_still, buf1, fmt.fmt.pix.sizeimage)) < 0)
goto exit0;
exit0:
free(buf1);
free(buf2);
close(fd_v4l);
exit1:
close(fd_still);
return ret;
}
int main(int argc, char **argv)
{
int fd_v4l;
int i;
int ret;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-w") == 0) {
if (argv[++i])
g_width = atoi(argv[i]);
else {
usage();
return -1;
}
}
else if (strcmp(argv[i], "-h") == 0) {
if (argv[++i])
g_height = atoi(argv[i]);
else {
usage();
return -1;
}
}
else if (strcmp(argv[i], "-t") == 0) {
if (argv[++i])
g_top = atoi(argv[i]);
else {
usage();
return -1;
}
}
else if (strcmp(argv[i], "-l") == 0) {
if (argv[++i])
g_left = atoi(argv[i]);
else {
usage();
return -1;
}
}
else if (strcmp(argv[i], "-c") == 0) {
g_convert = 1;
}
else if (strcmp(argv[i], "-m") == 0) {
if (argv[++i])
g_capture_mode = atoi(argv[i]);
else {
usage();
return -1;
}
}
else if (strcmp(argv[i], "-d") == 0) {
strcpy(g_v4l_device, argv[++i]);
}
else if (strcmp(argv[i], "-fr") == 0) {
if (argv[++i])
g_camera_framerate = atoi(argv[i]);
else {
usage();
return -1;
}
}
else if (strcmp(argv[i], "-f") == 0) {
i++;
if (strcmp(argv[i], "NV12") == 0) {
g_pixelformat = IPU_PIX_FMT_NV12;
g_bpp = 12;
}
else if (strcmp(argv[i], "YUV420") == 0) {
g_pixelformat = IPU_PIX_FMT_YUV420P2;
g_bpp = 12;
}
else if (strcmp(argv[i], "YUV422P") == 0) {
g_pixelformat = IPU_PIX_FMT_YUV422P;
g_bpp = 16;
}
else if (strcmp(argv[i], "YUYV") == 0) {
g_pixelformat = IPU_PIX_FMT_YUYV;
g_bpp = 16;
}
else if (strcmp(argv[i], "UYVY") == 0) {
g_pixelformat = IPU_PIX_FMT_UYVY;
g_bpp = 16;
}
else if (strcmp(argv[i], "YUV444") == 0) {
g_pixelformat = IPU_PIX_FMT_YUV444;
g_bpp = 32;
}
else if (strcmp(argv[i], "RGB565") == 0) {
g_pixelformat = IPU_PIX_FMT_RGB565;
g_bpp = 16;
}
else {
printf("Pixel format not supported.\n");
usage();
return -1;
}
}
else {
usage();
return -1;
}
}
ret = v4l_capture_setup(&fd_v4l);
if (ret)
return ret;
ret = v4l_capture_test(fd_v4l);
return ret;
}