核心内容摘要
Seedance 2.0 不只是“双分支”——它是扩散模型架构演进的第4个奇点?看20年CV架构师如何拆解其拓扑不变性设计
linux嵌入式视频流加速接入V4L2 自动驾驶边缘端设备或者服务器往往需要同步接入至少4路环视摄像头更甚者需要接入12路摄像头倘若单纯调用opencv集成的视频流读入代码面对多路的摄像头的庞大视频流数据是无法满足高帧率的视频接入的因此需要专门的不依赖第三方库的视频流接入代码提供高速的视频流接入服务。
提供工程级MJPEG及YUYV视频流读入编解码代码其中MJPEG的表现更是达到单帧30微秒左右。
需要的朋友可以直接将代码改写成多线程调用多路摄像头绝对会给您带来惊喜。
在自动驾驶边缘端设备以及服务器领域对摄像头视频流的高效处理至关重要。
想象一下自动驾驶汽车需要实时感知周围环境往往至少需要同步接入4路环视摄像头有些更复杂的场景甚至要接入12路摄像头。
如果只是简单地调用OpenCV集成的视频流读入代码面对如此庞大的多路摄像头视频流数据想要实现高帧率的视频接入简直是天方夜谭。
这时候就迫切需要专门的、不依赖第三方库的视频流接入代码来提供高速的视频流接入服务而Linux嵌入式视频流加速接入V4L2就是解决方案之一。
为何不用OpenCV先来看一段简单的OpenCV读视频流代码示例import cv2 cap cv
VideoCapture(
while True: ret, frame cap.read() if not ret: break cv
imshow(Video Stream, frame) if cv
waitKey(
0xFF ord(q): break cap.release() cv
destroyAllWindows()这段代码能读取单路摄像头视频流并展示。
然而当扩展到多路摄像头随着摄像头数量增多数据量呈指数级增长OpenCV的处理效率会大幅下降无法满足高帧率要求。
V4L2的优势与实现V4L2Video for Linux Two是Linux下用于视频设备的内核驱动框架它提供了底层的硬件访问接口能够更高效地处理视频流。
下面是一个简单的V4L2 MJPEG视频流读入代码示例以C语言为例#include stdio.h #include stdlib.h #include fcntl.h #include sys/mman.h #include linux/videodev
h #include unistd.h #define WIDTH 640 #define HEIGHT 480 #define BUFFER_COUNT 4 int main() { int fd; struct v4l2_capability cap; struct v4l2_format fmt; struct v4l2_requestbuffers req; void *buffers[BUFFER_COUNT]; size_t buffer_sizes[BUFFER_COUNT]; // 打开设备文件 fd open(/dev/video0, O_RDWR); if (fd
{ perror(open); return 1; } // 获取设备能力 if (ioctl(fd, VIDIOC_QUERYCAP, cap)
{ perror(VIDIOC_QUERYCAP); close(fd); return 1; } // 设置视频格式 fmt.type V4L2_BUF_TYPE_VIDEO_CAPTURE; fmt.fmt.pix.width WIDTH; fmt.fmt.pix.height HEIGHT; fmt.fmt.pix.pixelformat V4L2_PIX_FMT_MJPEG; fmt.fmt.pix.field V4L2_FIELD_INTERLACED; if (ioctl(fd, VIDIOC_S_FMT, fmt)
{ perror(VIDIOC_S_FMT); close(fd); return 1; } // 请求缓冲区 req.count BUFFER_COUNT; req.type V4L2_BUF_TYPE_VIDEO_CAPTURE; req.memory V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_REQBUFS, req)
{ perror(VIDIOC_REQBUFS); close(fd); return 1; } // 映射缓冲区 for (int i 0; i req.count; i) { struct v4l2_buffer buf; buf.type V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory V4L2_MEMORY_MMAP; buf.index i; if (ioctl(fd, VIDIOC_QUERYBUF, buf)
{ perror(VIDIOC_QUERYBUF); close(fd); return 1; } buffers[i] mmap(NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, fd, buf.m.offset); buffer_sizes[i] buf.length; } // 开启视频流捕获 enum v4l2_buf_type type V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd, VIDIOC_STREAMON, type)
{ perror(VIDIOC_STREAMON); close(fd); return 1; } // 循环读取视频帧 for (int i 0; i 100; i) { struct v4l2_buffer buf; buf.type V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_DQBUF, buf)
{ perror(VIDIOC_DQBUF); close(fd); return 1; } // 这里可以对读取到的帧数据进行处理例如解码MJPEG // 处理完后将缓冲区重新入队 if (ioctl(fd, VIDIOC_QBUF, buf)
{ perror(VIDIOC_QBUF); close(fd); return 1; } } // 停止视频流捕获 type V4L2_BUF_TYPE_VIDEO_CAPTURE; if (ioctl(fd, VIDIOC_STREAMOFF, type)
{ perror(VIDIOC_STREAMOFF); close(fd); return 1; } // 解除映射并关闭设备 for (int i 0; i req.count; i) { if (munmap(buffers[i], buffer_sizes[i])
{ perror(munmap); close(fd); return 1; } } close(fd); return 0; }这段代码实现了基本的MJPEG视频流读入。
首先打开视频设备文件查询设备能力接着设置视频格式为MJPEG请求并映射缓冲区。
之后开启视频流捕获循环读取视频帧并处理最后停止捕获解除缓冲区映射并关闭设备。
MJPEG及YUYV视频流编解码我们不仅提供了MJPEG视频流读入代码还包含YUYV视频流读入编解码代码。
MJPEG在性能上表现尤为出色单帧处理时间能达到30微秒左右。
如此高的效率得益于V4L2对底层硬件的直接访问和优化。
多线程调用多路摄像头对于需要接入多路摄像头的场景只需将上述代码改写成多线程调用即可。
例如利用POSIX线程库pthread#include pthread.h #include stdio.h #include stdlib.h #include fcntl.h #include sys/mman.h #include linux/videodev
h #include unistd.h #define WIDTH 640 #define HEIGHT 480 #define BUFFER_COUNT 4 #define CAMERA_COUNT 4 typedef struct { int camera_index; } CameraArgs; void* read_camera(void* args) { CameraArgs* cam_args (CameraArgs*)args; int fd; char device_path[20]; snprintf(device_path, sizeof(device_path), /dev/video%d, cam_args-camera_index); // 后续打开设备、设置格式、请求缓冲区等操作与单路摄像头代码类似 // 这里省略重复代码 // 循环读取视频帧 for (int i 0; i 100; i) { struct v4l2_buffer buf; buf.type V4L2_BUF_TYPE_VIDEO_CAPTURE; buf.memory V4L2_MEMORY_MMAP; if (ioctl(fd, VIDIOC_DQBUF, buf)
{ perror(VIDIOC_DQBUF); close(fd); pthread_exit(NULL); } // 处理帧数据 if (ioctl(fd, VIDIOC_QBUF, buf)
{ perror(VIDIOC_QBUF); close(fd); pthread_exit(NULL); } } // 停止视频流捕获、解除映射并关闭设备 pthread_exit(NULL); } int main() { pthread_t threads[CAMERA_COUNT]; CameraArgs args[CAMERA_COUNT]; for (int i 0; i CAMERA_COUNT; i) { args[i].camera_index i; if (pthread_create(threads[i], NULL, read_camera, args[i])!
{ perror(pthread_create); return 1; } } for (int i 0; i CAMERA_COUNT; i) { if (pthread_join(threads[i], NULL)!
{ perror(pthread_join); return 1; } } return 0; }这段代码创建了多个线程每个线程负责读取一路摄像头的视频流通过这种方式可以高效地实现多路摄像头的视频接入极大提升系统整体的视频处理能力。
linux嵌入式视频流加速接入V4L2 自动驾驶边缘端设备或者服务器往往需要同步接入至少4路环视摄像头更甚者需要接入12路摄像头倘若单纯调用opencv集成的视频流读入代码面对多路的摄像头的庞大视频流数据是无法满足高帧率的视频接入的因此需要专门的不依赖第三方库的视频流接入代码提供高速的视频流接入服务。
提供工程级MJPEG及YUYV视频流读入编解码代码其中MJPEG的表现更是达到单帧30微秒左右。
需要的朋友可以直接将代码改写成多线程调用多路摄像头绝对会给您带来惊喜。
总之在自动驾驶等对视频流处理要求极高的领域通过Linux嵌入式视频流加速接入V4L2配合MJPEG及YUYV视频流编解码代码并采用多线程调用多路摄像头的方式能够有效突破帧率瓶颈满足实际应用需求。
希望这些代码和思路能给需要的朋友带来帮助祝大家在开发中一切顺利