资讯动态

FFmpeg + MPEG-TS:实时视频传输的黄金组合与参数实战

发布时间:2026/10/14 12:21:37 来源:尧图企业网站定制
简介面向嵌入式与流媒体开发者的 MPEG-TS 视频处理参考包围绕 FFmpeg 在 ARM 平台上的编译与 TS 流分段需求展开。资源已在嵌入式 ARM 环境下验证可编译通过适合需要在智能家居、车载系统或移动设备中处理视频传输的工程师参考。压缩包仅 10KB共含 3 个文件以 C 语言源码为核心配合 Makefile 自动构建脚本与 COPYING 开源许可说明便于快速理解分段逻辑并接入现有构建流程。核心代码演示了如何将 MPEG-TS 流切割为适配 HLS、DASH 等自适应流协议的短片段为实时传输、监控或流媒体服务提供可修改的基础实现。目前已有 1554 人次学习下载对正在搭建嵌入式音视频传输链路的开发者具有一定借鉴意义。1. 在实时视频传输场景里mpeg-ts 和 ffmpeg 为什么一直是黄金组合做实时传输尤其是一路编码流要跨局域网推到解码端、网关或者录制服务器时最让我省心的封装格式还是 mpeg-ts。mpeg-ts 格式视频 ffmpeg 传输这个组合几乎能覆盖从点播转流、直播推流到设备拉流的全场景。TS 流把视频、音频和节目信息切成 188 字节的固定包只要有 PCR/PTS/DTS 就能自解释丢一小段包也不至于让整路流废掉。ffmpeg 负责把本地文件转码、复用成 TS再用 UDP/RTP/HTTP 发出去接收端同样是 ffmpeg 拉起一键存文件或解码播放。这套方案的优点是链路简单、参数透明、排错手段多适合不依赖商业平台的局域网交付也适合做协议验证。2. 从本地文件到 UDP 流ffmpeg 跑通 mpeg-ts 传输的最小链路2.1 先看到 TS 的骨架ES、PES、TS 三层各管什么很多朋友一上来就把 ffmpeg 命令跑通了但一出问题就完全黑匣子根本不知道对端在抱怨什么。所以我建议在敲命令前先花两分钟记住 TS 的三层结构编码层、PES 层、TS 包层。视频编码器出来的 H.264 码流叫 ES这是纯压缩数据没有时间概念。ffmpeg 的 mpegts muxer 先把 ES 打包成 PESPES 头里装着 PTS 和 DTS也就是这一帧什么时候显示、什么时候解码。然后再把 PES 内容切开装进 188 字节的 TS 包里每个包有 4 字节的 TS 头里面是 PID、连续性计数器等字段。除了音视频 PESmuxer 还会周期性地插入 PAT/PMT 表告诉接收端当前流里有哪几个节目、每个节目的视频和音频 PID 是多少同时插入 PCR 字段让接收端能重建编码器的时钟。这套结构解释了为什么 TS 能“丢包不散架”接收端只要抓到 PMT知道视频 PID就能在大量垃圾包里筛出需要的 TS 包。而 MP4 需要 moov 元数据一旦截断或丢包前面没看到的流根本解不了码。2.2 最小推流命令把 MP4 转成 TS 并走 UDP 发出去最基础也是我日常验证最简单的一条命令ffmpeg -re -i input.mp4 \ -c:v libx264 -preset veryfast -tune zerolatency \ -b:v 2M -maxrate 2M -bufsize 4M \ -pix_fmt yuv420p \ -c:a aac -b:a 128k -ac 2 \ -f mpegts udp://127.0.0.1:1234?pkt_size1316-re是按原视频帧率读取文件不加它ffmpeg 会以最快速度把文件推完接收端根本来不及处理。-tune zerolatency是 x264 的低延迟模式会通过减少参考帧和 B 帧来降低编码延迟代价是码率略高。-b:v 2M是平均码率-maxrate 2M限制峰值-bufsize 4M是码率控制缓冲区三者配合起来才能让码率曲线稳定不会突然爆流。-pix_fmt yuv420p是为了兼容各种解码器很多播放器不认 yuvj422p 这类格式。音频统一压成 AAC 双声道-ac 2避免原文件 5.1 声道在传输通道上扩张带宽。最后是-f mpegts指定输出封装格式URL 写成 UDP。pkt_size1316表示每个 UDP 报文装 7 个 TS 包正好 1316 字节既保持 MTU 安全也不至于包太碎导致网卡中断太多。想改成 3 个 TS 包一包也可以写 564但实际用 1316 最常见。2.3 接收与校验把 UDP 里的 TS 拉下来一边存一边看错误推流起来了先别高兴太早本机验证一下# 实时播放看画质和同步 ffplay -fflags nobuffer -flags low_delay \ -i udp://127.0.0.1:1234?buffer_size65536 # 只存 10 秒流并且把解码错误打印出来 ffmpeg -i udp://127.0.0.1:1234?buffer_size65536 -t 10 \ -c copy -f mpegts dump.tsbuffer_size65536是 UDP 接收缓冲单位字节。默认值往往只有几十 KB网卡一抖动就会丢包尤其在高码率下。这个参数我在真实项目里调过不下十次经验值是 2M 码率给 64K 起步4M 码率给 128K。-c copy是直接拷贝原始流不做二次编码这样时间和画面信息不会被重新改写排查问题更干净。-t 10表示只接收 10 秒适合自动化测试。如果在ffplay的窗口里能看到画面并且ffmpeg落盘后没有大量报错说明这条最小的 TS 链路已经通了一半。2.4 直拷贝与转码的选择什么时候用 -c copy 反而是坑上面落盘用了-c copy但这个选项不是哪里都能随便用。TS 封装对编码格式有硬约束视频常见的是 H.264/HEVC音频是 AAC/MP3/AC-3。如果你的源是 MP4 里的 H.264AAC-c copy没问题如果源是 MOV 里的 ProRes 或者 MKV 里的某些私有编码直接 copy 到 TS 会出现“不支持的编解码器”甚至封装成功但绝大多数播放器解不了码。我一般会先跑一条快速检测ffmpeg -i input.mp4 -c copy -f mpegts output.ts能过且播放正常就走 copy省 CPU。如果失败或者对端播放器不认再转码。另一个坑是时间戳-c copy会保留源文件 PTS源文件如果是非零起始时间戳推给直播系统后可能出现时间戳跳变。这种情况我会加-output_ts_offset把起点抬平具体在第 3 章展开。3. 决定传输质量的关键参数码率、GOP、PCR 和时间戳怎么配合3.1 码率模型直播传输最怕码率突然拉满本地文件封装成 TS码率波动大一点无所谓因为文件是顺序读的缓冲可以容忍。但网络传输不一样TS 流通常走 UDP没有流量控制码率尖峰一上来交换机和接收端缓冲区扛不住最先丢的是这种瞬间爆发。所以传输用 TS码率控制模型比编码复杂度更值得先调。常见的做法是把 bitrate 从纯 VBR 拉平到 ABR 甚至 CBR。ffmpeg 命令里-b:v设平均码率-maxrate设峰值-bufsize设控制窗口。比如你要标清 2M建议这样写ffmpeg -re -i input.mp4 \ -c:v libx264 -preset fast \ -b:v 4M -maxrate 4M -bufsize 8M \ -x264-params nal-hrdcbr:force-cfr1 \ -c:a aac -b:a 128k \ -f mpegts udp://127.0.0.1:1234?pkt_size1316-x264-params nal-hrdcbr:force-cfr1是让 x264 在编码层面按 CBR 模式输出配合 ffmpeg 的 maxrate/bufsize输出的码率曲线会比较平TS 复用后的 PCR 也更稳定。代价是复杂画面会额外填充空数据带宽利用率略低。这条适合丢包敏感、追求设备兼容性的广电场景。还有个选项是-mpegts_muxrate它直接规定 TS 复用的总码率比如 5M。如果设了muxer 会按固定速率输出 TS 包不足的部分填充空包。这个值必须大于视频音频实际码率否则 ffmpeg 直接报错。一般我不会主动设它除非对端解码器要求 PCR 间隔非常均匀或者你在调一个把 TS 发给老式设备的项目。3.2 GOP 与关键帧丢包后要等多久才能恢复GOP 就是两个 I 帧之间的帧数。I 帧是完整的图像P 帧和 B 帧依赖参考帧。如果网络丢包丢掉了一个关键帧接收端必须等下一个 I 帧才能恢复完整画面。所以 GOP 太大会让丢包后的恢复时间变得难以接受。对于 25fps 的实时流我通常把 GOP 设为 50也就是两秒一个关键帧。命令这样写-g 50 -keyint_min 50 -sc_threshold 0-g 50是最大 GOP 长度-keyint_min 50保证最小也是 50-sc_threshold 0是关闭场景切换检测否则 ffmpeg 在画面突变时会强制插入新 I 帧导致 GOP 不均匀。统一 GOP 的好处是接收端和录制端能预估关键帧间隔做丢包恢复和 seek 都更容易。如果要追求更低恢复时间可以把 GOP 缩到 251 秒但码率会明显上升。反过来如果走 HTTP/TCP 这种可靠传输GOP 可以放到 100 甚至更长带宽省很多。所以 GOP 不是一个固定参数它取决于通道可靠性和延迟容忍度。3.3 PCR、PTS 和 DTS时间戳是整条流的“龙骨”TS 流里最容易被忽略但最影响体验的是时间戳。PCR 是编码器的节目时钟基准接收端用 PCR 重建时钟再用 PTS/DTS 决定什么时候显示、什么时候解码。如果 PCR 不连续或者跳变播放器会画面卡顿、音画分离。ffmpeg 的 mpegts muxer 会自动插入 PCR一般不用管。但你可以用-pcr_period 20调整 PCR 插入间隔单位是毫秒。默认值由 muxer 根据 muxrate 自动算设备兼容性不好的时候手动设成 20~40ms 是常见做法。间隔太小会浪费带宽太大则时钟重建误差增加。另一个关键参数是-muxdelay。它表示 muxer 在内存里缓存多少秒数据才开始输出默认值偏大直播场景会显著拉高延迟。我一般用-muxdelay 0.2或更低。注意它不能设成 0 之后再转码否则 B 帧导致的乱序会直接体现到输出流接收端可能突发重排。如果输入文件的 PTS 不是从 0 开始或带着奇怪的起始偏移播放器会误判。最简单的修正方法是给整条流加一个恒定偏移-output_ts_offset 10这样所有 PTS/DTS 都加上 10 秒PCR 也会跟着平移。很多直播系统要求时间戳必须从某个正值开始加偏移是保留时间精度的同时绕开“零时间戳”问题。对于从采集卡、USBCamera 这类设备拉流时间戳经常是错的或缺失可以加输入选项ffmpeg -fflags genpts -use_wallclock_as_timestamps 1 -i ...genpts强制生成 PTSuse_wallclock_as_timestamps用本机实时时间作为基准。这个组合我用来处理很多“画面能出但进度条乱跳”的诡异问题。3.4 低延迟推流的一组参数模板把前面几个点放在一起我常用这样一组低延迟推流命令ffmpeg -re -i input.mp4 \ -c:v libx264 -preset ultrafast -tune zerolatency \ -b:v 2M -maxrate 2M -bufsize 2M \ -g 50 -keyint_min 50 -sc_threshold 0 \ -c:a aac -b:a 96k -ac 2 \ -muxdelay 0.2 \ -f mpegts udp://127.0.0.1:1234?pkt_size1316preset ultrafast会比veryfast更快编码延迟更低但压缩率差所以b:v 2M下画质会不如 slower 预设。低延迟是用码率和画质换来的没有免费的午餐。这组参数适合做局域网内交互式监看如果走公网或录制存档还是把 preset 调回veryfast或fast更稳妥。4. 不同传输通道怎么选UDP、RTP 还是 HTTP4.1 UDP 单播与组播协议开销最低对网络最敏感UDP 是 TS 传输默认通道之一因为 TS 本身就是为不可靠传输设计的UDP 头开销只有 8 字节几乎没有额外协议成本。单播地址直接写对端 IPffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast \ -f mpegts udp://192.168.1.100:1234?pkt_size1316组播更省带宽适合一台编码器把一路流分发给多台解码端ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast \ -f mpegts udp://239.0.0.1:1234?pkt_size1316ttl16localaddr192.168.1.10ttl16是组播包的生存时间跨三层交换机时不能设太小。localaddr指定从哪个网卡发出多网卡机器上必须显式写否则可能从错误的接口出去。接收端同样要指定localaddr命令类似ffplay -fflags nobuffer -flags low_delay \ -i udp://239.0.0.1:1234?buffer_size65536localaddr192.168.1.20UDP 没有拥塞控制也没有重传。网络一旦有瞬时拥塞丢包就直接反映到画面马赛克和音频爆音。所以 UDP 通道适合受控的局域网跨公网我不推荐。4.2 RTP 承载 TS多一个包序号排查丢包更容易RTP 是在 UDP 之上加了 12 字节头里面带 sequence number 和 RTP timestamp。它不保证可靠传输但接收端能通过序号精确知道丢了哪几个包这在做网络质量评估和丢包补偿时非常有用。FFmpeg 的 muxer 名是rtp_mpegts专门把 MPEG-TS 流封装成 RTP 包ffmpeg -re -i input.mp4 \ -c:v libx264 -preset veryfast \ -f rtp_mpegts -sdp_file live.sdp \ rtp://127.0.0.1:5004?pkt_size1316-sdp_file live.sdp会让 ffmpeg 同时导出一个 SDP 描述文件里面写了媒体格式、端口号和负载类型。接收端可以直接用这个 SDP 文件拉起ffmpeg -protocol_whitelist file,udp,rtp -i live.sdp -c copy out.tsRTP 比裸 UDP 的延迟略高一点点但换来了可观测性。如果接收端具备 jitter bufferRTP 的抗抖能力会明显优于裸 UDP。需要注意RTP 有两种常见封装rtp_mpegts是直接把 TS 包整个放进 RTP适合已经复用好的多节目 TS另一种是 RTP 封装 H.264 裸流那是rtph264和本主题不是一回事别混。4.3 HTTP 承载 TS用可靠的 TCP 换来防火墙友好HTTP 承载 TS 有两种玩法。一种是直接把 TS 文件放 web 目录下播放端通过 HTTP 渐进式拉流另一种是向流媒体服务端用 HTTP PUT 推流相当于把实时 TS 流写进一个 URL。推流命令的核心是加-method PUT服务端要能接收 PUT 请求并持续写入。我一般在局域网自建一个开源流媒体服务然后这样推ffmpeg -re -i input.mp4 \ -c:v libx264 -preset veryfast \ -f mpegts -method PUT \ http://192.168.1.10:8080/live/stream.ts接收端更简单ffmpeg -i http://192.168.1.10:8080/live/stream.ts -c copy dump.tsHTTP 底层是 TCP有重传和拥塞控制所以丢包不会导致马赛克但代价是网络差时重传会堆积延迟越拉越长。另外HTTP 推流需要服务端配合不是随便一个 web server 都能接收实时写入。4.4 三种通道怎么选直接给结论通道可靠性端到端延迟防火墙/公网适用场景UDP低丢包无重传最低差公网受限局域网单播、组播分发RTP中有序号可检测丢包较低一般需要丢包监控和 QoE 统计HTTP高TCP 重传网络差时升高好公网拉流、推流到流媒体服务我的选择习惯是同机房、同局域网优先 UDP跨地区、跨运营商走 HTTP需要向运营方证明丢包率的时候选 RTP因为 RTP 的序号能直接换算成丢包率。5. TS 传输排坑与避坑清单我踩过的 5 类问题5.1 现象画面频繁花屏、马赛克音频偶尔卡顿原因UDP 通道丢包。码率超过交换机缓冲或接收端 UDP 缓冲太小都会导致 188 字节的 TS 包整体丢失画面直接出现马赛克块等下一个 I 帧才恢复。解决步骤第一步接收端加大buffer_size从 64K 加到 128K 或 256K。第二步推流端降低码率峰值确保maxrate不要超过实际带宽的 70%。第三步把 GOP 从 50 缩小到 25缩短受损画面的恢复时间。如果丢包率仍然存在就要考虑换 RTP 加 jitter buffer或者干脆走 HTTP。5.2 现象音画不同步越来越严重原因最常见的是输入文件是可变帧率 VFR但推流端没有强制 CFR。VFR 文件的 PTS 间隔不固定muxer 直接复用后音频和视频的速率会逐渐漂移。另一个原因是推流命令漏了-re导致文件被瞬间推完接收端缓冲混乱。解决推流时固定帧率新版 ffmpeg 用-fps_mode cfr旧版用-vsync cfr并配合-r 25ffmpeg -re -i input.mp4 -r 25 -fps_mode cfr \ -c:v libx264 -preset veryfast \ -c:a aac -af aresampleasync1:first_pts0 \ -f mpegts udp://127.0.0.1:1234?pkt_size1316aresampleasync1:first_pts0会把音频重采样并把第一帧音频 PTS 归零让音频和视频回到同一个时间基准。5.3 现象播放器报 PCR 错误、时间戳跳变原因输入源的 PTS 不是从 0 开始或者源文件本身带着不连续的时间戳。TS 的 PCR 本来要求单调且间隔稳定如果源文件起始 PTS 是几秒之外的值muxer 直接搬运后就会出现 PCR 跳变。解决给输出加一个正的偏移把所有时间戳抬到安全区域ffmpeg -re -i input.mp4 \ -c:v libx264 -preset veryfast \ -output_ts_offset 10 \ -f mpegts udp://127.0.0.1:1234同时把 mux 延迟压低避免 PCR 和 PTS 之间出现奇怪的交互-muxdelay 0.1如果是采集设备输入的流本身没有正确时间戳就在输入侧加-fflags genpts让 ffmpeg 用解码顺序生成 pts。5.4 现象组播拉不到流换成单播却是好的原因组播依赖 IGMP交换机和终端网卡必须支持并加入组播组。如果交换机开了 IGMP Snooping 但没配好组播帧会被直接过滤。还有一个高频坑是多网卡机器没指定localaddr数据从错误的网卡发出或收不到。解决推流端和接收端都显式绑网卡# 推流端 ffmpeg -re -i input.mp4 -c:v libx264 -preset veryfast \ -f mpegts udp://239.0.0.1:1234?pkt_size1316ttl16localaddr192.168.1.10 # 接收端 ffplay -fflags nobuffer -flags low_delay \ -i udp://239.0.0.1:1234?buffer_size65536localaddr192.168.1.20再用tcpdump -ni eth0 host 239.0.0.1抓包确认组播报文是否到达接收端。如果抓包能看到报文但播放器没画面问题大概率在播放器的 UDP 接收缓冲继续加参数即可。5.5 现象直播延迟越拉越长最后画面差好几秒原因一串参数叠加会导致延迟被不断放大。最常见的是-muxdelay默认值太大接收端播放器又开了一个大缓冲再加上编码端 B 帧队列三层缓冲直接拉出几秒延迟。另一个隐蔽原因是 GOP 太大播放器必须缓冲更长关键帧间隔才能保证流畅。解决推流端把-muxdelay压到0.1或0.2编码端用-tune zerolatency播放端用-fflags nobuffer -flags low_delay -audio_buffer_size 20。如果延迟还在增长检查 ffmpeg 日志里的time是否远小于实际耗时那说明-re没有生效或者源本身帧率不准用-fps_mode cfr修正。6. 用 ffprobe 和抓包验证链路把 TS 传输从“感觉”变成“指标”6.1 用 ffprobe 检查时间戳连续性和 PCR链路通了画面也正常但“正常”不等于“质量好”。我每次交付前都会把流存成文件再用 ffprobe 检查 PTS/DTSffprobe -show_packets -select_streams v \ -read_intervals 0:5 -show_entries packetpts,dts \ -of csvp0 dump.ts | awk -F, {print $1, $2} | head -20只看前几个包确认时间戳是单调递增的。如果出现突然归零、大跳、倒退说明 muxer 或源文件的时间戳没处理好。再做一次音频流对比确认视频和音频的 pts 起点在同一区域ffprobe -show_packets -select_streams a \ -read_intervals 0:5 -show_entries packetpts dump.ts | head -56.2 用 tcpdump 实测 UDP 丢包UDP 丢包率是 TS 链路的核心指标。发送端和接收端两侧各抓 1000 个包# 接收端统计 tcpdump -ni eth0 udp port 1234 -c 1000 | wc -l如果发送端确认发了 1000 个 UDP 报文但接收端只数到 980丢包 2%对应到 TS 画面就是每 50 帧丢一帧花屏概率很高。此时先加大接收缓冲再检查交换机端口统计基本能定位瓶颈。6.3 端到端延迟的土办法画时间戳进画面没有专业设备时我常用 drawtext 把本地时间画进画面再对比对端屏显ffmpeg -re -i input.mp4 \ -vf drawtexttext%{localtime}:x10:y10:fontsize36 \ -c:v libx264 -preset veryfast -tune zerolatency \ -f mpegts udp://127.0.0.1:1234接收端用 ffplay 播放画面里的时间和本机实际时间之差就是端到端延迟的粗略值。这个方法测不了亚毫秒级精度但能快速分辨延迟是 0.3 秒还是 3 秒定位瓶颈已经足够。我现在每次交付一条 TS 链路都会把 GOP、buffer_size、端到端延迟三个数字写进交接文档。传输排错没有玄学多数问题都是时间戳和缓冲的账。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑