当前位置: 首页 > news >正文

基于 FFmpeg 与 V4L2 的多路摄像头视频采集,图像处理处理与 RTMP 推流项目(开源)

在直播、远程监控、视频会议等场景中,实时视频推流是核心需求之一。本文将分享一个基于 Linux 平台的解决方案,通过 V4L2 采集摄像头数据,结合 OpenCV 进行图像处理,最终使用 FFmpeg 编码并通过 RTMP 协议推流至服务器。项目代码模块化程度高,可扩展性强。

(本项目已完成pc平台及rk3566平台测试。)

项目代码已开源,链接:https://github.com/OHMYGODJONY/MultiCam-Realtime-Capture-and-Streaming.

对单个视频流灰度转换后效果:

扩展目标检测算法后检测效果:

一、项目背景与技术选型

1.1 需求场景

  • 实时采集摄像头视频数据(支持多设备)
  • 对视频帧进行自定义处理(如美颜、目标检测)
  • 将处理后的视频编码为 H.264 并通过 RTMP 推流

1.2 技术栈选择

  • V4L2:Linux 下标准的视频设备接口,直接操作硬件设备,支持 DMA 零拷贝,效率高于普通 USB 摄像头库。

v4l2教程:V4L2 使用教程_v4l2-compliance-CSDN博客

  • FFmpeg:强大的音视频处理库,提供编码、格式转换、协议推流等一站式功能。
  • 多线程 + 线程安全队列:实现采集、处理、推流的异步解耦,提升系统吞吐量。

二、整体架构设计

项目采用模块化设计,分为 4 个核心模块,数据流向清晰:

摄像头设备 → CameraCapture(采集) → ThreadSafeQueue(数据传递) → EncoderStreamer(编码推流)↑ImageProcessor(图像处理)
  • 采集模块(CameraCapture):基于 V4L2 实现摄像头初始化、参数配置、帧数据捕获。
  • 处理模块接口(ImageProcessor):提供可扩展的图像处理接口(提供BGR24DE cv::Mat格式数据),支持自定义算法。
  • 编码推流模块(EncoderStreamer):通过 FFmpeg 将视频编码为 H.264 并推流至 RTMP 服务器。
  • 线程安全队列(ThreadSafeQueue):实现采集线程与编码线程的解耦,避免阻塞。

三、开发环境与依赖安装

3.1 环境要求

  • 操作系统:Ubuntu 20.04+
  • 依赖库:
    • FFmpeg(libavformat、libavcodec、libswscale 等)
    • V4L2 开发库(libv4l-dev)
    • OpenCV(libopencv-dev)
    • pthread(线程库)
# 安装FFmpeg
sudo apt-get install libavutil-dev libavcodec-dev libavformat-dev libswscale-dev# 安装V4L2
sudo apt-get install libv4l-dev v4l-utils# 安装OpenCV
sudo apt-get install libopencv-dev# 安装线程库(通常系统已预装)
sudo apt-get install libpthread-stubs0-dev

四、核心模块实现详解

4.1 摄像头采集模块(CameraCapture)

基于 V4L2 实现,核心是通过 IOCTL 命令与设备交互,流程如下:

  • 打开设备与检查能力

    通过open()打开摄像头设备(如/dev/video0),使用VIDIOC_QUERYCAP查询设备是否支持视频捕获和流式 IO。

// 关键代码示例:打开设备并检查能力
fd_ = open(device_path_.c_str(), O_RDWR | O_NONBLOCK, 0);
v4l2_capability cap;
IOCTL_RETRY(fd_, VIDIOC_QUERYCAP, &cap);
if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE)) {// 设备不支持视频捕获
}
  • 设置采集参数

    通过VIDIOC_S_FMT设置分辨率、像素格式(默认 YUYV422),通过VIDIOC_S_PARM设置帧率。

  • 缓冲区管理

    申请 4 个 DMA 缓冲区(VIDIOC_REQBUFS),通过mmap()映射到用户空间,实现零拷贝数据访问。缓冲区通过VIDIOC_QBUF(入队)和VIDIOC_DQBUF(出队)循环使用。

  • 帧采集线程

    启动独立线程循环调用get_frame(),通过select()等待缓冲区就绪,获取帧数据后通过回调函数推送至处理队列。

4.2 图像处理模块(ImageProcessor)

设计为可扩展接口,默认提供空实现,用户可通过继承重写processFrame()实现自定义逻辑:

class ImageProcessor {
public:virtual void processFrame(cv::Mat& mat) {} // 基类空实现
};// 示例:自定义添加水印
class WatermarkProcessor : public ImageProcessor {void processFrame(cv::Mat& mat) override {cv::putText(mat, "Live Stream", cv::Point(10, 30), cv::FONT_HERSHEY_SIMPLEX, 1, cv::Scalar(0, 255, 0), 2);}
};

数据流转:摄像头原始帧(YUYV422)→ 转换为 BGR24(OpenCV 格式)→ 封装成cv::Mat →  调用processFrame()处理 → 转换回 YUV420P(编码所需格式)。

4.3 编码与 RTMP 推流模块(EncoderStreamer)

基于 FFmpeg 实现,核心流程:

  1. 初始化 FFmpeg

    • 调用avformat_network_init()初始化网络模块。
    • 创建输出格式上下文(AVFormatContext),指定 RTMP 地址和格式(flv)。
    • 查找 H.264 编码器(avcodec_find_encoder(AV_CODEC_ID_H264)),配置编码器参数(比特率、帧率、GOP 大小等)。
  2. 格式转换
    使用sws_scale()将图像处理后的 BGR24 格式转换为编码器所需的 YUV420P 格式。

  3. 编码与推流

    • 将转换后的帧通过avcodec_send_frame()送入编码器。
    • 通过avcodec_receive_packet()获取编码后的数据包(AVPacket)。
    • 调整时间戳(PTS)后,通过av_interleaved_write_frame()推流至 RTMP 服务器。
  4. 关键参数优化

    • 编码器参数:preset=ultrafast(快速编码,牺牲部分压缩率)、crf=23(质量控制)。
    • 推流参数:max_delay=0(减少延迟)、stimeout=2000000(2 秒超时)。

4.4 线程安全队列(ThreadSafeQueue)

基于std::mutexstd::condition_variable实现,支持超时机制,用于采集线程与编码线程的异步数据传递:

// 入队(生产者)
bool push(const T& item, int timeout_ms = -1);// 出队(消费者)
bool pop(T& item, int timeout_ms = 50);

通过队列解耦,避免采集线程因编码阻塞而丢帧,同时防止编码线程因无数据而空转。

五、常见问题与解决方案

  1. 摄像头无法打开

    • 检查设备权限:sudo chmod 666 /dev/video0
    • 确认设备存在:v4l2-ctl --list-devices
  2. 格式不支持

    • v4l2-ctl --list-formats-ext查询设备支持的分辨率和格式,调整初始化参数。
  3. 推流延迟高

    • 减少max_delay,降低编码器preset等级(如ultrafast)。
    • 缩小队列大小,避免帧堆积。
  4. 编码失败

    • 检查 FFmpeg 是否编译了 H.264 编码器:ffmpeg -encoders | grep h264
    • 确保输入帧格式为 YUV420P(编码器要求)。

总结

本文实现了从摄像头采集到 RTMP 推流的完整链路,核心在于通过模块化设计和多线程异步处理提升系统效率。V4L2 保证了采集性能,FFmpeg 简化了编码推流流程,而可扩展的图像处理接口为业务定制提供了便利。

 

http://www.dtcms.com/a/315642.html

相关文章:

  • GPU 基础矩阵精规组织教程:从基础作用到实战应用
  • EAGLE-2:通过动态草稿树加速语言模型推理
  • 国内办公安全平台新标杆:iOA一体化办公安全解决方案
  • 用 PyTorch 实现一个简单的神经网络:从数据到预测
  • Tdengine 时序库年月日小时分组汇总问题
  • EP01:【DL 第二弹】张量(Tensor)的创建和常用方法
  • 利用DeepSeek编写带缓冲输出的V语言程序
  • centos通过DockerCompose搭建开源MediaCMS
  • 信息收集--基础篇
  • 高效稳定:Spring Boot集成腾讯云OSS实现大文件分片上传与全路径获取
  • systemui 的启动流程是怎么样的?
  • 深入浅出 RabbitMQ-交换机详解与发布订阅模型实战
  • 软件版本、Nodejs中 ~、*、^
  • centos7 个人网站搭建之gitlab私有化部署实现线上发布
  • 鸿蒙OS 系统安全
  • 14.Linux : nfs与autofs的使用
  • 计算机基础速通--数据结构·栈与队列应用
  • 国内外大模型体验与评测技术
  • 安科瑞智慧能源管理系统在啤酒厂5MW分布式光伏防逆流控制实践
  • 【深度学习新浪潮】混元3D是什么产品?
  • 大模型之后,机器人正在等待它的“GPT-1 时刻”
  • BOM Cookie操作详解
  • 基于Halcon 3D的手眼标定方法
  • Kafka自动消费消息软件(自动化测试Kafka)
  • OneCode 3.0 前端架构全面研究
  • xxl-job配置相同,执行顺序
  • Android WiFi图标显示感叹号解决方法
  • Linux 线程同步与互斥
  • 链表之leetcode19:删除链表的倒数第N个结点
  • LeetCode 71~90题解