首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >FFmpeg输出hls时ts切片和m3u8索引动态更新解读

FFmpeg输出hls时ts切片和m3u8索引动态更新解读

原创
作者头像
liuzhen007
发布2025-07-13 22:06:30
发布2025-07-13 22:06:30
5630
举报
文章被收录于专栏:流媒体音视频流媒体音视频

前言

众所周知,FFmpeg输出hls时,m3u8索引文件是在不断动态更新的,每当新的ts切片生成,就会更新一次m3u8文件。但是,其中有很多细节需要我们深入探究,比如m3u8文件在更新时,如何避免读写不一致问题?所有ts切片的时长都是一样的吗?

正文

一、主要过程

1、初始化

这个过程主要是生成一个空的m3u8索引文件,然后在其中输入一些初始化标签,比如 #EXTM3U、#EXT-X-VERSION和#EXT-X-TARGETDURATION 等。

示例如下:

代码语言:txt
复制
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:10
#EXT-X-MEDIA-SEQUENCE:0

2、循环生成切片

hls处理模块不断接收音频流和视频流的数据包,把音频帧和视频帧写入到ts切片中,这里可能涉及到交错存储,先不展开说了,后续文章再详细说明。当满足切割条件时,比如关键帧到达或者时间阈值到达时,就会停止当前ts切片的写入并存储到物理磁盘,同时,生成新的 index+1 的 ts 切片继续写入。

3、更新索引文件

为了保证m3u8索引文件读写一致,会进行原子更新。首先,创建一个临时 .m3u8.tmp 文件,添加新切片条目,以 #EXTINF 标签开头,后面追加新切片的时长。如果此时播放列表已经满了,则移除最旧条目并递增媒体序列号(#EXT-X-MEDIA-SEQUENCE),.m3u8.tmp 文件的写操作完成后,直接替换原 .m3u8 索引文件。这个过程可以通过系统的重命名操作完成,实现原子化操作。

4、结束处理

如果启用了 delete_segments 参数,那么在过程中会自动删除从 m3u8 文件中移除的 ts 切片文件。当输入流结束时添加 #EXT-X-ENDLIST 结束标记,但如果是直播流的话,不会加这个标识,只有点播 m3u8 文件才有。

如果上述文字介绍过于枯燥,可以通过下面的流程图加强理解:

流程图的源代码如下:

代码语言:svg
复制
flowchart TD
    A([开始HLS输出]) --> B[初始化参数]
    B --> C[创建初始.m3u8文件]
    C --> D[设置媒体序列号( #EXT-X-MEDIA-SEQUENCE:0)]
    D --> E[接收音视频流数据]
    
    E --> F{达到切片条件?(关键帧 or 时间阈值)}
    F -- 是 --> G[生成新.ts切片文件]
    F -- 否 --> E
    
    G --> H[写入.ts文件到磁盘]
    H --> I[更新.m3u8索引文件]
    
    subgraph 更新索引文件 [原子化更新]
        I --> J[创建临时文件 .m3u8.tmp]
        J --> K[添加新切片信息 #EXTINF:时长, 文件名]
        K --> L{播放列表满?(hls_list_size限制)}
        L -- 是 --> M[移除最旧切片条目]
        L -- 否 --> N
        M --> N[递增媒体序列号 (#EXT-X-MEDIA-SEQUENCE+1)]
        N --> O[写入临时文件内容]
        O --> P[重命名临时文件替换原.m3u8]
    end
    
    P --> Q{启用删除旧切片}
    Q -- 是 --> R[删除播放列表外的旧.ts文件]
    Q -- 否 --> S
    R --> S
    
    S --> T{输入流结束?}
    T -- 否 --> E
    T -- 是 --> U[添加结束标记(#EXT-X-ENDLIST)]
    U --> V([结束])

二、关键参数

1、hls_time

控制切片的频率,多久生成一个 ts 切片,从而影响 m3u8 索引文件的更新频率。值越小,切片越频繁,更新越快,延迟越低(但也可能增加服务器和客户端负担)。比如 -hls_time 10 则表示 10 秒一个 ts 切片。

2、hls_list_size

控制播放列表的窗口大小,也就是 .m3u8 中有多少个 ts 切片。

3、delete_segments

开启后会实现磁盘空间的自动清理,避免旧的ts 切片文件无限累积,需要与 -hls_flags 一起使用。

4、single_file

这是一个特殊的控制参数,也需要与 -hls_flags 一起使用。启用后,FFmpeg 会将所有切片数据写入一个巨大的 .ts 切片文件。.m3u8 文件会动态更新,通过 #EXT-X-BYTERANGE 标签指向不同字节范围来模拟独立的切片。更新 .m3u8 时,只需添加新的 #EXTINF 和 #EXT-X-BYTERANGE 条目指向新写入的数据范围即可。

三、关键标签

1、#EXTM3U

标识文件是 m3u8 文件播放列表,必须放在文件第一行。

2、#EXT-X-VERSION

指定 hls 协议的版本,比如3、4、7等,不同版本支持的标签有所不同。

3、#EXTINF

描述每个媒体 ts 切片的时长(秒)和标题。注意:duration 必须是浮点数。

4、#EXT-X-TARGETDURATION

指定所有切片的目标时长。

5、#EXT-X-MEDIA-SEQUENCE

标识播放列表中第一个切片的序列号,一般从0开始。

6、#EXT-X-ENDLIST

标识播放列表结束,不再更新,直播场景中没有,但是点播场景中必须有。

四、主要方法

对应上面的主要过程,我们来看一下底层的代码。

1、hls_init()+hls_write_header()

解析 -hls_time 等参数,创建初始 ts 切片文件,初始化 m3u8 播放列表。

2、hls_write_packet()

生成 ts 切片,同时处理 ts 切片的切割逻辑并更新 m3u8 索引文件。

3、hls_write_trailer()+hls_deinit()

写入最后一个切片,更新 m3u8 文件,追加 #EXT-X-ENDLIST 标签。最后,释放上下文相关的资源。

最后,也可以通过下面的时序图加深理解:

最后

通过本文的介绍,我们了解了 FFmpeg 输出 hls 的关键步骤和主要方法,其逻辑清晰,涉及 init、header、packet、trailer、deinit 五个阶段,实现了高度可扩展的 hls 生成能力,既能处理点播文件转换,也能支持高并发场景下的直播流。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 正文
    • 一、主要过程
      • 1、初始化
      • 2、循环生成切片
      • 3、更新索引文件
      • 4、结束处理
    • 二、关键参数
      • 1、hls_time
      • 2、hls_list_size
      • 3、delete_segments
      • 4、single_file
    • 三、关键标签
      • 1、#EXTM3U
      • 2、#EXT-X-VERSION
      • 3、#EXTINF
      • 4、#EXT-X-TARGETDURATION
      • 5、#EXT-X-MEDIA-SEQUENCE
      • 6、#EXT-X-ENDLIST
    • 四、主要方法
      • 1、hls_init()+hls_write_header()
      • 2、hls_write_packet()
      • 3、hls_write_trailer()+hls_deinit()
  • 最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档