[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