Flash AS3 load videos while another is playing - actionscript-3

my flash site needs to play let's say 10 videos one after each other, to reduce waiting time I need to preload video 2 and video 3 while video 1 is playing and so on...
I need to follow this structure because at the end of video 1 users will have the chance to choose which will be the next (2 or 3).
All the code is on the first frame of my movie, I still have to learn classes, packages etc.
The first video is played through a linked video (myVideo) that I placed on the stage with the following code:
var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
ns.addEventListener(NetStatusEvent.NET_STATUS, statusHandler);
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
ns.play("video1.f4v");
var myVideo:Video = new Video();
myVideo.attachNetStream(ns);
addChild(myVideo);
I need to understand the best way to preload the other two videos while nr. 1 is playing.
Shall I create 2 more linked videos, place them out of the stage and load videos there so they will be immediately available when needed?
Thanks very much for your help!
--- EDIT: Added more details to my post ---
I'm doing some test to understand this procedure, I've tried the following:
var ns2:NetStream = new NetStream(nc);
var ns3:NetStream = new NetStream(nc);
ns2.play("video/video2.f4v");
ns2.pause();
ns2.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
ns3.play("video/video3.f4v");
ns3.pause();
ns3.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
it works, but loading 2 movies in this way will result in 100% cpu usage and poor frame rate of video playing... maybe I have to load video 2, check for loading complete and then start loading video 3... is this the proper way to do that?
Thanks again

I believe I found the way, here is the full script:
var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
ns.addEventListener(NetStatusEvent.NET_STATUS, statusHandler);
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
ns.play("video1.f4v");
var myVideo:Video = new Video();
myVideo.attachNetStream(ns);
addChild(myVideo);
var ns2:NetStream = new NetStream(nc);
var ns3:NetStream = new NetStream(nc);
function statusHandler(event:NetStatusEvent):void
{
switch (event.info.code)
{
case "NetStream.Play.Start" :
ns2.play("video/video2.f4v");
ns2.pause();
ns2.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
ns3.play("video/video3.f4v");
ns3.pause();
ns3.addEventListener(AsyncErrorEvent.ASYNC_ERROR, asyncErrorHandler);
break;
case "NetStream.Play.Stop" :
trace("ns video stop");
break;
}
}
when I call ns.play("video2.f4v"); the video is already in the browser cache so immediately starts playing and Cpu usage looks good too.
If there is a more professional way I'd like to learn more.
trace("thanks, see you soon");

The easiest way of achieving this would be using Greensock's LoaderMax. You can set up the list of videos you want to load and then prioritise some of them depending of user's actions.
LoaderMax has some great functionality which would be quite hard to build from scratch, it also fixes some weird Flashplayer behaviour.
There is a little bit of learning curve but it is not too steep.

Related

Getting Bitmap from Video decoded with Nestream AppendBytes (AS3)?

I am wondering if someone who has handled NetStream.appendBytes in Flash knows how to get the bitmapData from a decoded video frame? I have already looked at this question but that is from 3 years ago and the more recent comment/answer seems to be gone. In 2014 has anyone managed to turn those bytes into a bitmap? I am working with Flash Player 11.8 and this is not a desktop/AIR app.
In the image below I can do steps 1) and 2) but there's a brick wall at step 3)
The problem is that simply using bitmapdata.draw(video_container); does not work but instead it throws a Policy File error even though I am using a byteArray (from local video file in the same directory as the SWF). No internet is even involved but Flash tells me that "No Policy File granted permission from the server" or such nonsense. I think the error is just a bail-out insteading of straight up saying "You are not allowed to do this.."
I have tried: trying to appease this Crossdomain.xml issue anyway and looking into all known security/domain settings. I came to the conclusion that the error is not the problem but a side effect of the issue.. The issue here being that: Flash Player is aware of the SWF's location and of any files local to it. That's okay when you pass a String as URL etc but when the Netstream data is not local to the SWF domain then it becomes a Policy File issue. Problem is my data is in the Memory not in a folder like the SWF and therefore cannot alllow bitmapData.draw since it cannot "police" an array of bytes, any known fixes for this?... (I can't even say the words I really wanted to use).
What I am trying to achieve: Is to essentially use Netstream as an H.263 or H.264 image decoder in the same way Loader is a JPEG-to-Bitmap decoder or LoadCompressed.. is an MP3-to-PCM decoder. You know, access the raw material (here RGB pixels), apply some effects functions and then send to screen or save to disk.
I know it is a little late, but I think I found a solution for your problem.
So, to avoid the Security sandbox violation #2123 Error, you have just to do like this :
// ...
net_stream.play(null);
net_stream.play('');
// ...
Hope that can help.
I know this question is a couple months old, but I wanted to post the correct answer (because I just had this problem as well and other will too).
Correct answer:
It's a bug that has been open at adobe for almost 2 years
Link to the bug on Adobe
Work Around until the bug gets fixed (I am using this and it works great):
Workaround using Sprite and graphics
To take a snapshot from a video stream we don't need NetStream.appendBytes which inject data into a NetStream object.
For that we can use BitmapData.draw which has some security constraints. That's why in many times we get a flash security error. About that, Adobe said :
"... This method is supported over RTMP in Flash Player 9.0.115.0 and later and in Adobe AIR. You can control access to streams on Flash Media Server in a server-side script. For more information, see the Client.audioSampleAccess and Client.videoSampleAccess properties in Server-Side ActionScript Language Reference for Adobe Flash Media Server. If the source object and (in the case of a Sprite or MovieClip object) all of its child objects do not come from the same domain as the caller, or are not in a content that is accessible to the caller by having called the Security.allowDomain() method, a call to the draw() throws a SecurityError exception. This restriction does not apply to AIR content in the application security sandbox. ...".
For crossdomain file creation and some other security config for AMS server, you can take a look on this post : Crossdomain Video Snapshot - Fixing BitmapData.draw() Security Sandbox Violation.
After allowing our script to get data from our video stream, we can pass to the code.
I wrote a code that play a video stream ( rtmp or http ) and take a snapshot to show it in the stage or save it as a file after applying a pixel effect :
const server:String = null; //'rtmp://localhost/vod'
const stream:String = 'stream'; // 'mp4:big_buck_bunny_480p_h264.mp4';
var nc:NetConnection;
var ns:NetStream;
var video:Video;
const jpg_quality:int = 80;
const px_size:int = 10;
nc = new NetConnection();
nc.addEventListener(AsyncErrorEvent.ASYNC_ERROR, function(e:AsyncErrorEvent):void{});
nc.addEventListener(NetStatusEvent.NET_STATUS, function(e:NetStatusEvent):void{
if(e.info.code == 'NetConnection.Connect.Success'){
ns = new NetStream(nc);
ns.addEventListener(NetStatusEvent.NET_STATUS, function(e:NetStatusEvent):void{});
ns.addEventListener(AsyncErrorEvent.ASYNC_ERROR, function(e:AsyncErrorEvent):void{});
video = new Video(320, 180);
video.x = video.y = 10;
video.attachNetStream(ns);
addChild(video);
ns.play(stream);
}
})
nc.connect(server);
btn_show.addEventListener(
MouseEvent.CLICK,
function(e:MouseEvent): void{
var bmp:Bitmap = pixelate(video, px_size);
bmp.x = 10;
bmp.y = 220;
addChild(bmp);
}
)
btn_save.addEventListener(
MouseEvent.CLICK,
function(e:MouseEvent): void{
var bmp:Bitmap = pixelate(video, px_size);
var jpg_encoder:JPGEncoder = new JPGEncoder(80);
var jpg_stream:ByteArray = jpg_encoder.encode(bmp.bitmapData);
var file:FileReference = new FileReference();
file.save(jpg_stream, 'snapshot_'+int(ns.time)+'.jpg');
}
)
function pixelate(target:DisplayObject, px_size:uint):Bitmap {
var i:uint, j:uint = 0;
var s:uint = px_size;
var d:DisplayObject = target;
var w:uint = d.width;
var h:uint = d.height;
var bmd_src:BitmapData = new BitmapData(w, h);
bmd_src.draw(d);
var bmd_final:BitmapData = new BitmapData(w, h);
var rec:Rectangle = new Rectangle();
rec.width = rec.height = s;
for (i = 0; i < w; i += s){
for (j = 0; j < h; j += s){
rec.x = i;
rec.y = j;
bmd_final.fillRect(rec, bmd_src.getPixel32(i, j));
}
}
bmd_src.dispose();
bmd_src = null;
return new Bitmap(bmd_final);
}
Of course, this is just a simple example to show the manner to get a snapshot from a video stream, you should adapt and improve it to your needs ...
I hope all that can help you.

flash/AS3 netstream loading/buffering very slow, what am I missing?

My custom movieplayer uses the following code for playing video. It takes a really long time for the clip to start playing, but once it does, you can skip directly to the end.
I have a feeling that there is some knowledge I'm missing in how buffers and preload works. Could somebody send me in the right direcion?
private function init(e:Event = null):void {
connection = new NetConnection();
connection.addEventListener(NetStatusEvent.NET_STATUS, doNetStatus);
connection.addEventListener(IOErrorEvent.IO_ERROR, doIOError);
connection.addEventListener(SecurityErrorEvent.SECURITY_ERROR, doSecurityError);
connection.connect(null);
stream = new NetStream(connection);
stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR, doAsyncError);
stream.addEventListener(NetStatusEvent.NET_STATUS, doNetStatus);
stream.addEventListener(IOErrorEvent.IO_ERROR, doIOError);
stream.client = this;
video = new Video(1024, 576);
mc = new MovieClip();
mc.addChild(video);
stage.addChild(mc);
mc.addEventListener(MouseEvent.CLICK, onClick);
video.attachNetStream(stream);
stream.bufferTime = 5;
stream.receiveAudio(true);
stream.receiveVideo(true);
stream.play(SITEURL + vidID +".mp4");
}
You can see the player in action here: http://joon.be/serve/ngjd_player.swf
Apparently the video's weren't streaming because I needed to run QT FastStart on them.
This solved the problem, netstream is now running as expected.
You can download qt-faststart.exe and then in admin command promt run:
qt-faststart.exe "source.mp4" "fixed.mp4"
Took about 15-30 seconds for 10 minutes long video.
Credit: https://articulate.com/support/article/mp4-movie-doesnt-begin-playing-until-it-has-fully-downloaded
I also tried this free opensource converter HandBrake with Web Optimized checked. (took all 10 minutes to convert)

if I load a flv with netStream, how can I call a function when the flv stops playing

I have a website in ActionScript 3 that has lots of FLV animations that happen when you press buttons. Right now this is how I have it set up.
in AS3,
im loading FLv's (which are animations I exported in FLV form from After Effects)
with net stream. I have a timer set up for the same amount of length of time that the animations (FLV's) play and when the timer stops it calls a function that closes the stream, opens a new one and plays another video. The only problem I noticed using timers is that if the connection is slow and (animation)stops for a second, the timer keeps going, and calls the next flv too early.
Does anyone know a way to load a flv, or swf for that matter, at the end of play of the flv? so that the next FLV will always play at the end of the run time of the previous FLV, rather than using timers?
im thinking onComplete but I don't know how to implement that!?
Sequential playing is pretty easy to achieve with the OSMF framework, you should check it out. Google "osmf tutorials" and you should find a few tutorials online.
The framework is fairly recent, but it looks like it may become the de facto solution for media delivery in Flash as it's not limited to video but also audio & images.
As a developer you won't have to bother with the NetStream & NetConnection classes. Developing video solutions , as well as audio & images solutions should be streamlined and easier to handle. Only limitation is that it requires Flash 10
Here's some code for checking when a FLV ends with NetStream. I just provide snippets as I assume you got the FLV up and running already.
//create a netstream and pass in your connection
var netStream:NetStream = new NetStream(conn);
//add callback function for PlayStatus -event
var client : Object = {};
client.onPlayStatus = onPlayStatus;
netStream.client = client;
//attach your NetStream to the connection as usual
//---
//function that gets called onPlayStatus
function onPlayStatus(info : Object) : void {
trace("onPlayStatus:" +info.code + " " + info.duration);
if (info.code == "NetStream.Play.Complete") {
//play the next FLV and so on
}
}
EDIT: With your example code it will look something like this.
var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
var listener:Object = new Object();
listener.onMetaData = function(md:Object):void{};
listener.onPlayStatus = function(info : Object) : void {
trace("onPlayStatus:" +info.code + " " + info.duration);
if (info.code == "NetStream.Play.Complete") {
//play the next FLV and so on
}
};
ns.client = listener;
vid1.attachNetStream(ns);
const moviename1:String = "moviename2.flv";
const moviename1:String = "moviename3.flv";
var movietoplay:String = "moviename.flv";
ns.play(movietoplay);

How would I go about playing a sound object in reverse in Actionscript 3?

For a project I'm working on, it's necessary that I am able to play a sound object in reverse. How would I be able to do this in AS3?
This is doable as of player 10, but it's not a quick/simple implementation. You'll have to build your own custom support. Lets take a look:
var soundSource:Sound; //assuming this actually references a real sound file such as a MP3
var position:int = soundSource.bytesTotal;
var numBytesToReadEachSample:int = 8192;
var snd:Sound = new Sound();
snd.addEventListener(SampleDataEvent.SAMPLE_DATA, sampleData);
snd.play();
function sampleData(e:SampleDataEvent):void {
position -= numBytesToReadEachSample;
//here we read data from our source, and write it to the playing sound
e.data.writeBytes(soundSource.extract(position, numBytesToReadEachSample))
}
That's NOT TESTED AND INCOMPLETE, but is the general idea of what you want to do. Hopefully it points you into the right direction!
More information here: http://www.adobe.com/livedocs/flex/3/langref/flash/events/SampleDataEvent.html#SampleDataEvent%28%29
Best of luck!

Some help with basic Sound functions in actionscript 3

I'm working on a mp3 player and I'm super new at all things flash so there are lots of questions. Currently I'm getting stuck on the track change. My variable declaration look like this:
var index:int = -1;
var music:Sound = new Sound(new URLRequest("moe2008-05-24d02t02_vbr.mp3"));
var sc:SoundChannel;
var isPlaying:Boolean = false;
and my change track function looks like this:
function changeTrack(newTrack){
sc.stop();
isPlaying = false;
music = new Sound(new URLRequest(newTrack));
sc = music.play();
isPlaying = true;
index++;
}
Does anyone see any obvious errors???
Thanks
I think you should try to close the Sound connection (Sound.close()) before creating a new one. Also, I would use the same Sound object to load the new file (Sound.load()) to avoid possible GC problems (unless you need to fade in between sounds)...
Looks to me like you're missing the part where you actually load the external sound into a new sound object. Your example seems to be reusing the same sound object. Should be something like:
var sound:Sound = new Sound();
var request:URLRequest = new URLRequest("path/to/your/sound");
sound.load(request);
sc = sound.play();
You need the local sound variable to create a new sound as another sound instance cannot be loaded into an existing one:
Once load() is called on a Sound
object, you can't later load a
different sound file into that Sound
object. To load a different sound
file, create a new Sound object.
You'll probably want to use a Dictionary to keep track of which Sounds are loaded already. So when this method is called, you check if a sound object is registered in the dictionary and if it is, play that instead of loading a file.
As Flash Gordon said: "You're actually
redefing the local variables when you
reset its
property."http://www.actionscript.org/forums/archive/index.php3/t-181659.html
This line looks a bit suspicious.
sc = music.play();
Shouldn't that be:
var musicPlay = music.play();
sc = musicPlay;