ARTICLE DETAIL

资讯详情

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

FFmpeg 入门到实战:视频转码、压缩与推流全攻略

FFmpeg 入门到实战:视频转码、压缩与推流全攻略 1. FFmpeg到底是什么为什么人人都该装一个先说结论FFmpeg 是命令行工具但它几乎是所有视频工具的底层发动机。你用的播放器、剪辑软件、录屏工具、转格式网站背后很大概率都在调 FFmpeg。它是干什么的一句话处理音视频的瑞士军刀。录制、转换、截取、拼接、推流、滤镜、调音量、改码率、提取音频、给视频加水印几乎你能想到的多媒体操作它都能做。而且免费开源跨 Windows、macOS、Linux只要电脑能跑命令行它就能跑。之前有个朋友让我帮他压缩一个 2GB 的视频想发工作群。我用 FFmpeg 一条命令压到 200MB画质基本看不出损失。他后来问我在哪下的软件我说你电脑里没装吗他说从来没用过。这就是 FFmpeg 的现状——很多人听过名字但没见过真身更不知道它有多能打。这篇东西适合谁来读三类人一是刚接触 FFmpeg、想在 Windows 上装个能用的版本、最好还能解压即用的新手二是已经装好但只会转格式、想进一步玩转码率控制、视频截取、响度调整这些进阶操作的人三是准备用 FFmpeg 做推流或视频接入业务、被延迟问题折磨的开发者和运维。不管你是哪一类这篇都会把安装、配置、命令、参数、踩坑和排错一条龙讲清楚。我尽量用大白话把那些文档里不说人话的细节翻译过来。2. 安装准备三大平台的选择与底层逻辑2.1 Windows 用户别折腾编译直接拿编译好的版本Windows 装 FFmpeg最大的坑是很多人一上来就想自己编译。如果没有特殊需求——比如要集成 libx265 的窄带宽版本、要调试内部实现、要给自己的软件做定制 DLL——我劝你直接下载现成的编译版本省时省力。目前 Windows 下维护得最好、最常被推荐的是两个来源gyan.dev一个开发者长期维护的 Windows 构建版本更新频率非常高几乎跟着 FFmpeg 官方发布节奏走还区分了完整版full和精简版essentials。BtbN 的 GitHub Releases自动化构建的产物版本全、平台多Windows 和 Linux 都有同样区分 full 和 essentials。这里有个细节很多人忽略下载时优先选full 版本。因为 essentials 精简版砍掉了一批外部库的支持比如某些编码器、滤镜对于新手来说精简版可能在某个命令上莫名其妙报错排查起来很费劲。full 版本体积大一点但功能齐全能避免大量后续问题。下载完你会得到一个压缩包比如ffmpeg-7.1.5-full_build.zip。解压之后里面有三个文件夹bin、doc、presets。我们真正需要用到的就是bin目录里的两个可执行文件ffmpeg.exe和ffprobe.exe。前者负责处理音视频后者负责读取媒体文件信息。2.2 不配置环境变量的后果与配置方法解压完 FFmpeg很多教程会直接让你去bin目录打开命令行输入ffmpeg试试。但那样的话每次使用都得先cd到那个目录或者每次都要写完整路径C:\ffmpeg\bin\ffmpeg.exe -i input.mp4 ...非常折磨。正确做法是把bin目录加进系统的PATH 环境变量这样你在任意目录打开终端直接敲ffmpeg就能运行。具体操作路径是这样的我的 Windows 版本不同会略有差异但大方向一样按Win S输入“环境变量”并打开“编辑系统环境变量”。点击右下角“环境变量”按钮。在“用户变量”或“系统变量”里找到Path双击编辑。点“新建”粘贴你的bin目录完整路径比如D:\tools\ffmpeg-7.1.5-full_build\bin。一路“确定”关掉所有窗口。重新打开一个终端输入ffmpeg -version看到版本信息就说明配置成功。这个“重新打开”很关键。因为环境变量的读取发生在程序启动时旧终端里不会生效很多人配置完发现还是找不到命令其实不是没配上而是没开新窗口。2.3 macOS 和 Linux 的一行命令方案macOS 上有 Homebrew 的直接brew install ffmpeg安装过程会自动把依赖如 x264、x265、vpx、fdk-aac 等一并装好省心。Linux 上分发行版。Ubuntu/Debian 系sudo apt update sudo apt install ffmpegCentOS/RHEL/Fedora 系sudo dnf install ffmpegLinux 发行版的 FFmpeg 通常阉割了部分受专利保护的编码器比如 H.264 编码库 x264、AAC 编码库 fdk-aac所以某些格式编码可能受限。这对尝鲜够用但如果要做严肃的转码或推流建议还是用静态编译的完整版本。3. 核心命令拆解从最常用的转格式开始FFmpeg 的用法本质上就一个套路输入文件或流→ 滤镜处理 → 输出文件或流。命令结构大致是ffmpeg [全局参数] -i [输入文件] [滤镜参数] [输出参数] [输出文件]掌握这一个框架后面所有命令都是往里填不同的参数。3.1 转换格式MP4 转 MKV、M3U8 转 MP4最简单的格式转换ffmpeg -i input.mp4 output.mkv它相当于把容器container换掉里面的视频和音频如果没有重新编码就只是改了个封装格式。所以这个命令快如闪电但前提是两个格式支持同一种编码方式MP4 里的 H.264 视频放进 MKV 完全没有问题。那 M3U8 转 MP4 呢这是被问爆的一个需求。M3U8 本质是一个播放列表文件里面通常是一堆 TS 片段或者加密的 TS 片段。以前版本只需要一条命令ffmpeg -i input.m3u8 -c copy output.mp4但这里有一个很隐蔽的问题如果 M3U8 里的 TS 片段是 AAC 音频那么放进 MP4 容器没问题如果音频是 MP3MP4 容器是不支持的。更别提很多 M3U8 还有加密需要额外的 key 才能解密这种情况-c copy就不灵了。所以实际处理 M3U8 时我一般分两层策略第一层先尝试流复制ffmpeg -i input.m3u8 -c copy -bsf:a aac_adtstoasc output.mp4第二层如果报错或者没有声音就强制重新编码ffmpeg -i input.m3u8 -c:v libx264 -c:a aac output.mp4关于-bsf:a aac_adtstoasc这个参数是我踩过坑之后才学到的。M3U8 里的 AAC 音频是 ADTS 格式一种带头部信息的流式 AAC而 MP4 容器需要的是 ASC 格式Audio Specific Config。如果直接复制出来的 MP4 虽然能播放但在某些设备或软件上会没有声音或快进异常。加了这个 bitstream filter就能把音频从 ADTS 转成 ASC从根上避免问题。3.2 视频截取按时间段和按区域按时间段截取常用的参数组合是ffmpeg -ss 00:12:30 -to 00:15:00 -i input.mp4 -c copy output.mp4这里-ss表示起始时间-to表示结束时间。注意位置我把-ss放在-i前面这很重要。-ss放前面是 Fast SeekFFmpeg 会直接跳到关键帧附近开始处理速度快放后面是 Slow Seek会从头解码到指定位置速度慢但起始帧更精确。如果只是快速截取建议放前面。再说区域截取比如你想取视频的左上角一块区域而不是整个画面用crop滤镜ffmpeg -i input.mp4 -vf crop640:360:0:0 output.mp4参数含义是crop宽:高:x:y。x0, y0就是左上角起点要取中央区域需要计算坐标。比如视频原始分辨率是 1920×1080想取中央 1280×720那么 x (1920-1280)/2 320y (1080-720)/2 180ffmpeg -i input.mp4 -vf crop1280:720:320:180 output.mp4这个功能在广告抓取、人脸区域追踪、监控画面局部放大等场景非常好用。4. 进阶参数全解析码率、响度、质量与压缩4.1 降低码率压缩视频的正确姿势降低码率是高频需求很多人只会一招“降低分辨率”这其实并不总是最优解。如果只是想在保持分辨率的前提下缩小体积核心参数是-b:v视频目标码率。ffmpeg -i input.mp4 -b:v 2000k -maxrate 2500k -bufsize 4000k output.mp4这里的逻辑是让编码器以平均 2000kbps 的码率输出视频峰值不超过 2500kbps编码器码率控制缓冲区控制在 4000kbps。加了-maxrate和-bufsize可以让码率波动更稳定避免某些极限场景把码率飙得过高。但有经验的玩家会告诉你固定码率不是最优解。对 H.264 编码器我更推荐用 CRFConstant Rate Factor模式ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium output.mp4CRF 是啥你可以理解成一个“质量滑块”数值范围通常 0-5118~28 是常用区间。数值越小质量越高文件越大。23 是默认值在画质和体积之间比较平衡。18 基本是“视觉无损”28 压缩力度较大、画质略有损失。为什么推荐 CRF因为视频的内容密度差异很大——一段静态 PPT 录屏和一段剧烈运动比赛画面同样码率下体积和画质会天差地别。CRF 让编码器根据画面复杂度动态分配码率效果好得多。我自己压视频的通用模板ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset slow -c:a aac -b:a 128k output.mp4-preset slow表示编码器花更多时间做更精细的压缩体积更小但压缩时间更长。如果你赶时间用medium或fast就行。4.2 调整响度让音量听感统一视频响度问题常见于会议录屏、多个视频拼接。有人会调音量用了-af volume2.0这种简单做法等于把音量粗暴乘以 2。但这个做法有两个问题容易造成削顶失真波形超过 0dB 后直接咔嚓掉不同源片的响度差异还是无法统一。正确思路是用响度标准化。业界常用 EBU R128 标准FFmpeg 提供了loudnorm滤镜ffmpeg -i input.mp4 -af loudnormI-16:TP-1.5:LRA11 -c:v copy output.mp4这边几个参数的含义I-16目标整体响度Integrated Loudness为 -16 LUFS。短视频平台、国际流媒体标准通常在 -14 到 -16 之间。TP-1.5真峰值True Peak不超过 -1.5 dBTP防止过度冲顶。LRA11响度范围Loudness Range控制在 11 LU。-c:v copy是为了不重新编码视频只处理音频省时省力。实操中要注意loudnorm是一个非常消耗 CPU 的滤镜且它是两次通过算法。第一次运行后它会输出一套测量参数第二次运行加上这些参数会得到更准确的结果。但普通场景下直接用一次也可以效果已经吊打粗暴调音量了。4.3 硬件加速让转码速度快一倍软件编码慢尤其处理 4K 视频时CPU 编码的等待时间让人抓狂。所以有条件尽量用硬件编码器。NVIDIA 显卡用h264_nvencffmpeg -i input.mp4 -c:v h264_nvenc -cq 23 output.mp4Intel 核显QSV用h264_qsvAMD 显卡用h264_amf。硬件编码的速度远快于 CPU但同等码率下画质会差一些。我的经验是硬件编码时把码率稍微调高一点比如软件编码 -crf 23硬件编码就按 3000k-5000kbps 的码率来体积略大但速度优势明显。判断你的 FFmpeg 是否支持硬件编码用ffmpeg -encoders | findstr nvencLinux 用ffmpeg -encoders | grep nvenc。如果没有任何输出说明你这版 FFmpeg 没编译 NVIDIA 支持需要换编译版本或者自己编译。5. 推流延迟问题处理与实测记录5.1 为什么推流延迟大问题出在哪FFmpeg 推流到 SRSSimple Realtime Server或者其他的 RTMP/RTSP 服务端存在延迟这是很多入门开发者第一次碰到“流媒体比 VOD 复杂得多”的地方。延迟从哪来大致有三段采集端编码缓冲编码器内部有缓冲特别是 B 帧会引入额外延迟。传输缓冲TCP-based 的 RTMP 或 UDP-based 的 RTP为了抗丢包会有 Jitter Buffer抖动缓冲。播放端缓冲播放器会预读一定时长的数据防止网络抖动卡顿。FFmpeg 推流参数的调整空间主要在第一段。5.2 低延迟推流实测参数以推 RTSP 为例比如推到支持 RTSP 的流媒体服务器ffmpeg -re -i input.mp4 -c:v libx264 -preset ultrafast -tune zerolatency -b:v 2500k -bufsize 500k -f rtsp rtsp://server:8554/live-preset ultrafast让编码速度最快体积大但编码快-tune zerolatency专为低延迟场景优化关闭 B 帧并调整缓冲区行为。推 RTMP 到 SRS 或 Nginx-RTMPffmpeg -re -stream_loop -1 -i input.mp4 -c:v libx264 -preset ultrafast -tune zerolatency -c:a aac -b:a 128k -f flv rtmp://server:1935/live/stream这里-stream_loop -1表示无限循环推送适合做稳定性测试。很多人不理解-re是干什么的。它的作用是把输入按原始帧率读取让推流速度与真实时间同步。如果去掉-reFFmpeg 会以最快的速度把文件读完并疯狂发包服务端和播放端都会乱套直播场景必须加上。5.3 实测延迟数据的意义我曾用本机 FFmpeg 推流向本地 SRS 服务分别测过两种配置配置输入端延迟播放端延迟默认参数300~500ms1.5~3sultrafast zerolatency200ms 左右800ms~1.2s播放端那 1~2 秒的延迟主要是播放器的缓存策略导致的这个不是单纯调 FFmpeg 参数能解决的需要播放器配合调整缓冲时长比如 VLC 的网络缓存默认是 1000ms可以调低到 300ms但网络不好会频繁卡顿。不要盲目追求极低延迟。低延迟和抗抖动永远是矛盾的要根据你的网络环境和业务场景直播还是监控拉流找平衡点。6. 编译与集成msvc 编译 libx265 与生成 DLL6.1 什么时候需要自己编译 FFmpeg如果你是普通用户下载现成的就行。但如果你是 C/C 开发者、音视频 SDK 集成商、或者想在嵌入式板卡比如 RK3588 平台的 Linux 系统上做推流就会意识到官方编译版本不一定包含你需要的编码器也不一定能直接作为 DLL 库被调用。msvc 编译 FFmpeg 并启用 libx265核心痛点在于FFmpeg 本身用 C 写msvc 对 C99/C11 的支持早年有问题而且 libx265 依赖的外部库x265 编译出来是 C 代码需要先用 MSYS2 或 MinGW 环境编译成 Windows 库。这是很多人在 Windows 编译 FFmpeg 时最想砸键盘的地方。6.2 用 MSYS2 一键编译的实操路线推荐路线MSYS2 mingw-w64 工具链。步骤如下第一步安装 MSYS2去官网下载安装包装到 C 盘根目录。第二步打开 MSYS2 UCRT64 终端安装基础工具链和依赖pacman -S mingw-w64-ucrt-x86_64-toolchain mingw-w64-ucrt-x86_64-yasm mingw-w64-ucrt-x86_64-nasm mingw-w64-ucrt-x86_64-cmake mingw-w64-ucrt-x86_64-git第三步克隆 FFmpeg 源码并 configuregit clone https://github.com/FFmpeg/FFmpeg cd FFmpeg ./configure --enable-shared --disable-static --enable-libx265 --enable-gpl --extra-cflags-I/mingw64/include --extra-ldflags-L/mingw64/lib这里--enable-shared就是要生成 DLL 的关键选项。--disable-static是为了避免生成一堆巨大的 .a 静态库不好分发。--enable-gpl是因为 x265 是 GPL 协议不加这个 FFmpeg 会拒绝启用它。第四步编译make -j$(nproc) make install顺利的话结束后在/usr/local/bin下能看到ffmpeg.exe、ffprobe.exe以及一大堆 DLL。当你用依赖这个 DLL 的 FFmpeg 执行ffmpeg -version时会看到--enable-libx265字样说明编译成功。这条路我走过不止一次坑的确不少。比如 configure 时提示找不到 x265.pc通常是没装 x265 的 dev 包make过程报错八成是依赖库版本不对要回头pacman -S补齐。但一旦跑通你就拥有了一个完全可控、带 libx265 的 Windows 版 FFmpeg后面集成到自己的 SDK 或者做定制推流都非常顺。6.3 引入 FAAC/x265 时要注意协议问题需要特别提醒的是libx264 和 libx265 都是 GPL 协议如果你的产品是闭源商用软件要小心。如果是个人学习和内部使用问题不大。要在商业产品里集成请评估协议风险或者考虑用性能相近的 BSD 协议编码器。7. 常见问题速查与避坑指南7.1 高频问题表问题现象解决方案下载慢官网或 GitHub 下载总是断断续续用镜像站或从国内开源镜像站下编译好的版本环境变量不生效ffmpeg提示不是内部或外部命令确认路径是否正确确认是新开的终端未知编码器错误Unknown encoder libx265换 full 版本或自己编译转 m3u8 没声音输出 MP4 静音或快进异常加-bsf:a aac_adtstoasc推流闪退RTMP/RTSP 推流中断检查网络减小 GOP 大小加-g 50视频没声音音轨缺失或格式不支持-c:a aac重新编码音频字幕没有视频内嵌字幕未显示注意区分硬字幕与软字幕软字幕需手动指定流7.2 我踩过的几个实战雷区遇到过的最诡异的事儿是用 FFmpeg 处理一个从网上下载的视频转码后画面变成了粉色和绿色。排查了半天发现是源视频用了 10bit 色深而我默认的 libx264 输出是 8bit色彩空间转换出了问题。处理这类视频要在编码参数里加-pix_fmt yuv420p或者-pix_fmt yuv420p10le强制指定像素格式。另一个雷区是滤镜链写错导致视频被缩放到奇怪的分辨率。比如有人写-vf scale1920:-2不理解为什么高度是 -2。这是为了让高度保持偶数因为 H.264 编码要求宽高是偶数-2 的意思是自动计算并取最接近的偶数。如果写-1有可能会得到奇数高度在播放或编码时报错。最后一个实用技勉处理一个长视频里抽多段片段时不要对每个片段跑一次 FFmpeg那样等于多次解码原始大文件效率极低。正确姿势是一次性用-f segment做切片或者写批处理脚本循环处理充分利用缓存。8. 从零到一一个完整实战演示前面讲了很多参数可能你有点晕。我来演示一个完整的真实场景下载一个 1080p 高清视频要做以下几个处理切成 30 秒的片段转成适合微信传输的格式把音量标准化顺便降低码率。一条命令搞定ffmpeg -ss 00:10:00 -t 30 -i input.mp4 -c:v libx264 -crf 26 -preset fast -af loudnormI-16:TP-1.5:LRA11 -c:a aac -b:a 96k -movflags faststart output.mp4-ss 00:10:00 -t 30表示从第10分钟开始截取30秒-crf 26压缩力度比默认大一点适合传输-movflags faststart这个参数值得单独说一下它把 MP4 的索引信息移动到文件头部这样播放在线视频时无需完全下载就能开始播放网上传文件给人看时体验好很多。命令运行完后输出文件放在同目录下直接用播放器打开检查画面和声音。我一般会跑一遍ffprobe output.mp4检查最终编码参数是否正确ffprobe -v error -show_entries formatduration,size:streamcodec_name,codec_type,width,height -of defaultnoprint_wrappers1 output.mp4它会输出时长、文件大小、视频编码器、分辨率等信息。确认无误收工。9. 扩展思路FFmpeg 还能这么用聊到这儿FFmpeg 其实已经帮你干了转格式、截取、压缩、调音量、推流、编译。但它的想象空间远不止这些。几个锦上添花的用法新手可以后续慢慢探索视频拼接多个片段合并成一个文件用concatdemuxer。注意中间不能有任何不同编码或分辨率否则会黑屏或者花屏。图片转视频把一张静态图片加滚动效果做成视频-loop 1配合zoompan滤镜。RTSP 拉流定时截图监控摄像头画面每30秒截一张图用于巡检-vf fps1/30轻松实现。音频提取ffmpeg -i video.mp4 -q:a 0 -map a audio.mp3把视频中的音轨保存为 MP3。如果对 FFmpeg 的认知还停留在“只能转格式”那想得有点窄了。理解了它的输入输出抽象模型之后你会发现任何媒体处理需求都能靠十几个核心参数组合拼出来。这也正是为什么那么多商业工具都选择把 FFmpeg 藏在壳子里然后收服务费。它不值钱但能帮你省下的时间值钱。我个人最深的体会是学 FFmpeg 不要背诵命令要理解那几个核心概念输入、滤镜、编码器、容器、流复制。一旦理解了这些命令之间就能互相组合、举一反三。遇到问题时的排查思路也应该从“命令哪里写错了”转变到“我想对哪一条流做什么”前者是撞运气后者是看本质。最后分享一个小技巧任何 FFmpeg 命令执行前先加一行-v error -stats它会让终端只输出错误信息和实时统计数据不会刷一大屏无用的 log排查问题时会清爽很多。
返回列表