How to Serve HLS Offline – Enabling Offline Playback of DRM-Protected Videos 

DRM (Digital Rights Management) protected videos are videos that are encrypted to prevent unauthorized distribution and copying. To provide offline playback of HLS-encoded DRM-protected videos means allowing users to download and view these encrypted videos without an internet connection. The challenge is to maintain encrypted protection when played offline. It is hence critical to ensure that the DRM protection remains intact even when the video is played without an internet connection. 

This white paper describes a solution that enables the offline playback of DRM-protected videos.

1. Constraints

The following constraints were taken into consideration:

1 – The solution needs to be compatible with the existing mobile app player and has to adopt a standard format.

2 – Offline support for DRM must be provided, ideally utilizing the existing platform’s DRM to deter the copying of downloaded videos.

3 – Re-transcoding of the content should be avoided to prevent increased cost.  Existing HLS files must be repackaged to enable offline playback.

4 – The solution must integrate with the existing authentication pipeline to limit video downloads to appropriate access.

5 – User-selectable download quality must be supported.

2. Method

2.1 DRM setup

The recommended platform solution employs a SPEKE server for the generation and distribution of DRM keys. The  SPEKE server will generate an AES-128 encryption key for each video during transcoding, which is then provided to the player through a unique URL when the video is played. The player deciphers the video segments using this key.

In order to play the video offline, the key must be provided to the player without accessing the SPEKE server. To achieve this, the key is  extracted from the SPEKE server and provided to the player through a local file.

2.2 HLS file structure

The below HLS files are stored on S3 and are structured as follows:

{course_id}/{lesson_id}/index.m3u8
{course_id}/{lesson_id}/index_{720/1080/2160}.m3u8
{course_id}/{lesson_id}/index_{720/1080/2160}_{1/…}.ts

Here, index.m3u8 is the master index file that points to each resolution’s index file. index_{720/1080/2160}.m3u8 is the index file for each resolution and contains a list of video segments and a URL to the SPEKE server, which provides the DRM decryption key for the segments.

2.3 Solution outline

The following is a high-level tutorial of the implementation:

  • Copy the HLS files for the video locally
  • Redirect the SPEKE DRM URL to a local file
  • Parse the available resolutions from the master HLS manifest
  • For each resolution:
    • Create a master manifest file pointing to the current resolution
    • Create a zip file containing the master manifest, the resolution manifest, and the current resolution video segments
    • Copy the resulting zip file to S3

This will result in the creation of a zip file for each resolution that can be downloaded by the user.

2.4 Playback logic

The following outlines the process for downloading and playing the video on the client side:

2.4.1 Downloading

Download the zip file for the desired resolution.

Download the SPEKE DRM key from the SPEKE server. This file can be downloaded and stored alongside the zip file, it is identified by the {course_id}-{lesson_id} ID pair.

2.4.2 Playing

  • Extract the zip file to a local folder.
  • Copy the SPEKE DRM key to the local folder.
  • Point the player to the master manifest file in the local folder and begin playback.

Since a standard HLS format is used, the video will play without any additional work. 

Access control can be managed through a lifecycle rule on the SPEKE DRM key file, which can delete the key after a specified amount of time offline. Once the key is deleted, the user will be required to re-authenticate and download the key again, the video does not need to be downloaded again.

3. Deployment

3.1 Requirements

Solution requirements:

  1. Easily and quickly deployable.
  2. Event-driven and integrated with the existing transcoding pipeline
  3. Does not require a constant connection to a server.
  4. Supports new resolutions/formats and available resolutions from the HLS manifest files must be dynamically parsed.

3.2 Implementation

The solution runs as a script within a Docker container on AWS Fargate. The container is launched by a Lambda function, which can be triggered by S3 events or manually for backlog processing.

The container has the following input parameters, which are passed through environment variables:

  • input_bucket: The name of the S3 input bucket containing the source HLS files
  • lesson_key: The course/lesson ID used to identify the current lesson being processed
  • output_bucket: The name of the S3 output bucket where the resulting zip files will be uploaded

The container task definition will be created once, and the environment variables will be filled in at runtime using the S3 event data by the Lambda function, which will then launch the task on Fargate.

A more detailed description of the logic of the script is provided below, along with a pseudo-code outline of the logic.

Copy the HLS files for the lesson locally:

aws s3 cp s3://{input_bucket}/{lesson_key} . –recursive

Redirect the SPEKE DRM URL to a local file:

sed -i ‘s|https://speke.foo.com/{lesson_key}/{UUID}|./{UUID}|g’ index.m3u8

Parse the available resolutions from the master HLS manifest:

# The following command will extract the available resolutions from the master HLS manifest, here the “1440” from the following line : # EXT-X-STREAM-INF:BANDWIDTH=2658558,AVERAGE-BANDWIDTH=895257,CODECS=”avc1.4d4032,mp4a.40.2″,RESOLUTION=2560×1440,FRAME-RATE=29.970
RESOLUTIONS=$(cat index.m3u8 | grep EXT-X-STREAM | sed -nr ‘s|.*RESOLUTION=[0-9]*x([0-9]*),.*|\1|p’)

For each resolution, the following steps are performed:

  1. Create a temporary folder and change to:
mkdir temp && cd temp
  1. Move the current resolution video segments and the corresponding manifest to the temporary folder:
mv ../index_{resolution}.m3u8 ../index_{resolution}_*.ts .
  1. Create a new master manifest file that points to the current resolution from the main master manifest:
# Copy the master manifest header
head -n 3 ../index.m3u8 > index.m3u8
# Copy the current resolution from the master manifest
cat ../index.m3u8 | grep -A 1 “x$resolution” >> index.m3u8
  1. Create a zip file that contains the master manifest, the resolution manifest, and the current resolution video segments:
zip -r ../{lesson_key}_{resolution}.zip index.m3u8 index_{resolution}.m3u8 index_{resolution}_*.ts
  1. Copy the resulting zip file to S3:
aws s3 cp ../{lesson_key}_{resolution}.zip s3://{output_bucket}/{lesson_key}_{resolution}.zip
  1. Change back to the parent folder and delete the temporary folder:
cd .. && rm -rf temp

The complete script is as follows:

#!/bin/sh

# Copy the HLS files for the lesson locally
aws s3 cp s3://${input_bucket}/${lesson_key} . –recursive

# Redirect the SPEKE DRM URL to a local file
sed -i ‘s|https://speke.foo.com/${lesson_key}/${UUID}|./${UUID}|g’ index.m3u8

# Parse the available resolutions from the master HLS manifest
RESOLUTIONS=$(cat index.m3u8 | grep EXT-X-STREAM | sed -nr ‘s|.*RESOLUTION=[0-9]*x([0-9]*),.*|\1|p’)

# For each resolution
for resolution in $RESOLUTIONS; do
# Create a temporary folder and move into it
mkdir temp && cd temp

# Move the current resolution video segments and associated manifest to the temporary folder
mv ../index_${resolution}.m3u8 ../index_${resolution}_*.ts .

# Create a new master manifest file pointing to the current resolution from the main master manifest
# Copy the master manifest header
head -n 3 ../index.m3u8 > index.m3u8
# Copy the current resolution from the master manifest
cat ../index.m3u8 | grep -A 1 “x$resolution” >> index.m3u8

# Create a zip file containing the master manifest, the resolution manifest and the current resolution video segments
zip -r ../${lesson_key}_${resolution}.zip index.m3u8 index_${resolution}.m3u8 index_${resolution}_*.ts

# Copy the resulting zip file to S3
aws s3 cp ../${lesson_key}_${resolution}.zip s3://${output_bucket}/${lesson_key}_${resolution}.zip

# Move back to the parent folder and delete the temporary folder
cd .. && rm -rf temp
done

Conclusion and Summary

The solution described in this article offers a way to enable offline playback of DRM-protected videos by performing the following steps: 

  1. Downloading HLS files locally
  2. Redirecting the SPEKE DRM URL to a local file 
  3. Parsing the available resolutions from the master HLS manifest
  4. Creating a new master manifest file pointing to the current resolution from the main master manifest
  5. Creating a zip file containing the master manifest, the resolution manifest, and the current resolution video segments. 

The solution addresses the challenge of offline playback of DRM-protected videos by ensuring that the necessary HLS files and manifests are accessible locally and the DRM protection remains intact. The resulting zip file is then copied to S3, providing an easily accessible method for offline playback.

About TrackIt

TrackIt is an Amazon Web Services Advanced Consulting Partner specializing in cloud management, consulting, and software development solutions based in Marina del Rey, CA.

TrackIt specializes in Modern Software Development, DevOps, Infrastructure-As-Code, Serverless, CI/CD, and Containerization with specialized expertise in Media & Entertainment workflows, High-Performance Computing environments, and data storage.

TrackIt’s forté is cutting-edge software design with deep expertise in containerization, serverless architectures, and innovative pipeline development. The TrackIt team can help you architect, design, build and deploy a customized solution tailored to your exact requirements.

In addition to providing cloud management, consulting, and modern software development services, TrackIt also provides an open-source AWS cost management tool that allows users to optimize their costs and resources on AWS.