Overview
With Zencoder you can encode your videos to MP4 and then also repackage those as HLS outputs, through a process we call "transmuxing" (rather than transcoding). Transmuxing will repackage existing MP4 videos into the MPEG TS segments necessary for HTTP Live Streaming (HLS), without having to re-encode the video files. Using dependent outputs you can create your H.264 files plus the segmented files all in a single job, producing faster turnaround at lower cost; transmuxed outputs are charged at 1/4 of the cost of encoding. The resulting job creates 6 outputs - 2 charged at your account's regular rate, 3 transmuxed files at 1/4 of the encoding cost, and 1 playlist, which is free.
For this, you'll create a single job with two main sets of outputs (plus the playlists). The first set of outputs will be normal H.264/AAC MP4 files with a few special settings to allow them to work as source files for HLS outputs. The second set of outputs will use those MP4 files as "source" inputs, transmuxing their content to HLS outputs. Since these are dependent outputs, they will wait until their corresponding source finishes before being scheduled to process.
The key part of the process is using source
, a new option in V2 of the Zencoder API. Source tells an output to use the file created by another output on the job for processing, instead of the input file. In this situation, Zencoder will create H.264 files based on the input file at requested bitrates. As each of those outputs finishes, a segmented version will then be created from the output.
Video resolutions
The table below shows some common video resolutions.
Resolution Type | Common Name | Aspect Ratio | Pixel Size |
---|---|---|---|
SD (Standard Definition) | 480p | 4:3 | 640 x 480 |
HD (High Definition) | 720p | 16:9 | 1280 x 720 |
Full HD (FHD) | 1080p | 16:9 | 1920 x 1080 |
QHD (Quad HD) | 1440p | 16:9 | 2560 x 1440 |
2K video | 1080p | 1:1.77 | 2048 x 1080 |
4K video or Ultra HD (UHD) | 4K or 2160p | 1:1.9 | 3840 x 2160 |
8K video or Full Ultra HD | 8K or 4320p | 16∶9 | 7680 x 4320 |
In considering video resolutions for your outputs, you should consider what devices your viewers will most likely be using. (If you have some kind of analytics, that will helpful in determiniing this.) If mobile devices are a target, you may want to consider that "vertical" video is increasingly popular. To produce vertical video, you would typically swap the width and height values.
The H.264 Outputs
We'll start by creating 2 H.264 files, targeting high and low bitrates.
{
"label": "low",
"format": "mp4",
"video_bitrate": 200,
"decoder_bitrate_cap": 300,
"decoder_buffer_size": 1200,
"audio_sample_rate": 44100,
"height": "288",
"url": "s3://example-bucket/low.mp4",
"h264_reference_frames": 1,
"forced_keyframe_rate": "0.1",
"audio_bitrate": 56,
"decimate": 2
},
{
"label": "high",
"format": "mp4",
"video_bitrate": 1000,
"decoder_bitrate_cap": 1500,
"decoder_buffer_size": 6000,
"audio_sample_rate": 44100,
"height": "432",
"url": "s3://example-bucket/high.mp4",
"h264_reference_frames": "auto",
"h264_profile": "main",
"forced_keyframe_rate": "0.1",
"audio_bitrate": 56
}
The resulting files from these outputs are capable of being played on a wide variety of devices. Each targets a different bitrate and resolution, so users can be sent the appropriate file. Each is also appropriate for segmenting for HTTP Live Streaming and serving as an adaptive bitrate stream.
A few options in the request above to note:
forced_keyframe_rate
to 0.1. This forces the video to have a keyframe every 10 seconds. The segmented files will be 10 seconds long, so this ensures will ensure that there each segment will start with a keyframe.decoder_bitrate_cap
is set to 1.5x the target bitrate of the file.decoder_buffer_size
is set to 3.5x to 5x the target bitrate of the file. These settings will help keep a consistent bitrate throughout the file, so that the segmented segments won't vary too much in size and bitrate.
Now that the H.264 files have been created, additional outputs can be added to the request to create HTTP Live Streaming segmented files from the source, without needing to do additional encoding.
Segmented Outputs
Each of the H.264 video and the audio outputs above have labels
in their API options. These labels can be used in conjunction with the source
option to tell Zencoder to use the video created by the output with the given label, rather than the input file. Since the H.264 files are already at good settings for HLS, no additional encoding is necessary.
{
"source": "low",
"format": "ts",
"copy_audio": "true",
"copy_video": "true",
"url": "s3://example-bucket/hls-low/hls-low.m3u8",
"label": "hls-low",
"type": "segmented"
}
{
"source": "high",
"format": "ts",
"copy_audio": "true",
"copy_video": "true",
"url": "s3://example-bucket/hls-high/hls-high.m3u8",
"label": "hls-high",
"type": "segmented"
}
{
"streams": [
{
"path": "hls-low/hls-low.m3u8",
"bandwidth": 256
},
{
"path": "hls-high/hls-high.m3u8",
"bandwidth": 1056
}
],
"type": "playlist",
"url": "s3://example-bucket/playlist.m3u8"
}
The resulting files from these outputs are segmented outputs, targeting different bandwidths, plus a playlist file for the playback device to know the available streams.
Each segmented output includes the source
, and specifies one of the outputs listed earlier. They also include the copy_audio
and copy_video
options, which tell Zencoder to use the audio and video streams from the source file and repackage them in the new container, rather than transcode them. Finally, the outputs also specify a type
of segmented and a format
of ts, plus a url
with an extension of .m3u8, so that Zencoder knows to create segmented HLS files.
Finally, there is also a playlist generated that references each of the segmented outputs. Note that the first file referenced in the playlist is the low bitrate video; the device playing the video will generally load the first stream listed in the playlist initially, and switch to other streams as necessary. This means that the first 10 seconds of playback will use this stream, after which the device will have enough information to select the appropriate stream to play.
NOTES
- The HLS playlist generation currently uses no information from the other outputs in the job, but is simply a way to easily generate a correctly formatted adaptive-bitrate playlist and have it uploaded along with the other files.
- While iOS devices will play the adaptive bitrate playlist created, VLC won't, due to errors in handling relative URLs. It will look for the segment files in the same directory as the playlist file, rather than the directory of the manifest file.
Full Request
Now that we've gone over each of the major output sections, let's pull it together in to a single API request.
{
"input": "s3://zencodertesting/test.mov",
"outputs": [
{
"label": "low",
"format": "mp4",
"video_bitrate": 200,
"decoder_bitrate_cap": 300,
"decoder_buffer_size": 1200,
"audio_sample_rate": 44100,
"height": "288",
"url": "s3://example-bucket/low.mp4",
"h264_reference_frames": 1,
"forced_keyframe_rate": "0.1",
"audio_bitrate": 56,
"decimate": 2
},
{
"label": "high",
"format": "mp4",
"video_bitrate": 1000,
"decoder_bitrate_cap": 1500,
"decoder_buffer_size": 6000,
"audio_sample_rate": 44100,
"height": "432",
"url": "s3://example-bucket/high.mp4",
"h264_reference_frames": "auto",
"h264_profile": "main",
"forced_keyframe_rate": "0.1",
"audio_bitrate": 56
},
{
"source": "low",
"format": "ts",
"copy_audio": "true",
"copy_video": "true",
"url": "s3://example-bucket/hls-low/hls-low.m3u8",
"label": "hls-low",
"type": "segmented"
}
{
"source": "high",
"format": "ts",
"copy_audio": "true",
"copy_video": "true",
"url": "s3://example-bucket/hls-high/hls-high.m3u8",
"label": "hls-high",
"type": "segmented"
}
{
"streams": [
{
"path": "hls-low/hls-low.m3u8",
"bandwidth": 256
},
{
"path": "hls-high/hls-high.m3u8",
"bandwidth": 1056
}
],
"type": "playlist",
"url": "s3://example-bucket/playlist.m3u8"
}
]
}