Stream an FLVPlayback through the internet - actionscript-3

I have a video in flash in the size of 19 MB (5 minutes) and I want the user to see what that has been loaded so far, or even get an indication of what has been loaded - so he won't be stuck in a blank screen until the video loads.
The quality of the video is important so I won't resize it - but how can I:
stream it so the user can see what that has been loaded so far
give him an indication of how long he will need to wait until it loads.
My code looks something like this:
import fl.video.*;
var video = new FLVPlayback();
video.fullScreenTakeOver = false;
video.source = "MansfredLoop.f4v";
stage.addChild(video);
Where do I start?

import fl.video.*;
var totalBytes:int;
var loadedBytes:int;
var remainingBytes:int;
var myTimer:Timer = new Timer(100);
var video = new FLVPlayback();
video.fullScreenTakeOver = false;
video.source = "MansfredLoop.f4v";
stage.addChild(video);
myTimer.addEventListener("timer", timerHandler);
myTimer.start();
totalBytes = video.bytesLoaded;
function timerHandler(event:TimerEvent):void {
loadedBytes = video.bytesLoaded;
remainingBytes = totalBytes - loadedBytes;
}

Related

Play two videos simultaneously with sync in AS3

I am busy with a project where two videos have to play on top of each other.
Like the one in the following site, http://kindnessday.sg/home#/kindness/home
Because of the large filesize I cannot embed the videos in the swf. It will become too large. Therefore the video's must be loaded thro' webstream link. But First video plays before the second video and causing the videos unsynced.
Is there a way to play both video at the same time?
var stream = 'http://mydomain/clip1.mp4'
var stream1 = 'https://mydomain/clip2.mp4'
var http_stream:URLStream = null
var http_stream1:URLStream = null
var video:Video = new Video() // the video is used only to ensure that stream is playing
var video1:Video = new Video() // the video is used only to ensure that stream is playing
addChild(video1)
addChild(video)
var nc:NetConnection = new NetConnection()
nc.connect(null)
var ns:NetStream = new NetStream(nc)
ns.client = new Object()
ns.client.onMetaData = function(e){}
ns.play(null)
var ns1:NetStream = new NetStream(nc)
ns1.client = new Object()
ns1.client.onMetaData = function(e){}
ns1.play(null)
video.attachNetStream(ns)
video1.attachNetStream(ns1)
http_stream = new URLStream();
http_stream.addEventListener(ProgressEvent.PROGRESS, on_Progress)
http_stream.load(new URLRequest(stream))
http_stream1 = new URLStream();
//http_stream1.addEventListener(ProgressEvent.PROGRESS, on_Progress1)
http_stream1.load(new URLRequest(stream1))
function on_Progress(e:ProgressEvent):void {
var b:ByteArray = new ByteArray()
http_stream.readBytes(b, 0, http_stream.bytesAvailable)
ns.appendBytes(b)
var b1:ByteArray = new ByteArray()
http_stream1.readBytes(b1, 0, http_stream1.bytesAvailable)
ns1.appendBytes(b1)
if (ns.appendBytes(b)==ns1.appendBytes(b1)){
ns.play(stream);
ns1.play(stream1);
}
}
why not not check how much of each video has loaded and when you have enough amount (you decide) then you can run some function to play both netstreams...
var min_amount : int = 500000; //for 500 kb minimum
var check_if_ready : Boolean = true;
Also on progressEvent function of loading (URLloader or URLstream???)..
if ( check_if_ready == true )
{
if( myA_NetStream.bytesLoaded >= min_amount && myB_NetStream.bytesLoaded >= min_amount )
{
myA_NetStream.play(); myB_NetStream.play();
//reset since not needed on further progressEvents during this load
check_if_ready = false;
}
}
}
This should only play when both videos have loaded x-amount of bytes. Therefore you can be sure none starts before another)
For better synchronization control you should get into handling bytes in Flash/AS3 and using the AppendBytes method because then you can control playback on a frame-by-frame basis for both NetStreams.

Using present time of video to manage all video in Action Script 3.0

I would like to use present time of video to manage all video. For example, I have some cue points, I choose it and video is now playing from this cue point, and after 10 sec video goes to other part and everything depends on present time of video. I do not use it on web so my video isn't loading (I mean that property of VideoProgressEvent like bytesLoaded will not help me). Is it possible to do it in action script 3.0 ? Another question is if I can add some transitions between cue points.
import fl.video.*;
// Video component instance name
var flvControl:FLVPlayback = display;
var flvSource:String = "myMovie.flv";
// Set video
flvControl.source = flvSource;
var myTextFormat:TextFormat = new TextFormat();
myTextFormat.size = 20
btn1.setStyle("textFormat", myTextFormat);
btn2.setStyle("textFormat", myTextFormat);
btn3.setStyle("textFormat", myTextFormat);
btn4.setStyle("textFormat", myTextFormat);
display.autoPlay = false;
// Add seek to time code
function seekToTimeHandler1(event:MouseEvent):void
{
var sec:Number = 15;
flvControl.seek(sec);
}
btn1.addEventListener(MouseEvent.CLICK, seekToTimeHandler1);
// Add seek to time code
function seekToTimeHandler2(event:MouseEvent):void
{
var sec:Number = 61;
flvControl.seek(sec);
}
btn2.addEventListener(MouseEvent.CLICK, seekToTimeHandler2);
// Add seek to time code
function seekToTimeHandler3(event:MouseEvent):void
{
var sec:Number = 63;
flvControl.seek(sec);
}
btn3.addEventListener(MouseEvent.CLICK, seekToTimeHandler3);
// Add seek to time code
function seekToTimeHandler4(event:MouseEvent):void
{
var sec:Number = 80;
flvControl.seek(sec);
}
btn4.addEventListener(MouseEvent.CLICK, seekToTimeHandler4);

AS3 - XML Playlist with Single-Track Looping

So this one has me stumped. My plan for my website is to have music tracks pulled from an XML file which act as the background music for the various .swfs loaded by the menu buttons. I.e. hit 'Home', and it takes you back to the home .swf and plays the appropriate music. I want to do this through XML rather than attaching the music directly to the .swf to cut down on load time (syncing isn't a concern), as I can't seem to retain audio quality without bulking up the .swf significantly.
I'm encountering two problems: one is that with the current code, the music only plays once, and doesn't loop. The other is that I want the functionality to play one song as an intro, and then continue to loop another. I.e., hit the home button, intro plays, followed by the looping section, and never returns to the intro unless you hit home again. I can't seem to figure out how to manage either of these things short of creating a unique function for every single button.
Here's the code I'm using:
var my_songs:XMLList;
var my_total:Number;
var my_sound:Sound;
var my_channel:SoundChannel;
var current_song:Number;
var myXMLLoader:URLLoader = new URLLoader();
myXMLLoader.load(new URLRequest("playlist.xml"));
myXMLLoader.addEventListener(Event.COMPLETE, processXML);
function processXML(e:Event):void {
var myXML:XML = new XML(e.target.data);
my_songs = myXML.SONG;
my_total = my_songs.length();
//playSong(0);
myXMLLoader.removeEventListener(Event.COMPLETE, processXML);
myXMLLoader = null;
}
function playSong(mySong:Number):void {
var myURL = my_songs[mySong].#URL;
if (my_channel) {
my_channel.stop();
my_channel.removeEventListener(Event.SOUND_COMPLETE, playSong);
}
my_sound = new Sound();
my_sound.load(new URLRequest(myURL));
my_channel = my_sound.play();
my_channel.addEventListener(Event.SOUND_COMPLETE, playSong);
}
test_btn.addEventListener(MouseEvent.CLICK, onPlay);
function onPlay(e:MouseEvent):void {
playSong(0);
}
Thanks in advance for any help you can give!
YourSongstarting(0,999); // how ever you call to play the song
This above will repeat song forever. I suggest you stream the audio file as this will load the song quicker, then you can keep the songs in memory.you can still use xml or any other external textfile for the audio tracks locations or directly in flash/class files if this site is concrete.
any events you wold like to control simply compare the "Buffer" value out of 100%.Look up streaming audio as3 there are plenty of tutorials with source code if need be let me know i can give you an example.
You were close
var my_songs:XMLList;
var my_total:Number;
var my_sound:Sound;
var my_channel:SoundChannel;
var current_song:Number;
var myXMLLoader:URLLoader = new URLLoader();
myXMLLoader.load(new URLRequest("playlist.xml"));
myXMLLoader.addEventListener(Event.COMPLETE, processXML);
function processXML(e:Event):void {
var myXML:XML = new XML(e.target.data);
my_songs = myXML.SONG;
my_total = my_songs.length();
playSong(0);
myXMLLoader.removeEventListener(Event.COMPLETE, processXML);
myXMLLoader = null;
}
function playSong(e:Event):void {
if( current_song > my_total )
current_song = 0;
var myURL = my_songs[current_song++].#URL;
if (my_channel) {
my_channel.stop();
my_channel.removeEventListener(Event.SOUND_COMPLETE, playSong);
}
my_sound = new Sound();
my_sound.load(new URLRequest(myURL));
my_channel = my_sound.play();
my_channel.addEventListener(Event.SOUND_COMPLETE, playSong);
}
test_btn.addEventListener(MouseEvent.CLICK, onPlay);
function onPlay(e:MouseEvent):void {
playSong(e);
}

AS3 webcam resolution/size issue

I do not really know much in regard to Flash or Action Scripts but I have been having a bit of trouble with AS3 and webcams. I have a script that connects to a webcam and then sends its output to a php script that saves the captured image. This works all except for one problem. It seems that the maximum resolution allowed for the actual Camera object is 320x240. I went to the extreme of hooking a Canon 60D up as a webcam because I have a normal webcam that is supposed to have max resolution of 1280x720 and all I can get is a 320x240 image from it. What I have found so far is the max I can get out of the Canon is also 320x240. Maybe I have been looking at this to long but I am stumped. Below is a sample of the action script where videoCapture should be 1024x768. What happens instead is a 1024x768 image is created with a black background and in the top left is a 320x240 image from videoCapture. I could obviously resize this but that would defeat the purpose being poor quality. Is there something I am missing here or maybe some limitation of Flash even?
// adds event listener to the stage for keydown events.
stage.addEventListener(KeyboardEvent.KEY_DOWN, detectEnterKey);
import flash.display.Bitmap;
import flash.display.BitmapData;
import com.adobe.images.JPGEncoder;
import flash.ui.Keyboard;
import flash.events.KeyboardEvent;
var bandwidth:int = 0;
var quality:int = 100;
var cam:Camera = Camera.getCamera();
var videoCapture:Video = new Video();
var previewPortData:BitmapData = new BitmapData(1024, 768, true, 0x00000000);
var previewPort:Bitmap = new Bitmap(previewPortData);
function onCameraStatus(evt):void {
if (evt.code == "Camera.Muted") {
Security.showSettings(SecurityPanel.CAMERA);
}
}
// detects the keycode looking for enter key pressed.
function detectEnterKey(event:KeyboardEvent):void {
//trace("keycode: "+event.keyCode);
if (event.keyCode == Keyboard.ENTER) {
previewPortData.draw(videoCapture);
var myEncoder:JPGEncoder = new JPGEncoder(100);
var byteArray:ByteArray = myEncoder.encode(previewPortData);
var header:URLRequestHeader = new URLRequestHeader("Content-type", "application/octet-stream");
var saveJPG:URLRequest = new URLRequest("save.php");
saveJPG.requestHeaders.push(header);
saveJPG.method = URLRequestMethod.POST;
saveJPG.data = byteArray;
var urlLoader:URLLoader = new URLLoader();
urlLoader.addEventListener(Event.COMPLETE, sendComplete);
urlLoader.load(saveJPG);
function sendComplete(event:Event):void {
trace("compete");
}
}
}
if (cam == null) {
Security.showSettings(SecurityPanel.CAMERA);
} else {
cam.addEventListener(StatusEvent.STATUS, onCameraStatus)
cam.setQuality(bandwidth, quality);
cam.setMode(1024, 768, 30, false);
videoCapture.attachCamera(cam);
videoCapture.width = 1024;
videoCapture.height = 768;
addChild(videoCapture);
previewPort.x = 430;
previewPort.y = 50;
addChild(previewPort);
}
I also just had this problem. Solved it by including the width and height parameters when creating the Video object instead of setting them afterwards via Video.height and Video.width. Once i did that, all bitmapData taken from that video was correctly sized.
This is how i originally created the video that did not work (looked fine, but resulted in incorrectly sized bitmaps):
var vid = new Video();
vid.width = 640;
vid.height = 480;
...
This worked (bitmaps from this video were correctly sized):
var vid = new Video(640, 480);
...
Would love to know why the first way doesn't work. Maybe that's the bug mentioned above. (I didn't have access to that site so couldn't see it.)
Sounds like this bug was never fixed: http://bugs.adobe.com/jira/browse/FP-2138
I had a similar issue. What worked for me was that I replaced:
previewPortData.draw(videoCapture);
With:
previewPortData.draw(stage);

How can I make this Flash code work in IE when it's cached?

I have a flash file here, when the flash plays, it works fine, but in IE and if the flash was already loaded once and is now cached, it freezes up. After digging super deep on the internet I was able to find out the following:
There are a bunch of known bugs in
flash 9 and 10, one of those being an
issue with the Event.COMPLETE not
being fired from the main stage when
loading from cache when it's embedded
WMODE = "transparent" I'm not sure if
that's your issue, but it's worth
looking into. I've heard of a few
workarounds to the problem. One of
them being, not listening for for
progress or complete events at all and
just using a timed loop like
ENTER_FRAME or TIMER to watch the
bytesLoaded/bytesTotal.
My WMODE is window, but this makes the most sense to me. The loadText never gets set which tells me its not entering swfProgressHandle function. However the problem is I only wrote half this flash (everything inside init) in conjunction with someone else, but that other person I cannot get in contact with anymore. I am fairly new to flash so really don't know how to take his loading code and make it only run off timer events instead of progress and complete events (as said in the above quote) so that it will work in IE when cached. Can anyone help me on this? Most of the code is fine, it's just the beginning where those progress and complete handlers are for loading stuff that appears to be causing the issue.
package
{
//---Imports---
import flash.display.*;
import fl.transitions.Tween;
import fl.transitions.TweenEvent;
import fl.transitions.easing.*;
import flash.events.Event;
import flash.events.*;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.net.URLLoader;
import flash.net.URLRequest;
import flash.text.TextField;
import flash.utils.Timer;
import flash.utils.*;
import flash.text.Font;
public class FohLoader extends Sprite
{
//create and start load bar
private var loadBar:Sprite = new Sprite();
private var loadText:TextField = new TextField();
private var loadBarBg:Graphics = loadBar.graphics;
//load XML data
private var xmlLoader:URLLoader = new URLLoader();
private var xmlData:XML = new XML();
private var _queue:Array; //holds data objects of items to be loaded
private var _index:int; //the current item in the _queue
private var _images:Array; //holds DisplayObjects of the loaded images
public function FohLoader()
{
_queue = new Array();
_images = new Array();
_index = 0;
//waits for the stage to be created
addEventListener(Event.ADDED_TO_STAGE, stageReadyHandle);
}
private function stageReadyHandle(e:Event):void
{
removeEventListener(Event.ADDED_TO_STAGE, stageReadyHandle);
loadBarBg.lineStyle();
loadBarBg.beginFill(0x5a96c5, 1);
loadBarBg.drawRect(0, 0, 5, 10);
loadBarBg.endFill();
loadBar.x = (stage.stageWidth - 500)/2;
loadBar.y = 30;
loadBar.width = 5;
loadBar.height = 10;
this.addChild(loadBar);
loadText.x = (stage.stageWidth - 0)/2;
loadText.y = 50;
this.addChild(loadText);
//I have no idea if this crap works
//but you would have to do something like this if you want to keep your project to one swf file.
this.loaderInfo.addEventListener(ProgressEvent.PROGRESS, swfProgressHandle);
}
private function swfProgressHandle(e:ProgressEvent):void
{
//assumes you want the loadbar to be 500px at 100%
var getPercent:Number = bytesLoaded / e.bytesTotal;
trace(bytes_loaded + " of " + bytes_total + " loaded");
loadBar.width = getPercent * 150; //changed 500 to 150
loadText.text = String(Math.round(getPercent * 30) + "%"); //changed 100 to 30
if (e.bytesLoaded / e.bytesTotal >= 1)
{
e.target.removeEventListener(ProgressEvent.PROGRESS, swfProgressHandle);
loadXml();
}
}
private function loadXml()
{
xmlLoader.addEventListener(Event.COMPLETE, ParseXML);
xmlLoader.load(new URLRequest("flash.xml"));
}
private function ParseXML(e:Event):void
{
e.target.removeEventListener(Event.COMPLETE, ParseXML);
flashInputs = new XML(e.target.data);
//declare all XMl variables, terrible way to do it though
var imageURLList:XMLList = flashInputs.image_area.image.image_url;
var firmCount:XMLList = flashInputs.count_area.total_firms;
var quoteMsg:XMLList = flashInputs.quote_area.quote.quote_text;
var quoteOwner:XMLList = flashInputs.quote_area.quote.quote_owner;
var imageURL:XMLList = flashInputs.image_area.image.image_url;
var imageText:XMLList = flashInputs.image_area.image.image_text;
var quoteMsg0:XML = quoteMsg[0];
var quoteMsg1:XML = quoteMsg[1];
var quoteMsg2:XML = quoteMsg[2];
var quoteMsg3:XML = quoteMsg[3];
var quoteMsg4:XML = quoteMsg[4];
var quoteMsg5:XML = quoteMsg[5];
var quoteMsg6:XML = quoteMsg[6];
var quoteOwner0:XML = quoteOwner[0];
var quoteOwner1:XML = quoteOwner[1];
var quoteOwner2:XML = quoteOwner[2];
var quoteOwner3:XML = quoteOwner[3];
var quoteOwner4:XML = quoteOwner[4];
var quoteOwner5:XML = quoteOwner[5];
var quoteOwner6:XML = quoteOwner[6];
var imageText0:XML = imageText[0];
var imageText1:XML = imageText[1];
var imageText2:XML = imageText[2];
var imageText3:XML = imageText[3];
var imageText4:XML = imageText[4];
var imageText5:XML = imageText[5];
var imageText6:XML = imageText[6];
var imageURL0:XML = imageURL[0];
var imageURL1:XML = imageURL[1];
var imageURL2:XML = imageURL[2];
var imageURL3:XML = imageURL[3];
var imageURL4:XML = imageURL[4];
var imageURL5:XML = imageURL[5];
var imageURL6:XML = imageURL[6];
//loops through the imageURL array and adds each item to the queue
for each(var img:XML in imageURL)
{
addItem(String(img));
}
//loads the first item in the queue
loadItem();
}
//creates a new loader for the item
//adds a data object holding the item path and loader into the queue
private function addItem(path:String):void
{
var loader:Loader = new Loader();
_queue.push({loader:loader, path:path});
}
private function loadItem():void
{
_queue[_index].loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imgCompleteHandle);
_queue[_index].loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, IOErrorHandle);
_queue[_index].loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, imgProgressHandle);
_queue[_index].loader.load(new URLRequest(_queue[_index].path));
}
//checks the progress of each image, and increases the width of the load bar
private function imgProgressHandle(e:ProgressEvent):void
{
var perc:Number = e.bytesLoaded / e.bytesTotal;
//this line assumes you are loading 6 images, and want the loadbar to end up at 500px
//it also assumes the bar has already reached 30% (150px) from loading the swf
loadBar.width = 150 + (_index * (350 / 6)) + ((350 / 6) * perc);
//so the swf's 150 + (how many images have alrady loaded * the width each image needs to affect the bar) +
//(same thing * percent of current image loaded)
//sounds right, might have to mess with that.
}
//this just stops flash from outputting an error if the image fails to load
private function IOErrorHandle(e:IOErrorEvent):void
{
e.target.removeEventListener(Event.COMPLETE, imgCompleteHandle);
e.target.removeEventListener(IOErrorEvent.IO_ERROR, IOErrorHandle);
trace("Error handled, sir.");
trace("The problem was that, " + e);
}
private function imgCompleteHandle(e:Event):void
{
e.target.removeEventListener(Event.COMPLETE, imgCompleteHandle);
e.target.removeEventListener(ProgressEvent.PROGRESS, imgProgressHandle);
e.target.removeEventListener(IOErrorEvent.IO_ERROR, IOErrorHandle);
//adds the image to the _images array
_images.push(e.target.content);
//increments the load counter
_index++;
//checks to see if the queue is finished or not
if (_index < _queue.length)
{
trade("Not done loading, loading another item");
loadItem();
}
else
{
_index = 0;
_queue = [];
killLoadBar();
init();
}
}
private function killLoadBar()
{
this.removeChild(loadBar);
this.removeChild(loadText);
}
If you dont mind the flash loading every time and not using the cache you could just append a cache breaker to the swf url.
Any random thing will do.
Here's a example using swfobject (http://code.google.com/p/swfobject/)
<script type="text/javascript">
var flashvars = {};
var params = {};
var attributes = {};
swfobject.embedSWF("myContent.swf?rand="+Math.random(), "myContent", "300", "120", "9.0.0","expressInstall.swf", flashvars, params, attributes);
</script>
This should work around any IE cache bugs.
If you still get the error with this, then it's should not be cache related.
After taking a quick look at this, I can see what might be happening.
You listen for ADDED_TO_STAGE.
You handle ADDED_TO_STAGE and then start listening for PROGRESS.
You then set the loadText, and load the XML if progress is "done".
The problem here seems to be the "done" part and the progress handling. First, the
loaderInfo object has a COMPLETE event. Why not use it? (http://livedocs.adobe.com/flex/3/langref/flash/display/LoaderInfo.html)
Then you could skip the whole bytesLoaded/bytesTotal check.
Where I think the applicatation might be freezing is when the loaderInfo has cached resources and skips the "PROGRESS" step altogether. Then you would never get into the LoadXML code, and never, therefore, parse the xml.
You can install firebug in Firefox and check whether you're even attempting to load the XML file using the "net" tab. (or use a tool like filemon).