Re-enable video in the world.
There are a few rough edges which'll eventually get ironed out. git-svn-id: svn+ssh://src.earth.threerings.net/narya/trunk@4607 542714f4-19e9-0310-aa3c-eee0fc999fb1
This commit is contained in:
@@ -44,8 +44,6 @@ import flash.events.TextEvent;
|
||||
|
||||
import flash.geom.Point;
|
||||
|
||||
import flash.media.Video;
|
||||
|
||||
import flash.text.TextField;
|
||||
import flash.text.TextFieldAutoSize;
|
||||
|
||||
@@ -145,26 +143,12 @@ public class MediaContainer extends Sprite
|
||||
*/
|
||||
protected function setupVideo (url :String) :void
|
||||
{
|
||||
// TODO: re-implement video without flex
|
||||
var tf :TextField = new TextField();
|
||||
tf.autoSize = TextFieldAutoSize.LEFT;
|
||||
tf.text = "Video is temporarily disabled";
|
||||
tf.background = true;
|
||||
tf.selectable = false;
|
||||
tf.width = tf.textWidth + 5;
|
||||
setMediaObject(tf);
|
||||
|
||||
// var vid :VideoDisplay = new VideoDisplay();
|
||||
// vid.autoPlay = false;
|
||||
// _media = vid;
|
||||
// addChild(vid);
|
||||
// vid.addEventListener(ProgressEvent.PROGRESS, loadVideoProgress);
|
||||
// vid.addEventListener(VideoEvent.READY, loadVideoReady);
|
||||
// vid.addEventListener(VideoEvent.REWIND, videoDidRewind);
|
||||
//
|
||||
// // start it loading
|
||||
// vid.source = url;
|
||||
// vid.load();
|
||||
var vid :VideoDisplayer = new VideoDisplayer();
|
||||
vid.addEventListener(VideoDisplayer.SIZE_KNOWN, handleVideoSizeKnown);
|
||||
vid.addEventListener(VideoDisplayer.VIDEO_ERROR, handleVideoError);
|
||||
_media = vid;
|
||||
addChild(vid);
|
||||
vid.setup(url);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,25 +240,12 @@ public class MediaContainer extends Sprite
|
||||
|
||||
removeChild(loader);
|
||||
|
||||
// } else if (_media is VideoDisplay) {
|
||||
// var vid :VideoDisplay = (_media as VideoDisplay);
|
||||
// // remove any listeners
|
||||
// vid.removeEventListener(ProgressEvent.PROGRESS,
|
||||
// loadVideoProgress);
|
||||
// vid.removeEventListener(VideoEvent.READY, loadVideoReady);
|
||||
// vid.removeEventListener(VideoEvent.REWIND, videoDidRewind);
|
||||
//
|
||||
// // dispose of media
|
||||
// vid.pause();
|
||||
// try {
|
||||
// vid.close();
|
||||
// } catch (ioe :IOError) {
|
||||
// // ignore
|
||||
// }
|
||||
// vid.stop();
|
||||
//
|
||||
// // remove from hierarchy
|
||||
// removeChild(vid);
|
||||
} else if (_media is VideoDisplayer) {
|
||||
var vid :VideoDisplayer = (_media as VideoDisplayer);
|
||||
vid.removeEventListener(VideoDisplayer.SIZE_KNOWN, handleVideoSizeKnown);
|
||||
vid.removeEventListener(VideoDisplayer.VIDEO_ERROR, handleVideoError);
|
||||
vid.shutdown();
|
||||
removeChild(vid);
|
||||
|
||||
} else if (_media != null) {
|
||||
removeChild(_media);
|
||||
@@ -421,31 +392,24 @@ public class MediaContainer extends Sprite
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback to receive PROGRESS events on the video.
|
||||
* Handles video size known.
|
||||
*/
|
||||
protected function loadVideoProgress (event :ProgressEvent) :void
|
||||
protected function handleVideoSizeKnown (event :ValueEvent) :void
|
||||
{
|
||||
// var vid :VideoDisplay = (event.currentTarget as VideoDisplay);
|
||||
// updateContentDimensions(vid.videoWidth, vid.videoHeight);
|
||||
//
|
||||
// updateLoadingProgress(vid.bytesLoaded, vid.bytesTotal);
|
||||
var args :Array = (event.value as Array);
|
||||
updateContentDimensions(int(args[0]), int(args[1]));
|
||||
trace("Video size is now known: " + _w + ", " + _h);
|
||||
}
|
||||
|
||||
/**
|
||||
* A callback to receive READY events for video.
|
||||
* Handles an error loading a video.
|
||||
*/
|
||||
// protected function loadVideoReady (event :VideoEvent) :void
|
||||
// {
|
||||
// var vid :VideoDisplay = (event.currentTarget as VideoDisplay);
|
||||
// updateContentDimensions(vid.videoWidth, vid.videoHeight);
|
||||
// updateLoadingProgress(1, 1);
|
||||
//
|
||||
// vid.play();
|
||||
//
|
||||
// // remove the two listeners
|
||||
// vid.removeEventListener(ProgressEvent.PROGRESS, loadVideoProgress);
|
||||
// vid.removeEventListener(VideoEvent.READY, loadVideoReady);
|
||||
// }
|
||||
protected function handleVideoError (event :ValueEvent) :void
|
||||
{
|
||||
trace("Video load error: " + event.value);
|
||||
stoppedLoading();
|
||||
setupBrokenImage(-1, -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function to receive COMPLETE events for swfs or images.
|
||||
@@ -465,14 +429,6 @@ public class MediaContainer extends Sprite
|
||||
stoppedLoading();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the video auto-rewinds.
|
||||
*/
|
||||
// protected function videoDidRewind (event :VideoEvent) :void
|
||||
// {
|
||||
// (_media as VideoDisplay).play();
|
||||
// }
|
||||
|
||||
/**
|
||||
* Configure the mask for this object.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
package com.threerings.util { // TODO: Move.
|
||||
|
||||
import flash.display.Sprite;
|
||||
|
||||
import flash.events.AsyncErrorEvent;
|
||||
import flash.events.IOErrorEvent;
|
||||
import flash.events.Event;
|
||||
import flash.events.MouseEvent;
|
||||
import flash.events.NetStatusEvent;
|
||||
import flash.events.SecurityErrorEvent;
|
||||
import flash.events.TimerEvent;
|
||||
|
||||
import flash.media.Video;
|
||||
|
||||
import flash.net.NetConnection;
|
||||
import flash.net.NetStream;
|
||||
|
||||
import flash.utils.Timer;
|
||||
|
||||
public class VideoDisplayer extends Sprite
|
||||
{
|
||||
/** A value event dispatched when the size of the video is known.
|
||||
* Value: [ width, height ]. */
|
||||
public static const SIZE_KNOWN :String = "SIZE_KNOWN";
|
||||
|
||||
/** A value event sent when there's an error loading the video.
|
||||
* Value: original error event. */
|
||||
public static const VIDEO_ERROR :String = "VIDEO_ERROR";
|
||||
|
||||
public function VideoDisplayer ()
|
||||
{
|
||||
_vid = new Video();
|
||||
addChild(_vid);
|
||||
|
||||
addEventListener(MouseEvent.CLICK, handleClick);
|
||||
_videoChecker.addEventListener(TimerEvent.TIMER, handleVideoCheck);
|
||||
}
|
||||
|
||||
public function setup (url :String) :void
|
||||
{
|
||||
_netCon = new NetConnection();
|
||||
_netCon.addEventListener(NetStatusEvent.NET_STATUS, handleNetStatus);
|
||||
|
||||
// error handlers
|
||||
_netCon.addEventListener(AsyncErrorEvent.ASYNC_ERROR, handleAsyncError);
|
||||
_netCon.addEventListener(IOErrorEvent.IO_ERROR, handleIOError);
|
||||
_netCon.addEventListener(SecurityErrorEvent.SECURITY_ERROR, handleSecurityError);
|
||||
|
||||
_netCon.connect(null);
|
||||
trace("Not waiting, just using!");
|
||||
_netStream = new NetStream(_netCon);
|
||||
_netStream.client = this;
|
||||
//_netStream.client = new Callbacker(this);
|
||||
_vid.attachNetStream(_netStream);
|
||||
_videoChecker.start();
|
||||
_netStream.play(url);
|
||||
}
|
||||
|
||||
public function shutdown () :void
|
||||
{
|
||||
_videoChecker.reset();
|
||||
_vid.attachNetStream(null);
|
||||
|
||||
if (_netStream != null) {
|
||||
_netStream.close();
|
||||
_netStream = null;
|
||||
}
|
||||
if (_netCon != null) {
|
||||
_netCon.close();
|
||||
_netCon.removeEventListener(NetStatusEvent.NET_STATUS, handleNetStatus);
|
||||
_netCon.removeEventListener(AsyncErrorEvent.ASYNC_ERROR, handleAsyncError);
|
||||
_netCon.removeEventListener(IOErrorEvent.IO_ERROR, handleIOError);
|
||||
_netCon.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, handleSecurityError);
|
||||
_netCon = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check to see if we now know the dimensions of the video.
|
||||
*/
|
||||
protected function handleVideoCheck (event :TimerEvent) :void
|
||||
{
|
||||
if (_vid.videoWidth == 0 || _vid.videoHeight == 0) {
|
||||
return; // not known yet!
|
||||
}
|
||||
|
||||
// stop the checker timer
|
||||
_videoChecker.stop();
|
||||
|
||||
// set up the width/height
|
||||
_vid.width = _vid.videoWidth;
|
||||
_vid.height = _vid.videoHeight;
|
||||
|
||||
// tell any interested parties
|
||||
dispatchEvent(new ValueEvent(SIZE_KNOWN, [ _vid.videoWidth, _vid.videoHeight ]));
|
||||
}
|
||||
|
||||
protected function handleClick (event :MouseEvent) :void
|
||||
{
|
||||
trace("Click!");
|
||||
_netStream.togglePause();
|
||||
}
|
||||
|
||||
protected function handleNetStatus (event :NetStatusEvent) :void
|
||||
{
|
||||
var info :Object = event.info;
|
||||
if ("error" == info.level) {
|
||||
trace("NetStatus error: " + info.code);
|
||||
redispatchError(event);
|
||||
return;
|
||||
}
|
||||
// else info.level == "status"
|
||||
switch (info.code) {
|
||||
case "NetConnection.Connect.Success":
|
||||
trace("Connected!");
|
||||
break;
|
||||
|
||||
default:
|
||||
trace("NetStatus status: " + info.code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected function handleAsyncError (event :AsyncErrorEvent) :void
|
||||
{
|
||||
trace("AsyncError: " + event);
|
||||
redispatchError(event);
|
||||
}
|
||||
|
||||
protected function handleIOError (event :IOErrorEvent) :void
|
||||
{
|
||||
trace("IOError: " + event);
|
||||
redispatchError(event);
|
||||
}
|
||||
|
||||
protected function handleSecurityError (event :SecurityErrorEvent) :void
|
||||
{
|
||||
trace("SecurityError: " + event);
|
||||
redispatchError(event);
|
||||
}
|
||||
|
||||
protected function redispatchError (event :Event) :void
|
||||
{
|
||||
dispatchEvent(new ValueEvent(VIDEO_ERROR, event));
|
||||
}
|
||||
|
||||
public function callbackCalled (name :String, args :Array) :*
|
||||
{
|
||||
trace("Callback: " + name + ", args: " + args);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public function onMetaData (obj :Object) :void
|
||||
{
|
||||
trace("Got metadata..");
|
||||
for (var n :String in obj) {
|
||||
trace("name " + n + " -> " + obj[n]);
|
||||
}
|
||||
}
|
||||
|
||||
protected var _vid :Video;
|
||||
|
||||
protected var _netCon :NetConnection;
|
||||
|
||||
protected var _netStream :NetStream;
|
||||
|
||||
/** Checks the video every 100ms to see if the dimensions are now know.
|
||||
* Yes, this is how to do it. We could trigger on ENTER_FRAME, but then
|
||||
* we may not know the dimensions unless we're added on the display list,
|
||||
* and we want this to work in the general case. */
|
||||
protected var _videoChecker :Timer = new Timer(100);
|
||||
}
|
||||
}
|
||||
|
||||
import flash.utils.Proxy;
|
||||
|
||||
import flash.utils.flash_proxy;
|
||||
|
||||
import com.threerings.util.VideoDisplayer;
|
||||
|
||||
use namespace flash_proxy;
|
||||
|
||||
/**
|
||||
*/
|
||||
internal class Callbacker extends Proxy
|
||||
{
|
||||
public function Callbacker (displayer :VideoDisplayer)
|
||||
{
|
||||
_displayer = displayer;
|
||||
|
||||
_props
|
||||
}
|
||||
|
||||
override flash_proxy function hasProperty (name :*) :Boolean
|
||||
{
|
||||
return (_props[name] !== undefined);
|
||||
}
|
||||
|
||||
override flash_proxy function getProperty (name :*) :*
|
||||
{
|
||||
trace("Damn thing asked about '" + name + "'.");
|
||||
return _props[name];
|
||||
}
|
||||
|
||||
override flash_proxy function setProperty (name :*, value :*) :void
|
||||
{
|
||||
trace("Damn thing tried to set '" + name + "' to '" + value + "'.");
|
||||
_props[name] = value;
|
||||
}
|
||||
|
||||
override flash_proxy function deleteProperty (name :*) :Boolean
|
||||
{
|
||||
trace("Damn thing tried to delete '" + name + "'.");
|
||||
return (delete _props[name]);
|
||||
}
|
||||
|
||||
override flash_proxy function callProperty (name :*, ... args) :*
|
||||
{
|
||||
return _displayer.callbackCalled(name, args);
|
||||
}
|
||||
|
||||
protected var _props :Object = {};
|
||||
|
||||
protected var _displayer :VideoDisplayer;
|
||||
}
|
||||
Reference in New Issue
Block a user