For an overview of HLS and why we recommend it for video NFTs, see the HLS section in our Video NFTs guide.
How HLS works
HLS delivers videos as a series of small files called media segment files. These are either Video Transport Stream files (*.ts
) or fragmented mp4 files (*.mp4
or *.fmp4
).
HLS uses a multivariant (master) playlist to start the stream. This playlist is a text file (*.m3u8
) listing all the variant playlists files available to the player and additional information about what those variant playlists contain. The variant playlists contain lists of the video segments.
Master Playlist (.m3u8)
├── Variant Playlist 1 (.m3u8)
│ ├── Video Segment 1 (.ts)
│ ├── Video Segment 2 (.ts)
│ └── ...
├── Variant Playlist 2 (.m3u8)
│ ├── Video Segment 1 (.ts)
│ ├── Video Segment 2 (.ts)
│ └── ...
...
├── Variant Playlist N (.m3u8)
├── Video Segment 1 (.ts)
├── Video Segment 2 (.ts)
└── ...
A live example
Guild of Guardians uses this setup for their collection. Let's take a look at an example:
The animation_url
points to CollectionAsset_Hero_Varik_Base.m3u8
, which is the multi-variant playlist and is a text file that holds references to other variant playlists. It also lists the peak bitrate (BANDWIDTH
) of each variant—this is used to determined which variant should be played based on the client’s bandwidth.
#EXTM3U #EXT-X-VERSION:3 #EXT-X-STREAM-INF:BANDWIDTH=2944000,RESOLUTION=480x480,NAME="480" CollectionAsset_Hero_Varik_Base_480p.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=5504000,RESOLUTION=720x720,NAME="720" CollectionAsset_Hero_Varik_Base_720p.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=8576000,RESOLUTION=1080x1080,NAME="1080" CollectionAsset_Hero_Varik_Base_1080p.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=16768000,RESOLUTION=1440x1440,NAME="1440" CollectionAsset_Hero_Varik_Base_1440p.m3u8 #EXT-X-STREAM-INF:BANDWIDTH=36224000,RESOLUTION=2000x2000,NAME="2000" CollectionAsset_Hero_Varik_Base_2000p.m3u8
Each variant playlist file then contains the path to the video itself. Here’s how the 720p variant playlist looks like:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-ALLOW-CACHE:YES
#EXT-X-TARGETDURATION:8
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:8.000000,
CollectionAsset_Hero_Varik_Base_720p_0000.ts
#EXT-X-ENDLIST
You can learn more about the tags (#
) in Apple's documentation or check out the tutorial in the next section.
Basic HLS tutorial
In this tutorial, we will create video NFTs in the Immutable marketplace using HLS.
Requirements
To stream your videos using HLS, you’ll need:
A storage solution that supports video streaming
A video transcoder to ready your videos for streaming
A tool to measure the peak bitrate of your videos
For this tutorial, we used a dedicated Pinata gateway for storage (requires a paid subscription) and ffmpeg for transcoding the videos and measuring the bitrate.
Note: We chose those tools as they were easily accessible. We recommend you select your own tools based on your project needs in a production environment.
Step-by-step tutorial
1. Create the variant videos and multivariant playlists
Use a video transcoder to convert your video to a transport stream (*.ts
files) and create variants with different resolutions. Create a multivariant playlist for each variant.
You can do both using ffmpeg. Replace the filenames and run the following in the terminal:
# Transcode for 720p
ffmpeg -i cat.Mov -c:v libx264 -crf 23 -preset ultrafast -c:a copy -hls_time 10 -hls_list_size 0 -s 1280x720 -hls_segment_filename "cat_720p_%03d.ts" cat_720p.m3u8
# Transcode for 480p
ffmpeg -i cat.Mov -c:v libx264 -crf 23 -preset ultrafast -c:a copy -hls_time 10 -hls_list_size 0 -s 854x480 -hls_segment_filename "cat_480p_%03d.ts" cat_480p.m3u8
# Transcode for 360p
ffmpeg -i cat.Mov -c:v libx264 -crf 23 -preset ultrafast -c:a copy -hls_time 10 -hls_list_size 0 -s 640x360 -hls_segment_filename "cat_360p_%03d.ts" cat_360p.m3u8
2. Get the peak/max bitrate for each variant
Using ffmpeg, get the bitrate (kb/s) for each variant. You will need to specify the bitrate in the master playlist. This information helps the client player select the best variant to play according to the user's network and device capabilities.
ffmpeg -i cat_720p_000.ts -c copy -f null /dev/null 2>&1 | grep 'bitrate:'
ffmpeg -i cat_480p_000.ts -c copy -f null /dev/null 2>&1 | grep 'bitrate:'
ffmpeg -i cat_360p_000.ts -c copy -f null /dev/null 2>&1 | grep 'bitrate:'
3. Create a master playlist
Create a master playlist (*.m3u8
file). This is typically done manually. Here's an example:
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-STREAM-INF:BANDWIDTH=1250973,RESOLUTION=480x480,NAME="480"
cat_480p_000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=1671711,RESOLUTION=720x720,NAME="720"
cat_720p_000.m3u8
#EXT-X-STREAM-INF:BANDWIDTH=2300429,RESOLUTION=1080x1080,NAME="1080"
cat_1080p_000.m3u8
#EXTM3U
- is the file header.
#EXT-X-VERSION
- specifies the compatibility version of the playlist file.
#EXT-X-STREAM-INF
- indicates that the next URL in the playlist file identifies another playlist file. Every #EXT-X-STREAM-INF
tag must include the bandwidth
attribute, which is an integer that is the bitrate (obtained in step 2) for each media file, in bits per second (kb/s * 1000).
Video players will usually start playing from the first variant (480p in this example), so the first variant you specify in the list matters. The order of other variants don’t matter.
4. Upload your master + variant playlists and video files
Upload your *.m3u8
files and video files to Pinata or another storage service. All the files should be in the same folder. See example.
5. Create NFT metadata and mint your NFTs
Refer to the NFT minting tutorial if you’re not familiar with this step.
When creating metadata, make sure you set the animation_url
to the location of your master playlist and animation_url_mime_type
to application/vnd.apple.mpegurl
. Example:
{
"name": "1st NFT",
"description": "This is your 1st nft",
"animation_url": "https://bronze-magnetic-dove-193.mypinata.cloud/ipfs/QmTxigpmoRyQ2JmJGcDm5uSBGZ5zTH8WKa3R3ueTkPprF4/cat.m3u8",
"animation_url_mime_type": "application/vnd.apple.mpegurl",
"attack": 123,
"collectable": true,
"power": "adorable"
}
6. Check your NFT in the marketplace
In the marketplace, you should see the video of your NFT auto play
In the browser, you can confirm which variant of the video is playing by viewing the network tab in console:
As mentioned in step 3, the first variant in the master playlist will be played first. In the above example, the default 480p variant played first before switching to the 1080p variant based on network conditions.