Create M3U8 Playlist

Want to stream your own videos using **M3U8**? Maybe for a personal website, online course, or small streaming service? This guide will walk you through the entire process, from encoding videos to hosting playlists.

What You'll Need

Before starting, gather these tools:

  • FFmpeg - For video encoding and segmentation (free)
  • A web server - Apache, Nginx, or cloud hosting
  • Your source video - MP4, MOV, AVI, whatever you have
  • Text editor - Any will do
  • Basic command line knowledge - We'll use terminal commands

Step 1: Install FFmpeg

Windows:

Download from ffmpeg.org. Extract to a folder like C:\ffmpeg. Add to system PATH for easy access.

Mac:

brew install ffmpeg

Linux (Ubuntu/Debian):

sudo apt update
sudo apt install ffmpeg

Verify installation:

ffmpeg -version

Step 2: Basic Video Segmentation

Let's start simple - convert one video to M3U8 format.

Basic command:

ffmpeg -i input.mp4 \
  -codec: copy \
  -start_number 0 \
  -hls_time 10 \
  -hls_list_size 0 \
  -f hls \
  output.m3u8

This creates:

  • output.m3u8 - The playlist file
  • output0.ts, output1.ts, ... - Video segments

Each segment is 10 seconds (controlled by -hls_time 10).

Step 3: Creating Multiple Quality Levels

For adaptive streaming, encode multiple quality versions.

Create 1080p version:

ffmpeg -i input.mp4 \
  -vf scale=1920:1080 \
  -c:v libx264 -b:v 5000k \
  -c:a aac -b:a 128k \
  -hls_time 6 \
  -hls_playlist_type vod \
  -hls_segment_filename "1080p_%03d.ts" \
  1080p.m3u8

Create 720p version:

ffmpeg -i input.mp4 \
  -vf scale=1280:720 \
  -c:v libx264 -b:v 2500k \
  -c:a aac -b:a 128k \
  -hls_time 6 \
  -hls_playlist_type vod \
  -hls_segment_filename "720p_%03d.ts" \
  720p.m3u8

Create 480p version:

ffmpeg -i input.mp4 \
  -vf scale=854:480 \
  -c:v libx264 -b:v 1000k \
  -c:a aac -b:a 96k \
  -hls_time 6 \
  -hls_playlist_type vod \
  -hls_segment_filename "480p_%03d.ts" \
  480p.m3u8

Step 4: Create Master Playlist

Now create a master playlist that lists all quality levels.

Create file master.m3u8:

#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080
1080p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2500000,RESOLUTION=1280x720
720p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1000000,RESOLUTION=854x480
480p.m3u8

Players will load this master playlist first, then choose appropriate quality based on bandwidth.

Step 5: Organize Your Files

Keep things tidy:

video/
  master.m3u8
  1080p.m3u8
  1080p_000.ts
  1080p_001.ts
  ...
  720p.m3u8
  720p_000.ts
  720p_001.ts
  ...
  480p.m3u8
  480p_000.ts
  480p_001.ts
  ...

Or organize by quality:

video/
  master.m3u8
  1080p/
    index.m3u8
    segment_000.ts
    segment_001.ts
  720p/
    index.m3u8
    segment_000.ts
    segment_001.ts

Step 6: Set Up Web Server

Simple Python Server (for testing):

Navigate to your video folder and run:

python3 -m http.server 8000

Access at http://localhost:8000/master.m3u8

Nginx Configuration:

For production, configure Nginx properly:

server {
    listen 80;
    server_name your-domain.com;
    
    location /videos/ {
        alias /path/to/videos/;
        
        types {
            application/vnd.apple.mpegurl m3u8;
            video/mp2t ts;
        }
        
        add_header Cache-Control "public, max-age=3600";
        add_header Access-Control-Allow-Origin "*";
    }
}

Step 7: Enable CORS

For web playback, enable Cross-Origin Resource Sharing.

Apache (.htaccess):

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "GET, HEAD"

Nginx:

add_header Access-Control-Allow-Origin "*";
add_header Access-Control-Allow-Methods "GET, HEAD";

Step 8: Test Your Playlist

Test with multiple methods:

VLC Player:

vlc http://localhost:8000/master.m3u8

Browser:

Use our M3U8 player to test your playlist URL.

Command line validation:

ffmpeg -v error -i master.m3u8 -f null -

No output means no errors!

Step 9: Add Encryption (Optional)

Protect your content with AES-128 encryption.

Generate encryption key:

openssl rand 16 > encryption.key

Create key info file (enc.keyinfo):

http://your-domain.com/encryption.key
encryption.key
$(openssl rand -hex 16)

Encode with encryption:

ffmpeg -i input.mp4 \
  -hls_key_info_file enc.keyinfo \
  -hls_time 6 \
  -hls_playlist_type vod \
  output.m3u8

The playlist will include encryption tags. Players fetch the key automatically.

Step 10: CDN Distribution

For serious traffic, use a CDN.

Popular CDN Options:

  • Cloudflare - Good free tier
  • AWS CloudFront - Integrates with S3
  • Fastly - High performance

Setup process (general):

  1. Upload videos to your origin server or S3
  2. Configure CDN to cache .m3u8 and .ts files
  3. Set appropriate cache TTLs
  4. Update playlist URLs to use CDN domain

Batch Processing Multiple Videos

Create a script to process many videos:

#!/bin/bash
for video in *.mp4; do
    name="${video%.mp4}"
    
    # Create output directory
    mkdir -p "$name"
    
    # Generate 1080p
    ffmpeg -i "$video" \
        -vf scale=1920:1080 \
        -c:v libx264 -b:v 5000k \
        -c:a aac -b:a 128k \
        -hls_time 6 \
        -hls_segment_filename "$name/1080p_%03d.ts" \
        "$name/1080p.m3u8"
    
    # Generate 720p
    ffmpeg -i "$video" \
        -vf scale=1280:720 \
        -c:v libx264 -b:v 2500k \
        -c:a aac -b:a 128k \
        -hls_time 6 \
        -hls_segment_filename "$name/720p_%03d.ts" \
        "$name/720p.m3u8"
    
    # Create master playlist
    cat > "$name/master.m3u8" << EOF
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=5000000,RESOLUTION=1920x1080
1080p.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2500000,RESOLUTION=1280x720
720p.m3u8
EOF
    
    echo "Processed $video"
done

Optimization Tips

Choose right segment length:

  • 6-10 seconds for VOD (good balance)
  • 2-4 seconds for low-latency live
  • Longer segments = less overhead, slower adaptation

Encoding settings:

  • Use H.264 for maximum compatibility
  • H.265 for better compression (check device support)
  • AAC audio codec universally supported

Bitrate ladder:

Offer quality levels spaced 2-3x apart in bitrate. For example: 500k, 1500k, 4500k.

Monitoring and Analytics

Track playlist usage:

Server logs:

Analyze access logs to see popular videos, quality selection patterns, geographic distribution.

Player analytics:

Implement JavaScript tracking in your player to gather playback metrics.

Common Pitfalls to Avoid

  • Don't use spaces in filenames - causes URL encoding issues
  • Always test different quality levels individually
  • Set correct MIME types on server
  • Include CORS headers from the start
  • Keep segment duration consistent within a playlist

Scaling Considerations

As your service grows:

Storage:

Multiple quality levels multiply storage needs. Budget accordingly.

Bandwidth:

Popular videos consume significant bandwidth. CDN becomes essential.

Encoding:

Consider cloud transcoding services (AWS MediaConvert, Zencoder) for large volumes.

Alternative: Simpler Solutions

If this seems complex, alternatives exist:

For simple use cases, platforms like Vimeo or YouTube handle all the technical details. You just upload.

If you need more control but less complexity, consider video hosting services like Mux or JW Player. They provide APIs for uploading and streaming.

Building your own infrastructure makes sense when you need full control, have specific requirements, or want to minimize ongoing costs.

Conclusion

Creating M3U8 playlists isn't as daunting as it first appears. FFmpeg does the heavy lifting. A basic web server hosts the files. Add a CDN for scale.

Start small - single quality, no encryption. Get that working first. Then add complexity as needed.

Once set up, you have full control over your video delivery. No platform restrictions, no unexpected fees, complete ownership.

If you want to test M3U8 playback without building infrastructure, try our online player. And if you need to go the other direction - converting M3U8 back to MP4 - our converter handles that easily.

Back to Blog