RK3568 android11 移植 v4l2loopback 虚拟摄像头

2024-01-19 10:20

本文主要是介绍RK3568 android11 移植 v4l2loopback 虚拟摄像头,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一,v4l2loopback 简介

v4l2loopback是一个Linux内核模块,它允许用户创建虚拟视频设备。这种虚拟视频设备可以用于各种用途,例如将实际摄像头的视频流复制到虚拟设备上,或者用于视频流的处理和分析等。v4l2loopback的主要作用是创建一个虚拟的Video4Linux2设备,它可以接收来自其他应用程序的视频数据,并将这些数据提供给其他应用程序
一旦加载了v4l2loopback模块,就可以在/dev目录下找到虚拟设备文件,通常命名为/dev/videoX(X是一个数字)。

二,驱动文件配置

1. v4l2loopback 内核模块驱动文件

1> v4l2loopback.c: v4l2loopback 内核模块的 C 语言源代码文件。它包含了实现 v4l2loopback 模块功能的代码。
2> v4l2loopback.h: v4l2loopback 内核模块的头文件,通常包含一些宏定义、结构体定义、函数声明等。
3> v4l2loopback_formats.h:这个文件包含了有关视频格式的定义和处理,用于支持 v4l2loopback 模块对不同视频格式的处理和转换。

2. 移植 v4l2loopback驱动

a. 将驱动(v4l2loopback)拷贝到下面的文件夹:

./kernel/drivers/v4l2loopback

b. 在 Makefile 中添加 v4l2loopback设备

kernel/drivers/Makefile中添加:
+obj-y                           +=v4l2loopback/

c. 编译kernel后会在目录下生成对应的.o文件

~/RK3568_Android11/kernel/drivers/v4l2loopback$ ls
built-in.a  Makefile  modules.builtin  modules.order  v4l2loopback.c  v4l2loopback_formats.h  v4l2loopback.h  v4l2loopback.o

d. 验证 v4l2loopback.ko 模块是否加载成功
在这里插入图片描述
设备 video9 就是 v4l2loopback.ko 模块驱动的设备,确认v4l2loopback.ko 模块移植成功。


三,hardware下整合v4l2loopback 虚拟摄像头设备

源码目录:hardware/interfaces/camera/
修改补丁如下:

diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index ec3264894..c2a1f4156 100755
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -22,6 +22,8 @@#include <array>#include <regex>#include <linux/videodev2.h>
+#include <linux/v4l2-subdev.h>
+#include <linux/videodev2.h>#include "android-base/macros.h"#include "CameraMetadata.h"#include "../../3.2/default/include/convert.h"
@@ -373,6 +395,7 @@ status_t ExternalCameraDevice::initDefaultCharsKeys(UPDATE(ANDROID_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION,&opticalStabilizationMode, 1);+    ALOGD("=========mCameraId.c_str():%s ANDROID_LENS_FACING_EXTERNAL:%d========", mCameraId.c_str(), ANDROID_LENS_FACING_EXTERNAL);const uint8_t facing = ANDROID_LENS_FACING_EXTERNAL;UPDATE(ANDROID_LENS_FACING, &facing, 1);@@ -831,6 +854,16 @@ void ExternalCameraDevice::getFrameRateList(}}+    struct v4l2_capability capability_v4l2;
+    int ret_query_v4l2 = ioctl(fd, VIDIOC_QUERYCAP, &capability_v4l2);
+    if (ret_query_v4l2 < 0) {
+        ALOGE("%s v4l2 QUERYCAP %s failed: %s", __FUNCTION__, strerror(errno));
+    }
+    if(strstr((const char*)capability_v4l2.driver,"v4l2")){
+        LOGD("======%s: capability_v4l2.driver:%s ========", __func__, capability_v4l2.driver);
+        SupportedV4L2Format::FrameRate fr = {1,30}; //特定帧率(1帧每秒到30帧每秒)添加到 format->frameRates 向量中
+        format->frameRates.push_back(fr);
+    }if (format->frameRates.empty()) {ALOGE("%s: failed to get supported frame rates for format:%c%c%c%c w %d h %d",__FUNCTION__,
@@ -917,6 +950,12 @@ std::vector<SupportedV4L2Format> ExternalCameraDevice::getCandidateSupportedFormint ret = 0;while (ret == 0) {ret = TEMP_FAILURE_RETRY(ioctl(fd, VIDIOC_ENUM_FMT, &fmtdesc));
+        if(ret < 0 && strstr((const char*)capability.driver, "v4l2")) {
+            ALOGE("driver.find :%s",capability.driver);
+            fmtdesc.pixelformat = V4L2_PIX_FMT_NV12; 
+			ret = 0;
+        }ALOGV("index:%d,ret:%d, format:%c%c%c%c", fmtdesc.index, ret,fmtdesc.pixelformat & 0xFF,(fmtdesc.pixelformat >> 8) & 0xFF,
@@ -963,6 +1002,39 @@ std::vector<SupportedV4L2Format> ExternalCameraDevice::getCandidateSupportedForm}}}
+            if(strstr((const char*)capability.driver, "v4l2")) {
+					ALOGD("driver.find :%s",capability.driver);
+					SupportedV4L2Format format_1920x1080 {
+                            .width = 1920,
+                            .height = 1080,
+                            .fourcc = V4L2_PIX_FMT_NV12
+                        };
+					updateFpsBounds(fd, cropType, fpsLimits, format_1920x1080, outFmts);//名为 updateFpsBounds 的函数,向其传递了一些参数,包括文件描述符 fd、crop 类型、帧率限制、format_1920x1080 结构和 outFmts
+					ret = -1;
+                }}fmtdesc.index++;}
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index e2ab4fa2f..664d7d262 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -14,7 +14,7 @@* limitations under the License.*/#define LOG_TAG "ExtCamDevSsn@3.4"
-//#define LOG_NDEBUG 0
+#define LOG_NDEBUG 0#define ATRACE_TAG ATRACE_TAG_CAMERA#include <log/log.h>@@ -3104,7 +3104,18 @@ int ExternalCameraDeviceSession::configureV4l2StreamLocked(ALOGE("%s: QUERYBUF %d failed: %s", __FUNCTION__, i,  strerror(errno));return -errno;}
+//fy
+        ALOGD("==========mV4L2Buffer[%d] = (char*)mmap()==========", i);
+        if (buffer.memory == V4L2_MEMORY_MMAP) {
+            mV4L2Buffer[i] = (char*)mmap(0 /* start anywhere */ ,
+                        buffer.length, PROT_READ, MAP_SHARED, mV4l2Fd.get(),
+                        buffer.m.offset);
+            if (mV4L2Buffer[i] == MAP_FAILED) {
+                LOGE("%s(%d): Unable to map buffer(length:0x%x offset:0x%x) %s(err:%d)\n",__FUNCTION__,__LINE__, buffer.length,buffer.m.offset,strerror(errno),errno);
+            }+        }
+        V4l2BufferLen = buffer.length;if (TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_QBUF, &buffer)) < 0) {ALOGE("%s: QBUF %d failed: %s", __FUNCTION__, i,  strerror(errno));return -errno;
@@ -3401,8 +3412,10 @@ Status ExternalCameraDeviceSession::configureStreams(}}// Find the smallest format that matches the desired aspect ratio and is wide/high enough
-    SupportedV4L2Format v4l2Fmt {.width = 0, .height = 0};
-    SupportedV4L2Format v4l2Fmt_tmp {.width = 0, .height = 0};
+//    SupportedV4L2Format v4l2Fmt {.width = 0, .height = 0};
+//    SupportedV4L2Format v4l2Fmt_tmp {.width = 0, .height = 0};
+//初始化宽度为 1920,高度为 1088,fourcc 值为 V4L2_PIX_FMT_NV12;
+    SupportedV4L2Format v4l2Fmt {.width = 1920, .height = 1088, .fourcc = V4L2_PIX_FMT_NV12};
+    SupportedV4L2Format v4l2Fmt_tmp {.width = 1920, .height = 1088, .fourcc = V4L2_PIX_FMT_NV12};for (const auto& fmt : mSupportedFormats) {uint32_t dim = (mCroppingType == VERTICAL) ? fmt.width : fmt.height;if (dim >= maxDim) {
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession_3.4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession_3.4.h
index 209c5e91e..027a27ae7 100755
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession_3.4.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession_3.4.h
@@ -383,6 +383,9 @@ protected:SupportedV4L2Format mV4l2StreamingFmt;double mV4l2StreamingFps = 0.0;size_t mV4L2BufferCount = 0;
+    #define V4L2_BUFFER_MAX             32
+    char *mV4L2Buffer[V4L2_BUFFER_MAX];
+    unsigned int V4l2BufferLen = 0;struct v4l2_plane planes[1];struct v4l2_capability mCapability;diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDevice_3_4.h
index 6e0e4ebab..e085682d4 100644
diff --git a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
index 65447421c..a5a74e380 100755
--- a/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProviderImpl_2_4.cpp
@@ -257,6 +257,8 @@ void ExternalCameraProviderImpl_2_4::addExternalCamera(const char* devName) {}void ExternalCameraProviderImpl_2_4::deviceAdded(const char* devName) {
+    ALOGD("=============%s===========", __func__);
+    struct v4l2_capability capability;if (std::atoi(devName + kDevicePrefixLen) >= 30){sp<device::V3_4::implementation::ExternalFakeCameraDevice> deviceImpl =
@@ -267,14 +269,15 @@ void ExternalCameraProviderImpl_2_4::deviceAdded(const char* devName) {}deviceImpl.clear();} else {
-    {
+        {
+        ALOGD("======fd(::open(devName, O_RDWR)) devName:%s ==========", devName);base::unique_fd fd(::open(devName, O_RDWR));if (fd.get() < 0) {ALOGE("%s open v4l2 device %s failed:%s", __FUNCTION__, devName, strerror(errno));return;}-        struct v4l2_capability capability;
+//        struct v4l2_capability capability;int ret = ioctl(fd.get(), VIDIOC_QUERYCAP, &capability);if (ret < 0) {ALOGE("%s v4l2 QUERYCAP %s failed", __FUNCTION__, devName);
@@ -289,6 +292,7 @@ void ExternalCameraProviderImpl_2_4::deviceAdded(const char* devName) {// See if we can initialize ExternalCameraDevice correctlysp<device::V3_4::implementation::ExternalCameraDevice> deviceImpl =new device::V3_4::implementation::ExternalCameraDevice(devName, mCfg);
+    ALOGD("=========ExternalCameraDevice(devName:%s======", devName);if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {ALOGW("%s: Attempt to init camera device %s failed!", __FUNCTION__, devName);return;
@@ -296,7 +300,15 @@ void ExternalCameraProviderImpl_2_4::deviceAdded(const char* devName) {deviceImpl.clear();}-    addExternalCamera(devName);
+    //fy
+    if(capability.device_caps & V4L2_CAP_VIDEO_CAPTURE) {
+        ALOGD("===========dzp_test: devName:%s========", devName);
+        addExternalCamera(devName);
+    }
+    else addExternalCamera(devName);return;}@@ -331,6 +349,7 @@ ExternalCameraProviderImpl_2_4::HotplugThread::HotplugThread(ExternalCameraProviderImpl_2_4::HotplugThread::~HotplugThread() {}bool ExternalCameraProviderImpl_2_4::HotplugThread::threadLoop() {
+    ALOGD("============%s kDevicePath:%s========", __func__, kDevicePath);// Find existing /dev/video* devicesDIR* devdir = opendir(kDevicePath);if(devdir == 0) {
@@ -351,6 +370,7 @@ bool ExternalCameraProviderImpl_2_4::HotplugThread::threadLoop() {snprintf(v4l2DevicePath, kMaxDevicePathLen,"%s%s", kDevicePath, de->d_name);mParent->deviceAdded(v4l2DevicePath);
+                ALOGD("=============v4l2DevicePath:%s ==============", v4l2DevicePath);}}}
  1. 添加虚拟摄像头设备接口:在 “hardware/interfaces/camera/” 目录下可能会添加或修改相机设备的接口,以便 Android 系统可以与 v4l2loopback 虚拟摄像头进行交互。

  2. 实现虚拟摄像头设备功能:可能会在该目录下实现虚拟摄像头设备的功能,包括与 Android 相机框架的集成、数据流处理等。

  3. 支持虚拟摄像头的配置:可能会对 Android 相机服务的配置进行修改,以支持虚拟摄像头设备的添加和管理。

改动的目的是将 v4l2loopback 虚拟摄像头设备整合到 Android 系统中,以便应用程序可以与虚拟摄像头进行交互,并利用其提供的视频流数据


四,赋予虚拟摄像头注册节点权限

device/rockchip/common/ueventd.rockchip.rc中修改:/dev/video9          0666   media      camera

虚拟摄像头注册节点设为666权限是为了确保所有用户都能够访问和使用该节点。权限数字666表示所有用户都有读写权限,这意味着任何用户都可以读取和写入该节点,从而能够对虚拟摄像头进行访问和控制
例如,如果虚拟摄像头用于视频会议应用程序,那么所有参与会议的用户都需要能够访问虚拟摄像头节点。
需要注意的是,赋予666权限也可能存在一定的安全风险,因为这样做会允许任何用户都能够对该节点进行读写操作。因此,在实际应用中,需要仔细考虑安全性和访问控制的需求,以确定是否真的需要将虚拟摄像头节点权限设置为666。

这篇关于RK3568 android11 移植 v4l2loopback 虚拟摄像头的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/622107

相关文章

Mysql虚拟列的使用场景

《Mysql虚拟列的使用场景》MySQL虚拟列是一种在查询时动态生成的特殊列,它不占用存储空间,可以提高查询效率和数据处理便利性,本文给大家介绍Mysql虚拟列的相关知识,感兴趣的朋友一起看看吧... 目录1. 介绍mysql虚拟列1.1 定义和作用1.2 虚拟列与普通列的区别2. MySQL虚拟列的类型2

VMWare报错“指定的文件不是虚拟磁盘“或“The file specified is not a virtual disk”问题

《VMWare报错“指定的文件不是虚拟磁盘“或“Thefilespecifiedisnotavirtualdisk”问题》文章描述了如何修复VMware虚拟机中出现的“指定的文件不是虚拟... 目录VMWare报错“指定的文件不是虚拟磁盘“或“The file specified is not a virt

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

文章解读与仿真程序复现思路——电力自动化设备EI\CSCD\北大核心《考虑燃料电池和电解槽虚拟惯量支撑的电力系统优化调度方法》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源程序擅长文章解读,论文与完整源程序,等方面的知识,电网论文源程序关注python

4-4.Andorid Camera 之简化编码模板(获取摄像头 ID、选择最优预览尺寸)

一、Camera 简化思路 在 Camera 的开发中,其实我们通常只关注打开相机、图像预览和关闭相机,其他的步骤我们不应该花费太多的精力 为此,应该提供一个工具类,它有处理相机的一些基本工具方法,包括获取摄像头 ID、选择最优预览尺寸以及打印相机参数信息 二、Camera 工具类 CameraIdResult.java public class CameraIdResult {

用了虚拟机后,本机摄像头打不开了(联想电脑thinkpad)

虚拟机有摄像头,我断开了连接,现在本机的摄像头打开就是一个锁 我先把虚拟机的摄像头关了 然后把本机的vm usb关闭了 Win+R),输入services.msc,找到VMware USB Arbitration Service,确保其状态为“关闭 然后打开桌面助手 开启 参考: 联想知识库

AF透明模式/虚拟网线模式组网部署

透明模式组网 实验拓扑  防火墙基本配置 接口配置 eth1  eth3   放通策略  1. 内网用户上班时间(9:00-17:00)不允许看视频、玩游戏及网上购物,其余时 间访问互联网不受限制;(20 分) 应用控制策略   2. 互联网用户只允许访问内网两台服务器的 WEB、SSH 和远程桌面服务,其余 服务均不允许访问;(20 分) 外网访问内网的限制策略   虚拟网线模式组网 实

摄像头模组介绍和技术指标

1 手机摄像头概述 1.1 手机摄像头概述  手机的数码相机功能指的是手机是否可以通过内置或是外接的数码相机进行拍摄静态图片或短片拍摄,作为手机的一项新的附加功能,手机的数码相机功能得到了迅速的发展。 手机摄像头分为内置与外置,内置摄像头是指摄像头在手机内部,更方便。外置手机通过数据线或者手机下部接口与数码相机相连,来完成数码相机的一切拍摄功能。 外置数码相机的优点在于可以减轻手机的重

RT-Thread(Nano版本)的快速移植(基于NUCLEO-F446RE)

目录 概述 1 RT-Thread 1.1 RT-Thread的版本  1.2 认识Nano版本 2 STM32F446U上移植RT-Thread  2.1 STM32Cube创建工程 2.2 移植RT-Thread 2.2.1 安装RT-Thread Packet  2.2.2 加载RT-Thread 2.2.3 匹配相关接口 2.2.3.1 初次编译代码  2.2.3.

Thinkphp6.0+vue个人虚拟物品网站源码

Thinkphp6.0+vue个人虚拟物品网站源码 支持码支付对接 扫码自动发货 源码一共包含两个部分thinkphp6.0后端文件,以及vue前端文件。 服务器环境 php7以上,mysql5.6以上; 内附安装说明 代码免费下载