RK3588 Android12实现UVC输出功能详解

news2024/11/18 8:49:17

首先需要在相关部分添加uvc的功能,这里参考一下:rockchip rk3588添加uvc及uvc,adb的复合设备_uvc.gs6-CSDN博客

setprop sys.usb.config none;setprop sys.usb.config uvc
或者setprop sys.usb.config none;setprop sys.usb.config uvc,adb
使rk3588 进入uvc的device模式。

然后我们开始uvc_app的开发:

由于涉及到UVC协议和V4L2标准接口,所以通过调用JNI接口来实现UVC的功能。

上述进入device模式之后,会在/dev下生成一个video节点,通过ls /sys/class/video4linux来确认节点

1、对这个节点,我们需要先配置需要监听的事件

static void uvc_events_init(struct uvc_device *dev)
{
    struct v4l2_event_subscription sub;
    unsigned int payload_size;

    switch (dev->fcc) {
    case V4L2_PIX_FMT_YUYV:
        payload_size = dev->width * dev->height * 2;
        break;
    case V4L2_PIX_FMT_MJPEG:
        payload_size = dev->imgsize;
        break;
    }

    uvc_fill_streaming_control(dev, &dev->probe, 0, 0);
    uvc_fill_streaming_control(dev, &dev->commit, 0, 0);

    if (dev->bulk) {
        /* FIXME Crude hack, must be negotiated with the driver. */
        dev->probe.dwMaxPayloadTransferSize = dev->commit.dwMaxPayloadTransferSize = payload_size;
    }

    memset(&sub, 0, sizeof sub);
    sub.type = UVC_EVENT_SETUP;
    ioctl(dev->uvc_fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
    sub.type = UVC_EVENT_DATA;
    ioctl(dev->uvc_fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
    sub.type = UVC_EVENT_STREAMON;
    ioctl(dev->uvc_fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
    sub.type = UVC_EVENT_STREAMOFF;
    ioctl(dev->uvc_fd, VIDIOC_SUBSCRIBE_EVENT, &sub);
}

主要分为连接、断开、数据传输、流的开启或关闭

2、监听事件


static void uvc_events_process(struct uvc_device *dev)
{
    struct v4l2_event v4l2_event;
    struct uvc_event *uvc_event = (void *)&v4l2_event.u.data;
    struct uvc_request_data resp;
    int ret;

    ret = ioctl(dev->uvc_fd, VIDIOC_DQEVENT, &v4l2_event);
    if (ret < 0) {
        printf("VIDIOC_DQEVENT failed: %s (%d)\n", strerror(errno), errno);
        return;
    }

    memset(&resp, 0, sizeof resp);
    resp.length = -EL2HLT;

    switch (v4l2_event.type) {
    case UVC_EVENT_CONNECT:
        return;

    case UVC_EVENT_DISCONNECT:
        dev->uvc_shutdown_requested = 1;
        printf(
            "UVC: Possible USB shutdown requested from "
            "Host, seen via UVC_EVENT_DISCONNECT\n");
        return;

    case UVC_EVENT_SETUP:
        uvc_events_process_setup(dev, &uvc_event->req, &resp);
        break;

    case UVC_EVENT_DATA:
        ret = uvc_events_process_data(dev, &uvc_event->data);
        if (ret < 0)
            break;
        return;

    case UVC_EVENT_STREAMON:
        if (!dev->bulk)
            uvc_handle_streamon_event(dev);
        return;

    case UVC_EVENT_STREAMOFF:
        /* Stop V4L2 streaming... */
        if (!dev->run_standalone && dev->vdev->is_streaming) {
            /* UVC - V4L2 integrated path. */
            v4l2_stop_capturing(dev->vdev);
            dev->vdev->is_streaming = 0;
        }

        /* ... and now UVC streaming.. */
        if (dev->is_streaming) {
            uvc_video_stream(dev, 0);
            uvc_uninit_device(dev);
            uvc_video_reqbufs(dev, 0);
            dev->is_streaming = 0;
            dev->first_buffer_queued = 0;
        }

        return;
    }

    ret = ioctl(dev->uvc_fd, UVCIOC_SEND_RESPONSE, &resp);
    if (ret < 0) {
        printf("UVCIOC_S_EVENT failed: %s (%d)\n", strerror(errno), errno);
        return;
    }
}

3、初始化节点,也就是对UVC流控制端口的配置,配置传输速率、包大小、端点序号等。

static void uvc_events_process_streaming(struct uvc_device *dev, uint8_t req, uint8_t cs, struct uvc_request_data *resp)
{
    struct uvc_streaming_control *ctrl;

    printf("streaming request (req %02x cs %02x)\n", req, cs);

    if (cs != UVC_VS_PROBE_CONTROL && cs != UVC_VS_COMMIT_CONTROL)
        return;

    ctrl = (struct uvc_streaming_control *)&resp->data;
    resp->length = sizeof *ctrl;

    switch (req) {
    case UVC_SET_CUR:
        dev->control = cs;
        resp->length = 34;
        break;

    case UVC_GET_CUR:
        if (cs == UVC_VS_PROBE_CONTROL)
            memcpy(ctrl, &dev->probe, sizeof *ctrl);
        else
            memcpy(ctrl, &dev->commit, sizeof *ctrl);
        break;

    case UVC_GET_MIN:
    case UVC_GET_MAX:
    case UVC_GET_DEF:
        uvc_fill_streaming_control(dev, ctrl, req == UVC_GET_MAX ? -1 : 0, req == UVC_GET_MAX ? -1 : 0);
        break;

    case UVC_GET_RES:
        CLEAR(ctrl);
        break;

    case UVC_GET_LEN:
        resp->data[0] = 0x00;
        resp->data[1] = 0x22;
        resp->length = 2;
        break;

    case UVC_GET_INFO:
        resp->data[0] = 0x03;
        resp->length = 1;
        break;
    }
}

除了上述还有其他配置,比如亮度、曝光、闪光灯等配置,就不再一一赘述了。

4、最后是开启UVC流

static int uvc_handle_streamon_event(struct uvc_device *dev)
{
    int ret;

    ret = uvc_video_reqbufs(dev, dev->nbufs);
    if (ret < 0)
        goto err;

    if (!dev->run_standalone) {
        /* UVC - V4L2 integrated path. */
        if (IO_METHOD_USERPTR == dev->vdev->io) {
            /*
             * Ensure that the V4L2 video capture device has already
             * some buffers queued.
             */
            ret = v4l2_reqbufs(dev->vdev, dev->vdev->nbufs);
            if (ret < 0)
                goto err;
        }

        ret = v4l2_qbuf(dev->vdev);
        if (ret < 0)
            goto err;

        /* Start V4L2 capturing now. */
        ret = v4l2_start_capturing(dev->vdev);
        if (ret < 0)
            goto err;

        dev->vdev->is_streaming = 1;
    }

    /* Common setup. */

    /* Queue buffers to UVC domain and start streaming. */
    ret = uvc_video_qbuf(dev);
    if (ret < 0)
        goto err;

    if (dev->run_standalone) {
        uvc_video_stream(dev, 1);
        dev->first_buffer_queued = 1;
        dev->is_streaming = 1;
    }

    return 0;

err:
    return ret;
}

在这个函数里面我们就可以通过采集摄像头的数据,来写入到UVC节点里面

最后是JNI函数的封装

在我们自定义的类中可以声明该函数

 public static native int prepareCamera(String uvcDevName,String v4lDevName);

然后通过 javac -h命令把这个类生成一个头文件,实现头文件里声明的函数,将以上的流程添加到这个函数里,最后在对应地方调用即可

UVC实现源码:https://github.com/wlhe/uvc-gadget

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1900336.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

为什么需要服务器?服务器可以做些什么

目录 一、服务器和电脑的区别二、什么是SSH三、什么是免密码登录四、服务器如何实现SSH免密码登录 一、服务器和电脑的区别 服务器和电脑是两种不同类型的计算机系统&#xff0c;它们在设计、功能和用途上存在明显的区别。首先&#xff0c;从硬件配置上看&#xff0c;服务器通…

基于java+springboot+vue实现的大学生就业需求分析系统(文末源码+Lw)233

摘 要 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互联网时代才发现能补上自…

基于java+springboot+vue实现的药店管理系统(文末源码+Lw)285

摘 要 传统信息的管理大部分依赖于管理人员的手工登记与管理&#xff0c;然而&#xff0c;随着近些年信息技术的迅猛发展&#xff0c;让许多比较老套的信息管理模式进行了更新迭代&#xff0c;药品信息因为其管理内容繁杂&#xff0c;管理数量繁多导致手工进行处理不能满足广…

【Linux】:程序地址空间

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关Linux程序地址空间的相关知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从…

016-GeoGebra基础篇-加载项错误_使用此功能所需的服务已关闭,请检查你的隐私设置,

最近有伙伴说遇到一个问题&#xff1a;“加载项错误_使用此功能所需的服务已关闭&#xff0c;请检查你的隐私设置”&#xff0c;该怎么解决&#xff1f; 若大家也遇到同样的问题&#xff0c;建议按照我下边的步骤逐个排查下&#xff0c;基本可以解决“GeoGebra无法完美插入PPT…

利用border绘制三角技巧

绘制三角形的效果如图 <html lang"zh-cn"> <head><meta charset"UTF-8"><title>demo</title><style>* {margin: 0;padding: 0;}.box {/* 盒子宽高改成零就变成三角形 &#xff0c;需要哪个方向的三角形就设置哪个方向…

PD协议诱骗芯片,XSP08Q,XSP16应用笔记

XSP08Q是3C数码或小家电产品的Type-C接口控制芯片&#xff0c;它负责和PD充电器通讯&#xff0c;获取充电器的快充电压档位&#xff0c;如5V4A&#xff0c;9V3A&#xff0c;12V2A&#xff0c;15V3A&#xff0c;20V5A等等。 XSP08Q支持PD协议&#xff0c;BC1.2协议&#xff0c;Q…

Spring MVC 获取请求数据的四种方式,以及获取请求头数据,获取Cookie 的数据,设置Spring MVC 的字符集编码过滤器

1. Spring MVC 获取请求数据的四种方式&#xff0c;以及获取请求头数据&#xff0c;获取Cookie 的数据&#xff0c;设置Spring MVC 的字符集编码过滤器 文章目录 1. Spring MVC 获取请求数据的四种方式&#xff0c;以及获取请求头数据&#xff0c;获取Cookie 的数据&#xff0c…

【IT领域新生必看】Java中的Static关键字详解:小白也能轻松掌握的神奇用法

文章目录 引言什么是Static关键字&#xff1f;Static变量&#xff08;类变量&#xff09;定义和使用示例&#xff1a; 应用场景 Static方法&#xff08;类方法&#xff09;定义和使用示例&#xff1a; 应用场景 Static代码块定义和使用示例&#xff1a; 应用场景 Static嵌套类定…

ESP32 通过蓝牙显示歌词代码示例

通过蓝牙协议播放音乐&#xff0c;有的时候需要显示歌词&#xff0c;这里就是a2dp库获取了歌词 值得注意的是要想正确获取到歌词&#xff0c;必须打开各种播放器的字幕&#xff08;歌词&#xff09;开关 本项目用了三个开源库 a2dp&#xff0c;tft_espi,xfont. a2dp &#x…

Qt 网络编程 udp通信

学习目标&#xff1a;使用udp通信 前置环境 运行环境:qt creator 4.12 学习内容 UDP 协议基础知识 1、UDP(用户数据报协议)是轻量的、不可靠的、面向数据报、无连接的协议&#xff0c;用于可靠性要求不高的场合。两个应用程序之间进行UDP 通信不需先建立持久的 socket 连接…

【IT领域新生必看】解密Java中的静态方法与实例方法:小白也能轻松掌握的全方位指南

文章目录 引言什么是静态方法&#xff1f;定义和使用静态方法示例&#xff1a; 静态方法的特点示例&#xff1a; 什么是实例方法&#xff1f;定义和使用实例方法示例&#xff1a; 实例方法的特点示例&#xff1a; 静态方法与实例方法的区别作用范围示例&#xff1a; 访问权限示…

宁德时代天行发布,商用车超充时代来临

近日&#xff0c;宁德时代正式推出商用动力电池品牌——“宁德时代天行”&#xff0c;同时发布“宁德时代天行轻型商用车&#xff08;L&#xff09;-超充版”和“宁德时代天行轻型商用车&#xff08;L&#xff09;-长续航版”两款产品&#xff0c;可实现4C超充能力和500km的实况…

14-38 剑和诗人12 - RAG+ 思维链 ⇒ 检索增强思维(RAT)

在快速发展的 NLP 和 LLM 领域&#xff0c;研究人员不断探索新技术来增强这些模型的功能。其中一种备受关注的技术是检索增强生成 (RAG) 方法&#xff0c;它将 LLM 的生成能力与从外部来源检索相关信息的能力相结合。然而&#xff0c;最近一项名为检索增强思维 (RAT) 的创新通过…

计算机网络(2

计算机网络续 一. 网络编程 网络编程, 指网络上的主机, 通过不同的进程, 以编程的方式实现网络通信(或网络数据传输). 即便是同一个主机, 只要不同进程, 基于网络来传输数据, 也属于网络编程. 二. 网络编程套接字(socket) socket: 操作系统提供的网络编程的 API 称作 “soc…

免杀笔记 ----> DLL注入

这段时间我们暂时没什么事情干的话我们就继续更新我们的免杀笔记力&#xff01;&#xff01;&#xff01; &#xff1a;今天我们讲DLL注入 目录 1.DLL注入 2.直接加载DLL&#xff1f; 3.远程线程注入 获取Handle 远程申请内存空间 将我们的CS的DLL加载入内存 创建远程线…

C语言 | Leetcode C语言题解之第218题天际线问题

题目&#xff1a; 题解&#xff1a; struct pair {int first, second; };struct Heap {struct pair* heap;int heapSize;bool (*cmp)(struct pair*, struct pair*); };void init(struct Heap* obj, int n, bool (*cmp)(struct pair*, struct pair*)) {obj->heap malloc(si…

Midjourney对图片细微调整和下载保存

点击v2是对第二图片细微调整。 点击u3对第3张图片进行放大。 保存图片: 对点击u3放大的图片&#xff0c;双击 , 右键保存图片

antd通过监听change方法实现表格分页查询功能

<script setup> import {computed, onMounted, ref} from "vue"; import axios from "axios";const columns [{name: 姓名,dataIndex: name,key: name,},{name: 性别,dataIndex: gender,key: gender,},{title: 年龄,dataIndex: age,key: age,},{tit…

江苏徐州SAP代理商有哪些?怎么选择?

在数字化浪潮席卷全球的今天&#xff0c;企业对于高效、智能的管理系统需求日益迫切。SAP作为全球领先的企业管理软件解决方案提供商&#xff0c;其产品在市场上享有极高的声誉。而在江苏徐州&#xff0c;哲讯智能科技作为SAP的代理商&#xff0c;以其专业的技术实力和优质的服…