第一章-08-响应类型-JSON格式
2026/5/16 19:31:53
RK3568这颗芯片在视频处理领域确实是个狠角色,我第一次用它做H265编码测试时,1080P@60fps的流畅度直接让我惊掉了下巴。相比传统方案,它最大的优势在于内置的独立NPU和RGA加速模块,这让视频编码不再是CPU的负担。
实测下来,同样的画质下H265比H264节省了40%以上的带宽。举个例子,监控场景中原本需要4Mbps的H264流,用H265只需要2.3Mbps左右。更绝的是它的零拷贝机制——数据从摄像头到编码器全程不经过内存拷贝,延迟能控制在50ms以内。
配置编码参数时要注意几个关键点:
// 关键参数示例 mpp_enc_cfg_set(enc_cfg, "codec:id", "hevc"); mpp_enc_cfg_set(enc_cfg, "rc:mode", "cbr"); // 恒定码率 mpp_enc_cfg_set(enc_cfg, "rc:bps_target", 2500000); // 2.5Mbps mpp_enc_cfg_set(enc_cfg, "rc:fps_in", 60); // 输入帧率 mpp_enc_cfg_set(enc_cfg, "rc:fps_out", 60); // 输出帧率 mpp_enc_cfg_set(enc_cfg, "rc:gop", 60); // 关键帧间隔SRS的HEVC支持是个隐藏宝藏,但配置不当很容易踩坑。我最开始用默认配置推流时,总是遇到花屏问题,后来发现是缺少了关键的HEVC配置:
# hevc.flv.conf 关键配置 listen 1935; max_connections 1000; srs_log_tank file; srs_log_file ./objs/srs.log; http_server { enabled on; listen 8080; dir ./objs/nginx/html; } vhost __defaultVhost__ { h265 { enabled on; } http_remux { enabled on; mount [vhost]/[app]/[stream].flv; hstrs on; } }调试时有个实用技巧:用Wireshark抓包看RTMP握手过程。正常流程应该是:
如果卡在第三步,通常是防火墙问题;如果数据发了但没画面,八成是编码参数不对。
要实现200ms以内的端到端延迟,这几个参数必须死磕:
// 设置低延迟模式 MPP_RET ret = mpi->control(enc_ctx, MPP_ENC_SET_CFG, enc_cfg); ret = mpi->control(enc_ctx, MPP_ENC_SET_LOW_LATENCY, (void*)1);// 计算正确的dts/pts int64_t now = av_gettime() / 1000; pkt->dts = now - start_time; pkt->pts = pkt->dts; if (first_packet) { start_time = now; first_packet = 0; }传统FLV播放延迟在1秒以上,我们改用WebTransport+WebCodecs方案后,延迟直接降到300ms内。核心思路是:
关键代码片段:
const decoder = new VideoDecoder({ output(frame) { // 直接渲染到canvas renderFrame(frame); }, error(e) { console.error(e); } }); const transport = new WebTransport('https://example.com:4433/stream'); const reader = transport.datagrams.readable.getReader(); while (true) { const { value, done } = await reader.read(); const frame = parseAV1Frame(value); decoder.decode(frame); }实测数据对比:
| 方案 | 平均延迟 | CPU占用 | 兼容性 |
|---|---|---|---|
| FLV.js | 1200ms | 15% | 全平台 |
| MSE+HEVC | 800ms | 25% | 需插件 |
| WebTransport | 280ms | 18% | Chrome 97+ |
// 处理时间戳翻转 static int64_t fix_pts(int64_t pts) { static int64_t last_pts = 0; if (pts < last_pts && (last_pts - pts) > 0x7FFFFFFF) { pts += 0x100000000; } last_pts = pts; return pts; }void cleanup() { mpi->reset(enc_ctx); mpp_destroy(enc_ctx); mpp_buffer_put(frame_buffer); mpp_buffer_put(packet_buffer); }if (frame_type == KEY_FRAME) { fwrite(sps, 1, sps_len, fp); fwrite(pps, 1, pps_len, fp); }通过perf工具分析发现,默认配置下有30%的CPU时间消耗在内存拷贝上。优化方案:
int dma_fd = get_dma_buffer_fd(); mpp_buffer_import(frame_buffer, MPP_BUFFER_TYPE_DMA, dma_fd);// NEON汇编优化 vld3.u8 {d0,d1,d2}, [r1]! // 加载YUV数据 vst4.u8 {d0,d1,d2,d3}, [r0]! // 存储RGBA优化前后对比:
| 操作 | 原耗时(ms) | 优化后(ms) |
|---|---|---|
| YUV转换 | 8.2 | 1.7 |
| 帧拷贝 | 3.5 | 0.2 |
| 编码 | 12.1 | 10.3 |
最后分享个监控脚本,用来实时查看推流状态:
#!/bin/bash while true; do ts=$(date +"%T") fps=$(cat /proc/video_stat | awk '/fps/{print $2}') delay=$(netstat -anp | grep rtmp | awk '{print $7}' | cut -d/ -f1 | xargs ps -o etime= -p) echo "[$ts] FPS:$fps Delay:$delay" sleep 1 done