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:
Ray Greenwell
2007-02-28 02:59:37 +00:00
parent d652de50e7
commit 8a46320e95
2 changed files with 249 additions and 68 deletions
+24 -68
View File
@@ -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;
}