//////////////////////////////////////////////////////////////////////////////// // // Licensed to the Apache Software Foundation (ASF) under one or more // contributor license agreements. See the NOTICE file distributed with // this work for additional information regarding copyright ownership. // The ASF licenses this file to You under the Apache License, Version 2.0 // (the "License"); you may not use this file except in compliance with // the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // //////////////////////////////////////////////////////////////////////////////// package spark.components { import flash.display.DisplayObject; import flash.display.StageDisplayState; import flash.events.Event; import flash.events.FullScreenEvent; import flash.events.KeyboardEvent; import flash.events.MouseEvent; import flash.events.TimerEvent; import flash.geom.Rectangle; import flash.media.Video; import flash.system.ApplicationDomain; import flash.utils.Timer; import mx.core.FlexGlobals; import mx.core.IVisualElementContainer; import mx.core.mx_internal; import mx.events.FlexEvent; import mx.managers.PopUpManager; import mx.utils.BitFlagUtil; import org.osmf.events.LoadEvent; import org.osmf.events.MediaPlayerStateChangeEvent; import org.osmf.events.TimeEvent; import org.osmf.media.MediaPlayerState; import spark.components.mediaClasses.MuteButton; import spark.components.mediaClasses.ScrubBar; import spark.components.mediaClasses.VolumeBar; import spark.components.supportClasses.ButtonBase; import spark.components.supportClasses.SkinnableComponent; import spark.components.supportClasses.ToggleButtonBase; import spark.core.IDisplayText; import spark.events.TrackBaseEvent; use namespace mx_internal; //-------------------------------------- // Events //-------------------------------------- /** * Dispatched when the data is received as a download operation progresses. * This event is only dispatched when playing a video by downloading it * directly from a server, typically by issuing an HTTP request. * It is not displatched when playing a video from a special media server, * such as Flash Media Server. * *

This event may not be dispatched when the source is set to null or a playback * error occurs.

* * @eventType org.osmf.events.LoadEvent.BYTES_LOADED_CHANGE * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.0 * @productversion Flex 4 */ [Event(name="bytesLoadedChange",type="org.osmf.events.LoadEvent")] /** * Dispatched when the playhead reaches the duration for playable media. * * @eventType org.osmf.events.TimeEvent.COMPLETE * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.0 * @productversion Flex 4 */ [Event(name="complete", type="org.osmf.events.TimeEvent")] /** * Dispatched when the currentTime property of the MediaPlayer has changed. * *

This event may not be dispatched when the source is set to null or a playback * error occurs.

* * @eventType org.osmf.events.TimeEvent.CURRENT_TIME_CHANGE * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.0 * @productversion Flex 4 */ [Event(name="currentTimeChange",type="org.osmf.events.TimeEvent")] /** * Dispatched when the duration property of the media has changed. * *

This event may not be dispatched when the source is set to null or a playback * error occurs.

* * @eventType org.osmf.events.TimeEvent.DURATION_CHANGE * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.0 * @productversion Flex 4 */ [Event(name="durationChange", type="org.osmf.events.TimeEvent")] /** * Dispatched when the MediaPlayer's state has changed. * * @eventType org.osmf.events.MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.0 * @productversion Flex 4 */ [Event(name="mediaPlayerStateChange", type="org.osmf.events.MediaPlayerStateChangeEvent")] //-------------------------------------- // Styles //-------------------------------------- include "../styles/metadata/BasicInheritingTextStyles.as"; /** * Controls the visibility of the drop shadow for this component. * * @default true * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [Style(name="dropShadowVisible", type="Boolean", inherit="no", theme="spark")] /** * The time, in milli-seconds, to wait in fullscreen mode with no user-interaction * before hiding the video playback controls. * *

If set to Infinity, then the playback controls will not * be hidden in fullscreen mode. Changing this value while already in * fullscreen mode has no effect.

* * @default 3000 * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [Style(name="fullScreenHideControlsDelay", type="Number", format="Time", inherit="no")] /** * @copy spark.components.supportClasses.GroupBase#style:symbolColor * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [Style(name="symbolColor", type="uint", format="Color", inherit="yes", theme="spark")] //-------------------------------------- // SkinStates //-------------------------------------- /** * Uninitialized state of the VideoPlayer. * The Video Player has been constructed at this point, * but the source has not been set and no connection * attempt is in progress. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("uninitialized")] /** * Loading state of the VideoPlayer. * The VideoPlayer is loading or connecting to the source. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("loading")] /** * Ready state of the VideoPlayer. * The video is ready to be played. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("ready")] /** * Playing state of the VideoPlayer * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("playing")] /** * Paused state of the VideoPlayer * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("paused")] /** * Buffering state of the VideoPlayer * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("buffering")] /** * Playback Error state of the VideoPlayer. * An error was encountered while trying to play the video. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("playbackError")] /** * Disabled state of the VideoPlayer * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("disabled")] /** * Uninitialized state of the VideoPlayer when * in full screen mode. * The Video Player has been constructed at this point, * but the source has not been set and no connection * attempt is in progress. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("uninitializedAndFullScreen")] /** * Loading state of the VideoPlayer when * in full screen mode. * The VideoPlayer is loading or connecting to the source. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("loadingAndFullScreen")] /** * Ready state of the VideoPlayer when * in full screen mode. The video is ready to be played. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("readyAndFullScreen")] /** * Playing state of the VideoPlayer when * in full screen mode. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("playingAndFullScreen")] /** * Paused state of the VideoPlayer when * in full screen mode. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("pausedAndFullScreen")] /** * Buffering state of the VideoPlayer when * in full screen mode. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("bufferingAndFullScreen")] /** * Playback Error state of the VideoPlayer when * in full screen mode. * An error was encountered while trying to play the video. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("playbackErrorAndFullScreen")] /** * Disabled state of the VideoPlayer when * in full screen mode. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ [SkinState("disabledAndFullScreen")] //-------------------------------------- // Excluded APIs //-------------------------------------- [Exclude(name="focusBlendMode", kind="style")] [Exclude(name="focusThickness", kind="style")] //-------------------------------------- // Other metadata //-------------------------------------- [AccessibilityClass(implementation="spark.accessibility.VideoPlayerAccImpl")] [DefaultProperty("source")] [IconFile("VideoPlayer.png")] /** * Because this component does not define a skin for the mobile theme, Adobe * recommends that you not use it in a mobile application. Alternatively, you * can define your own mobile skin for the component. For more information, * see Basics of mobile skinning. */ [DiscouragedForProfile("mobileDevice")] /** * The VideoPlayer control is a skinnable video player that supports * progressive download, multi-bitrate streaming, and streaming video. * It supports playback of FLV and F4v files. The VideoPlayer control * contains a full-featured UI for controlling video playback. * *

VideoDisplay is the chromeless version that does not support skinning. * It is useful when you do not want the user to interact with the control.

* *

The VideoPlayer control has the following default characteristics:

* * * * * * * * * * * * * * * * * * * * * *
CharacteristicDescription
Default size263 pixels wide by 184 pixels high
Minimum size0
Maximum size10000 pixels wide and 10000 pixels high
Default skin classspark.skins.spark.VideoPlayerSkin
* * @see spark.components.VideoDisplay * @see spark.skins.spark.VideoPlayerSkin * @see spark.skins.spark.mediaClasses.fullScreen.FullScreenButtonSkin * @see spark.skins.spark.mediaClasses.fullScreen.MuteButtonSkin * @see spark.skins.spark.mediaClasses.fullScreen.PlayPauseButtonSkin * @see spark.skins.spark.mediaClasses.fullScreen.ScrubBarSkin * @see spark.skins.spark.mediaClasses.fullScreen.ScrubBarThumbSkin * @see spark.skins.spark.mediaClasses.fullScreen.ScrubBarTrackSkin * @see spark.skins.spark.mediaClasses.fullScreen.VolumeBarSkin * @see spark.skins.spark.mediaClasses.fullScreen.VolumeBarThumbSkin * @see spark.skins.spark.mediaClasses.fullScreen.VolumeBarTrackSkin * @see spark.skins.spark.mediaClasses.normal.FullScreenButtonSkin * @see spark.skins.spark.mediaClasses.normal.MuteButtonSkin * @see spark.skins.spark.mediaClasses.normal.PlayPauseButtonSkin * @see spark.skins.spark.mediaClasses.normal.ScrubBarSkin * @see spark.skins.spark.mediaClasses.normal.ScrubBarThumbSkin * @see spark.skins.spark.mediaClasses.normal.ScrubBarTrackSkin * @see spark.skins.spark.mediaClasses.normal.VolumeBarSkin * @see spark.skins.spark.mediaClasses.normal.VolumeBarThumbSkin * @see spark.skins.spark.mediaClasses.normal.VolumeBarTrackSkin * * @mxml * *

The <s:VideoPlayer> tag inherits all of the tag * attributes of its superclass and adds the following tag attributes:

* *
 *  <s:VideoPlayer
 
 *    Properties
 *    autoDisplayFirstFrame="true"
 *    autoPlay="true"
 *    autoRewind="true"
 *    loop="false"
 *    muted="false"
 *    pauseWhenHidden="true"
 *    scaleMode="letterbox"
 *    source=""
 *    volume="1"
 *  
 *    Events
 *    bytesLoadedChange="No default"
 *    complete="No default"
 *    currentTimeChange="No default"
 *    durationChange="No default"
 *    mediaPlayerStateChange="No default"
 *  
 * 
 *    Styles
 *    alignmentBaseline="baseline"
 *    baselineShift="0"
 *    cffHinting="0.0"
 *    color="0x000000"
 *    digitCase="default"
 *    digitWidth="default"
 *    direction="ltr"
 *    dominantBaseline="auto"
 *    dropShadowVisible="true"
 *    fontFamily="Arial"
 *    fontLookup="device"
 *    fontSize="12"
 *    fontStyle="normal"
 *    fontWeight="normal"
 *    justificationRule="auto"
 *    justificationStyle="auto"
 *    kerning="false"
 *    ligatureLevel="common"
 *    lineHeight="120%"
 *    lineThrough="false%"
 *    locale="en"
 *    renderingMode="cff"
 *    textAlign="start"
 *    textAlignLast="start"
 *    textAlpha="1"
 *    textDecoration="start"
 *    textJustify="interWord"
 *    trackingLeft="0"
 *    trackingRight="00"
 *    typographicCase="default"
 *  />
 *  
* * @includeExample examples/VideoPlayerExample.mxml * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public class VideoPlayer extends SkinnableComponent { include "../core/Version.as"; //-------------------------------------------------------------------------- // // Class constants // //-------------------------------------------------------------------------- /** * @private */ private static const AUTO_DISPLAY_FIRST_FRAME_PROPERTY_FLAG:uint = 1 << 0; /** * @private */ private static const AUTO_PLAY_PROPERTY_FLAG:uint = 1 << 1; /** * @private */ private static const AUTO_REWIND_PROPERTY_FLAG:uint = 1 << 2; /** * @private */ private static const LOOP_PROPERTY_FLAG:uint = 1 << 3; /** * @private */ private static const SCALE_MODE_PROPERTY_FLAG:uint = 1 << 4; /** * @private */ private static const MUTED_PROPERTY_FLAG:uint = 1 << 5; /** * @private */ private static const SOURCE_PROPERTY_FLAG:uint = 1 << 6; /** * @private */ private static const VOLUME_PROPERTY_FLAG:uint = 1 << 7; /** * @private */ private static const PAUSE_WHEN_HIDDEN_PROPERTY_FLAG:uint = 1 << 8; /** * @private */ private static const THUMBNAIL_SOURCE_PROPERTY_FLAG:uint = 1 << 9; //-------------------------------------------------------------------------- // // Class properties // //-------------------------------------------------------------------------- /** * @private */ private static var _screenClass:Class; /** * @private */ private static var checkedForScreenClass:Boolean; /** * @private */ private static function get screenClass():Class { if (!checkedForScreenClass) { checkedForScreenClass = true; if (ApplicationDomain.currentDomain. hasDefinition("flash.display::Screen")) { _screenClass = Class(ApplicationDomain.currentDomain. getDefinition("flash.display::Screen")); } } return _screenClass; } //-------------------------------------------------------------------------- // // Class mixins // //-------------------------------------------------------------------------- /** * @private * Placeholder for mixin by VideoPlayerAccImpl. */ mx_internal static var createAccessibilityImplementation:Function; //-------------------------------------------------------------------------- // // Constructor // //-------------------------------------------------------------------------- /** * Constructor. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function VideoPlayer() { super(); } //-------------------------------------------------------------------------- // // Skin Parts // //-------------------------------------------------------------------------- [SkinPart(required="true")] /** * A required skin part that defines the VideoDisplay. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public var videoDisplay:VideoDisplay; [SkinPart(required="false")] /** * An optional skin part to display the current value of codecurrentTime. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public var currentTimeDisplay:IDisplayText; [SkinPart(required="false")] /** * An optional skin part for a button to toggle fullscreen mode. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public var fullScreenButton:ButtonBase; [SkinPart(required="false")] /** * An optional skin part for the mute button. The mute * button has both a muted property and a * volume property. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public var muteButton:MuteButton; [SkinPart(required="false")] /** * An optional skin part for the pause button. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public var pauseButton:ButtonBase; [SkinPart(required="false")] /** * An optional skin part for the play button. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public var playButton:ButtonBase; [SkinPart(required="false")] /** * An optional skin part for all of the player controls. * This skin is used to determine what to hide when the player is in full screen * mode and there has been no user interaction. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public var playerControls:DisplayObject; [SkinPart(required="false")] /** * An optional skin part for a play/pause button. When the * video is playing, the selected property is set to * true. When the video is paused or stopped, * the selected property is set to false. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public var playPauseButton:ToggleButtonBase; [SkinPart(required="false")] /** * An optional skin part for the scrub bar (the * timeline). * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public var scrubBar:ScrubBar; [SkinPart(required="false")] /** * An optional skin part for the stop button. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public var stopButton:ButtonBase; [SkinPart(required="false")] /** * An optional skin part to display the duration. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public var durationDisplay:IDisplayText; [SkinPart(required="false")] /** * An optional skin part for the volume control. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public var volumeBar:VolumeBar; //-------------------------------------------------------------------------- // // Variables // //-------------------------------------------------------------------------- /** * @private * Several properties are proxied to videoDisplay. However, when videoDisplay * is not around, we need to store values set on VideoPlayer. This object * stores those values. If videoDisplay is around, the values are stored * on the videoDisplay directly. However, we need to know what values * have been set by the developer on the VideoPlayer (versus set on * the videoDisplay or defaults of the videoDisplay) as those are values * we want to carry around if the videoDisplay changes (via a new skin). * In order to store this info effeciently, videoDisplayProperties becomes * a uint to store a series of BitFlags. These bits represent whether a * property has been explicitely set on this VideoPlayer. When the * contentGroup is not around, videoDisplayProperties is a typeless * object to store these proxied properties. When videoDisplay is around, * videoDisplayProperties stores booleans as to whether these properties * have been explicitely set or not. */ private var videoDisplayProperties:Object = {}; /** * @private * The value of the pauseWhenHidden property before exiting * fullScreen. We need to store it away here so we can * restore it at commitProperties() time because of an AIR * Mac bug. */ private var exitingFullScreenPauseWhenHidden:Boolean; /** * @private * Whether the pauseWhenHidden property needs to be updated. */ private var needsToUpdatePauseWhenHidden:Boolean = false; //-------------------------------------------------------------------------- // // Properties // //-------------------------------------------------------------------------- //---------------------------------- // autoDisplayFirstFrame //---------------------------------- [Inspectable(category="General", defaultValue="true")] /** * @copy spark.components.VideoDisplay#autoDisplayFirstFrame * * @default true * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get autoDisplayFirstFrame():Boolean { if (videoDisplay) { return videoDisplay.autoDisplayFirstFrame; } else { var v:* = videoDisplayProperties.autoDisplayFirstFrame; return (v === undefined) ? true : v; } } /** * @private */ public function set autoDisplayFirstFrame(value:Boolean):void { if (videoDisplay) { videoDisplay.autoDisplayFirstFrame = value; videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint, AUTO_DISPLAY_FIRST_FRAME_PROPERTY_FLAG, true); } else { videoDisplayProperties.autoDisplayFirstFrame = value; } } //---------------------------------- // autoPlay //---------------------------------- [Inspectable(category="General", defaultValue="true")] /** * @copy spark.components.VideoDisplay#autoPlay * * @default true * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get autoPlay():Boolean { if (videoDisplay) { return videoDisplay.autoPlay; } else { var v:* = videoDisplayProperties.autoPlay; return (v === undefined) ? true : v; } } /** * @private */ public function set autoPlay(value:Boolean):void { if (videoDisplay) { videoDisplay.autoPlay = value; videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint, AUTO_PLAY_PROPERTY_FLAG, true); } else { videoDisplayProperties.autoPlay = value; } } //---------------------------------- // autoRewind //---------------------------------- [Inspectable(category="General", defaultValue="true")] /** * @copy spark.components.VideoDisplay#autoRewind * * @default true * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get autoRewind():Boolean { if (videoDisplay) { return videoDisplay.autoRewind; } else { var v:* = videoDisplayProperties.autoRewind; return (v === undefined) ? true : v; } } /** * @private */ public function set autoRewind(value:Boolean):void { if (videoDisplay) { videoDisplay.autoRewind = value; videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint, AUTO_REWIND_PROPERTY_FLAG, true); } else { videoDisplayProperties.autoRewind = value; } } //---------------------------------- // bytesLoaded //---------------------------------- [Inspectable(Category="General", defaultValue="0")] [Bindable("bytesLoadedChange")] [Bindable("mediaPlayerStateChange")] /** * @copy spark.components.VideoDisplay#bytesLoaded * * @default 0 * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get bytesLoaded():Number { if (videoDisplay) return videoDisplay.bytesLoaded; else return 0; } //---------------------------------- // bytesTotal //---------------------------------- [Inspectable(Category="General", defaultValue="0")] [Bindable("mediaPlayerStateChange")] /** * @copy spark.components.VideoDisplay#bytesTotal * * @default 0 * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get bytesTotal():Number { if (videoDisplay) return videoDisplay.bytesTotal; else return 0; } //---------------------------------- // currentTime //---------------------------------- [Inspectable(Category="General", defaultValue="0")] [Bindable("currentTimeChange")] [Bindable("mediaPlayerStateChange")] /** * @copy spark.components.VideoDisplay#currentTime * * @default 0 * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get currentTime():Number { if (videoDisplay) return videoDisplay.currentTime; else return 0; } //---------------------------------- // duration //---------------------------------- [Inspectable(Category="General", defaultValue="0")] [Bindable("durationChange")] [Bindable("mediaPlayerStateChange")] /** * @copy spark.components.VideoDisplay#duration * * @default 0 * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get duration():Number { if (videoDisplay) return videoDisplay.duration; else return 0; } //---------------------------------- // loop //---------------------------------- [Inspectable(Category="General", defaultValue="false")] /** * @copy spark.components.VideoDisplay#loop * * @default false * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get loop():Boolean { if (videoDisplay) { return videoDisplay.loop; } else { var v:* = videoDisplayProperties.loop; return (v === undefined) ? false : v; } } /** * @private */ public function set loop(value:Boolean):void { if (videoDisplay) { videoDisplay.loop = value; videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint, LOOP_PROPERTY_FLAG, true); } else { videoDisplayProperties.loop = value; } } //---------------------------------- // mediaPlayerState //---------------------------------- [Inspectable(category="General", defaultValue="uninitialized")] [Bindable("mediaPlayerStateChange")] /** * @copy spark.components.VideoDisplay#mediaPlayerState * * @default uninitialized * * @see org.osmf.media.MediaPlayerState * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get mediaPlayerState():String { if (videoDisplay) return videoDisplay.mediaPlayerState; else return MediaPlayerState.UNINITIALIZED; } //---------------------------------- // muted //---------------------------------- [Inspectable(category="General", defaultValue="false")] [Bindable("volumeChanged")] /** * @copy spark.components.VideoDisplay#muted * * @default false * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get muted():Boolean { if (videoDisplay) { return videoDisplay.muted; } else { var v:* = videoDisplayProperties.muted; return (v === undefined) ? false : v; } } /** * @private */ public function set muted(value:Boolean):void { if (videoDisplay) { videoDisplay.muted = value; videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint, MUTED_PROPERTY_FLAG, true); } else { videoDisplayProperties.muted = value; } if (volumeBar) volumeBar.muted = value; if (muteButton) muteButton.muted = value; } //---------------------------------- // pauseWhenHidden //---------------------------------- [Inspectable(category="General", defaultValue="true")] /** * @copy spark.components.VideoDisplay#pauseWhenHidden * * @default true * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get pauseWhenHidden():Boolean { if (needsToUpdatePauseWhenHidden) { return exitingFullScreenPauseWhenHidden; } else if (videoDisplay) { return videoDisplay.pauseWhenHidden; } else { var v:* = videoDisplayProperties.pauseWhenHidden; return (v === undefined) ? false : v; } } /** * @private */ public function set pauseWhenHidden(value:Boolean):void { if (needsToUpdatePauseWhenHidden) { exitingFullScreenPauseWhenHidden = value; } else if (videoDisplay) { videoDisplay.pauseWhenHidden = value; videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint, PAUSE_WHEN_HIDDEN_PROPERTY_FLAG, true); } else { videoDisplayProperties.pauseWhenHidden = value; } } //---------------------------------- // playing //---------------------------------- [Inspectable(category="General")] [Bindable("mediaPlayerStateChange")] /** * @copy spark.components.VideoDisplay#playing * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get playing():Boolean { if (videoDisplay) return videoDisplay.playing; else return false; } //---------------------------------- // scaleMode //---------------------------------- [Inspectable(Category="General", enumeration="none,stretch,letterbox,zoom", defaultValue="letterbox")] /** * @copy spark.components.VideoDisplay#scaleMode * * @default "letterbox" * * @see org.osmf.display.ScaleMode * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get scaleMode():String { if (videoDisplay) { return videoDisplay.scaleMode; } else { var v:* = videoDisplayProperties.scaleMode; return (v === undefined) ? "letterbox" : v; } } /** * @private */ public function set scaleMode(value:String):void { if (videoDisplay) { videoDisplay.scaleMode = value; videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint, SCALE_MODE_PROPERTY_FLAG, true); } else { videoDisplayProperties.scaleMode = value; } } //---------------------------------- // source //---------------------------------- [Inspectable(category="General", defaultValue="null")] [Bindable("sourceChanged")] /** * @copy spark.components.VideoDisplay#source * * @default null * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get source():Object { if (videoDisplay) { return videoDisplay.source; } else { var v:* = videoDisplayProperties.source; return (v === undefined) ? null : v; } } /** * @private */ public function set source(value:Object):void { if (videoDisplay) { videoDisplay.source = value; videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint, SOURCE_PROPERTY_FLAG, true); } else { videoDisplayProperties.source = value; } } //---------------------------------- // thumbnailSource //---------------------------------- [Inspectable(category="General")] /** * @private * @copy spark.components.VideoDisplay#thumbnailSource * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ mx_internal function get thumbnailSource():Object { if (videoDisplay) { return videoDisplay.thumbnailSource; } else { var v:* = videoDisplayProperties.thumbnailSource; return (v === undefined) ? null : v; } } /** * @private */ mx_internal function set thumbnailSource(value:Object):void { if (videoDisplay) { videoDisplay.thumbnailSource = value; videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint, THUMBNAIL_SOURCE_PROPERTY_FLAG, true); } else { videoDisplayProperties.thumbnailSource = value; } } //---------------------------------- // videoObject //---------------------------------- [Inspectable(category="General", defaultValue="null")] /** * @copy spark.components.VideoDisplay#videoObject * * @default null * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get videoObject():Video { if (videoDisplay) return videoDisplay.videoObject; else return null; } //---------------------------------- // volume //---------------------------------- [Inspectable(category="General", defaultValue="1.0", minValue="0.0", maxValue="1.0")] [Bindable("volumeChanged")] /** * @copy spark.components.VideoDisplay#volume * * @default 1 * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function get volume():Number { if (videoDisplay) { return videoDisplay.volume; } else { var v:* = videoDisplayProperties.volume; return (v === undefined) ? 1 : v; } } /** * @private */ public function set volume(value:Number):void { if (videoDisplay) { videoDisplay.volume = value; videoDisplayProperties = BitFlagUtil.update(videoDisplayProperties as uint, VOLUME_PROPERTY_FLAG, true); } else { videoDisplayProperties.volume = value; } if (volumeBar) volumeBar.value = value; } //-------------------------------------------------------------------------- // // Overridden methods // //-------------------------------------------------------------------------- /** * @private */ override protected function initializeAccessibility():void { if (VideoPlayer.createAccessibilityImplementation != null) VideoPlayer.createAccessibilityImplementation(this); } /** * @private */ override protected function getCurrentSkinState():String { if (!videoDisplay || !videoDisplay.videoPlayer) return null; var state:String = videoDisplay.videoPlayer.state; // now that we have our video player's current state (atleast the one we care about) // and that we've set the previous state to something we care about, let's figure // out our skin's state if (!enabled) state="disabled" if (fullScreen) return state + "AndFullScreen"; return state; } /** * @private */ override protected function partAdded(partName:String, instance:Object):void { super.partAdded(partName, instance); if (instance == videoDisplay) { videoDisplay.addEventListener(TimeEvent.CURRENT_TIME_CHANGE, videoDisplay_currentTimeChangeHandler); videoDisplay.addEventListener(LoadEvent.BYTES_LOADED_CHANGE, videoDisplay_bytesLoadedChangeHandler); videoDisplay.addEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, videoDisplay_mediaPlayerStateChangeHandler); videoDisplay.addEventListener(TimeEvent.DURATION_CHANGE, videoDisplay_durationChangeHandler); videoDisplay.addEventListener(TimeEvent.COMPLETE, dispatchEvent); // just strictly for binding purposes videoDisplay.addEventListener("sourceChanged", dispatchEvent); videoDisplay.addEventListener("volumeChanged", videoDisplay_volumeChangedHandler); // copy proxied values from videoProperties (if set) to video var newVideoProperties:uint = 0; if (videoDisplayProperties.source !== undefined) { videoDisplay.source = videoDisplayProperties.source; newVideoProperties = BitFlagUtil.update(newVideoProperties as uint, SOURCE_PROPERTY_FLAG, true); } if (videoDisplayProperties.autoPlay !== undefined) { videoDisplay.autoPlay = videoDisplayProperties.autoPlay; newVideoProperties = BitFlagUtil.update(newVideoProperties as uint, AUTO_PLAY_PROPERTY_FLAG, true); } if (videoDisplayProperties.volume !== undefined) { videoDisplay.volume = videoDisplayProperties.volume; newVideoProperties = BitFlagUtil.update(newVideoProperties as uint, VOLUME_PROPERTY_FLAG, true); } if (videoDisplayProperties.autoRewind !== undefined) { videoDisplay.autoRewind = videoDisplayProperties.autoRewind; newVideoProperties = BitFlagUtil.update(newVideoProperties as uint, AUTO_REWIND_PROPERTY_FLAG, true); } if (videoDisplayProperties.loop !== undefined) { videoDisplay.loop = videoDisplayProperties.loop; newVideoProperties = BitFlagUtil.update(newVideoProperties as uint, LOOP_PROPERTY_FLAG, true); } if (videoDisplayProperties.scaleMode !== undefined) { videoDisplay.scaleMode = videoDisplayProperties.scaleMode; newVideoProperties = BitFlagUtil.update(newVideoProperties as uint, SCALE_MODE_PROPERTY_FLAG, true); } if (videoDisplayProperties.muted !== undefined) { videoDisplay.muted = videoDisplayProperties.muted; newVideoProperties = BitFlagUtil.update(newVideoProperties as uint, MUTED_PROPERTY_FLAG, true); } if (videoDisplayProperties.pauseWhenHidden !== undefined) { videoDisplay.pauseWhenHidden = videoDisplayProperties.pauseWhenHidden; newVideoProperties = BitFlagUtil.update(newVideoProperties as uint, PAUSE_WHEN_HIDDEN_PROPERTY_FLAG, true); } if (videoDisplayProperties.autoDisplayFirstFrame !== undefined) { videoDisplay.autoDisplayFirstFrame = videoDisplayProperties.autoDisplayFirstFrame; newVideoProperties = BitFlagUtil.update(newVideoProperties as uint, AUTO_DISPLAY_FIRST_FRAME_PROPERTY_FLAG, true); } if (videoDisplayProperties.thumbnailSource !== undefined) { videoDisplay.thumbnailSource = videoDisplayProperties.thumbnailSource; newVideoProperties = BitFlagUtil.update(newVideoProperties as uint, THUMBNAIL_SOURCE_PROPERTY_FLAG, true); } // these are state properties just carried over from an old video element if (videoDisplayProperties.currentTime !== undefined || videoDisplayProperties.playing !== undefined) { videoDisplay_updateCompleteHandlerProperties = { autoPlay: videoDisplay.autoPlay, playing: videoDisplayProperties.playing, currentTime: videoDisplayProperties.currentTime}; // so the videoDisplay doesn't start playing...we'll handle it instead in // videoDisplay_updateCompleteHandler videoDisplay.autoPlay = false; videoDisplay.addEventListener(FlexEvent.UPDATE_COMPLETE, videoDisplay_updateCompleteHandler); } videoDisplayProperties = newVideoProperties; if (volumeBar) { volumeBar.value = videoDisplay.volume; volumeBar.muted = videoDisplay.muted; } if (muteButton) { muteButton.volume = videoDisplay.volume; muteButton.muted = videoDisplay.muted; } if (scrubBar) updateScrubBar(); if (currentTimeDisplay) updateCurrentTime(); if (durationDisplay) updateDuration(); } else if (instance == playButton) { playButton.addEventListener(MouseEvent.CLICK, playButton_clickHandler); } else if (instance == pauseButton) { pauseButton.addEventListener(MouseEvent.CLICK, pauseButton_clickHandler); } else if (instance == playPauseButton) { playPauseButton.addEventListener(MouseEvent.CLICK, playPauseButton_clickHandler); } else if (instance == stopButton) { stopButton.addEventListener(MouseEvent.CLICK, stopButton_clickHandler); } else if (instance == muteButton) { if (videoDisplay) { muteButton.muted = muted; muteButton.volume = volume; } muteButton.addEventListener(FlexEvent.MUTED_CHANGE, muteButton_mutedChangeHandler); } else if (instance == volumeBar) { volumeBar.minimum = 0; volumeBar.maximum = 1; if (videoDisplay) { volumeBar.value = volume; volumeBar.muted = muted; } volumeBar.addEventListener(Event.CHANGE, volumeBar_changeHandler); volumeBar.addEventListener(FlexEvent.MUTED_CHANGE, volumeBar_mutedChangeHandler); } else if (instance == scrubBar) { if (videoDisplay) updateScrubBar(); // add thumbPress and thumbRelease so we pause the video while dragging scrubBar.addEventListener(TrackBaseEvent.THUMB_PRESS, scrubBar_thumbPressHandler); scrubBar.addEventListener(TrackBaseEvent.THUMB_RELEASE, scrubBar_thumbReleaseHandler); // add change to actually seek() when the change is complete scrubBar.addEventListener(Event.CHANGE, scrubBar_changeHandler); // add changeEnd and changeStart so we don't update the scrubbar's value // while the scrubbar is moving around due to an animation scrubBar.addEventListener(FlexEvent.CHANGE_END, scrubBar_changeEndHandler); scrubBar.addEventListener(FlexEvent.CHANGE_START, scrubBar_changeStartHandler); } else if (instance == fullScreenButton) { fullScreenButton.addEventListener(MouseEvent.CLICK, fullScreenButton_clickHandler); } else if (instance == currentTimeDisplay) { if (videoDisplay) updateCurrentTime(); } else if (instance == durationDisplay) { if (videoDisplay) updateDuration(); } } /** * @private * Holds the state of the video element when the skin is being swapped out. * This is so the new videoDisplay can load up and start playing * where it left off. */ private var videoDisplay_updateCompleteHandlerProperties:Object; /** * @private * We only listen for the updateComplete event on the videoDisplay when * a skin has been swapped. This is so we can push the old videoDisplay's * state in to the new object, and we can start playing the video * where it left off. */ private function videoDisplay_updateCompleteHandler(event:FlexEvent):void { if (videoDisplay_updateCompleteHandlerProperties.autoPlay) videoDisplay.autoPlay = true; if (videoDisplay_updateCompleteHandlerProperties.currentTime !== undefined) videoDisplay.seek(videoDisplay_updateCompleteHandlerProperties.currentTime); if (videoDisplay_updateCompleteHandlerProperties.playing) videoDisplay.play(); videoDisplay_updateCompleteHandlerProperties = null; videoDisplay.removeEventListener(FlexEvent.UPDATE_COMPLETE, videoDisplay_updateCompleteHandler); } /** * @private */ override protected function partRemoved(partName:String, instance:Object):void { super.partRemoved(partName, instance); if (instance == videoDisplay) { // validate before doing anything with the videoDisplay. // This is so if the video element hasn't been validated, it won't start playing. // plus this way we'll get a valid currentTime and all those other properties // we are interested in. videoDisplay.validateNow(); // copy proxied values from video (if explicitely set) to videoProperties var newVideoProperties:Object = {}; if (BitFlagUtil.isSet(videoDisplayProperties as uint, SOURCE_PROPERTY_FLAG)) newVideoProperties.source = videoDisplay.source; if (BitFlagUtil.isSet(videoDisplayProperties as uint, AUTO_PLAY_PROPERTY_FLAG)) newVideoProperties.autoPlay = videoDisplay.autoPlay; if (BitFlagUtil.isSet(videoDisplayProperties as uint, VOLUME_PROPERTY_FLAG)) newVideoProperties.volume = videoDisplay.volume; if (BitFlagUtil.isSet(videoDisplayProperties as uint, AUTO_REWIND_PROPERTY_FLAG)) newVideoProperties.autoRewind = videoDisplay.autoRewind; if (BitFlagUtil.isSet(videoDisplayProperties as uint, LOOP_PROPERTY_FLAG)) newVideoProperties.loop = videoDisplay.loop; if (BitFlagUtil.isSet(videoDisplayProperties as uint, SCALE_MODE_PROPERTY_FLAG)) newVideoProperties.scaleMode = videoDisplay.scaleMode; if (BitFlagUtil.isSet(videoDisplayProperties as uint, MUTED_PROPERTY_FLAG)) newVideoProperties.muted = videoDisplay.muted; if (BitFlagUtil.isSet(videoDisplayProperties as uint, PAUSE_WHEN_HIDDEN_PROPERTY_FLAG)) newVideoProperties.pauseWhenHidden = videoDisplay.pauseWhenHidden; if (BitFlagUtil.isSet(videoDisplayProperties as uint, AUTO_DISPLAY_FIRST_FRAME_PROPERTY_FLAG)) newVideoProperties.autoDisplayFirstFrame = videoDisplay.autoDisplayFirstFrame; if (BitFlagUtil.isSet(videoDisplayProperties as uint, THUMBNAIL_SOURCE_PROPERTY_FLAG)) newVideoProperties.thumbnailSource = videoDisplay.thumbnailSource; // push our current state (where we were in the video and whether we were playing) // so that the new skin gets these as well newVideoProperties.currentTime = videoDisplay.currentTime; newVideoProperties.playing = videoDisplay.playing; videoDisplay.stop(); videoDisplayProperties = newVideoProperties; videoDisplay.removeEventListener(TimeEvent.CURRENT_TIME_CHANGE, videoDisplay_currentTimeChangeHandler); videoDisplay.removeEventListener(LoadEvent.BYTES_LOADED_CHANGE, videoDisplay_bytesLoadedChangeHandler); videoDisplay.removeEventListener(MediaPlayerStateChangeEvent.MEDIA_PLAYER_STATE_CHANGE, videoDisplay_mediaPlayerStateChangeHandler); videoDisplay.removeEventListener(TimeEvent.DURATION_CHANGE, videoDisplay_durationChangeHandler); videoDisplay.removeEventListener(TimeEvent.COMPLETE, dispatchEvent); // just strictly for binding purposes videoDisplay.removeEventListener("sourceChanged", dispatchEvent); videoDisplay.removeEventListener("volumeChanged", videoDisplay_volumeChangedHandler); } else if (instance == playButton) { playButton.removeEventListener(MouseEvent.CLICK, playButton_clickHandler); } else if (instance == pauseButton) { pauseButton.removeEventListener(MouseEvent.CLICK, pauseButton_clickHandler); } else if (instance == playPauseButton) { playPauseButton.removeEventListener(MouseEvent.CLICK, playPauseButton_clickHandler); } else if (instance == stopButton) { stopButton.removeEventListener(MouseEvent.CLICK, stopButton_clickHandler); } else if (instance == muteButton) { playButton.removeEventListener(FlexEvent.MUTED_CHANGE, muteButton_mutedChangeHandler); } else if (instance == volumeBar) { volumeBar.removeEventListener(Event.CHANGE, volumeBar_changeHandler); volumeBar.removeEventListener(FlexEvent.MUTED_CHANGE, volumeBar_mutedChangeHandler); } else if (instance == scrubBar) { scrubBar.removeEventListener(TrackBaseEvent.THUMB_PRESS, scrubBar_thumbPressHandler); scrubBar.removeEventListener(TrackBaseEvent.THUMB_RELEASE, scrubBar_thumbReleaseHandler); scrubBar.removeEventListener(Event.CHANGE, scrubBar_changeHandler); scrubBar.removeEventListener(FlexEvent.CHANGE_END, scrubBar_changeEndHandler); scrubBar.removeEventListener(FlexEvent.CHANGE_START, scrubBar_changeStartHandler); } else if (instance == fullScreenButton) { fullScreenButton.removeEventListener(MouseEvent.CLICK, fullScreenButton_clickHandler); } } /** * @private */ override protected function commitProperties():void { super.commitProperties(); // if coming from full screen mode, we reset the // pauseWhenHidden property here because of an AIR bug // that requires us to defer it. if (needsToUpdatePauseWhenHidden) { needsToUpdatePauseWhenHidden = false; pauseWhenHidden = exitingFullScreenPauseWhenHidden; } } //-------------------------------------------------------------------------- // // Methods // //-------------------------------------------------------------------------- /** * @throws TypeError If the skin hasn't been loaded and there is no videoDisplay. * * @copy spark.components.VideoDisplay#pause() * * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function pause():void { videoDisplay.pause(); } /** * @copy spark.components.VideoDisplay#play() * * @throws TypeError if the skin hasn't been loaded up yet * and there's no videoDisplay. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function play():void { //trace("play"); videoDisplay.play(); } /** * @copy spark.components.VideoDisplay#seek() * * @throws TypeError if the skin hasn't been loaded up yet * and there's no videoDisplay. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function seek(time:Number):void { videoDisplay.seek(time); } /** * @copy spark.components.VideoDisplay#stop() * * @throws TypeError if the skin hasn't been loaded up yet * and there's no videoDisplay. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 1.5 * @productversion Flex 4 */ public function stop():void { videoDisplay.stop(); } /** * @private */ private function updateScrubBar():void { if (!videoDisplay) return; if (!scrubBarMouseCaptured && !scrubBarChanging) { scrubBar.minimum = 0; scrubBar.maximum = videoDisplay.duration; scrubBar.value = videoDisplay.currentTime; } // if streaming, then we pretend to have everything in view // if progressive, then look at the bytesLoaded and bytesTotal if (!videoDisplay.videoPlayer.canLoad) scrubBar.loadedRangeEnd = videoDisplay.duration; else if (videoDisplay.bytesTotal == 0) scrubBar.loadedRangeEnd = 0; else scrubBar.loadedRangeEnd = (videoDisplay.bytesLoaded/videoDisplay.bytesTotal)*videoDisplay.duration; } /** * @private */ private function updateDuration():void { durationDisplay.text = formatTimeValue(duration); } /** * Formats a time value, specified in seconds, into a String that * gets used for currentTime and the duration. * * @param value Value in seconds of the time to format. * * @return Formatted time value. * * @langversion 3.0 * @playerversion Flash 10 * @playerversion AIR 2.5 * @productversion Flex 4.5 */ protected function formatTimeValue(value:Number):String { // default format: hours:minutes:seconds value = Math.round(value); var hours:uint = Math.floor(value/3600) % 24; var minutes:uint = Math.floor(value/60) % 60; var seconds:uint = value % 60; var result:String = ""; if (hours != 0) result = hours + ":"; if (result && minutes < 10) result += "0" + minutes + ":"; else result += minutes + ":"; if (seconds < 10) result += "0" + seconds; else result += seconds; return result; } /** * @private */ private function updateCurrentTime():void { currentTimeDisplay.text = formatTimeValue(currentTime); } /** * @private * Returns the screen bounds. * If we are on the AIR Player, we need to work around AIR Player bug #2503351 * We check if the flash.display.Screen class is defined. If so, then * we are running on the AIR Player and can access this API. */ mx_internal function getScreenBounds():Rectangle { var resultRect:Rectangle = new Rectangle(0, 0, stage.fullScreenWidth, stage.fullScreenHeight); if (screenClass) { // Get the screen where the application resides try { var nativeWindowBounds:Rectangle = stage["nativeWindow"]["bounds"]; var currentScreen:Object = screenClass["getScreensForRectangle"](nativeWindowBounds)[0]; // Return the bounds of that screen resultRect = currentScreen["bounds"]; } catch (e:Error) { } } return resultRect; } //-------------------------------------------------------------------------- // // Event handlers // //-------------------------------------------------------------------------- /** * @private */ private function videoDisplay_currentTimeChangeHandler(event:TimeEvent):void { if (scrubBar) updateScrubBar(); if (currentTimeDisplay) updateCurrentTime(); dispatchEvent(event); } /** * @private */ private function videoDisplay_bytesLoadedChangeHandler(event:LoadEvent):void { if (scrubBar) updateScrubBar(); dispatchEvent(event); } /** * @private */ private function videoDisplay_mediaPlayerStateChangeHandler(event:MediaPlayerStateChangeEvent):void { invalidateSkinState(); if (scrubBar) updateScrubBar(); if (durationDisplay) updateDuration(); if (currentTimeDisplay) updateCurrentTime(); if (playPauseButton) playPauseButton.selected = playing; //trace("mediaPlayerStateChangeHandler " + event + " state = " + event.state + " playing = " + playing); dispatchEvent(event); } /** * @private */ private function videoDisplay_durationChangeHandler(event:TimeEvent):void { if (scrubBar) updateScrubBar(); if (durationDisplay) updateDuration(); dispatchEvent(event); } /** * @private */ private function videoDisplay_volumeChangedHandler(event:Event):void { if (volumeBar) { volumeBar.value = volume; volumeBar.muted = muted; } if (muteButton) { muteButton.muted = muted; muteButton.volume = volume; } dispatchEvent(event); } /** * @private * Indicates whether we are in the full screen state or not. * We use this when determining our current skin state. */ private var fullScreen:Boolean = false; /** * @private * Holds a list of properties for the "video player state" that will * be restored when going out of fullScreen mode. */ private var beforeFullScreenInfo:Object; /** * @private * Timer, which waits for 3 seconds by default to hide the * playback controls. If there's interaction by the user, then * these playback controls are show again, and the timer will reset * and start the countdown. */ private var fullScreenHideControlTimer:Timer; /** * @private */ private function fullScreenButton_clickHandler(event:MouseEvent):void { if (!fullScreen) { // check to make sure we can go into fullscreen mode if (!systemManager.getTopLevelRoot()) return; var screenBounds:Rectangle = getScreenBounds(); fullScreen = true; // need it to go into full screen state for the skin invalidateSkinState(); // keep track of pauseWhenHidden b/c we will set it to false temporarily // so that the video does not pause when we reparent it to the top // level application var oldPauseWhenHidden:Boolean = pauseWhenHidden; // let's get it off of our layout system so it doesn't interfere with // the sizing and positioning. Then let's resize it to be // the full size of our screen. Then let's position it off-screen so // there are no other elements in the way. beforeFullScreenInfo = {parent: this.parent, x: this.x, y: this.y, explicitWidth: this.explicitWidth, explicitHeight: this.explicitHeight, percentWidth: this.percentWidth, percentHeight: this.percentHeight, isPopUp: this.isPopUp}; pauseWhenHidden = false; if (!isPopUp) { // remove from old parent if (parent is IVisualElementContainer) { var ivec:IVisualElementContainer = IVisualElementContainer(parent); beforeFullScreenInfo.childIndex = ivec.getElementIndex(this); ivec.removeElement(this); } else { beforeFullScreenInfo.childIndex = parent.getChildIndex(this); parent.removeChild(this); } // add as a popup PopUpManager.addPopUp(this, FlexGlobals.topLevelApplication as DisplayObject, false, null, moduleFactory); } // Resize the component to be the full screen of the stage. // Push the component at (0,0). It should be on top of everything // at this point because it was added as a popup setLayoutBoundsSize(screenBounds.width, screenBounds.height, true); // set the explicit width/height to make sure this value sticks regardless // of any other code or layout passes. Calling setLayoutBoundsSize() before hand // allows us to use postLayout width/height. // Setting explictWidth/Height sets percentWidth/Height to NaN. this.explicitWidth = width; this.explicitHeight = height; setLayoutBoundsPosition(0, 0, true); // this is for video performance reasons, but sometimes the videoObject isn't there // if the source is null if (videoDisplay.videoObject) { beforeFullScreenInfo.smoothing = videoDisplay.videoObject.smoothing; beforeFullScreenInfo.deblocking = videoDisplay.videoObject.deblocking; videoDisplay.videoObject.smoothing = false; videoDisplay.videoObject.deblocking = 0; } this.validateNow(); systemManager.stage.addEventListener(FullScreenEvent.FULL_SCREEN, fullScreenEventHandler); // TODO (rfrishbe): Should we make this FULL_SCREEN_INTERACTIVE if in AIR? systemManager.stage.displayState = StageDisplayState.FULL_SCREEN; pauseWhenHidden = oldPauseWhenHidden; var fullScreenHideControlsDelay:Number = getStyle("fullScreenHideControlsDelay"); if (fullScreenHideControlsDelay == 0) { playerControls.visible = false; if (volumeBar) volumeBar.closeDropDown(true); } else if (fullScreenHideControlsDelay < Infinity) { // start timer for detecting for mouse movements/clicks to hide the controls fullScreenHideControlTimer = new Timer(fullScreenHideControlsDelay, 1); fullScreenHideControlTimer.addEventListener(TimerEvent.TIMER_COMPLETE, fullScreenHideControlTimer_timerCompleteHandler, false, 0, true); // use stage or systemManager? systemManager.getSandboxRoot().addEventListener(MouseEvent.MOUSE_DOWN, resetFullScreenHideControlTimer); systemManager.getSandboxRoot().addEventListener(MouseEvent.MOUSE_MOVE, resetFullScreenHideControlTimer); systemManager.getSandboxRoot().addEventListener(MouseEvent.MOUSE_WHEEL, resetFullScreenHideControlTimer); // keyboard events don't happen when in fullScreen mode, but could be in fullScreen and interactive mode systemManager.getSandboxRoot().addEventListener(KeyboardEvent.KEY_DOWN, resetFullScreenHideControlTimer); fullScreenHideControlTimer.start(); } } else { systemManager.stage.displayState = StageDisplayState.NORMAL; } } /** * @private * After waiting a certain time perdiod, we hide the controls if no * user-interaction has occurred on-screen. */ private function fullScreenHideControlTimer_timerCompleteHandler(event:TimerEvent):void { playerControls.visible = false; if (volumeBar) volumeBar.closeDropDown(true); } /** * @private * Handles when mouse interaction happens, and we are in the fullscreen mode. This * resets the fullScreenHideControlTimer. */ private function resetFullScreenHideControlTimer(event:Event):void { playerControls.visible = true; if (fullScreenHideControlTimer) { fullScreenHideControlTimer.reset(); fullScreenHideControlTimer.start(); } else { fullScreenHideControlTimer = new Timer(getStyle("fullScreenHideControlsDelay"), 1); fullScreenHideControlTimer.addEventListener(TimerEvent.TIMER_COMPLETE, fullScreenHideControlTimer_timerCompleteHandler, false, 0, true); } } /** * @private * Handles when coming out the full screen mode */ private function fullScreenEventHandler(event:FullScreenEvent):void { // going in to full screen is handled by the // fullScreenButton_clickHandler if (event.fullScreen) return; // keep track of pauseWhenHidden b/c we will set it to false temporarily // so that the video does not pause when we reparent it to the top // level application exitingFullScreenPauseWhenHidden = pauseWhenHidden; pauseWhenHidden = false; // set the fullScreen variable back to false and remove this event listener fullScreen = false; systemManager.stage.removeEventListener(FullScreenEvent.FULL_SCREEN, fullScreenEventHandler); // remove the event listeners to hide the controls systemManager.getSandboxRoot().removeEventListener(MouseEvent.MOUSE_DOWN, resetFullScreenHideControlTimer); systemManager.getSandboxRoot().removeEventListener(MouseEvent.MOUSE_MOVE, resetFullScreenHideControlTimer); systemManager.getSandboxRoot().removeEventListener(MouseEvent.MOUSE_WHEEL, resetFullScreenHideControlTimer); systemManager.getSandboxRoot().removeEventListener(KeyboardEvent.KEY_DOWN, resetFullScreenHideControlTimer); if (fullScreenHideControlTimer) { fullScreenHideControlTimer.stop(); fullScreenHideControlTimer = null; } // make the controls visible no matter what playerControls.visible = true; // reset it so we're re-included in the layout this.x = beforeFullScreenInfo.x; this.y = beforeFullScreenInfo.y; this.explicitWidth = beforeFullScreenInfo.explicitWidth; this.explicitHeight = beforeFullScreenInfo.explicitHeight; this.percentWidth = beforeFullScreenInfo.percentWidth; this.percentHeight = beforeFullScreenInfo.percentHeight; // sometimes there's no video object currently or there might not've been a // video object when we went in to fullScreen mode. There may be no videoObject // if the source hasn't been set. if (videoDisplay.videoObject && beforeFullScreenInfo.smoothing !== undefined) { videoDisplay.videoObject.smoothing = beforeFullScreenInfo.smoothing; videoDisplay.videoObject.deblocking = beforeFullScreenInfo.deblocking; } if (!beforeFullScreenInfo.isPopUp) { // remove from top level application: PopUpManager.removePopUp(this); // add back to original parent if (beforeFullScreenInfo.parent is IVisualElementContainer) beforeFullScreenInfo.parent.addElementAt(this, beforeFullScreenInfo.childIndex); else beforeFullScreenInfo.parent.addChildAt(this, beforeFullScreenInfo.childIndex); } // want to update pauseWhenHidden, but can't do it here // b/c the AIR window thinks it's invisible at this point // if we're on a Mac (a bug), so let's just defer this check // to commitProperties(). if (exitingFullScreenPauseWhenHidden) { // if we need to set it back to true needsToUpdatePauseWhenHidden = true; invalidateProperties(); } beforeFullScreenInfo = null; invalidateSkinState(); invalidateSize(); invalidateDisplayList(); } /** * @private */ private function playButton_clickHandler(event:MouseEvent):void { if (!playing) play(); } /** * @private */ private function pauseButton_clickHandler(event:MouseEvent):void { pause(); } /** * @private */ private function stopButton_clickHandler(event:MouseEvent):void { stop(); } /** * @private */ private function playPauseButton_clickHandler(event:MouseEvent):void { if (playing) pause(); else play(); // need to synch up to what we've actually got because sometimes // the play() didn't actually play() because there's no source // or we're in an error state playPauseButton.selected = playing; } /** * @private */ private function muteButton_mutedChangeHandler(event:FlexEvent):void { muted = muteButton.muted; } /** * @private */ private function volumeBar_changeHandler(event:Event):void { if (volume != volumeBar.value) volume = volumeBar.value; } /** * @private */ private function volumeBar_mutedChangeHandler(event:FlexEvent):void { if (muted != volumeBar.muted) muted = volumeBar.muted; } /** * @private * When someone is holding the scrubBar, we don't want to update the * range's value--for this time period, we'll let the user completely * control the range. */ private var scrubBarMouseCaptured:Boolean; /** * @private * We pause the video when dragging the thumb for the scrub bar. This * stores whether we were paused or not. */ private var wasPlayingBeforeSeeking:Boolean; /** * @private * We are in the process of changing the timestamp */ private var scrubBarChanging:Boolean; /** * @private */ private function scrubBar_changeStartHandler(event:Event):void { scrubBarChanging = true; } /** * @private */ private function scrubBar_thumbPressHandler(event:TrackBaseEvent):void { scrubBarMouseCaptured = true; if (playing) { pause(); wasPlayingBeforeSeeking = true; } } /** * @private */ private function scrubBar_thumbReleaseHandler(event:TrackBaseEvent):void { scrubBarMouseCaptured = false; if (wasPlayingBeforeSeeking) { play(); wasPlayingBeforeSeeking = false; } } /** * @private */ private function scrubBar_changeHandler(event:Event):void { seek(scrubBar.value); } /** * @private */ private function scrubBar_changeEndHandler(event:Event):void { scrubBarChanging = false; } } }