十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

openpilot 远程实时摄像头流:用 compressed_vipc.py 在 PC 上解码并显示设备三路相机画面

openpilot 远程实时摄像头流:用 compressed_vipc.py 在 PC 上解码并显示设备三路相机画面 openpilot 远程实时摄像头流用 compressed_vipc.py 在 PC 上解码并显示设备三路相机画面【免费下载链接】openpilotopenpilot is an operating system for robotics. Currently, it upgrades the driver assistance system on 300 supported cars.项目地址: https://gitcode.com/GitHub_Trending/op/openpilot本篇指南讲解 openpilot 仓库中openpilot/tools/camerastream工具链的完整用法如何先在设备端启动camerad、encoderd和 messaging 桥接三件套再用compressed_vipc.py把设备上的 HEVC 压缩码流经网络拉取、在 PC 本地解码并重新发布到 VisionIPC 供watch3.py实时显示。读完并照做后你可以在自己的电脑上实时看到任意一台运行 openpilot 的设备上三路摄像头窄角道路、广角道路、车内的原始画面并观察到每一帧从采集到显示各阶段的延迟分解——这对调试相机管线、验证模型输入画面、远程观察真车行为都非常有用。整体数据链路从设备相机到 PC 屏幕理解这个工具组最快的方式是先看清帧数据在整条链路上的形态变化设备上camerad打开三路硬件相机把裸帧NV12写入名为camerad的 VisionIPC 服务器设备上encoderd作为camerad的 VisionIPC 客户端订阅这些裸帧用硬件编码器Comma 硬件走 V4L2 硬件编码见 encoderd.cc 中__COMMA_HARDWARE__分支选择V4LEncoder否则回退FfmpegEncoder将其压成 HEVC 码流连同帧索引一起发布为 cereal 消息设备上cereal/messaging/bridge把设备进程间消息总线上的数据通过 ZMQTCP转发出去这是跨机器的关键一步PC 上compressed_vipc.py作为 ZMQ 订阅端连回设备按相机逐帧解码 HEVC → NV12PC 上解码后的 NV12 数据重新发布到 PC 本地的 VisionIPC 服务器默认名为cameradwatch3.py作为客户端把三路画面画到同一窗口。对应源码中的消息服务定义可以在 log.capnp 中看到narrowRoadEncodeData 86 :EncodeData; cabinEncodeData 87 :EncodeData; wideRoadEncodeData 88 :EncodeData;三个EncodeData服务在 services.py 中均被标记为高优先级、队列容量QueueSize.BIG因为视频流数据量大、要求实时narrowRoadEncodeData: (False, 20., None, QueueSize.BIG), cabinEncodeData: (False, 20., None, QueueSize.BIG), wideRoadEncodeData: (False, 20., None, QueueSize.BIG),前置条件设备与 PC 必须处于同一 openpilot 版本文档特别强调设备和你的 PC 必须运行同一个 openpilot commit。从源码看这是硬约束设备端bridge把每个消息服务名通过 FNV-1a 哈希映射到 TCP 端口起点 8023见 bridge_zmq.cc 的get_port()PC 端订阅时用同一份services.h计算同样的端口。如果两端 commit 不一致服务定义端口哈希、消息 schema就可能对不上连上也没有有效数据EncodeData消息里的idxencodeId、timestampSof/Eof、flags等与compressed_vipc.py里的解析逻辑强绑定schema 不一致会导致解码端持续判定丢包。设备端操作启动三个进程SSH 登录设备后在三个独立终端分别执行cd /data/openpilot ./openpilot/cereal/messaging/bridgecd /data/openpilot/system/loggerd ./encoderdcd /data/openpilot/system/camerad ./camerad说明bridge无参数运行时走msgq_to_zmq方向即把设备本地消息总线广播出去bridge.cc 的main()argc 2才走反向的zmq_to_msgqencoderd负责把 VisionIPC 裸帧编码成 HEVC 并发布*EncodeData消息它还会响应LivestreamEncoderBitrate、LivestreamRequestKeyframe两个 Params 参数来动态调整直播码率和请求关键帧见 encoderd.cc 的encoder_set_bitrate()/encoder_request_keyframe()。也可以把三进程合成一条命令一次性启动按一次 CtrlC 即可全部停止( cd /data/openpilot ./openpilot/cereal/messaging/bridge cd /data/openpilot/system/camerad/ ./camerad cd /data/openpilot/system/loggerd/ ./encoderd wait ) ; trap kill $(jobs -p) SIGINTPC 端操作解码并重新发布到 VisionIPC在 PC 上的 openpilot 检出目录中运行解码脚本cd ~/openpilot/tools/camerastream ./compressed_vipc.py ipip是设备的网络地址文档示例中为设备的 SSH 主机名/IP如comma-ffffffff。完整参数来自 compressed_vipc.py 的 argparse 定义$ python3 compressed_vipc.py -h usage: compressed_vipc.py [-h] [--cams CAMS] [--server SERVER] [--silent] addr Decode video streams and broadcast on VisionIPC positional arguments: addr Address of comma three options: -h, --help show this help message and exit --cams CAMS Cameras to decode --server SERVER choose vipc server name --silent Suppress debug output各参数在源码中的实际语义参数源码位置默认值说明addr位置参数必填设备地址每个解码子进程用它建立到设备的 ZMQ 订阅--camsargs.cams.split(,)0,1,2即全部三路逗号分隔的流编号映射到VisionStreamType0NARROW_ROAD窄角道路、1CABIN车内、2WIDE_ROAD广角道路枚举定义见 visionipc.py--serverVisionIpcServer(server_name)cameradPC 本地 VisionIPC 服务器名watch3.py按这个名字取流--silentdebug(not args.silent)关闭去掉每帧的丢包/重同步/延迟调试输出文档给出的最小示例——只解码第一路窄角并在另一终端显示cd ~/openpilot/tools/camerastream ./compressed_vipc.py comma-ffffffff --cams 0 cd ~/openpilot/selfdrive/ui/ ./watch3.pyPC 端显示watch3.py 三路同屏watch3.py是一个只有十几行的 Raylib 演示程序把三路画面平铺到同一窗口右上为窄角道路、左下为车内、右下为广角road CameraView(camerad, VisionStreamType.VISION_STREAM_NARROW_ROAD) driver CameraView(camerad, VisionStreamType.VISION_STREAM_CABIN) wide CameraView(camerad, VisionStreamType.VISION_STREAM_WIDE_ROAD) for _ in gui_app.render(): road.render(rl.Rectangle(gui_app.width // 4, 0, gui_app.width // 2, gui_app.height // 2)) driver.render(rl.Rectangle(0, gui_app.height // 2, gui_app.width // 2, gui_app.height // 2)) wide.render(rl.Rectangle(gui_app.width // 2, gui_app.height // 2, gui_app.width // 2, gui_app.height // 2))见 watch3.py。注意它硬编码连接名为camerad的 VisionIPC 服务器所以compressed_vipc.py --server如果改名watch3 也需要同步调整。解码流程深潜compressed_vipc.py 的关键机制compressed_vipc.py的结构可以分三层来看compressed_vipc.py1. 先探测帧尺寸再建 VisionIPC 缓冲。CompressedVipc.__init__先用SubMaster订阅各*EncodeData服务并update()等待第一帧只为读取ed.width/ed.height随后在 PC 本地VisionIpcServer上create_buffers(vst, 4, W, H)4 个环形缓冲并启动监听最后为每一路相机 fork 一个独立的解码子进程p multiprocessing.Process(targetdecoder, args(addr, self.vipc_server, vst, ed.width, ed.height, debug))2. 解码前必须先等到关键帧。HEVC 解码需要 VPS/SPS/PPS 参数集加一个 I 帧才能开始。解码循环里if not seen_iframe and not (evta.idx.flags V4L2_BUF_FLAG_KEYFRAME): continue # waiting for iframe其中V4L2_BUF_FLAG_KEYFRAME 8来自 V4L2 编码器驱动的标志位定义。收到关键帧后先codec.decode(evta.header)把参数集喂给解码器再解码后续帧。3. 丢包自动重同步。每帧消息带有idx.encodeId如果encodeId不连续evta.idx.encodeId ! last_idx 1调用resync()清空 FFmpeg 解码器缓冲avcodec_flush_buffers、丢弃时间戳队列、等待下一个关键帧重新起解。这一机制让网络偶发抖动不会导致画面永久花屏。4. 每帧延迟分解输出。默认非--silent模式下每帧打印一行延迟统计roll {frame_latency:6.2f} ms latency {process_latency:6.2f} ms {network_latency:6.2f} ms {pc_latency:6.2f} ms {total:6.2f} ms四项分别是设备上帧采集时间timestampEof - timestampSof、设备编码到发布耗时logMonoTime - timestampEof、网络传输耗时PC 收到时刻减unixTimestampNanos、PC 端解码耗时。这个输出是评估从路面上发生事件到你在 PC 上看到画面端到端延迟的现成工具。解码器实现ctypes 直接封装 FFmpeg 库解码器在 ffmpeg_decoder.py 中实现不依赖 FFmpeg 的 Python 绑定而是用ctypes.CDLL直接加载libavutil.so.59、libavcodec.so.61、libswscale.so.8因此依赖 PC 上安装的 FFmpeg 动态库版本与这里写死的 so 主版本号一致。几个值得注意的解码参数在Decoder.__init__中设置_check(_avutil.av_opt_set(self._context, bthreads, b4, 0), set decoder threads) _check(_avutil.av_opt_set(self._context, bthread_type, bslice, 0), set decoder thread type) _check(_avutil.av_opt_set(self._context, bflags, blow_delay, 0), set low-delay mode)源码注释解释了取舍4 个 slice 线程是该工作负载下延迟的最低点——帧级线程会在解码器内部多囤帧增加延迟而 slice 线程能在不加帧队列的前提下缩短单帧解码时间。解码输出经sws_scale用SWS_FAST_BILINEAR转成 NV12紧凑 numpy 数组尺寸W*H*3/2供 VisionIPC 直接发送。端到端验证与排查清单按下面的顺序可以快速定位看不到画面类问题设备与 PC commit 不一致→ 先同步版本这是文档明示的第一前提三个设备端进程是否都在bridge、encoderd、camerad缺一不可encoderd依赖camerad的 VisionIPC 流存在VisionIpcClient::getAvailableStreams(camerad)拿不到流就不建编码线程看compressed_vipc.py的调试输出持续打印waiting for iframe说明没收到关键帧可检查设备端编码是否正常频繁DROP PACKET!说明网络丢包解码器会自动重同步HEADER ERROR/DECODE ERROR则触发同样重同步尺寸不匹配若打印decoded frame is WxH, expected WxH通常是两端 commit 不一致导致编码器分辨率与订阅端探测值不符同样会触发 resync只想要低带宽调试用--cams 0只拉窄角一路能显著降低带宽占用。小结tools/camerastream这一组工具串起了 openpilot 相机管线的远端可观测能力设备端camerad → encoderd → bridge三件套把三路 HEVC 直播推上网络PC 端compressed_vipc.py以每进程一路相机的方式解码并回发布到 VisionIPCwatch3.py完成三屏同显。其源码中关键帧门控 encodeId 连续性检测 自动重同步 逐帧延迟分解的解码策略本身就是一份高质量的低延迟网络视频解码参考实现相关文件见 compressed_vipc.py 与 ffmpeg_decoder.py。【免费下载链接】openpilotopenpilot is an operating system for robotics. Currently, it upgrades the driver assistance system on 300 supported cars.项目地址: https://gitcode.com/GitHub_Trending/op/openpilot创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表