You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

直播状态下手动更新Nginx-RTMP生成的.m3u8播放列表失败求助

解决Nginx-RTMP直播时HLS播放列表无法手动修改的问题

问题根源

Nginx-rtmp-module的HLS模块会主动维护m3u8播放列表:每次生成新的TS分片时,都会根据当前所有符合条件的分片重新生成完整的m3u8文件,覆盖你手动修改的内容。即使删除m3u8,模块也会自动重建包含所有历史分片的版本。

可行解决方案

方案1:禁用Nginx自动生成HLS,用自定义脚本维护播放列表

完全绕过Nginx的HLS自动生成逻辑,自己控制m3u8内容:

  1. 修改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一致
            }
        }
    }
    
  2. 编写脚本监控分片生成,动态生成只保留最后一个分片的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
    
  3. 给脚本加执行权限并后台运行:
    chmod +x update_hls_playlist.sh
    nohup ./update_hls_playlist.sh &
    

方案2:用Nginx反向代理+Lua过滤播放列表内容

如果不想完全禁用Nginx的HLS生成,可以通过ngx_lua模块在返回m3u8时动态修改内容:

  1. 确保Nginx已安装ngx_lua模块(推荐用OpenResty)
  2. 修改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/;
            }
        }
    }
    
  3. 重启Nginx,此时访问/cam/index.m3u8会自动返回只包含最后一个分片的播放列表。

方案3:调整Nginx HLS参数(近似需求)

如果只是想减少保留的分片数量,而非严格只留最后一个,可以将hls_playlist_length设为与分片时长一致的最小值:

hls_playlist_length 10s;

但此方法无法保证精确只留最后一个分片,适合对精度要求不高的场景。

内容的提问来源于stack exchange,提问作者Juan Trejos

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 11:39:46