openharmony 使用uvc库获取摄像头数据使用nativewindow显示

news2024/11/30 18:25:57

界面代码:

XComponent({ id: 'xcomponentId', type: 'texture', libraryname: 'entry' })
            .width(800)
            .height(500)

Natvie代码:

1、头文件

//NativeWindow
#include <ace/xcomponent/native_interface_xcomponent.h>
#include <cstdint>
#include <native_window/external_window.h>
#include <sys/mman.h>

//UVC
#include "libuvc.h"
#include "stdio.h"
#include "string.h"

2、关键变量

OHNativeWindow* nativeWindow = nullptr;
BufferHandle* bufferHandle = nullptr;
// 初始化 OH_NativeXComponent_Callback
OH_NativeXComponent_Callback callback;
void* mappedAddr = nullptr;
int winwidth = 640;
int winheigh = 480;
OHNativeWindowBuffer* buffer = nullptr;
int fenceFd;
// 设置刷新区域,如果Region中的Rect为nullptr,或者rectNumber为0,则认为OHNativeWindowBuffer全部有内容更改。
Region region{nullptr, 0};

3、注册回调函数,通过回调函数获取nativewindow,可以在

static napi_value Init(napi_env env, napi_value exports)中调用
// 定义回调函数
void OnSurfaceCreatedCB(OH_NativeXComponent* component, void* window)
{
    
    // 可获取 OHNativeWindow 实例
    nativeWindow = static_cast<OHNativeWindow*>(window);
    OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","surface create get nativewindow");
    // ...
}
void OnSurfaceChangedCB(OH_NativeXComponent* component, void* window)
{
    // 可获取 OHNativeWindow 实例
    nativeWindow = static_cast<OHNativeWindow*>(window);
    // ...
}
void OnSurfaceDestroyedCB(OH_NativeXComponent* component, void* window)
{
    // 可获取 OHNativeWindow 实例
    nativeWindow = static_cast<OHNativeWindow*>(window);
    // ...
}
void DispatchTouchEventCB(OH_NativeXComponent* component, void* window)
{
    // 可获取 OHNativeWindow 实例
    nativeWindow = static_cast<OHNativeWindow*>(window);
    OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","DispatchTouchEventCB get nativewindow");
    // ...
}


static napi_value nativewin_init(napi_env env,  napi_value exports)
{
#if NATIVE_WINDOW_
    napi_value exportInstance = nullptr;
    // 用来解析出被wrap了NativeXComponent指针的属性
    napi_get_named_property(env, exports, OH_NATIVE_XCOMPONENT_OBJ, &exportInstance);
    
    OH_NativeXComponent *nativeXComponent = nullptr;
    // 通过napi_unwrap接口,解析出NativeXComponent的实例指针
    napi_unwrap(env, exportInstance, reinterpret_cast<void**>(&nativeXComponent));
    
    // 获取XComponentId
    char idStr[OH_XCOMPONENT_ID_LEN_MAX + 1] = {};
    uint64_t idSize = OH_XCOMPONENT_ID_LEN_MAX + 1;
    OH_NativeXComponent_GetXComponentId(nativeXComponent, idStr, &idSize);
    
    callback.OnSurfaceCreated = OnSurfaceCreatedCB;
    callback.OnSurfaceChanged = OnSurfaceChangedCB;
    callback.OnSurfaceDestroyed = OnSurfaceDestroyedCB;
    callback.DispatchTouchEvent = DispatchTouchEventCB;
    
    // 注册回调函数
    OH_NativeXComponent_RegisterCallback(nativeXComponent, &callback);
    

    return nullptr;

#endif
}

4、设置nativewindow窗口


void SetNativeWindow(OHNativeWindow* nativeWindow, uint64_t width,  uint64_t height)
{
    if(nativeWindow!=nullptr)
    {
        // 设置 OHNativeWindowBuffer 的宽高
        int32_t code = SET_BUFFER_GEOMETRY;
        
        // 这里的nativeWindow是从上一步骤中的回调函数中获得的
        winwidth = width;
        winheigh = height;
        int32_t bufferHeight = static_cast<int32_t>(height );
        int32_t bufferWidth = static_cast<int32_t>(width );
        int32_t ret = OH_NativeWindow_NativeWindowHandleOpt(nativeWindow, code, bufferWidth, bufferHeight);
        if(ret<0)
        {
            OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","SetNativeWindow fail %{public}d",ret);
        } else {
            OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","SetNativeWindow  ok");
        }
    } else {
        OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","get NativeWindow fail");
    }
}

5、显示一帧数据  可以放到uvc的回调函数中

void draw_init(OHNativeWindow* nativeWindow,BufferHandle* bufferHandle,int32_t *bgrdata)
{
    if(nativeWindow!=nullptr)
    {
        //OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","draw_init");
        // 通过 OH_NativeWindow_NativeWindowRequestBuffer 获取 OHNativeWindowBuffer 实例
        OH_NativeWindow_NativeWindowRequestBuffer(nativeWindow, &buffer, &fenceFd);
        if(buffer == nullptr)
        {
            OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","RequestBuffer fail");
            return;
        }
        else
        {
            //OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","RequestBuffer ok");
        }
        // 通过 OH_NativeWindow_GetBufferHandleFromNative 获取 buffer 的 handle
        bufferHandle = OH_NativeWindow_GetBufferHandleFromNative(buffer);
        if(bufferHandle == nullptr)
        {
            OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","GetBufferHandle fail");
            return;
        }
        else
        {
            //OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","GetBufferHandle ok");
        }
        // 使用内存映射函数mmap将bufferHandle对应的共享内存映射到用户空间,可以通过映射出来的虚拟地址向bufferHandle中写入图像数据
        // bufferHandle->virAddr是bufferHandle在共享内存中的起始地址,bufferHandle->size是bufferHandle在共享内存中的内存占用大小
        mappedAddr = mmap(bufferHandle->virAddr, bufferHandle->size, PROT_READ | PROT_WRITE, MAP_SHARED, bufferHandle->fd, 0);
        if (mappedAddr == MAP_FAILED) {
            // mmap failed
            OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","mmap failed");
            return;
        } else {
            //OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","mmap ok");
        }
        static uint32_t value = 0xFF;
        int32_t index = 0;
        uint32_t *pixel = static_cast<uint32_t *>(mappedAddr); // 使用mmap获取到的地址来访问内存
        for (uint32_t x = 0; x < winwidth ; x++) {
            for (uint32_t y = 0;  y < winheigh; y++) {
                *pixel++ = bgrdata[index++];
            }
        }
        // 设置刷新区域,如果Region中的Rect为nullptr,或者rectNumber为0,则认为OHNativeWindowBuffer全部有内容更改。
        // 通过OH_NativeWindow_NativeWindowFlushBuffer 提交给消费者使用,例如:显示在屏幕上。
        OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, buffer, fenceFd, region);
        //OH_NativeWindow_NativeWindowFlushBuffer(nativeWindow, buffer, fenceFd, region);

        // 内存使用完记得去掉内存映射
        int result = munmap(mappedAddr, bufferHandle->size);
        if (result == -1) {
            // munmap failed
        }
        //OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","mmap write ok");

    } else {
        OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","draw_init fail");
    }

}

6、uvc设备打开及注册回到函数

bool s_cbSignal=false;
void uvc_callback(uvc_frame_t *frame, void *ptr);


void uvc_start()
{
    uvc_context_t *m_ctx = nullptr;
    uvc_device_t *m_dev = nullptr;/*!< uvc设备结构*/
    uvc_device_handle_t *m_devh = nullptr;/*!< 打开uvc设备的句柄*/
    int fps = 25;
    uvc_frame_format frame_format = UVC_FRAME_FORMAT_MJPEG;
    uvc_error_t res = uvc_init(&m_ctx, nullptr);
    int deviceWidth = 640;
    int deviceHeight = 480;
    
    if (res < 0)
    {
        OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc init fail");
    } else {
        OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc init ok");
    }
    int VID=0xxxx,PID=0xxxx;
    res = uvc_find_device( m_ctx, &m_dev, VID, PID, nullptr);
    if (res < 0)
    {
        OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc find fail");
    } else {
        OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc find ok");
        res = uvc_open(m_dev, &m_devh);
        if (res < 0)
        {
            OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc open fail%{public}d",res);
        } else {
            OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc open ok");
            uvc_stream_ctrl_t ctrl;
            res = uvc_get_stream_ctrl_format_size( m_devh, &ctrl, frame_format, deviceWidth, deviceHeight, fps);
            uvc_print_stream_ctrl(&ctrl, stderr);
            if (res < 0)
            {
                OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc get stream mode fail");
            } else {
                OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc get stream mode ok");

                void* user_ptr = nullptr;
                res = uvc_start_streaming(m_devh, &ctrl, uvc_callback, user_ptr, 0);
                if(res < 0)
                {
                    OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc_start_streaming error");
                } else {
                    OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc_start_streaming ok");
                }
                struct timeval tpstart,tpend;
                float timeuse;
                gettimeofday(&tpstart,nullptr);
                while(!s_cbSignal)
                {
                    gettimeofday(&tpend,nullptr);
                    timeuse=(1000000*(tpend.tv_sec-tpstart.tv_sec) + tpend.tv_usec-tpstart.tv_usec)/1000000.0;
                    if(timeuse > 2)
                    {
                        //printf("等待回调超时\n");
                        return ;
                    }
                }
                return ;

            }
        }
    }
}


void uvc_callback(uvc_frame_t *frame, void *ptr)
{
    
    
    //OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc getting stream");
    s_cbSignal = true;
#if 1
    static int g_current_bufNum = 0;
    if(g_current_bufNum >= 3)
    {
        g_current_bufNum = 0;
    }
    (void)ptr;
    uvc_frame_t *bgr;
    uvc_error_t ret = UVC_ERROR_OTHER;

    bgr = uvc_allocate_frame(frame->width * frame->height * 3);
    if (!bgr)
    {
        OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc allocate error");
        return;
    }
    //OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc_allocate_frame");
    try {
        ret = uvc_any2rgb(frame, bgr);//RGB
        if (ret)
        {
            uvc_perror(ret, "uvc_any2rgb(face)");
            uvc_free_frame(bgr);
            OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc any2rgb");
            return;
        }
        //OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc_any2rgb");
    } catch (...)
    {
        uvc_perror(ret, "uvc_any2rgb(face) catch");
        uvc_free_frame(bgr);
        OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc any2rgb catch");
        return;
    }

    //"frame width=%{public}d height=%{public}d format=%{public}d size=%{public}d",
    //bgr->width,bgr->height,bgr->frame_format,bgr->data_bytes);

    static uint32_t value = 0xFF;
    int32_t index = 0;
    int32_t indexrgb = 0;
    
    for (uint32_t x = 0; x < winwidth ; x++) {
        for (uint32_t y = 0;  y < winheigh; y++) {
            value = *((uint8_t *)(bgr->data)+indexrgb++); value+=(*((uint8_t *)(bgr->data)+indexrgb++)<<8);value+=(*((uint8_t *)(bgr->data)+indexrgb++)<<16);
            bmpdata[index++] = value;
        }
    }
    draw_init(nativeWindow,bufferHandle,bmpdata);
    //memcpy(bmpdata,bgr->data,bgr->data_bytes);
    uvc_free_frame(bgr);
    
    
    //OH_LOG_Print(LOG_APP,LOG_INFO, LOG_PRINT_DOMAIN,"Init","uvc_free_frame");
#endif
}

需要依赖的库

target_link_libraries(entry PUBLIC libace_napi.z.so  libhilog_ndk.z.so )
target_link_libraries(entry PUBLIC libace_ndk.z.so libuvc.so)
target_link_libraries(entry PUBLIC libnative_buffer.so libnative_window.so)

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

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

相关文章

云轴科技ZStack助力 “上科大智慧校园信创云平台”入选上海市2024年优秀信创解决方案

近日&#xff0c;为激发创新活⼒&#xff0c;促进信创⾏业⾼质量发展&#xff0c;由上海市经济信息化委会同上海市委网信办、上海市密码管理局、上海市国资委等主办的“2024年上海市优秀信创解决方案”征集遴选活动圆满落幕。云轴科技ZStack支持的“上科大智慧校园信创云平台”…

【ArcGIS Pro】实现一下完美的坐标点标注

在CAD里利用湘源可以很快点出一个完美的坐标点标注。 但是在ArcGIS Pro中要实现这个效果却并不容易。 虽然有点标题党&#xff0c;这里就尽量在ArcGIS Pro中实现一下。 01 标注实现方法 首先是准备工作&#xff0c;准备一个点要素图层&#xff0c;包含xy坐标字段。 在地图框…

聚云科技×亚马逊云科技:打通生成式AI落地最后一公里

云计算时代&#xff0c;MSP&#xff08;云管理服务提供商&#xff09;犹如一个帮助企业上云、用云、管理云的专业管家&#xff0c;在云计算厂商与企业之间扮演桥梁的作用。生成式AI浪潮的到来&#xff0c;也为MSP带来全新的生态价值和发展空间。 作为国内领先的云管理服务提供…

brew安装mongodb和php-mongodb扩展新手教程

1、首先保证macos下成功安装了Homebrew&#xff0c; 在终端输入如下命令&#xff1a; brew search mongodb 搜索是不是有mongodb资源&#xff0c; 演示效果如下&#xff1a; 2、下面来介绍Brew 安装 MongoDB&#xff0c;代码如下&#xff1a; brew tap mongodb/brew brew in…

图像显示的是矩阵的行和列,修改为坐标范围。

x 3; y 3; f1x x^2 y^2; guance1 f1x; F (x, y) sqrt((x.^2 y.^2 - guance1).^2); % 使用点乘 [x, y] meshgrid(0:1:5, 0:1:5); Z F(x, y); figure; imagesc(Z); % 由于 imagesc 使用矩阵索引作为坐标&#xff0c;我们需要手动添加刻度 % 这里我们假设 x 和 y 的范围…

深入理解Redis线程模型

前置目标&#xff1a;搭建一个Redis单机服务器。搭建过程参考前面的文档&#xff08;https://blog.csdn.net/Zhuxiaoyu_91/article/details/143904807&#xff09;。 建议调整的redis核心配置&#xff1a; daemonize yes # 允许后台启动 protected‐mode no #关闭保护模…

机器学习实战:泰坦尼克号乘客生存率预测(数据处理+特征工程+建模预测)

项目描述 任务&#xff1a;根据训练集数据中的数据预测泰坦尼克号上哪些乘客能生存下来 数据源&#xff1a;csv文件&#xff08;train.csv&#xff09; 目标变量&#xff1a;Survived&#xff08;0-1变量&#xff09; 数据集预览&#xff1a; 1、英文描述&#xff1a; 2、…

人工智能之数学基础:欧式距离及在人工智能领域中的应用

本文重点 欧式距离,也称为欧几里得距离,是数学中用于衡量多维空间中两点之间绝对距离的一种基本方法。这一概念最早由古希腊数学家欧几里得提出,并以其名字命名。欧式距离的计算基于勾股定理,即在一个直角三角形中,斜边的平方等于两直角边的平方和。在多维空间中,欧式距…

logminer挖掘日志归档查找问题

--根据发生问题时间点查找归档文件 select first_time,NAME from gv$archived_log where first_time>2016-03-15 17:00:00 and first_time<2016-03-15 21:00:00; 2016-03-15 17:23:55 ARCH/jxdb/archivelog/2016_03_15/thread_1_seq_41588.4060.906577337 2016-03-15 17:…

洛谷 P1747 好奇怪的游戏 C语言 bfs

题目&#xff1a; https://www.luogu.com.cn/problem/P1747#submit 题目描述 爱与愁大神坐在公交车上无聊&#xff0c;于是玩起了手机。一款奇怪的游戏进入了爱与愁大神的眼帘&#xff1a;***&#xff08;游戏名被打上了马赛克&#xff09;。这个游戏类似象棋&#xff0c;但…

【c++篇】:解读Set和Map的封装原理--编程中的数据结构优化秘籍

✨感谢您阅读本篇文章&#xff0c;文章内容是个人学习笔记的整理&#xff0c;如果哪里有误的话还请您指正噢✨ ✨ 个人主页&#xff1a;余辉zmh–CSDN博客 ✨ 文章所属专栏&#xff1a;c篇–CSDN博客 文章目录 前言一.set和map的初步封装1.树的节点封装修改2.Find()查找函数3.红…

字符型注入‘)闭合

前言 进行sql注入的时候&#xff0c;不要忘记闭合&#xff0c;先闭合再去获取数据 步骤 判断是字符型注入 用order by获取不了显位&#xff0c;select也一样 是因为它是’)闭合&#xff0c;闭合之后&#xff0c;就可以获取数据了 最后就是一样的步骤

电脑启动需要经历哪些过程?

传统BIOS启动流程 1. BIOS BIOS 启动&#xff0c;BIOS程序是烧进主板自带的ROM里的&#xff0c;所以无硬盘也可以启动。BIOS先进行自检&#xff0c;检查内存、显卡、磁盘等关键设备是否存在功能异常&#xff0c;会有蜂鸣器汇报错误&#xff0c;无错误自检飞快结束。 硬件自检…

PYNQ 框架 - OV5640驱动 + Linux 驱动分析

目录 1. 简介 1.1 博文要点 1.2 V4L2 2. 极简 Char 驱动 2.1 源码 2.2 Makefile 2.3 加载驱动 2.4 设备文件 2.5 测试驱动程序 2.6 卸载驱动程序 2.7 自动创建设备文件 2.8 日志等级 3. 极简 V4L2 驱动 3.1 源码 3.2 Makefile 3.3 设备节点类型 3.4 测试 V4L2…

微信小程序Webview与H5通信

背景 近期有个微信小程序需要用到web-view嵌套H5的场景&#xff0c;该应用场景需要小程序中频繁传递数据到H5进行渲染&#xff0c;且需要保证页面不刷新。 由于微信小程序与H5之间的通信限制比较大&#xff0c;显然无法满足于我的业务场景 探索 由于微信小程序与webview的环境是…

【maven-4】IDEA 配置本地 Maven 及如何使用 Maven 创建 Java 工程

IntelliJ IDEA&#xff08;以下简称 IDEA&#xff09;是一款功能强大的集成开发环境&#xff0c;广泛应用于 Java 开发。下面将详细介绍如何在 IDEA 中配置本地 Maven&#xff0c;并创建一个 Maven Java 工程&#xff0c;快速上手并高效使用 Maven 进行 Java 开发。 1. Maven …

交通流量预测:基于交通流量数据建立模型

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

【故障处理系列--移动云云盘根目录在线扩容】

移动云云盘根目录扩容 **目的&#xff1a;**测试harbor仓库服务器的根目录能否在线扩容 1、移动云控制台系统盘扩容 这里以我自己的虚拟机演示 2、查看分区的文件类型 3、安装growpart工具 rootgitlab-cli:~# apt install cloud-guest-utils -y rootgitlab-cli:~# apt ins…

不可分割的整体—系统思考的微妙法则

不可分割的整体——系统思考的微妙法则 作为企业领导者&#xff0c;我们经常需要做出决策&#xff0c;但有时候&#xff0c;我们会忽略一个事实&#xff1a;每个决策都不是孤立的&#xff0c;它背后都是一个复杂系统的一部分。 无论是市场动态、团队协作&#xff0c;还是产品…

内核模块里获取当前进程和父进程的cmdline的方法及注意事项,涉及父子进程管理,和rcu的初步介绍

一、背景 在编写内核态系统监控代码时&#xff0c;有时候为了调试的便捷性&#xff0c;不仅要拿到异常事件有关的线程id&#xff0c;进程id和父进程id&#xff0c;还需要拿到当前进程和父进程的comm和cmdline。主要有几下几个原因&#xff1a; 1&#xff09;单纯的pid或者tgi…