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

如何让FFmpeg按顺序编码分辨率并实时更新HLS主播放列表?

解决方案:顺序编码HLS分辨率并实时更新主播放列表

要实现按顺序编码分辨率、完成一个就更新主播放列表的需求,核心思路是放弃-var_stream_map的并行编码逻辑,改为分批次单独处理每个分辨率,编码完成后立即将该流的信息追加到主播放列表中。以下是具体实现步骤和注意事项:


关键前提

所有分辨率的编码必须保证关键帧对齐,否则播放时切换分辨率会出现卡顿。需统一设置以下参数:

  • -g 48 -keyint_min 48:固定关键帧间隔
  • -sc_threshold 0:禁用场景切换自动插入关键帧
  • -hls_time 4:统一切片时长

步骤1:编码第一个分辨率(240p)并生成初始主播放列表

先编码最低分辨率,完成后立即生成可播放的主播放列表:

# 编码240p流
/home/test/ffmpeg -i 1.mp4 \
-map 0:v:0 -map 0:a:0 \
-c:v h264 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 \
-c:a aac -ar 48000 \
-filter:v scale="trunc(oh*a/2)*2:240" -maxrate:v 856k -bufsize:v 1200k -b:a 96k \
-hls_time 4 -hls_list_size 0 -hls_segment_filename 240p_%03d.ts 240p.m3u8

# 生成初始主播放列表
cat > master.m3u8 << EOF
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=952000,RESOLUTION=426x240,CODECS="avc1.4D401E,mp4a.40.2"
240p.m3u8
EOF

此时用户已经可以通过master.m3u8播放240p流。

步骤2:后台编码后续分辨率(480p/720p)并更新主播放列表

将后续分辨率的编码放到后台执行,完成后自动将流信息追加到主播放列表:

# 后台编码480p流(不占用终端)
nohup /home/test/ffmpeg -i 1.mp4 \
-map 0:v:0 -map 0:a:0 \
-c:v h264 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 \
-c:a aac -ar 48000 \
-filter:v scale="trunc(oh*a/2)*2:480" -maxrate:v 1498k -bufsize:v 2100k -b:a 128k \
-hls_time 4 -hls_list_size 0 -hls_segment_filename 480p_%03d.ts 480p.m3u8 > /dev/null 2>&1 &

# 等待480p编码完成后,更新主播放列表(可通过脚本自动检测,或手动执行)
echo -e "\n#EXT-X-STREAM-INF:BANDWIDTH=1626000,RESOLUTION=854x480,CODECS=\"avc1.4D401E,mp4a.40.2\"" >> master.m3u8
echo "480p.m3u8" >> master.m3u8

# 720p编码同理,重复上述逻辑
nohup /home/test/ffmpeg -i 1.mp4 \
-map 0:v:0 -map 0:a:0 \
-c:v h264 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 \
-c:a aac -ar 48000 \
-filter:v scale="trunc(oh*a/2)*2:720" -maxrate:v 2800k -bufsize:v 5600k -b:a 192k \
-hls_time 4 -hls_list_size 0 -hls_segment_filename 720p_%03d.ts 720p.m3u8 > /dev/null 2>&1 &

# 720p完成后更新主播放列表
echo -e "\n#EXT-X-STREAM-INF:BANDWIDTH=2992000,RESOLUTION=1280x720,CODECS=\"avc1.4D401E,mp4a.40.2\"" >> master.m3u8
echo "720p.m3u8" >> master.m3u8

自动化脚本(推荐)

可以写一个Shell脚本自动完成顺序编码和主列表更新,避免手动操作:

#!/bin/bash
INPUT_FILE="1.mp4"
MASTER_PL="master.m3u8"

# 初始化主播放列表
cat > $MASTER_PL << EOF
#EXTM3U
#EXT-X-VERSION:3
EOF

# 定义分辨率配置:名称 高度 视频码率 音频码率
RESOLUTIONS=(
    "240p 240 856k 96k"
    "480p 480 1498k 128k"
    "720p 720 2800k 192k"
)

for res in "${RESOLUTIONS[@]}"; do
    read name height v_bitrate a_bitrate <<< "$res"
    
    # 计算符合比例的宽度(保证偶数)
    width=$(ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 $INPUT_FILE | awk -F'x' -v h=$height '{print int(h*$1/$2/2)*2}')
    # 计算总带宽(视频+音频,转成bps)
    total_bps=$(( ${v_bitrate%k}*1000 + ${a_bitrate%k}*1000 ))

    # 编码当前分辨率
    echo "开始编码${name}..."
    /home/test/ffmpeg -i $INPUT_FILE \
    -map 0:v:0 -map 0:a:0 \
    -c:v h264 -profile:v main -crf 20 -sc_threshold 0 -g 48 -keyint_min 48 \
    -c:a aac -ar 48000 \
    -filter:v scale="${width}:${height}" -maxrate:v $v_bitrate -bufsize:v $(( ${v_bitrate%k}*2 ))k -b:a $a_bitrate \
    -hls_time 4 -hls_list_size 0 -hls_segment_filename "${name}_%03d.ts" "${name}.m3u8"

    # 更新主播放列表
    echo "已完成${name}编码,更新主播放列表..."
    echo -e "\n#EXT-X-STREAM-INF:BANDWIDTH=${total_bps},RESOLUTION=${width}x${height},CODECS=\"avc1.4D401E,mp4a.40.2\"" >> $MASTER_PL
    echo "${name}.m3u8" >> $MASTER_PL
done

echo "所有分辨率编码完成"

执行脚本后,会按顺序编码每个分辨率,完成一个就立即更新主播放列表,用户可随时播放已完成的流。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 18:57:09