直播状态下手动更新Nginx-RTMP生成的.m3u8播放列表失败求助
解决Nginx-RTMP直播时HLS播放列表无法手动修改的问题
问题根源
Nginx-rtmp-module的HLS模块会主动维护m3u8播放列表:每次生成新的TS分片时,都会根据当前所有符合条件的分片重新生成完整的m3u8文件,覆盖你手动修改的内容。即使删除m3u8,模块也会自动重建包含所有历史分片的版本。
可行解决方案
方案1:禁用Nginx自动生成HLS,用自定义脚本维护播放列表
完全绕过Nginx的HLS自动生成逻辑,自己控制m3u8内容:
- 修改Nginx配置,关闭HLS自动生成:
rtmp { server { listen 1935; application live { live on; # 关闭hls指令,只将TS分片推送到指定目录 push rtmp://localhost:1935/hls_store; } application hls_store { live on; record all; record_path /var/www/html/cam/; record_suffix .ts; record_unique on; # 用系统时间命名分片,和原配置的hls_fragment_naming system一致 } } } - 编写脚本监控分片生成,动态生成只保留最后一个分片的m3u8:
用inotifywait监控目录的文件创建事件,每次有新TS文件生成时,重新生成m3u8:#!/bin/bash HLS_DIR="/var/www/html/cam/" PLAYLIST="${HLS_DIR}/index.m3u8" # 初始化播放列表头部 cat > $PLAYLIST <<EOF #EXTM3U #EXT-X-VERSION:3 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-TARGETDURATION:12 EOF # 监控目录,有新TS文件创建时更新播放列表 inotifywait -m -e create --format "%f" $HLS_DIR | while read FILE do if [[ $FILE == *.ts ]]; then # 清空原有分片条目,只保留最新的一个 sed -i '/#EXTINF:/,$d' $PLAYLIST echo "#EXTINF:10.000," >> $PLAYLIST echo "$FILE" >> $PLAYLIST fi done - 给脚本加执行权限并后台运行:
chmod +x update_hls_playlist.sh nohup ./update_hls_playlist.sh &
方案2:用Nginx反向代理+Lua过滤播放列表内容
如果不想完全禁用Nginx的HLS生成,可以通过ngx_lua模块在返回m3u8时动态修改内容:
- 确保Nginx已安装
ngx_lua模块(推荐用OpenResty) - 修改Nginx配置,添加自定义location处理m3u8请求:
http { server { listen 80; location /cam/index.m3u8 { set $original_playlist /var/www/html/cam/index.m3u8; content_by_lua_block { local file = io.open(ngx.var.original_playlist, "r") if not file then ngx.exit(404) end local content = file:read("*a") file:close() # 拆分播放列表为行 local lines = {} for line in string.gmatch(content, "[^\r\n]+") do table.insert(lines, line) end # 定位最后一个EXTINF条目位置 local last_extinf_idx = 0 for i, line in ipairs(lines) do if string.find(line, "^#EXTINF:") then last_extinf_idx = i end end # 重新构建只含最后一个分片的播放列表 local new_content = "" -- 保留前4行固定头部 for i=1,4 do new_content = new_content .. lines[i] .. "\n" end -- 添加最后一个分片的条目 for i=last_extinf_idx,#lines do new_content = new_content .. lines[i] .. "\n" end ngx.header.content_type = "application/vnd.apple.mpegurl" ngx.print(new_content) } } # 正常提供TS分片文件 location /cam/ { root /var/www/html/; } } } - 重启Nginx,此时访问
/cam/index.m3u8会自动返回只包含最后一个分片的播放列表。
方案3:调整Nginx HLS参数(近似需求)
如果只是想减少保留的分片数量,而非严格只留最后一个,可以将hls_playlist_length设为与分片时长一致的最小值:
hls_playlist_length 10s;
但此方法无法保证精确只留最后一个分片,适合对精度要求不高的场景。
内容的提问来源于stack exchange,提问作者Juan Trejos
相关产品推荐
相关产品推荐

