How to Create M3U8 with FFmpeg Segment Muxer

This guide explains how to generate an M3U8 index playlist file while splitting a live stream using FFmpeg's segment muxer. You will learn the exact command-line parameters required to slice your input stream into TS (Transport Stream) segments and simultaneously output a continuously updated HLS-compatible M3U8 playlist.

The Basic Command

To split an incoming stream and generate an M3U8 index file, use the -f segment muxer along with the -segment_list and -segment_list_type options.

Here is the fundamental command:

ffmpeg -i input_stream -codec copy -f segment -segment_time 10 -segment_list playlist.m3u8 -segment_list_type m3u8 segment_%03d.ts

Parameter Breakdown

  • -i input_stream: The source of your live stream (e.g., an RTMP feed, RTSP stream, or a local file).
  • -codec copy: Copies the video and audio streams without re-encoding, saving CPU resources.
  • -f segment: Specifies that the segment muxer should be used to split the stream.
  • -segment_time 10: Sets the target segment length to 10 seconds. Note that FFmpeg will split at the nearest keyframe (I-frame) after this duration.
  • -segment_list playlist.m3u8: Defines the name of the output index/playlist file.
  • -segment_list_type m3u8: Forces FFmpeg to format the index file as an HLS/M3U8 playlist.
  • segment_%03d.ts: The naming pattern for the generated TS segments (e.g., segment_001.ts, segment_002.ts).

Configuring for Live Streams

By default, the segment muxer behaves like a Video-on-Demand (VOD) recorder, appending all segments to the M3U8 file and adding an end tag (#EXT-X-ENDLIST). For a true live stream, you must configure a sliding window to keep only the most recent segments in the playlist.

Use the following options to optimize the playlist for live broadcasting:

ffmpeg -i input_stream -codec copy -f segment -segment_time 6 -segment_list_size 5 -segment_list_flags +live -segment_list_type m3u8 segment_%03d.ts

Key Live Parameters

  • -segment_list_size 5: Limits the M3U8 playlist to only contain the 5 most recent segments. Older segments are removed from the index file as new ones are added.
  • -segment_list_flags +live: Instructs the muxer to generate a live-compatible playlist. This prevents the #EXT-X-ENDLIST tag from being written to the end of the M3U8 file, allowing players to keep fetching updates.

Handling Keyframe Intervals (GOP Size)

Because FFmpeg can only split a stream on a keyframe, your segments might not be exactly equal to the -segment_time value if the source stream has irregular keyframe intervals.

To ensure precise segment lengths, you can force a constant Group of Pictures (GOP) size during encoding:

ffmpeg -i input_stream -c:v libx264 -g 60 -keyint_min 60 -f segment -segment_time 2 -segment_list playlist.m3u8 -segment_list_type m3u8 segment_%03d.ts

In this example:

  • -g 60 forces a keyframe every 60 frames.
  • If your stream is 30 frames per second (fps), a keyframe will occur exactly every 2 seconds, matching the -segment_time 2 duration for perfectly split segments.