Nginx+FFmpeg搭建HLS流 播放时TS片段重复跳段问题如何解决
HLS流随机重复、跳片问题修复方案
该故障是推流关键帧配置、Nginx HLS切片逻辑、文件读取竞态三者不匹配导致的,播放器日志里的#EXT-X-DISCONTINUITY标记就是检测到切片不连续的直接证明——客户端拉到未写完的切片、序号跳变的切片时,就会触发重读旧片、跳过损坏片的逻辑,表现就是画面重复、跳数秒后恢复。
修复步骤
- 对齐推流GOP和切片时长
Nginx的RTMP模块只能在关键帧位置切割ts切片,你当前配置hls_fragment 3(3秒一切),但推流参数-g 30是30帧一个关键帧,如果源视频是30fps,GOP时长只有1秒;如果是25fps,GOP时长1.2秒,和3秒的切片配置完全错位,会出现切片时长波动、切片未写完就被写入m3u8列表的问题。
替换推流命令为如下内容,强制关键帧间隔和切片时长对齐,关闭场景切换自动插关键帧、关闭B帧避免时间戳错乱:
# 30fps源视频用-g 90,25fps源视频改成-g 75,保证GOP时长刚好3秒 ffmpeg -re -stream_loop -1 -i 'video1.mp4' \ -vcodec libx264 -vprofile baseline -bf 0 -g 90 -keyint_min 90 -sc_threshold 0 \ -acodec aac -strict -2 \ -f flv 'rtmp://172.20.120.75/show/test' &
- 补全Nginx RTMP模块HLS配置
你当前的HLS配置缺少切片写入保护、序号连续相关参数,修改rtmp服务下的application show块:
application show { live on; hls on; hls_path /var/hls/; hls_fragment 3; hls_playlist_length 60; # 新增以下配置 hls_fragment_naming system; # 用时间戳命名切片,避免序号重复冲突 hls_continuous on; # 推流中断重连时切片序号不跳变 hls_cleanup on; # 自动清理过期切片,避免旧文件干扰 deny play all; }
然后修改http块全局配置,删掉directio 512;这一行——directio是直接读写磁盘绕过系统缓存的配置,/tmp默认是内存文件系统,开这个参数会导致Nginx读取正在写入的ts文件时拿到截断的半截内容,直接触发播放器的不连续判定。
接着调整/hls路径的缓存策略,你现在给所有文件都设no-cache会导致ts文件重复拉取,还可能拉到写入中的文件,修改location块:
location /hls { access_log off; add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Expose-Headers' 'Content-Length'; # m3u8列表完全禁用缓存,保证客户端拿到最新列表 if ($request_uri ~* \.m3u8$) { add_header 'Cache-Control' 'no-cache, no-store, must-revalidate'; } # ts文件允许3秒缓存,避免重复拉取 if ($request_uri ~* \.ts$) { add_header 'Cache-Control' 'max-age=3'; } if ($request_method = 'OPTIONS') { add_header 'Access-Control-Allow-Origin' '*'; add_header 'Access-Control-Max-Age' 1728000; add_header 'Content-Type' 'text/plain charset=UTF-8'; add_header 'Content-Length' 0; return 204; } types { application/dash+xml mpd; application/vnd.apple.mpegurl m3u8; video/mp2t ts; } root /var/; }
- 替换切片存储目录
不要把HLS切片存在/tmp路径下,系统会定时清理/tmp下的临时文件,容易把正在使用的ts文件删掉,手动创建专用目录并授权:
mkdir -p /var/hls # CentOS/RHEL系统执行 chown nginx:nginx /var/hls # Ubuntu/Debian系统执行 # chown www-data:www-data /var/hls
验证方式
改完所有配置后重启Nginx,重启推流进程,拉流时如果ffplay日志里不再出现Skip ('#EXT-X-DISCONTINUITY')记录,播放就不会再出现重复、跳片问题。如果还有偶发异常,可以把hls_fragment改成4秒,和m3u8里的EXT-X-TARGETDURATION参数对齐,留1秒冗余抵消网络抖动影响。
内容的提问来源于stack exchange,提问作者Fugen
相关产品推荐
相关产品推荐

