赞
踩
最近有个需求是将海康摄像头在浏览器上进行实时显示。
然而海康目前的web接口无法满足我们拥有的设备,主要提到我们的设备不支持websocket取流,故不支持无插件开发,需要用到非常旧的chrome版本,方可使用它们的开发包,而且是有插件开发包。
有技术不求人,自己动手自己做。于是本项目立项,自己取流然后进行显示。*
小主出于napi为官方维护,且对node版本可以自动适配,故选之。
anyway, 本博客主要是简单介绍取流实现这一块用到的napi技术要点。
开发流程简介
接下来你将看到
napi 官网的接口说明: http://nodejs.cn/api/n-api.html
无论何时进行开发,错误的出现是必然的,可能是一时疏忽,亦或是对参数的理解不到位都有可能造成错误的出现,所以获取和分析错误信息的能力非常重要。 根据官方提供的接口 napi_get_last_error_info, 由于每次代码相同,小主对其进一步定义成一个宏定义方便使用。
#define GET_NAPI_ERROR() const napi_extended_error_info* errorInfo; \
status = napi_get_last_error_info(env, &errorInfo); \
if (status == napi_ok) { \
printf("last error info is %s\n", errorInfo->error_message); \
} \
else { \
printf("get last error eror\n"); \
}
如上宏定义,使用时,只需插入 GET_NAPI_ERROR()
即可打印出出错信息。
其中的status,一般是函数开头定义好,专门用来接收napi接口状态的变量。
napi_status status;
获取js参数, 我这边以C++实现的实时预览接口为例,简单介绍一下这一个接口的实现, 一共需要用到的有两个参数, 一个参数作为播放通道号进行传入,另一个参数作为视频流的返回方法——回调函数。
获取js传来的参数列表—— napi_get_cb_info
获取参数信息 ——napi_get_value_string_utf8
napi_value RealPlay(napi_env env, napi_callback_info info){// napi 标准头 napi_value napi_ret; napi_status status; // 变量声明 char strTemp[2] = {}; // 用于接收通道参数 int channelNum = 0; // 用于存储视频通道号 napi_value js_callback; // 用于存储回调函数 size_t argc = 2; // 用于napi接口的传入(我要取多少个参数)传出(实际有多少个参数)参数 napi_value argv[2]; // 得到js传来的所有参数,均为napi_value类型,之后在逐个进行解析 status = napi_get_cb_info(env, info, &argc, argv, NULL, NULL); assert(status == napi_ok); if (argc < 2) { napi_create_int32(env, 302, &napi_ret); // 传入参数过少,直接返回 return napi_ret; } // 至此获取到了传入的所有参数列表 argv. // 解析传入的int参数 begin status = napi_get_value_string_utf8(env, argv[0], strTemp, 2, nullptr); // 这里我直接使用 napi_get_value_int32接口获取不到通道号参数。故转了一下,先获取为char*,再进行char* to int 的转换。 channelNum = atoi(strTemp); // 解析传入的int参数 end // 保存获取到的回调函数 js_callback = argv[1]; // 如果需要直接调用回调函数返回数据,则调用下面的语句 // napi_value arg_ret; // status = napi_create_string_utf8(env, "hello world", NAPI_AUTO_LENGTH, arg_ret); // assert(status == napi_ok); // napi_value global; // status = napi_get_global(env, &global); // assert(status == napi_ok); // status = napi_call_function(env, global, js_callback, 1, arg_ret, nullptr); // assert(status == napi_ok); // ... 其他一些执行语句 return napi_ret; }
js 如何多次调用回调函数呢,基于上面获取到的js_callback
变量进行代码讲述。
接口1:实际调用js函数的执行函数, 具体函数参考如下函数指针进行实现。该函数的参数由napi内部自动传入,相当于napi内部的一个回调。
接口2: napi_call_threadsafe_function该函数在任何需要调用回调的地方调用, 本质上相当于Qt发出调用js函数的信号,告诉接口1,我需要调用js函数,并把data
数据作为js函数的参数返回.
其中参数napi_threadsafe_function func
由接口3提供。
接口3: 根据已经得到的回调函数js_callback
创建napi_threadsafe_function
函数, 创建后就可以在接口2调用了。
首先实现接口1的那个函数,以备后用。
void realPlayThreadSafe_func_callJs(napi_env env, napi_value js_callback, void* context, void* data) {
napi_status status;
napi_value argv[2];
napi_value undefined;
status = napi_get_undefined(env, &undefined);
// 如没必要对data进行处理,则可以直接调用js函数,并传入data参数
status = napi_call_function(env, undefined, js_callback, 2, data, nullptr);
if (status != napi_ok) {
printf("call js call back function failed\n");
GET_NAPI_ERROR();
}
}
之后创建全局js_cb函数。
// 由于需要在其他函数中对js_cb进行调用, 故声明为全局定义. napi_threadsafe_function realPlayCallbackFunc = nullptr; napi_value RealPlay(napi_env env, napi_callback_info info){ // ... 一些其他语句 js_callback = argv[1]; // 开始创建本地 threadsafe 回调函数 napi_value srcCbName; // napi接口需要,暂未明确其目的??,非可选参数 if (napi_create_string_utf8(env, "realpCb", NAPI_AUTO_LENGTH, &srcCbName) == napi_ok) { printf("create callbak source success\n"); } status = napi_create_threadsafe_function(env, js_callback, // napi_value 回调函数 nullptr, srcCbName, 0, 1, nullptr, nullptr, nullptr, realPlayThreadSafe_func_callJs, // 实际的执行单元, 接口1 &realPlayCallbackFunc); // 全局threadsafe函数 if (status == napi_ok) { printf("threadsafe function create success \n"); } else { printf("threadsafe function create failed, ret=%d \n", status); GET_NAPI_ERROR(); } }
至此准备工作完成,找到合适的地方开始调用。
void i_need_call_js( ){
napi_status status;
// ...
int data = 666;
status = napi_call_threadsafe_function(realPlayCallbackFunc, &data, napi_tsfn_nonblocking); // 调用后,将会自动调用接口1的实现方法进一步调用js回调函数。
assert(status == napi_ok);
// ...
}
如果代码看起来不够清晰,希望此图可助你理解。
本次经验分享到此结束,由于网上该部分资料尚未完善,结构基本由博主组织试验而成,如有不足之处还请海涵, 并可在评论区指出以示后人避坑。
有些术语可能不太准确,姑且先这样理解吧。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。