当前位置: 首页 > news >正文

树莓派 FFmpeg 实战笔记(二):命令行、源码编译与硬件编码的真相

前言:第一阶段我手写 V4L2 代码点亮了摄像头,第二阶段的目标是把 FFmpeg 从"会敲命令"啃到"看懂源码结构":吃透命令行工具、从源码编译一遍、摸清树莓派的硬件编解码路径。这一晚踩了网络的坑、硬件的坑、还有自己给自己挖的坑,全部记录在此。

实验环境

项目

配置

硬件

树莓派 4(4GB),CSI 摄像头 IMX219(Camera Module V2),无头模式 SSH

系统

Debian 13 (trixie),arm64

FFmpeg

apt 版 7.1.5(deb13u1+rpt1,树莓派特供版)+ 自编译 n7.1

关键设备

/dev/video0(unicam CSI)、/dev/video11(bcm2835-codec 硬件编码)


一、命令行工具吃透

1.1 ffprobe:容器、编码器、时间基是三件不同的事

ffprobe -v error -show_entries format=format_name,duration,bit_rate \ -show_entries stream=codec_name,time_base in.mp4 ffmpeg -i in.mp4 -c copy in.ts # 无损换壳,不重编码 ffprobe -v error -show_entries stream=codec_name,time_base in.ts

结果:同一个 H.264 流,mp4 里time_base=1/15360,塞进 ts 后变成1/90000

结论format_name是壳(容器),codec_name是内容(编码器),time_base是壳自己定义的时间刻度——MPEG-TS 协议硬性规定 90kHz。换壳不换内容(-c copyspeed=771x,瞬间完成),但时间基跟着壳走。时间戳是容器层的属性,不是编码器的属性,这个认知在后面反复救了我。

1.2 preset / CRF / GOP:编码器的三个旋钮

同一段 10 秒 720p 测试视频(testsrc2生成),三组对照实验:

实验

耗时(real)

speed

体积

日志里的证据

-preset ultrafast

3.1s

3.66x

8.4M

cabac=0 bframes=0 ref=1,profile 退化为 Constrained Baseline

-preset medium

9.5s

1.08x

3.5M

cabac=1 bframes=3 ref=3,profile High

-crf 18/-crf 30

5.0M / 1.3M

平均 QP 17 vs 33

-g 15(默认 250)

3.8M

frame I:20vs 默认的frame I:2

结论

  • preset 是"拿 CPU 时间换压缩率":ultrafast 放弃高级工具,算得快但文件大了一倍多;

  • CRF 是画质标尺,经验法则数值每 +6,体积约减半

  • GOP 缩小 → I 帧暴增(I 帧体积是 P 帧的 2~3 倍)→ 文件略变大,但播放器能更快"开门见山",直播延迟更低

1.3-re与推流:一次 UDP 丢包实验

# 终端1:ffplay udp://127.0.0.1:8888 # 终端2:不带 -re 全速灌流 ffmpeg -i in.mp4 -c copy -f mpegts udp://127.0.0.1:8888?pkt_size=1316

播放器端立刻刷出[mpegts @ ...] Packet corrupt,画面花屏卡死。

原理:不带-re时 FFmpeg 以几百倍速把数据灌进网卡,UDP"只管发不管收",接收缓冲区瞬间溢出,大量丢包;H.264 前后帧强依赖,丢一包倒一片。-re的作用就是给 FFmpeg 踩刹车,按原生帧率发流。

延伸思考:为什么推摄像头不需要-re?因为摄像头是"活"的——传感器物理上就是 30fps 出图,自带物理节流;本地文件是"死"的,才需要-re模拟实时。

1.4 CSI 摄像头:为什么我的摄像头没有 H.264?

ffmpeg -f v4l2 -list_formats all -i /dev/video0

输出里全是Raw: yuyv422 / bayer_*,没有任何 Compressed 格式,直接抓取报错。

破案:我的摄像头是CSI 接口,它只是裸传感器,只输出 RAW Bayer 数据;USB 摄像头才自带 ISP+编码芯片直接吐 H.264/MJPEG。CSI 的正确流水线是:传感器 RAW → ISP(/dev/video13+)→ 硬件编码器(bcm2835-codec)。手动用 FFmpeg 串联这条流水线太折磨,工程上的标准做法是让官方工具干苦力:

rpicam-vid -t 10000 --width 1280 --height 720 -o cam_raw.h264 ffmpeg -framerate 30 -i cam_raw.h264 -c copy cam.mp4

日志里能看到 libcamera 自动选择了1920x1080-SBGGR10/RAW传感器格式并输出1280x720-YUV420——ISP 在默默干活。两个无害的"假报警":

  • Failed to create egl/drm preview:无头模式没显示器,自动退回后台录制,正常;

  • Timestamps are unset in a packet基本流(ES)天生没有时间戳,时间戳是容器层赋予的。用-framerate声明帧率、-fflags +genpts生成时间戳可缓解;就算警告还在,文件也完全能播——它只是封装器的"牢骚",不是错误。这恰好是 1.1 结论的二次验证。


二、从源码编译:与网络斗智斗勇的一晚

2.1 git clone 的两种死法

  • 第一种:GnuTLS recv error (-110): The TLS connection was non-properly terminated,直接失败;

  • 第二种:重试后卡在Receiving objects: 41% ... 19.00 KiB/s假死。

解法:放弃 git 协议,改下源码压缩包,走镜像代理,十几秒下完:

wget https://<镜像代理>/https://github.com/FFmpeg/FFmpeg/archive/refs/tags/n7.1.tar.gz tar -xf n7.1.tar.gz && cd FFmpeg-n7.1

2.2 configure 是 FFmpeg 的"功能开关面板"

./configure --enable-v4l2-m2m --enable-libx264 --enable-gpl --disable-doc

输出里Enabled encoders出现了h264_v4l2m2mhevc_v4l2m2m——--enable-v4l2-m2m这个开关被"实体化"了。随后make -j2 > make.log 2>&1 &扔后台(树莓派内存有限,-j2防 OOM)。

2.3 源码漫步:三个"寻宝"

grep -A 5 "typedef struct AVRational" libavutil/rational.h # 时间基的真面目:{num, den} 分数 grep -n "VIDIOC_REQBUFS" libavdevice/v4l2.c # 第一阶段手写的 ioctl,被封装在这里 grep v4l2 libavcodec/codec_list.c # 编译生成的编解码器注册表

AVRational就是一个分子/分母结构体——FFmpeg 用整数分数彻底避开浮点误差,ffprobe里的1/90000就是它。而v4l2.c里躺着我第一阶段写过的同一批VIDIOC_*ioctl。"命令行 → 库 → 内核驱动"这条链,至此在脑子里闭环了。

2.4 反转:我杀掉了编译一小时的 make

做硬件实验前随手一查:

ffmpeg -hide_banner -encoders | grep v4l2m2m # V..... h264_v4l2m2m V4L2 mem2mem H.264 encoder wrapper ...

树莓派官方 apt 源早就默认开启了 v4l2-m2m!我对抗龟速网络、配 configure、让 CPU 满载编译一小时……其实根本不需要编译。于是kill %1,并用 htop 确认:两个 100% 的cc1(gcc 编译本体)正是-j2的两个工人,load≈2.0 与之一一对应。

编译是"无用功"吗?不是。configure开关机制、make 后台任务管理、源码与命令行的映射——这些是apt install永远学不到的。但实用层面,今晚确实本可以省下一小时去喝茶。😄


三、硬件 vs 软件编码终极对决

time ffmpeg -i in.mp4 -c:v h264_v4l2m2m -b:v 4M -y out_hw.mp4 # 硬编 time ffmpeg -i in.mp4 -c:v libx264 -preset medium -y out_sw.mp4 # 软编

硬编日志里写着:Using device /dev/video11, driver 'bcm2835-codec'——活确实是专用芯片干的。

维度

h264_v4l2m2m

libx264 medium

耗时(real)

3.9s

18.1s*

speed

2.82x

0.563x*

CPU 时间(user)

6.0s

35.5s

体积

4.8M

3.5M

* 带星号是因为这次软编时后台 make 还在偷 CPU(空载时是 9.5s / 1.08x)——意外收获的一条教训:做基准测试必须控制变量,后台任务会让数据失真。

两个隐藏细节:

  1. 硬件编码器不吃-crf。bcm2835-codec 是"死脑筋",只接受-b:v码率模式,所以硬编文件反而更大(4M 固定码率 vs 软编 crf23 跑出的 2.8M)。嵌入式硬件加速最容易踩的坑之一。

  2. 硬编 user 时间只有 6 秒:CPU 基本在"搬运",计算全在芯片里。跑htop对比两次 CPU 占用,是理解"硬件加速"最直观的一课。

里程碑达成:现在我能对着一份转码日志逐行标注归属——Input #0 ...是 demuxer(libavformat)在拆壳;Stream mapping是解码→编码管线;Output #0是 muxer;带[libx264 @]前缀的才是 encoder(libavcodec)在说话;frame= ... speed=是运行统计。


四、踩坑清单

现象

原因

解法

git clone 报 GnuTLS 错误 / 卡 19KB/s

网络问题

镜像代理 wget 源码包

make: no makefile found

configure 没成功/没进源码目录

先 configure 再 make

v4l2 抓 CSI 摄像头只有 raw 格式

CSI 传感器只输出 RAW Bayer

rpicam-vid走 ISP+硬编流水线

裸 h264 封装 mp4 报 timestamps 警告

基本流无时间戳

-framerate/+genpts;理解警告非错误

推流不加-re播放端 Packet corrupt

UDP 缓冲溢出丢包

本地文件加-re,摄像头不用

rpicam 报 preview 创建失败

无头模式

正常,自动后台录制

硬编传-crf无效

硬件只支持码率模式

-b:v

软编速度莫名减半

后台编译偷 CPU

基准测试要空载

五、第二阶段自检清单

  • 说清 format_name / codec_name / time_base 三者关系,及 mp4 与 ts 时间基差异

  • 一句话说清 preset / crf / g 各自影响

  • 说清-re的作用与"何时不需要"

  • 说清 CSI 与 USB 摄像头的架构差异、ES 无时间戳的本质

  • 在源码里找到 AVRational、VIDIOC ioctl、codec 注册表

  • 对着日志逐行标注 demuxer / muxer / encoder 归属

六、写在最后

这一晚最大的收获不是某个参数,而是三个认知升级:时间戳属于容器不属于流摄像头架构决定数据形态硬件编码器有自己的脾气。哦对,还有第四条:动手前先ffmpeg -encoders | grep v4l2看一眼,说不定系统早就帮你装好了。😂

http://www.cnnetsun.cn/news/4153449.html

相关文章:

  • Vue3 后台管理选型:vue3-antd-admin 这套模板能省多少事
  • 告别几KB龟速!2026百度网盘加速全教程:PanDownload直链解析突破限速
  • 案例驱动的多智能体框架:破解电商搜索相关性难题
  • 技术写作中AI的陷阱与人工主导的高质量内容生产流程
  • 区块链运维实战:从国赛题目解析到企业级部署与监控
  • 大模型应用新范式:训练接口层实现跨模型性能迁移
  • 慧知租车换电开源SaaS平台:一套可私有化部署的换电租车一体化解决方案
  • 微信聊天记录导出与个人数据管理:开源项目「留痕」实用指南
  • AI电商工作台:从商品建档到批量生成营销素材的技术实现
  • 智能体编程的上下文工程:从Mise en Place哲学到高效AI编码实践
  • 华为昇腾算力实战指南:从CUDA迁移到国产AI芯片的完整路径
  • 谷歌Turbovec向量搜索库实战:TurboQuant量化算法解析与Rust实现
  • 质数口袋问题:动态增量筛法实现零冗余质数生成
  • PP-Structure Docker化实战:从Python库到生产级OCR服务
  • 蓝牙折叠键盘如何通过多设备切换重塑移动办公生产力
  • 客流量预测实战:从业务理解到模型部署的完整指南
  • Java异常处理机制解析与面试实战指南
  • Java技术面试深度解析:大厂与中小企业评估逻辑差异
  • AI如何重塑求职招聘:智能匹配与自动化面试解析
  • 数学建模竞赛:从模型构建到论文写作的实战指南
  • LLM推理成本全解析:从硬件、模型到工程优化的实战估算与降本策略
  • 基于SpringBoot的面向空巢老人的宠物陪伴支持系统设计与实现毕业设计项目源码文档
  • Windows CMD命令提示符面试题解析与实战指南
  • UE5实时弹幕对接:从Python数据桥接到3D场景交互全链路实现
  • Java面试核心考点与实战解析
  • AI文本检测实战指南:从原理到工具,构建混合识别系统
  • 技术从业者如何识别AI生成内容:原理、特征与工程实践
  • AI写作识别指南:从文本特征到人机协作的深度解析
  • 多智能体LLM共识系统的内部攻击风险与防御实践
  • AI Agent上下文管理:ZCode框架双层注入与CLAUDE.md防误读实战