Advertisement
Guest User

Spark's VideoDisplay

a guest
Feb 16th, 2012
465
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. ////////////////////////////////////////////////////////////////////////////////
  2. //
  3. //  ADOBE SYSTEMS INCORPORATED
  4. //  Copyright 2009 Adobe Systems Incorporated
  5. //  All Rights Reserved.
  6. //
  7. //  NOTICE: Adobe permits you to use, modify, and distribute this file
  8. //  in accordance with the terms of the license agreement accompanying it.
  9. //
  10. ///////////////////////////////////////////////////////////////////////////////
  11.  
  12. package spark.components
  13. {
  14.  
  15. import flash.events.Event;
  16. import flash.geom.Point;
  17. import flash.geom.Rectangle;
  18. import flash.media.Video;
  19.  
  20. import mx.core.IUIComponent;
  21. import mx.core.IVisualElement;
  22. import mx.core.UIComponent;
  23. import mx.core.mx_internal;
  24. import mx.events.FlexEvent;
  25. import mx.events.PropertyChangeEvent;
  26. import mx.resources.IResourceManager;
  27. import mx.resources.ResourceManager;
  28.  
  29.  
  30. import org.osmf.containers.MediaContainer;
  31. import org.osmf.elements.VideoElement;
  32. import org.osmf.events.AudioEvent;
  33. import org.osmf.events.DisplayObjectEvent;
  34. import org.osmf.events.LoadEvent;
  35. import org.osmf.events.MediaPlayerCapabilityChangeEvent;
  36. import org.osmf.events.MediaPlayerStateChangeEvent;
  37. import org.osmf.events.SeekEvent;
  38. import org.osmf.events.TimeEvent;
  39. import org.osmf.layout.HorizontalAlign;
  40. import org.osmf.layout.LayoutMetadata;
  41. import org.osmf.layout.ScaleMode;
  42. import org.osmf.layout.VerticalAlign;
  43. import org.osmf.media.DefaultMediaFactory;
  44. import org.osmf.media.MediaElement;
  45. import org.osmf.media.MediaFactory;
  46. import org.osmf.media.MediaFactoryItem;
  47. import org.osmf.media.MediaPlayer;
  48. import org.osmf.media.MediaPlayerState;
  49. import org.osmf.media.MediaResourceBase;
  50. import org.osmf.media.URLResource;
  51. import org.osmf.media.MediaType;
  52. import org.osmf.net.NetLoader;
  53. import org.osmf.net.DynamicStreamingItem;
  54. import org.osmf.net.rtmpstreaming.RTMPDynamicStreamingNetLoader;
  55. import org.osmf.net.DynamicStreamingResource;
  56. import org.osmf.net.FMSURL;
  57. import org.osmf.utils.OSMFStrings;
  58. import org.osmf.utils.URL;
  59.  
  60. import spark.components.mediaClasses.DynamicStreamingVideoItem;
  61. import spark.components.mediaClasses.DynamicStreamingVideoSource;
  62. import spark.primitives.BitmapImage;
  63.  
  64. use namespace mx_internal;
  65.  
  66. //--------------------------------------
  67. //  Events
  68. //--------------------------------------
  69.  
  70. /**
  71.  *  Dispatched when the data is received as a download operation progresses.
  72.  *  This event is only dispatched when playing a video by downloading it
  73.  *  directly from a server, typically by issuing an HTTP request.
  74.  *  It is not displatched when playing a video from a special media server,
  75.  *  such as Flash Media Server.
  76.  *
  77.  *  <p>This event may not be dispatched when the source is set to null or a playback
  78.  *  error occurs.</p>
  79.  *
  80.  *  @eventType org.osmf.events.LoadEvent.BYTES_LOADED_CHANGE
  81.  *  
  82.  *  @langversion 3.0
  83.  *  @playerversion Flash 10
  84.  *  @playerversion AIR 1.0
  85.  *  @productversion Flex 4
  86.  */
  87. [Event(name="bytesLoadedChange",type="org.osmf.events.LoadEvent")]
  88.  
  89. /**
  90.  *  Dispatched when the playhead reaches the duration for playable media.
  91.  *
  92.  *  @eventType org.osmf.events.TimeEvent.COMPLETE
  93.  *  
  94.  *  @langversion 3.0
  95.  *  @playerversion Flash 10
  96.  *  @playerversion AIR 1.0
  97.  *  @productversion Flex 4
  98.  */  
  99. [Event(name="complete", type="org.osmf.events.TimeEvent")]
  100.  
  101. /**
  102.  *  Dispatched when the <code>currentTime</code> property of the MediaPlayer has changed.
  103.  *
  104.  *  <p>This event may not be dispatched when the source is set to null or a playback
  105.  *  error occurs.</p>
  106.  *
  107.  *  @eventType org.osmf.events.TimeEvent.CURRENT_TIME_CHANGE
  108.  *
  109.  *  @langversion 3.0
  110.  *  @playerversion Flash 10
  111.  *  @playerversion AIR 1.0
  112.  *  @productversion Flex 4
  113.  */
  114. [Event(name="currentTimeChange",type="org.osmf.events.TimeEvent")]
  115.  
  116. /**
  117.  *  Dispatched when the <code>duration</code> property of the media has changed.
  118.  *
  119.  *  <p>This event may not be dispatched when the source is set to null or a playback
  120.  *  error occurs.</p>
  121.  *
  122.  *  @eventType org.osmf.events.TimeEvent.DURATION_CHANGE
  123.  *
  124.  *  @langversion 3.0
  125.  *  @playerversion Flash 10
  126.  *  @playerversion AIR 1.0
  127.  *  @productversion Flex 4
  128.  */
  129. [Event(name="durationChange", type="org.osmf.events.TimeEvent")]
  130.  
  131. /**
  132.  *  Dispatched when the MediaPlayer's state has changed.
  133.  *
  134.  *  @eventType org.osmf.events.MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE
  135.  *  
  136.  *  @langversion 3.0
  137.  *  @playerversion Flash 10
  138.  *  @playerversion AIR 1.0
  139.  *  @productversion Flex 4
  140.  */
  141. [Event(name="mediaPlayerStateChange", type="org.osmf.events.MediaPlayerStateChangeEvent")]
  142.  
  143. //--------------------------------------
  144. //  Other metadata
  145. //--------------------------------------
  146.  
  147. [DefaultProperty("source")]
  148.  
  149. [ResourceBundle("osmf")]
  150.  
  151. [IconFile("VideoDisplay.png")]
  152.  
  153. /**
  154.  * Because this component does not define a skin for the mobile theme, Adobe
  155.  * recommends that you not use it in a mobile application. Alternatively, you
  156.  * can define your own mobile skin for the component. For more information,
  157.  * see <a href="http://help.adobe.com/en_US/Flex/4.0/UsingSDK/WS53116913-F952-4b21-831F-9DE85B647C8A.html">Spark Skinning</a>.
  158.  */
  159. [DiscouragedForProfile("mobileDevice")]
  160.  
  161. /**
  162.  *  The VideoDisplay class is chromeless video player that supports
  163.  *  progressive download, multi-bitrate, and streaming video.
  164.  *
  165.  *  <p><code>VideoDisplay</code> is the chromeless version that does not support skinning.
  166.  *  It is useful when you do not want the user to interact with the control.</p>
  167.  *
  168.  *  <p><code>VideoPlayer</code> is the skinnable version.</p>
  169.  *
  170.  *  <p>The VideoDisplay control has the following default characteristics:</p>
  171.  *     <table class="innertable">
  172.  *        <tr>
  173.  *           <th>Characteristic</th>
  174.  *           <th>Description</th>
  175.  *        </tr>
  176.  *        <tr>
  177.  *           <td>Default size</td>
  178.  *           <td>0 pixels wide by 0 pixels high with no content,
  179.  *             and the width and height of the video with content</td>
  180.  *        </tr>
  181.  *        <tr>
  182.  *           <td>Minimum size</td>
  183.  *           <td>0</td>
  184.  *        </tr>
  185.  *        <tr>
  186.  *           <td>Maximum size</td>
  187.  *           <td>10000 pixels wide and 10000 pixels high</td>
  188.  *        </tr>
  189.  *     </table>
  190.  *
  191.  *  @mxml
  192.  *
  193.  *  <p>The <code>&lt;s:VideoDisplay&gt;</code> tag inherits all of the tag
  194.  *  attributes of its superclass and adds the following tag attributes:</p>
  195.  *
  196.  *  <pre>
  197.  *  &lt;s:VideoDisplay
  198.  *    <strong>Properties</strong>
  199.  *    autoDisplayFirstFrame="true"
  200.  *    autoPlay="true"
  201.  *    autoRewind="true"
  202.  *    loop="false"
  203.  *    muted="false"
  204.  *    pauseWhenHidden="true"
  205.  *    scaleMode="letterbox"
  206.  *    source=""
  207.  *    volume="1"
  208.  *  
  209.  *    <strong>Events</strong>
  210.  *    bytesLoadedChange="<i>No default</i>"
  211.  *    complete="<i>No default</i>"
  212.  *    currentTimeChange="<i>No default</i>"
  213.  *    durationChange="<i>No default</i>"
  214.  *    mediaPlayerStateChange="<i>No default</i>"
  215.  *  
  216.  *  /&gt;
  217.  *  </pre>
  218.  *
  219.  *  @see spark.components.VideoPlayer
  220.  *
  221.  *  @includeExample examples/VideoDisplayExample.mxml
  222.  *  
  223.  *  @langversion 3.0
  224.  *  @playerversion Flash 10
  225.  *  @playerversion AIR 1.5
  226.  *  @productversion Flex 4
  227.  */
  228. public class VideoDisplay extends UIComponent
  229. {
  230.     include "../core/Version.as";
  231.    
  232.     //--------------------------------------------------------------------------
  233.     //
  234.     //  Class methods
  235.     //
  236.     //--------------------------------------------------------------------------
  237.    
  238.     /**
  239.      *  @private
  240.      *  Set as the OSMF.resourceBundleFunction and used to look up
  241.      *  strings so the OSMF RTEs are localized in Flex.
  242.      */
  243.     private static function getResourceString(resourceName:String,
  244.                                               args:Array = null):String
  245.     {
  246.         var resourceManager:IResourceManager = ResourceManager.getInstance();
  247.         return resourceManager.getString("osmf", resourceName, args);
  248.     }
  249.    
  250.     /**
  251.      * Copied from OSMF ScaleModeUtils.getScaledSize. ScaleModeUtils became
  252.      * an internal OSMF class in OSMF 1.0 so it is copied here.
  253.      *
  254.      * Calculates the scaled size based on the scaling algorithm.  
  255.      * The available width and height are the width and height of the container.
  256.      * The intrinsic width and height are the width and height of the content.
  257.      *  
  258.      *  @langversion 3.0
  259.      *  @playerversion Flash 10
  260.      *  @playerversion AIR 1.5
  261.      *  @productversion OSMF 1.0
  262.      */
  263.     private static function getScaledSize
  264.         ( scaleMode:String
  265.           , availableWidth:Number, availableHeight:Number
  266.             , intrinsicWidth:Number, intrinsicHeight:Number
  267.         ):Point
  268.     {
  269.         var result:Point;
  270.        
  271.         switch (scaleMode)
  272.         {
  273.             case ScaleMode.ZOOM:
  274.             case ScaleMode.LETTERBOX:
  275.                
  276.                 var availableRatio:Number
  277.                 = availableWidth
  278.                 / availableHeight;
  279.                
  280.                 var componentRatio:Number
  281.                 = (intrinsicWidth || availableWidth)
  282.                 / (intrinsicHeight || availableHeight);
  283.                
  284.                 if  (   (scaleMode == ScaleMode.ZOOM && componentRatio < availableRatio)
  285.                     ||  (scaleMode == ScaleMode.LETTERBOX && componentRatio > availableRatio)
  286.                 )
  287.                 {
  288.                     result
  289.                     = new Point
  290.                         ( availableWidth
  291.                             , availableWidth / componentRatio
  292.                         );
  293.                 }
  294.                 else
  295.                 {
  296.                     result
  297.                     = new Point
  298.                         ( availableHeight * componentRatio
  299.                             , availableHeight
  300.                         );
  301.                 }
  302.                
  303.                 break;
  304.            
  305.             case ScaleMode.STRETCH:
  306.                
  307.                 result
  308.                 = new Point
  309.                 ( availableWidth
  310.                     , availableHeight
  311.                 );
  312.                 break;
  313.            
  314.             case ScaleMode.NONE:
  315.                
  316.                 result
  317.                 = new Point
  318.                 ( intrinsicWidth    || availableWidth
  319.                     , intrinsicHeight   || availableHeight
  320.                 );
  321.                
  322.                 break;
  323.         }
  324.        
  325.         return result;
  326.     }
  327.    
  328.     //--------------------------------------------------------------------------
  329.     //
  330.     //  Constructor
  331.     //
  332.     //--------------------------------------------------------------------------
  333.    
  334.     /**
  335.      *  Constructor.
  336.      *  
  337.      *  @langversion 3.0
  338.      *  @playerversion Flash 10
  339.      *  @playerversion AIR 1.5
  340.      *  @productversion Flex 4
  341.      */
  342.     public function VideoDisplay()
  343.     {
  344.         super();
  345.        
  346.         // create the underlying MediaPlayer class first.
  347.         createUnderlyingVideoPlayer();
  348.        
  349.         // added and removed event listeners to see whether we should
  350.         // start or stop the video
  351.         addEventListener(Event.ADDED_TO_STAGE, addedToStageHandler);
  352.         addEventListener(Event.REMOVED_FROM_STAGE, removedFromStageHandler);
  353.        
  354.         // Set the OSMF hook used for localizing runtime error messages.
  355.         // OSMF itself has English-only messages,
  356.         // but higher layers like Flex can provide localized versions.
  357.         OSMFStrings.resourceStringFunction = getResourceString;
  358.     }
  359.    
  360.     //--------------------------------------------------------------------------
  361.     //
  362.     //  Variables
  363.     //
  364.     //--------------------------------------------------------------------------
  365.    
  366.     /**
  367.      *  @private
  368.      *  This is the underlying VideoPlayer object. At some point in the
  369.      *  future, we may change to a new implementation.
  370.      */
  371.     mx_internal var videoPlayer:MediaPlayer;
  372.    
  373.     /**
  374.      *  @private
  375.      *  This is the underlying container used to display
  376.      *  the underlying videoPlayer.
  377.      */
  378.     mx_internal var videoContainer:MediaContainer;
  379.      
  380.     /**
  381.      *  @private
  382.      *  How the correct media elements are created based on the url of
  383.      *  the resource.
  384.      */
  385.     mx_internal var mediaFactory:MediaFactory;
  386.      
  387.     /**
  388.      *  @private
  389.      *  Whether the video is on the display list or not
  390.      */
  391.     private var _isOnDisplayList:Boolean = false;
  392.    
  393.     /**
  394.      *  @private
  395.      *  Whether the we should play the video when the video
  396.      *  becomes playable again (visible, on display list, and enabled).
  397.      *  This starts out as true, but when we pause the video is changePlayback(),
  398.      *  we set it to false.  Also, when a user action occurs, like pause() or play()
  399.      *  or stop() is called, we set it to false as well.
  400.      */
  401.     private var playTheVideoOnVisible:Boolean = true;
  402.    
  403.     /**
  404.      *  @private
  405.      */
  406.     private var effectiveVisibility:Boolean = false;
  407.    
  408.     /**
  409.      *  @private
  410.      */
  411.     private var effectiveVisibilityChanged:Boolean = false;
  412.        
  413.     /**
  414.      *  @private
  415.      */
  416.     private var effectiveEnabled:Boolean = false;
  417.    
  418.     /**
  419.      *  @private
  420.      */
  421.     private var effectiveEnabledChanged:Boolean = false;
  422.    
  423.     /**
  424.      *  @private
  425.      *  We do different things in the source setter based on if we
  426.      *  are initialized or not.
  427.      */
  428.     private var initializedOnce:Boolean = false;
  429.    
  430.     /**
  431.      *  @private
  432.      *  Keeps track of the muted property while loading up a
  433.      *  video because of autoDisplayFirstFrame.
  434.      */
  435.     private var beforeLoadMuted:Boolean;
  436.    
  437.     /**
  438.      *  @private
  439.      *  Keeps track whether we are loading up the
  440.      *  video because of autoDisplayFirstFrame.
  441.      *
  442.      *  <p>In this case we are in "state1" of loading,
  443.      *  which means we are waiting for the READY
  444.      *  MediaPlayerStateChangeEvent and haven't done anything yet.</p>
  445.      */
  446.     private var inLoadingState1:Boolean;
  447.    
  448.     /**
  449.      *  @private
  450.      *  Keeps track whether we are loading up the
  451.      *  video because of autoDisplayFirstFrame.
  452.      *
  453.      *  <p>In this case we are in "state2" of loading,
  454.      *  which means have set videoPlayer.displayObject.visible=false  
  455.      *  and videoPlayer.muted=true.  We've also called play() and are
  456.      *  waiting for the DimensionChangeEvent.</p>
  457.      *
  458.      *  <p>Note: At this point, inLoadingState1 = true as well.</p>
  459.      */
  460.     private var inLoadingState2:Boolean;
  461.    
  462.     /**
  463.      *  @private
  464.      *  Keeps track whether we are loading up the
  465.      *  video because of autoDisplayFirstFrame.
  466.      *
  467.      *  <p>In this case we are in "state3" of loading,
  468.      *  which means have received the DimensionChangeEvent and have called
  469.      *  pause() and seek(0).  We are currently waiting for the
  470.      *  SEEK_END event, at which point we will be completely loaded up.</p>
  471.      *
  472.      *  <p>Note: At this point, inLoadingState1 = inLoadingState2 = true.</p>
  473.      */
  474.     private var inLoadingState3:Boolean;
  475.    
  476.     /**
  477.      *  @private
  478.      *
  479.      *  Old value of videoPlayer.currentTimeUpdateInterval. We store the old
  480.      *  value when we are taken off the stage and pauseWhenHidden is true
  481.      *  (removedFromStageHandler). We restore the old value when we are added
  482.      *  to the stage (addedToStageHandler). The value is used in setupSource()
  483.      *  to turn the timers back on if they were disabled. The value if also used
  484.      *  to check if we should turn off the timers in videoPlayer_seekChangeHandler
  485.      *  and videoPlayer_currentTimeChangeHandler.
  486.      *  This is done to keep this component from being pinned in memory by the timer
  487.      *  associated the currentTimeUpdateInterval property.
  488.      */
  489.     private var oldCurrentTimeUpdateInterval:Number = NaN;
  490.    
  491.     /**
  492.      *  @private
  493.      *
  494.      *  Old value of videoPlayer.bytesLoadedUpdateInterval. We store the old
  495.      *  value when we are taken off the stage and pauseWhenHidden is true
  496.      *  (removedFromStageHandler). We restore the old value when we are added
  497.      *  to the stage (addedToStageHandler). The value is used in setupSource()
  498.      *  to turn the timers back on if they were disabled. The value if also used
  499.      *  to check if we should turn off the timers in videoPlayer_seekChangeHandler
  500.      *  and videoPlayer_currentTimeChangeHandler.
  501.      *  This is done to keep this component from being pinned in memory by the timer
  502.      *  associated the bytesLoadedUpdateInterval property.
  503.      */
  504.     private var oldBytesLoadedUpdateInterval:Number = NaN;
  505.    
  506.     //--------------------------------------------------------------------------
  507.     //
  508.     //  Properties
  509.     //
  510.     //--------------------------------------------------------------------------
  511.    
  512.     //----------------------------------
  513.     //  autoDisplayFirstFrame
  514.     //----------------------------------
  515.    
  516.     /**
  517.      *  @private
  518.      */
  519.     private var _autoDisplayFirstFrame:Boolean = true;
  520.        
  521.     [Inspectable(category="General", defaultValue="true")]
  522.    
  523.     /**
  524.      *  If <code>autoPlay = false</code>, then
  525.      *  <code>autoDisplayFirstFrame</code> controls whether the video
  526.      *  is loaded when the <code>source</code> is set.  
  527.      *  If <code>autoDisplayFirstFrame</code>
  528.      *  is set to <code>true</code>, then the first frame of the video is
  529.      *  loaded and the video is sized correctly.  
  530.      *  If <code>autoDisplayFirstFrame</code> is set to <code>false</code>, then no
  531.      *  connection to the source is made, the first frame is not shown,
  532.      *  and the video's size is not determined until someone tries to play
  533.      *  the video.
  534.      *
  535.      *  <p>If <code>autoPlay = true</code>, then this flag is ignored.</p>
  536.      *  
  537.      *  @default true
  538.      *
  539.      *  @langversion 3.0
  540.      *  @playerversion Flash 10
  541.      *  @playerversion AIR 1.5
  542.      *  @productversion Flex 4
  543.      */
  544.     public function get autoDisplayFirstFrame():Boolean
  545.     {
  546.         return _autoDisplayFirstFrame;
  547.     }
  548.    
  549.     /**
  550.      * @private
  551.      */
  552.     public function set autoDisplayFirstFrame(value:Boolean):void
  553.     {
  554.         _autoDisplayFirstFrame = value;
  555.     }
  556.    
  557.     //----------------------------------
  558.     //  autoPlay
  559.     //----------------------------------
  560.    
  561.     /**
  562.      * @private
  563.      */
  564.     private var _autoPlay:Boolean = true;
  565.    
  566.     [Inspectable(category="General", defaultValue="true")]
  567.    
  568.     /**
  569.      *  Specifies whether the video starts playing immediately when the
  570.      *  <code>source</code> property is set.
  571.      *  If <code>true</code>, the video file immediately begins to buffer and
  572.      *  play.
  573.      *
  574.      *  <p>Even if <code>autoPlay</code> is set to <code>false</code>, Flex
  575.      *  starts loading the video after the <code>initialize()</code> method is
  576.      *  called.
  577.      *  For Flash Media Server, this means creating the stream and loading
  578.      *  the first frame to display.
  579.      *  In the case of an HTTP download, Flex starts downloading the stream
  580.      *  and shows the first frame.</p>
  581.      *
  582.      *  <p>If <code>playWhenHidden</code> is set to <code>false</code>, then
  583.      *  <code>autoPlay</code> also affects what happens when the video
  584.      *  comes back on stage and is enabled and visible.</p>
  585.      *  
  586.      *  @default true
  587.      *  
  588.      *  @langversion 3.0
  589.      *  @playerversion Flash 10
  590.      *  @playerversion AIR 1.5
  591.      *  @productversion Flex 4
  592.      */
  593.     public function get autoPlay():Boolean
  594.     {
  595.         return _autoPlay;
  596.     }
  597.    
  598.     /**
  599.      * @private (setter)
  600.      */
  601.     public function set autoPlay(value:Boolean):void
  602.     {
  603.         if (autoPlay == value)
  604.             return;
  605.        
  606.         _autoPlay = value;
  607.        
  608.         // call changePlayback() but don't immediately play or pause
  609.         // based on this change to autoPlay
  610.         changePlayback(false, false);
  611.     }
  612.    
  613.     //----------------------------------
  614.     //  autoRewind
  615.     //----------------------------------
  616.    
  617.     [Inspectable(category="General", defaultValue="true")]
  618.    
  619.     /**
  620.      *  Specifies whether the FLV file should rewind to the first frame
  621.      *  when play stops, either by calling the <code>stop()</code> method or by
  622.      *  reaching the end of the stream.
  623.      *
  624.      *  <p>This property has no effect for live streaming video.</p>
  625.      *
  626.      *  @default true
  627.      *  
  628.      *  @langversion 3.0
  629.      *  @playerversion Flash 10
  630.      *  @playerversion AIR 1.5
  631.      *  @productversion Flex 4
  632.      */
  633.     public function get autoRewind():Boolean
  634.     {
  635.         return videoPlayer.autoRewind;
  636.     }
  637.    
  638.     public function set autoRewind(value:Boolean):void
  639.     {
  640.         videoPlayer.autoRewind = value;
  641.     }
  642.    
  643.     //----------------------------------
  644.     //  bytesLoaded
  645.     //----------------------------------
  646.    
  647.     [Inspectable(Category="General", defaultValue="0")]
  648.     [Bindable("bytesLoadedChange")]
  649.     [Bindable("mediaPlayerStateChange")]
  650.    
  651.     /**
  652.      *  The number of bytes of data that have been downloaded into the application.
  653.      *
  654.      *  @return The number of bytes of data that have been downloaded into the application.
  655.      *  @default 0
  656.      *  
  657.      *  @langversion 3.0
  658.      *  @playerversion Flash 10
  659.      *  @playerversion AIR 1.5
  660.      *  @productversion Flex 4
  661.      */
  662.     public function get bytesLoaded():Number
  663.     {
  664.         return videoPlayer.bytesLoaded;
  665.     }
  666.    
  667.     //----------------------------------
  668.     //  bytesTotal
  669.     //----------------------------------
  670.    
  671.     [Inspectable(Category="General", defaultValue="0")]
  672.     [Bindable("mediaPlayerStateChange")]
  673.    
  674.     /**
  675.      *  The total size in bytes of the data being downloaded into the application.
  676.      *
  677.      *  @return The total size in bytes of the data being downloaded into the application.
  678.      *  @default 0
  679.      *  
  680.      *  @langversion 3.0
  681.      *  @playerversion Flash 10
  682.      *  @playerversion AIR 1.5
  683.      *  @productversion Flex 4
  684.      */
  685.     public function get bytesTotal():Number
  686.     {
  687.         return videoPlayer.bytesTotal;
  688.     }
  689.    
  690.     //----------------------------------
  691.     //  currentTime
  692.     //----------------------------------
  693.    
  694.     [Inspectable(Category="General", defaultValue="0")]
  695.     [Bindable("currentTimeChange")]
  696.     [Bindable("mediaPlayerStateChange")]
  697.    
  698.     /**
  699.      *  Current time of the playhead, measured in seconds,
  700.      *  since the video starting playing.
  701.      *
  702.      *  @default 0
  703.      *  
  704.      *  @langversion 3.0
  705.      *  @playerversion Flash 10
  706.      *  @playerversion AIR 1.5
  707.      *  @productversion Flex 4
  708.      */
  709.     public function get currentTime():Number
  710.     {
  711.         return videoPlayer.currentTime;
  712.     }
  713.    
  714.     //----------------------------------
  715.     //  duration
  716.     //----------------------------------
  717.    
  718.     [Inspectable(Category="General", defaultValue="0")]
  719.     [Bindable("durationChange")]
  720.     [Bindable("mediaPlayerStateChange")]
  721.    
  722.     /**
  723.      *  Duration of the video's playback, in seconds
  724.      *
  725.      *  @return The total running time of the video in seconds
  726.      *  @default 0
  727.      *  
  728.      *  @langversion 3.0
  729.      *  @playerversion Flash 10
  730.      *  @playerversion AIR 1.5
  731.      *  @productversion Flex 4
  732.      */
  733.     public function get duration():Number
  734.     {
  735.         return videoPlayer.duration;
  736.     }
  737.    
  738.     //----------------------------------
  739.     //  loop
  740.     //----------------------------------
  741.    
  742.     [Inspectable(Category="General", defaultValue="false")]
  743.    
  744.     /**
  745.      *  Indicates whether the media should play again after playback has completed.
  746.      *  The <code>loop</code> property takes precedence over the <code>autoRewind</code>
  747.      *  property, so if loop is set to <code>true</code>, the <code>autoRewind</code>
  748.      *  property is ignored.
  749.      *
  750.      *  @default false
  751.      *  
  752.      *  @langversion 3.0
  753.      *  @playerversion Flash 10
  754.      *  @playerversion AIR 1.5
  755.      *  @productversion Flex 4
  756.      */
  757.     public function get loop():Boolean
  758.     {
  759.         return videoPlayer.loop;
  760.     }
  761.    
  762.     /**
  763.      *  @private
  764.      */
  765.     public function set loop(value:Boolean):void
  766.     {
  767.         if (loop == value)
  768.             return;
  769.        
  770.         videoPlayer.loop = value;
  771.     }
  772.    
  773.     //----------------------------------
  774.     //  mediaPlayerState
  775.     //----------------------------------
  776.    
  777.     [Inspectable(category="General", defaultValue="uninitialized")]
  778.     [Bindable("mediaPlayerStateChange")]
  779.    
  780.     /**
  781.      *  The current state of the video.  See
  782.      *  org.osmf.media.MediaPlayerState for available values.
  783.      *  
  784.      *  @default uninitialized
  785.      *
  786.      *  @see org.osmf.media.MediaPlayerState
  787.      *
  788.      *  @langversion 3.0
  789.      *  @playerversion Flash 10
  790.      *  @playerversion AIR 1.5
  791.      *  @productversion Flex 4
  792.      */
  793.     public function get mediaPlayerState():String
  794.     {
  795.         return videoPlayer.state;
  796.     }
  797.    
  798.     //----------------------------------
  799.     //  muted
  800.     //----------------------------------
  801.    
  802.     [Inspectable(category="General", defaultValue="false")]
  803.     [Bindable("volumeChanged")]
  804.    
  805.     /**
  806.      *  Set to <code>true</code> to mute the video, <code>false</code>
  807.      *  to unmute the video.
  808.      *  
  809.      *  @langversion 3.0
  810.      *  @playerversion Flash 10
  811.      *  @playerversion AIR 1.5
  812.      *  @productversion Flex 4
  813.      */
  814.     public function get muted():Boolean
  815.     {
  816.         // if inLoadingState2, we've got to
  817.         // fake the muted value
  818.         if (inLoadingState2)
  819.             return beforeLoadMuted;
  820.        
  821.         return videoPlayer.muted;
  822.     }
  823.    
  824.     /**
  825.      *  @private
  826.      */
  827.     public function set muted(value:Boolean):void
  828.     {
  829.         if (muted == value)
  830.             return;
  831.        
  832.         // if inLoadingState2, don't change muted...just fake it
  833.         if (inLoadingState2)
  834.         {
  835.             beforeLoadMuted = value;
  836.             return;
  837.         }
  838.        
  839.         videoPlayer.muted = value;
  840.     }
  841.    
  842.     //----------------------------------
  843.     //  pauseWhenHidden
  844.     //----------------------------------
  845.    
  846.     /**
  847.      *  @private
  848.      *  Storage variable for pauseWhenHidden
  849.      */
  850.     private var _pauseWhenHidden:Boolean = true;
  851.    
  852.     [Inspectable(category="General", defaultValue="true")]
  853.    
  854.     /**
  855.      *  Controls whether the video continues to play when it is
  856.      *  "hidden".  The video is "hidden" when either <code>visible</code>
  857.      *  is set to <code>false</code> on it or one of its ancestors,  
  858.      *  or when the video is taken off
  859.      *  of the display list.  If set to <code>true</code>, the video
  860.      *  pauses playback until the video is visible again.  If set to
  861.      *  <code>false</code> the video continues to play when it is hidden.
  862.      *
  863.      *  <p>If the video is disabled (or one of the video's parents are
  864.      *  disabled), the video pauses as well, but when it is re-enabled,
  865.      *  the video does not play again.  This behavior is not controlled through
  866.      *  <code>pauseWhenHidden</code>; it is defined in the VideoDisplay component.</p>
  867.      *
  868.      *  @default true
  869.      *  
  870.      *  @langversion 3.0
  871.      *  @playerversion Flash 10
  872.      *  @playerversion AIR 1.5
  873.      *  @productversion Flex 4
  874.      */
  875.     public function get pauseWhenHidden():Boolean
  876.     {
  877.         return _pauseWhenHidden;
  878.     }
  879.    
  880.     /**
  881.      *  @private
  882.      */
  883.     public function set pauseWhenHidden(value:Boolean):void
  884.     {
  885.         if (_pauseWhenHidden == value)
  886.             return;
  887.        
  888.         _pauseWhenHidden = value;
  889.        
  890.         if (_pauseWhenHidden)
  891.         {
  892.             addVisibilityListeners();
  893.             computeEffectiveVisibilityAndEnabled();
  894.         }
  895.         else
  896.         {
  897.             removeVisibilityListeners();
  898.         }
  899.        
  900.         // call changePlayback().  If we're invisible or off the stage,
  901.         // setting this to true can pause the video.  However, setting it
  902.         // to false should have no immediate impact.
  903.         changePlayback(value, false);
  904.     }
  905.    
  906.     //----------------------------------
  907.     //  playing
  908.     //----------------------------------
  909.    
  910.     [Inspectable(category="General")]
  911.     [Bindable("mediaPlayerStateChange")]
  912.    
  913.     /**
  914.      *  Contains <code>true</code> if the video is playing or is attempting to play.
  915.      *  
  916.      *  <p>The video may not be currently playing, as it may be seeking
  917.      *  or buffering, but the video is attempting to play.</p>
  918.      *
  919.      *  @see #play()
  920.      *  @see #pause()
  921.      *  @see #stop()
  922.      *  @see #autoPlay
  923.      *  
  924.      *  @langversion 3.0
  925.      *  @playerversion Flash 10
  926.      *  @playerversion AIR 1.5
  927.      *  @productversion Flex 4
  928.      */
  929.     public function get playing():Boolean
  930.     {
  931.         return videoPlayer.playing;
  932.     }
  933.    
  934.     //----------------------------------
  935.     //  scaleMode
  936.     //----------------------------------
  937.    
  938.     /**
  939.      *  @private
  940.      */
  941.     private var _scaleMode:String = ScaleMode.LETTERBOX;
  942.    
  943.     [Inspectable(Category="General", enumeration="none,stretch,letterbox,zoom", defaultValue="letterbox")]
  944.    
  945.     /**
  946.      *  The <code>scaleMode</code> property describes different ways of
  947.      *  sizing the video content.  
  948.      *  You can set <code>scaleMode</code> to
  949.      *  <code>"none"</code>, <code>"stretch"</code>,
  950.      *  <code>"letterbox"</code>, or <code>"zoom"</code>.
  951.      *
  952.      *  <p>If no width, height, or constraints are specified on the component,
  953.      *  this property has no effect.</p>
  954.      *
  955.      *  @default "letterbox"
  956.      *
  957.      *  @see org.osmf.display.ScaleMode
  958.      *  
  959.      *  @langversion 3.0
  960.      *  @playerversion Flash 10
  961.      *  @playerversion AIR 1.5
  962.      *  @productversion Flex 4
  963.      */
  964.     public function get scaleMode():String
  965.     {
  966.         return _scaleMode;
  967.     }
  968.    
  969.     /**
  970.      *  @private
  971.      */
  972.     public function set scaleMode(value:String):void
  973.     {
  974.         if (scaleMode == value)
  975.             return;
  976.        
  977.         switch(value)
  978.         {
  979.             case ScaleMode.NONE:
  980.                 _scaleMode = ScaleMode.NONE;
  981.                 break;
  982.             case ScaleMode.STRETCH:
  983.                 _scaleMode = ScaleMode.STRETCH;
  984.                 break;
  985.             case ScaleMode.LETTERBOX:
  986.                 _scaleMode = ScaleMode.LETTERBOX;
  987.                 break;
  988.             case ScaleMode.ZOOM:
  989.                 _scaleMode = ScaleMode.ZOOM;
  990.                 break;
  991.             default:
  992.                 _scaleMode = ScaleMode.LETTERBOX;
  993.                 break;
  994.         }
  995.        
  996.         // set scaleMode on the videoElement object
  997.         if (videoPlayer.media)
  998.         {
  999.             var layout:LayoutMetadata = videoPlayer.media.
  1000.                                 getMetadata(LayoutMetadata.LAYOUT_NAMESPACE) as LayoutMetadata;
  1001.             if (layout)
  1002.                 layout.scaleMode = _scaleMode;
  1003.         }
  1004.        
  1005.         invalidateSize();
  1006.         invalidateDisplayList();
  1007.     }
  1008.    
  1009.     //----------------------------------
  1010.     //  source
  1011.     //----------------------------------
  1012.    
  1013.     private var _source:Object;
  1014.     private var sourceChanged:Boolean;
  1015.        
  1016.     [Inspectable(category="General", defaultValue="null")]
  1017.     [Bindable("sourceChanged")]
  1018.    
  1019.     /**
  1020.      *  The video source.
  1021.      *
  1022.      *  <p>For progressive download, the source is just a path or URL pointing
  1023.      *  to the video file to play.</p>
  1024.      *
  1025.      *  <p>For streaming (recorded streaming, live streaming,
  1026.      *  or multi-bitrate streaming), the source property is a
  1027.      *  DynamicStreamingVideoSource object.  If you just want to play
  1028.      *  a recorded or live streaming video with no multi-bitrate support,
  1029.      *  you can just pass in a String URL pointing to the video
  1030.      *  stream.  However, if you do this, the streamType is assumed to be "any,"
  1031.      *  and you don't have as much control over the streaming as you would if
  1032.      *  you used the DynamicStreamingVideoSource object.</p>
  1033.      *
  1034.      *  <p>Note: Setting the source on a MediaPlayerStateChangeEvent.LOADING or a
  1035.      *  MediaPlayerStateChangeEvent.READY is not recommended if the source was
  1036.      *  previously set.  This could cause an infinite loop or an RTE.  
  1037.      *  If you must do an operation like that, wait an additional frame to
  1038.      *  set the source.</p>
  1039.      *
  1040.      *  @see spark.components.mediaClasses.DynamicStreamingVideoSource
  1041.      *  
  1042.      *  @langversion 3.0
  1043.      *  @playerversion Flash 10
  1044.      *  @playerversion AIR 1.5
  1045.      *  @productversion Flex 4
  1046.      */
  1047.     public function get source():Object
  1048.     {
  1049.         return _source;
  1050.     }
  1051.    
  1052.     /**
  1053.      * @private (setter)
  1054.      */
  1055.     public function set source(value:Object):void
  1056.     {
  1057.         _source = value;
  1058.        
  1059.         // if we haven't initialized, let's wait to set up the
  1060.         // source in commitProperties() as it is dependent on other
  1061.         // properties, like autoPlay and enabled, and those may not
  1062.         // be set yet, especially if they are set via MXML.
  1063.         // Otherwise, if we have initialized, let's just set up the
  1064.         // source immediately.  This way people can change the source
  1065.         // and immediately call methods like seek().
  1066.         if (!initializedOnce)
  1067.         {
  1068.             sourceChanged = true;
  1069.             invalidateProperties();
  1070.         }
  1071.         else
  1072.         {
  1073.             setUpSource();
  1074.         }
  1075.        
  1076.         dispatchEvent(new Event("sourceChanged"));
  1077.     }
  1078.    
  1079.     //----------------------------------
  1080.     //  thumbnailSource
  1081.     //----------------------------------
  1082.    
  1083.     /**
  1084.      *  @private
  1085.      */
  1086.     private var _thumbnailSource:Object;
  1087.    
  1088.     /**
  1089.      *  @private
  1090.      *  Group that holds the BitmapImage for the thumbnail
  1091.      */
  1092.     private var thumbnailGroup:Group;
  1093.    
  1094.     /**
  1095.      *  @private
  1096.      *  BitmapImage for the thumbnail
  1097.      */
  1098.     private var thumbnailBitmapImage:BitmapImage;
  1099.    
  1100.     [Inspectable(Category="General")]
  1101.    
  1102.     /**
  1103.      *  @private
  1104.      *  Thumbnail source is an internal property used to replace the video with a thumbnail.
  1105.      *  This is for places where we just want to load in a placeholder object for the video
  1106.      *  and don't want to incur the extra load-time or memory of loading up the video.
  1107.      *
  1108.      *  <p>Thumbnail source can take any valid source that can be passed in to
  1109.      *  <code>spark.primitivies.BitmapImage#source</code>.</p>
  1110.      *  
  1111.      *  @langversion 3.0
  1112.      *  @playerversion Flash 10
  1113.      *  @playerversion AIR 1.5
  1114.      *  @productversion Flex 4
  1115.      */
  1116.     mx_internal function get thumbnailSource():Object
  1117.     {
  1118.         return _thumbnailSource;
  1119.     }
  1120.    
  1121.     /**
  1122.      *  @private
  1123.      */
  1124.     mx_internal function set thumbnailSource(value:Object):void
  1125.     {
  1126.         if (_thumbnailSource == value)
  1127.             return;
  1128.        
  1129.         _thumbnailSource = value;
  1130.        
  1131.         // if we haven't initialized, let's wait to set up the
  1132.         // source in commitProperties() as it is dependent on other
  1133.         // properties, like autoPlay and enabled, and those may not
  1134.         // be set yet, especially if they are set via MXML.
  1135.         // Otherwise, if we have initialized, let's just set up the
  1136.         // source immediately.  This way people can change the source
  1137.         // and immediately call methods like seek().
  1138.         if (!initializedOnce)
  1139.         {
  1140.             sourceChanged = true;
  1141.             invalidateProperties();
  1142.         }
  1143.         else
  1144.         {
  1145.             setUpThumbnailSource();
  1146.         }
  1147.     }
  1148.    
  1149.     /**
  1150.      *  @private
  1151.      *  Sets up the thumbnail source for use.
  1152.      */
  1153.     private function setUpThumbnailSource():void
  1154.     {
  1155.         if (thumbnailSource)
  1156.         {            
  1157.             // create thumbnail group if there isn't one
  1158.             if (!thumbnailGroup)
  1159.             {
  1160.                 thumbnailBitmapImage = new BitmapImage();
  1161.                 thumbnailBitmapImage.includeInLayout = false;
  1162.                
  1163.                 thumbnailGroup = new Group();
  1164.                 // add thumbnailGroup to the display list first in case
  1165.                 // bitmap needs to check its layoutDirection.
  1166.                 addChild(thumbnailGroup);
  1167.                 thumbnailGroup.clipAndEnableScrolling = true;
  1168.                 thumbnailGroup.addElement(thumbnailBitmapImage);
  1169.             }
  1170.            
  1171.             // if thumbnailGroup isn't on the display list, then add it.
  1172.             if (!this.contains(thumbnailGroup))
  1173.                 addChild(thumbnailGroup);
  1174.            
  1175.             thumbnailBitmapImage.source = thumbnailSource;
  1176.             invalidateSize();
  1177.             invalidateDisplayList();
  1178.         }
  1179.         else
  1180.         {
  1181.             if (thumbnailGroup)
  1182.             {
  1183.                 // null out the source and remove the thumbnail group
  1184.                 if (thumbnailBitmapImage)
  1185.                     thumbnailBitmapImage.source = null;
  1186.                 if (this.contains(thumbnailGroup))
  1187.                     removeChild(thumbnailGroup);
  1188.                 invalidateSize();
  1189.             }
  1190.         }
  1191.     }
  1192.    
  1193.     //----------------------------------
  1194.     //  videoObject
  1195.     //----------------------------------
  1196.    
  1197.     [Inspectable(category="General", defaultValue="null")]
  1198.    
  1199.     /**
  1200.      *  The underlying flash player <code>flash.media.Video</code> object.
  1201.      *
  1202.      *  <p>If the source is <code>null</code>, then there may be no
  1203.      *  underlying <code>flash.media.Video object</code> yet.  In that
  1204.      *  case, <code>videoObject</code> returns <code>null</code>.</p>
  1205.      *
  1206.      *  @default null
  1207.      *  
  1208.      *  @langversion 3.0
  1209.      *  @playerversion Flash 10
  1210.      *  @playerversion AIR 1.5
  1211.      *  @productversion Flex 4
  1212.      */
  1213.     public function get videoObject():Video
  1214.     {
  1215.         return videoPlayer.displayObject as Video;
  1216.     }
  1217.    
  1218.     //----------------------------------
  1219.     //  volume
  1220.     //----------------------------------
  1221.    
  1222.     [Inspectable(category="General", defaultValue="1.0", minValue="0.0", maxValue="1.0")]
  1223.     [Bindable("volumeChanged")]
  1224.    
  1225.     /**
  1226.      *  The volume level, specified as a value between 0 and 1.
  1227.      *
  1228.      *  @default 1
  1229.      *  
  1230.      *  @langversion 3.0
  1231.      *  @playerversion Flash 10
  1232.      *  @playerversion AIR 1.5
  1233.      *  @productversion Flex 4
  1234.      */
  1235.     public function get volume():Number
  1236.     {
  1237.         return videoPlayer.volume;
  1238.     }
  1239.    
  1240.     /**
  1241.      *  @private
  1242.      */
  1243.     public function set volume(value:Number):void
  1244.     {
  1245.         if (volume == value)
  1246.             return;
  1247.        
  1248.         videoPlayer.volume = value;
  1249.     }
  1250.    
  1251.     //--------------------------------------------------------------------------
  1252.     //
  1253.     //  Overridden methods
  1254.     //
  1255.     //--------------------------------------------------------------------------
  1256.    
  1257.     /**
  1258.      *  @private
  1259.      */
  1260.     override protected function commitProperties():void
  1261.     {
  1262.         super.commitProperties();
  1263.        
  1264.         initializedOnce = true;
  1265.        
  1266.         if (effectiveVisibilityChanged || effectiveEnabledChanged)
  1267.         {
  1268.             // if either visibility of enabled changed, re-compute them here
  1269.             computeEffectiveVisibilityAndEnabled();
  1270.            
  1271.             // if visibility changed and we care about it, we can
  1272.             // cause a play or a pause depending on our visibility
  1273.             var causePause:Boolean = false;
  1274.             var causePlay:Boolean = false;
  1275.             if (effectiveVisibilityChanged && pauseWhenHidden)
  1276.             {
  1277.                 causePause = !effectiveVisibility;
  1278.                 causePlay = effectiveVisibility;
  1279.             }
  1280.            
  1281.             // if enabled changed, we can only cause a pause.  
  1282.             // Re-enabling a component doesn't cause a play.
  1283.             if (effectiveEnabledChanged)
  1284.             {
  1285.                 if (!effectiveEnabled)
  1286.                     causePause = true;
  1287.             }
  1288.            
  1289.             changePlayback(causePause, causePlay);
  1290.            
  1291.             effectiveVisibilityChanged = false;
  1292.             effectiveEnabledChanged = false;
  1293.         }
  1294.        
  1295.         if (sourceChanged)
  1296.         {
  1297.             sourceChanged = false;
  1298.            
  1299.             if (thumbnailSource)
  1300.                 setUpThumbnailSource();
  1301.             else
  1302.                 setUpSource();
  1303.         }
  1304.     }
  1305.    
  1306.     /**
  1307.      *  @private
  1308.      */
  1309.     override protected function measure() : void
  1310.     {
  1311.         super.measure();
  1312.        
  1313.         var intrinsicWidth:Number;
  1314.         var intrinsicHeight:Number;
  1315.        
  1316.         // if showing the thumbnail, just use the thumbnail's size
  1317.         if (thumbnailSource && thumbnailGroup)
  1318.         {
  1319.             intrinsicWidth = thumbnailBitmapImage.getPreferredBoundsWidth();
  1320.             intrinsicHeight = thumbnailBitmapImage.getPreferredBoundsHeight();
  1321.         }
  1322.         else
  1323.         {
  1324.             // If there is no media the width/height will be NaN.
  1325.             // Convert it to zero for our purposes.
  1326.             intrinsicWidth = videoPlayer.mediaWidth;
  1327.             if (isNaN(intrinsicWidth))
  1328.                 intrinsicWidth = 0;
  1329.  
  1330.             intrinsicHeight = videoPlayer.mediaHeight;
  1331.             if (isNaN(intrinsicHeight))
  1332.                 intrinsicHeight = 0;
  1333.         }
  1334.  
  1335.         measuredWidth = intrinsicWidth;
  1336.         measuredHeight = intrinsicHeight;
  1337.        
  1338.         // Determine whether 'width' and 'height' have been set.
  1339.         var bExplicitWidth:Boolean = !isNaN(explicitWidth);
  1340.         var bExplicitHeight:Boolean = !isNaN(explicitHeight);
  1341.  
  1342.         // If only one has been set, calculate the other based on aspect ratio.
  1343.         if (bExplicitWidth && !bExplicitHeight && intrinsicWidth > 0)
  1344.             measuredHeight = explicitWidth * intrinsicHeight / intrinsicWidth;
  1345.         else if (bExplicitHeight && !bExplicitWidth && intrinsicHeight > 0)
  1346.             measuredWidth = explicitHeight * intrinsicWidth / intrinsicHeight;
  1347.     }
  1348.    
  1349.     /**
  1350.      *  @private
  1351.      */
  1352.     override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number) : void
  1353.     {
  1354.         super.updateDisplayList(unscaledWidth, unscaledHeight);
  1355.        
  1356.         // if just showing the thumbnail, push this width/height in to the thumbnail
  1357.         // otherwise we'll push it in to the video object
  1358.         if (thumbnailSource && thumbnailGroup)
  1359.         {
  1360.             // get what the size of our image should be
  1361.             var newSize:Point = getScaledSize(scaleMode, unscaledWidth, unscaledHeight,
  1362.                 thumbnailBitmapImage.getPreferredBoundsWidth(), thumbnailBitmapImage.getPreferredBoundsHeight());
  1363.            
  1364.             // set the thumbnailGroup to be the size of the component.
  1365.             // set the bitmap image to be the size it should be according to OSMF
  1366.             thumbnailGroup.setLayoutBoundsSize(unscaledWidth, unscaledHeight);
  1367.             thumbnailBitmapImage.setLayoutBoundsSize(newSize.x, newSize.y);
  1368.            
  1369.             // center the thumnail image within the thumbnail group.
  1370.             // if it's too big to fit, the thumbnail group will crop it
  1371.             thumbnailBitmapImage.x = (unscaledWidth - newSize.x)/2;
  1372.             thumbnailBitmapImage.y = (unscaledHeight - newSize.y)/2;
  1373.            
  1374.             return;
  1375.         }
  1376.        
  1377.         videoContainer.width = Math.floor(unscaledWidth);
  1378.         videoContainer.height = Math.floor(unscaledHeight);
  1379.  
  1380.         // need to validate the gateway immediately--otherwise we may run out of synch
  1381.         // as they may wait a frame by default before validating (see SDK-24880)
  1382.         videoContainer.validateNow();
  1383.     }
  1384.    
  1385.     //--------------------------------------------------------------------------
  1386.     //
  1387.     //  Methods
  1388.     //
  1389.     //--------------------------------------------------------------------------
  1390.    
  1391.     /**
  1392.      *  Pauses playback without moving the playhead.
  1393.      *  If playback is already is paused or is stopped, this method has no
  1394.      *  effect.  
  1395.      *
  1396.      *  <p>To start playback again, call the <code>play()</code> method.</p>
  1397.      *  
  1398.      *  @langversion 3.0
  1399.      *  @playerversion Flash 10
  1400.      *  @playerversion AIR 1.5
  1401.      *  @productversion Flex 4
  1402.      */
  1403.     public function pause():void
  1404.     {
  1405.         // check to see if we can call methods on the video player object yet
  1406.         if (!videoPlayerResponsive())
  1407.             return;
  1408.        
  1409.         playTheVideoOnVisible = false;
  1410.        
  1411.         // if we're loading up, then we will pause automatically, so let's
  1412.         // not interrupt this process
  1413.         // if inLoadingState1 && pausable, then let loading state handle it
  1414.         // if inLoadingState1 && !pausable, then let the loading state handle it
  1415.         // if !inLoadingState1 && pausable, then just pause
  1416.         // if !inLoadingState1 && !pausable, then load (if needed to show first frame)
  1417.         if (!inLoadingState1 && videoPlayer.canPause)
  1418.             videoPlayer.pause();
  1419.         else if (!videoPlayer.canPause && autoDisplayFirstFrame)
  1420.             load();
  1421.     }
  1422.    
  1423.     /**
  1424.      *  Causes the video to play.  Can be called while the video is
  1425.      *  paused, stopped, or while the video is already playing.
  1426.      *
  1427.      *  @langversion 3.0
  1428.      *  @playerversion Flash 10
  1429.      *  @playerversion AIR 1.5
  1430.      *  @productversion Flex 4
  1431.      */
  1432.     public function play():void
  1433.     {
  1434.         // check to see if we can call methods on the video player object yet
  1435.         if (!videoPlayerResponsive())
  1436.             return;
  1437.        
  1438.         playTheVideoOnVisible = false;
  1439.        
  1440.         // if we're loading up, use a special method to cancel the load
  1441.         // and to start playing again.  Otherwise, go ahead and play
  1442.         if (inLoadingState1)
  1443.             cancelLoadAndPlay();
  1444.         else if (videoPlayer.canPlay)
  1445.             videoPlayer.play();
  1446.     }
  1447.    
  1448.     /**
  1449.      *  Seeks to given time in the video. If the video is playing,
  1450.      *  continue playing from that point. If the video is paused, seek to
  1451.      *  that point and remain paused. If the video is stopped, seek to
  1452.      *  that point and enters paused state.
  1453.      *  This method has no effect with live video streams.
  1454.      *
  1455.      *  <p>If time is less than 0 or NaN, throws exception. If time
  1456.      *  is past the end of the stream, or past the amount of file
  1457.      *  downloaded so far, then attempts to seek and, if it fails, it then recovers.</p>
  1458.      *
  1459.      *  <p>The <code>currentTime</code> property might not have the expected value
  1460.      *  immediately after you call <code>seek()</code>.
  1461.      *  For a progressive download,
  1462.      *  you can seek only to a keyframe; therefore, a seek takes you to the
  1463.      *  time of the first keyframe after the specified time.</p>
  1464.      *  
  1465.      *  <p><strong>Note</strong>: When streaming, a seek always goes to the precise specified
  1466.      *  time even if the source FLV file doesn't have a keyframe there.</p>
  1467.      *
  1468.      *  <p>Seeking is asynchronous, so if you call the <code>seek()</code> method,
  1469.      *  <code>currentTime</code> does not update immediately. </p>
  1470.      *
  1471.      *  @param time The seek time, in seconds.
  1472.      *  
  1473.      *  @langversion 3.0
  1474.      *  @playerversion Flash 10
  1475.      *  @playerversion AIR 1.5
  1476.      *  @productversion Flex 4
  1477.      */
  1478.     public function seek(time:Number):void
  1479.     {
  1480.         // check to see if we can call methods on the video player object yet
  1481.         if (!videoPlayerResponsive())
  1482.             return;
  1483.        
  1484.         // TODO (rfrishbe): could handle what to do if this gets called when loading() better.
  1485.         // Need to store where we want to seek to.
  1486.         if (videoPlayer.canSeek)
  1487.             videoPlayer.seek(time);
  1488.     }
  1489.    
  1490.     /**
  1491.      *  Stops video playback.  If <code>autoRewind</code> is set to
  1492.      *  <code>true</code>, rewinds to first frame.  If video is already
  1493.      *  stopped, has no effect.  To start playback again, call
  1494.      *  <code>play()</code>.
  1495.      *
  1496.      *  @see #autoRewind
  1497.      *  @see #play()
  1498.      *  
  1499.      *  @langversion 3.0
  1500.      *  @playerversion Flash 10
  1501.      *  @playerversion AIR 1.5
  1502.      *  @productversion Flex 4
  1503.      */
  1504.     public function stop():void
  1505.     {
  1506.         // check to see if we can call methods on the video player object yet
  1507.         if (!videoPlayerResponsive())
  1508.             return;
  1509.        
  1510.         playTheVideoOnVisible = false;
  1511.        
  1512.         // if we're loading up, then we will stop automatically, so let's
  1513.         // not interrupt this process
  1514.         // if inLoadingState1 && pausable, then let loading state handle it
  1515.         // if inLoadingState1 && !pausable, then let the loading state handle it
  1516.         // if !inLoadingState1 && pausable, then just pause
  1517.         // if !inLoadingState1 && !pausable, then load (if needed to show first frame)
  1518.         if (!inLoadingState1 && videoPlayer.canPause)
  1519.             videoPlayer.stop();
  1520.         else if (!videoPlayer.canPause && autoDisplayFirstFrame)
  1521.             load();
  1522.     }
  1523.    
  1524.     //--------------------------------------------------------------------------
  1525.     //
  1526.     //  Private Methods
  1527.     //
  1528.     //--------------------------------------------------------------------------
  1529.    
  1530.     /**
  1531.      *  @private
  1532.      *  If the video player is responsive, then methods can be called on the underlying
  1533.      *  video player.
  1534.      */
  1535.     private function videoPlayerResponsive():Boolean
  1536.     {
  1537.         // can't call any methods before we've initialized
  1538.         if (!initializedOnce)
  1539.             return false;
  1540.        
  1541.         // if displaying a thumbnail, no methods can be called b/c there's no video
  1542.         // loaded up
  1543.         if (thumbnailSource)
  1544.             return false;
  1545.        
  1546.         // if the video player's in a bad state, we can't do anything
  1547.         if (videoPlayer.state == MediaPlayerState.PLAYBACK_ERROR ||
  1548.             videoPlayer.state == MediaPlayerState.UNINITIALIZED ||
  1549.             videoPlayer.state == MediaPlayerState.LOADING)
  1550.         {
  1551.             return false;
  1552.         }
  1553.        
  1554.         // if no source, return false as well
  1555.         if (!source)
  1556.             return false;
  1557.        
  1558.         // otherwise, we are in a good state and have a source, so let's go
  1559.         return true;
  1560.     }
  1561.    
  1562.     /**
  1563.      *  @private
  1564.      */
  1565.     private function createUnderlyingVideoPlayer():void
  1566.     {
  1567.         // create new video player
  1568.         videoPlayer = new MediaPlayer();
  1569.         videoContainer = new MediaContainer();
  1570.         videoContainer.clipChildren = true;
  1571.        
  1572.         mediaFactory = new DefaultMediaFactory();
  1573.        
  1574.         // remove unsupport media types
  1575.         var unsupportedMediaTypes:Array = ["org.osmf.elements.video.dvr.dvrcast",
  1576.                                            "org.osmf.elements.image",
  1577.                                            "org.osmf.elements.swf"];
  1578.        
  1579.         for each (var mediaType:String in unsupportedMediaTypes)
  1580.         {
  1581.             var mediaFactoryItem:MediaFactoryItem = mediaFactory.getItemById(mediaType);
  1582.             if (mediaFactoryItem)
  1583.                 mediaFactory.removeItem(mediaFactoryItem);
  1584.         }
  1585.  
  1586.         // internal events
  1587.         videoPlayer.addEventListener(DisplayObjectEvent.MEDIA_SIZE_CHANGE, videoPlayer_mediaSizeChangeHandler);
  1588.         videoPlayer.addEventListener(AudioEvent.VOLUME_CHANGE, videoPlayer_volumeChangeHandler);
  1589.         videoPlayer.addEventListener(AudioEvent.MUTED_CHANGE, videoPlayer_mutedChangeHandler);
  1590.        
  1591.         // public events
  1592.         videoPlayer.addEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, videoPlayer_mediaPlayerStateChangeHandler);
  1593.         videoPlayer.addEventListener(TimeEvent.CURRENT_TIME_CHANGE, dispatchEvent);
  1594.         videoPlayer.addEventListener(LoadEvent.BYTES_LOADED_CHANGE, dispatchEvent);
  1595.         videoPlayer.addEventListener(TimeEvent.DURATION_CHANGE, videoPlayer_durationChangeHandler);
  1596.         videoPlayer.addEventListener(TimeEvent.COMPLETE, dispatchEvent);
  1597.        
  1598.         addChild(videoContainer);
  1599.     }
  1600.    
  1601.     /**
  1602.      *  @private
  1603.      *  Sets up the source for use.
  1604.      */
  1605.     private function setUpSource():void
  1606.     {
  1607.         // clean up any listeners from the old source, especially if we
  1608.         // are in the processing of loading that video file up
  1609.         cleanUpSource()
  1610.        
  1611.         // if was playing a previous video, let's remove it now
  1612.         if (videoPlayer.media && videoContainer.containsMediaElement(videoPlayer.media))
  1613.         {
  1614.             videoContainer.removeMediaElement(videoPlayer.media);
  1615.         }
  1616.        
  1617.         var videoElement:org.osmf.media.MediaElement = null;
  1618.        
  1619.         // check for 4 cases: streaming video, progressive download,
  1620.         // an IMediaResource, or a VideoElement.  
  1621.         // The latter 2 are undocumented but allowed for flexibility until we
  1622.         // can support OSMF better after they ship OSMF 1.0.  At that point, support
  1623.         // for a source as an IMediaResource or a VideoElement may be removed.
  1624.         if (source is DynamicStreamingVideoSource)
  1625.         {
  1626.             // the streaming video case.
  1627.             // build up a DynamicStreamingResource to pass in to OSMF
  1628.             var streamingSource:DynamicStreamingVideoSource = source as DynamicStreamingVideoSource;
  1629.             var dsr:DynamicStreamingResource;
  1630.            
  1631.             // check for two cases for host: String and URL.
  1632.             // Technically, we only support URL, but we secretly allow
  1633.             // them to send in an OSMF URL or FMSURL here to help resolve any ambiguity
  1634.             // around serverName vs. streamName.
  1635.             if (streamingSource.host is String)
  1636.             {
  1637.                 dsr = new DynamicStreamingResource(streamingSource.host as String,
  1638.                                                    streamingSource.streamType);
  1639.             }
  1640.             else if (streamingSource.host is URL)
  1641.             {
  1642.                 dsr = new DynamicStreamingResource(URL(streamingSource.host).host,
  1643.                                                    streamingSource.streamType);
  1644.             }      
  1645.            
  1646.             if (dsr)
  1647.             {
  1648.                 var n:int = streamingSource.streamItems.length;
  1649.                 var item:DynamicStreamingVideoItem;
  1650.                 var dsi:DynamicStreamingItem;
  1651.                 var streamItems:Vector.<DynamicStreamingItem> = new Vector.<DynamicStreamingItem>(n);
  1652.                
  1653.                 for (var i:int = 0; i < n; i++)
  1654.                 {
  1655.                     item = streamingSource.streamItems[i];
  1656.                     dsi = new DynamicStreamingItem(item.streamName, item.bitrate);
  1657.                     streamItems[i] = dsi;
  1658.                 }
  1659.                 dsr.streamItems = streamItems;
  1660.                
  1661.                 dsr.initialIndex = streamingSource.initialIndex;
  1662.                
  1663.                 // add video type metadata so if the URL is ambiguous, OSMF will
  1664.                 // know what type of file we're trying to connect to
  1665.                 dsr.mediaType = MediaType.VIDEO;
  1666.                
  1667.                 videoElement = new org.osmf.elements.VideoElement(dsr, new RTMPDynamicStreamingNetLoader());
  1668.             }
  1669.         }
  1670.         else if (source is String && source != "")
  1671.         {
  1672.             var urlResource:URLResource = new URLResource(source as String);
  1673.             videoElement = mediaFactory.createMediaElement(urlResource);
  1674.            
  1675.             // If the url could not be resolved to a media element then try
  1676.             // telling osmf the media is a video and try again.
  1677.             // We do not specify the media type as video the first time,
  1678.             // so we can have the chance to play audio.
  1679.             if (videoElement == null)
  1680.             {
  1681.                 urlResource.mediaType = MediaType.VIDEO;
  1682.                 videoElement = mediaFactory.createMediaElement(urlResource);                
  1683.             }
  1684.         }
  1685.         else if (source is MediaResourceBase)
  1686.         {
  1687.             videoElement = mediaFactory.createMediaElement(MediaResourceBase(source));
  1688.         }
  1689.         else if (source is org.osmf.elements.VideoElement)
  1690.         {
  1691.             videoElement = source as org.osmf.elements.VideoElement;
  1692.         }
  1693.        
  1694.         // reset the visibilityPausedTheVideo flag
  1695.         playTheVideoOnVisible = true;
  1696.         // set up videoPlayer.autoPlay based on whether this.autoPlay is
  1697.         // set and whether we are visible and the other typical conditions.
  1698.         changePlayback(false, false);
  1699.        
  1700.         // if we're not going to autoPlay (or couldn't autoPlay because
  1701.         // we're hidden or for some other reason), but we need to seek
  1702.         // to the first frame, then we have to do this on our own
  1703.         // by using our load() method.
  1704.         if (videoElement && (!autoPlay || !shouldBePlaying) && autoDisplayFirstFrame)
  1705.             load();
  1706.        
  1707.         // set videoPlayer's element to the newly constructed VideoElement
  1708.         // set the newly constructed videoElement's gateway to be the videoGateway
  1709.         videoPlayer.media = videoElement;
  1710.        
  1711.         if (videoElement)
  1712.         {
  1713.             // If we are loading a video, make sure the timers are restored in case
  1714.             // they had been disabled. The timers will be disabled again if we are
  1715.             // only loading the first frame.
  1716.             if (!isNaN(oldCurrentTimeUpdateInterval))
  1717.             {
  1718.                 videoPlayer.currentTimeUpdateInterval = oldCurrentTimeUpdateInterval;
  1719.                 videoPlayer.bytesLoadedUpdateInterval = oldBytesLoadedUpdateInterval;
  1720.             }
  1721.  
  1722.             if (videoElement.getMetadata(LayoutMetadata.LAYOUT_NAMESPACE) == null)
  1723.             {
  1724.                 var layout:LayoutMetadata = new LayoutMetadata();
  1725.                 layout.scaleMode = scaleMode;
  1726.                 layout.verticalAlign = VerticalAlign.MIDDLE;
  1727.                 layout.horizontalAlign = HorizontalAlign.CENTER;
  1728.                 layout.percentWidth = 100;
  1729.                 layout.percentHeight = 100;
  1730.                 videoElement.addMetadata(LayoutMetadata.LAYOUT_NAMESPACE, layout);
  1731.             }              
  1732.  
  1733.             if (videoElement && !videoContainer.containsMediaElement(videoElement) )
  1734.             {
  1735.                 videoContainer.addMediaElement(videoElement);
  1736.             }              
  1737.         }
  1738.         else
  1739.         {
  1740.             // if our source is null, let's invalidateSize() here.
  1741.             // if it's a bad source, we'll get a playbackError and invalidate
  1742.             // the size down there.  If it's a good source, we'll get a
  1743.             // dimensionChange event and invalidate the size in there.
  1744.             invalidateSize();
  1745.         }
  1746.     }
  1747.    
  1748.     /**
  1749.      *  @private
  1750.      *  Our own internal load() method to handle the case
  1751.      *  where autoPlay = false and autoDisplayFirstFrame = true
  1752.      *  so that we can load up the video, figure out its size,
  1753.      *  and show the first frame
  1754.      */
  1755.     private function load():void
  1756.     {
  1757.         inLoadingState1 = true;
  1758.        
  1759.         // wait until we can mute, play(), pause(), and seek() before doing anything.
  1760.         // We should be able to do all of these operations on the READY state change event.
  1761.         videoPlayer.addEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, videoPlayer_mediaPlayerStateChangeHandlerForLoading);
  1762.     }
  1763.    
  1764.     //--------------------------------------------------------------------------
  1765.     //
  1766.     //  pauseWhenHidden: Event handlers and Private Methods
  1767.     //
  1768.     //--------------------------------------------------------------------------
  1769.    
  1770.     /**
  1771.      *  @private
  1772.      *  Whether the video should be playing based on enabled,
  1773.      *  pauseWhenHidden, whether it's on the display list, and its
  1774.      *  effective visibility.
  1775.      */
  1776.     private function get shouldBePlaying():Boolean
  1777.     {
  1778.         // if disabled, return false
  1779.         if (!effectiveEnabled)
  1780.             return false;
  1781.        
  1782.         // if we want to look at visibility, check to
  1783.         // see if we are on the display list and check out
  1784.         // effectiveVisibility (which looks up our parent chain
  1785.         // to make sure us and all of our ancestors are visible)
  1786.         if (pauseWhenHidden)
  1787.         {
  1788.             if (!_isOnDisplayList)
  1789.                 return false;
  1790.            
  1791.             if (!effectiveVisibility)
  1792.                 return false;
  1793.         }
  1794.        
  1795.         return true;
  1796.     }
  1797.    
  1798.     /**
  1799.      *  @private
  1800.      *  This method will pause or play the video by looking at the state of
  1801.      *  the component and determining whether it should play or pause.  This
  1802.      *  method gets called when an important event occurs, such as
  1803.      *  the component being added/removed from the stage, the component's
  1804.      *  effective visibility changing, or when autoPlay is set.  
  1805.      *
  1806.      *  <p>Only certain events are "action events" which can cause the video
  1807.      *  to pause or play immediately.  For example, when autoPlay is set to
  1808.      *  true/false, that shouldn't cause any immediate action, but changePlayback()
  1809.      *  is still called so that autoPlay can be set on the underlying media player.</p>
  1810.      *
  1811.      *  <p>Actions that can pause the video are:
  1812.      *  <ul>
  1813.      *      <li>Changes in effective enablement</li>
  1814.      *      <li>Changes in effective visibility</li>
  1815.      *      <li>Changes in staging (added or removed from display list)</li>
  1816.      *      <li>Setting pauseWhenHidden = true</li>
  1817.      *  </ul></p>
  1818.      *
  1819.      *  <p>Actions that can play the video are:
  1820.      *  <ul>
  1821.      *      <li>Changes in effective visibility</li>
  1822.      *      <li>Changes in staging (added or removed from display list)</li>
  1823.      *  </ul></p>
  1824.      *
  1825.      *  @param causePause Whether this action can cause a currently playing video to pause
  1826.      *  @param causePlay Whether this action can cause a currently paused video to play
  1827.      */
  1828.     private function changePlayback(causePause:Boolean, causePlay:Boolean):void
  1829.     {
  1830.         // if we shouldn't be playing, we pause the video.
  1831.         // if we come back up and should be playing, we will
  1832.         // start playing the video again if the video wasn't paused
  1833.         // by the user or developer and autoPlay is true.      
  1834.         if (shouldBePlaying)
  1835.         {
  1836.             videoPlayer.autoPlay = autoPlay;
  1837.            
  1838.             // only play the video if visibility caused it to pause
  1839.             // (instead of a user or developer calling video.pause()).
  1840.             // Also, only play if autoPlay is true.  Otherwise when
  1841.             // the visibility changes, we won't automatically
  1842.             // play the video
  1843.             if (causePlay && (playTheVideoOnVisible && autoPlay))
  1844.             {
  1845.                 playTheVideoOnVisible = false;
  1846.                
  1847.                 // set autoplay and call play() if the
  1848.                 // source has loaded up and it's playable
  1849.                 if (inLoadingState1)
  1850.                     cancelLoadAndPlay();
  1851.                 else if (videoPlayer.canPlay)
  1852.                     videoPlayer.play();
  1853.             }
  1854.         }
  1855.         else
  1856.         {
  1857.             // there are really three states the video player can
  1858.             // be in with respect to play vs. paused:
  1859.             // 1) playing
  1860.             // 2) paused
  1861.             // 3) loading
  1862.             // Here we are checking if we are playing or loading
  1863.             // and going to play soon (autoPlay = true)
  1864.             if (causePause && (playing || (videoPlayer.state == MediaPlayerState.LOADING && autoPlay)))
  1865.                 playTheVideoOnVisible = true;
  1866.  
  1867.             // always set autoPlay to false here and
  1868.             // if pausable, pause the video
  1869.             videoPlayer.autoPlay = false;
  1870.             if (causePause)
  1871.             {
  1872.                 // if we're loading up, then we will pause automatically, so let's
  1873.                 // not interrupt this process
  1874.                 // if inLoadingState1 && pausable, then let loading state handle it
  1875.                 // if inLoadingState1 && !pausable, then let the loading state handle it
  1876.                 // if !inLoadingState1 && pausable, then just pause
  1877.                 // if !inLoadingState1 && !pausable, then load (if needed to show first frame)
  1878.                 if (!inLoadingState1 && videoPlayer.canPause)
  1879.                     videoPlayer.pause();
  1880.                 else if (!videoPlayer.canPause && autoDisplayFirstFrame)
  1881.                     load();
  1882.             }
  1883.         }
  1884.     }
  1885.    
  1886.     /**
  1887.      *  @private
  1888.      *  Cancels the load, no matter what state it's in, and starts to play().
  1889.      */
  1890.     private function cancelLoadAndPlay():void
  1891.     {
  1892.         if (inLoadingState1)
  1893.         {
  1894.             if (!inLoadingState2)
  1895.             {
  1896.                 // first step
  1897.                
  1898.                 // Don't need to do anything but set inLoadingState1 = false (done down below).
  1899.                 // This is handled in videoPlayer_mediaPlayerStateChangeHandlerForLoading which will still
  1900.                 // be fired and will handle calling videoPlayer.play() without the rest of the loading
  1901.                 // junk because inLoadingState1 = false now
  1902.             }
  1903.             else if (!inLoadingState3)
  1904.             {
  1905.                 // second step
  1906.                 videoPlayer.muted = beforeLoadMuted;
  1907.                
  1908.                 if (videoPlayer.displayObject)
  1909.                     videoPlayer.displayObject.visible = true;
  1910.                
  1911.                 videoPlayer.removeEventListener(TimeEvent.CURRENT_TIME_CHANGE, videoPlayer_currentTimeChangeHandler);
  1912.                 videoPlayer.removeEventListener(MediaPlayerCapabilityChangeEvent.CAN_SEEK_CHANGE, videoPlayer_canSeekChangeHandler);
  1913.             }
  1914.             else
  1915.             {
  1916.                 // third step
  1917.                 videoPlayer.removeEventListener(SeekEvent.SEEKING_CHANGE, videoPlayer_seekChangeHandler);
  1918.                 videoPlayer.muted = beforeLoadMuted;
  1919.                 if (videoPlayer.displayObject)
  1920.                     videoPlayer.displayObject.visible = true;
  1921.                
  1922.                 // wasn't playing
  1923.                 if (videoPlayer.canPlay)
  1924.                     videoPlayer.play();
  1925.             }
  1926.            
  1927.             inLoadingState1 = false;
  1928.             inLoadingState2 = false;
  1929.             inLoadingState3 = false;
  1930.         }
  1931.     }
  1932.    
  1933.     /**
  1934.      *  @private
  1935.      *  Cancels the load, no matter what state it's in.  This is used when changing the source.
  1936.      */
  1937.     private function cleanUpSource():void
  1938.     {
  1939.         // TODO (rfrishbe): very similar to cancelLoadAndPlay(). Should collapse it down.
  1940.        
  1941.         // always remove listener as we could be out of loadState1 but still "loading to play"
  1942.         videoPlayer.removeEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, videoPlayer_mediaPlayerStateChangeHandlerForLoading);
  1943.        
  1944.         if (inLoadingState1)
  1945.         {
  1946.             if (!inLoadingState2)
  1947.             {
  1948.                 // first step
  1949.                
  1950.                 // Just need to remove event listeners as we did above
  1951.             }
  1952.             else if (!inLoadingState3)
  1953.             {
  1954.                 // second step
  1955.                 videoPlayer.muted = beforeLoadMuted;
  1956.                 videoPlayer.displayObject.visible = true;
  1957.                
  1958.                 // going to call pause() now to stop immediately
  1959.                 videoPlayer.pause();
  1960.             }
  1961.             else
  1962.             {
  1963.                 // third step
  1964.                 videoPlayer.removeEventListener(SeekEvent.SEEKING_CHANGE, videoPlayer_seekChangeHandler);
  1965.                 videoPlayer.muted = beforeLoadMuted;
  1966.                 videoPlayer.displayObject.visible = true;
  1967.                
  1968.                 // already called pause(), so don't do anything
  1969.             }
  1970.            
  1971.             inLoadingState1 = false;
  1972.             inLoadingState2 = false;
  1973.             inLoadingState3 = false;
  1974.         }
  1975.     }
  1976.    
  1977.     /**
  1978.      *  @private
  1979.      */
  1980.     private function addedToStageHandler(event:Event):void
  1981.     {
  1982.         _isOnDisplayList = true;
  1983.        
  1984.         // add listeners to current parents to see if their visibility has changed
  1985.         if (pauseWhenHidden)
  1986.             addVisibilityListeners();
  1987.        
  1988.         addEnabledListeners();
  1989.        
  1990.         computeEffectiveVisibilityAndEnabled();
  1991.  
  1992.         // When added to the stage, restore some videoPlayer timers that we had
  1993.         // disabled when we went offstage.
  1994.         if (!isNaN(oldCurrentTimeUpdateInterval))
  1995.         {
  1996.             videoPlayer.currentTimeUpdateInterval = oldCurrentTimeUpdateInterval;
  1997.             videoPlayer.bytesLoadedUpdateInterval = oldBytesLoadedUpdateInterval;
  1998.  
  1999.             oldCurrentTimeUpdateInterval = NaN;
  2000.             oldBytesLoadedUpdateInterval = NaN;
  2001.         }
  2002.        
  2003.         // being added to the display list will not pause the video, but
  2004.         // it may play the video if pauseWhenHidden = true
  2005.         changePlayback(false, pauseWhenHidden);
  2006.     }
  2007.    
  2008.     /**
  2009.      *  @private
  2010.      */
  2011.     private function removedFromStageHandler(event:Event):void
  2012.     {
  2013.         _isOnDisplayList = false;
  2014.        
  2015.         // remove listeners from old parents
  2016.         if (pauseWhenHidden)
  2017.             removeVisibilityListeners();
  2018.        
  2019.         removeEnabledListeners();
  2020.        
  2021.         // Stop the timers associated with these intervals when we go
  2022.         // offscreen so we are not pinned in memory. Save the old
  2023.         // values of the timers so we can restore them when we come
  2024.         // back on stage.
  2025.         if (pauseWhenHidden)
  2026.         {
  2027.             oldCurrentTimeUpdateInterval = videoPlayer.currentTimeUpdateInterval;
  2028.             oldBytesLoadedUpdateInterval = videoPlayer.bytesLoadedUpdateInterval;
  2029.             videoPlayer.currentTimeUpdateInterval = -1;
  2030.             videoPlayer.bytesLoadedUpdateInterval = -1;
  2031.         }
  2032.        
  2033.         // being removed from the display list will pause the video if
  2034.         // pauseWhenHidden = true
  2035.         changePlayback(pauseWhenHidden, false);
  2036.     }
  2037.    
  2038.     /**
  2039.      *  @private
  2040.      *  Add event listeners for SHOW and HIDE on all the ancestors up the parent chain.
  2041.      *  Adding weak event listeners just to be safe.
  2042.      */
  2043.     private function addVisibilityListeners():void
  2044.     {
  2045.         var current:IVisualElement = this;
  2046.         while (current)
  2047.         {
  2048.             // add visibility listeners to the parent
  2049.             current.addEventListener(FlexEvent.HIDE, visibilityChangedHandler, false, 0, true);
  2050.             current.addEventListener(FlexEvent.SHOW, visibilityChangedHandler, false, 0, true);
  2051.            
  2052.             // add listeners to the design layer too
  2053.             if (current.designLayer)
  2054.             {
  2055.                 current.designLayer.addEventListener("layerPropertyChange",
  2056.                     designLayer_layerPropertyChangeHandler, false, 0, true);
  2057.             }
  2058.            
  2059.             current = current.parent as IVisualElement;
  2060.         }
  2061.     }
  2062.    
  2063.     /**
  2064.      *  @private
  2065.      *  Add event listeners for "enabledChanged" event on all ancestors up the parent chain.
  2066.      *  Adding weak event listeners just to be safe.
  2067.      */
  2068.     private function addEnabledListeners():void
  2069.     {
  2070.         var current:IVisualElement = this;
  2071.         while (current)
  2072.         {
  2073.             current.addEventListener("enabledChanged", enabledChangedHandler, false, 0, true);
  2074.             current.addEventListener("enabledChanged", enabledChangedHandler, false, 0, true);
  2075.            
  2076.             current = current.parent as IVisualElement;
  2077.         }
  2078.     }
  2079.    
  2080.     /**
  2081.      *  @private
  2082.      *  Remove event listeners for SHOW and HIDE on all the ancestors up the parent chain.
  2083.      */
  2084.     private function removeVisibilityListeners():void
  2085.     {
  2086.         var current:IVisualElement = this;
  2087.         while (current)
  2088.         {
  2089.             current.removeEventListener(FlexEvent.HIDE, visibilityChangedHandler, false);
  2090.             current.removeEventListener(FlexEvent.SHOW, visibilityChangedHandler, false);
  2091.            
  2092.             if (current.designLayer)
  2093.             {
  2094.                 current.designLayer.removeEventListener("layerPropertyChange",
  2095.                     designLayer_layerPropertyChangeHandler, false);
  2096.             }
  2097.            
  2098.             current = current.parent as IVisualElement;
  2099.         }
  2100.     }
  2101.    
  2102.     /**
  2103.      *  @private
  2104.      *  Remove event listeners for "enabledChanged" event on all ancestors up the parent chain.
  2105.      */
  2106.     private function removeEnabledListeners():void
  2107.     {
  2108.         var current:IVisualElement = this;
  2109.         while (current)
  2110.         {
  2111.             current.removeEventListener("enabledChanged", enabledChangedHandler, false);
  2112.             current.removeEventListener("enabledChanged", enabledChangedHandler, false);
  2113.            
  2114.             current = current.parent as IVisualElement;
  2115.         }
  2116.     }
  2117.    
  2118.     /**
  2119.      *  @private
  2120.      *  Event call back whenever the visibility of us or one of our ancestors
  2121.      *  changes
  2122.      */
  2123.     private function visibilityChangedHandler(event:FlexEvent):void
  2124.     {
  2125.         effectiveVisibilityChanged = true;
  2126.         invalidateProperties();
  2127.     }
  2128.    
  2129.     /**
  2130.      *  @private
  2131.      *  Event call back whenever the visibility of our designLayer or one of our parent's
  2132.      *  designLayers change.
  2133.      */
  2134.     private function designLayer_layerPropertyChangeHandler(event:PropertyChangeEvent):void
  2135.     {
  2136.         if (event.property == "effectiveVisibility")
  2137.         {
  2138.             effectiveVisibilityChanged = true;
  2139.             invalidateProperties();
  2140.         }
  2141.     }
  2142.    
  2143.     /**
  2144.      *  @private
  2145.      *  Event call back whenever the enablement of us or one of our ancestors
  2146.      *  changes
  2147.      */
  2148.     private function enabledChangedHandler(event:Event):void
  2149.     {
  2150.         effectiveEnabledChanged = true;
  2151.         invalidateProperties();
  2152.     }
  2153.    
  2154.     /**
  2155.      *  @private
  2156.      */
  2157.     private function computeEffectiveVisibilityAndEnabled():void
  2158.     {
  2159.         // start out with true visibility and enablement
  2160.         // then loop up parent-chain to see if any of them are false
  2161.         effectiveVisibility = true;
  2162.         effectiveEnabled = true;
  2163.         var current:IVisualElement = this;
  2164.        
  2165.         while (current)
  2166.         {
  2167.             if (!current.visible ||
  2168.                 (current.designLayer && !current.designLayer.effectiveVisibility))
  2169.             {
  2170.                 effectiveVisibility = false;
  2171.                 if (!effectiveEnabled)
  2172.                     break;
  2173.             }
  2174.            
  2175.             if (current is IUIComponent && !IUIComponent(current).enabled)
  2176.             {
  2177.                 effectiveEnabled = false;
  2178.                 if (!effectiveVisibility)
  2179.                     break;
  2180.             }
  2181.            
  2182.             current = current.parent as IVisualElement;
  2183.         }
  2184.     }
  2185.    
  2186.     //--------------------------------------------------------------------------
  2187.     //
  2188.     //  Event handlers
  2189.     //
  2190.     //--------------------------------------------------------------------------
  2191.    
  2192.     /**
  2193.      *  @private
  2194.      */
  2195.     private function videoPlayer_volumeChangeHandler(event:AudioEvent):void
  2196.     {
  2197.         dispatchEvent(new Event("volumeChanged"));
  2198.     }
  2199.    
  2200.     /**
  2201.      *  @private
  2202.      */
  2203.     private function videoPlayer_mutedChangeHandler(event:AudioEvent):void
  2204.     {
  2205.         dispatchEvent(new Event("volumeChanged"));
  2206.     }
  2207.    
  2208.     /**
  2209.      *  @private
  2210.      *  Event handler for mediaPlayerStateChange event.
  2211.      */
  2212.     private function videoPlayer_mediaPlayerStateChangeHandler(event:MediaPlayerStateChangeEvent):void
  2213.     {
  2214.         // if the event change caused us to go in to a state where
  2215.         // nothing is loaded up and we've no chance of getting a
  2216.         // dimensionChangeEvent, then let's invalidate our size here
  2217.         if (event.state == MediaPlayerState.PLAYBACK_ERROR)
  2218.             invalidateSize();
  2219.        
  2220.         // this is a public event, so let's re-dispatch it
  2221.         dispatchEvent(event);
  2222.     }
  2223.    
  2224.     /**
  2225.      *  @private
  2226.      *  Event handler for mediaPlayerStateChange event--used only  
  2227.      *  when trying to load up the video without playing it.
  2228.      */
  2229.     private function videoPlayer_mediaPlayerStateChangeHandlerForLoading(event:MediaPlayerStateChangeEvent):void
  2230.     {
  2231.         // only come in here when we want to load the video without playing it.
  2232.         //trace("videoPlayer_mediaPlayerStateChangeHandlerForLoading: mediaPlayerState = " + event.state);
  2233.        
  2234.         // wait until we are ready so that we can set mute, play, pause, and seek
  2235.         if (event.state == MediaPlayerState.READY)
  2236.         {
  2237.             // now that we are loading up, let's remove the event listener:
  2238.             videoPlayer.removeEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, videoPlayer_mediaPlayerStateChangeHandlerForLoading);
  2239.            
  2240.             // if we are already playing() for some reason because someone called play(), then
  2241.             // we don't need to do anything.
  2242.             if (videoPlayer.playing)
  2243.                 return;
  2244.            
  2245.             // if this load wasn't cancelled, then we'll do the load stuff.
  2246.             // otherwise, we'll just cause play().
  2247.             if (inLoadingState1)
  2248.             {
  2249.                 //trace("videoPlayer_mediaPlayerStateChangeHandlerForLoading: inLoadingState1");
  2250.  
  2251.                 beforeLoadMuted = videoPlayer.muted;
  2252.                 videoPlayer.muted = true;
  2253.                
  2254.                 if (videoPlayer.displayObject)
  2255.                     videoPlayer.displayObject.visible = false;
  2256.                
  2257.                 inLoadingState2 = true;
  2258.             }
  2259.            
  2260.             // call play(), here, then wait to call pause() and seek(0) in the
  2261.             // mediaSizeChangeHandler
  2262.             //trace("videoPlayer_mediaPlayerStateChangeHandlerForLoading: call videoPlayer.play()");
  2263.             videoPlayer.play();
  2264.         }
  2265.     }
  2266.    
  2267.     /**
  2268.      *  @private
  2269.      */
  2270.     private function videoPlayer_mediaSizeChangeHandler(event:DisplayObjectEvent):void
  2271.     {
  2272.         //trace("videoPlayer_mediaSizeChangeHandler");
  2273.         invalidateSize();
  2274.        
  2275.         // if we're loading up the video, then let's finish the load in here
  2276.         if (inLoadingState2)
  2277.         {
  2278.             //trace("videoPlayer_mediaSizeChangeHandler: inLoadingState2");
  2279.  
  2280.             if (videoPlayer.canSeek && videoPlayer.canSeekTo(0))
  2281.             {
  2282.                 //trace("videoPlayer_mediaSizeChangeHandler: canSeek to first frame");
  2283.                 inLoadingState3 = true;
  2284.                
  2285.                 // Don't call pause and seek inside this handler because OSMF is
  2286.                 // not expecting us to change its HTTPStreamingState value in
  2287.                 // HTTPNetStream.onMainTimer as a result of dispatching this
  2288.                 // event (see SDK-27028).
  2289.                 callLater(pauseAndSeekCallBack);
  2290.             }
  2291.             else if (duration < 0)
  2292.             {
  2293.                 // Work around for negative durations - FM-1009
  2294.                 // We want to seek to the first frame but we can't because the
  2295.                 // duration of the video is reported as negative. As a work around,
  2296.                 // listen for the first time change event and then pause the video.
  2297.                 //trace("videoPlayer_mediaSizeChangeHandler: negative duration - wait for first current time change event");
  2298.                 videoPlayer.addEventListener(TimeEvent.CURRENT_TIME_CHANGE, videoPlayer_currentTimeChangeHandler);
  2299.             }
  2300.             else
  2301.             {
  2302.                 //trace("videoPlayer_mediaSizeChangeHandler: waiting for media to become seekable");
  2303.                
  2304.                 // wait for the media to become seekable.
  2305.                 videoPlayer.addEventListener(MediaPlayerCapabilityChangeEvent.CAN_SEEK_CHANGE, videoPlayer_canSeekChangeHandler);
  2306.             }
  2307.         }
  2308.     }
  2309.  
  2310.     private function pauseAndSeekCallBack():void
  2311.     {
  2312.         // the seek(0) is asynchronous so let's add an event listener to see when it's finsished:
  2313.         videoPlayer.addEventListener(SeekEvent.SEEKING_CHANGE, videoPlayer_seekChangeHandler);
  2314.        
  2315.         // called play(), now call pause() and seek(0);
  2316.         videoPlayer.pause();
  2317.         videoPlayer.seek(0);
  2318.                
  2319.     }
  2320.    
  2321.     /**
  2322.      *  @private
  2323.      *  Wait until the media is seekable before we call pause() and seek().
  2324.      */  
  2325.     private function videoPlayer_canSeekChangeHandler(event:Event):void
  2326.     {
  2327.         //trace("videoPlayer_canSeekChangeHandler: seeking = " + videoPlayer.canSeek);
  2328.        
  2329.         videoPlayer.removeEventListener(MediaPlayerCapabilityChangeEvent.CAN_SEEK_CHANGE, videoPlayer_canSeekChangeHandler);
  2330.  
  2331.         if (inLoadingState2)
  2332.         {
  2333.             if (videoPlayer.canSeek && videoPlayer.canSeekTo(0))
  2334.             {
  2335.                 inLoadingState3 = true;
  2336.                
  2337.                 // Don't call pause and seek inside this handler because OSMF is
  2338.                 // not expecting us to change its HTTPStreamingState value in
  2339.                 // HTTPNetStream.onMainTimer as a result of dispatching this
  2340.                 // event (see SDK-27028).
  2341.                 callLater(pauseAndSeekCallBack);
  2342.             }
  2343.         }
  2344.     }
  2345.    
  2346.     /**
  2347.      *  @private
  2348.      *  Event handler for seekEnd events.  We only use this
  2349.      *  when trying to load up the video without playing it.
  2350.      *  This will be called after the video has loaded up and
  2351.      *  we have finished seeking back to the first frame.
  2352.      */
  2353.     private function videoPlayer_seekChangeHandler(event:SeekEvent):void
  2354.     {
  2355.         if (!event.seeking)
  2356.         {
  2357.             inLoadingState1 = false;
  2358.             inLoadingState2 = false;
  2359.             inLoadingState3 = false;
  2360.            
  2361.             videoPlayer.removeEventListener(SeekEvent.SEEKING_CHANGE, videoPlayer_seekChangeHandler);
  2362.             videoPlayer.muted = beforeLoadMuted;
  2363.             if (videoPlayer.displayObject)
  2364.                 videoPlayer.displayObject.visible = true;
  2365.  
  2366.             // Disable the TimeEvents again that we had
  2367.             // enabled for loading a video while offstage.
  2368.             if (!isNaN(oldCurrentTimeUpdateInterval))
  2369.             {
  2370.                 videoPlayer.currentTimeUpdateInterval = -1;
  2371.                 videoPlayer.bytesLoadedUpdateInterval = -1;
  2372.             }
  2373.         }
  2374.     }
  2375.    
  2376.    
  2377.     /**
  2378.      *  @private
  2379.      *
  2380.      *  Work around for negative durations - see FM-1009.
  2381.      *  See want to seek to the first frame but can't because
  2382.      *  the video has a negative duration. So we listen to the
  2383.      *  current time. When we get a time change so we must be at
  2384.      *  least the first frame so pause the video now and clean
  2385.      *  up the load state variables.
  2386.      */
  2387.     private function videoPlayer_currentTimeChangeHandler(event:TimeEvent):void
  2388.     {
  2389.         //trace("videoPlayer_currentTimeChangeHandler: time = " + event.time);
  2390.        
  2391.         videoPlayer.removeEventListener(TimeEvent.CURRENT_TIME_CHANGE, videoPlayer_currentTimeChangeHandler);
  2392.         videoPlayer.removeEventListener(MediaPlayerCapabilityChangeEvent.CAN_SEEK_CHANGE, videoPlayer_canSeekChangeHandler);
  2393.  
  2394.         videoPlayer.pause();
  2395.         videoPlayer.muted = beforeLoadMuted;
  2396.        
  2397.         if (videoPlayer.displayObject)
  2398.             videoPlayer.displayObject.visible = true;
  2399.  
  2400.         inLoadingState1 = false;
  2401.         inLoadingState2 = false;
  2402.         inLoadingState3 = false;
  2403.  
  2404.         // Disable the TimeEvents again that we had
  2405.         // enabled for loading a video while offstage.
  2406.         if (!isNaN(oldCurrentTimeUpdateInterval))
  2407.         {
  2408.             videoPlayer.currentTimeUpdateInterval = -1;
  2409.             videoPlayer.bytesLoadedUpdateInterval = -1;
  2410.         }
  2411.     }
  2412.  
  2413.     /**
  2414.      *  @private
  2415.      *
  2416.      *  Work around for negative durations - see FM-1009.
  2417.      *
  2418.      *  If we get a duration event that is negative while in
  2419.      *  inLoadingState2 is true, then listen for the first time
  2420.      *  change event so we can pause the video.
  2421.      */
  2422.     private function videoPlayer_durationChangeHandler(event:TimeEvent):void
  2423.     {
  2424.         //trace("videoPlayer_durationChangeHandler: time = " + event.time);
  2425.         dispatchEvent(event);
  2426.        
  2427.         if (inLoadingState2)
  2428.         {
  2429.             if (event.time < 0)
  2430.             {
  2431.                 // Work around for negative durations - FM-1009
  2432.                 // We want to seek to the first frame but we can't because the
  2433.                 // duration of the video is reported as negative. As a work around,
  2434.                 // listen for the first time change event and then pause the video.
  2435.                 //trace("videoPlayer_durationChangeHandler: negative duration - wait for first current time change event");
  2436.                 videoPlayer.addEventListener(TimeEvent.CURRENT_TIME_CHANGE, videoPlayer_currentTimeChangeHandler);
  2437.             }
  2438.         }
  2439.     }
  2440. }
  2441. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement