Repository with minimal samples for playing HLS/DASH with CMAF video, across as many platforms as possible.
All test content in this repository was derived from the Netflix Open Source Content Platform which is licensed under the Creative Commons Attribution 4.0 International Public License
Currently the following titles exist as test media:
If you would like to follow along and encode your own piece of test content, refer to the Content Preparation section below.
Ensure you have:
- Node/NPM
- Web Browsers
- Android Studio
- Xcode
Optional things:
- Physical devices
You can point the samples at any content, but to get things off the ground this repo contains a sample encoded HLS/DASH with CMAF playlist with a two bitrate variations located in the .content
directory.
Before moving on to each platform, pop into that directory and run:
npm install
npm start
Inside of the /web
directory:
npm install
npm start
Then navigate to the individual pages. Note that the html5
sample will only work in Safari, or any browser that natively supports HLS and fMP4 (Fragmented MP4).
Samples available:
Inside of the /android
and /androidtv-firetv
directories respectively, open Android Studio to the root build.gradle
files. Build and run the apps on your device of choice.
Samples available:
Inside of the /ios-tvos-macos
directory, open Xcode to the project files. Build and run the apps on your device of choice, across the build targets.
Samples available:
Inside of the /roku
directory:
npm install
npm run build
There will be build generated here: ./out/roku.zip
To view on a Roku device, make sure your Roku is in developer mode and install the application by uploading the generated zip file to the Development Application Installer screen.
Note: the Roku device must be on the same network as the server hosting the content. The build command assumes your are hosting the content on the machine you are building on.
TODO
TODO
TODO
TODO
TODO
TODO
If you would like to prepare and use your own piece of media, the following section will walk you through the steps to properly encode and package sample content which can be played using the samples configured in this repo. Once packaged the content can be placed in the .content/public
directory.
For the sample content included in this repo the following transmuxing, transcoding, and packaging steps were performed.
To start, download the full Sol Levante 35GB HDR10 2020 ST2084 UHD source media file from the Netflix Open Source Content Platform above.
To work with a file of this size it's easier if we trim it down right from the start. We'll use a combination of ffmpeg
and bento4
throughout this process, but any media tools with sufficient spec compliance and codec support will do.
First we'll trim the video down to a 15 second section:
ffmpeg -i SolLevante_HDR10_r2020_ST2084_UHD_24fps_1000nit.mov \
-ss 00:00:30 -to 00:00:45 \
-c:v copy -c:a copy \
sollevante.mov
Now we'll transcode/transmux the .mov
QuickTime file to h.264 AAC:
ffmpeg -i sollevante.mov \
-vcodec h264 -acodec aac \
sollevante.mp4
Next we'll generate a 360p and 480p rendition of the new source content, using the Shaka Media Packager demo settings. These account for the correct GOP (Group of Pictures) alignment and bitrate settings.
# 360p
ffmpeg -i sollevante-main.mp4 -c:a copy \
-vf "scale=-2:360" \
-c:v libx264 -profile:v baseline -level:v 3.0 \
-x264-params scenecut=0:open_gop=0:min-keyint=72:keyint=72 \
-minrate 600k -maxrate 600k -bufsize 600k -b:v 600k \
-y sollevante_360p_600.mp4
# 480p
ffmpeg -i sollevante-main.mp4 -c:a copy \
-vf "scale=-2:480" \
-c:v libx264 -profile:v main -level:v 3.1 \
-x264-params scenecut=0:open_gop=0:min-keyint=72:keyint=72 \
-minrate 1000k -maxrate 1000k -bufsize 1000k -b:v 1000k \
-y sollevante_480p_1000.mp4
At this point we have two renditions of h.264 AAC mp4 content. In order to package this as CMAF we'll need to first transcode the content so it's fragmented. Internally this is just converting the actual sections of media data (mdat
) into consistently sized boxes, which in this case we'll make 3s to align with CMAF spec recommendations for compatibility between HLS and DASH.
To do the final steps we'll use bento4
. This packaging libraries requires the input renditions to be packaged are first fragmented:
bento4/bin/mp4fragment ./sollevante_360p_600.mp4 sollevante_360p_600_fragment.mp4
bbento4/bin/mp4fragment ./sollevante_480p_1000.mp4 sollevante_480p_1000_fragment.mp4
At this point we can wrap up our two fragmented renditions and host them under our .content
directory:
./bento4/bin/mp4dash --hls \
sollevante_360p_600_fragment.mp4 \
sollevante_480p_1000_fragment.mp4
This produces a content
directory in the same structure as provided under the .content/sol-levante
section.
Right now the content profile is encoded as High
, and ffmpeg was complaining about the inability to transcode the source media which already encoded with a high profile. If you need to tweak the profile you can use the following snippet:
ffmpeg -i sollevante.mp4 \
-vf "scale=2*trunc(iw/2):-2,setsar=1" \
-profile:v main -pix_fmt yuv420p \
sollevante-main.mp4