Skip to content

Instantly share code, notes, and snippets.

@chrislavender
Last active April 19, 2024 15:28
Show Gist options
  • Save chrislavender/cad26500c9655627544f to your computer and use it in GitHub Desktop.
Save chrislavender/cad26500c9655627544f to your computer and use it in GitHub Desktop.
HTTP Live Streaming Tutorial

Note: This is an older post that I did back when I thought I might have time to be a blogger. Oh I was oh so wrong. However, it has proven useful for some folks on stackoverflow. Thus I'm keeping it alive here on Gist.

One of my past projects dealt heavily with an open source Apple technology called HTTP Live Streaming. It’s an HTTP based streaming protocol that at its most fundamental level provides a way to stream video and audio from just about any server with nothing but a few free software tools provided by Apple**. However, it has a few additional features that I think make it a really exciting tool. Yet, I haven’t seen HTTP Live Streaming used very much. This is probably mainly due to the combination of a lack of good/clear documentation, and Apple’s Live Streaming Developer Tools being command line based also make the barrier to entry higher than many developers want to deal with.

The hope is to share my understanding of how to use this technology to:

  • try to lower the barrier to entry for others
  • serve as a reference for myself when I forget parts of the process
For simplicity sake, this blog post focuses on using HTTP Live Streaming to deliver prerecorded material rather than an actual Live broadcast. However, the process is nearly identical. Also, I’ll be assuming that the assets to be streamed are being prepped using OSX based machines. This post is going to cover prepping a single .mp4 file for streaming using the mediafilesegmenter.

Table of Contents

Setup

The basic concept behind HTTP Live Streaming (or HLS) is relatively straight forward. Chop up the video into smaller chunks that are easier to transmit and create a header file (or “playlist”), which has the location and other information about the stream files so that the client knows where to go to get the video.

The first thing you need is some video encoded in .mp4 format. A popular cross platform tool for this is HandBrake and it is freely available with decent online documentation.

Additionally, the one bit of setup needed for your server is to configure the .htaccess file to be aware of what to do with the two file types associated with HLS. The two file types are

  • .m3u8: playlists that in this use-case point to different file segment “streams”
  • .ts: the segmented video files. Each series of .ts files constitutes a “stream”
To make sure your server knows how to handle these file types, you’ll need to locate the .htaccess file on your server. Note the “.” prefix, which means you’ll need to use a ftp client that will show hidden files. In your .htaccess file add these two lines:

 AddHandler application/x-mpegURL m3u8
 AddHandler video/MP2T ts

One gotcha (or at least it got me): note that the extensions do not have a “.” prefix on them. Just use “ts” rather than “.ts”.

At this point your server should be ready to roll.

Segment

First you’ll need to install Apple’s HTTP Live Streaming Developer Tools from the Apple Developer website. To segment a video, the only one of these tools you’ll need is the mediafilesegmenter command line program. You’ll know if it’s installed or not by going to the Terminal, typing mediaf, and hit TAB.

If installed it should autocomplete. Press Return and you should get a list of all the options for the mediafilesegmentor. There’s lots of options but we’re only interested in this:

 -f <path> | --file-base=<path>  : path at which to store index and media files

Obviously from the list of options there’s lots more you can do, but for basic segmentation for streaming this is all you need.

Now type in mediafilesegmenter -f and drag and drop into the Terminal window the folder in which you want the segmented files to be put. Then drag and drop your .mp4 file into the Terminal window. Finally, hit Return.

In my case the entire command line looked like this:

 mediafilesegmenter -f /Users/Chris/Desktop/test/segment_example  /Users/Chris/Desktop/test/thePianist.mp4

Relative paths will work here as well, so if I had navigated to the “test” folder and manually typed the relative paths it would have looked like this:

 mediafilesegmenter -f segment_example thePianist.mp4

Now you should have lots of segmented .ts files and a couple .m3u8 files in your destination folder (in my case called segmented_example). Next, take the entire folder and put it on the Apache server that has the .htaccess file you edited earlier.

Stream

Essentially you’re done at this point right? Let’s see if it worked. You can do this quick an easy by using the free open source media playback software VLC. Just use the “Advanced Open File…” option under the File menu and select “Network”. Then type the URL path to your prog_index.m3u8 file and choose Open. If it starts streaming everything went according to plan.

However, I’m guessing that doing all of this to simply play it back in an app like VLC is not what brought you here. You want to stream to a website or mobile device right?

HTML5 Playback

This is probably the most flexible option. Supposedly any HTML5 video player should work, but I use Video.js. There’s even a WordPress plugin that will allow you to play a stream from within a post!

Once installed, all you need to do is point the player to your prog_index.m3u8 file like this:

 <source src="http://www.thumbafon.com/code_examples/video/segment_example/prog_index.m3u8" type='application/x-mpegURL' / >

iOS AVPlayer

If you’re interested in streaming to an iOS device natively you can do it with code like this:

 #import <MediaPlayer/MediaPlayer.h>
  
 @interface ViewController ()
 @property (strong, nonatomic) MPMoviePlayerController *streamPlayer;
 @end
  
 @implementation ViewController
 @synthesize streamPlayer = _streamPlayer;
  
 - (void)viewDidLoad {
     NSURL *streamURL = [NSURL URLWithString:@"http://www.thumbafon.com/code_examples/video/segment_example/prog_index.m3u8"];
     _streamPlayer = [[MPMoviePlayerController alloc] initWithContentURL:streamURL];
     [self.streamPlayer.view setFrame: self.view.bounds ];
     self.streamPlayer.controlStyle = MPMovieControlStyleEmbedded;
     [self.view addSubview: self.streamPlayer.view];
     [self.streamPlayer play];
 }
  
 - (void)dealloc {
     // if non-ARC don't forget!
     // [_streamPlayer release];
     // [super dealloc];
 }
 
 @end

If you’ve got the hang of this, between the mediafilesegmenter options and the built in playback capabilities of your chosen playback framework, there’s a ton more to experiment with. I tried to give the most basic foot-in-the-door explanation that I could to here.

Now… why use this at all? I mean, you can just playback any .mp4 while it loads right? Well yes, but HTTP Live Streaming has some additional features that make it suitable for the right situation.

Of course there’s the Live Streaming part. And the magic is that it’s fundamentally the same process. However, instead of using mediafilesegmenter you use mediastreamsegmentor. Of course this is happening continuously in real-time so it is a little more complex.

There’s also Variant Playlists. This adds the ability to offer different streams depending on connection quality. The streams can be switched in real time. Plus, the audio can be abstracted away from the video allowing you to also provide separate audio tracks for your video streams that are switchable in real time. Why would you do that? Localization would be one good reason.

Finally there’s also the addition of Timed Metadata, or meta data that can be imprinted at explicit times in the video playback.

Happy coding!

Note** Apple’s software tools are free for registered Apple Developers. Of course the registration is not free. I understand that there are free third party tools available. However, I have no experience with them, and it’s unclear if all functionality (i.e. Timed Metadata) is available with these third party tools.

@bretsko
Copy link

bretsko commented Sep 11, 2016

Thanks for the tutorial, unfortunately MPMoviePlayerController is deprecated in iOS 9, only AVPlayer will be supported

@chrislavender
Copy link
Author

Indeed the example code is out dated. Follow the stackoverflow link at the top of the article. There's updated code examples there for iOS.

@r-a-o
Copy link

r-a-o commented Dec 2, 2018

import UIKit
import AVKit
...

class VideoPlayerViewController: UIViewController {

    var player: AVPlayer?

    override func viewDidLoad() {
        super.viewDidLoad()

        guard let url = URL(string: "http://stream-url.com/file.m3u8") else {
            print("Umm, looks like an invalid URL!")
            return
        }

        player = AVPlayer(url: url)
        let controller = AVPlayerViewController()
        controller.delegate = self
        controller.player = player

        // present the player controller & play
        present(controller, animated: true) {
            self.player?.play()
        }
    }

}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment