uvc camera linux v4l2运行死机原因解析及解决办法

1、根据测试发现,linux uvc容错性很差,一旦出现视频流错误,恢复正常的可能性很小。要解决此问题,务必提升上位机接收能力,减小因接受速度慢导致的下层缓存溢出出错,而间接导致linux uvc出错而无法恢复正常。

2、解决办法如下:(1)提升上位机缓存能力,由于v4l2的机制是通过帧缓冲队列存储uvc驱动接收的图像,camera属于固定速率产生图像,所以帧缓冲空间务必要大。以免线程卡顿导致缓存很快溢出,导致摄像头数据发送不上来而阻塞,代码改动如下:

(2)避免在图像接收函数中的耗时处理,最好从帧缓存队列接完图像尽快把内存释放掉,可以把接到的图像迅速copy放入一个缓存的空间中,在别的线程里面处理,处理不过来可以扔掉,这样图像接收线程可以以最快的速度接收图像。代码要求:



参考代码
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <linux/videodev2.h>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>

#include <iostream>
using namespace std;
using namespace cv;

#define CAMERA	"/dev/video0"
#define CAPTURE_FILE	"frame.yuv"

#define BUFFER_COUNT 20

typedef struct __video_buffer
{
	void *start;
	size_t length;

}video_buf_t;

int width = 752;
int height = 480;

static int fd;

bool v4l2_init();
bool v4l2_start();
void v4l2_cvshow();

video_buf_t *framebuf;

int main(int argc, char *argv[])
{
	v4l2_init();
	v4l2_start();
	v4l2_cvshow();
	printf("error oucured and qiut!!!!!!!!\n");
	//while(1);
	close(fd);
	return 0;
}


bool v4l2_init()
{
	if((fd = open(CAMERA,O_RDWR)) == -1)
	{
		perror("Camera open failed!\n");
		return false;
	}

	//query camera capabilities
	struct v4l2_capability cap;

	if(ioctl(fd,VIDIOC_QUERYCAP,&cap) == -1)
	{
		perror("VIDIOC_QUERYCAP failed!\n");
		return false;
	}

    printf("Capability Informations:\n");
    printf(" driver: %s\n", cap.driver);
    printf(" card: %s\n", cap.card);
    printf(" bus_info: %s\n", cap.bus_info);
    printf(" version: %08X\n", cap.version);
    printf(" capabilities: %08X\n", cap.capabilities);
 

    //set format
    struct v4l2_format fmt;
    memset(&fmt,0,sizeof(fmt));

    fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
    fmt.fmt.pix.width = width;
    fmt.fmt.pix.height = height;
    fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
    fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;

    if(ioctl(fd,VIDIOC_S_FMT,&fmt) == -1)
    {
    	perror("VIDIOC_S_FMT failed!\n");
    	return false;
    }

    //get format
    if(ioctl(fd,VIDIOC_G_FMT,&fmt) == -1)
    {
    	perror("VIDIOC_G_FMT failed!\n");
    	return false;
    }
    printf("Stream Format Informations:\n");
    printf(" type: %d\n", fmt.type);
    printf(" width: %d\n", fmt.fmt.pix.width);
    printf(" height: %d\n", fmt.fmt.pix.height);
    char fmtstr[8];
    memset(fmtstr, 0, 8);
    memcpy(fmtstr, &fmt.fmt.pix.pixelformat, 4);
    printf(" pixelformat: %s\n", fmtstr);
    printf(" field: %d\n", fmt.fmt.pix.field);
    printf(" bytesperline: %d\n", fmt.fmt.pix.bytesperline);
    printf(" sizeimage: %d\n", fmt.fmt.pix.sizeimage);
    printf(" colorspace: %d\n", fmt.fmt.pix.colorspace);
    printf(" priv: %d\n", fmt.fmt.pix.priv);
    printf(" raw_date: %s\n", fmt.fmt.raw_data);

    return true;
}

bool v4l2_start()
{
	//request memory allocation
	struct v4l2_requestbuffers reqbuf;
	reqbuf.count = BUFFER_COUNT;
	reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	reqbuf.memory = V4L2_MEMORY_MMAP;

	if(ioctl(fd,VIDIOC_REQBUFS,&reqbuf) == -1)
	{
		perror("VIDIOC_REQBUFS failed!\n");
		return false;
	}

	framebuf = (video_buf_t *)calloc(reqbuf.count,sizeof(video_buf_t));
	struct v4l2_buffer buf;

	for(int i = 0;i < reqbuf.count;i ++)
	{
		buf.index = i;
		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory = V4L2_MEMORY_MMAP;
		if(ioctl(fd,VIDIOC_QUERYBUF,&buf) == -1)
		{
			perror("VIDIOC_QUERYBUF failed!\n");
			return false;
		}

		//mmap buffer
		framebuf[i].length = buf.length;
		framebuf[i].start = mmap(NULL,buf.length,
			PROT_READ | PROT_WRITE,
			MAP_SHARED,fd,buf.m.offset);
		if(framebuf[i].start == MAP_FAILED)
		{
			perror("mmap failed!\n");
			return false;
		}
		//buffer queue
		if(ioctl(fd,VIDIOC_QBUF,&buf) == -1)
		{
			perror("VIDIOC_QBUF failed!\n");
			return false;
		}
	}
	//start camera capture
	enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	if(ioctl(fd,VIDIOC_STREAMON,&type) == -1)
	{
		perror("VIDIOC_STREAMON failed!\n");
		return false;
	}

	return true;
}

void v4l2_cvshow()
{
	bool quit = false;
	struct v4l2_buffer buf;
	CvMat cvmat;
	IplImage* image;
	int retry = 0;

	while(!quit)
	{
		buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		buf.memory = V4L2_MEMORY_MMAP;
		if(ioctl(fd,VIDIOC_DQBUF,&buf) == -1)
		{
			perror("VIDIOC_DQBUF failed!\n");
			usleep(10000);
			retry ++;
			if(retry > 100)
				quit = true;
			continue;
		}
		if(buf.bytesused != 721920){
		printf("videosize=%d\n",buf.bytesused);
		}else{
		// Mat img(height,width,CV_8UC3,framebuf[buf.index].start);
		// imshow("Image",img);
		
		//cvmat = cvMat(height,width,CV_8UC2,framebuf[buf.index].start);
		//image = cvDecodeImage(&cvmat,1);
		//cvShowImage("Image",image);
		//cvReleaseImage(&image);
		}		
		
		if(ioctl(fd,VIDIOC_QBUF,&buf) == -1)
		{
			perror("VIDIOC_QBUF failed!\n");
			continue;
		}
		waitKey(10);
	}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值