Protected HLS using ffmpeg and openssl

This will walk you through creating Protected/ Encrypted hls stream using ffmpeg and openssl.

ffmpeg is a complete, cross-platform solution to record, convert and stream audio and video. It includes libavcodec – the leading audio/video codec library.

openssl : The OpenSSL Project is a collaborative effort to develop a robust, commercial-grade, full-featured, and Open Source toolkit implementing the Secure Sockets Layer (SSL v2/v3) and Transport Layer Security (TLS v1) protocols as well as a full-strength general purpose cryptography library.

Protected HLS : is encrypted apple hls. It’s not a complete DRM solution. In this method segment files are encrypted using AES-128 bit

Im using a ubuntu 13.10 box.

Step 1 : Install openssl and ffmpeg

apt-get install openssl ffmpeg

 

Step 2 : segment your video file for hls playback.

ffmpeg -i $input -vcodec libx264 -acodec libvo_aacenc -b:v 128k -flags -global_header -map 0:0 -map 0:1 -f segment -segment_time 4 -segment_list_size 0 -segment_list list.m3u8 -segment_format mpegts stream%d.ts

Here $input is input video file. This command will create a list of streamxx.ts files and list.m3u8 file. You can open this m3u8 file in a hls supported player or on a android/ios devices through a web service to confirm segments are working. (Note: segments should be on the same folder as m3u8 file)

 

Step 3 : encrypt the segments. Create following bash script in the same folder and execute it to encrypt segments.

#!/bin/bash

keyFile=”video.key”
openssl rand 16 > $keyFile
encryptionKey=`cat $keyFile | hexdump -e ’16/1 “%02x”‘`

splitFilePrefix=”stream”
encryptedSplitFilePrefix=”enc/${splitFilePrefix}”

numberOfTsFiles=`ls ${splitFilePrefix}*.ts | wc -l`

for (( i=1; i<$numberOfTsFiles; i++ ))
do
initializationVector=`printf ‘%032x’ $i`
openssl aes-128-cbc -e -in ${splitFilePrefix}$i.ts -out ${encryptedSplitFilePrefix}$i.ts -nosalt -iv $initializationVector -K $encryptionKey

done

This will create a ‘enc’ folder and create encrypted segments in that folder.

 

Step 4 : move/copy video.key and list.m3u8 to enc folder and modify the list.m3u8 as follow (use gedit or notepad),

#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-ALLOW-CACHE:YES
#EXT-X-KEY:METHOD=AES-128,URI=”video.key”
#EXT-X-TARGETDURATION:9

just insert the bold line and leave the rest as it is.

 

All done, now simply open the m3u8 file using a supported player or iphone/android device. I tested this successfully on a Android 4.2 device just few seconds ago. Good Luck.

Feel free to ask any questions you have

 

Thank you “Robert D” for pointing out the bug.

Pay attention to quotes when you copy paste from the site.

Advertisements

15 thoughts on “Protected HLS using ffmpeg and openssl

  1. 1. ffmpeg -i $input -vcodec libx264 -acodec libvo_aacenc -b:v 128k -flags -global_header -map 0:0 -map 0:1 -f segment -segment_time 4 -segment_list_size 0 -segment_list list.m3u8 -segment_format mpegts stream%d.ts

    even though I just downloaded ffmpeg. This step doesn’t work for me.

    Unable to find a suitable output format for ‘128k’
    128k: Invalid argument

    So I changed it to:

    ffmpeg -i filename.mp4 -acodec libvo_aacenc -c:v libx264 -profile:v high -level 41 -b:v 600K -flags -global_header -map 0:0 -map 0:1 -f segment -segment_time 4 -segment_list_size 0 -segment_list list.m3u8 -segment_format mpegts stream%d.ts

    2.
    keyFile=”video.key”
    openssl rand 16 > $encyptionKeyFile

    Wouldn’t the second line actually be:
    openssl rand 16 > $keyFile

    ?

    also on my machine (mac) I have to create the enc folder. It does not create it. Also I have to carefully replace all the single quotes and double quotes.

    after that it does produce a video that will play on an iOS device, but doesn’t ever start on Android (Nexus 7/Android 4.4.2).

    I’ve been googling around because Android is so picky on what it will play, but nobody has the steps that make it work consistently. Some video’s play on the device, others don’t.

    • yes it should be $keyFile. Im changing now. Thanx

      I couldn’t test on many devices, I will soon. But so far the stream I generated played perfectly with my HTC One x (Android 4.2.2 stock mod)

      You have changed encoding parameters, please check wether its compliant with android standards. I’m really busy at the moment. I will look into it asap

    • what you are looking (android standards) is this,

      according to that document you must use baseline profile to maintain compatibility with android devices. (Look under video -> H.264 AVC). But you are using “high” profile. THat why it doesn’t work on most android devices. In my experience stock android hls support is buggy. But manufactures have done their own improvements. So hls does work on most android devices reasonably.

  2. Thanks for sharing this. I am trying to convert the encryption piece to nodejs and having a hard time with it. any pointers would be much appreciated.

    • I got this far…

      // key: 32 hex characters
      // iv: the index of the chunk (integer)

      function encryptFile (inputPath, outputPath, key, iv , options, callback) {

      if(typeof options === ‘function’) {
      callback = options;
      options = {};
      }

      var keyBuf = new Buffer(key);
      var ivBuf = new Buffer(iv.toString(’16’));

      var inputStream = fs.createReadStream(inputPath);
      var outputStream = fs.createWriteStream(outputPath);
      var cipher = crypto.createCipheriv(options.algorithm, keyBuf,ivBuf);

      inputStream.on(‘data’, function(data) {
      var buf = new Buffer(cipher.update(data), ‘binary’);
      outputStream.write(buf);
      });

      inputStream.on(‘end’, function() {
      var buf = new Buffer(cipher.final(‘binary’), ‘binary’);
      outputStream.write(buf);
      outputStream.end();
      outputStream.on(‘close’, function() {
      callback();
      });
      });
      };

  3. Thanks for your great job. Actually I did all the things you mentioned above. The one difference that we have is that I added IV in both encryption command and m3u8.
    When I use VLC to play, it shows that

    httplive info: HTTP Live Streaming (my_ip_address/sample/sample.m3u8)
    httplive error: IV invalid
    core info: stopping playback

    Also, when I play the m3u8 ony any devices, it just stopped at the first scene. After a few minutes, it can play the video.

    Have you or anyone ever encountered before?

  4. Can you please post you key file content? I’m trying to do it using ffmpeg and I’ve used 12345678901234567890123456789011 as the key. But android is not able to decrypt and play it even though it’s getting the key properly. I might have made some mistake making the key file.

  5. Hi,

    I am using Windows 2008 serve, I have created m3u8 package using FFMPEG, I wanted to add AES 128 encryption. Can you please provide step by step procedure to do the same. I don’t have much experience in streaming so I need some basic steps and tools for using encryption. I also wanted to know once I encrypted, how can I open them?
    At present m3u8 package which I have created is playing fine in VLC, if I put that package in Tomcat folder at “D:\apache-tomcat-9.0.0.M10\webapps\ROOT” and try to stream them using VLC. Streamed output I am trying checked on “https://www.hlsplayer.net/rtmp-player” showing error in m3u8 file. (I am not sure if I am doing correctly)

    Thanks in advance.

    Vij

  6. Hi,
    I am trying to encrypt a video(mp4) file having a single file output. Here is the command that I use: ffmpeg -i -c:v libx264 -preset slow -hls_list_size 0 -hls_key_info_file encrypt.keyinfo -f hls -hls_playlist_type vod -hls_time 20 -threads 0 . However when I play the generated m3u8 file in safari the video stop for seconds(timer goes on) and resume after few seconds. This is happens multiple times in a single video playback. Can anyone help me to encode video file with single output file.

  7. Thx for the article! Sometimes the good example is better than all huge documentation!

    But sorry script is still not workng without “Robert D” comments. Still you need

    mkdir enc

    and

    keyFile=”video.key”
    openssl rand 16 > $encyptionKeyFile

    to

    keyFile=”video.key”
    openssl rand 16 > $keyFile

    If you achieving the error about “hexdump 16/1 ” again follow the comment of “Robert D” and ” carefully replace all the single quotes and double quotes.” looks like copying from your site occuring this. `cat $keyFile | hexdump -e ’16/1 “%02x”‘`

  8. Thanks for this post!

    Do you have any idea on how to achieve key rotation for live streaming?

    Thanks

  9. Pingback: FFMPEG STREAMING – Nhan Le Dinh
  10. Pingback: Live Streaming With FFMPEG – Kobe Nguyen

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s