391 lines
13 KiB
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;
|
|
}
|