Tutorial: HTML5 and Flash Video Streaming with CloudFront

17 December, 2012

Amazon Web ServicesCloudFront is a great way to distribute streaming media, both with RTMP and pseudo streaming.

This tutorial aims to help you create a signed CloudFront URL for both RTMP and progressive streaming. We use both technologies so that users with Flash player installed can use RTMP streaming whilst HTML5 players can use the pseudo-streaming. We then use JW Player 6 to play the video.

If you just want to create a private URL for a downloadable file, follow the steps to create a pseudo-streaming file, it’s the same.

What is pseudo-streaming?

Pseudo-streaming allows you to seek/skip in a video without having to load the entire video. It works by passing the HTTP server the byte-range so only the video from the seek point is downloaded.

What is RTMP?

RTMP is a streaming protocol used by Flash player. It is seen as a more secure way to stream video as it is harder to intercept and copy.

The reason we want to use RTMP for flash is that Flash cannot pseudo-stream without server side modules being installed, making RTMP a much better user experience.

Step One

Make sure you have setup two CloudFront distributions, one for streaming and one for Download. The streaming distribution will provide the RTMP stream whilst the download distribution will provide the pseudo-streaming.

Set both distributions to private and select the same S3 bucket origin. Allow CloudFront to automatically grant itself permissions to the S3 bucket.

Upload your MP4 file to any directory in your S3 bucket, the bucket policy should automatically allow CloudFront access to the file, so you shouldn’t need to change any permissions. CloudFront’s policy gives it access to the owner of the buckets files only, so make sure you upload as the owner of the S3 bucket.

Step Two

The following function will generate a signed URL. You will need to pass it the URL and expiry time.

function getsignedurl($resource, $expires) {
	// key pair generated for cloudfront
	$keyPairId = 'Your Key pair id';
	$json = '{"Statement":[{"Resource":"' . $resource . '","Condition":{"DateLessThan":{"AWS:EpochTime":' . $expires . '}}}]}';
 	// read cloudfront private key pair
	$fp = fopen(/home/yoursite/folder/amazon.pem', 'r');
	$priv_key = fread($fp, 8192);
	// create the private key
	$key = openssl_get_privatekey($priv_key);
	// sign the policy with the private key, this may not work properly on windows.
	// depending on your php version you might have to use
	// openssl_sign($json, $signed_policy, $key, OPENSSL_ALGO_SHA1)
	openssl_sign($json, $signed_policy, $key);
	// create url safe signed policy
	$base64_signed_policy = base64_encode($signed_policy);
	$signature = str_replace(array('+', '=', '/'), array('-', '_', '~'), $base64_signed_policy);
	// construct the url
	$url = $resource . '?Expires=' . $expires . '&Signature=' . $signature . '&Key-Pair-Id=' . $keyPairId;
	return $url;

A key point to remember at this stage is that CloudFront deals with signing the RTMP and pseudo-streaming URL completely differently.

To get the signed URL for your RTMP stream you will need to pass just the folder and filename of the file you wish to stream.

$expires = time() + 5 * 60; //Expire the link in 5 minutes
$RTMP_url = getsignedurl("folder/file.mp4", $expires);

To get the URL for the pseudo-stream, or any other normal file you will need to pass in the full URL.

$expires = time() + 5 * 60; //Expire the link in 5 minutes
$pseudo_url = getsignedurl("http://yoursubdomain.cloudfront.net/folder/file.mp4", $expires);

Step Three

Integrate with JW Player 6, include the JW Player required JavaScript files and then use the following code to load the player.

<div id=”example_video”></div>
var RTMP_url = ‘<?php echo $RTMP_URL; ?>’; var pseudo_url = ‘<?php echo $pseudo_url; ?>’;
jwplayer('example_video').setup({ playlist: [{ image: "/img/video.png", sources: [ { file: "rtmp://yoursubdomain.cloudfront.net/cfx/st/mp4:" + RTMP_url, height: 569, width: 940 }, { file: pseudo_url, height: 569, width: 940 } ], title: "Play movie" }], width: "940", height: "569", primary: "flash" });

Because the RTMP stream does not contain the full URL you will need to prepend your CloudFront URL to it, using the RTMP protocol instead of HTTP. In the example the primary source is set to flash as it is the most widely supported and helps with IE9 HTML5 video problems. The MP4: before the file path tells JW Player to expect an MP4. If you use a browser with no flash support like an iPhone the JW HTML5 player will load and pseudo-stream your MP4.

1 Comment

16th October 2017 at 9:16am

Hi Ollie,

can you provide a full view of the code in an php and html file? I just didn't get it together and the player always says it could not connect to the server.


Post reply

Leave a comment

Replying to: - Cancel