[linux]uvc摄像头调试

uvc摄像头调试

改分辨率:
源码中
v412fmt.fmt.pix.width 图像宽度
v412fmt.fmt.pix.height 图像高度

/*
 * capturing from UVC
 * platform: rk3568
 */
 
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <asm/types.h>
#include <linux/videodev2.h>
#include <errno.h> 
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
 
#include <jpeglib.h>

#define FILENAME_DEFAULT "/mnt/holdenhuang/image/output"
#define IP_DEFAULT "172.16.31.208"

int imag_w = 0;
int imag_h = 0;
int *video_buff[4];
__u32   format;

void helper(char *sPrgNm)
{
    printf("\nUsage : %s [-d <device>] [-f <format>] [-n <number>] [-help] etc.\n", sPrgNm);
    printf("-d <device>        -- /dev/video9 to switch uvc\n");
    printf("-n <framenum>      -- buffer frame, default as [30]\n");
    printf("-f <format>        -- support list as [0-1], 0: mjpeg, 1: yuyv\n    \
               -- <v4l2-ctl  --list-formats -d /dev/video> can view the supported formats\r\n");
    printf("  -i <ipaddr>        -- set udp receive ip\n");
}

static void _save_stream_to_file(unsigned char *buffer, int size, char *outname)
{
	FILE *fp = NULL;

	fp = fopen(outname, "wb");
	if (!fp) {
		printf("save file error..\n");
		return;
	}
	fwrite(buffer, size, 1, fp);
	fflush(fp);
	if (fp) fclose(fp);
}

/*摄像头初始化*/
int Camera_Init(char *dev)
{
    int i=0;
    /*1.打开摄像头设备*/
    int fd=open(dev, 2);
    if(fd<0)
		return -1;//摄像头打开失败
	
    /*2.设置摄像头捕获格式*/
    struct v4l2_format v4l2fmt;
    memset(&v4l2fmt, 0, sizeof(v4l2fmt));//初始化结构体
    v4l2fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频捕获格式
    v4l2fmt.fmt.pix.width = 1920;//图像宽度
    v4l2fmt.fmt.pix.height = 1080;//图像高度
    v4l2fmt.fmt.pix.pixelformat = format;//V4L2_PIX_FMT_MJPEG;//YUYV颜色编码格式
    if(ioctl(fd,VIDIOC_S_FMT, &v4l2fmt))
		return -2;//设置格式失败
    printf("采集图像大小:%d*%d\n",v4l2fmt.fmt.pix.width, v4l2fmt.fmt.pix.height);
    imag_w = v4l2fmt.fmt.pix.width;
    imag_h = v4l2fmt.fmt.pix.height;
	
    /*3.申请缓冲区*/
    struct v4l2_requestbuffers v4l2reqbuf;
    memset(&v4l2reqbuf, 0, sizeof(v4l2reqbuf));//初始化结构体
    v4l2reqbuf.count = 4;//申请的缓冲区个数
    v4l2reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频捕获格式
    v4l2reqbuf.memory = V4L2_MEMORY_MMAP;//内存映射
    if(ioctl(fd, VIDIOC_REQBUFS, &v4l2reqbuf))
		return -3;//申请缓冲区失败
    printf("申请的缓冲区个数:%d\n", v4l2reqbuf.count);
	
    /*4.将缓冲区映射到进程空间*/
    struct v4l2_buffer v4l2buf;
    memset(&v4l2buf, 0, sizeof(v4l2buf));//初始化结构体
    v4l2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频捕获格式
    v4l2buf.memory = V4L2_MEMORY_MMAP;//内存映射
    for(i = 0; i < v4l2reqbuf.count; i++)
    {
        v4l2buf.index = i;/*缓冲区下标*/
        if(ioctl(fd, VIDIOC_QUERYBUF, &v4l2buf))
			return -4;//申请缓冲区失败
		video_buff[i] = mmap(NULL, v4l2buf.length, PROT_READ|PROT_WRITE, MAP_SHARED, fd, v4l2buf.m.offset);
        printf("video_buff[%d]=%p, len = %d\n", i, video_buff[i], v4l2buf.length);
    }
	
    /*5.将映射的空间添加到采集队列*/
    memset(&v4l2buf, 0, sizeof(v4l2buf));//初始化结构体
    v4l2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频捕获格式
    v4l2buf.memory = V4L2_MEMORY_MMAP;//内存映射
    for(i = 0; i < v4l2reqbuf.count; i++)
    {
        v4l2buf.index = i;/*缓冲区下标*/
        if(ioctl(fd, VIDIOC_QBUF, &v4l2buf))
			return -5;//添加到采集队列失败
    }
	
    /*6.开启摄像头*/
    int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频捕获格式
    if(ioctl(fd, VIDIOC_STREAMON, &type))
		return -6;//启动摄像头失败
    return fd;//成功返回摄像头文件描述符
}

/*YUYV转RGB888*/
void yuv_to_rgb(unsigned char *yuv_buffer, unsigned char *rgb_buffer, int iWidth, int iHeight)
{
  int x;
  int z = 0;
  unsigned char *ptr = rgb_buffer;
  unsigned char *yuyv = yuv_buffer;
  for (x = 0; x < iWidth * iHeight; x++)
  {
    int r, g, b;
    int y, u, v;
    if (!z)
    y = yuyv[0] << 8;
    else
    y = yuyv[2] << 8;
    u = yuyv[1] - 128;
    v = yuyv[3] - 128;
    r = (y + (359 * v)) >> 8;
    g = (y - (88 * u) - (183 * v)) >> 8;
    b = (y + (454 * u)) >> 8;
    *(ptr++) = (b > 255) ? 255 : ((b < 0) ? 0 : b);
    *(ptr++) = (g > 255) ? 255 : ((g < 0) ? 0 : g);
    *(ptr++) = (r > 255) ? 255 : ((r < 0) ? 0 : r);
    if(z++)
    {
      z = 0;
      yuyv += 4;
    }
  }
}

int main(int argc, char **argv)
{
	int ret = -1;
	int count = 30;
	char filename[64];
	int fd = -1;
    struct timeval tv_begin, tv_end;
    int capture = 0;
    char *dev_path;
    int para = 0;
    int input_format = 0;
    int i = 0;
    char name[4];
    char *ip_addr = IP_DEFAULT;

    if(argc < 5){
        helper(argv[0]);
        return -1;
    }
    
    for(int j =0; j < argc; j++){
        if(strstr(argv[j], "help")){
            helper(argv[0]);
            return -1;
        }
    }

    while ((para = getopt(argc, argv, "d:n:f:i:help::")) != -1) {
        switch(para) {
        case 'd':
            dev_path = optarg;
            break;
        case 'f':
            input_format = atoi(optarg);
            if(input_format == 0){
                format = V4L2_PIX_FMT_MJPEG;
                snprintf(name, sizeof(name), "%s", "jpg");
            }
            if(input_format == 1){
                format = V4L2_PIX_FMT_YUYV;
                snprintf(name, sizeof(name), "%s", "yuv");
            }
            break;
        case 'n':
            count = atoi(optarg);
            printf("getframe num: %d\r\n", count);
            break;
        case 'i':
                ip_addr = optarg;
                break;
        default:
            break;
        }   

    }
    //printf("V4L2_PIX_FMT_MJPEG = %d\r\n", format);

	fd=Camera_Init(dev_path);
	if(fd<0){
		printf("初始化摄像头失败,res=%d\n",fd);
		return 0;
	}
	printf("初始化摄像头成功\n");
	struct v4l2_buffer v4l2buf;
	memset(&v4l2buf, 0, sizeof(v4l2buf));//初始化结构体
	v4l2buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;//视频捕获格式
	v4l2buf.memory = V4L2_MEMORY_MMAP;//内存映射
/*
    int sockfd;
    struct sockaddr_in dest_addr;
    dest_addr.sin_family = AF_INET; //使用IPV4
    dest_addr.sin_port = htons(8099);//服务器端口号
    dest_addr.sin_addr.s_addr = inet_addr(ip_addr);//适用于局域网通信
    sockfd = socket(AF_INET,SOCK_DGRAM,0);//创建TCP,指定ip类型为IPV4
    if(sockfd < 0){
            printf("socket create fail!\r\n");
            return -1;
    }
    int optval =  1920 * 1080;
    int optlen = sizeof(optval);
    int sendbuff = 0;
    setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char*)&optval,optlen);
    getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &sendbuff, &optlen);
	printf("send buffer size = %d\n", sendbuff);
    printf("sockfd = %d ip = %s \r\n", sockfd, ip_addr);
*/
    char *sensor_srcbuf;
    sensor_srcbuf = malloc(1920 * 1080 * 2);

	while(i < count){
        gettimeofday(&tv_begin, NULL);
        /*从采集队列中取出图像数据*/
		if(ioctl(fd, VIDIOC_DQBUF, &v4l2buf)) break;//取数据失败

		//printf("v4l2buff[%d]=%p\n, len = %d\r\n",v4l2buf.index, video_buff[v4l2buf.index], v4l2buf.length);
		/*将头数据和位图数据写入到文件中*/
        gettimeofday(&tv_end, NULL);
        printf("> capture frame timecost %lums\n", (((tv_end.tv_sec*1000 + tv_end.tv_usec/1000)) - (tv_begin.tv_sec*1000 + tv_begin.tv_usec/1000)));
		snprintf(filename,sizeof(filename),"%s-%d.%s", FILENAME_DEFAULT, i, name);//图片名字
		memcpy(sensor_srcbuf, video_buff[v4l2buf.index], v4l2buf.length);
        //printf("filename = %s, ret = %d\n", filename, ret);
        _save_stream_to_file((unsigned char *)sensor_srcbuf, v4l2buf.length, filename);
		if(ioctl(fd, VIDIOC_QBUF, &v4l2buf)) break;//添加到采集队列失败
		i++;
	}
    //if(sockfd) close(sockfd);
	if(fd) close(fd);//关闭摄像头
}



运行指令

v4l2-ctl --list-formats-ext -d /dev/video9
posted @ 2023-03-18 15:38  dysonnnn  阅读(356)  评论(0编辑  收藏  举报