How-to Transcode to HLS Streaming Format

Before you start

This guide assumes that you understand the basics of making a Transcode API request. We recommend completing the Getting Started with Transcoding Media guide first.

And you need your own cloud storage. Refer to How to Transcode with Your Own Cloud Storage. Note it is not possible to create Streaming outputs with Dolby Temporary Storage or Presigned URLs—you must connect your own storage provider.

If you use our examples, be sure to update your storage and input sections to point to your files along with your API Token. You will also need to install the appropriate http client for your language. (Requests for Python, Axios for JavaScript)

Creating HTTP Live Streaming (HLS) Adaptive Bitrate outputs

HLS is a delivery mechanism for streaming audio and video content over the internet developed by Apple. It is a flexible and widely supported format that supports the HTML5 video tag, as well as a host of other web players and physical devices.

One of the main benefits to HLS is that it utilizes Adaptive Bitrate streaming (ABR). With ABR, you can encode your video into a "ladder" of resolutions and bitrates commonly referred to as "renditions", "rungs", or "layers". The player dynamically selects the optimal bitrate to be delivered to the end viewer based on the viewer's current network conditions. If the viewer's available bandwidth drops, the player seamlessly switches to a lower-bitrate video layer to prevent stalling and buffering.

If you are new to HLS, Dolby.io's Transcode API can help you create HLS outputs by inspecting your input file and generating the audio and video layers. If you know what your ladder should look like, you can explicitly define all of your audio and video "layers."

Creating HLS with Dolby.io

After you start a transcode request, you use the returned job_id to make job status requests. After a Successful job status is returned, you can review the transcoded media in the cloud storage that you provided.

To learn more about customizing the behavior of transcoding, explore the Transcode API reference. Here are some examples to get started.

Example HLS output where Dolby.io creates the ABR ladder

If you aren't sure what your ladder settings should be for your streaming output, this example demonstrates the easiest way to get started creating HLS with the transcode API. We simply take our source video and let the API determine what the "renditions" of the ABR ladder should be with regard to resolution and bitrate based on the input file.

import os

# The requests library must be installed before running this example.
import requests

# Add your API token as an environmental variable or hard coded value.
api_token = os.getenv("DOLBYIO_API_TOKEN", "your_token_here")

# Call the Transcode API endpoint.
url = "https://api.dolby.com/media/transcode"

# Set your API token in your request header.
headers = {
    "Authorization": "Bearer {0}".format(api_token),
    "Content-Type": "application/json",
    "Accept": "application/json"
}

# Before you run this example, update the paths and filenames to point to your media.
body = {
    "inputs": [
        {
            "source": {
                "ref": "s3_input",
                "filename": "media_file1.mp4"
            }
        }
    ],
    "outputs": [
        {
            "destination": {
                "ref": "s3_output",
                "filename": "master_manifest.m3u8"
            },
            "kind": "hls"
        }
    ],
    "storage": [
        {
            "id": "s3_input",
            "bucket": {
                "url": "s3://my-storage-bucket/input/",
                "auth": {
                    "key": "AKIASZXXXXXXXXYLWWUHQ",
                    "secret": "kjYK54XXXXXXXXXZtKFySioE+3"
                }
            }
        },
        {
            "id": "s3_output",
            "bucket": {
                "url": "s3://my-s3-storage-bucket/output/",
                "auth": {
                    "key": "AKIASZXXXXXXXXYLWWUHQ",
                    "secret": "kjYK54XXXXXXXXXZtKFySioE+3"
                }
            }
        }
    ]
}

try:
    # Submit the request to the API.
    response = requests.post(url, json=body, headers=headers)

    # Raise an error if an HTTPError occurred.
    response.raise_for_status()

# Exception handling.
except requests.exceptions.HTTPError as e:
    raise Exception(response.text)

# Request was successful.
print(response.json()["job_id"])
// The Axios library must be installed before running this example.
const axios = require("axios").default

// Add your API token as an environmental variable or hard coded value.  
const api_token = process.env.DOLBYIO_API_TOKEN || "your_token_here"  

// Before you run this example, update the paths and filenames to point to your media.
const config = {
    "method": "post",
    "url": "https://api.dolby.com/media/transcode",
    "headers": {
        "Authorization": `Bearer ${api_token}`,
        "Content-Type": "application/json",
        "Accept": "application/json"
    },
    "data": {
        "inputs": [
            {
                "source": {
                    "ref": "s3_input",
                    "filename": "media_file1.mp4"
                }
            }
        ],
        "outputs": [
            {
                "destination": {
                    "ref": "s3_output",
                    "filename": "master_manifest.m3u8"
                },
                "kind": "hls"
            }
        ],
        "storage": [
            {
                "id": "s3_input",
                "bucket": {
                    "url": "s3://my-storage-bucket/input/",
                    "auth": {
                        "key": "AKIASZXXXXXXXXYLWWUHQ",
                        "secret": "kjYK54XXXXXXXXXZtKFySioE+3"
                    }
                }
            },
            {
                "id": "s3_output",
                "bucket": {
                    "url": "s3://my-s3-storage-bucket/output/",
                    "auth": {
                        "key": "AKIASZXXXXXXXXYLWWUHQ",
                        "secret": "kjYK54XXXXXXXXXZtKFySioE+3"
                    }
                }
            }
        ]
    }
}

// Submit the request.
axios(config)
    .then(function(response) {
        // Log the successful "job_id" returned from the API.
        console.log(response.data.job_id)
    })
    .catch(function(error) {
        // If there was an error, log the error.
        console.log(error)
    })
#!/bin/bash

# Add your API token as an environmental variable or hard coded value.
API_TOKEN=${DOLBYIO_API_TOKEN:-"your_token_here"}

# Before you run this example, update the paths and filenames to point to your media.
curl -X POST "https://api.dolby.com/media/transcode" \
    --header "Authorization: Bearer $API_TOKEN" \
    --header 'Content-Type: application/json' \
    --header 'Accept: application/json' \
    --data '{
    "inputs": [
        {
            "source": {
                "ref": "s3_input",
                "filename": "media_file1.mp4"
            }
        }
    ],
    "outputs": [
        {
            "destination": {
                "ref": "s3_output",
                "filename": "master_manifest.m3u8"
            },
            "kind": "hls"
        }
    ],
    "storage": [
        {
            "id": "s3_input",
            "bucket": {
                "url": "s3://my-storage-bucket/input/",
                "auth": {
                    "key": "AKIASZXXXXXXXXYLWWUHQ",
                    "secret": "kjYK54XXXXXXXXXZtKFySioE+3"
                }
            }
        },
        {
            "id": "s3_output",
            "bucket": {
                "url": "s3://my-s3-storage-bucket/output/",
                "auth": {
                    "key": "AKIASZXXXXXXXXYLWWUHQ",
                    "secret": "kjYK54XXXXXXXXXZtKFySioE+3"
                }
            }
        }
    ]
}'

If you would like a little more control over how your ladder is generated without specifying each layer, you can set the num_audio_layers and num_video_layers on the HLS or DASH output. The API will try to optimize the layer distribution based on the media info of your input.

{
    "destination" : {
        "ref" : "s3_output",
        "filename" :  "master_manifest.m3u8"
    },
    "kind" : "hls",
    "segment_duration_sec" : 6,
    "num_video_layers": 5,
    "num_audio_layers" 1
}

Example HLS output with an explicitly defined ABR ladder

If you know how you want your video and audio renditions defined, we demonstrate how to call the API explicitly in this example. In addition to the kind: hls output, we define each audio and video layer.

You will notice that we define the height of each layer only, letting the API calculate what the width should be when scaling the source. We also do not define a frame_rate. The API uses the frame_rate from the input file. These are both recommended best practices.

The use of max_bitrate_kb is not explicitly required in this case. It tells the encoder to be a bit more constrained with its data rate which is desired for Adaptive Bitrate Streaming.

Lastly, to output audio-only and video-only layers, we also specify the removal of the video from the audio-only outputs and audio from the video-only outputs. You can read more about that in our How to Transcode an Audio-Only or Video-Only Output.

Here's a full example:

import os

# note that this example uses the requests library, it must be installed before running this example
import requests

# Add your API token as an environmental variable or hard coded value.
api_token = os.getenv("DOLBYIO_API_TOKEN", "your_token_here")

# Call the Transcode API endpoint
url = "https://api.dolby.com/media/transcode"


headers = {
    "Authorization": "Bearer {0}".format(api_token),
    "Content-Type": "application/json",
    "Accept": "application/json"
}

# if you want to run this example, don't forget to update your paths, and filenames to your own media
body = {
    "inputs": [
        {
            "source": {
                "ref": "s3_input",
                "filename": "media_file1.mp4"
            }
        }
    ],
    "outputs": [
        {
            "id": "vid_1080p",
            "destination": {
                "ref": "s3_output",
                "filename": "airplane_1080p.mp4"
            },
            "kind": "mp4",
            "audio": "remove",
            "video": {
                "codec": "h264",
                "height": 1080,
                "bitrate_mode": "vbr",
                "bitrate_kb": 6000,
                "max_bitrate_kb": 6600
            }
        },
        {
            "id": "vid_720p",
            "destination": {
                "ref": "s3_output",
                "filename": "airplane_720p.mp4"
            },
            "kind": "mp4",
            "audio": "remove",
            "video": {
                "codec": "h264",
                "height": 720,
                "bitrate_mode": "vbr",
                "bitrate_kb": 3000,
                "max_bitrate_kb": 3300
            }
        },
        {
            "id": "vid_480p",
            "destination": {
                "ref": "s3_output",
                "filename": "airplane_480p.mp4"
            },
            "kind": "mp4",
            "audio": "remove",
            "video": {
                "codec": "h264",
                "height": 360,
                "bitrate_mode": "vbr",
                "bitrate_kb": 400,
                "max_bitrate_kb": 440
            }
        },
        {
            "destination": {
                "ref": "s3_output",
                "filename": "airplane_audio.mp4"
            },
            "kind": "mp4",
            "video": "remove",
            "audio": [
                {
                    "codec": "aac_lc",
                    "bitrate_kb": 128
                }
            ]
        },
        {
            "id": "hls_out",
            "destination": {
                "ref": "s3_output",
                "filename": "master_manifest.m3u8"
            },
            "kind": "hls",
            "segment_duration_sec": 6
        }
    ],
    "storage": [
        {
            "id": "s3_input",
            "bucket": {
                "url": "s3://my-storage-bucket/input/",
                "auth": {
                    "key": "AKIASZXXXXXXXXYLWWUHQ",
                    "secret": "kjYK54XXXXXXXXXZtKFySioE+3"
                }
            }
        },
        {
            "id": "s3_output",
            "bucket": {
                "url": "s3://my-s3-storage-bucket/output/",
                "auth": {
                    "key": "AKIASZXXXXXXXXYLWWUHQ",
                    "secret": "kjYK54XXXXXXXXXZtKFySioE+3"
                }
            }
        }
    ]
}

try:
    # submit the request to the API
    response = requests.post(url, json=body, headers=headers)

    # raise an error if an HTTPError occurred
    response.raise_for_status()

# exception handling
except requests.exceptions.HTTPError as e:
    raise Exception(response.text)

# request was successful
print(response.json()["job_id"])
// note that this example uses the axios library, it must be installed before running this example
const axios = require("axios").default

// Add your API token as an environmental variable or hard coded value.  
const api_token = process.env.DOLBYIO_API_TOKEN || "your_token_here"  

// if you want to run this example, don't forget to update your paths, and filenames
const config = {
    "method": "post",
    "url": "https://api.dolby.com/media/transcode",
    "headers": {
        "Authorization": `Bearer ${api_token}`,
        "Content-Type": "application/json",
        "Accept": "application/json"
    },
    "data": {
        "inputs": [
            {
                "source": {
                    "ref": "s3_input",
                    "filename": "media_file1.mp4"
                }
            }
        ],
        "outputs": [
            {
                "id": "vid_1080p",
                "destination": {
                    "ref": "s3_output",
                    "filename": "airplane_1080p.mp4"
                },
                "kind": "mp4",
                "audio": "remove",
                "video": {
                    "codec": "h264",
                    "height": 1080,
                    "bitrate_mode": "vbr",
                    "bitrate_kb": 6000,
                    "max_bitrate_kb": 6600
                }
            },
            {
                "id": "vid_720p",
                "destination": {
                    "ref": "s3_output",
                    "filename": "airplane_720p.mp4"
                },
                "kind": "mp4",
                "audio": "remove",
                "video": {
                    "codec": "h264",
                    "height": 720,
                    "bitrate_mode": "vbr",
                    "bitrate_kb": 3000,
                    "max_bitrate_kb": 3300
                }
            },
            {
                "id": "vid_480p",
                "destination": {
                    "ref": "s3_output",
                    "filename": "airplane_480p.mp4"
                },
                "kind": "mp4",
                "audio": "remove",
                "video": {
                    "codec": "h264",
                    "height": 360,
                    "bitrate_mode": "vbr",
                    "bitrate_kb": 400,
                    "max_bitrate_kb": 440
                }
            },
            {
                "destination": {
                    "ref": "s3_output",
                    "filename": "airplane_audio.mp4"
                },
                "kind": "mp4",
                "video": "remove",
                "audio": [
                    {
                        "codec": "aac_lc",
                        "bitrate_kb": 128
                    }
                ]
            },
            {
                "id": "hls_out",
                "destination": {
                    "ref": "s3_output",
                    "filename": "master_manifest.m3u8"
                },
                "kind": "hls",
                "segment_duration_sec": 6
            }
        ],
        "storage": [
            {
                "id": "s3_input",
                "bucket": {
                    "url": "s3://my-storage-bucket/input/",
                    "auth": {
                        "key": "AKIASZXXXXXXXXYLWWUHQ",
                        "secret": "kjYK54XXXXXXXXXZtKFySioE+3"
                    }
                }
            },
            {
                "id": "s3_output",
                "bucket": {
                    "url": "s3://my-s3-storage-bucket/output/",
                    "auth": {
                        "key": "AKIASZXXXXXXXXYLWWUHQ",
                        "secret": "kjYK54XXXXXXXXXZtKFySioE+3"
                    }
                }
            }
        ]
    }
}

// submit the request
axios(config)
    .then(function(response) {
        // log the successful "job_id" returned on success from the API
        console.log(response.data.job_id)
    })
    .catch(function(error) {
        // if there was an error, log the error
        console.log(error)
    })
#!/bin/bash

# Add your API token as an environmental variable or hard coded value.
API_TOKEN=${DOLBYIO_API_TOKEN:-"your_token_here"}

# if you want to run this example, don't forget to update your paths, and filenames to your own media
curl -X POST "https://api.dolby.com/media/transcode" \
    --header "Authorization: Bearer $API_TOKEN" \
    --data '{
    "inputs": [
        {
            "source": {
                "ref": "s3_input",
                "filename": "media_file1.mp4"
            }
        }
    ],
    "outputs": [
        {
            "id": "vid_1080p",
            "destination": {
                "ref": "s3_output",
                "filename": "airplane_1080p.mp4"
            },
            "kind": "mp4",
            "audio": "remove",
            "video": {
                "codec": "h264",
                "height": 1080,
                "bitrate_mode": "vbr",
                "bitrate_kb": 6000,
                "max_bitrate_kb": 6600
            }
        },
        {
            "id": "vid_720p",
            "destination": {
                "ref": "s3_output",
                "filename": "airplane_720p.mp4"
            },
            "kind": "mp4",
            "audio": "remove",
            "video": {
                "codec": "h264",
                "height": 720,
                "bitrate_mode": "vbr",
                "bitrate_kb": 3000,
                "max_bitrate_kb": 3300
            }
        },
        {
            "id": "vid_480p",
            "destination": {
                "ref": "s3_output",
                "filename": "airplane_480p.mp4"
            },
            "kind": "mp4",
            "audio": "remove",
            "video": {
                "codec": "h264",
                "height": 360,
                "bitrate_mode": "vbr",
                "bitrate_kb": 400,
                "max_bitrate_kb": 440
            }
        },
        {
            "destination": {
                "ref": "s3_output",
                "filename": "airplane_audio.mp4"
            },
            "kind": "mp4",
            "video": "remove",
            "audio": [
                {
                    "codec": "aac_lc",
                    "bitrate_kb": 128
                }
            ]
        },
        {
            "id": "hls_out",
            "destination": {
                "ref": "s3_output",
                "filename": "master_manifest.m3u8"
            },
            "kind": "hls",
            "segment_duration_sec": 6
        }
    ],
    "storage": [
        {
            "id": "s3_input",
            "bucket": {
                "url": "s3://my-storage-bucket/input/",
                "auth": {
                    "key": "AKIASZXXXXXXXXYLWWUHQ",
                    "secret": "kjYK54XXXXXXXXXZtKFySioE+3"
                }
            }
        },
        {
            "id": "s3_output",
            "bucket": {
                "url": "s3://my-s3-storage-bucket/output/",
                "auth": {
                    "key": "AKIASZXXXXXXXXYLWWUHQ",
                    "secret": "kjYK54XXXXXXXXXZtKFySioE+3"
               }
            }
        }
    ]
}'

For more detailed parameter information, take a look at the streaming output types for HLS and DASH in the Transcode API reference.