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

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

界面代码:

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));// 获取XComponentIdchar 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 的 handlebufferHandle = 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 failedOH_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 1static 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);//RGBif (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.lryc.cn/news/496101.html

相关文章:

  • SQL Server 实战 - 多种连接
  • 【手术显微镜】市场高度集中,由于高端手术显微镜的制造技术主要掌握于欧美企业
  • IDEA 2024 配置Maven
  • Admin.NET框架使用宝塔面板部署步骤
  • Flutter中的Future和Stream
  • 107.【C语言】数据结构之二叉树求总节点和第K层节点的个数
  • spring boot支持那些开发工具?
  • Go-MediatR:Go语言中的中介者模式
  • 5.11【机器学习】
  • 在 CentOS 上安装 Docker:构建容器化环境全攻略
  • Python练习(2)
  • 如何实现一套键盘鼠标控制两台计算机(罗技Options+ Flow功能快速实现演示)
  • 现代应用程序中基于 Cell 架构的安全防护之道
  • 【导航查询】.NET开源 ORM 框架 SqlSugar 系列
  • 【基础分析】——Qt 信号和槽的机制 优点
  • Vue3学习宝典
  • leecode96.不同的二叉搜索树
  • 树莓派基本配置-基础配置配置
  • 手机卡限速丨中国移动5G变3G,网速500kb
  • SpringCloud之OpenFeign:OpenFeign与Feign谁更适合你的SpringCloud项目?
  • yt6801 ubuntu有线连接驱动安装
  • 算法日记 36-38day 动态规划
  • hdlbits系列verilog解答(Dff16e-同步复位上升沿16位触发器)-85
  • HTTPTomcatServlet
  • IDEA连接Apifox客户端
  • Linux的奇妙冒险——进程PCB第一讲
  • 阿里巴巴热土计划企划金:点燃贫困地区可持续发展的希望之火
  • 2-6 C浮点数指针运算案例
  • 开源的跨平台SQL 编辑器Beekeeper Studio
  • 07《缓存》计算机组成与体系结构 系列课