概念
Linux 的虚拟相机机制(Virtual Camera)是一种通过软件模拟出一个摄像头设备的方式,常用于以下场景:
- 视频源模拟(测试用途):没有真实摄像头也能调试视频相关应用;
- 视频流重定向:把本地视频文件、网络流等伪装成摄像头供应用读取;
- 特效或 AI 处理:在采集后先用程序处理,再虚拟成摄像头给其他软件使用。
下载 v4l2loopback 源码
https://github.com/v4l2loopback/v4l2loopback
v4l2loopback$ tree
.
├── AUTHORS
├── ChangeLog
├── COPYING
├── currentversion.sh
├── dkms.conf
├── doc
│ ├── docs.txt
│ ├── kernel_debugging.txt
│ ├── makeformats.sh
│ ├── missingformats.h # 内核级调试说明,建议在调试初始化失败时查看
│ └── v4l2_formats.txt # 支持的视频格式说明
├── examples # 示例代码目录,包含如何使用虚拟设备进行图像写入
│ ├── Makefile
│ ├── ondemandcam.c
│ ├── README
│ ├── restarting-writer.sh
│ ├── test.c
│ ├── yuv420_infiniteloop.c
│ └── yuv4mpeg_to_v4l2.c
├── Kbuild
├── Makefile
├── Makefile.manual
├── man
├── NEWS
├── README.md
├── release.sh
├── SECURITY.md
├── tests # 自动测试脚本和测试程序,用于验证模块功能
│ ├── checkformat.sh
│ ├── common.h
│ ├── consumer.c
│ ├── interlaced_w
│ ├── Makefile
│ ├── producer.c
│ └── test_dqbuf.c
├── TODO
├── udev # 包含 udev 规则(用于自动命名 /dev/video*)
│ └── 60-persistent-v4l2loopback.rules
├── utils # 用于动态修改 loopback 设备参数(如分辨率、支持格式等)的工具程序源码。
│ ├── Makefile
│ └── v4l2loopback-ctl.c
├── v4l2loopback.c # ✅ 核心驱动源码(主 .ko 编译对象)
├── v4l2loopback_formats.h # 视频格式定义
├── v4l2loopback.h # ✅ 用于编译内核模块的主 Makefile
└── vagrant
├── README.md
├── Vagrantfile
└── vbox-restart
移植到T113-S3 linux kernel-5.4
t113_linux/kernel/linux-5.4/drivers/media/v4l2loopback$ tree
.
├── Kconfig
├── Makefile
├── v4l2loopback.c
├── v4l2loopback_formats.h
└── v4l2loopback.h
Kconfig
config VIDEO_V4L2LOOPBACK
tristate "Virtual video loopback device"
depends on VIDEO_DEV && MEDIA_CONTROLLER
help
This is a virtual video driver that allows user-space programs
to feed video data to video4linux devices.
Say Y here to include support for v4l2loopback.
Makefile
obj-y += v4l2loopback.o
编译
t113_linux/kernel/linux-5.4/drivers/media/Kconfig
source "drivers/media/v4l2loopback/Kconfig"
t113_linux/kernel/linux-5.4/drivers/media/Makefile
obj-y += v4l2loopback/
/dev/video0
内核添加v4l2loopback驱动后,自动生成了/dev/video0节点
v4l2-ctl –all -d /dev/video0
buildroot 添加 v4l2loopback-ctl
t113_linux/buildroot/buildroot-201902/configs/sun8iw20p1_t113_defconfig
BR2_PACKAGE_V4L2LOOPBACK_CTL=y
添加的源码
t113_linux/buildroot/buildroot-201902/package/v4l2loopback-ctl$ tree
.
├── Config.in
├── v4l2loopback-ctl.c
├── v4l2loopback-ctl.mk
├── v4l2loopback_formats.h
└── v4l2loopback.h
编译脚本
################################################################################
#
# v4l2loopback-ctl (local version)
#
################################################################################
V4L2LOOPBACK_CTL_VERSION = v0.14.0
V4L2LOOPBACK_CTL_SITE = $(TOPDIR)/package/v4l2loopback-ctl
V4L2LOOPBACK_CTL_SITE_METHOD = local
define V4L2LOOPBACK_CTL_BUILD_CMDS
$(TARGET_CC) $(TARGET_CFLAGS) \
-I$(TOPDIR)/package/v4l2loopback-ctl \
-o $(@D)/v4l2loopback-ctl $(TOPDIR)/package/v4l2loopback-ctl/v4l2loopback-ctl.c
endef
define V4L2LOOPBACK_CTL_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(@D)/v4l2loopback-ctl $(TARGET_DIR)/usr/bin/v4l2loopback-ctl
endef
$(eval $(generic-package))
v4l2loopback-ctl 和 v4l2-ctl
- v4l2-ctl:用于与实际的硬件摄像头(或者视频捕捉设备)进行交互,操作摄像头的参数。
- v4l2loopback-ctl:用于与虚拟摄像头设备交互,通常与 v4l2loopback 驱动一起使用,用于创建和管理虚拟视频设备。
sh-4.4# v4l2loopback-ctl list
OUTPUT CAPTURE NAME
/dev/video0 /dev/video0 Dummy video device (0x0000)
v4l2loopback-ctl常用命令
命令 | 参数说明 | 功能描述 |
---|---|---|
add |
[OPTIONS] [<outputdevice> [<capturedevice>]] |
添加新的 v4l2loopback 虚拟设备 |
delete |
<device> |
删除指定的虚拟设备 |
list |
[OPTIONS] |
列出当前所有 v4l2loopback 虚拟设备 |
query |
<device> |
查询设备的当前配置与能力 |
set-fps |
<device> <fps> |
设置指定设备的帧率 |
get-fps |
<device> |
获取指定设备的帧率 |
set-caps |
<device> <caps> |
设置视频格式能力(如分辨率、帧率) |
get-caps |
<device> |
获取当前设置的视频格式能力 |
set-timeout-image |
[OPTIONS] <device> <image> |
设置在无输入帧时显示的占位图像 |
测试demo
对开源项目做如下修改
添加lib/libjpeg.so 和 jpeglib.h 文件, 从T113-S3源码out目录中提取
diff --git a/camera_demo.pro b/camera_demo.pro
index 14fdae1..7cad2a6 100644
--- a/camera_demo.pro
+++ b/camera_demo.pro
@@ -16,7 +16,7 @@ DEFINES += QT_DEPRECATED_WARNINGS
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
-unix:LIBS += /usr/lib/x86_64-linux-gnu/libjpeg.so
+unix:LIBS += $$PWD/lib/libjpeg.so
SOURCES += \
main.cpp \
diff --git a/widget.cpp b/widget.cpp
index bb0ce64..ed69b5a 100644
--- a/widget.cpp
+++ b/widget.cpp
@@ -39,7 +39,7 @@ void Widget::InitWidget()
ui->cb_camera_name->addItem(QString::fromLatin1(GetCameraName(i)));
//启动默认视频
- StartRun(2);
+ StartRun(0);
imageprocessthread->init(ui->cb_camera_name->currentIndex());
imageprocessthread->start();
diff --git a/v4l2.c b/v4l2.c
index 014c5b0..6d9ef68 100644
--- a/v4l2.c
+++ b/v4l2.c
@@ -2,6 +2,7 @@
#include <jpeglib.h>
#include "sys/time.h"
#include "libv4l2.h"
+#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
@@ -22,7 +23,7 @@ int fd = -1;
int videoIsRun = -1;
int deviceIsOpen = -1;
unsigned char *rgb24 = NULL;
-int WIDTH = 1280, HEIGHT = 720;
+int WIDTH = 640, HEIGHT = 480;
//V4l2相关结构体
static struct v4l2_capability cap;
@@ -101,7 +102,7 @@ int MJPEG2RGB(unsigned char* data_frame, unsigned char *rgb, int bytesused)
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_decompress(&cinfo);
jpeg_mem_src(&cinfo, data, data_size);
- int rc = jpeg_read_header(&cinfo, TRUE);
+ int rc = jpeg_read_header(&cinfo, true);
if(!(1==rc))
{
//printf("Not a jpg frame.\n");
@@ -169,7 +170,7 @@ void StartVideoPrePare()
format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
format.fmt.pix.width = WIDTH;
format.fmt.pix.height = HEIGHT;
- format.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
+ format.fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG; //V4L2_PIX_FMT_YUYV
ioctl(fd, VIDIOC_S_FMT, &format);
//申请帧缓存区
@@ -434,7 +435,7 @@ int V4L2SetResolution(int new_width, int new_height)
WIDTH = new_width;
HEIGHT = new_height;
- StartRun(2);
+ StartRun(0);
return 0;
}
图片测试命令
ffmpeg -re -loop 1 -i image.jpg -vcodec mjpeg -f v4l2 /dev/video0
参数 | 说明 |
---|---|
ffmpeg |
启动 FFmpeg 工具。 |
-re |
按“实时”速度读取输入,模拟真实摄像头的帧率(而不是尽快读完)。 |
-loop 1 |
循环输入,1 表示无限次循环播放输入图片。 |
-i image.jpg |
指定输入文件为 image.jpg 。 |
-vcodec mjpeg |
设置视频编码格式为 MJPEG(Motion JPEG),每帧都是独立 JPEG 图像。 |
-f v4l2 |
设置输出格式为 V4L2(Linux 视频设备接口标准)。 |
/dev/video0 |
指定输出为虚拟摄像头设备 /dev/video0 (由 v4l2loopback 驱动创建)。 |
视频测试命令
ffmpeg -re -stream_loop -1 -i meihua_640x480.mp4 -vcodec mjpeg -f v4l2 /dev/video0
参数 | 解释 |
---|---|
ffmpeg |
ffmpeg 是一个强大的命令行工具,用于处理音频和视频数据。 |
-re |
以实时速度读取输入文件。这是为了模拟实时播放视频,确保推送到虚拟摄像头时不会过快地发送帧。 |
-stream_loop -1 |
-stream_loop 参数指定循环播放视频。-1 表示无限循环,即视频将持续不断地播放,直到手动停止。 |
-i meihua_640x480.mp4 |
指定输入文件,这里是名为 meihua_640x480.mp4 的视频文件。该文件将被推送到虚拟摄像头。 |
-vcodec mjpeg |
设置视频编码格式为 MJPEG(Motion JPEG),这是虚拟摄像头通常支持的格式。 |
-f v4l2 |
指定输出格式为 v4l2,表示将视频流推送到 V4L2(Video for Linux 2)设备,即虚拟摄像头。 |
/dev/video0 |
输出设备的路径,指向虚拟相机设备 /dev/video0 。这是虚拟摄像头的设备文件,应用程序可以通过它获取视频流。 |
、