1. RV1106这块板子为什么会成为视频捕获的首选
做嵌入式视频开发这些年,我经手过不少方案:海思的Hi3516系列、君正的T系列、全志的V系列,各有各的脾气。去年因为一个户外低功耗视频终端的项目,我拿到了瑞芯微的RV1106,老实说,一开始没抱太大期望——这颗料看起来就是一颗IPC专用SoC,规格表不花哨,参数也不算激进。但真正把H264视频流捕获和编码的完整流程跑通之后,我发现自己对这颗芯片的判断有些保守了。
先说说RV1106在视频链路里到底扮演什么角色。它是一颗专门面向视觉处理的应用处理器,内部集成了自研的ISP和H264/H265硬件编码器,也带了一个不错的NPU。你如果只把它当成一颗"能跑Linux的MCU"来看,那就浪费了它最核心的价值——它真正擅长的事情是:接收摄像头sensor的原始图像数据,经过ISP处理,再通过硬件编码器压缩成H264码流。整个过程中,CPU几乎不需要参与像素级计算,这让CPU可以腾出大量算力去做业务逻辑,比如跑AI算法、处理网络协议栈、管理存储。
我实测下来,RV1106的H264编码能力在1080p@60fps级别跑得很稳,如果只要求1080p@30fps,CPU占用率可以压得很低。对于大多数视频流捕获场景,比如网络摄像头、工业视觉终端、车载记录仪,这个性能储备是足够的。而且这颗芯片的封装和功耗控制做得不错,在低功耗场景下比很多同类方案有优势,单板甚至可以靠PoE供电直接跑完整套视频链路。
不过说实话,RV1106的软件生态和它的硬件能力有一定差距。官方SDK的文档比较"开发板风格",很多细节要靠自己去读源码和寄存器手册。这篇文章我就把从零开始搭建RV1106视频流捕获与H264编码链路的完整流程写出来,附带我踩过的坑和验证过的参数配置,给正在调研这块板子的人一个参考。
适合读这篇文章的人:
- 正在评估RV1106作为视频产品主控的硬件工程师或嵌入式工程师
- 已经拿到开发板,但不知道从哪里开始跑通视频链路的入门者
- 想了解H264硬件编码器实际工程配置的开发者
不适合读这篇文章的人:没有Linux和C语言基础,想通过图形化界面点一点就完成开发的朋友。RV1106的整个开发流程还是命令行为主,SDK也是Linux体系下的工具链。
2. 环境搭建与开发板初始化:最容易卡住的三道门槛
2.1 SDK选型:用哪个版本决定你后面少踩多少坑
RV1106的SDK在瑞芯微的官方仓库里通过repo方式管理,名字叫luckfox-pico,因为瑞芯微官方有对应的Luckfox Pico开发板。我第一次拉代码的时候就遇到了这里的一个坑:repo工具需要Python 2.7环境,但当前系统默认的Python已经是3.x了,直接执行repo init会报语法错误。
我的解决方法是直接在用户目录下建一个Python 2.7的虚拟环境,专门用来执行repo工具。这个做法在老版本SDK上很管用,新版的SDK(2024年之后的master分支)已经解决了Python 3的兼容问题,所以如果你现在拉代码,建议直接拉最新的release分支,不要用老版本,否则后面编译工具链也会有一堆兼容性麻烦。
SDK拉下来之后,整个目录结构大概是这样:
sdk/ ├── kernel/ # Linux内核源码(5.10版本) ├── u-boot/ # 引导加载程序 ├── buildroot/ # 根文件系统构建系统 ├── app/ # 板级应用示例 ├── tools/ # 烧录工具、交叉编译工具链 ├── output/ # 编译产物这里有个经验之谈:核心开发阶段,尽量不要改动kernel和u-boot的默认配置。RV1106的SDK默认配置是经过官方验证的,能跑通大多数基础功能。贸然去裁剪内核或者调整DTS(设备树),很容易引入视频帧中断丢失、编码器时钟频率异常这类疑难杂症。
2.2 交叉编译环境的三个隐藏坑
RV1106用的是arm-rockchip830-linux-uclibcgnueabihf这套工具链,跟常见的arm-linux-gnueabihf有一些细微差别。这套工具链是Buildroot定制的,所以它的glibc/uclibc版本和系统库路径跟Ubuntu自带的交叉编译工具链不一样。如果你图省事直接用Ubuntu的gcc-arm-linux-gnueabihf编译应用程序,可能会出现编译通过、板子上跑不起来,或者运行报错说缺libgcc库的情况。
我的建议是:SDK里自带的tools/linux/toolchain目录下已经准备好了工具链,把这个路径加到PATH里,不要自己去装新的交叉编译器。同时要注意工具链的名称带uclibc,意味着板子上的根文件系统是精简过的,很多动态库依赖和宿主机不同,编译时要加-static或者显式链接你需要的库,不然上板执行会报symbol找不到。
还有一个小细节:SDK的Buildroot默认把stripped过的二进制打包到根文件系统里,所以如果你要gdb调试,记得在编译应用时关掉-O2优化(用-Og),并且不要strip。这样调试体验会好很多。我一开始图省事没关优化,结果在gdb里看变量全是优化后的假值,排查了一个下午。
2.3 烧录与启动:从SD卡到SPI Nor的差异
RV1106支持从SD卡、SPI Nor Flash、EMMC三种介质启动。开发调试阶段,我强烈建议用SD卡启动,因为替换内核和根文件系统都很方便,只要把SD卡拔下来插到电脑上重新分区拷贝就行。而SPI Nor启动每次烧录都要用瑞芯微的RKDevTool工具,开发模式下频繁烧录很容易把Flash的寿命和扇区擦写磨损搞掉一截。
SD卡启动的准备步骤说起来不复杂,但第一次操作容易搞混分区:
- 先用SDK里的打包脚本生成update.img,再解包出boot.img和rootfs.img
- 把SD卡分成两个分区,第一个分区放boot.img(内核+dtb),第二个分区放rootfs.img
- 把分区表标记为可启动,插卡上电
启动之后,确认系统起来了,先用cat /proc/cpuinfo和cat /proc/meminfo看一眼系统状态。接下来就是本文的核心——视频流捕获与编码。
3. 视频捕获链路拆解:从sensor到内存的完整旅程
3.1 sensor选型与DTS配置的对应关系
RV1106的Camera接口支持DVP和MIPI CSI两种输入方式。我用的是SC3336这颗sensor,它是一颗200万像素、1/2.7英寸的CMOS图像传感器,输出RAW10格式,通过MIPI CSI-2接口连接。SC3336在RV1106 SDK里已经内置了驱动,所以DTS配置相对简单,只需要在board dts里把对应的sensor节点使能,并配置I2C地址和MIPI通道数。
DTS里有一个关键参数是sensor的link-freq和pixel-rate,这两个值必须和sensor的驱动代码一致。如果配错了,sensor初始化会失败,或者采集出来的图像是花屏、绿屏。我的经验是:直接用SDK自带的面板配置文件(rk1106-bb.dts里的ov5647节点改参数),不要从零自己写节点。SC3336和OV5647的寄存器配置逻辑不同,但DTS框架可以复用,只需要改I2C地址和reset引脚的GPIO编号。
&i2c2 { status = "okay"; clock-frequency = <400000>; sc3336: sc3336@30 { compatible = "smartsens,sc3336"; reg = <0x30>; pinctrl-names = "default"; pinctrl-0 = <&csi_pwdn>; reset-gpios = <&gpio2 RK_PB5 GPIO_ACTIVE_LOW>; pwdn-gpios = <&gpio2 RK_PB4 GPIO_ACTIVE_HIGH>; rockchip,camera-module-index = <1>; rockchip,camera-module-facing = "back"; rockchip,camera-module-name = "default"; rockchip,camera-module-lens-name = "default"; port { sc3336_out: endpoint { remote-endpoint = <&csi2dphy1_input>; >MppEncCfg cfg; mpp_enc_cfg_init(&cfg); mpp_enc_cfg_set_s32(cfg, "prep:width", width); mpp_enc_cfg_set_s32(cfg, "prep:height", height); mpp_enc_cfg_set_s32(cfg, "prep:hor_stride", width); mpp_enc_cfg_set_s32(cfg, "prep:ver_stride", height); mpp_enc_cfg_set_s32(cfg, "prep:format", MPP_FMT_NV12); mpp_enc_cfg_set_s32(cfg, "rc:mode", MPP_ENC_RC_MODE_CBR); // 或VBR mpp_enc_cfg_set_s32(cfg, "rc:bps", width * height * 4); // 目标码率 mpp_enc_cfg_set_s32(cfg, "rc:bps_max", width * height * 8); mpp_enc_cfg_set_s32(cfg, "rc:bps_min", width * height * 2); mpp_enc_cfg_set_s32(cfg, "codec:type", MPP_VIDEO_CodingAVC); // H264这里最关键的是hor_stride和ver_stride。它们不是简单的width和height,而是sensor输出时每行像素的align值。RV1106要求stride按16字节对齐(有些平台要求64字节),如果你的width是1920,1920本身已经是16的倍数,但是如果分辨率是1080×1920这种竖屏产品,你用1080作为stride而不做对齐,编码器输出的码流就会花屏。正确做法是:
int aligned_w = (width + 15) / 16 * 16; int aligned_h = (height + 1) / 2 * 2;第一个stride用于NV12的Y平面,ver_stride其实对应的是uv缓冲区的行数对齐。记得把这两个值传给编码器,而不是直接传分辨率。
4.2 码率控制模式:CBR还是VBR,别拍脑袋
码率控制是H264编码里很影响产品体验的一个模块。RV1106的硬件编码器支持CBR(固定码率)和VBR(可变码率)两种模式,还支持CQP(固定量化参数)模式。
- CBR模式:目标码率固定,适合网络传输带宽受限的场景(比如RTSP推流到公网),码率波动小,但画面复杂度高时会出现质量下降。
- VBR模式:允许码率在设定范围内波动,复杂场景可以临时拉高码率保证质量,适合本地录存储,文件不会因为复杂画面产生明显失真。
- CQP模式:固定QP值,不关心码率大小,适合项目调试阶段观察原始编码质量,不适合产品发布。
我的一个项目做的是双码流:主码流用CBR 4Mbps推RTSP,子码流用VBR 512Kbps做本地录像。主码流保证网络流畅,子码流保证本地文件不至于在暗光场景下糊成一团。这里要提醒的是,CBR模式下如果你设置的码率远低于场景所需,编码器会强制丢细节,画面会出现"马赛克块状物",这是正常现象,不要误以为编码器硬件坏了。如果需要诊断码率设置是否合理,可以直接统计每帧的编码字节数,与目标对比。
// 编码帧回调里统计 if (packet->len > target_frame_bytes * 1.5) { printf("warning: frame too large, idr=%d size=%d\n", packet->is_intra, packet->len); }还有一个细节:GOP(Group of Pictures)长度。如果你做的是低延时视频流传输,I帧间隔设置过大会导致关键帧等待时间过长;设置过小虽然拉流快,但码率会被拉高。我的默认配置是GOP=2×fps,也就是2秒一个I帧,大部分场景够用了。如果做的是监控存储类产品,GOP可以放到4秒甚至更长,因为存储场景对关键帧频繁程度不敏感,码率更宝贵。
4.3 编码循环:把V4L2帧送入MPPI的零拷贝思路
把V4L2采集到的NV12帧送进编码器,这里有一个"零拷贝"的优化空间值得注意。
V4L2采集到的是内核空间的DMA buffer,MPPI编码器需要的输入也是物理内存地址。如果你把每个采集帧都memcpy到用户空间一块普通内存里,再交给编码器,那么每一帧会多出两次拷贝操作——一次从内核buffer拷贝到用户空间,一次从用户空间拷贝到编码器输入。1080p@30fps下,每帧3.1MB的数据量,两次拷贝对CPU的带宽占用是3.1MB×30×2=186MB/s,这个数字在一些低主频的CPU上会让CPU占用率直接飙到40%以上。
RV1106的V4L2驱动支持通过DMA_BUF导出缓冲区(VIDIOC_EXPBUF),MPPI可以通过传递fd的方式直接引用这块物理内存,从而实现零拷贝。整个流程变成:
- V4L2申请缓冲区时,用VIDIOC_EXPBUF导出对应的dma-buf fd
- 将fd告诉MPPI的MppBuffer,作为编码器输入
- V4L2把采集出的帧放入queue,MPPI直接从对应fd读取数据编码
这样CPU几乎不参与图像数据的搬运,CPU占用率可以控制在5%以内。早期我图省事直接mmap+V4L2拷贝,1080p@30fps下CPU占用率在40%左右,后来改成dma-buf零拷贝,降到3%~5%,这个优化对整机功耗和稳定性影响非常大。
实现零拷贝的步骤有几个细节:
- VIDIOC_EXPBUF需要内核驱动支持,RV1106的V4L2驱动默认支持
- MPP的buffer需要通过MPP_BUFFER_DMA类型分配,并且用mpp_buffer_import传入外部fd
- 开发过程中如果遇到"buffer busy"或编码帧卡住的情况,大概率是buffer生命周期管理问题,需要确保V4L2的QBUF和MPPI的编码入队操作严格顺序化
5. 码流处理与推流:本地存储和RTSP消息流方案实战对比
5.1 H264码流的正确打包:别把裸流直接塞进文件里
编码器输出的是一段一段的H264原始码流(Annex B格式),带有起始码(00 00 00 01)和多个NAL单元。如果直接把这个裸流按顺序写入文件,虽然可以用ffplay直接播放(ffplay能自动解析裸流),但文件没有时间戳索引、没有封装,无法做定位和切片。
正常做法是把H264裸流封装进MP4或FLV容器。RV1106 SDK的app目录下有一个mpp_enc_test例子,它输出的就是裸流文件。要存储成MP4,有两种方案:
- 用FFmpeg库在应用层封装
- 用SDK自带的Muxer模块(瑞芯微有封装MP4的库)
FFmpeg方式更通用,功能完整,但需要裁剪库体积、处理可能的license问题。我推荐用SDK自带的Muxer,至少对RV1106平台优化过。下面的代码是MPP Muxer模块封装MP4的关键流程:
MppMuxer* muxer = NULL; MppMuxerCreate(&muxer); MppMuxerConfig config = { .type = MPP_MUXER_TYPE_MP4, .filename = (const char*)out_path, }; mpp_muxer_config(muxer, &config); // 每次编码返回一个packet MPP_RET ret = mpp_muxer_write(muxer, packet);这个模块内部会解析H264的SPS/PPS和I帧信息,自动生成MP4的moov box。唯一需要注意的是,MP4封装要求知道总时长或者使用fmp4模式,如果做的是流式录制(录制时间不定长),建议用fragmented MP4(fMP4),这样即使录制中断,之前的视频片段也完整可播放。
5.2 自己写一个轻量RTSP推流:什么时候值得做
项目需要把实时视频流送到局域网客户端查看,最常见的方案就是RTSP推流。市面上的选项无非是:
- 在RV1106上跑一个Live555
- 在RV1106上跑一个GStreamer的RTSP服务
- 在RV1106上用一个现成的RTSP服务器二进制
但这些方案都比较重。Live555体积不小,GStreamer更是重量级,RV1106的Flash资源和内存资源并不宽裕。而且这些方案引入的依赖多了,维护起来也是负担。所以,如果产品形态比较简单(没有多路并发需求),自己实现一个极简RTSP服务器模块是完全可行的。
RTSP协议本身不复杂,核心是RTSP信令(HTTP风格)+ RTP承载H264码流。H264在RTP中打包要符合RFC3984规范,I帧要拆分成FU-A分片,P帧如果小于MTU(通常1400字节)则直接单包发送。编码器输出的H264帧很大,一个1080p的I帧可能达到100KB,必须分片。
自己实现时,优先级最高的是一个H264 NAL拆包器。从MPP拿到的packet是一整帧的码流,内部可能包含多个NAL(如SPS/PPS/SEI/SLICE),你需要遍历NAL,根据类型做分类:
- NAL type=7(SPS)和type=8(PPS),通过RTSP的sdp描述(sprop-parameter-sets)发送给客户端
- NAL type=5(IDR)和type=1(非IDR slice),通过RTP打包发送
一个简化版的NAL切分逻辑可以这样写:
static void clip_h264_nal(const void* data, size_t len) { const uint8_t* p = data; size_t offset = 0; while (offset < len) { // 找起始码 if (p[offset] == 0 && p[offset+1] == 0 && p[offset+2] == 1) { // 前一个NAL结束 } } }这里有一个很多人忽略的细节:MPP输出的H264 packet有时是分片的(一个packet只包含部分NAL单元),有时是完整帧。调试RTSP丢包、花屏问题时,先确认对端拿到的码流是正确的,不一定要怀疑网络问题。
5.3 本地RTSP服务器测试工具的选择
在没有自研RTSP之前,我评估过网上几个能在RV1106上跑的现成工具。实测下来有一个轻量方案值得推荐:mediamtx(原rtsp-simple-server),它是一个Go编译的单一二进制,交叉编译到ARM Linux非常容易,运行内存占用很低,支持RTSP推拉流,还支持WebRTC转推。用它可以快速把RV1106编码出的H264流推起来,方便在局域网内用VLC等工具预览验证。
使用方法很简单:
- 在RV1106上以rtsp地址做推流端,把编码器输出的H264裸流通过FFmpeg或自研程序以RTSP方式推到mediamtx监听的端口
- 局域网内的客户端用VLC打开rtsp://192.168.x.x:8554/stream直接预览
我自己写了一个小工具,从MPP拿到的packet通过RTSP库推流到mediamtx,整体延迟大约300ms以内(无线环境),稳定性不错。在项目早期,这个方案能帮我快速验证编码链路和画质,等业务成熟后,再把真正产品化的播放逻辑放进去。
下面是我实测过的几种工具搭配:
| 工具 | 体积 | 内存占用 | 交叉编译难度 | 适用场景 |
|---|---|---|---|---|
| mediamtx | 约50MB | 约20MB | 低(Go交叉编译简单) | 开发验证、原型测试 |
| Live555 | 约200MB(含依赖) | 约40MB | 中 | 需要稳定成熟的RTSP库时 |
| GStreamer + rtspsrc | 约300MB | 约80MB | 高 | 需要完整的媒体处理管线 |
| 自研简易RTSP | 约50KB | 约1MB | 低 | 产品落地,控制体积和依赖 |
6. 性能优化与实际项目踩坑记录
6.1 CPU占用率优化:从40%到5%的三个步骤
前文提到零拷贝把CPU占用率大幅降下来,这是第一大步。但完整的优化链路不止这一处。我整理三个实际操作中最有效的优化点:
第一,关闭V4L2采集线程的CPU调频策略,优先绑定到固定CPU核心。RV1106有双核A7,默认内核调度会在两个核之间来回迁移线程,迁移带来的cache失效对视频缓冲区的操作很不友好。我在采集线程里设置了sched_setaffinity,把采集线程绑定在CPU0,编码线程绑定在CPU1,中断响应也做了对应调整。这个改动之后,画面的丢帧率明显降低,而且CPU调度延迟不再导致偶发的"卡一顿"。
第二,用DPDK思路优化内存分配:预分配、复用,避免在热路径上频繁malloc/free。V4L2缓冲区本身是预分配的,编码器的packet buffer也需要预分配。MPP的mpp_buffer_get接口支持从buffer group里申请,申请后可复用,不释放。我在初始化阶段一次性申请了5个编码输入buffer和5个packet buffer,之后整个采集编码循环里不再调用任何malloc。这样做除了减少开销,更重要的是避免长时间运行后内存碎片化,对7×24小时连续运行的设备来说,内存碎片化是隐性杀手。
第三,降低编码器的延迟,而不是盲目追求码率。视频系统的"端到端延时"由三部分组成:sensor曝光时间+ISP处理时间+编码器延迟+网络传输延迟。编码器本身存在帧级延迟(frame delay),通过MPP可以设置是否开启"低延迟模式"(low delay P帧),虽然会在一定程度上降低压缩率,但对交互型视频应用(比如无人机图传、远程遥控)来说,延迟降低的收益远大于码率增加的成本。RV1106的编码器低延迟模式我实测过,可以降低约一个帧周期(33ms),代价是码率上升约15%。具体取舍看业务场景。
6.2 常见问题排查:画面花屏、卡顿、RTSP无法拉流的定位思路
这里记录几个我在RV1106上真实遇到、排查了很久的问题,希望后来者少走弯路:
问题A:编码器输出的码流播放时画面间歇性花屏,且每次花屏都伴随I帧
排查过程:一开始怀疑编码器参数配置错误,反复调整比特率、GOP长度,无效。后来把编码器的原始码流保存到本地文件,用ffprobe逐帧分析,发现花屏时间点对应的NCU单元数量异常,进一步查发现V4L2采集到的那一帧本身就不是完整帧——是因为ISP在输出时遇到了帧同步问题,导致缓冲区里写入了一半新帧一半旧帧,编码器并不知道,照常编码,就产生了一个"完整但不一致"的错误帧。
修复方案:在V4L2采集侧增加帧同步锁,保证每次读出的缓冲区是完整一帧;同时在应用层对采集帧数做计数,如果两次V4L2_DQBUF间隔异常(明显大于1/fps),丢弃导致的问题帧,不让它进入编码器。加上之后,花屏问题基本不再出现。
问题B:长时间运行后,编码器输入队列阻塞,画面卡在最后一帧
排查过程:跑720p@30fps连续运行48小时后,画面突然冻结。看内核日志,发现编码器的中断频率异常,且进程状态是D状态(不可中断睡眠),跟踪到是编码器在等一个buffer释放,而这个buffer被应用层拿着没有归还。原因是应用代码里有个分支:当网络断连时,推流模块抛异常,导致编码线程的写buffer流程中断,没有调用mpp_buffer_put。
修复方案:在编码线程的外层while循环里加try-catch逻辑,确保无论网络如何,编码buffer都会归还到MPP缓冲池。同时给编码线程加上喂狗机制:如果连续10秒没有成功编码出一帧,自动复位编码器,防止系统在跑飞后彻底卡死。
问题C:通过mediamtx推流后,VLC首帧黑屏,过几秒才出画面
排查过程:VLC播放RTSP时,需要等待SPS/PPS和第一个I帧才能开始解码。如果RTSP服务器在推流时,把SPS/PPS信息只放在RTSP DESCRIBE响应里,而客户端没有正确解析,就会一直等。此外,如果视频源不做循环发送SPS/PPS,新连接的客户端只有等下一个I帧到来才能看到画面。
修复方案:在RTP传输中,周期性插入SPS/PPS NAL单元(比如每2秒一次),或者在每个IDR帧前面强制附带SPS/PPS。这个操作在自研RTSP里加上不难,但对于使用现成库的朋友,标准做法是设置sprop-parameter-sets参数,并要求推流程序定期发送。
6.3 帧率统计与丢帧检测:让设备真正可运维的细节
视频设备的稳定性不能靠感觉,要有数据支撑。我在RV1106的主循环里加了三组统计指标:
- V4L2采集帧率:实际每秒从sensor拿到的帧数,反映相机链路健康度
- 编码器帧率:每秒实际编码成功的帧数,反映编码链路健康度
- 丢帧数:采集到但未编码成功的帧数(可以统计v4l2 buffer溢出次数)
这些指标通过一个简单的共享内存结构体暴露给外部管理接口,我在Linux里写了一个watchdog脚本,每60秒读取一次指标,如果发现连续多次编码帧率为0,自动重启应用并记录错误日志。有了这套机制,即使设备在无人值守的环境运行,也能快速通过日志远程定位问题。
统计代码很简单,核心就是两个原子计数器:
static atomic_t v4l2_frame_count; static atomic_t enc_frame_count; void v4l2_capture_thread(void) { while (1) { // dequeue frame atomic_inc(&v4l2_frame_count); } } void encoder_thread(void) { while (1) { // encode packet atomic_inc(&enc_frame_count); } }这些计数器的精度不需要太高,够判断链路是否存活即可。
7. 一些个人建议:开发RV1106视频链路时的整体思路
最后分享几点实际的开发经验。
第一,把视频链路拆成三个独立模块来开发:采集、编码、推流/存储。三个模块之间用清晰的数据灌接口(环形队列或者MPP buffer直接传递)衔接。这样做的好处是调试时可以单独替换任何一个模块,不影响其他测试。例如编码有问题,可以直接用SDK自带的mpp_enc_test喂一个静态图,并不需要先把sensor配好。
第二,在前期就用真实的sensor和镜头跑通完整链路,不要只用测试图调试。很多画质问题(暗角、偏色、噪点)都是sensor和镜头模组引入的,测试图检测不出来这些。
第三,不要忽视电源设计。RV1106在进行硬件编码时瞬时功耗会增加约0.5W,如果供电设计不够强壮,会出现sensor图像闪烁、编码器偶发crash。我早期在一套面包板上跑的时候经常莫名其妙掉帧,后来确认是3.3V供电被拉垮所致,换用DC-DC模块独立供电后稳定了很多。
第四,把日志系统当成产品一部分来设计。RV1106的编码链路涉及sensor驱动、ISP、编码器驱动、设备树、MPP库、应用层,任何一个环节出问题,日志分离不清就无法定位。建议给日志加上模块前缀和级别过滤,线上设备只打印error,开发设备打印debug。我习惯在应用层启动时打印一个版本字符串,包含SDK commit hash,线上出问题能立刻知道跑的是哪个版本的代码。
RV1106的H264视频流捕获与编码链路,整体上手难度中等,但硬件编码器一旦跑通,性能表现相当扎实,在低功耗和性价比上很能打。如果你正在用这颗料做产品原型,我建议把前两周的时间主要花在SDK编译和基础环境上,一旦环境跑通,视频链路反而比预想的更顺利。
最终,如果你也跑通了同样的链路,欢迎交流具体的参数配置和粒子优化方式。视频开发这条路,细节永远比你想的多,但每解决一个问题,对这套系统的理解就更深一层。