AS3 NetStream doesn't seem to close - actionscript-3

I'm using the following code to reuse a single FLVPlayback component variable.
Would anyone know why the NetStream doesn't stop?
public function clearVideoPlayer(newSource:String):void {
if (_videoFLV) {
removeChild(_videoFLV);
_videoFLV.getVideoPlayer(0).close();
_videoFLV = null;
}
_videoFLV = new FLVPlayback();
_videoFLV.autoPlay = false;
_videoFLV.autoRewind = false;
_videoFLV.width = 320;
_videoFLV.height = 240;
_videoFLV.source = newSource;
addChild(_videoFLV);
}
But after running the function several times, accoring to Scout the NetStream doesn't get closed.
In the Network Events row of the UI I get
e.g. 4 x Recieving NetStream audio/video, 5 x Recieving NetStream audio/video, 2 x Recieving NetStream audio/video
This goes on indefinitely, long after the length of any of the videos.
Thanks,
Mark

Have you tried to replace
_videoFLV.getVideoPlayer(0).close();
by
_videoFLV.closeVideoPlayer(0);
Moreover, setting _videoFLV to null is useless since you assign a new value to it just after.

Related

How to make a score in a dynamic textfield display on another frame?

I'am trying to make a scoring system by using a timer so that it work on the basis that as the player keeps on going the timer/score keeps on going up and I got that to work with this code.
var nCount:Number = 0;
var myScore:Timer = new Timer(10, nCount);
score_txt.text = nCount.toString();
myScore.start();
myScore.addEventListener(TimerEvent.TIMER, countdown);
function countdown(e:TimerEvent):void{
nCount++;
score_txt.text = nCount.toString();
}
However say for example the player crashes I want the game to remember the score and then display it on another frame where I have a game over screen so that it shows the final score to the player and this is the part that I have no idea how to do. Any help would be appreciated.
Many Thanks
You can't modify objects on "another frame". You can only modify objects on the current frame. The frames simply represent state that is baked into the SWF to be actualized when the timeline reaches those frames; you cannot change SWF frame data at runtime. You can only change the resulting objects once those frames are constructed by the player.
What you can do is store your score in a variable (available across all frames) and simply set the correct text objects when you are on those frames.
For your code, you simply need to only set the nCount to 0 when the SWF loads (or you want to reset it), and set the score_txt immediately on the frame it exists. For example, you could do it like this:
// Don't initialize a value, that would overwrite
// it every time this frame is visited
var nCount:Number;
// Only the first time, when the value is NaN, set the score to 0
if(isNaN(nCount)){
nCount = 0;
}
// Immediately show the current score text
score_txt.text = nCount.toString();
// The rest stays the same
var myScore:Timer = new Timer(10, nCount);
score_txt.text = nCount.toString();
myScore.start();
myScore.addEventListener(TimerEvent.TIMER, countdown);
function countdown(e:TimerEvent):void{
nCount++;
score_txt.text = nCount.toString();
}

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 CS5:AS3 - Import swf to play for X seconds?

I need to have a swf load at the beginning, but I don't want to play about the last 3 seconds of the video.
Can someone help me out with a code that would basically have my swf play for "x" seconds?
Heres what I Have so far.. Currently it is set up to play the swf, but subtract "x" seconds from it but for some reason it doesn't seem to work
var mySwf:MovieClip;
var reducedTotalFrames:int;
var clipLoader:Loader = new Loader();
clipLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);
clipLoader.load(new URLRequest("schoolintro.swf"));
function loadComplete(e:Event):void
{
mySwf = LoaderInfo(e.currentTarget).content as MovieClip;
var totalFrameCount:int = mySwf.currentScene.numFrames;
var secondsToSubtract:int = 3;
var threeSecondFrameCount:int = (stage.frameRate * secondsToSubtract);
reducedTotalFrames = totalFrameCount - threeSecondFrameCount;
stage.addEventListener(Event.ENTER_FRAME, onRender);
stage.addChild(mySwf);
}
function onRender(e:Event):void
{
if(mySwf != null && mySwf.currentFrame >= reducedTotalFrames){
//This is the end of the SWF with 3 seconds trimmed off. Here we can stop play
stage.removeEventListener(Event.ENTER_FRAME, onRender);
mySwf.stop();
//doSomethingElse();
}
}
Try some basic debugging, like placing trace statements in the code inside onRender to ensure it's being called, to ensure the mySwf reference is working correctly (for example, tracing out mySwf.currentScene.numFrames, and if its 0, you know you're not referencing your swf properly or the swf is not frame-based). If it the SWF is not frame-based, then you're going to have real issues controlling or even doing anything about this since all the animation/action going on inside the loaded SWF is code-based.
I think you just need to change this line from
var threeSecondFrameCount:int = (stage.frameRate * secondsToSubtract);
to
var threeSecondFrameCount:int = (stage.frameRate / secondsToSubtract);
not sure is this what you want or not.

Getting metadata from multiple preloading video

I found out that I could only get the metadata of the 1st video I clicked. How does metadata works? It could only load once before the video ends?
Here's some example what I'm doing
//will be adding new video when this function is called
public function set newVideo():void
{
videoProperties();
}
public function videoProperties():void
{
meta=new Object()
nc = new NetConnection();
nc.connect(null);
ns = new NetStream(nc);
nsArray[dList.currentIndex] = ns;
nsi = nsArray[dList.currentIndex];
// Add the buffer time to the video Net Stream
nsi.bufferTime = buffer;
// Set client for Meta Data Function
nsi.client = {};
nsi.client.onMetaData = onMetaData;
nsi.addEventListener(AsyncErrorEvent.ASYNC_ERROR,asyncErrorHandler);
nsi.addEventListener(NetStatusEvent.NET_STATUS, onNetStatusEvent);
nsi.play(videoURL);
nsi.pause();
nsi.seek(-1);
}
private function onMetaData(info:Object):void
{
//some video duration calculations
}
I tried to load all the metadata at once, but seems like it needs the video to be play only it will manage to get the metadata.
Are you trying to get the metadata without starting the video loading process? If so, that's not possible with actionscript alone. That said, since flvs load progressively you don't need to load an entire video to get at the meta data. You can load each video and stop loading it when you've got the metadata.

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);