界面代码:
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)