latest stable versions: v150827 (changelog)

Old Forums (READ-ONLY): The community now lives at WP Sharks™. If you have an s2Member® Pro question, please use our new Support System.

CloudFront and RTMP Streaming JW

Home Forums Community Forum CloudFront and RTMP Streaming JW

This topic contains 35 replies, has 5 voices. Last updated by  ryan 4 years, 10 months ago.

Page 2 Of Topic Replies

Viewing 10 replies - 26 through 35 (of 35 total)
Author Replies
Author Replies
Posted: Wednesday Feb 29th, 2012 at 11:54 pm #6860
ryan
Username: ryanm

OK, here is a working function. I feel pretty embarrassed about my first “draft” now.

add_shortcode('fdnVideo_embed', function ($atts){
	$atts = shortcode_atts(
		array(
			'src' 	=>	'',
			'width' =>	'600',
			'height'=>	'338',
			'title' =>	''
	), $atts);
	
	$cfg = array (
		'file_download' => $atts['src'], 
		'url_to_storage_source' => true,
		'count_against_user' => true
	); 

	if (($mp4 = s2member_file_download_url ($cfg, "get-streamer-array"))) { 
		$output = '
				<div id="jw-container">JW Player® appears here.</div>
				<script type="text/javascript" src="/jwplayer/jwplayer.js"></script>
				<script type="text/javascript">
        			jwplayer("jw-container").setup({modes: /* JW Player¨. */
        				[
		            		/* First try real-time streaming with Flash¨ player. */
				            {type: "flash", provider: "rtmp", src: "/jwplayer/player.swf",
								config: {streamer: "' . $mp4["streamer"]. '", file: "'. $mp4["file"] .'"}},
        
				            /* Else, try an HTML5 video tag. */
				            {type: "html5", provider: "video",
		        		        config: {file: "'.  $mp4["url"] .'"}},
		        
		            		/* Else, this is a safe fallback. */
				            {type: "download", /* Download the file. */
				                config: {file: "' . $mp4["url"] .'"}}
						],
        		
	        		/* Set video dimensions. */ 
	        		width: '. $atts['width'] .', height: '. $atts['height'] .'
	        		});
	   			</script>';   			
   		} else {   			
   			$output = 'Sorry, you do NOT have access to this file.';   		
   		}	
   		
	return $output;
	});

NOW my issue is that two on one page fails. :) The code appears correct, i.e. two different videos are referenced and two different URIs are generated.

Cheers,
Ryan

Posted: Thursday Mar 1st, 2012 at 4:34 am #6870
Staff Member

@luisrosario

Tried your example for file_download_key => true and getting a stream not found. I have a working example of the standard config of jw and html fallback, this new example having trouble with

Oh, very sorry. You’ll need to use this updated code sample. It should be "file_download_key" => true, with the quotes. Totally my mistake, very sorry. I’ve updated the code sample that I posted previously.

Here it is again, in it’s entirety. Don’t forget that you need a video.mp4 test file, for the sample to work. You will find further details on these configuration options in the s2Member Codex, here.

<div id="jw-container">JW Player® appears here.</div>
<script type="text/javascript" src="/jwplayer/jwplayer.js"></script>

<?php if(is_user_logged_in() && current_user_can("access_s2member_level1"))
	{
		/* A direct URL to the RTMP source; issuing a File Download Key to the current visitor in real-time. */
		$cfg = array ("file_download" => "video.mp4", "file_download_key" => true, "url_to_storage_source" => true);
		
		/* API Function `s2member_file_download_url()`.
			See docs here: http://www.s2member.com/codex/stable/s2member/api_functions/package-functions/#src_doc_s2member_file_download_url() */
		$mp4 = s2member_file_download_url ($cfg, "get-streamer-array");
		?>

		<script type="text/javascript">
			jwplayer("jw-container").setup({modes: /* JW Player®. */
			[
				/* Only allow real-time streaming with Flash® player. */
				{type: "flash", provider: "rtmp", src: "/jwplayer/player.swf",
				config: {streamer: "<?php echo $mp4&#91;"streamer"&#93;; ?>", file: "<?php echo $mp4&#91;"file"&#93;; ?>"}}
			],
			/* Set video dimensions. */ width: 480, height: 270
			});
		</script>

<?php } else /* Access is denied by site owner. */ { ?>
	Sorry, you do NOT have access to this file.
<?php } ?>

@Jason … Also, I had a question. Is there a way to force a s3 download link not cloudfront into the html fallback? So basically if a mobile device is loading html fallback, instead of the video coming form cloudfront, it’s delivered from s3 storage utilizing the default 30 second expiration to prevent link sharing. Is that possible? Creating a hybrid of s3 and cloudfront dynamically generating the urls for each case in the jwplayer…

Yes, you will need s2Member v120301 or higher, and you’ll need to specify the “file_storage” parameter in your configuration, as seen in the code sample below. This only works properly in s2Member v120301 or higher, because a minor bug related to the “file_storage” parameter was only just corrected in the latest release.

You will find further details on the “file_storage” parameter in the s2Member Codex, here.

<div id="jw-container">JW Player® appears here.</div>
<script type="text/javascript" src="/jwplayer/jwplayer.js"></script>

<?php
/* A direct URL to the CloudFront RTMP source; counting the file against the current User in real-time. */
$mp4_via_cf_cfg = array ("file_storage" => "cf", "file_download" => "video.mp4", "url_to_storage_source" => true, "count_against_user" => true);

/* A direct URL to the Amazon S3 source; NOT counting this variation against the current User. */
$mp4_via_s3_cfg = array ("file_storage" => "s3", "file_download" => "video.mp4", "url_to_storage_source" => true);

/* API Function `s2member_file_download_url()` returns false if access is denied to the current User. */
if (($mp4_via_cf = s2member_file_download_url ($mp4_via_cf_cfg, "get-streamer-array")) && ($mp4_via_s3["url"] = s2member_file_download_url ($mp4_via_s3_cfg))) {
?>

	<script type="text/javascript">
		jwplayer("jw-container").setup({modes: /* JW Player®. */
		[
			/* First try real-time streaming with Flash® player. */
			{type: "flash", provider: "rtmp", src: "/jwplayer/player.swf",
				config: {streamer: "<?php echo $mp4_via_cf&#91;"streamer"&#93;; ?>", file: "<?php echo $mp4_via_cf&#91;"file"&#93;; ?>"}},
				
			/* Else, try an HTML5 video tag with the `mp4` file. */
			{type: "html5", provider: "video",
			config: {file: "<?php echo $mp4_via_s3&#91;"url"&#93;; ?>"}},
			
			/* Else, this is a safe fallback. */
			{type: "download", /* Download the file. */
				config: {file: "<?php echo $mp4_via_s3&#91;"url"&#93;; ?>"}}
		],
		/* Set video dimensions. */ width: 480, height: 270
		});
	</script>

<?php } else /* Access is denied to the current User. */ { ?>
	Sorry, you do NOT have access to this file.
<?php } ?>

Here is the same thing, only this example uses File Download Keys instead of Basic Download Restrictions.

<div id="jw-container">JW Player® appears here.</div>
<script type="text/javascript" src="/jwplayer/jwplayer.js"></script>

<?php
if(is_user_logged_in() && current_user_can("access_s2member_level1"))
{
	/* A direct URL to the CloudFront RTMP source. */
	$mp4_via_cf_cfg = array ("file_storage" => "cf", "file_download" => "video.mp4", "file_download_key" => true, "url_to_storage_source" => true);
	
	/* A direct URL to the Amazon S3 source. */
	$mp4_via_s3_cfg = array ("file_storage" => "s3", "file_download" => "video.mp4", "file_download_key" => true, "url_to_storage_source" => true);
	
	/* Here we use API Function `s2member_file_download_url()` to generate the URLs we need below. */
	$mp4_via_cf = s2member_file_download_url ($mp4_via_cf_cfg, "get-streamer-array");
	$mp4_via_s3["url"] = s2member_file_download_url ($mp4_via_s3_cfg);
?>

	<script type="text/javascript">
		jwplayer("jw-container").setup({modes: /* JW Player®. */
		[
			/* First try real-time streaming with Flash® player. */
			{type: "flash", provider: "rtmp", src: "/jwplayer/player.swf",
				config: {streamer: "<?php echo $mp4_via_cf&#91;"streamer"&#93;; ?>", file: "<?php echo $mp4_via_cf&#91;"file"&#93;; ?>"}},
				
			/* Else, try an HTML5 video tag with the `mp4` file. */
			{type: "html5", provider: "video",
			config: {file: "<?php echo $mp4_via_s3&#91;"url"&#93;; ?>"}},
			
			/* Else, this is a safe fallback. */
			{type: "download", /* Download the file. */
				config: {file: "<?php echo $mp4_via_s3&#91;"url"&#93;; ?>"}}
		],
		/* Set video dimensions. */ width: 480, height: 270
		});
	</script>

<?php } else /* Access is denied to the current User. */ { ?>
	Sorry, you do NOT have access to this file.
<?php } ?>
Posted: Thursday Mar 1st, 2012 at 1:00 pm #6906

Hey Jason, to verify the above config with cloudfront and s3 url, will the s3 url use the default 30s url expiration? If so, would you agree the above example with Cloud Front RTMP Streaming and S3 Html Fallback is definitely a more secure method for using both delivery methods.. Although, one may still be able to download the s3 file within the default 30 second window.. But I feel this at least is step in the right direction towards a solution for both cases. If there’s anything I could suggest, if there was a way to completely hide the s3 url for the html fallback portion with an encryption of sorts, I think this combo would be a very strong solution for secure media delivery using s2member. We are a big supporter of your software and use it heavily on our site and now with the video functionality, we will be upgrading our video delivery and moving to s2 for this functionality. We have been using s3flowshield, but the power of s2member with the video integration is definitely more powerful.

One more thought, is there a way to isolate the cloudfront download distribution url and replace the s3 url in the config and have a different url expiration time than the streaming distribution? Best,

-Luis

  • This reply was modified 4 years, 10 months ago by  luisrosario.
Posted: Friday Mar 2nd, 2012 at 12:04 am #6950
Staff Member

@luisrosario

will the s3 url use the default 30s url expiration?

Yes, that is correct.

If so, would you agree the above example with Cloud Front RTMP Streaming and S3 Html Fallback is definitely a more secure method for using both delivery methods.

More secure, yes. However, if a direct download of the MP4 file is made possible, even if it’s limited to just 30 seconds, that’s still enough time for a Member to connect to your S3 Bucket, download the full MP4 file, and potentially share it with others. Not likely at all, but I’m just being careful how I answer this.

A stream over the RTMP protocol cannot be downloaded, so this is the most secure way to serve protected audio/video. If you make the full MP4 available in any way, you’re always at risk of that MP4 file being shared or redistributed by another. You can post warnings and legal notices all day long, but if the MP4 file is downloaded by anyone in full length, you’ll be making it possible, unfortunately.

If there’s anything I could suggest, if there was a way to completely hide the s3 url for the html fallback portion with an encryption of sorts

Interesting. I’m not sure how this would be accomplished though. If a direct download is made available, at some point the URL must be sent to the browser, and that will expose it. I’m all ears though. If you have something in mind, I’d love to hear your thoughts on this. Thank you!

One more thought, is there a way to isolate the cloudfront download distribution url and replace the s3 url in the config and have a different url expiration time than the streaming distribution?

Sorry, perhaps I’m not understanding this question. I think what you’re asking though, is solved by the code sample I posted previously. Generating both a CloudFront and an Amazon S3 URL, allows you to offer both versions in any way that you choose. Generating the URLs does not expose them, you will only expose them if you decide to do so in your code. So modifications of what I posted above might be desired in certain cases.

By default, CloudFront URLs are good for up to 24 hours, then they expire automatically. This also goes for the URLs returned in the streamer array, as seen in the code sample above. So again, any access by granted by s2Member to any file served via CloudFront, will be good for up to 24 hours.

The Amazon S3 URLs are defaulted to 30 seconds, then they expire automatically. Amazon S3 URLs are direct links to download the full file, they’re not streamers. Thus, Amazon S3 URLs can be limited to just a few seconds, because that’s all that’s required in most cases. Just enough time for a Member to connect to the file and begin downloading it. Once the download begins, the expiration time is irrelevant (i.e. they can take as much time as they need to finish downloading the file, as long as the connection was established in the first 30 seconds).

Posted: Friday Mar 2nd, 2012 at 1:07 am #6980

Thanks Jason for the reply. There are a couple points I’d like to address..

1- YES your example above generating Cloudfront and S3 URLS does take it one step further. But as your said, there are still limitations.

2- With that said, I realized after you provided the example, that if there was a way to use the Cloudfront Download Distribution, not Streaming, instead of s3 URL, and assign it a shorter length expiring url i.e. 30 seconds … that would be more favorable in terms of user experience on mobile devices. Since the file would be delivered via Cloudfront, it would be a quicker download, minimizing playback issues in the html fallback. So I thought maybe we could adopt the same logic with the s3 url generation and expiration time and apply it to Cloudfront Download URL. I’ve been doing tests with the example you provided and have seen some difference in the way the video downloads versus using Cloudfront Download … In any case, Maybe this is not possible to split the Cloudfront Distributions URL expiration times ?? …

3- In regards to encrypting the html fallback url .. I can only give you an example of this as we currently use S3flowshield for protecting files from S3 storage.. We have s2member on top as added security. Our main issue with flowshield is it doesn’t use cloudfront. If you visit

http://www.groovetemple.tv/processed-foods/

You’ll see a video here served from s3 using flowshields url generation to file ect.. If you look at page source, you’ll see where the player is located and all the data is blocked out. Copying this would yield nothing and there are displaying the player and video file somehow.. And added measure as well, is they give the option in the dashboard to set the expiration time. For a while flowshield did not have html fallback and it also exposed the url, but site admin had the option of setting the expiration times of the url as I said previously.

4- So moral of the story, ideally, as a site owner, I would love to be able to use the Cloudfront Download URL to deliver videos to devices using html fallback, but either hide the URL or Garble it up to make copying a link useless or allow a shorter url expiration time … Although RTMP is very secure, mobile is very important to video streaming and making it secure is just as important..

5- I would imagine with extending s2 in this way would really, IMO, make even more complete than it already is.

Posted: Friday Mar 2nd, 2012 at 3:06 am #7016

Luis, could you explain some more what you’re suggesting to copy from FlowShield to make the s2Member URLs more secure? I went to the page and got the URL to the video file (don’t worry, I x’ed out the bucket), FlowShield didn’t really hide it if you know where to look.

http://content.xxxxxxxxxxxxx.s3.amazonaws.com/1min/2011/nutritious/food/processed_foods.mp4?AWSAccessKeyId=AKIAJ5M5TJKEPWTFWZJQ&Expires=1330675211&Signature=FBrBsDmjhRYnYYq%2BCDrUoU%2FwYso%3D

Also, I’d like to point out that RTMP is harder to get, but not impossible. There are several stream downloaders out there. And, no matter what protection one applies, the file ist still being downloaded by the browser, so after the browser finishes getting it you have a full copy of it in the cache, which you can find with cache viewers.

It’s not bad to protect the files as much as possible, but I just want to keep it real that it’s really very hard to completely prevent their download and to keep a copy of the file. So more protection will reduce the number of people that’ll be able to get it, and that should be good enough, in my opinion.

That said, I did find once a site that got it quite right and was a true pain to backup a video I had paid for. I’m just guessing how they did it, but seems to be close: they were serving segments of the file at a time, each with their own expiration, etc. This made it very hard cause then you had to get each segment. The playback was smooth, though, not sure if they used a playlist in the player, or what player it was, seemed custom. Not impossible to get, I guess, but was a real pain so it was a deterrent. Food for thought…

Posted: Friday Mar 2nd, 2012 at 1:20 pm #7089

Hey Cristian, I agree with you on all that you are saying. I’m curious as to where you found the url… In this case obviously you know where to look.. I’m not sure the average person could find out where to look for the url, but I guess my argument is lets not make so obvious, because as it stands, viewing page source one can easily locate the s2 output of the html url and download. So either make that harder to find, or allow a shorter expiration for the cloudfront download url without affecting the streaming url expiration so users will be able to still seek video ect if viewing via flash and if viewing via html, the cloudfront download link expires similarly to the s3 url link. Based on my testing, using forced s3 url with streaming cloudfront as provided by Jason in a previous example is not as good as using the cloudfront for dowload and streaming all together. So if I could deliver html video via cloudfront download url with shorther expiration, that would be a step in the right direction IMO..

Posted: Friday Mar 2nd, 2012 at 4:32 pm #7100

Great. Awesome feedback. Thanks! :)

I know Jason is looking into this and improving it, so there’s a good chance that this will get better with coming releases.

Posted: Friday Mar 2nd, 2012 at 4:35 pm #7101

Quick tip: Another good deterrent I’ve found is naming your files and dirs with random cryptic names, if possible, a mix of characters. It makes it hard for you to track which file is which, but once you have it set up, you hardly have to touch them again. Now, for the person trying to download all your videos, it also is a pain having to rename everything and it’ll make many not bother with it, especially when there are several files.

Posted: Sunday Mar 4th, 2012 at 6:10 pm #7239
ryan
Username: ryanm

What about running the resulting javascript through a packer/obfuscater? Granted this will not “encrypt” the URIs but will make it less accessible to most views. For those really determined it will increase the time it take them to “find” the URIs, further decreasing the likelihood that one would be able to DL the video before the expiration of the TTL.

Something like Packer JavaScript for PHP (http://joliclic.free.fr/php/javascript-packer/en/).

I did not spend much time looking at s3flowshield, it might do something similar.

Viewing 10 replies - 26 through 35 (of 35 total)

This topic is closed to new replies. Topics with no replies for 2 weeks are closed automatically.

Old Forums (READ-ONLY): The community now lives at WP Sharks™. If you have an s2Member® Pro question, please use our new Support System.

Contacting s2Member: Please use our Support Center for bug reports, pre-sale questions & technical assistance.