开源:Air8101 硬件平台 RTMP 视频推流实现
近期有行业同行咨询是否存在基Ar8101的RTMP推流方案这里明确说明该方案已开源可直接参考使用。Air8101是支持2.4G WIFI6和蓝牙的 WiFi SoC最大支持 200W 像素的静态图像拍照支持1024*720分辨率的10寸屏显示同时兼容DVP/USB摄像头即插即用支持多路视频采集及RTMP推流功能。本文将以Air8101核心板与AirCAMERA_1030摄像头配件板为硬件示例详细演示如何基于LuatOS和合宙音视频平台快速搭建USB摄像头实时推流应用为视频上云部署提供技术参考。一、主要硬件准备为确保方案顺利部署请提前准备以下关键硬件Air8101核心板USB摄像头配件板AirCAMERA_1030[TYPE-C数据线用于供电及固件烧录调试Win10及其以上PC电脑接线方式如下Air8101核心板通过Type-C USB口供电核心板正面的拨码开发拨到5V一端背面的功耗测试开关拨到OFF一端AirCAMERA_1030直插在Air8101核心板上。USB HUB可选接入多路摄像头时使用AirCAMERA_1030 配件板 Air8101 核心板硬件连接示意图单路摄像头链接方式四路摄像头链接方式 如图所示将四路 USB 摄像头接入 HUB 中然后将 HUB 通过 USB 口连接到 Air8101 核心板上;二、开源示例RTMP 的主要特点为低延迟、协议兼容性较好在直播传输、安防视频监控、远程设备视频巡检等对实时性有要求的物联网应用场景中较为常用。设备可通过 RTMP 协议进行推流实现音视频数据的实时传输终端设备如手机、PC 可直接接收并实时播放画面无需等待文件录制完成后再进行上传。本示例基于Air8101核心板与AirCAMERA_1030配件板实现USB摄像头的RTMP实时推流。2.1 RTMP业务逻辑订阅IP_READY信息确认联网后执行RTMP推流任务获取RTMP推流地址通过http.request()请求从服务器获取推流地址初始化摄像头excamera.open()初始化USB摄像头RTMP推流excamera.rtmp()确保摄像头状态正常然后rtmpc:start()开始推流逻辑监控推流状态循环监控推流过程每20秒打印一次内存信息。处理异常情况推流异常时发送RECONNECT_RTMP信息然后根据重连函数进行重连释放资源推流结束时excamera.close()关闭摄像头释放资源。核心代码如下完整demo详见源码仓库最新文件本文件为USB摄像头RTMP推流功能模块核心业务逻辑为1. USB 摄像头初始化、帧率配置与H264视频编码2. 通过HTTP请求获取RTMP推流地址3. 连接RTMP服务器并进行视频推流-- 引入excamera扩展库localexcamerarequire(excamera)localRTMP_TASK_NAMErtmp_app_task-- RTMP任务名称-- HTTP请求获取RTMP服务器地址函数localfunctionrtmp_http_request()localget_device_idnetdrv.mac(socket.LWIP_STA)-- Air8101用STA MAC作为设备IDlog.info(打印设备的ID号,get_device_id)localurlhttp://video.luatos.com:10030/api-system/deviceVideo/get../..get_device_id log.info(打印的URL,url)localcamera_header{[Accept-Encoding]identity,[Host]video.luatos.com:10030,[Content-Type]application/json}localpost_body{deviceAccess8,-- 8 代表接入方式为RTMPdeviceUseradmin,-- 平台录像机设置的设备用户不是登录用的用户名devicePsdAir123456-- 平台录像机设置的设备密码不是登录用的密码}-- 发送POST请求并等待响应localcode,headers,bodyhttp.request(POST,url,camera_header,json.encode(post_body)).wait()log.info(打印的请求code,code)ifcode~200thenlog.error(HTTP请求失败)returnfalse,nilendlog.info(打印的请求body,body)localjson_bodyjson.decode(body)ifnotjson_bodyorjson_body.code~200thenlog.error(请求视频URL失败,json_bodyandjson_body.msgor未知错误)returnfalse,nilendlocalrtmp_urljson_body.data.urlList[1]log.info(请求得到的RTMP地址,rtmp_url)ifnotrtmp_urlthenlog.error(未获取到RTMP地址)returnfalse,nilendreturntrue,rtmp_urlendlocalg_s_rtmp_state-- RTMP状态回调函数-- 连接过程中如果连接失败state状态依次为STATE_IDLE-STATE_DISCONNECTING-STATE_IDLE-STATE_ERROR-- 已经建立了连接推流过程中如果本地调用disconnect接口state状态依次为STATE_IDLE-STATE_DISCONNECTING-STATE_IDLE-- 已经建立了连接推流过程中如果网络或者服务器出现了异常或者本地发送数据出现了异常state状态依次为STATE_IDLE-STATE_DISCONNECTING-STATE_IDLE-STATE_ERRORlocalfunctionrtmp_state_callback(state)-- 打印RTMP状态变化基础日志log.info(rtmp_state_callback state,state)-- 根据不同状态执行对应逻辑ifstatertmp.STATE_IDLEthenlog.info(空闲状态可能和推流时效有关需要等待一段时间再尝试重连)ifg_s_rtmp_statertmp.STATE_DISCONNECTINGthensys.sendMsg(RTMP_TASK_NAME,RTMP_EVENT,DISCONNECTED)endelseifstatertmp.STATE_CONNECTINGthenlog.info(正在连接)elseifstatertmp.STATE_HANDSHAKINGthenlog.info(握手中)elseifstatertmp.STATE_CONNECTEDthenlog.info(已连接)sys.sendMsg(RTMP_TASK_NAME,RTMP_EVENT,CONNECTED)elseifstatertmp.STATE_PUBLISHINGthenlog.info(推流中)elseifstatertmp.STATE_DISCONNECTINGthenlog.info(正在断开)elseifstatertmp.STATE_ERRORthenlog.info(错误)endg_s_rtmp_statestateend-- RTMP main task 的任务处理函数localfunctionrtmp_task()localcamera_opened,msg,rtmpc,success,rtmp_urlwhiletruedo-- 1. 如果当前时间点设置的默认网卡还没有连接成功一直在这里循环等待whilenotsocket.adapter(socket.dft())dolog.warn(rtmp_task,wait IP_READY,socket.dft())-- 在此处阻塞等待默认网卡连接成功的消息IP_READY-- 或者等待1秒超时退出阻塞等待状态;-- 注意此处的1000毫秒超时不要修改的更长-- 因为当使用exnetif.set_priority_order配置多个网卡连接外网的优先级时会隐式的修改默认使用的网卡-- 当exnetif.set_priority_order的调用时序和此处的socket.adapter(socket.dft())判断时序有可能不匹配-- 此处的1秒能够保证即使时序不匹配也能1秒钟退出阻塞状态再去判断socket.adapter(socket.dft())sys.waitUntil(IP_READY,1000)end-- 检测到了IP_READY消息log.info(rtmp_task,recv IP_READY,socket.dft())-- 清空此task绑定的消息队列中的未处理的消息sys.cleanMsg(RTMP_TASK_NAME)-- 2. HTTP请求获取RTMP服务器地址success,rtmp_urlrtmp_http_request()ifnotsuccessthenlog.error(获取RTMP地址失败)gotoEXCEPTION_PROCend-- 3. 配置摄像头camera_openedexcamera.open({idcamera.USB,sensor_width1280,sensor_height720,usb_port1})ifnotcamera_openedthenlog.error(摄像头初始化失败)gotoEXCEPTION_PROCend-- 启动摄像头log.info(启动摄像头...)ifnotexcamera.rtmp()thenlog.error(无法启动摄像头)gotoEXCEPTION_PROCend-- 创建RTMP客户端rtmpcrtmp.create(rtmp_url)ifnotrtmpcthenlog.error(rtmp.create,创建RTMP客户端失败)gotoEXCEPTION_PROCendlog.info(rtmp.create,RTMP客户端创建成功)-- 设置RTMP状态回调rtmpc:setCallback(rtmp_state_callback)-- 连接RTMP服务器log.info(开始连接RTMP服务器...)successrtmpc:connect()ifnotsuccessthenlog.error(连接RTMP服务器失败)gotoEXCEPTION_PROCend-- 推流状态的处理调度逻辑whiletruedo-- 等待消息msgsys.waitMsg(RTMP_TASK_NAME,RTMP_EVENT)ifmsgthenlog.info(rtmp_task waitMsg,msg[2],msg[3],msg[4])-- 连接成功ifmsg[2]CONNECTEDthen-- 直接启动推流不检查返回值log.info(准备开始推流)rtmpc:start()log.info(推流已启动)-- 连接失败/连接断开elseifmsg[2]DISCONNECTEDthenbreak-- 需要主动关闭连接-- 用户需要主动关闭rtmp连接时可以调用sys.sendMsg(RTMP_TASK_NAME, RTMP_EVENT, CLOSE)elseifmsg[2]CLOSEthen-- 主动断开rtmp client连接rtmpc:disconnect()endendend-- 出现异常::EXCEPTION_PROC::-- 清空此task绑定的消息队列中的未处理的消息sys.cleanMsg(RTMP_TASK_NAME)-- 5. 关闭推流log.info(推流结束开始释放资源)-- 关闭摄像头ifcamera_openedthenexcamera.close()log.info(excamera已关闭)end-- 关闭RTMP客户端ifrtmpcthenrtmpc:stop()log.info(RTMP推流已停止)rtmpc:disconnect()log.info(RTMP连接已断开)rtmpc:destroy()log.info(RTMP客户端已销毁)end-- 确保所有状态重置log.info(所有资源已释放5秒后重连)-- 5秒后跳转到循环体开始位置自动发起重连sys.wait(5000)endendlocalfunctionwifi_sta_func(evt,data)-- evt 可能的值有: CONNECTED, DISCONNECTED-- 当evtCONNECTED, data是连接的AP的ssid, 字符串类型-- 当evtDISCONNECTED, data断开的原因, 整数类型log.info(收到STA事件,evt,data)ifevtDISCONNECTEDthensys.sendMsg(RTMP_TASK_NAME,RTMP_EVENT,DISCONNECTED)endend-- 内存检查函数localfunctionmemory_check()whiletruedo-- 等待20秒sys.wait(20000)-- 打印系统内存使用信息log.info(系统内存使用情况,rtos.meminfo(sys))-- 打印Lua虚拟机内存使用信息log.info(Lua虚拟机内存使用情况,rtos.meminfo(lua))endend-- wifi的STA相关事件sys.subscribe(WLAN_STA_INC,wifi_sta_func)-- 运行这个task的处理函数rtmp_tasksys.taskInitEx(rtmp_task,RTMP_TASK_NAME)-- 启动内存检查任务sys.taskInit(memory_check)2.2 RTMP推流功能核心步骤搭建好硬件环境修改rtmp_app.lua中的deviceUser、devicePsd参数修改netdrv_wifi.lua 中的Wi-Fi账号密码;打开main.lua文件中require “rtmp_app”同时注释掉:require “take_photo_http_post”烧录内核固件和相关demo成功后自动开机运行可以看到代码运行结果如下日志中如果出现以下类似打印则说明RTMP推流成功。三、合宙音视频平台查看目前合宙音视频测试平台已开放安卓系统移动端APP下载和PC端浏览器操作。本文以PC端为例支持使用共享账号在线查看合宙挂测设备也支持用户使用合宙IoT账号自主添加配置在线设备。3.1 账号密码账号密码与您的合宙IoT平台账号可通用3.2 新增设备参照下图按步点击注意设备账户密码需与代码中日配置一致。3.3 查看推流视频点击实时视频查看自己设备的推流情况。