(一)V4L2的基本操作套路

 先说的话:像摄像头,RFID,等等一系列需要的驱动进行交互的程序,一般这类程序的基本步骤是一样的,都是由主机发送指令给从机,从机回复信息,由主机处理信息。此类型操作不在基础,而是在于算法上,如何基于驱动程序,安全、快速、高效的处理从机信息才是应该专研的地方,如果没有深入研究过从机返回信息的内容是不容易掌握的。(比如说视频采集,你不清楚视频的存储方式,压缩方式等等,你只会一种套路处理视频采集,而很难优化算法)

#include 

#include "myhead.h"
#include "lcd.h"
#include "jpg.h"

#define CAMERA "/dev/video7"   // 摄像头驱动文件
#define FILED -1
#define BUFFERS_COUNT 4        // 申请缓冲块的块数
#define JPG_NAME "1.txt"       // 临时图存放

// 保存每个缓冲块的大小和映射首地址
struct usrbuf
{
	void *addr;
	int buf_size;
};

bool show_camera(void)
{
	// 1、打开摄像头
	int camera_fd;
	if(FILED == (camera_fd = open(CAMERA, O_RDWR)))
	{
		perror("打开摄像头失败: ");
		return false;
	}

	// 开始设置摄像头属性
	// 2、设置摄像头采集通道
	int index = 0;
	if (FILED == ioctl(camera_fd, VIDIOC_S_INPUT, &index))
	{
		perror("摄像头采集通道设置失败: ");
		return false;
	}

	// 3、获取摄像头采集格式
	struct v4l2_format fmt;
	bzero(&fmt, sizeof (fmt));
	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	if (FILED == ioctl(camera_fd, VIDIOC_G_FMT, &fmt))
	{
		perror("获取摄像头采集格式失败: ");
		return false;
	}
	printf("摄像头采集画面的高是: %d  宽是: %d\n",
		fmt.fmt.pix.height, fmt.fmt.pix.width);
	// 默认采集 jpeg 图片
	if (fmt.fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
	       printf("摄像头采集的是jpeg图片!\n");

	// 4、申请缓冲块
	struct v4l2_requestbuffers buffers;
	bzero(&buffers, sizeof (buffers));
	buffers.count = BUFFERS_COUNT;
	buffers.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	buffers.memory = V4L2_MEMORY_MMAP;
	if (FILED == ioctl(camera_fd, VIDIOC_REQBUFS, &buffers))
	{
		perror("申请缓冲块失败: ");
		return false;
	}	


	// 5、准备结构体来具体化缓冲内存
	struct usrbuf *usr_buffers = calloc(BUFFERS_COUNT, sizeof (*usr_buffers));

	// 6、分配缓冲块并映射内存
	int i = 0;
	for (i = 0; i < BUFFERS_COUNT; i++)
	{
		struct v4l2_buffer sbuf;
		bzero(&sbuf, sizeof (sbuf));
		sbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
		sbuf.memory = V4L2_MEMORY_MMAP;
		sbuf.index = i;
		if (FILED == ioctl(camera_fd, VIDIOC_QUERYBUF, &sbuf))
		{
			perror("分配缓冲块失败: ");
			return false;
		}
		usr_buffers[i].buf_size = sbuf.length;
		usr_buffers[i].addr = mmap(NULL, sbuf.length, PROT_READ|PROT_WRITE,
				MAP_SHARED, camera_fd, sbuf.m.offset);

		// 画面入队,放入缓存内存块
		if (FILED == ioctl(camera_fd, VIDIOC_QBUF, &sbuf))
		{
			perror("画面入队失败: ");
			return false;
		}
		
	}
	// 7、开始使用摄像头采集数据
	enum v4l2_buf_type type;
	type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
	if (FILED == ioctl(camera_fd, VIDIOC_STREAMON, &type))
	{
		perror("开始摄像头采集失败: ");
		return false;
	}
	// 8、循环显示视频流
	
	struct v4l2_buffer out_buf;
	int jpg_fd;

	lcd_info *testlcd;
	bool bzero_lcd = BZERO_LCD;
	testlcd = init_lcd(bzero_lcd);

	while (1)
	{
		for (i = 0; i < BUFFERS_COUNT; i++)
		{
			bzero(&out_buf, sizeof (out_buf));
			out_buf.type   = V4L2_BUF_TYPE_VIDEO_CAPTURE;
			out_buf.memory = V4L2_MEMORY_MMAP;
			out_buf.index  = i;
			if (FILED == ioctl(camera_fd, VIDIOC_DQBUF, &out_buf))
			{
				perror("图像出队失败: ");
  				return false;
			}

			if(FILED == (jpg_fd = open(JPG_NAME, O_RDWR|O_CREAT|O_TRUNC, 0777)))
			{
				perror("打开jpg图片失败: ");
				return false;
			}

			write(jpg_fd, usr_buffers[i].addr, usr_buffers[i].buf_size);
			close(jpg_fd);

			// lcd 显示图片
			display(JPG_NAME, testlcd->fbmem, &testlcd->vinfo, 0, 0);
			
			// 入队
			if (FILED == ioctl(camera_fd, VIDIOC_QBUF, &out_buf))
			{
				perror("入队失败: ");
				return false;
			}
		
		}
	
	}

}



int main(int argc, char **argv)
{

	if (show_camera() == false)
	{
		printf("摄像头出现问题\n");
		return 0;
	
	}
	return 0;
}

 

你可能感兴趣的:(音视频)