V4L2读取摄像头MJPEG帧后使用C语言JPEG库解压缩保存到本地

  • 摄像头配置
  • 读取一帧
  • 调用libjpeg库解压缩(没有的话可以在gith上下载自己编译)
  • 保存为RGB24图像
  • 下面是内存中摄像头读取的数据直接转存为RGB图片的源码。
  • 输入:图像指针地址,图像长度(两个参数都能由V4L2读取一帧的时候获得)
#include <jpeglib.h> // 记得编译的时候-ljpeg

//convert mjpeg frame to RGB24
int MJPEG2RGB(uint8_t* data_frame, int bytesused)
{
	// variables:

	struct jpeg_decompress_struct cinfo;
	struct jpeg_error_mgr jerr;
	unsigned int width, height;
	// data points to the mjpeg frame received from v4l2.
	unsigned char *data = data_frame;
	size_t data_size =  bytesused;

	// all the pixels after conversion to RGB.
	unsigned char *pixels;// to store RBG 存放RGB结果
	int pixel_size = 0;//size of one pixel
	if ( data == NULL  || data_size <= 0)
	{
		printf("Empty data!\n");
		return -1;
	}
	uint8_t h1 = 0xFF;
	uint8_t h2 = 0xD8;//jpg的头部两个字节

//	if(*(data)!=h1 || *(data+1)==h2)
//	{
//		// error header
//		printf("wrong header %d\n ",cnt);
//		return -2;
//	}
	// ... In the initialization of the program:
	cinfo.err = jpeg_std_error(&jerr);
	jpeg_create_decompress(&cinfo);
	jpeg_mem_src(&cinfo, data, data_size);
	 int rc = jpeg_read_header(&cinfo, TRUE);
	 if(!(1==rc))
	 {
		 printf("Not a jpg frame.\n");
		 return -2;
	 }
	jpeg_start_decompress(&cinfo);
	width = cinfo.output_width;
	height = cinfo.output_height;
	pixel_size = cinfo.output_components;	//3
	int bmp_size = width * height * pixel_size;
	pixels = (unsigned char *)malloc(bmp_size);

	// ... Every frame:

	while (cinfo.output_scanline < cinfo.output_height)
	{
		unsigned char *temp_array[] ={ pixels + (cinfo.output_scanline) * width * pixel_size };
		jpeg_read_scanlines(&cinfo, temp_array, 1);
	}

	jpeg_finish_decompress(&cinfo);
	jpeg_destroy_decompress(&cinfo);

	// Write the decompressed bitmap out to a ppm file, just to make sure
	//保存为PPM6格式(P6	Pixmap	Binary)

 
	char fname[25] = { 0 };        // file name
	if (FMT == V4L2_PIX_FMT_MJPEG)
	{
		sprintf(fname, "output_%d.ppm", cnt);//cnt 是用来计算的全局变量

		char buf[50];		//for header
		rc = sprintf(buf, "P6 %d %d 255\n", width, height);
		FILE *fd = fopen(fname, "w");
		fwrite(buf, rc, 1, fd);
		fwrite(pixels, bmp_size, 1, fd);
		fflush(fd);
		fclose(fd);
	}


 
	free(pixels);// free

	return 0;
}

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是使用v4l2获取mjpeg格式图片C语言代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/mman.h> #include <linux/videodev2.h> #define CAMERA_DEVICE "/dev/video0" #define CAPTURE_FILE "capture.jpeg" #define BUFFER_COUNT 4 struct buffer { void *start; size_t length; }; int main() { int fd; struct v4l2_capability cap; struct v4l2_format fmt; struct v4l2_requestbuffers req; struct v4l2_buffer buf; enum v4l2_buf_type type; struct buffer *buffers; int i, n_buffers; FILE *fp; // 打开摄像头设备 fd = open(CAMERA_DEVICE, O_RDWR); if (fd == -1) { perror("Failed to open camera device"); return EXIT_FAILURE; } // 查询摄像头设备的能力 if (ioctl(fd, VIDIOC_QUERYCAP, &cap) == -1) { perror("Failed to query camera device"); return EXIT_FAILURE; } // 检查是否支持视频捕获 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) { fprintf(stderr, "Camera device does not support video capture\n"); return EXIT_FAILURE; } // 检查是否支持流形式的视频捕获 if (!(cap.capabilities & V4L2_CAP_STREAMING)) { fprintf(stderr, "Camera device does not support streaming\n"); return EXIT_FAILURE; } // 设置摄像头设备的格式 memset(&fmt, 0, sizeof(fmt)); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width = 640; fmt.fmt.pix.height = 480; fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; if (ioctl(fd, VIDIOC_S_FMT, &fmt) == -1) { perror("Failed to set camera device format"); return EXIT_FAILURE; } // 请求摄像头设备的缓冲区 memset(&req, 0, sizeof(req)); req.count = BUFFER_COUNT; req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory = V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_REQBUFS, &req) == -1) { perror("Failed to request camera device buffers"); return EXIT_FAILURE; } // 映射摄像头设备的缓冲区 buffers = calloc(req.count, sizeof(*buffers)); for (i = 0, n_buffers = 0; i < req.count; i++) { memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (ioctl(fd, VIDIOC_QUERYBUF, &buf) == -1) { perror("Failed to query camera device buffer"); return EXIT_FAILURE; } buffers[i].length = buf.length; buffers[i].start = mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset); if (buffers[i].start == MAP_FAILED) { perror("Failed to map camera device buffer"); return EXIT_FAILURE; } n_buffers++; } // 启动摄像头设备的视频流 for (i = 0; i < n_buffers; i++) { memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; buf.index = i; if (ioctl(fd, VIDIOC_QBUF, &buf) == -1) { perror("Failed to enqueue camera device buffer"); return EXIT_FAILURE; } } type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd, VIDIOC_STREAMON, &type) == -1) { perror("Failed to start camera device stream"); return EXIT_FAILURE; } // 从摄像头设备中获取图片 memset(&buf, 0, sizeof(buf)); buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory = V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_DQBUF, &buf) == -1) { perror("Failed to dequeue camera device buffer"); return EXIT_FAILURE; } // 保存图片到文件 fp = fopen(CAPTURE_FILE, "wb"); if (fp == NULL) { perror("Failed to open capture file"); return EXIT_FAILURE; } fwrite(buffers[buf.index].start, buf.bytesused, 1, fp); fclose(fp); // 停止摄像头设备的视频流 type = V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd, VIDIOC_STREAMOFF, &type) == -1) { perror("Failed to stop camera device stream"); return EXIT_FAILURE; } // 释放摄像头设备的缓冲区 for (i = 0; i < n_buffers; i++) { if (munmap(buffers[i].start, buffers[i].length) == -1) { perror("Failed to unmap camera device buffer"); return EXIT_FAILURE; } } free(buffers); // 关闭摄像头设备 if (close(fd) == -1) { perror("Failed to close camera device"); return EXIT_FAILURE; } return EXIT_SUCCESS; } ``` 这段代码使用v4l2调用摄像头设备的API,请求摄像头设备的缓冲区,映射缓冲区,启动视频流,从视频流中获取一张图片保存图片到文件,停止视频流,释放缓冲区,最后关闭摄像头设备。请注意,此代码中的图片格式为MJPEG,如果你需要获取其他格式的图片,需要修改代码中的像素格式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值