/**
* Copyright dmitry.ern ( http://wonderfl.net/user/dmitry.ern )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/6gNK
*/
// Treds Video Player
// forked from ProjectNya's FLVPlayer Test (1)
package
{
import flash.display.Sprite;
import flash.events.Event;
import flash.system.Security;
import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.tweens.ITween;
import org.libspark.betweenas3.events.TweenEvent;
import org.libspark.betweenas3.easing.*;
import flash.net.URLRequest;
import flash.external.ExternalInterface;
import flash.trace.Trace;
import flash.events.ProgressEvent;
import flash.external.ExternalInterface;
[ SWF( backgroundColor = '#000000', width = '1280', height = '720', frameRate = '50' ) ] // Почему параметры width и height нужны? Зачем они? В какое значение их лучше всего поставить? Я же их после переопределяю. Странно всё это :)
public class Main extends Sprite
{
private var listener:String = ''; // js слушатели
public var videoHeight:int = 720;
public var videoWidth:int = 1280;
private var player:FLVPlayer;
private var seekBar:SeekBar;
public function Main()
{
Security.loadPolicyFile( "https://t.treds.net/crossdomain.xml" ); // Сделать выбор домена, откуда брать crossdomain.xml
Security.allowDomain( '*' );
Security.allowInsecureDomain( '*' );
// JS callbacks
listener = root.loaderInfo.parameters.listener;
//ExternalInterface.addCallback("loaded", loaded);
// Create player
player = new FLVPlayer( videoWidth, videoHeight, onReady, onPlaybackProgress, onLoadedProgress, onDataLoaded, onPlaybackComplete);
// Flash callbacks for JS callbacks
ExternalInterface.addCallback( 'play', player.play );
ExternalInterface.addCallback( 'pause', player.pause );
ExternalInterface.addCallback( 'stop', player.stop );
ExternalInterface.addCallback( 'volume', player.volume );
ExternalInterface.addCallback( 'position', player.seek );
ExternalInterface.addCallback( 'getTime', player.getTime );
ExternalInterface.addCallback( 'getDuration', player.getDuration );
// Configure player
addChild(player);
controller();
seekBar.initialize();
player.seekBar = seekBar;
//player.autoPlay = true;
player.addEventListener(Event.INIT, initialize, false, 0, true);
try {
player.source = encodeURI(root.loaderInfo.parameters.url);
}
catch (e:Error) {
}
}
private function initialize( evt:Event ):void
{
player.removeEventListener(Event.INIT, initialize);
player.start();//fade();
}
/*private function fade( ):void
{
var itween:ITween = BetweenAS3.to(loading, {alpha: 0, visible: 0}, 0.8, Linear.easeNone);
itween.addEventListener(TweenEvent.COMPLETE, faded, false, 0, true);
itween.play();
}
private function faded( evt:TweenEvent ):void
{
evt.target.removeEventListener(TweenEvent.COMPLETE, faded);
removeChild(loading);
loading = null;
player.start();
}*/
private function controller( ):void
{
// Create interface
seekBar = new SeekBar();
}
// JS callbacks //
private function call(method:String, arg:*, arg2:* = null, arg3:* = null):void {
ExternalInterface.call(listener + '.' + method, arg, arg2, arg3);
}
// Flash callbacks to JS //
// When the player is ready
public function onReady():void
{
var videoData:Object = new Object();
videoData.duration = player.getDuration();
call( "onReady", videoData );
}
public function onDataLoaded(duration:* = null, width:* = null, height:* = null):void
{
var videoData:Object = new Object();
videoData.duration = duration;
videoData.width = width;
videoData.height = height;
call( "onDataLoaded", videoData );
}
private function onPlaybackProgress():void {
var time:int = player.getDuration() * player.percent;//player.getTime();
call("onPlaybackProgress", time, player.percent);
}
private function onLoadedProgress(loaded:Number):void {
var loaded:Number = loaded * 100;
call("onLoadedProgress", loaded);
}
private function onPlaybackComplete():void {
call("onPlaybackComplete", null);
}
}
}
//////////////////////////////////////////////////
// FLVPlayer
//////////////////////////////////////////////////
import flash.display.DisplayObject;
import flash.display.Sprite;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.display.Bitmap;
import flash.events.Event;
import flash.net.NetConnection;
import flash.net.NetStream;
import flash.media.Video;
import flash.events.Event;
import flash.events.NetStatusEvent;
import flash.events.SecurityErrorEvent;
import flash.events.AsyncErrorEvent;
import flash.external.ExternalInterface;
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundTransform;
class FLVPlayer extends Sprite {
public var id:uint;
private var _connection:NetConnection;
private var _stream:NetStream;
private var _client:StreamClient;
private var flvPath:String;
private var vw:uint;
private var vh:uint;
private var _video:Video;
private var _seekBar:SeekBar;
private var initialized:Boolean = false;
private var duration:Number = 0;
private var _percent:Number = 0;
private var completed:Boolean = false;
private var readyCallback:Function;
private var playbackProgress:Function;
private var loadedProgress:Function;
private var dataLoaded:Function;
private var playbackComplete:Function;
private var tryToPlay:Boolean = false; // Флаг попытки проигрыша, устанавливается для проигрыша на более позднем этапе, если изначально проиграть не получилось из-за того что видео не загрузилось. Хак или вроде того @dmitry
private var streamClosed:Boolean = false;
private var playing:Boolean = false;
public function FLVPlayer(w:uint, h:uint, onReadyCallback:Function, onPlaybackProgress:Function, onLoadedProgress:Function, onDataLoaded:Function, onPlaybackComplete:Function) {
vw = w;
vh = h;
readyCallback = onReadyCallback;
playbackProgress = onPlaybackProgress;
loadedProgress = onLoadedProgress;
dataLoaded = onDataLoaded;
playbackComplete = onPlaybackComplete;
init();
}
private function init():void {
_video = new Video(vw, vh);
addChild(_video);
_video.smoothing = true;
_connection = new NetConnection();
_connection.addEventListener(NetStatusEvent.NET_STATUS, ncNetStatus, false, 0, true);
_connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityError, false, 0, true);
//_connection.connect(null);
}
public function set seekBar(bar:SeekBar):void {
_seekBar = bar;
}
public function set source(path:String):void {
flvPath = path;
_connection.connect(null);
}
private function ncNetStatus(evt:NetStatusEvent):void {
switch (evt.info.code) {
case "NetConnection.Connect.Success" : //接続成功
initialize();
break;
case "NetConnection.Connect.Failed" : //接続失敗
break;
case "NetConnection.Connect.Rejected" : //接続拒否
break;
case "NetConnection.Connect.Closed" : //接続(正常)切断
break;
}
}
private function securityError(evt:SecurityErrorEvent):void {
trace(evt.text);
}
private function initialize():void {
_client = new StreamClient();
_client.addEventListener(Event.INIT, onMetaData, false, 0, true);
_stream = new NetStream(_connection);
_stream.bufferTime = 5;
_stream.addEventListener(NetStatusEvent.NET_STATUS, nsNetStatus, false, 0, true);
_stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncError, false, 0, true);
_stream.client = _client;
_video.attachNetStream(_stream);
load();
}
private function onMetaData(evt:Event):void {
duration = evt.target.duration;
dataLoaded(evt.target.duration, evt.target.width, evt.target.height);
setup();
}
private function load():void {
_stream.receiveAudio(false);
_stream.play(flvPath);
_stream.pause();
addEventListener(Event.ENTER_FRAME, progress, false, 0, true);
}
private function progress(evt:Event):void {
var loaded:Number = _stream.bytesLoaded/_stream.bytesTotal;
_seekBar.progress = loaded;
if (loaded >= 1) {
removeEventListener(Event.ENTER_FRAME, progress);
}
if (loaded > 0) {
loadedProgress(loaded);
}
}
private function nsNetStatus(evt:NetStatusEvent):void {
switch (evt.info.code) {
case "NetStream.Buffer.Full" :
break;
case "NetStream.Buffer.Flush" :
break;
case "NetStream.Buffer.Empty" :
break;
case "NetStream.Play.Start" :
setup();
break;
case "NetStream.Play.Stop" :
complete();
break;
case "NetStream.Play.StreamNotFound" :
break;
case "NetStream.Pause.Notify" :
break;
case "NetStream.Seek.Notify" :
break;
case "NetStream.Seek.InvalidTime" :
break;
}
}
private function asyncError(evt:AsyncErrorEvent):void {
trace(evt.text);
}
private function setup():void {
if (duration > 0) {
if (!initialized) {
initialized = true;
dispatchEvent(new Event(Event.INIT));
readyCallback();
}
}
}
public function start():void {
stop();
_stream.receiveAudio(true);
if (tryToPlay) play();
}
private function playPause(evt:MouseEvent):void {
if( playing == false )
{
play( );
}
else
{
pause( );
}
}
public function play( ):void
{
tryToPlay = true;// Видео может ещё не до конца загрузиться, а JS может запросить проигрыш. В этом случае нужно сохранить флаг "играть видео, когда появится такая возможность". Не хочу делать на одном флаге с autoplay во избежании возможных конфликтов.
playing = true;
if( streamClosed == true )
{
_stream.play( flvPath );
streamClosed = false;
}
else
{
_stream.resume( );
}
addEventListener(Event.ENTER_FRAME, update, false, 0, true);
}
public function pause():void {
removeEventListener(Event.ENTER_FRAME, update);
playing = false;
_stream.pause();
}
public function stop():void {
pause();
makeThumbnail();
_stream.close();
streamClosed = true;
_video.clear();
}
// Создание картинки-заглушки на основе текущего кадра
public function makeThumbnail():void
{
var thumbnailData:BitmapData = new BitmapData( vw, vh, false, 0x000000 );
try{
thumbnailData.draw( _video as DisplayObject );z
} catch(error:Error){ ExternalInterface.call('console.log', error);}
var thumbnail:Bitmap = new Bitmap( thumbnailData );
//addChild( thumbnail );
}
public function volume(v:Number):void {
_stream.soundTransform = new SoundTransform( v / 100 );
}
public function complete():void {
removeEventListener(Event.ENTER_FRAME, update);
playing = false;
percent = 1;
playbackComplete();
}
public function seek(seconds:Number):void {
_stream.seek(seconds);
percent = seconds * duration / 100;
}
public function update(evt:Event):void {
percent = _stream.time/duration;
}
public function getTime():int {
return _stream.time;
}
public function getDuration():int {
return duration;
}
public function getPercent():Number {
return percent;
}
public function press(evt:Event):void {
removeEventListener(Event.ENTER_FRAME, update);
_stream.pause();
}
/*private function drag(evt:Event):void {
percent = _seekBar.percent;
playbackProgress();
}*/
private function release(evt:Event):void {
seek(percent = _seekBar.percent);
if (playing == false) {
play();
} else {
pause();
}
}
public function get percent():Number {
return _percent;
}
public function set percent(param:Number):void {
_percent = param;
if (_percent >= 1) {
_percent = 1;
completed = true;
} else {
completed = false;
}
_seekBar.percent = _percent;
playbackProgress();
}
}
//////////////////////////////////////////////////
// StreamClient
//////////////////////////////////////////////////
import flash.events.EventDispatcher;
import flash.events.Event;
class StreamClient extends EventDispatcher {
public var info:Object;
public var duration:Number;
public var width:Number;
public var height:Number;
public function StreamClient() {
}
public function onMetaData(metaData:Object):void {
info = metaData;
duration = info.duration;
width = info.width;
height = info.height;
dispatchEvent(new Event(Event.INIT));
}
}
//////////////////////////////////////////////////
// PlayPauseBtnクラス
//////////////////////////////////////////////////
/*import flash.display.Sprite;
import flash.display.Shape;
import flash.events.MouseEvent;
import flash.geom.ColorTransform;
class PlayPauseBtn extends Sprite {
public var id:uint;
private var _playing:Boolean = false;
public function PlayPauseBtn() {
init();
}
private function init():void {
playing = false;
}
public function get playing():Boolean {
return _playing;
}
public function set playing(param:Boolean):void {
_playing = param;
}
}*/
//////////////////////////////////////////////////
// SeekBar
//////////////////////////////////////////////////
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
class SeekBar extends Sprite {
public var id:uint;
private var _progress:Number = 0;
private var _percent:Number = 0;
private var _enabled:Boolean = true;
public function SeekBar() {
init();
}
private function init():void {
progress = 0;
percent = 0;
}
public function initialize():void {
init();
}
public function get progress():Number {
return _progress;
}
public function set progress(param:Number):void {
_progress = param;
}
public function get percent():Number {
return _percent;
}
public function set percent(param:Number):void {
_percent = param;
}
}