前言
前面测试了多种技术路线,本篇补全剩下的2种主流技术,v4l2+sdl2(偏底层),v4l2+QtOpengl(应用),v4l2+ffmpeg+QtQImage(Image的方式转图低于1ms,但是从yuv格式转到rgb格式需要ffmpeg进行转码耗时)。
存在色彩空间不准确,不进行细究。
没有找到命令行,只找到了v4l2-ctl可以查看和控制摄像头的参数。
看gsteamer的源头就是v4l2src,随手写个代码使用v4l2打开摄像头查看延迟,其中v4l2是个框架负责操作和捕获,无法直接进行渲染显示,本次使用了SDL进行显示。
注意:这里不对v4l2介绍,会有专门的专栏去讲解v4l2的多媒体开发,但是这里使用v4l2的代码写个简单的程序来打开。
sudoapt-getinstall libsdl2-dev libsdl2-2.0-0
然后写代码,代码贴在Demo里面
查看内存:
到这里,我们得出结论,gstreamer基本是最优秀的框架之一了,初步测试不是特别严谨,但是基本能反应情况(比如ffmpeg得fmplay本轮测试是最差,但是ffmpeg写代码可以进行ffmpeg源码和编程代码的优化,达到150ms左右,诸如这类情况不考虑)。
V4l2+SDL优于gstreamer优于ffmplayer优于v4l2+QtOpenGL优于cheese优于ffmpeg。
其中v4l2+SDL、gstreamer、fmplayer在内存占用上有点区别,延迟差不多130ms左右。Cheese和v4l2+QtOpenGL延迟差不多
到170ms。Ffmpeg的播放器延迟到500ms左右。
这里要注意,大部分低延迟内窥镜笔者接触的都是buffer叠显存的方式,少数厂家使用v4l2+QtOpenGL的方式,经过测试慢了一帧左右。
#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>#include<errno.h>#include<SDL2/SDL.h>#include<SDL2/SDL_pixels.h>#defineWIDTH640#defineHEIGHT480intmain(){setbuf(stdout,NULL);int fd;structv4l2_format fmt;structv4l2_requestbuffers req;structv4l2_buffer buf;void*buffer_start;unsignedint buffer_length;// 打开摄像头设备 fd =open("/dev/video0", O_RDWR);if(fd==-1){perror("打开摄像头设备失败");return EXIT_FAILURE;}// 设置视频格式 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("设置视频格式失败");close(fd);return EXIT_FAILURE;}// 请求缓冲区 memset(&req,0,sizeof(req)); req.count=1; req.type= V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory= V4L2_MEMORY_MMAP;if(ioctl(fd, VIDIOC_REQBUFS,&req)==-1){perror("请求缓冲区失败");close(fd);return EXIT_FAILURE;}// 映射缓冲区 memset(&buf,0,sizeof(buf)); buf.type= V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory= V4L2_MEMORY_MMAP; buf.index=0;if(ioctl(fd, VIDIOC_QUERYBUF,&buf)