/*************************************************************************
*
* ADOBE SYSTEMS INCORPORATED
* Copyright 2004-2008 Adobe Systems Incorporated
* All Rights Reserved.
*
* NOTICE: Adobe permits you to use, modify, and distribute this file in accordance with the
* terms of the Adobe license agreement accompanying it. If you have received this file from a
* source other than Adobe, then your use, modification, or distribution of it requires the prior
* written permission of Adobe.
*
**************************************************************************/
package fl.video {
import flash.events.*;
import flash.geom.Rectangle;
import flash.media.*;
import flash.net.*;
import flash.utils.*;
use namespace flvplayback_internal;
/**
* Dispatched by the VideoPlayer instance when it closes the NetConnection
* by timing out or through a call to the close()
method, or when
* you call the load()
or play()
methods or set the
* source
property and cause the RTMP connection
* to close as a result. The FLVPlayback instance dispatches this event only when
* streaming from Flash Media Server (FMS) or other Flash Video Streaming Service (FVSS).
*
*
The close
event is of type VideoEvent and has the constant
* VideoEvent.CLOSE
.
stop()
or
* pause()
methods
* or click the corresponding controls.
*
* When the application uses progressive download, it does not set the
* totalTime
* property explicitly, and it downloads an FLV file that does not specify the duration
* in the metadata. The video player sets the totalTime
property to an approximate
* total value before it dispatches this event.
The video player also dispatches the stateChange
and stopped
* events.
The complete
event is of type VideoEvent and has the constant
* VideoEvent.COMPLETE
.
info
property that contains the info object received by the
* NetStream.onCuePoint
event callback for FLV file cue points.
* For ActionScript cue points, it contains the object that was passed
* into the ActionScript cue point methods or properties.
*
* The cuePoint
event is of type MetadataEvent and has the constant
* MetadataEvent.CUE_POINT
.
info
property that contains the
* info object received by the NetStream.onMetaData
event callback.
*
* The metadataReceived
event is of type MetadataEvent and has the constant
* MetadataEvent.METADATA_RECEIVED
.
playheadUpdateInterval
property or when rewinding starts.
* The component does not dispatch this event when the video player is paused or stopped
* unless a seek occurs.
*
* The playheadUpdate
event is of type VideoEvent and has the constant
* VideoEvent.PLAYHEAD_UPDATE
.
progressInterval
property, starting
* when the load begins and ending when all bytes are loaded or there is a network error.
* The default is every 0.25 seconds starting when load is called and ending
* when all bytes are loaded or if there is a network error. Use this event to check
* bytes loaded or number of bytes in the buffer.
*
* Dispatched only for a progressive HTTP download. Indicates progress in number of
* downloaded bytes. The event object has the bytesLoaded
and bytesTotal
* properties, which are the same as the FLVPlayback properties of the same names.
The progress
event is of type VideoProgressEvent and has the constant
* VideoProgressEvent.PROGRESS
.
play()
* or load()
method. It starts only once for each FLV file that is loaded.
*
* The ready
event is of type VideoEvent and has the constant
* VideoEvent.READY
.
autoLayout
* event or calling the setScale()
or
* setSize()
methods or changing the width
, height
,
* scaleX
, and scaleY
properties.visibleVideoPlayerIndex
property is switched from one video player to another.The layout
event is of type LayoutEvent and has the constant
* LayoutEvent.LAYOUT
.
autoRewind
property is set to true
.
*
* The autoRewound
event is of type VideoEvent and has the constant
* VideoEvent.AUTO_REWOUND
.
autoRewind
call is
* completed the stateChange
event is dispatched with the rewinding
* state. The stateChange
event does not
* start until rewinding has completed.
*
* This event can be used to track when playback enters or leaves unresponsive
* states such as in the middle of connecting, resizing, or rewinding. The
* play()
, pause()
, stop()
and seek()
* methods queue the requests to be executed when the player enters
* a responsive state.
The stateChange
event is of type VideoEvent and has the constant
* VideoEvent.STATE_CHANGE
.
unsupportedPlayerVersion
* event is dispatched.
*
* The unsupportedPlayerVersion
event is of type VideoEvent and has the constant
* VideoEvent.UNSUPPORTED_PLAYER_VERSION
.
cuePoint
events occur.
*
* The FLVPlayback class wraps the VideoPlayer class. Use the FLVPlayback class in almost all cases because there is no * functionality in the VideoPlayer class that cannot be accessed using the * FLVPlayback class.
* *In version 2.5, the FLVPlayback class implements the default NCManager
* interface to access streaming FLV files on Flash Media Server. You interact with
* NCManager when you set the contentPath
property and when you pass
* a URL to the play()
and load()
methods. If you use the
* VideoPlayer class by itself, however,
* you must include the following statement in your ActionScript code :
The NCManager class implements an interface, INCManager, and it can be replaced * with a custom class for managing network communications that implements this interface. * If you do that, you also need to include the following statement, replacing NCManager * with the name of the class you have provided:
* *You do not need to add this statement if you are using the default NCManager class.
* *Note: You also can set iNCManagerClass
to replace the default
* fl.video.NCManager when using the FLVPlayback component.
To handle multiple streams for multiple bandwidths, NCManager supports a subset of * SMIL.
* * @includeExample examples/VideoPlayerExample.as -noswf * * @see NCManager * @see FLVPlayback * * @tiptext VideoPlayer class * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public class VideoPlayer extends Video { include "ComponentVersion.as" // buffer states /** * @private */ flvplayback_internal static var BUFFER_EMPTY:String = "bufferEmpty"; /** * @private */ flvplayback_internal static var BUFFER_FULL:String = "bufferFull"; /** * @private */ flvplayback_internal static var BUFFER_FLUSH:String = "bufferFlush"; // state /** * @private */ protected var _state:String; /** * @private */ flvplayback_internal var _cachedState:String; /** * @private */ flvplayback_internal var _bufferState:String; /** * @private */ flvplayback_internal var _sawPlayStop:Boolean; /** * @private */ flvplayback_internal var _cachedPlayheadTime:Number; /** * @private */ protected var _metadata:Object; /** * @private */ protected var _registrationX:Number; /** * @private */ protected var _registrationY:Number; /** * @private */ protected var _registrationWidth:Number; /** * @private */ protected var _registrationHeight:Number; /** * @private */ flvplayback_internal var _startingPlay:Boolean; /** * @private */ flvplayback_internal var _lastSeekTime:Number; /** * @private */ flvplayback_internal var _invalidSeekTime:Boolean; /** * @private */ flvplayback_internal var _invalidSeekRecovery:Boolean; /** * @private */ flvplayback_internal var _readyDispatched:Boolean; /** * @private */ flvplayback_internal var _autoResizeDone:Boolean; /** * @private */ flvplayback_internal var _lastUpdateTime:Number; /** * @private */ flvplayback_internal var lastUpdateTimeStuckCount:Number; /** * @private */ flvplayback_internal var _sawSeekNotify:Boolean; // INCManager /** * @private */ protected var _ncMgr:INCManager; /** * To make all VideoPlayer objects use your * custom class as the default INCManager implementation, set the *iNCManagerClass
property to the class object or string name
* of your custom class.
* The FLVPlayback class includes the definition
* of the custom class; the video player does not.
*
* @default "fl.video.NCManager" as a string
*
* @tiptext VideoPlayer class
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public static var iNCManagerClass:Object = "fl.video.NCManagerDynamicStream";
/**
* Registers a custom class for the NetStream's client property.
* By default, fl.video.VideoPlayerClient
is used; this class handles the onMetaData()
and onCuePoint()
messages.
* To add custom handling for other messages, such as onImageData()
and onTextData()
,
* you can create your own class and set this property to the class.
*
* The constructor for the class must take a VideoPlayer
instance as its only parameter, and it must have a Boolean ready property.
* This property should be false
while the Client is still waiting for any data messages expected at the beginning of the file.
* If the VideoPlayer does its resize autorewind before these messages are received, they may never be received.
* By default, fl.video.VideoPlayerClient
will return true
from the ready property as soon as onMetaData()
is called.
You can set the property to the class object itself (as in the example below) or the string name of the class:
*Note that setting it to the string name of the class is not enough by itself to force the class to be compiled into the SWF.
* The default value is the class object fl.video.VideoPlayerClient
, not the string name.
It is strongly recommended that any custom implementation should subclass fl.video.VideoPlayer
.
* To do otherwise risks breaking the metadata and cue point handling built into the VideoPlayer and the FLVPlayback component.
VideoError.NETSTREAM_CLIENT_CLASS_UNSET
will be thrown.
* @langversion 3.0
* @playerversion Flash 9.0.115.0
* @default fl.video.VideoPlayerClient
*/
public static var netStreamClientClass:Object = fl.video.VideoPlayerClient;
// info about NetStream
/**
* @private
*/
protected var _ns:NetStream;
/**
* @private
*/
flvplayback_internal var _currentPos:Number;
/**
* @private
*/
flvplayback_internal var _atEnd:Boolean;
/**
* @private
*/
flvplayback_internal var _atEndCheckPlayhead:Number;
/**
* @private
*/
protected var _streamLength:Number;
// store properties
/**
* @private
*/
protected var _align:String;
/**
* @private
*/
protected var _scaleMode:String;
/**
* @private
*
* If true, then video plays immediately, if false waits for
* play
to be called. Set to true if stream is
* loaded with call to play()
, false if loaded
* by call to load()
.
Even if _autoPlay
is set to false, we will start
* start loading the video after initialize()
is
* called. In the case of Flash Media Server (FMS), this means creating the stream
* and loading the first frame to display (and loading more if
* scaleMode
is
* VideoScaleMode.MAINTAIN_ASPECT_RATIO
or
* VideoScaleMode.NO_SCALE
). In the case of HTTP
* download, we will start downloading the stream and show the
* first frame.
width
and height
properties simultaneously.
* Setting the width
or height
individually
* triggers two autolayout
events whereas calling the
* setSize()
method causes only one autolayout
event.
*
* If the scaleMode
property is
* VideoScaleMode.MAINTAIN_ASPECT_RATIO
or
* VideoScaleMode.NO_SCALE
then calling this method
* triggers an immediate autolayout
event.
scaleX
and scaleY
properties simultaneously.
* Setting the scaleX
or scaleY
individually
* triggers two autolayout
events whereas calling the
* setScale()
method causes only one autolayout
event.
*
* If the scaleMode
property is
* VideoScaleMode.MAINTAIN_ASPECT_RATIO
or
* VideoScaleMode.NO_SCALE
, calling this method
* causes an immediate autolayout
event.
If the player is in an unresponsive state, queues the request.
* *Throws an exception if called with no arguments at a time when no stream
* is connected. Use the stateChange
event and the
* connected
property to determine when it is
* safe to call this method.
null
.
*
* @param totalTime Pass in the length of the FLV file. Pass in 0
or NaN
* to automatically detect the length from metadata, server, or
* XML. If the INCManager.streamLength
property is not 0
,
* null
, or undefined when the ncConnected
property is called,
* that value takes precedence over this one.
*
* @param isLive Pass in true
if streaming a live feed from Flash Media Server (FMS).
*
* @tiptext play method
*
* @see #stateResponsive
* @see #load()
*
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function play(url:String=null, totalTime:Number=NaN, isLive:Boolean=false):void {
//ifdef DEBUG
//debugTrace("play(" + url + ")");
//endif
// if new url passed, ask the INCManager to reconnect for us
if (url != null) {
if (_state == VideoState.EXEC_QUEUED_CMD) {
_state = _cachedState;
} else if (!stateResponsive && _state != VideoState.DISCONNECTED && _state != VideoState.CONNECTION_ERROR) {
queueCmd(QueuedCommand.PLAY, url, isLive, totalTime);
return;
} else {
execQueuedCmds();
}
_autoPlay = true;
_load(url, totalTime, isLive);
// playing will start automatically once stream is setup, so return.
return;
}
if (!isXnOK()) {
if ( _state == VideoState.CONNECTION_ERROR ||
_ncMgr == null || _ncMgr.netConnection == null ) {
throw new VideoError(VideoError.NO_CONNECTION);
} else {
//ifdef DEBUG
//debugTrace("RECONNECTING!!!");
//endif
flushQueuedCmds();
queueCmd(QueuedCommand.PLAY);
setState(VideoState.LOADING);
_cachedState = VideoState.LOADING;
_ncMgr.reconnect();
// playing will start automatically once stream is setup, so return.
return;
}
} else if (_state == VideoState.EXEC_QUEUED_CMD) {
_state = _cachedState;
} else if (!stateResponsive) {
queueCmd(QueuedCommand.PLAY);
return;
} else {
execQueuedCmds();
}
// recreate stream if necessary (this will never happen with
// http download, just rtmp)
if (_ns == null) {
_createStream();
}
switch (_state) {
case VideoState.BUFFERING:
if (_ncMgr.isRTMP) {
_play(0);
if (_atEnd) {
_atEnd = false;
_currentPos = 0;
setState(VideoState.REWINDING);
} else if (_currentPos > 0) {
_seek(_currentPos);
_currentPos = 0;
}
}
// no break
case VideoState.PLAYING:
// already playing
return;
case VideoState.STOPPED:
if (_ncMgr.isRTMP) {
if (_isLive) {
_play(-1);
setState(VideoState.BUFFERING);
} else {
_play(0);
if (_atEnd) {
_atEnd = false;
_currentPos = 0;
_state = VideoState.BUFFERING;
setState(VideoState.REWINDING);
} else if (_currentPos > 0) {
_seek(_currentPos);
_currentPos = 0;
setState(VideoState.BUFFERING);
} else {
setState(VideoState.BUFFERING);
}
}
} else {
_pause(false);
if (_atEnd) {
_atEnd = false;
_seek(0);
_state = VideoState.BUFFERING;
setState(VideoState.REWINDING);
} else {
if (_bufferState == BUFFER_EMPTY) {
setState(VideoState.BUFFERING);
} else {
setState(VideoState.PLAYING);
}
}
}
break;
case VideoState.PAUSED:
_pause(false);
if (!_ncMgr.isRTMP) {
if (_bufferState == BUFFER_EMPTY) {
setState(VideoState.BUFFERING);
} else {
setState(VideoState.PLAYING);
}
} else {
setState(VideoState.BUFFERING);
}
break;
} // switch
}
/**
* Plays a stream using the Dynamic Streaming feature. You will need to create a new
* DynamicStreamItem and pass that as an argument in play2. The component will then
* automatically switch between the available bit rates passed in with the streams to
* play the most appropriate stream bit rate for the users available bandwidth at that time.
*
* @param dsi A DynamicStreamItem object containing the URI, streams and stream bit rates.
*
*/
public function play2(dsi:DynamicStreamItem):void {
var nc:INCManager = this.ncMgr;
_prevVideoWidth = super.videoWidth;
_prevVideoHeight = super.videoHeight;
// reset state
_autoResizeDone = false;
_cachedPlayheadTime = 0;
_bufferState = BUFFER_EMPTY;
_sawPlayStop = false;
_metadata = null;
_startingPlay = false;
_invalidSeekTime = false;
_invalidSeekRecovery = false;
_contentPath = "";
_currentPos = 0;
_streamLength = NaN;
_atEnd = false;
_readyDispatched = false;
_lastUpdateTime = NaN;
lastUpdateTimeStuckCount = 0;
_sawSeekNotify = false;
waitingForEnough = false;
baselineProgressTime = NaN;
startProgressTime = NaN;
totalDownloadTime = NaN;
totalProgressTime = NaN;
_httpDoSeekCount = 0;
// must stop ALL intervals here
_updateTimeTimer.reset();
_updateProgressTimer.reset();
_idleTimeoutTimer.reset();
_autoResizeTimer.reset();
_rtmpDoStopAtEndTimer.reset();
_rtmpDoSeekTimer.reset();
_httpDoSeekTimer.reset();
_finishAutoResizeTimer.reset();
_delayedBufferingTimer.reset();
// close netstream
closeNS(false);
if(dsi.start == -1){
_autoPlay = false;
_isLive = true;
_updateProgressTimer.start();
}
nc.connectDynamicStream(dsi);
_streamLength = NaN;
setState(VideoState.LOADING);
_cachedState = VideoState.LOADING;
}
/**
* Plays the FLV file when enough of it has downloaded. If the FLV file has downloaded
* or you are streaming from Flash Media Server (FMS), then calling the playWhenEnoughDownloaded()
* method is identical to the play()
method with no parameters. Calling
* this method does not pause playback, so in many cases, you may want to call
* the pause()
method before you call this method.
*
* @tiptext playWhenEnoughDownloaded method
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function playWhenEnoughDownloaded():void {
if (_ncMgr != null && _ncMgr.isRTMP) {
play();
return;
}
if (!isXnOK()) {
throw new VideoError(VideoError.NO_CONNECTION);
} else if (_state == VideoState.EXEC_QUEUED_CMD) {
_state = _cachedState;
} else if (!stateResponsive) {
queueCmd(QueuedCommand.PLAY_WHEN_ENOUGH);
return;
} else {
execQueuedCmds();
}
waitingForEnough = true;
checkReadyForPlay(bytesLoaded, bytesTotal);
}
/**
* Similar to the play()
method, but causes the FLV file
* to load without playing. Autoresizing occurs if appropriate, and the first
* frame of the FLV file is shown.
* After initial loading and autolayout, the state is VideoState.PAUSED
.
*
* This method takes the same parameters as the play()
method,
* but you cannot call the load()
method without a URL.
* If you do, an error is thrown. If the video player is in an unresponsive state,
* the load()
method queues the request.
null URL sent to VideoPlayer.load
.
*
* @param totalTime The length of an FLV file. Pass in 0, null
, or
* undefined to automatically detect length from metadata, server, or XML.
*
* @param isLive The value is true
if you stream a live feed from Flash Media Server (FMS).
*
* @see #play()
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function load(url:String, totalTime:Number=NaN, isLive:Boolean=false):void {
if (url == null) {
throw new VideoError(VideoError.NULL_URL_LOAD);
}
//ifdef DEBUG
//debugTrace("load(" + url + ")");
//endif
if (_state == VideoState.EXEC_QUEUED_CMD) {
_state = _cachedState;
} else if (!stateResponsive && _state != VideoState.DISCONNECTED && _state != VideoState.CONNECTION_ERROR) {
queueCmd(QueuedCommand.LOAD, url, isLive, totalTime);
return;
} else {
execQueuedCmds();
}
_autoPlay = false;
_load(url, totalTime, isLive);
}
/**
* Does loading work for play and load.
*
* @private
*/
flvplayback_internal function _load(url:String, totalTime:Number, isLive:Boolean):void {
//ifdef DEBUG
//debugTrace("_load(" + url + ", " + isLive + ", " + totalTime + ")");
//endif
_prevVideoWidth = super.videoWidth;
_prevVideoHeight = super.videoHeight;
// reset state
_autoResizeDone = false;
_cachedPlayheadTime = 0;
_bufferState = BUFFER_EMPTY;
_sawPlayStop = false;
_metadata = null;
_startingPlay = false;
_invalidSeekTime = false;
_invalidSeekRecovery = false;
_isLive = isLive;
_contentPath = url;
_currentPos = 0;
_streamLength = (isNaN(totalTime) || totalTime <= 0) ? NaN : totalTime;
_atEnd = false;
_readyDispatched = false;
_lastUpdateTime = NaN;
lastUpdateTimeStuckCount = 0;
_sawSeekNotify = false;
waitingForEnough = false;
baselineProgressTime = NaN;
startProgressTime = NaN;
totalDownloadTime = NaN;
totalProgressTime = NaN;
_httpDoSeekCount = 0;
// must stop ALL intervals here
_updateTimeTimer.reset();
_updateProgressTimer.reset();
_idleTimeoutTimer.reset();
_autoResizeTimer.reset();
_rtmpDoStopAtEndTimer.reset();
_rtmpDoSeekTimer.reset();
_httpDoSeekTimer.reset();
_finishAutoResizeTimer.reset();
_delayedBufferingTimer.reset();
// close netstream
closeNS(false);
// if returns false, wait for a "connected" message and
// then do these things
if (_ncMgr == null) {
createINCManager();
}
var instantConnect:Boolean = _ncMgr.connectToURL(_contentPath);
setState(VideoState.LOADING);
_cachedState = VideoState.LOADING;
if (instantConnect) {
_createStream();
_setUpStream();
}
if (!_ncMgr.isRTMP) {
_updateProgressTimer.start();
}
}
/**
* Pauses video playback. If video is paused or stopped, has
* no effect. To start playback again, call play()
.
* Takes no parameters.
*
* If player is in an unresponsive state, the pause()
method
* queues the request.
Throws an exception if called when no stream is
* connected. Use the stateChange
event and
* connected
property to determine when it is
* safe to call this method.
If the player is in a stopped state, a call to the pause()
* method has no effect and the player remains in a stopped state.
autoRewind
is set to
* true
, rewinds to first frame. If video is already
* stopped, has no effect. To start playback again, call
* play()
. Takes no parameters.
*
* If player is in an unresponsive state, queues the request.
* *Throws an exception if called when no stream is
* connected. Use the stateChange
event and
* connected
property to determine when it is
* safe to call this method.
The playheadTime
property might not have the expected value
* immediately after you call one of the seek methods or set
* playheadTime
to cause seeking. For a progressive download,
* you can seek only to a keyframe; therefore, a seek takes you to the
* time of the first keyframe after the specified time.
Note: When streaming, a seek always goes to the precise specified * time even if the source FLV file doesn't have a keyframe there.
* *Seeking is asynchronous, so if you call a seek method or set the
* playheadTime
property, playheadTime
does not update immediately.
* To obtain the time after the seek is complete, listen for the seek
event,
* which does not start until the playheadTime
property is updated.
Throws an exception if called when no stream is
* connected. Use the stateChange
event and
* the connected
property to determine when it is
* safe to call this method.
NaN
.
* @see #stateResponsive
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function seek(time:Number):void {
//ifdef DEBUG
//debugTrace("seek:"+time);
//endif
// we do not allow more seeks until we are out of an invalid seek time state
if (_invalidSeekTime) return;
if (isNaN(time) || time < 0) throw new VideoError(VideoError.INVALID_SEEK);
if (!isXnOK()) {
if ( _state == VideoState.CONNECTION_ERROR ||
_ncMgr == null || _ncMgr.netConnection == null ) {
throw new VideoError(VideoError.NO_CONNECTION);
} else {
//ifdef DEBUG
//debugTrace("RECONNECTING!!!");
//endif
flushQueuedCmds();
queueCmd(QueuedCommand.SEEK, null, false, time);
setState(VideoState.LOADING);
_cachedState = VideoState.LOADING;
_ncMgr.reconnect();
// playing will start automatically once stream is setup, so return.
return;
}
} else if (_state == VideoState.EXEC_QUEUED_CMD) {
_state = _cachedState;
} else if (!stateResponsive) {
queueCmd(QueuedCommand.SEEK, null, false, time);
return;
} else {
execQueuedCmds();
}
// recreate stream if necessary (this will never happen with
// http download, just rtmp)
if (_ns == null) {
_createStream();
}
if (_atEnd && time < playheadTime) {
_atEnd = false;
}
switch (_state) {
case VideoState.PLAYING:
_state = VideoState.BUFFERING;
// no break;
case VideoState.BUFFERING:
case VideoState.PAUSED:
_seek(time);
setState(VideoState.SEEKING);
break;
case VideoState.STOPPED:
if (_ncMgr.isRTMP) {
_play(0);
_pause(true);
}
_seek(time);
_state = VideoState.PAUSED;
setState(VideoState.SEEKING);
break;
}
}
/**
* Forces the video stream and Flash Media Server connection to close. This
* method triggers the close
event. You usually do not need to call this
* method directly, because the idle timeout functionality takes care of closing the stream.
*
* @see #idleTimeout
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function close():void {
//ifdef DEBUG
//debugTrace("close()");
//endif
closeNS(true);
// never makes sense to close an http NetConnection, it doesn't really maintain
// any kind of network connection!
if (_ncMgr != null && _ncMgr.isRTMP) {
_ncMgr.close();
}
setState(VideoState.DISCONNECTED);
dispatchEvent(new VideoEvent(VideoEvent.CLOSE, false, false, _state, playheadTime));
}
//
// public getters, setters
//
/**
* A number that is the horizontal scale.
*
* @default 1
* @see #setScale()
* @see #scaleY
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public override function set scaleX(xs:Number):void {
super.scaleX = xs;
_registrationWidth = width;
switch (_scaleMode) {
case VideoScaleMode.MAINTAIN_ASPECT_RATIO:
case VideoScaleMode.NO_SCALE:
startAutoResize();
break;
}
}
/**
* A number that is the vertical scale.
*
* @default 1
* @see #setScale()
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public override function set scaleY(ys:Number):void {
super.scaleY = ys;
_registrationHeight = height;
switch (_scaleMode) {
case VideoScaleMode.MAINTAIN_ASPECT_RATIO:
case VideoScaleMode.NO_SCALE:
startAutoResize();
break;
}
}
/**
* A number that specifies the horizontal position (in pixels) of the video player.
*
* Setting the x
property also affects the registrationX
property.
* When either the x
or registrationX
property is set,
* the second property is changed to maintain its offset from the
* first. For example, if x
= 10 and registrationX
= 20, setting
* x
= 110 also sets registrationX
= 120.
Setting the y
property also affects the registrationY
property.
* When either the y
or registrationY
property is set,
* the second property is changed to maintain its offset from the
* first. For example, if y
= 10 and registrationY
= 20, setting
* y
= 110 also sets registrationY
= 120.
Note: The flash.media.Video.width
property is similar to the
* fl.video.VideoPlayer.videoWidth
property.
Note: Do not confuse this property with the
* flash.media.Video.height
property which is similar to the
* fl.video.VideoPlayer.videoHeight
property.
x
property,
* which reflects the actual location of the video content.
*
* Example 1, load an 80x80 FLV file with the following settings: *
registrationX
= 100registrationY
= 100registrationWidth
= 60registrationHeight
= 40align
= VideoAlign.CENTER
scaleMode
= VideoScaleMode.NO_SCALE
x
= 90y
= 80width
= 80height
= 80Example 2, load the same scenario as example 1 but with the following settings: *
scaleMode
= VideoScaleMode.MAINTAIN_ASPECT_RATIO
x
= 110y
= 100width
= 40height
= 80Example 3, load the same scenario as example 2 but with the following settings: *
scaleMode
= VideoScaleMode.EXACT_FIT
x
= 100y
= 100width
= 60height
= 40When either the x
or registrationX
* property is set, the second property is changed to maintain its
* offset from the first. For example, if x
= 10 and
* registrationX
= 20, setting x
= 110 also
* sets registrationX
= 120.
y
property,
* which reflects the actual location of the video content.
*
* Example 1, load an 80x80 FLV file with the following settings: *
registrationX
= 100registrationY
= 100registrationWidth
= 60registrationHeight
= 40align
= VideoAlign.CENTER
scaleMode
= VideoScaleMode.NO_SCALE
x
= 90y
= 80width
= 80height
= 80Example 2, load the same scenario as example 1 but with the following settings: *
scaleMode
= VideoScaleMode.MAINTAIN_ASPECT_RATIO
x
= 110y
= 100width
= 40height
= 80Example 3, load the same scenario as example 2 but with the following settings: *
scaleMode
= VideoScaleMode.EXACT_FIT
x
= 100y
= 100width
= 60height
= 40When either the y
or registrationY
* property is set, the second property is changed to maintain its
* offset from the first. For example, if y
= 10 and
* registrationY
= 20, setting y
= 110 also
* sets registrationY
= 120.
registrationWidth
property
* with the width
property. The width
* property reflects the actual width of the video content.
*
* Example 1, load an 80x80 FLV file with the following settings: *
registrationX
= 100registrationY
= 100registrationWidth
= 60registrationHeight
= 40align
= VideoAlign.CENTER
scaleMode
= VideoScaleMode.NO_SCALE
x
= 90y
= 80width
= 80height
= 80Example 2, load the same scenario as example 1 but with the following settings: *
scaleMode
= VideoScaleMode.MAINTAIN_ASPECT_RATIO
x
= 110y
= 100width
= 40height
= 80Example 3, load the same scenario as example 2 but with the following settings: *
scaleMode
= VideoScaleMode.EXACT_FIT
x
= 100y
= 100width
= 60height
= 40Setting the registrationWidth
property is
* equivalent to setting the width
property and vice
* versa. Setting any other property or calling any method that
* alters the width, such as scaleX
,
* setSize
, and setScale
, also keeps
* width
and registrationWidth
in sync.
registrationHeight
property
* with the height
property. The height
* property reflects the actual height of the video content.
*
* Example 1, load an 80x80 FLV file with the following settings: *
registrationX
= 100registrationY
= 100registrationWidth
= 60registrationHeight
= 40align
= VideoAlign.CENTER
scaleMode
= VideoScaleMode.NO_SCALE
x
= 90y
= 80width
= 80height
= 80Example 2, load the same scenario as example 1 but with the following settings: *
scaleMode
= VideoScaleMode.MAINTAIN_ASPECT_RATIO
x
= 110y
= 100width
= 40height
= 80Example 3, load the same scenario as example 2 but with the following settings: *
scaleMode
= VideoScaleMode.EXACT_FIT
x
= 100y
= 100width
= 60height
= 40Setting the registrationHeight
property is
* equivalent to setting the height
property and vice
* versa. Setting any other property or calling any method that
* alters the height, such as scaleX
,
* setSize
, and setScale
, setting keeps
* height
and registrationHeight
in sync.
true
, makes the VideoPlayer instance visible.
* If false
, it makes the instance invisible.
*
* @default true
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public override function get visible():Boolean {
if (!_hiddenForResize) __visible = super.visible;
return __visible;
}
/**
* @private (setter)
*/
public override function set visible(v:Boolean):void {
__visible = v;
if (!_hiddenForResize) super.visible = __visible;
}
/**
* Specifies how the video is displayed relative to the
* registrationX
, registrationY
,
* registrationWidth
and
* registrationHeight
properties. The align
property does
* this autolayout when the scaleMode
property is set to
* VideoScaleMode.MAINTAIN_ASPECT_RATIO
or
* VideoScaleMode.NO_SCALE
. Changing this property
* after an FLV file is loaded causes an automatic layout to
* start immediately.
* Values come
* from the VideoAlign class.
*
* @default VideoAlign.CENTER
*
* @see #registrationX
* @see #registrationY
* @see #registrationWidth
* @see #registrationHeight
* @see #scaleMode
* @see VideoAlign
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get align():String {
return _align;
}
/**
* @private (setter)
*/
public function set align(s:String):void {
if (_align != s) {
// check for valid value
switch (s) {
case VideoAlign.CENTER:
case VideoAlign.TOP:
case VideoAlign.LEFT:
case VideoAlign.BOTTOM:
case VideoAlign.RIGHT:
case VideoAlign.TOP_LEFT:
case VideoAlign.TOP_RIGHT:
case VideoAlign.BOTTOM_LEFT:
case VideoAlign.BOTTOM_RIGHT:
break;
default:
// just ignore bad values, no error
return;
}
_align = s;
switch (_scaleMode) {
case VideoScaleMode.MAINTAIN_ASPECT_RATIO:
case VideoScaleMode.NO_SCALE:
startAutoResize();
break;
}
}
}
/**
* Specifies how the video resizes after loading. If set to
* VideoScaleMode.MAINTAIN_ASPECT_RATIO
, maintains the
* video aspect ratio within the rectangle defined by
* registrationX
, registrationY
,
* registrationWidth
and
* registrationHeight
. If set to
* VideoScaleMode.NO_SCALE
, causes the video to size automatically
* to the dimensions of the source FLV file. If set to
* VideoScaleMode.EXACT_FIT
, causes the dimensions of
* the source FLV file to be ignored and the video is stretched to
* fit the rectangle defined by
* registrationX
, registrationY
,
* registrationWidth
and
* registrationHeight
. If this is set
* after an FLV file has been loaded an automatic layout will start
* immediately. Values come from
* VideoScaleMode
.
*
* @see VideoScaleMode
* @default VideoScaleMode.MAINTAIN_ASPECT_RATIO
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get scaleMode():String {
return _scaleMode;
}
/**
* @private (setter)
*/
public function set scaleMode(s:String):void {
if (_scaleMode != s) {
// check for valid value
switch (s) {
case VideoScaleMode.MAINTAIN_ASPECT_RATIO:
case VideoScaleMode.NO_SCALE:
case VideoScaleMode.EXACT_FIT:
break;
default:
// just ignore bad values, no error
return;
}
if ( _scaleMode == VideoScaleMode.EXACT_FIT && _resizeImmediatelyOnMetadata &&
(_videoWidth < 0 || _videoHeight < 0 ) ) {
_resizeImmediatelyOnMetadata = false;
}
_scaleMode = s;
startAutoResize();
}
}
/**
* A Boolean value that, if true
, causes the FLV file to rewind to
* Frame 1 when play stops, either because the player reached the end of the
* stream or the stop()
method was called. This property is
* meaningless for live streams.
*
* @default false
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get autoRewind():Boolean {
return _autoRewind;
}
/**
* @private (setter)
*/
public function set autoRewind(flag:Boolean):void {
_autoRewind = flag;
}
/**
* A number that is the current playhead time or position, measured in seconds,
* which can be a fractional value. Setting this property triggers a seek and
* has all the restrictions of a seek.
*
* When the playhead time changes, which includes once every .25 seconds
* while the FLV file plays, the component dispatches the playheadUpdate
* event.
For several reasons, the playheadTime
property might not have the expected
* value immediately after calling one of the seek methods or setting playheadTime
* to cause seeking. First, for a progressive download, you can seek only to a
* keyframe, so a seek takes you to the time of the first keyframe after the
* specified time. (When streaming, a seek always goes to the precise specified
* time even if the source FLV file doesn't have a keyframe there.) Second,
* seeking is asynchronous, so if you call a seek method or set the
* playheadTime property, playheadTime
does not update immediately.
* To obtain the time after the seek is complete, listen for the seek
event,
* which does not fire until the playheadTime
property has updated.
If you set this property through the Component inspector or the Property inspector,
* the FLV file begins loading and playing at the next enterFrame
event.
* The delay provides time to set the isLive
, autoPlay
,
* and cuePoints
properties,
* among others, which affect loading. It also allows ActionScript that is placed
* on the first frame to affect the FLVPlayback component before it starts playing.
If you set this property through ActionScript, it immediately calls the
* VideoPlayer.load()
method when the autoPlay
property is
* set to false
. Alternatively, it calls the VideoPlayer.play()
method when
* the autoPlay
property is set to true
. The autoPlay
,
* totalTime
, and isLive
properties affect how the new FLV file is
* loaded, so if you set these properties, you must set them before setting the
* source
property.
Set the autoPlay
property to false
to prevent the new
* FLV file from playing automatically.
NetStream.soundTransform
property to expose
* more sound control. Set the property to change the settings;
* use the getter accessor method of the property to retrieve
* the current settings.
*
* @see #volume
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get soundTransform():SoundTransform {
if (_ns != null) _soundTransform = _ns.soundTransform;
var st:SoundTransform = new SoundTransform();
st.volume = (_hiddenForResize) ? _volume : _soundTransform.volume;
st.leftToLeft = _soundTransform.leftToLeft;
st.leftToRight = _soundTransform.leftToRight;
st.rightToLeft = _soundTransform.rightToLeft;
st.rightToRight = _soundTransform.rightToRight;
return st;
}
/**
* @private (setter)
*/
public function set soundTransform(st:SoundTransform):void {
if (st == null) return;
if (_hiddenForResize) {
_volume = st.volume;
}
_soundTransform = new SoundTransform();
_soundTransform.volume = (_hiddenForResize) ? 0 : st.volume;
_soundTransform.leftToLeft = st.leftToLeft;
_soundTransform.leftToRight = st.leftToRight;
_soundTransform.rightToLeft = st.rightToLeft;
_soundTransform.rightToRight = st.rightToRight;
if (_ns != null) _ns.soundTransform = _soundTransform;
}
/**
* A Boolean value that is true
if the FLV file is streaming from Flash Media Server (FMS) using RTMP.
* Its value is false
for any other FLV file source.
*
* @see FLVPlayback#isRTMP
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get isRTMP():Boolean {
if (_ncMgr == null) return false;
return _ncMgr.isRTMP;
}
/**
* A Boolean value that is true
if the video stream is live. This property
* is effective only when streaming from a video server, such as Flash Media Server or other Flash Video Streaming Service. The value of this
* property is ignored for an HTTP download.
*
* Set the isLive
property to false
when sending a prerecorded video
* stream to the video player and to true
when sending real-time data
* such as a live broadcast. For better performance when you set
* the isLive
property to false
, do not set the
* bufferTime
property to 0
.
load()
, play()
, stop()
, pause()
,
* and seek()
methods.
*
* The possible values for the state property are: buffering
,
* connectionError
, disconnected
, loading
,
* paused
, playing
, rewinding
, seeking
,
* and stopped
. You can use the FLVPlayback class properties to test for
* these states.
true
if the state is responsive. If the state is
* unresponsive, calls to the play()
, load()
, stop()
,
* pause()
, and seek()
* methods are queued and executed later, when the state changes to a
* responsive one. Because these calls are queued and executed later,
* it is usually not necessary to track the value of the stateResponsive
* property. The responsive states are:
* stopped
, playing
, paused
, and buffering
.
*
* @see FLVPlayback#stateResponsive
* @see VideoState#DISCONNECTED
* @see VideoState#STOPPED
* @see VideoState#PLAYING
* @see VideoState#PAUSED
* @see VideoState#LOADING
* @see VideoState#RESIZING
* @see VideoState#CONNECTION_ERROR
* @see VideoState#REWINDING
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get stateResponsive():Boolean {
switch (_state) {
case VideoState.STOPPED:
case VideoState.PLAYING:
case VideoState.PAUSED:
case VideoState.BUFFERING:
return true;
default:
return false;
}
}
/**
* A number that indicates the extent of downloading, in number of bytes, for an
* HTTP download. Returns 0 when there
* is no stream, when the stream is from Flash Media Server (FMS), or if the information
* is not yet available. The returned value is useful only for an HTTP download.
*
* @tiptext Number of bytes already loaded
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get bytesLoaded():uint {
if (_ns == null || _ncMgr.isRTMP) return uint.MIN_VALUE;
return _ns.bytesLoaded;
}
/**
* A number that specifies the total number of bytes downloaded for an HTTP download.
* Returns -1 when there is no stream, when the stream is from Flash Media Server (FMS), or if
* the information is not yet available. The returned value is useful only
* for an HTTP download.
*
* @tiptext Number of bytes to be loaded
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get bytesTotal():uint {
if (_ns == null || _ncMgr.isRTMP) return uint.MAX_VALUE;
return _ns.bytesTotal;
}
/**
* A number that is the total playing time for the video in seconds.
*
* When streaming from Flash Media Server (FMS) and using the default
* NCManager
, this value is determined
* automatically by server-side application programming interfaces (APIs), and that value
* overrides anything set through this property or gathered
* from metadata. The property is ready for reading when the
* stopped
or playing
state is reached after setting the
* source
property. This property is meaningless for live streams
* from an FMS.
With an HTTP download, the value is determined * automatically if the FLV file has metadata embedded; otherwise, * set it explicitly, or it will be NaN. If you set it * explicitly, the metadata value in the stream is * ignored.
* *When you set this property, the value takes effect for the next
* FLV file that is loaded by setting source
. It has no effect
* on an FLV file that has already loaded. Also, this property does not return
* the new value passed in until an FLV file is loaded.
Playback still works if this property is never set (either * explicitly or automatically), but it can cause problems * with seek controls.
* *Unless set explicitly, the value will be NaN until it is set to a valid value from metadata.
* * @see #source * @tiptext The total length of the FLV in seconds * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get totalTime():Number { return _streamLength; } /** * A number that specifies the number of seconds to buffer in memory before * beginning to play a video stream. For FLV files streaming over RTMP, * which are not downloaded and buffer only in memory, it can be important * to increase this setting from the default value of 0.1. For a progressively * downloaded FLV file over HTTP, there is little benefit to increasing this * value although it could improve viewing a high-quality video on an older, * slower computer. * *For prerecorded (not live) video, do not set the bufferTime
* property to 0
; use the default buffer time or increase the buffer
* time.
This property does not specify the amount of the FLV file to download before * starting playback.
* * @see FLVPlayback#bufferTime * @see #isLive * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get bufferTime():Number { if (_ns != null) _bufferTime = _ns.bufferTime; return _bufferTime; } /** * @private (setter) */ public function set bufferTime(aTime:Number):void { _bufferTime = aTime; if (_ns != null) { _ns.bufferTime = _bufferTime; } } /** * This property is the amount of seconds that the VideoPlayer will append * to an ongoing live stream when it is being watched in DVR mode. If the total * duration of the DVR stream is not made available from the server, the * VideoPlayer will continually append this value in minutes when the current * recorded duration is within the dvrIncrementVariance of the perpetual total * duration of the stream. * * @see #isDVR * @see #dvrIncrementVariance * */ public function get dvrIncrement():Number { return _dvrIncrement; } /** * @private (setter) */ public function set dvrIncrement(increment:Number):void { if(increment > 60) { _dvrIncrement = increment; if(_dvrIncrementVariance > _dvrIncrement) { _dvrIncrementVariance = increment/2; } } } /** * The difference threshold, in seconds, between the current duration * and total duration of a DVR stream. When this value is reached, it will * trigger a call to Flash Media Server to return the current and total * duration of a stream. If the total duration of the stream is unknown, * the component will append the value of the dvrIncrement to the current * duration and call FMS again when the difference threshold is reached again. * * @see #isDVR * @see #dvrIncrement * */ public function get dvrIncrementVariance():Number { return _dvrIncrementVariance; } /** * @private (setter) */ public function set dvrIncrementVariance(variance:Number):void { if(variance > 0 && variance < _dvrIncrement-60) { _dvrIncrementVariance = variance; } } /** * In the event a DVR stream may run beyond the total duration defined * by Flash Media Server, enabling the dvrFixedDuration will force it to * stop playing when the total duration is reached. If disabled, the value * of dvrIncrement will be appended to the end of the stream. This property * is ignored when the total duration is not given by Flash Media Server. * * @see #isDVR * @see #dvrIncrement * @see #dvrIncrementVariance * */ public function get dvrFixedDuration():Boolean { return _dvrFixedDuration; } /** * @private (setter) */ public function set dvrFixedDuration(fixed:Boolean):void { _dvrFixedDuration = fixed; } /** * When a DVR stream is played it will by default begin playing at the beginning * of the stream recording. Enabling this will move the playhead of the stream * to the latest live data produced by the server. * * @see #isDVR * */ public function get dvrSnapToLive():Boolean { return _dvrSnapToLive; } /** * @private (setter) */ public function set dvrSnapToLive(snapToLive:Boolean):void { _dvrSnapToLive = snapToLive; } /** * The amount of time, in milliseconds, before Flash terminates an idle connection * to a video server, such as Flash Media Server, because playing paused or stopped. * This property has no effect on an * FLV file downloading over HTTP. * *If this property is set when a video stream is already idle, it restarts the * timeout period with the new value.
* * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get idleTimeout():Number { return _idleTimeoutTimer.delay; } /** * @private (setter) */ public function set idleTimeout(aTime:Number):void { _idleTimeoutTimer.delay = aTime; } /** * A Boolean value that enables the DVR functionality when a live stream is * being recorded by Flash Media Server. * * @see VideoPlayer#isDVR * * @langversion 3.0 * @playerversion Flash 10.0.0.0 */ public function get isDVR():Boolean { return _isDVR; } /** * @private (setter) */ public function set isDVR(dvr:Boolean):void { if(dvr && _isLive) { _isLive = false; } _isDVR = dvr; } /** * A number that is the amount of time, in milliseconds, between each *playheadUpdate
event. Setting this property while the FLV file is
* playing restarts the timer.
*
* Because ActionScript cue points start on playhead updates, lowering
* the value of the playheadUpdateInterval
property can increase the accuracy
* of ActionScript cue points.
Because the playhead update interval is set by a call to the global
* setInterval()
method, the update cannot fire more frequently than the
* SWF file frame rate, as with any interval that is set this way.
* So, as an example, for the default frame rate of 12 frames per second,
* the lowest effective interval that you can create is approximately
* 83 milliseconds, or one second (1000 milliseconds) divided by 12.
progress
event. If you set this property while the video
* stream is playing, the timer restarts.
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function get progressInterval():Number {
return _updateProgressTimer.delay;
}
/**
* @private (setter)
*/
public function set progressInterval(aTime:Number):void {
_updateProgressTimer.delay = aTime;
}
/**
* An INCManager object that provides access to an instance of the class implementing
* INCManager
, which is an interface to the NCManager class.
*
* You can use this property to implement a custom INCManager that requires * custom initialization.
* * @see FLVPlayback#ncMgr * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get ncMgr():INCManager { if (_ncMgr == null) createINCManager(); return _ncMgr; } /** * Allows direct access to the NetConnection instance created by the video player. * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get netConnection():NetConnection { if (_ncMgr != null) return _ncMgr.netConnection; return null; } /** * Allows direct access to the NetStream instance created by the video player. * * @langversion 3.0 * @playerversion Flash 9.0.28.0 */ public function get netStream():NetStream { return _ns; } /** * * An object that is a metadata information packet that is received from a call to * theNetSteam.onMetaData()
callback method, if available.
* Ready when the metadataReceived
event is dispatched.
*
* If the FLV file is encoded with the Flash 8 encoder, the metadata
* property contains the following information. Older FLV files contain
* only the height
, width
, and duration
values.
Parameter | Description |
---|---|
canSeekToEnd | A Boolean value that is true if the FLV file is encoded with a keyframe on the last frame that allows seeking to the end of a progressive download movie clip. It is false if the FLV file is not encoded with a keyframe on the last frame. |
cuePoints | An array of objects, one for each cue point embedded in the FLV file. Value is undefined if the FLV file does not contain any cue points. Each object has the following properties:
*
*
|
audiocodecid | A number that indicates the audio codec (code/decode technique) that was used. |
audiodelay | A number that represents time 0 in the source file from which the FLV file was encoded.
* Video content is delayed for the short period of time that is required to synchronize the audio. For example, if the Note that the FLVPlayback and VideoPlayer classes compensate for this delay in their time settings. This means that you can continue to use the time settings that you used in your the source file. |
audiodatarate | A number that is the kilobytes per second of audio. |
videocodecid | A number that is the codec version that was used to encode the video. |
framerate | A number that is the frame rate of the FLV file. |
videodatarate | A number that is the video data rate of the FLV file. |
height | A number that is the height of the FLV file. |
width | A number that is the width of the FLV file. |
duration | A number that specifies the duration of the FLV file in seconds. |
playheadUpdateInterval
to send playheadUpdate
* events. Events only sent when playhead is moving, sent every
* 0.25 seconds by default.
*
* @private
*/
flvplayback_internal function doUpdateTime(e:TimerEvent=null):void {
//ifdef DEBUG
////debugTrace("doUpdateTime()");
//endif
var theTime:Number = playheadTime;
if (theTime != _atEndCheckPlayhead) {
_atEndCheckPlayhead = NaN;
}
// stop interval if we are stopped or paused
switch (_state) {
case VideoState.STOPPED:
case VideoState.DISCONNECTED:
case VideoState.CONNECTION_ERROR:
_updateTimeTimer.stop();
break;
case VideoState.PAUSED:
if(!_isDVR) {
_updateTimeTimer.stop();
}
break;
case VideoState.PLAYING:
case VideoState.BUFFERING:
// if all is downloaded and we are playing and we are stalled,
// then we might have gotten stopped without getting a
// NetStream.Play.Stop NetStatus event
if (_ncMgr != null && !_ncMgr.isRTMP && _lastUpdateTime == theTime &&
_ns != null && _ns.bytesLoaded == _ns.bytesTotal ) {
if (lastUpdateTimeStuckCount > lastUpdateTimeStuckCountMax) {
lastUpdateTimeStuckCount = 0;
httpDoStopAtEnd();
} else {
lastUpdateTimeStuckCount++;
}
}
}
if(_isDVR && _dvrMgr != null && _dvrPlaying){
if((_streamLength - _dvrMgr.currentDuration < _dvrIncrementVariance) && _dvrMgr.isRec && !_dvrMgr.offline && _dvrMgr.checkInterval(_dvrIncrementVariance)){
_dvrMgr.getStreamDuration(_ncMgr.streamName);
}
if(_ns.time > _dvrMgr.totalDuration && _dvrMgr.totalDuration != 0) {
if(_dvrFixedDuration == true){
_ns.play(false);
}
}
if(_dvrMgr.currentDuration >= 0) {
var _currDuration:Number = (_dvrMgr.currentDuration <= _streamLength) ? _dvrMgr.currentDuration : _streamLength;
dispatchEvent(new VideoProgressEvent(VideoProgressEvent.PROGRESS, false, false, _currDuration, _streamLength));
}
}
if (_lastUpdateTime != theTime) {
dispatchEvent(new VideoEvent(VideoEvent.PLAYHEAD_UPDATE, false, false, _state, theTime));
_lastUpdateTime = theTime;
lastUpdateTimeStuckCount = 0;
}
}
/**
* Called at interval determined by
* progressInterval
to send progress
events.
* Object dispatch starts when _load
is called, ends
* when all bytes downloaded or a network error of some kind
* occurs.
*
* @default 0.25
*
* @private
*/
flvplayback_internal function doUpdateProgress(e:TimerEvent):void {
if (_ns == null) return;
//ifdef DEBUG
////debugTrace("doUpdateProgress()");
////debugTrace("_ns.bytesLoaded = " + _ns.bytesLoaded);
////debugTrace("_ns.bytesTotal = " + _ns.bytesTotal);
//endif
var curBytesLoaded:uint = _ns.bytesLoaded;
var curBytesTotal:uint = _ns.bytesTotal;
if (curBytesTotal < uint.MAX_VALUE) {
dispatchEvent(new VideoProgressEvent(VideoProgressEvent.PROGRESS, false, false, curBytesLoaded, curBytesTotal))
}
if ( _state == VideoState.DISCONNECTED || _state == VideoState.CONNECTION_ERROR ||
curBytesLoaded >= curBytesTotal ) {
_updateProgressTimer.stop();
}
checkEnoughDownloaded(curBytesLoaded, curBytesTotal);
}
/**
* @private
*/
flvplayback_internal function updateDVRDuration(e:Event):void
{
var currentDuration:int = e.target.currentDuration;
if(!isNaN(e.target.totalDuration)){
_streamLength = e.target.totalDuration;
}
if(_dvrMgr.totalDuration > 0) {
if(!_dvrFixedDuration && _dvrMgr.isRec && (_dvrMgr.totalDuration - _dvrMgr.currentDuration < _dvrIncrementVariance)) {
_streamLength = _dvrMgr.currentDuration + _dvrIncrement;
} else {
_streamLength = _dvrMgr.totalDuration;
}
} else {
_streamLength = _dvrMgr.currentDuration + _dvrIncrement;
}
if(_dvrStart && _dvrMgr.offline != true) {
_dvrStart = false;
_createStream();
_setUpStream();
} else if(_dvrStart && _dvrMgr.offline == true) {
return;
}
if(currentDuration > _streamLength && _dvrFixedDuration && _dvrMgr.totalDuration > 0) {
currentDuration = _streamLength;
}
dispatchEvent(new VideoProgressEvent(VideoProgressEvent.PROGRESS, false, false, currentDuration, _streamLength));
}
flvplayback_internal function handleDVRError(e:Event):void
{
// dvr stream is not available
/*
this._isLive = true;
if(_dvrStart) {
_dvrStart = false;
_isDVR = false;
_createStream();
_setUpStream();
}
*/
}
/**
* @private
*/
flvplayback_internal function checkEnoughDownloaded(curBytesLoaded:uint, curBytesTotal:uint):void {
//ifdef DEBUG
//debugTrace("checkEnoughDownloaded(" + curBytesLoaded + ", " + curBytesTotal + ")");
//endif
// wait until we have some bytes loaded and total data to start our checks
if (curBytesLoaded == 0 || curBytesTotal == uint.MAX_VALUE) {
return;
}
// if we have no totalTime set from metadata or by other method,
// then we can't do any of our calculations. Before starting play,
// we check for stateResponsive to make sure we are not still waiting for metadata
if (isNaN(totalTime) || totalTime <= 0) {
if (waitingForEnough && stateResponsive) {
waitingForEnough = false;
_cachedState = _state;
_state = VideoState.EXEC_QUEUED_CMD;
play();
execQueuedCmds();
}
return;
}
// if it is all loaded, we need look no further!
if (curBytesLoaded >= curBytesTotal) {
// if we are waiting, then we should play
if (waitingForEnough) {
waitingForEnough = false;
_cachedState = _state;
_state = VideoState.EXEC_QUEUED_CMD;
play();
execQueuedCmds();
}
return;
}
// if first time handling a progress event for this vp, we stash
// the baseline progress time. This is because it is possible
// that the user started downloading this FLV earlier so has a
// portion of it cached, but not the entire thing. If we do not
// note this, it could skew our download rate calculations badly
if (isNaN(baselineProgressTime)) {
baselineProgressTime = (curBytesLoaded / curBytesTotal) * totalTime;
}
if (isNaN(startProgressTime)) {
// first time we hit a progress event with more than 0 bytes
// loaded but less than bytesTotal bytes lodaed, we just grab
// the start time in seconds to use in our download rate
// calculations
startProgressTime = getTimer();
} else {
// if we have a start time grabbed...
// calculate total time spent downloading, in seconds
totalDownloadTime = (getTimer() - startProgressTime) / 1000;
// calculate total playing time of FLV downloaded, in seconds.
// This approximate value assumes that the bytes / second of
// playing time in the FLV is linear, which is not an accurate
// assumption but it will usually be good enough when averaged
// over long spans of the FLV.
totalProgressTime = (curBytesLoaded / curBytesTotal) * totalTime;
// check if it we are ready to start playing
if (waitingForEnough) {
checkReadyForPlay(curBytesLoaded, curBytesTotal);
}
}
}
/**
* @private
*/
flvplayback_internal function checkReadyForPlay(curBytesLoaded:uint, curBytesTotal:uint):void {
//ifdef DEBUG
//debugTrace("checkReadyForPlay()");
//endif
// play if downloaded all the way
if (curBytesLoaded >= curBytesTotal) {
waitingForEnough = false;
_cachedState = _state;
_state = VideoState.EXEC_QUEUED_CMD;
play();
execQueuedCmds();
return;
}
// if no baseline progress time set we are definitely not ready to
// play because have not received any progress events yet
if (isNaN(baselineProgressTime)) return;
// if totalTime is undefined or not set to a valid value, then
// none of our calculations are valid. The progress event
// listener will take care of just starting an FLV if we do not
// know the totalTime
if (isNaN(totalTime) || totalTime < 0) {
waitingForEnough = false;
_cachedState = _state;
_state = VideoState.EXEC_QUEUED_CMD;
play();
execQueuedCmds();
} else {
// we don't want to make download estimate rates to early because
// our calculations are very approximate, so wait until at least
// 1.5 seconds of downloading has occurred (not so long of a wait)
// remember that if the WHOLE FLV downloads in less than 1.5
// seconds, that will still trigger a start outside of this function,
// since we don't call this function when bytesLoaded == bytesTotal
if (totalDownloadTime > 1.5) {
// download rate calculation as (approximate FLV playing time) / (time spent downloading FLV)
var downloadRate:Number = (totalProgressTime - baselineProgressTime) / totalDownloadTime;
// if we estimate that we will be done downloading the FLV by the time
// we get to the end of it
if (totalTime - playheadTime > ((totalTime - totalProgressTime) / downloadRate)) {
waitingForEnough = false;
_cachedState = _state;
_state = VideoState.EXEC_QUEUED_CMD;
play();
execQueuedCmds();
}
} // if (totalDownloadTime > 1.5)
} // if (!isNaN(totalTime) && totalTime > 0)
}
/**
* NetStatusEvent.NET_STATUS
event listener
* for rtmp. Handles automatic resizing, autorewind and
* buffering messaging.
*
* @private
*/
flvplayback_internal function rtmpNetStatus(e:NetStatusEvent):void {
//ifdef DEBUG
//debugTrace("rtmpNetStatus:"+e.info.code);
//debugTrace("_state == " + _state);
//debugTrace("_cachedState == " + _cachedState);
//debugTrace("_bufferState == " + _bufferState);
//debugTrace("_sawPlayStop == " + _sawPlayStop);
//debugTrace("_cachedPlayheadTime == " + _cachedPlayheadTime);
//debugTrace("playheadTime == " + playheadTime);
//debugTrace("_ns.bufferLength = " + _ns.bufferLength);
//debugTrace("_startingPlay = " + _startingPlay);
//endif
if (_state == VideoState.CONNECTION_ERROR) {
// always do nothing
return;
}
switch (e.info.code) {
case "NetStream.Play.Stop":
if (_startingPlay) return;
if(_isDVR && _dvrMgr != null && _dvrMgr.checkInterval(1)){
_dvrPlaying = false;
if(_ncMgr.streamName == "" && _ncMgr.streams.length > 0) {
_dvrMgr.getStreamDuration(_ncMgr.streams[0].src);
} else {
_dvrMgr.getStreamDuration(_ncMgr.streamName);
}
}
switch (_state) {
case VideoState.RESIZING:
if (_hiddenForResize) finishAutoResize();
break;
case VideoState.LOADING:
case VideoState.STOPPED:
case VideoState.PAUSED:
// yes we are stopped, we already know this
break;
default:
_sawPlayStop = true;
// this code used to only be in the flush handler, checking for _sawPlayStop,
// but there can be timing issues where the flush comes just before the stop, instead
// of just after
if ( !_rtmpDoStopAtEndTimer.running &&
( _bufferState == BUFFER_FLUSH || (_ns.bufferTime <= 0.1 && _ns.bufferLength <= 0.1) ) ) {
// if we did a seek toward the end of the file so that
// there is less file left to show than we have
// buffer, than we will get a NetStream.Play.Stop when
// the buffer loads rest of the file, but never get
// a NetStream.Buffer.Full, since it won't fill, so
// we check if we are done on a timer
_cachedPlayheadTime = playheadTime;
_rtmpDoStopAtEndTimer.reset();
_rtmpDoStopAtEndTimer.start();
}
break;
} // switch (_state)
break;
case "NetStream.Buffer.Empty":
switch (_bufferState) {
case BUFFER_FULL:
if (_sawPlayStop) {
rtmpDoStopAtEnd();
} else if (_state == VideoState.PLAYING) {
setState(VideoState.BUFFERING);
}
break;
}
_bufferState = BUFFER_EMPTY;
_sawPlayStop = false;
break;
case "NetStream.Buffer.Flush":
if (_sawSeekNotify && _state == VideoState.SEEKING) {
_bufferState = BUFFER_EMPTY;
_sawPlayStop = false;
setStateFromCachedState(false);
doUpdateTime();
execQueuedCmds();
}
if ( !_rtmpDoStopAtEndTimer.running && _sawPlayStop &&
( _bufferState == BUFFER_EMPTY || (_ns.bufferTime <= 0.1 && _ns.bufferLength <= 0.1) ) ) {
// if we did a seek toward the end of the file so that
// there is less file left to show than we have
// buffer, than we will get a NetStream.Play.Stop when
// the buffer loads rest of the file, but never get
// a NetStream.Buffer.Full, since it won't fill, so
// we check if we are done on a timer
_cachedPlayheadTime = playheadTime;
_rtmpDoStopAtEndTimer.reset();
_rtmpDoStopAtEndTimer.start();
}
switch (_bufferState) {
case BUFFER_EMPTY:
if ( !_hiddenForResize ) {
if ((_state == VideoState.LOADING && _cachedState == VideoState.PLAYING) || _state == VideoState.BUFFERING) {
setState(VideoState.PLAYING);
} else if (_cachedState == VideoState.BUFFERING) {
_cachedState = VideoState.PLAYING;
}
}
_bufferState = BUFFER_FLUSH;
break;
default:
if (_state == VideoState.BUFFERING) {
setStateFromCachedState();
}
break;
} // switch (_bufferState)
break;
case "NetStream.Buffer.Full":
if (_sawSeekNotify && _state == VideoState.SEEKING) {
_bufferState = BUFFER_EMPTY;
_sawPlayStop = false;
setStateFromCachedState(false);
doUpdateTime();
execQueuedCmds();
}
switch (_bufferState) {
case BUFFER_EMPTY:
_bufferState = BUFFER_FULL;
if ( !_hiddenForResize ) {
if ((_state == VideoState.LOADING && _cachedState == VideoState.PLAYING) || _state == VideoState.BUFFERING) {
setState(VideoState.PLAYING);
} else if (_cachedState == VideoState.BUFFERING) {
_cachedState = VideoState.PLAYING;
}
if (_rtmpDoStopAtEndTimer.running) {
_sawPlayStop = true;
_rtmpDoStopAtEndTimer.reset();
}
}
break;
case BUFFER_FLUSH:
_bufferState = BUFFER_FULL;
if ( _rtmpDoStopAtEndTimer.running) {
_sawPlayStop = true;
_rtmpDoStopAtEndTimer.reset();
}
break;
} // switch (_bufferState)
if (_state == VideoState.BUFFERING) {
setStateFromCachedState();
}
break;
case "NetStream.Pause.Notify":
if (_state == VideoState.RESIZING && _hiddenForResize) {
finishAutoResize();
}
break;
case "NetStream.Unpause.Notify":
if (_state == VideoState.PAUSED) {
_state = VideoState.PLAYING;
setState(VideoState.BUFFERING);
} else {
_cachedState = VideoState.PLAYING;
}
break;
case "NetStream.Play.Start":
_rtmpDoStopAtEndTimer.reset();
_bufferState = BUFFER_EMPTY;
_sawPlayStop = false;
if (_isDVR && _dvrMgr != null) {
_dvrPlaying = true;
}
if (_startingPlay && _dvrMgr != null) {
if(_dvrFixedDuration && _dvrMgr.totalDuration > 0 && _dvrMgr.currentDuration >= _dvrMgr.totalDuration) {
_dvrSnapToLive = false;
}
if(_dvrSnapToLive && _isDVR && _dvrMgr.isRec) {
_seek(_dvrMgr.currentDuration);
}
_startingPlay = false;
_cachedPlayheadTime = playheadTime;
} else if (_startingPlay) {
_startingPlay = false;
_cachedPlayheadTime = playheadTime;
} else if (_state == VideoState.PLAYING) {
setState(VideoState.BUFFERING);
}
break;
case "NetStream.Play.Reset":
_rtmpDoStopAtEndTimer.reset();
if (_state == VideoState.REWINDING) {
_rtmpDoSeekTimer.reset();
if (playheadTime == 0 || playheadTime < _cachedPlayheadTime) {
setStateFromCachedState();
} else {
_cachedPlayheadTime = playheadTime;
_rtmpDoSeekTimer.start();
}
}
break;
case "NetStream.Seek.Notify":
if (playheadTime != _cachedPlayheadTime) {
setStateFromCachedState(false);
doUpdateTime();
execQueuedCmds();
} else {
_sawSeekNotify = true;
_rtmpDoSeekTimer.start();
}
break;
case "Netstream.Play.UnpublishNotify":
break;
case "Netstream.Play.PublishNotify":
break;
case "NetStream.Play.StreamNotFound":
closeNS(false);
if (!_ncMgr.connectAgain()) {
setState(VideoState.CONNECTION_ERROR);
}
break;
case "NetStream.Play.Failed":
case "NetStream.Failed":
case "NetStream.Play.FileStructureInvalid":
case "NetStream.Play.NoSupportedTrackFound":
setState(VideoState.CONNECTION_ERROR);
break;
} // switch (e.info.code)
}
/**
* NetStatusEvent.NET_STATUS
event listener
* for http. Handles autorewind.
*
* @private
*/
flvplayback_internal function httpNetStatus(e:NetStatusEvent):void {
//ifdef DEBUG
//debugTrace("httpNetStatus:"+e.info.code);
//debugTrace("_state == " + _state);
//debugTrace("playheadTime == " + playheadTime);
//debugTrace("_bufferState = " + _bufferState);
//endif
switch (e.info.code) {
case "NetStream.Play.Stop":
_delayedBufferingTimer.reset();
if (_invalidSeekTime) {
_invalidSeekTime = false;
_invalidSeekRecovery = true;
setState(_cachedState);
seek(playheadTime);
} else {
switch (_state) {
case VideoState.SEEKING:
httpDoSeek(null);
// no break
case VideoState.PLAYING:
case VideoState.BUFFERING:
httpDoStopAtEnd();
break;
}
}
break;
case "NetStream.Seek.InvalidTime":
if (_invalidSeekRecovery) {
_invalidSeekTime = false;
_invalidSeekRecovery = false;
setState(_cachedState);
seek(0);
} else {
_invalidSeekTime = true;
_httpDoSeekCount = 0;
_httpDoSeekTimer.start();
}
break;
case "NetStream.Buffer.Empty":
_bufferState = BUFFER_EMPTY;
if (_state == VideoState.PLAYING) {
_delayedBufferingTimer.reset();
_delayedBufferingTimer.start();
}
break;
case "NetStream.Buffer.Full":
case "NetStream.Buffer.Flush":
_delayedBufferingTimer.reset();
_bufferState = BUFFER_FULL;
if ( !_hiddenForResize ) {
if ((_state == VideoState.LOADING && _cachedState == VideoState.PLAYING) || _state == VideoState.BUFFERING) {
setState(VideoState.PLAYING);
} else if (_cachedState == VideoState.BUFFERING) {
_cachedState = VideoState.PLAYING;
}
}
break;
case "NetStream.Seek.Notify":
_invalidSeekRecovery = false;
switch (_state) {
case VideoState.SEEKING:
case VideoState.REWINDING:
_httpDoSeekCount = 0;
_httpDoSeekTimer.start();
break;
} // switch (_state)
break;
case "NetStream.Play.StreamNotFound":
case "NetStream.Play.FileStructureInvalid":
case "NetStream.Play.NoSupportedTrackFound":
setState(VideoState.CONNECTION_ERROR);
break;
} // switch (e.info.code)
}
/**
* Called by INCManager after the connection is complete or failed after a call to the
* INCManager.connectToURL()
method. If the connection failed, set
* the INCManager.netConnection
property to null
or
* undefined before calling.
*
* @see #ncReconnected()
* @see INCManager#connectToURL()
* @see NCManager#connectToURL()
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function ncConnected():void {
//ifdef DEBUG
//debugTrace("ncConnected()");
//endif
if (_ncMgr == null || _ncMgr.netConnection == null) {
setState(VideoState.CONNECTION_ERROR);
var fpcaps:FPMediaCapabilities = new FPMediaCapabilities();
if( fpcaps.rtmpe == false ) {
dispatchEvent(new VideoEvent(VideoEvent.UNSUPPORTED_PLAYER_VERSION, false, false, VideoState.CONNECTION_ERROR, playheadTime));
}
} else if (_ns == null) {
if (_isDVR && _dvrMgr == null) {
_dvrStart = true;
_dvrMgr = new DVRManager(_ncMgr.netConnection);
_dvrMgr.addEventListener(DVRManager.DVR_EVENT, updateDVRDuration);
_dvrMgr.addEventListener(DVRManager.DVR_ERROR, handleDVRError);
if(_ncMgr.streams != null) {
if(_ncMgr.streams.length > 0) {
if(_ncMgr.streams.length > 1) {
for(var i:int=1; i<_ncMgr.streams.length; i++) {
try {
_ncMgr.netConnection.call("DVRSubscribe", null, _ncMgr.streams[i].src);
} catch(e:Error) {}
}
}
_dvrMgr.getStreamDuration(_ncMgr.streams[0].src);
}
} else {
_dvrMgr.getStreamDuration(_ncMgr.streamName);
}
return;
} else {
_createStream();
_setUpStream();
}
}
}
/**
* Called by INCManager after the reconnection is complete or has failed after a call to
* the INCManager.reconnect()
method. If the connection fails,
* set the INCManager.netconnection
property to null
* before you call it.
*
* @see #ncConnected()
* @see INCManager#reconnect()
* @see NCManager#reconnect()
*
* @langversion 3.0
* @playerversion Flash 9.0.28.0
*/
public function ncReconnected():void {
//ifdef DEBUG
//debugTrace("reconnected called!");
//endif
if (_ncMgr == null || _ncMgr.netConnection == null) {
setState(VideoState.CONNECTION_ERROR);
} else {
_ns = null;
_state = VideoState.STOPPED;
execQueuedCmds();
}
}
/**
* handles NetStream.onMetaData callback
*
* @private
*/
flvplayback_internal function onMetaData(info:Object):void {
if (_metadata != null) return;
_metadata = info;
if (isNaN(_streamLength)){
_streamLength = info["duration"];
}
if (_resizeImmediatelyOnMetadata && _ns.client.ready) {
_resizeImmediatelyOnMetadata = false;
_autoResizeTimer.reset();
_autoResizeDone = false;
doAutoResize();
}
dispatchEvent(new MetadataEvent(MetadataEvent.METADATA_RECEIVED, false, false, info));
}
/**
* handles NetStream.onCuePoint callback
*
* @private
*/
flvplayback_internal function onCuePoint(info:Object):void {
if ( !_hiddenForResize ||
(!isNaN(_hiddenRewindPlayheadTime) && playheadTime < _hiddenRewindPlayheadTime) ) {
dispatchEvent(new MetadataEvent(MetadataEvent.CUE_POINT, false, false, info));
}
}
//
// private functions
//
/**
* sets state, dispatches event, execs queued commands. Always try to call
* this AFTER you do your work, because the state might change again after
* you call this if you set it to a responsive state becasue of the call
* to exec queued commands. If you set this to a responsive state and
* then do more state based logic, check _state to make sure it did not
* change out from under you.
*
* @private
*/
flvplayback_internal function setState(s:String, execQueued:Boolean=true):void {
if (s == _state) return;
_hiddenRewindPlayheadTime = NaN;
_cachedState = _state;
_cachedPlayheadTime = playheadTime;
_state = s;
var newState:String = _state;
//ifdef DEBUG
//debugTrace("state = " + newState);
//debugTrace("_cachedState == " + _cachedState);
//debugTrace("_cachedPlayheadTime == " + _cachedPlayheadTime);
//endif
dispatchEvent(new VideoEvent(VideoEvent.STATE_CHANGE, false, false, newState, playheadTime));
if (!_readyDispatched) {
switch (newState) {
case VideoState.STOPPED:
case VideoState.PLAYING:
case VideoState.PAUSED:
case VideoState.BUFFERING:
_readyDispatched = true;
dispatchEvent(new VideoEvent(VideoEvent.READY, false, false, newState, playheadTime));
break;
} // switch
}
switch (_cachedState) {
case VideoState.REWINDING:
dispatchEvent(new VideoEvent(VideoEvent.AUTO_REWOUND, false, false, newState, playheadTime));
if (_ncMgr.isRTMP && newState == VideoState.STOPPED) {
closeNS();
}
break;
} // switch
switch (newState) {
case VideoState.STOPPED:
case VideoState.PAUSED:
if (_ncMgr.isRTMP) {
_idleTimeoutTimer.reset();
_idleTimeoutTimer.start();
}
break;
case VideoState.SEEKING:
case VideoState.REWINDING:
_bufferState = BUFFER_EMPTY;
_sawPlayStop = false;
_idleTimeoutTimer.reset();
break;
case VideoState.PLAYING:
case VideoState.BUFFERING:
_updateTimeTimer.start();
_idleTimeoutTimer.reset();
break;
case VideoState.LOADING:
case VideoState.RESIZING:
_idleTimeoutTimer.reset();
break;
} // switch
if (execQueued) {
execQueuedCmds();
}
}
/**
* Sets state to _cachedState if the _cachedState is VideoState.PLAYING,
* VideoState.PAUSED or VideoState.BUFFERING, otherwise sets state to VideoState.STOPPED.
*
* @private
*/
flvplayback_internal function setStateFromCachedState(execQueued:Boolean=true):void {
switch (_cachedState) {
case VideoState.PLAYING:
case VideoState.PAUSED:
case VideoState.BUFFERING:
setState(_cachedState, execQueued);
break;
default:
setState(VideoState.STOPPED, execQueued);
break;
}
}
/**
* creates our implementatino of the INCManager
.
* We put this off until we need to do it to give time for the
* user to customize the iNCManagerClass
* static variable.
*
* @private
*/
flvplayback_internal function createINCManager():void {
var theClass:Class = null;
try {
if (iNCManagerClass is String) {
theClass = Class(getDefinitionByName(String(iNCManagerClass)));
} else if (iNCManagerClass is Class) {
theClass = Class(iNCManagerClass);
}
} catch (e:Error) {
theClass = null;
}
if (theClass == null) {
throw new VideoError(VideoError.INCMANAGER_CLASS_UNSET, (iNCManagerClass == null) ? "null" : iNCManagerClass.toString());
}
_ncMgr = new theClass();
_ncMgr.videoPlayer = this;
}
/**
* creates an instance of the class specified by the
* netStreamClientClass
static property.
*
* @private
*/
flvplayback_internal function createNetStreamClient():Object {
var theClass:Class = null;
var theInst:Object = null;
try {
if (netStreamClientClass is String) {
theClass = Class(getDefinitionByName(String(netStreamClientClass)));
} else if (netStreamClientClass is Class) {
theClass = Class(netStreamClientClass);
}
if (theClass != null) {
theInst = new theClass(this);
}
} catch (e:Error) {
theClass = null;
theInst = null;
}
if (theInst == null) {
throw new VideoError(VideoError.NETSTREAM_CLIENT_CLASS_UNSET, (netStreamClientClass == null) ? "null" : netStreamClientClass.toString());
}
return theInst;
}
/**
* ONLY CALL THIS WITH RTMP STREAMING
* *Has the logic for what to do when we decide we have come to * a stop by coming to the end of an rtmp stream. There are a few * different ways we decide this has happened, and we sometimes * even set an interval that calls this function repeatedly to * check if the time is still changing, which is why it has its * own special function.
* * @private */ flvplayback_internal function rtmpDoStopAtEnd(e:TimerEvent=null):void { //ifdef DEBUG //debugTrace("rtmpDoStopAtEnd(" + e + ")"); //endif // check if we really want to stop if this was triggered on an // interval. If we are running this on an interval (see // rtmpNetStatus) we do a stop when the playhead hasn't moved // since last time we checked, we check every 0.25 seconds. if (_rtmpDoStopAtEndTimer.running) { switch (_state) { case VideoState.DISCONNECTED: case VideoState.CONNECTION_ERROR: _rtmpDoStopAtEndTimer.reset(); return; } if (e == null || _cachedPlayheadTime == playheadTime) { _rtmpDoStopAtEndTimer.reset(); } else { _cachedPlayheadTime = playheadTime; return; } } // special check to see if we started at end, so our _atEnd variable was WRONG if (_atEndCheckPlayhead == playheadTime && _atEndCheckPlayhead != _lastSeekTime && !_isLive && playheadTime != 0) { _atEnd = false; _currentPos = 0; _play(0); return; } _atEndCheckPlayhead = NaN; _bufferState = BUFFER_EMPTY; _sawPlayStop = false; _atEnd = true; // all this triggers callbacks, so need to keep checking if // _state == STOPPED--if no longer, then we bail setState(VideoState.STOPPED); if (_state != VideoState.STOPPED) return; doUpdateTime(); if (_state != VideoState.STOPPED) return; dispatchEvent(new VideoEvent(VideoEvent.COMPLETE, false, false, _state, playheadTime)); if (_state != VideoState.STOPPED) return; if (_autoRewind && !_isLive && playheadTime != 0) { _atEnd = false; _currentPos = 0; _play(0, 0); setState(VideoState.REWINDING); } else { closeNS(); } } /** *ONLY CALL THIS WITH RTMP STREAMING
* *Wait until time goes back to zero to leave rewinding state.
* * @private */ flvplayback_internal function rtmpDoSeek(e:TimerEvent):void { //ifdef DEBUG //debugTrace("rtmpDoSeek()"); //endif if (_state != VideoState.REWINDING && _state != VideoState.SEEKING) { _rtmpDoSeekTimer.reset(); _sawSeekNotify = false; } else if (playheadTime != _cachedPlayheadTime) { _rtmpDoSeekTimer.reset(); _sawSeekNotify = false; setStateFromCachedState(false); doUpdateTime(); _lastSeekTime = playheadTime; execQueuedCmds(); } } /** *ONLY CALL THIS WITH HTTP PROGRESSIVE DOWNLOAD
* *Call this when playing stops by hitting the end.
* * @private */ flvplayback_internal function httpDoStopAtEnd():void { //ifdef DEBUG //debugTrace("httpDoStopAtEnd()"); //endif if (_atEndCheckPlayhead == playheadTime && _atEndCheckPlayhead != _lastUpdateTime && playheadTime != 0) { _atEnd = false; _seek(0); return; } _atEndCheckPlayhead = NaN; _atEnd = true; if (isNaN(_streamLength)) { _streamLength = _ns.time; } _pause(true); setState(VideoState.STOPPED); if (_state != VideoState.STOPPED) return; doUpdateTime(); if (_state != VideoState.STOPPED) return; dispatchEvent(new VideoEvent(VideoEvent.COMPLETE, false, false, _state, playheadTime)); if (_state != VideoState.STOPPED) return; if (_autoRewind) { _atEnd = false; _pause(true); _seek(0); setState(VideoState.REWINDING); } } /** *ONLY CALL THIS WITH HTTP PROGRESSIVE DOWNLOAD
* *If we get an onStatus callback indicating a seek is over, * but the playheadTime has not updated yet, then we wait on a * timer before moving forward.
* * @private */ flvplayback_internal function httpDoSeek(e:TimerEvent):void { //ifdef DEBUG //debugTrace("httpDoSeek()"); //debugTrace("playheadTime = " + playheadTime); //debugTrace("_cachedPlayheadTime = " + _cachedPlayheadTime); //endif var seekState:Boolean = (_state == VideoState.REWINDING || _state == VideoState.SEEKING); // if seeking or rewinding, then need to wait for playhead time to // change or for timeout if ( seekState && _httpDoSeekCount < httpDoSeekMaxCount && (_cachedPlayheadTime == playheadTime || _invalidSeekTime) ) { _httpDoSeekCount++; return; } // reset _httpDoSeekCount = 0; _httpDoSeekTimer.reset(); // only do the rest if were seeking or rewinding to start with if (!seekState) return; setStateFromCachedState(false); if (_invalidSeekTime) { _invalidSeekTime = false; _invalidSeekRecovery = true; seek(playheadTime); } else { doUpdateTime(); _lastSeekTime = playheadTime; execQueuedCmds(); } } /** *Wrapper for NetStream.close()
. Never call
* NetStream.close()
directly, always call this
* method because it does some other housekeeping.
We do a brief timer before entering VideoState.BUFFERING state to avoid * quick switches from VideoState.BUFFERING to VideoState.PLAYING and back.
* * @private */ flvplayback_internal function doDelayedBuffering(e:TimerEvent):void { //ifdef DEBUG //debugTrace("doDelayedBuffering()"); //endif switch (_state) { case VideoState.LOADING: case VideoState.RESIZING: // if loading or resizing, still at beginning so keep whirring, might go into buffering state break; case VideoState.PLAYING: _delayedBufferingTimer.reset(); // when we hit buffering, we pause and start waiting // for enough to download IF we have a totalTime // and IF we haven't already downloaded everything if ( !isNaN(totalTime) && totalTime > 0 && bytesLoaded > 0 && bytesLoaded < uint.MAX_VALUE && bytesLoaded < bytesTotal ) { pause(); if (_state == VideoState.PAUSED) { waitingForEnough = true; playWhenEnoughDownloaded(); } } else { setState(VideoState.BUFFERING); } break; default: // any other state, bail and kill timer _delayedBufferingTimer.reset(); break; } } /** * Wrapper forNetStream.pause()
. Never call
* NetStream.pause()
directly, always call this
* method because it does some other housekeeping.
*
* @private
*/
flvplayback_internal function _pause(doPause:Boolean):void {
//ifdef DEBUG
//debugTrace("_pause(" + doPause + ")");
//endif
_atEndCheckPlayhead = playheadTime;
_rtmpDoStopAtEndTimer.reset();
if (doPause) {
_ns.pause();
} else {
_ns.resume();
}
}
/**
* Wrapper for NetStream.play()
. Never call
* NetStream.play()
directly, always call this
* method because it does some other housekeeping.
*
* @private
*/
flvplayback_internal function _play(startTime:int=0, endTime:int=-1):void {
//ifdef DEBUG
//var debugString:String = "_play("
//if (arguments.length > 0) {
// debugString += arguments[0];
// if (arguments.length > 1) {
// debugString += ", " + arguments[1];
// }
//}
//debugString += ")";
//debugTrace(debugString);
//debugTrace("_ncMgr.streamName = " + _ncMgr.streamName);
//endif
waitingForEnough = false;
_rtmpDoStopAtEndTimer.reset();
_startingPlay = true;
if(_isDVR && _dvrMgr != null){
if(_dvrMgr.offset > 0){
startTime = _dvrMgr.offset;
}
}
if(_ncMgr.isDynamicStream == true) {
// Flash10 Code
_playDynamicStream(startTime, endTime);
} else {
_ns.play(_ncMgr.streamName, (_isLive) ? -1 : startTime, endTime);
}
}
/**
* Extension of _play to handle the necessary elements required for Dynamic Streaming.
*
* @param startTime
* @param endTime
*
*/
flvplayback_internal function _playDynamicStream(startTime:int=0, endTime:int=-1):void {
var ts:Array = _ncMgr.streams;
var dsi:DynamicStreamItem = new DynamicStreamItem();
dsi.start = (_isLive) ? -1 : startTime;
dsi.len = endTime;
for(var i:int=0; i< ts.length; i++){
dsi.addStream(ts[i].src, ts[i].bitrate/1000);
}
_ns.play(dsi);
}
/**
* Wrapper for NetStream.seek()
. Never call
* NetStream.seek()
directly, always call
* this method because it does some other housekeeping.
*
* @private
*/
flvplayback_internal function _seek(time:Number):void {
//ifdef DEBUG
//debugTrace("_seek(" + time + ")");
//endif
_rtmpDoStopAtEndTimer.reset();
if ( _metadata != null &&
_metadata.audiodelay != undefined &&
(isNaN(_streamLength) || time + _metadata.audiodelay < _streamLength) ) {
time += _metadata.audiodelay;
}
if(_isDVR && _dvrMgr != null){
if(time > _dvrMgr.currentDuration - _ns.bufferTime) {
// cannot go below 0
time = (_dvrMgr.currentDuration - _ns.bufferTime >= 0) ? _dvrMgr.currentDuration - _ns.bufferTime : 0;
}
}
_ns.seek(time);
_lastSeekTime = time;
_invalidSeekTime = false;
_bufferState = BUFFER_EMPTY;
_sawPlayStop = false;
_sawSeekNotify = false;
}
/**
* Gets whether connected to a stream. If not, then calls to APIs
* play() with no args
, stop()
,
* pause()
and seek()
will throw
* exceptions.
*
* @see #stateResponsive
* @private
*/
flvplayback_internal function isXnOK():Boolean {
if (_state == VideoState.LOADING) return true;
if (_state == VideoState.CONNECTION_ERROR) return false;
if (_state != VideoState.DISCONNECTED) {
if ( _ncMgr == null ||
_ncMgr.netConnection == null ||
(_ncMgr.isRTMP && !_ncMgr.netConnection.connected) ) {
setState(VideoState.DISCONNECTED);
return false;
}
return true;
}
return false;
}
/**
* Kicks off autoresize process
*
* @private
*/
flvplayback_internal function startAutoResize():void {
switch (_state) {
case VideoState.DISCONNECTED:
case VideoState.CONNECTION_ERROR:
// autoresize will happen later automatically
return;
default:
// starting a resize when there is no NetStream can cause problems!
if (_ns == null) {
return;
}
_autoResizeDone = false;
if ( stateResponsive &&
( super.videoWidth != 0 || super.videoHeight != 0 ||
_bufferState == BUFFER_FULL || _bufferState == BUFFER_FLUSH ||
_ns.time > autoResizePlayheadTimeout ) ) {
// do it now!
doAutoResize();
} else {
// do it on an interval, it won't happen until we are
// back in a responsive state
_autoResizeTimer.reset();
_autoResizeTimer.start();
}
break;
}
}
/**
* Does the actual work of resetting the width and height.
* *Called on an interval which is stopped when width and height
* of the Video
object are not zero. Finishing the
* resize is done in another method which is either called on a
* interval set up here for live streams or on a
* NetStream.Play.Stop event in rtmpNetStatus
after
* stream is rewound if it is not a live stream. Still need to
* get a http solution.
Makes video visible, turns on sound and starts * playing if live or autoplay.
* * @private */ flvplayback_internal function finishAutoResize(e:TimerEvent=null):void { //ifdef DEBUG //debugTrace("finishAutoResize()"); //endif if (stateResponsive) return; _hiddenForResize = false; super.visible = __visible; volume = _volume; //ifdef DEBUG //debugTrace("_autoPlay = " + _autoPlay); //endif dispatchEvent(new AutoLayoutEvent(AutoLayoutEvent.AUTO_LAYOUT, false, false, oldBounds, oldRegistrationBounds)); if (_autoPlay) { if (_ncMgr.isRTMP) { if (!_isLive) { _currentPos = 0; _play(0); } if (_state == VideoState.RESIZING) { setState(VideoState.LOADING); _cachedState = VideoState.PLAYING; } } else { waitingForEnough = true; _cachedState = _state; _state = VideoState.PAUSED; checkReadyForPlay(bytesLoaded, bytesTotal); if (waitingForEnough) { _state = _cachedState; setState(VideoState.PAUSED); } else { _cachedState = VideoState.PLAYING; } } } else { setState(VideoState.STOPPED); } } /** *Creates NetStream
and does some basic
* initialization.
INCManager
if it has it for us.
*
* Starts resize if necessary, otherwise starts playing if * necessary, otherwise loads first frame of video. In http case, * starts progressive download in any case.
* * @private */ flvplayback_internal function _setUpStream():void { //ifdef DEBUG //debugTrace("_setUpStream()"); //endif // INCManager MIGHT have gotten the stream length, width and height for // us. If its length is less than 0, then it did not. if ( !isNaN(_ncMgr.streamLength) && _ncMgr.streamLength >= 0 ) { _streamLength = _ncMgr.streamLength; } _videoWidth = (_ncMgr.streamWidth >= 0) ? _ncMgr.streamWidth : -1; _videoHeight = (_ncMgr.streamHeight >= 0) ? _ncMgr.streamHeight : -1; _resizeImmediatelyOnMetadata = ((_videoWidth >= 0 && _videoHeight >= 0) || _scaleMode == VideoScaleMode.EXACT_FIT); if (!_hiddenForResize) { __visible = super.visible; super.visible = false; _volume = volume; volume = 0; _hiddenForResize = true; } _hiddenForResizeMetadataDelay = 0; _play(0); if (_currentPos > 0) { _seek(_currentPos); _currentPos = 0; } _autoResizeTimer.reset(); _autoResizeTimer.start(); } /** *ONLY CALL THIS WITH RTMP STREAMING
* *Only used for rtmp connections. When we pause or stop,
* setup an interval to call this after a delay (see property
* idleTimeout
). We do this to spare the server from
* having a bunch of extra xns hanging around, although this needs
* to be balanced with the load that creating connections puts on
* the server, and keep in mind that Flash Media Server (FMS) can be configured to
* terminate idle connections on its own, which is a better way to
* manage the issue.