<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" 
      xmlns:thr="http://purl.org/syndication/thread/1.0">
  <link rel="alternate" type="text/html" href="http://insideria.com/2009/12/rias-go-hollywood-integrating.html" />
  <link rel="self" type="application/atom+xml" href="http://insideria.com/atom.xml" />
  <id>tag:insideria.com,2010://34/tag:www.insideria.com,2009://34.38453-</id>
  <updated>2010-07-16T20:39:43Z</updated>
  <title>Comments for RIA&apos;s go Hollywood: An Introduction to Integrating Video Into Your Application (http://insideria.com/2009/12/rias-go-hollywood-integrating.html)</title>
  <generator uri="http://www.sixapart.com/movabletype/">Movable Type 4.21-en</generator>
  <entry>
    <id>tag:www.insideria.com,2009://34.38453</id>
    <link rel="alternate" type="text/html" href="http://insideria.com/2009/12/rias-go-hollywood-integrating.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blogs.oreilly.com/cgi-bin/mt/mt-atom.cgi/weblog/blog_id=34/entry_id=38453" title="RIA's go Hollywood: An Introduction to Integrating Video Into Your Application" />
    <published>2009-12-29T14:00:00Z</published>
    <updated>2009-12-29T14:00:00Z</updated>
    <title>RIA&apos;s go Hollywood: An Introduction to Integrating Video Into Your Application</title>
    <summary>In this article we&apos;re going to cover an exciting, and increasingly popular way to deliver an amazing user experience, video. Few mediums can grab one&apos;s attention quicker than video. Let&apos;s face it, people on the Internet have almost no attention span -- we&apos;ve even reduced our conversations to 140 character chunks -- so the faster you can grab and engage the user the better.</summary>
    <author>
      <name>Tim Todish</name>
      
    </author>
    
    <category term="Features" />
    
    <content type="html" xml:lang="en" xml:base="http://insideria.com/">
      <![CDATA[<p>In my <a href="http://www.insideria.com/2009/09/a-flex-developers-guide-to-use.html">last article</a> I talked about the importance of creating an engaging user experience and gave you a road map to follow to help get you there. In this article we're going to cover an exciting, and increasingly popular way to deliver that experience, video. Few mediums can grab one's attention quicker than video. Let's face it, people on the Internet have almost no attention span -- we've even reduced our conversations to 140 character chunks -- so the faster you can grab and engage the user the better.</p>

<p>Now of course, video is not right for every situation. In fact improperly using video in an app or including it when you shouldn't, can create a miserable user experience. We certainly don't want that, so it's very important to plan ahead and make sure your project lends itself well to incorporating video in the first place. Take a look at this <a href="http://discover.sonystyle.com/altus">Sony</a> site. It is a fantastic example of how video can be used to enhance the experience of a site. Right away you can tell the video is clean and well edited. This is a critical first step in using video on your site or in your app. Low quality or poorly edited video will turn off your users faster than a blink tag. Get it right. If video isn't your thing, hire someone to help you. It is better to have no video at all than to use video that is poor quality. Next you'll notice that there are a few different ways to interact with the video itself as well as items within the video. In this article, we're going to cover how to add these elements to your application.</p>

<p>Here's the <a href="http://doubletmedia.com/video/Main.html">final version</a> of what we're going to build in part one. Let me take a moment to say a big thank you to Josh Reed from <a href="http://reedmultimedia.com">Reed Multimedia</a> for shooting and editing this clip together for me. It's short and sweet but demonstrates a couple of interactive elements we can take a look at. First off though, let's take a quick look at how Josh setup the video file.</p>

<h2>Video Setup</h2>
<p>The video clips were captured and edited in Adobe Premiere.  After that, they were brought into After Effects where the clips could be color graded and time-remapped to enhance the action.  Finally, the audio design was created in Soundbooth and then brought back in to After Effects.  The After Effects composition was then rendered out using the F4V (H.264) format.  The default settings would work fine, but to reduce file size and increase download time, we changed the default bitrate settings.  The bitrate settings for these videos were VBR, 1 Pass with a target bitrate of 1.5 and a maximum bitrate of 3. Increasing the bitrate will result in better video quality, but also increases file size, and as a result could have a significant impact on download time.  Be sure to include audio output if you wish, by checking the box in the main options window.  The audio was output with the following settings: 44.1khz, 16 bit, and stereo.</p>

<h2>Tying It All Together</h2>
<p>Cue points are the key to making this all work. So what's a cue point?  As the name suggests, cue points are points in your video that dispatch events, specifically the CuePointEvent. You create listeners to wait for these events to fire and then handlers to execute whatever code you want when they do. There are three types of cue points, Navigation, Event and ActionScript. In this article we're only going to be dealing with ActionScript cue points but here's a quick definition of each courtesy of Adobe.</p>

<em><blockquote><p>A navigation cue point allows you to seek a particular frame in the FLV file because it creates a keyframe within the FLV file as near as possible to the time that you specify. A keyframe is a data segment that occurs between image frames in the FLV file stream. When you seek a navigation cue point, the component seeks to the keyframe and starts the cuePoint event.</p>

<p>An event cue point enables you to synchronize a point in time within the FLV file with an external event on the web page. The cuePoint event occurs precisely at the specified time. You can embed navigation and event cue points in an FLV file using either the Video Import wizard or the Flash Video Encoder.</p>

<p>An ActionScript cue point is an external cue point that you can add either through the component&#8217;s Flash Video Cue Points dialog box or through theFLVPlayback.addASCuePoint() method. The component stores and tracks ActionScript cue points apart from the FLV file, and consequently, they are less accurate than embedded cue points. ActionScript cue points are accurate to a tenth of a second.</p></blockquote></em>

<p>As you can see, different circumstances require different cue point types. Personally, I tend to use ActionScript cue points most often for the simple reason that you can add them in your code. Many times you may not have the luxury of adding the cue points during the render process so this is your only option. If you know ahead of time that you are going to be using cue points in your project and you are able to be involved in the video production process there are some advantages to adding your cue points during the render process. Most notably they offer more precise timing capabilities.</p>

<p>There is one thing to note before we start looking at some code. The way you setup and handle cue points is a little different between Flash and Flex so keep that in mind as you plan your project. We're going to cover the Flex method in these examples. Okay, let's get to it. The setup is pretty simple. The main application only contains a VideoDisplay component tied to a progress bar to show the progress of the movie. We also have a Canvas container that holds our seek point images that we will use to jump to a specific point within the video. </p>

<p>Let's start by taking a look at the VideoDisplay component. There are a couple things to point out here.</p>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;"> 
<code language="perl">
<pre>
&lt;mx:VideoDisplay id="<span class="quote">vidPlayer</span>"
	source="<span class="quote">assets/videos/michael.f4v</span>"
	cuePointManagerClass="<span class="quote">mx.controls.videoClasses.CuePointManager</span>"
	<span class="category2">x</span>="<span class="quote">37</span>" <span class="category2">y</span>="<span class="quote">27</span>" 
	<span class="category2">width</span>="<span class="quote">720</span>" <span class="category2">height</span>="<span class="quote">480</span>"
	borderStyle="<span class="quote">solid</span>" <span class="category2">borderColor</span>="<span class="quote">#3E3E3E</span>" borderThickness="<span class="quote">3</span>"
	click="<span class="quote">onVidPlayerClick(event);</span>"
	playheadUpdate="<span class="quote">onPlayheadUpdate(event);</span>"/&gt;</pre>
</code>
 
</div></div>

<p>Most of the stuff there is pretty standard, ID, height, width, source etc .... The one attribute to note is the cuePointManagerClass. This needs to be set so the VideoDisplay component knows how to handle the cue points. You can write your own or use the standard on like I did here. I also setup a couple event handlers for clicks and the playheadUpdate which keeps our progress bar in sync.</p>

<p>Now we need some cue points to pass in to our player. These are up in the init() function. You could either load your cue points dynamically from an XML file or database or hard code them as I've done here.</p>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;"> 
<code language="perl">
<pre>
[Bindable]
<span class="category1">private</span> <span class="category1">var</span> _cpArray:<span class="category2">Array</span> = <span class="category1">new</span> <span class="category2">Array</span>();
			
<span class="category1">private</span> <span class="category1">function</span> <span class="category2">init</span>():<span class="category1">void</span>
{
 	_cpArray.<span class="category2">push</span>({<span class="category2">name</span>:"<span class="quote">showFightCard1</span>", <span class="category2">time</span>:2, <span class="category2">type</span>:"<span class="quote">actionscript</span>"});
 	_cpArray.<span class="category2">push</span>({<span class="category2">name</span>:"<span class="quote">hideFightCard1</span>", <span class="category2">time</span>:8, <span class="category2">type</span>:"<span class="quote">actionscript</span>"});
 	_cpArray.<span class="category2">push</span>({<span class="category2">name</span>:"<span class="quote">showFist</span>", <span class="category2">time</span>:16, <span class="category2">type</span>:"<span class="quote">actionscript</span>"});
 				
 	vidPlayer.cuePointManager.setCuePoints(_cpArray);								
 	
 	vidPlayer.addEventListener(CuePointEvent.CUE_POINT,onCuePoint);
}</pre>
</code>
 
</div></div>

<p>The cue points are passed to the VideoDisplay component as an array of objects, so here we are just pushing cue point objects to the array. There isn't anything magical about these objects. They simply contain a <strong>name </strong>you can use to identify which cue point is firing, the <strong>time </strong>you want the event to fire, in seconds, and the <strong>type</strong>. After the array is finished we pass it to our player using the setCuePoints method of the player's cuePointManager class. Finally we add an event listener to the player to watch for our cue point events.</p>

<p>Let's take a look at what happens when one of our events fires. The first interaction we have in the video is a fight card that drops down from the top of the display. Now the video editor could have built this in After Effects just as easily if not more so, but what happens when that data changes? If that data is "baked in" then the video would need to be re-rendered after each update. This could be a very tedious and time consuming process. By adding this functionality in Flex we've significantly cut down on the complexity of making such updates. It gets cut down even further if we pull the data in dynamically from an external source.</p>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;"> 
<code language="perl">
<pre>
<span class="category1">private</span> <span class="category1">function</span> onCuePoint(e:CuePointEvent):<span class="category1">void</span>
{
 	<span class="category1">switch</span>(e.cuePointName) 
 	{
  		<span class="category1">case</span> "<span class="quote">showFightCard1</span>" :
  			loadFightCard(1);
  			<span class="category1">break</span>;
  		<span class="category1">case</span> "<span class="quote">hideFightCard1</span>" :
  			hideFightCard();
  			<span class="category1">break</span>;
  		<span class="category1">case</span> "<span class="quote">showFist</span>" :
  			showFist();
  			<span class="category1">break</span>;
  		<span class="category1">case</span> "<span class="quote">hideFist</span>" :
  			hideFist();
  			<span class="category1">break</span>;
  	}
}</pre>
</code>
 
</div></div>

<p>The onCuePoint function is our event handler function. It expects one parameter of type CuePointEvent which we can use to retrieve data about the cue point being fired. In this case we just need to know the name, which we run through a switch statement and call the corresponding function accordingly. In this case we're looking for the the "showFightCard1" cue point. When it fires we call the loadFightCard function and pass it the card number. That function basically creates a new FightCard component, sets some parameters, adds it to the stage and tweens it into view. This all should begin two seconds into the video as specified in the "showFightCard1" cue point object.</p>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;"> 
<code language="perl">
<pre>
<span class="category1">private</span> <span class="category1">function</span> loadFightCard(cardNo:<span class="category2">Number</span>):<span class="category1">void</span>
{
 	<span class="category1">var</span> fc:FightCard = <span class="category1">new</span> FightCard();
 	fc.cardNo = cardNo;
 	fc.<span class="category2">x</span> = 465;
 	fc.<span class="category2">y</span> = 38;
 	fc.<span class="category2">height</span> = 0;
 	
 	<span class="category1">this</span>._currentFightCard = <span class="category1">new</span> FightCard();
 	<span class="category1">this</span>._currentFightCard = fc;
 	
 	<span class="category1">this</span>.addChild(fc);
 	
 	<span class="category1">var</span> t:GTween = <span class="category1">new</span> GTween(fc,.4,{<span class="category2">height</span>:125});
 	t.<span class="category2">play</span>();
}</pre>
</code>
 
</div></div>

<p>The "fist button" gets added in much the same way. 
<ol>
	<li>Listen for the proper cue point</li>
	<li>Route through the event handler to the proper function</li>
	<li>Execute the function</li>
</ol>
The only real noticeable difference in this function is adding the click event to the object we're adding to the stage. In this example we're just linking to a new web site but it could do any number of things such as load a new video or create a new component on the stage.</p>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;"> 
<code language="perl">
<pre>
_fist.addEventListener(MouseEvent.CLICK,onFistClick);</pre>
</code>
 
</div></div>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;"> 
<code language="perl">
<pre>
<span class="category1">private</span> <span class="category1">function</span> onFistClick(e:MouseEvent):<span class="category1">void</span>
{
 	vidPlayer.<span class="category2">pause</span>();
 	flash.net.navigateToURL(<span class="category1">new</span> URLRequest("<span class="quote">http://www.grandrapidsmixedmartialarts.com/</span>"));
}</pre>
</code>
 
</div></div>

<p>Lastly, let's cover how to jump to a specific point within our video. When the application loads you'll notice two small buttons on the progress bar. These buttons represent points in time in the clip. Clicking on one jumps us directly to that point. If you remember when we discussed navigation cue points I mentioned that they offer more accurate timing capabilities because it inserts a keyframe in the video itself. This is a nice feature but sadly one that is not available to us since we're using the VideoDisplay control as you cannot seek to embedded cue points with this control. Never fear however, we can still achieve the same effect. In our init() function we add an event listener to our video player to tell us when the metadata for our video has been loaded. </p>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;"> 
<code language="perl">
<pre>
vidPlayer.addEventListener(MetadataEvent.METADATA_RECEIVED,loadSeekPoints);</pre>
</code>
 
</div></div>

<p>Once we have that information we can load our seek points.</p>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;"> 
<code language="perl">
<pre>
<span class="category1">private</span> <span class="category1">function</span> loadSeekPoints(e:MetadataEvent):<span class="category1">void</span>
{
 	<span class="category1">var</span> arSeekPoints:<span class="category2">Array</span> = <span class="category1">new</span> <span class="category2">Array</span>();
 	arSeekPoints.<span class="category2">push</span>({<span class="category2">name</span>:"<span class="quote">point1</span>", <span class="category2">time</span>:21});
 	arSeekPoints.<span class="category2">push</span>({<span class="category2">name</span>:"<span class="quote">point2</span>", <span class="category2">time</span>:36});
 	
 	<span class="category1">for</span> each(<span class="category1">var</span> obj:<span class="category2">Object</span> <span class="category1">in</span> arSeekPoints)
 	{
  		<span class="category1">var</span> sp:SeekPoint = <span class="category1">new</span> SeekPoint();
  		sp.seekPointName = obj.<span class="category2">name</span>;
  		sp.seekPointTime = obj.<span class="category2">time</span>;
  		sp.source = "<span class="quote">assets/images/point.png</span>";
  		sp.buttonMode = <span class="category1">true</span>;
  		sp.<span class="category2">useHandCursor</span> = <span class="category1">true</span>;
  		sp.addEventListener(MouseEvent.CLICK,seekToPoint);
  		sp.<span class="category2">y</span> = 2;
  		sp.<span class="category2">x</span> = (((sp.seekPointTime/e.info.<span class="category2">duration</span>) * 720)-7);
  		spContainer.addChild(sp);
  	}				
}</pre>
</code>
 
</div></div>

<p>This function is not unlike the others we've used to add items to our stage. We start with an array of seek point objects that contain the name and time we want to seek to in seconds. Obviously in a real application if we had several seek points we'd want to load these dynamically but this works for the demo. Next we loop through our array, creating our seek point objects and positioning on the stage. You'll notice each object has a click handler that points to our seekToPoint function.</p>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;"> 
<code language="perl">
<pre>
<span class="category1">private</span> <span class="category1">function</span> seekToPoint(e:MouseEvent):<span class="category1">void</span>
{
 	<span class="category1">if</span>(<span class="category1">this</span>._currentFightCard != <span class="category1">null</span>) hideFightCard();
 	
 	vidPlayer.playheadTime = e.currentTarget.seekPointTime;
}</pre>
</code>
 
</div></div>

<p>This function is pretty simple. It starts by checking to see if the fight card is on the stage and if so, it hides it. This is necessary because we are seeking past the cue point in our video that hides the card. Without this check the card would remain visible for the rest of the video. </p>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;"> 
<code language="perl">
<pre>
<span class="category1">if</span>(<span class="category1">this</span>._currentFightCard != <span class="category1">null</span>) hideFightCard</pre>
</code>
 
</div></div>

<p>The next line seeks to our new time in the video. Our seek point objects have a seekPointTime property that we can access through the event object. We set the playHeadTime property of our video player to this value and voila. That's it.</p>

<div class="acode" style="overflow: auto; padding: 10px;" ><div style="overflow-x: visible;"> 
<code language="perl">
<pre>
vidPlayer.playheadTime = e.currentTarget.seekPointTime;</pre>
</code>
 
</div></div>

<p>As you can see the concepts and process for adding interactive video to your applications is not very difficult. Now that you have the knowledge, only your imagination can limit the possibilities of how to use it. Just remember, video is not a good option for every site or application. Just because you can, doesn't mean you should. Use these new tricks wisely.</p>

<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-1078907-5");
pageTracker._trackPageview();
} catch(err) {}</script>]]>
      
    </content>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.38453-comment:2245880</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.38453" type="text/html" href="http://insideria.com/2009/12/rias-go-hollywood-integrating.html"/>
    <link rel="alternate" type="text/html" href="http://insideria.com/2009/12/rias-go-hollywood-integrating.html#comment-2245880" />
    <title>Comment from brindy on 2009-12-29</title>
    <author>
        <name>brindy</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>" Let's face it, people on the Internet have almost no attention span"</p>

<p>You're right and that's where I stopped reading.</p>]]>
    </content>
    <published>2009-12-29T15:17:29Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.38453-comment:2377982</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.38453" type="text/html" href="http://insideria.com/2009/12/rias-go-hollywood-integrating.html"/>
    <link rel="alternate" type="text/html" href="http://insideria.com/2009/12/rias-go-hollywood-integrating.html#comment-2377982" />
    <title>Comment from PIFFY on 2010-03-10</title>
    <author>
        <name>PIFFY</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>lol brindy - but really I agree with the quote.<br />
PIFFY - <a href="http://piffy.org">Pay It Forward</a> For Youth</p>]]>
    </content>
    <published>2010-03-11T03:33:04Z</published>
  </entry>

  <entry>
    <id>tag:www.insideria.com,2009://34.38453-comment:2427466</id>
    <thr:in-reply-to ref="tag:www.insideria.com,2009://34.38453" type="text/html" href="http://insideria.com/2009/12/rias-go-hollywood-integrating.html"/>
    <link rel="alternate" type="text/html" href="http://insideria.com/2009/12/rias-go-hollywood-integrating.html#comment-2427466" />
    <title>Comment from Alex on 2010-04-10</title>
    <author>
        <name>Alex</name>
        <uri></uri>
    </author>
    <content type="html" xml:lang="en" xml:base="">
        <![CDATA[<p>I totally agree with you on the video. The Sony site you linked to was awesome. It was a little slow loading for me but I got the point. Far better than any text on products and it engaged me a lot longer. The MMA was cool tool. And, finally, I agree that I should hire someone to do video for me when the time comes. Right now I keep things simple but this tutorial is great.<br />
<a href="http://hubpages.com/hub/Ab-Circle">Alex</a></p>]]>
    </content>
    <published>2010-04-11T06:26:23Z</published>
  </entry>

</feed
