How to Determine the Completion of a Flash Video (FLV) File (AS2)

ActionScript 2.0

Nearly a year ago, I posted a short entry on Flash video, “How to Load External Video (FLV).”  As of today, that article has received more feedback than any other on this blog, often asking how to tell when a video file has completed.  The article describes a technique for loading external FLV files without the use of either the FLVPlayback Component or the older Media Components.  Looking back, I believe I should have referenced that detail somehow in the title, because many of the questions have ended up pertaining to FLVPlayback, which has its own complete event.  If you’re using that Component, handling the built-in event is the easiest way to respond to the end of a Flash video, and we’ll cover that in just a moment.  In the spirit of the original article, however, we’ll also take a look at how to determine the completion of a Flash video loaded with ActionScript and a Video object only. 

An answer, short and sweet

If you’re using the FLVPlayback Component, here’s what you can do.  The following code sample assumes:

  • you have an instance of the FLVPlayback Component on the Stage
  • its instance name is videoPlayer (or use what you like, but update the code to suit)
  • its contentPath parameter, in the Parameters tab of the Property inspector, is set to the location of your FLV file

Type the following into your scripts layer:

var listener:Object = new Object();
listener.complete = function(evt:Object):Void {
  trace("Video complete");
  trace(evt.state);
  trace(evt.playheadTime);
}
videoPlayer.addEventListener("complete", listener);

How it works

An arbitrarily named variable, listener, is declared and set to an instance of the Object class.  This object will be used, in a similar fashion described in the “Event Listener” heading under “Event Handlers versus Event Listeners,” to act as liaison for the FLVPlayback.complete event.  This is shown in line 2, where a function is assigned to a complete property of the listener object.  The function receives an arbitrarily named parameter, evt, which is also an Object instance.  This evt object can be used inside the function to report two properties (state and playheadTime) dispatched by FLVPlayback along with its complete event.  In fact, that’s the very next part.  Inside the function, there are three trace() statements.  The first sends a short “Video complete” message to the Output panel.  The next two reference the evt object and the values of the two passed-in properties (state will be “stopped” and playheadTime will indicate the length of the video).  Finally, the complete event is associated with the listener object and subscribed to the FLVPlayback instance itself.

In actual practice, you’ll want to use something other than trace() statements inside that function.  You might, for example, have paused the timeline as the video began; if so, now would be the time to start it again with a play() action.  The choice is yours.  :)

What if I’m using one of the Media Components?

You’re in luck.  The ActionScript works practically the same way.  Drag an instance of MediaDisplay (for example) to the Stage and give it an instance name.  Use the same ActionScript, making sure to match that last line with whatever instance name you choose.  The Media Components don’t pass along properties with their complete event, so omit the evt:Object part between the parentheses.  (That means you should also omit the evt.state and evt.playheadTime references, because they no longer apply.)

What if I’m using no Components at all?

This is where it gets interesting, because the non-Component approach has taken me on a wild goose chase, off and on, since I first wrote the “How to Load” article last April.  The NetStream class, used in the non-Component approach, has no complete event.  The closest we get is an onStatus event that carries with it a code property — similar in principle to the state and playheadTime properties mentioned above — whose message can be “NetStream.Play.Stop” under the right circumstances.  When I first experimented with this property, I wasn’t sure exactly when it might occur.  Sure, it would presumably indicate that a Flash video had ended, but might it not also happen if a video paused because of network traffic?

To make matters worse, I’ve seen notes on other blogs that seem to indicate the “NetStream.Play.Stop” value doesn’t always appear when expected.  In light of that, I’ve been looking for another approach and believe I’ve found it in the NetStream.onMetaData event.  My suggestion still uses the onStatus event, but with assistance from onMetaData.

Another answer, short and sweet

This code sample assumes:

  • no FLVPlayback or Media Component on the Stage; instead, a Video object as described in “How to Load External Video (FLV)
  • an instance name of videoPlayer on this Video object (or use what you like, but update the code to suit)

Enter the following ActionScript into your scripts layer.

var duration:Number = 0;
var nc:NetConnection = new NetConnection();
nc.connect(null);
var ns:NetStream = new NetStream(nc);
videoPlayer.attachVideo(ns);
ns.play("myVideo.flv");

ns.onMetaData = function(evt:Object):Void {
  duration = evt.duration;
};
ns.onStatus = function(evt:Object):Void {
  if (this.time > 0 && this.time >= duration) {
    trace("Video complete")
    delete this.onStatus;
  }
}

How it works

If you’re familiar with non-Component video playing, most of the first several lines should already make sense (if not, read that “How to Load” article).  The only different is an arbitrary new variable, duration, declared and initialized to zero in the first line.  This variable will have its value set by feedback from the NetStream.onMetaData event.

Following the first six lines, a function literal is assigned to the onMetaData event of the ns (NetStream) instance.  This event relies on a smattering of extra information attached to the FLV file itself by the video encoder.  For this example, I used Flash 8 to encode an AVI, but 3rd party encoders exist, and their documentation should tell you if they include a duration property among the data they attach.  The onMetaData event passes along an object, which is collected as evt in the function.  This evt object contains a duration property whose value is passed to the previously declared duration variable.  This value represents the playing length of the video.

Finally, in like fashion, a function literal is assigned to the NetStream.onStatus event of the ns instance.  NetStream does support a time property, which indicates the current position of the video as it plays.  An if statement checks the value of ns’s time property to ensure that it’s a) greater than 0 and b) equal to or greater than our duration variable.  If so, the video must have finished.  In addition, the onStatus function is deleted, otherwise this event may fire more than once.  In your own testing, comment out the delete line to see what I mean.

Some readers have noticed (by using trace()) that the time property never quite reaches duration. If that’s true for you, change the if condition to something like this:

if (this.time > 0 && this.time >= (duration - 0.5))

… where you’re subtracting half a second (or whatever works).

Note:  this approach depends entirely on metadata bring present in your FLV file(s).  Not only metadata, but specifically a duration property.  The Flash video encoder itself supports this property, but your own preferred encoder may not.  To see for sure what metadata (if any) is getting included in your FLVs, change the above onMetaData handler to the following.  You’ll get a list of the whole shebang.

ns.onMetaData = function(evt:Object):Void {
  // duration = evt.duration;
  for (prop:String in evt) {
    trace(prop + ": " + evt[prop]);
  }
};

My test video, encoded in Flash, returned the following output:

canSeekToEnd: true
audiocodecid: 2
audiodelay: 0.038
audiodatarate: 96
videocodecid: 4
framerate: 29.9699859619141
videodatarate: 400
height: 480
width: 720
duration: 71.538

Lots of useful information!

98 Responses to “How to Determine the Completion of a Flash Video (FLV) File (AS2)”

  1. Arturo de la Mora Says:

    Thanks for your input… I don’t really understand much on FLV handling on flash, so I posted with a lot of code… also added some custom buttons… Great blog, I’ll be sneaking around!. I just placed the video on my website. Have a nice day!

    :)

  2. var Says:

    Another thing I’ve run across is a flicker at the end of an flv playing. And it ending on an all black screen instead of the last frame of the movie… I wrote this last night…

    bg_listener.ready = function(eventObject:Object):Void {
    trace(”Total play time for this video is: “+bg_flv.totalTime);
    var pauseTime = (bg_flv.totalTime*1000)-2;
    trace(”pauseTime: “+pauseTime);
    setTimeout(bg_flv, “pause”, pauseTime);
    };
    bg_flv.addEventListener(”ready”, bg_listener);

    that way it makes the movie pause 2 miliseconds before it ends.

    It feels sort of hackey though… any ideas Stiller?

  3. David Stiller Says:

    var,

    The only thing I worry about with such an approach is that you’re relying on a timer mechanism (setTimout()) that may or may not match up with the actual playback speed of the video on a given user’s machine.

    If you’re using the FLVPlayback Component — that’s my guess, since you’re handling a ready event — you may want to use the playheadUpdate event to continuously check the video’s current position against a revised totalTime property, but honestly … if you felt your approach was hacky, I feel the same way about mine, because it uses such a tight loop that might go on for several minutes.

  4. Complistic Says:

    hey,

    With the non-Component methed,
    (using duration from metadata)

    The Time and the end of the clip is(almost always) not be the duration so in my case it works less often then the “NetStream.Play.Stop” methed.

    any ideas?

  5. David Stiller Says:

    Complistic,

    I’m not sure why your metadata would be incorrect (is that what you’re saying?) but if so, and if you know the duration of your videos before hand, you can always use a loop (like setInterval(), for example) to repeatedly check the NetStream.time property against that known value. Does that make sense?

  6. Matt Says:

    Ok i’m having a little bit of trouble with this method. I copy and pasted the code into the file and followed it step by step. I loaded the video very simply. It came straight out of the Adobe FLV encoder. The duration of the video is 10 seconds. The problem is that it never seems to get to the end of the video. When I list variables this is what i get:
    ___________________________________
    Level #0:
    Variable _level0.$version = “WIN 8,0,22,0″
    Variable _level0.duration = 10
    Variable _level0.nc = [object #1, class ‘NetConnection’] {
    contentType:”application/x-fcs”
    }
    Variable _level0.ns = [object #2, class ‘NetStream’] {
    onMetaData:[function ‘onMetaData’],
    onStatus:[function ‘onStatus’],
    time:[getter/setter] 9.95,
    currentFps:[getter/setter] 0,
    bufferTime:[getter/setter] 0.1,
    bufferLength:[getter/setter] 0,
    liveDelay:[getter/setter] 0,
    bytesLoaded:[getter/setter] 266361,
    bytesTotal:[getter/setter] 266361,
    decodedFrames:[getter/setter] 0,
    videocodec:[getter/setter] 4,
    audiocodec:[getter/setter] 0
    }
    Variable _level0.prop = “duration”

    _________________________________

    Additionally, here is my metadata:

    canSeekToEnd: true
    videocodecid: 4
    framerate: 20
    videodatarate: 200
    height: 286
    width: 234
    duration: 10
    _________________________________

    It seems to me like my video is stopping at a duration of 9.95 and therefor never reaching video complete. Is there something very obvious here that I could be doing wrong?

  7. David Stiller Says:

    Matt,

    That’s 1/20th of a second off, which could arguably fly in many cases — we’re talking about one or two clipped frames, in a 30fps FLV — but if you need greater accuracy than that, you may want to test for the time vs. duration comparison under circumstances other than onStatus. I could see using an onEnterFrame event handler instead, for example …

    this.onEnterFrame = function():Void {
      if (ns.time > 0 && ns.time >= duration) {
        trace("Video complete")
        delete this.onEnterFrame;
      }
    }

    … but you’d have to increase your SWF’s framerate to compensate for the FLV’s framerate. I suppose you could also pad the end of your FLV with a quarter second of silent black, or set up a setInterval() loop that polls for the comparison in a very tight loop — but then I’d start worrying about excessive CPU cycles just to correct for a relatively small inaccuracy.

  8. Matt Says:

    I am definitely cool with the 1/20th thing, I don’t mind clipping frames. The problem is that because it is checking against duration, it is never greater than or equal to (only getting to 9.95 instead of 10.00), which means it never triggers a video complete. Is the best solution for this to check against:

    (this.time > 0 && this.time >= duration - .05)

    That is the only way I can figure out to make the event trigger.

  9. David Stiller Says:

    Matt,

    Yeah, that’s a good, clean approach. Much simpler than my last reply. :) So weird, though, that you’re seeing what you’re seeing!

  10. Steve Says:

    Thanks Dave for your great tips and insights into Flash development. One thing just to clarify (you alluded to this earlier), is that none of the code-based techniques are 100% frame-accurate, video-speaking. For example if you had two videos that needed to play together seamlessly (i.e., frame #1 of the second video needs to start playing immediatley follwing the last frame of the first video, so they appear seamless), none of the code-based approaches will really work. That’s partly due to the difficutly in triggering an event exactly at the end of the last frame of video, and partly due to the lack of exact control when the next NetStream will start playing.

    We recently did a project (disc based) which was similar to the old Dragon Quest game where different video clips played in sequence based on user input. In order to keep the transitions absolutley seamless, we had to go old-school and embed the video into the timelines themselves. You lose a lot of FLV’s inherent advantages this way, but if you need absolute frame-accurate control of the clips, AFAIK that is the only way to do it.

  11. David Stiller Says:

    Steve,

    Thanks for the insight! Man, I’d love to work on a Dragon’s Lair type project. That one took many fistfuls of quarters from me. ;)

  12. Grant Gibson Says:

    David, Steve,

    In case it’s helpful, I’ve found a way to get FLV’s to playback seamlessly — for a disc-based app at least.

    When I was using a single FLVPlayback instance to stream the clips, I always got a 1-2 second gap between clips. My app needed to run seamlessly, so I layered two FLVPlayback instances on top of each other - sort of like an A & B roll you get in video editing apps.

    I then wrote some actionscript to flip between the two players whenever the current player gets to the end. At the same time, I’m pre-loading the next clip into the non-active player in the background.

    The script goes something like this…

    function doNextScene() {
    currentScene++
    if (currentPlayer == “a”) {
    currentPlayer = “b”;
    } else {
    currentPlayer = “a”;
    }
    if(currentPlayer == “a”) {
    videoPlayerA._alpha = 100;
    videoPlayerB._alpha = 0;
    videoPlayerA.play();
    videoPlayerB.contentPath = “clips/” + selectedClips[currentScene+1];
    } else {
    videoPlayerB._alpha = 100;
    videoPlayerA._alpha = 0;
    videoPlayerB.play();
    videoPlayerA.contentPath = “clips/” + selectedClips[currentScene+1];
    }
    }

    Both video players need their autoPlay param set to false for this to work.

    You could probably get this technique to work for web-based apps too by using the bufferTime parameter to cache some of the next clip in the background (assuming your bandwidth profile would allow concurrent loading).

    Hope this is useful to someone. :)

  13. Alfred Says:

    Hello David,

    Very useful info on this blog! Thanks a ton!

    I have reached a roadblock that I hope someone could shed some light on. I would like to load the flv files via ASP. I am looking to do something like this:

    videoload.asp output:
    &video1=http://www.site.com/testvideo1.flv&video2=http://www.site.com/testvideo02.flv

    Actionscript:
    loadVariables(”videoload.asp”, “”);
    timeOut = getTimer();
    var listenerObject:Object = new Object();
    listenerObject.stopped = function(eventObject:Object):Void {
    RL_FLVPlybk.contentPath = video2;
    RL_FLVPlybk.skin = “SteelExternalAll.swf”;
    };
    RL_FLVPlybk.addEventListener(”stopped”,listenerObject);
    RL_FLVPlybk.contentPath = video1;

    I have several specific questions:
    1) Do I need an ‘&’ ampersand at the beginning of the asp output? I’ve seen it done with and without an ampersand on several sites discussing passing multiple variables between flash and server side script.
    2) I keep getting “null url sent to VideoPlayer.load” when I run the page, even when trying to access a static text file in place of the asp file. What am I doing wrong?

    Any info would be appreciated. Thank you.

  14. Clint Says:

    Has anyone had experience with looping flv files. I’ve been using the “complete” listener to loop a video, but have found that there is a slight skip whenever the video restarts. I’m wondering if it’s to do with the complete event returning slightly late, or if it’s the flvplayback component struggling at the beginning of the video.

    See: http://www.nab.com.au/socceroos for the project in action to see what I am talking about. (you will note the skips in the video in the background players and in between moves of the main character during gameplay)

  15. JamieG Says:

    Having an issue with playing one video after the other in a timeline.

    Right now im entering
    ————————————————–
    stop();

    var listener:Object = new Object();
    listener.complete = function(evt:Object):Void {

    gotoAndPlay(”next”);
    }
    videoPlayer.addEventListener(”complete”, listener);
    ————————————————————-

    Then it goes to the “next” frame which is good. The problem I’m having is that it wont keep doing this, if i add the same code with a new goto it doesnt seem to wan to go there.

    Im somewhat of a code dunce so any ideas on this would be greatfully appreciated.

    cheers

  16. Igo Says:

    Hi!!…Thanks for the tip!….I am having another problem with Media Components…i am using it to load an mp3..and adding some CuePoints, i need to play the movie, just when it has been loaded…because if i play it before…the cuePoints get crazy…Thanks!!

  17. David Stiller Says:

    To Grant …

    Hey, thanks for the input!

    To Alfred …

    Do I need an ‘&’ ampersand at the beginning of the asp output?

    In my personal experience, it hasn’t been necessary. Normal query strings start with a question mark (?), then enumerate urlencoded name/value pairs separated by ampersands (&). That’s how it is for ASP pages that talk to other ASP pages, PHP pages that talk to other PHP pages, and so on — including Flash. Though I haven’t tested the following yet myself, I read on one of the Adobe forums that, in fact, AS3 doesn’t allow an ampersand prefix.

    I keep getting “null url sent to VideoPlayer.load” when I run the page … What am I doing wrong?

    It looks like you’re requesting for data, but not waiting for it. You’re assigning RL_FLVPlybk.contentPath = video1; before that video1 variable comes back. Instead of the loadVariables() function, I recommend the LoadVars class, which dispatches an event when it completes. Your event handler, in that case, would set the contentPath

    To Clint …

    I haven’t personally tried what you’re trying, but I would imagine the skipping might occur for any number of reasons, including the possible Component “struggle” you mention and discrepancies between SWF framerate and FLV framerate(s). Depending on your needs, Grant’s response from May 19 may give you something to experiment with.

    If this were my project, I would probably do without the FLVPlayback Component and use two NetStream instances (and two Video objects) — one preloading the second clip while the first is playing. I would start the second clip a half second (give or take) before the first one ends, then send the first one off to fetch the third clip, and so on, tag-teaming.

    None of this would be especially easy, I’m sure. Clearly, a number of people have had trouble with this sort of looping … and my curiosity is piqued. I’ve added this topic to my (now monstrous) list of blog “things to write about,” and I can’t say for sure when this topic will surface … but I trust it will at some point. :)

    To JamieG …

    Is the same FLVPlayback instance (here with the instance name videoPlayer) in the same frame that the gotoAndPlay() sends the playhead to? If not — if that’s a new (different) FLVPlayback instance — you’ll have to write a new event handler for that one, too.

    To Igo …

    I’m afraid I don’t understand your question — sorry!

  18. Paul Says:

    Hello David,

    I ran across something interesting that other readers may (or may not) find useful. I was using the method you outline above to listen for the end of an flv running through the FLV Playback component, and it was just not working. If I changed to listening for the ’stopped’ event, and then pressed the stop button during playback, the event fired just fine, but never after the clip ended. After some troubleshooting, I decided that the problem was with the flv itself; what I eventually discovered was that clips I transcoded using the Adobe Flash video encoder all seemed to have this issue, while flvs from other transcoders did not. So I’m curious if anyone else has run across this issue, or if it’s just me?

  19. Clint Says:

    Hi David, thanks for the response. I had actually tried something in the same vain as Grants suggestion, but I just noticed that he states AutoPlay must be disabled. I don’t think I checked this out, so I am going to go back and rewrite teh video sequencer to give it a try at least.

  20. David Stiller Says:

    To Paul …

    Thanks for that insight! I don’t use the FLVPlayback Component very often, so I can’t say off the top of my head that I’ve run into the same issue, but it wouldn’t surprise me. There are definitely differences between how FLVPlayback and NetStream dispatch their various events (some overlap and some don’t). I’m curious to see what others may have encountered. :)

    To Clint …

    Cool. Write back if you come up with something nifty!

  21. Andy Smith Says:

    Thanks for the blog David - very helpful.

    I’m having a similar problem that Matt had (back in May) where the playback is stopping a few milliseconds before the end and therefore is not triggering the complete event.

    Could you advise me on how to implement the fix (this.time > 0 && this.time >= duration - .05)? I’m not really sure where to put this code in order to make it work. Thanks for your help! Andy

  22. David Stiller Says:

    Andy,

    Sure thing. :) In the original article, under the “Another answer, short and sweet” section, here’s a block of code that handles an onStatus event for video displayed via the NetStream class. That onStatus event handler is where the replacement line needs to go, and this only applies (I believe) if you’re going the Video object/NetStream route. Relace that event handler in the article with the following:

    ns.onStatus = function(evt:Object):Void {
      if (this.time > 0 && this.time >= duration - 0.5) {
        delete this.onStatus;
      }
    }

    Note that I dropped the trace() line, which is only for testing anyway, and you may want to adjust 0.5 (half a second) with a slightly higher or lower value, until you find what works for your situation.

    Now, on its own, the above revision doesn’t actually do anything. That’s why the earlier trace() was present, as a stand-in. Replace trace() with whatever ActionScript meets your needs, such as starting up the main timeline again (if it had been stopped), or something along those lines.

  23. Mike Says:

    Great stuff! I like how you also have code/tips for non-FLVPlayback apps. How, though, could I get playheadTime? (I’m trying to sync slides with video).

    Thanks,
    Mike

  24. Mike Says:

    oops…I forgot to add the I’m using the mediaPlayback component.

    Thanks again,
    Mike

  25. David Stiller Says:

    Mike,

    If you’re using any of the Media-related Components (MediaPlayback, MediaDisplay, or MediaController), you’ll find your answers in the Media class of the Components Language Reference. It sounds like you’ve already consulted that, because Media.playheadTime is indeed inherited by MediaPlayback and MediaDisplay, so you should be good. :)

    If you’re hoping to sync up other assets with the video, though, you’ll probably want to use cue points instead — otherwise, you’ll have to loop continuously (with MovieClip.onEnterFrame, say, or setInterval()) to repeatedly check the Media.playheadTime property associated with your particular instance. Check out the sample code snippet for the Media.cuePoint entry for a good start.

  26. Jayson K. Hanes Says:

    Here’s a code snippet I created that fixed my problem with the “progressive download” that keeps downloading when a video is stopped:

    1st, I put an image on frame 1 relative to the movie about to be played (mine are dynamically loaded), with a play button for the user to click, which, when clicked, plays the root to frame 2

    2nd, I put the flvplayback component ON frame 2 which is autoplay=false, and this code:

    var listenerPlay:Object = new Object();
    listenerPlay.playing = function(evt:Object):Void {
    var listenerStop:Object = new Object();
    listenerStop.stopped = function(evt:Object):Void {
    _root.player.removeEventListener(”stopped”);
    _root.gotoAndStop(1);
    }
    _root.player.addEventListener(”stopped”, listenerStop);
    _root.player.removeEventListener(”playing”);
    }
    player.addEventListener(”playing”, listenerPlay);

    if there is a more elegant method of achieving this, please share.. but this works for my needs with dozens of movies on the stage, allowing a user to click play/stop and choose another, without bogging down the users’ pc etc if they click one, then another, and another.. etc.

  27. Jayson K. Hanes Says:

    correction: I stated in the last paragraph “..with dozens of movies on the stage..”.. this isn’t accurate and could lead to confusion. It should have been “.. with dozens of movies formatted on the html page (ie. multiple instances of swf’s each with the above).

  28. Damiano Says:

    David,

    I am working on a SWF which calls in turn some other SWF animations and FLV movies based on an xml playlist. I am using the way you explain here to check the playback status and turn to the next SWF or FLV to play. During the first playlist loop everything semms to be ok, second time when the FLV plays, the onStatus does not trigger the end event. I tried putting -0.5 or -1 seconds but nothing changes. Anything to suggest? Thanks!

  29. David Stiller Says:

    To Jayson …

    That’s a pretty neat approach! You can certainly collapse the code a teensy bit by using a single generic Object instance for your listener. (As a matter of fact, as long as event names don’t overlap, you can use a single listener object for as many events as you need, even if those events are dispatched by more than one object.)

    stop();
    var listener:Object = new Object();
    listener.playing = function(evt:Object):Void  {
      player.removeEventListener("playing", listener);
      player.addEventListener("stopped", listener);
    };
    listener.stopped = function(evt:Object):Void  {
      player.removeEventListener("stopped");
      gotoAndStop(_currentframe - 1);
    };
    player.addEventListener("playing", listener);

    Note that you don’t need the _root reference because of how these event handler functions determine scope. They look inside themselves first — for example, looking for an object with the instance name player — and when they don’t find it, they look “up the chain,” so to speak, until the object is discovered.

    Note, too, that instead of sending the main timeline’s playhead to frame 1, I used the expression _currentframe - 1. The functions will look for the MovieClip_currentframe property in themselves, won’t find it, then will look up the chain to the nearest MovieClip instance. By using an expression rather than a hard coded number, you can pop this snippet into any frame you like, if need be (as long as it has a previous frame to step back to).

    If you don’t care about the extraneous event handlers — and for a small project, it shouldn’t matter — you can do away with the removeEventHandler() references. In fact, all you really need (if I understand your goal) is to handle the stopped event:

    var listener:Object = new Object();
    listener.stopped = function(evt:Object):Void {
    gotoAndStop(_currentframe - 1);
    };
    player.addEventListener(”stopped”, listener);

    To Damiano …

    Do all your FLV files have a duration property in their metadata? (Note: you also mentioned you’re loading SWFs — but SWF files don’t have a duration property and aren’t loaded using NetStream. I’m guessing your issue only pertains to the FLVs.)

  30. George Says:

    Hey Great stuff!! Thanks for that, 95% of the time it works great although when my video rebuffers due to the network or a slow connection, it does detect when the video has finished (i am doing this through actionscript so i am using your last method.

    Please help asap!!

    Thanks all :D

  31. Pedro Rubini Says:

    In addition, for those of you who, like me, have been looking for a way to convert the duration time into 00:00 (minutes:seconds), here’s a function that does it:

    function calculateTime(dur) {
      var Ttime:Number = Math.floor(Number(dur));
      var minutes:Number = Math.floor(Ttime/60);
      var seconds = Math.floor(Ttime%60);
      if (seconds<10) {
        seconds = ("0"+seconds);
      }
      myTime = minutes+":"+seconds;
      if (myTime.charAt(0) == "N") {
        return "00:00";
      } else {
        return myTime;
      }
    }
  32. David Stiller Says:

    To George …

    The non-component example makes use of the NetStream.onStatus event, which may not fire the way we’re expecting (read, as often) during network latency. You can certainly try another event — perhaps something more consistently repetitive, such as MovieClip.onEnterFrame. The downside is that too many concurrent onEnterFrame handlers, or too much going on in a single such handler, can potentially slow down your SWF, but it’s worth a shot. Assuming this code is written in a keyframe (in which case this refers to a MovieClip instance; namely, the main timeline) …

    this.onEnterFrame = function():Void {
      if (ns.time > 0 && ns.time >= duration) {
        trace("Video complete")
        delete this.onEnterFrame;
      }
    }

    To Pedro …

    Thanks! For readers interested in more about the modulo operator used in Pedro’s code, see “Lesser Known Operators: Modulo (%)” and “How to Convert Milliseconds to Minutes and Seconds.”

  33. Bonifar Says:

    ..any idea how i could scale an flv video? the default scaling is screwing up the quality :(

  34. David Stiller Says:

    Bonifar,

    Just like with images, video scaling isn’t an especially recommended practice, especially when the scaling goes up (bigger). As scaling increases an image’s size, its pixels begin to show — that’s just how it works, for better or worse. You should definitely experiment with all your various encoding options (bitrate, framerate, compression, etc.).

  35. chris Says:

    David, Thanks for sharing your Flash know-how. It really helped.

  36. David Stiller Says:

    chris,

    Sure thing!

  37. Louis Says:

    Wow great info on your top section “How to Determine the Completion of a Flash Video (FLV) File”. I had that problem for awhile now. All i did was paste your code in and Bam, i detected the end of my embedded FLV - Good job!

    Louis

  38. David Stiller Says:

    Louis,

    Glad to hear it! :)

  39. David Ives Says:

    Hi,

    I am a complete newbie to Flash and am having a real issue with the following;

    I have an fla with 3 frames, frame 1 has some information and a link to frame 2 where an external flv is to be played. The issue I have got is that I want after the flv has finished the fla to move to frame 3 and display some more information but I cannot seem to find a solution to this.

    Please please please could someone explain to me how this is achieved as simply as possible.

    Your help would be so much appreciated.

    Thank you

  40. David Stiller Says:

    David,

    Your answer depends entirely on what mechanism you’re using to display the video. If you’re using the FLVPlayback component, then you’d use the FLVPlayback approach shown above. In the event handler, you’d set the playhead moving again by way of the MovieClip.play() method or play() function.

    var listener:Object = new Object();
    listener.complete = function(evt:Object):Void {
      play();
    }
    videoPlayer.addEventListener("complete", listener);

    That code would go in frame 2, right alongside your component (which would have the instance name videoPlayer.

  41. Ann Says:

    Hello,
    It was really a good experience to go through your article.I have a doubt,can we do this program in Adobe Captivate(software for flash).I need to build up an e-learning system.I would like to know how much amount video is being viewed by a particular client,and Can I include questions in between the video clip.Please help me to resolve this issue.
    Regards,
    Ann

  42. David Ives Says:

    Thank you for this, I am using the FLVPlayback component. I simply imported the externally hosted video to the frame. I tried putting the code you suggested but it just keeps cycling around the 3 frames.

    And I get the error 1046: Type was not found or was not a compile-time constant: Void.

    I am at a complete loss about this :(

  43. David Stiller Says:

    To Ann …

    Your endeavor is certainly possible, and it’s even possible with Flash, but you’ll need some sort of server-side middleware (PHP, ASP.NET, Ruby on Rails, Cold Fusion, etc.) in order to record user interactions as you’ve described. Flash would comprise the front end and would communicate with the back end via GET or POST, web services, or the like. Whether this is something Captivate can do — that’s beyond my knowledge, I’m afraid.

    To David …

    When you see numbered error messages like that, it’s almost certain you’re authoring a document configured for ActionScript 3.0. This particular error message (type not found, Void) nudges that “almost certain” into “definitely sure.” In ActionScript 3.0, the Void type is lowercased (void), but AS3 is considerably different in other respects as well, to the point where the code in this article simply doesn’t apply to the AS3 version of FLVPlayback.

    You can either: a) delete the FLVPlayback instance, go to File > Publish Settings > Flash tab and change the ActionScript version to 2.0, then replace the FLVPlayback instance, or b) leave your FLA as is and use ActionScript 3.0 syntax instead.

    I’ve been meaning to “upgrade” the most popular articles on this site for ActionScript 3.0, and this is another gentle reminder. I’ve added most of my video articles (like this one) to the revision list. :)

  44. neil Says:

    Great post, youve got me out of a sticky situation!!

    dogs danglies!!

    Cheers

  45. David Stiller Says:

    neil,

    Bob’s your uncle, man. :)

  46. Neal Says:

    Hi David its Neal, hope you are keeping well.

    I’m sure you know my flash player quite well but I’ve come across a new problem.

    What I’m trying to achieve is that when the currently playing video gets to the end the playhead moves back to the beginning and my toggle play/pause button changes state.

    Code I’ve tried (with duration established as per your code) is:

    ns.onStatus = function(evt:Object):Void {
    if (this.time > 2 && this.time >= duration) {
    ns.seek(0);
    ns.pause(true);
    btnToggle.toggled = true;
    btnToggle.gotoAndStop(3);
    }
    }

    I’ve used the code within the if statement on my stop button which works perfectly yet in the above it dosen’t work and causes other videos called from my buttons to not load and play?

    Your help David as ever would be welcome.

    Thanks, Neal

  47. Howard Says:

    David,

    Thanks in advance for your help. I have used your code to deploy flash video on what will be our new home page. I am designing the new site fully in flash.

    I ran into a snag, where the video (at least the audio) keeps playing when the end user navigates to a different scene. You can hear the audio still when navigating other areas of the site. How can I put the kibosh on this?

    Here is the url: http://www.180group.com/180FlashBeta.html, check it out. Notice the audio keeps playing if you hit Services or any other pages…

    The site is not public yet, but I run it from this address to quality control it online.

    Your help is appreciated!

    Howard

  48. David Stiller Says:

    To Neal …

    I’ve used the code within the if statement on my stop button which works perfectly yet in the above it dosen’t work and causes other videos called from my buttons to not load and play?

    Without seeing the code from your other buttons, I’m not sure I can figure out what’s going wrong here. Part of the problem may be one of scope. Your onStatus event handler function is associated with the ns instance itself. References to ns inside that function should be this (as done in the if statement) — so, this.seek(0);, etc. — and then, btnToggle may or may not be scoped to that function (meaning, may not be visible from that function’s point of view). To test for that, add trace(btnToggle); inside that function and keep an eye on the Output panel to see if you get a proper reference to btnToggle or if you get undefined.

    To Howard …

    I checked out your beta page and didn’t see (rather, didn’t hear!) the problem. Did you already figure out a solution, maybe? If not, let me know. Off the top of my head, though, I would think that in addition to sending the user to a new Scene, those nav buttons might also have to be programmed to halt the video stream.

  49. Howard Says:

    Yes David, I did figure out the problem. Thank you for your response. I ended up having to do exactly what you said, and halt the video stream when the user navigated to a new page.

    We went live with the page last Friday and have recieved some really positive responses. Thank you so much for your blog on externally streaming fla’s, as our site wouldn’t have been the same without it.

    The 180 Groups New Flash Website

  50. David Stiller Says:

    Howard,

    Congrats! :)

  51. Neal Says:

    Hi David, hope you are well.

    Thanks for your response, I’ve made your suggest changes. I’m still having problems with trying to reset the video to the beginning when the current video gets to the end. I’ve tried using the following:

    ns.onStatus = function(evt:Object):Void {
    if (evt.code == “NetStream.Buffer.Full”) {
    bufferClip._visible = false;
    }
    if (evt.code == “NetStream.Buffer.Empty”) {
    bufferClip._visible = true;
    }
    if (this.time > 0.5 && this.time >= duration) {
    bufferClip._visible = false;
    this.seek(0);
    this.pause(true);
    }
    }

    All I want is to the video to reset back to the start when it gets to the end, but still now luck. Any further ideas,

    Thanks, Neal

  52. James Says:

    Hi David-
    I’m not very familiar with working with video and the various actionscript functions that go along with it. I managed to implement the example you provided that allows for actions to be run when the video is complete. How would I then run a set of actions once it has moved away from the last frame of the video? This would either be from someone pressing play again, scrubbing the playback head or rewinding.

    Thanks, James

  53. David Stiller Says:

    To Neal …

    It sounds as if you’re just not getting the results you’re expecting, so a number of trace() statements may be in order. Since you can’t really see what’s going on with code like this, it often helps to instruct ActionScript to tell you what it’s doing. Immediately inside your onStatus event hander, put a generic trace("onStatus has been triggered"); just so you know the event is getting handled at all. I would also add trace(evt.code); — not inside any of the if statements, but right inside the function. That way you’ll know which of those ifs is getting hit (if either). Finally, add trace(this.time); and trace(duration);, to make sure those values are present.

    To James …

    The approach you take is going to depend on the mechanism you’re using to play your videos. If you’re using FLVPlayback, for example, you might look into the FLVPlayback.stateChange event, which you can handle the same way FLVPlayback.complete is shown above. If you’re using NetStream, the same NetStream.onStatus event should do it, but you’ll want to listen for the message NetStream.Play.Start
    (for example) in the way Neal is listening for NetStream.Buffer.Full in the question just before yours. See how he’s using if statements before the final if statement that checks time against duration? You can do the same, and put as many additional instructions as you like. Does that make sense?

  54. Neal Says:

    Hi David,

    Thanks for this, having looked through, and rebuilt some of my player components this now is working great. I think my problem was not deleting the onStatus event when the video had finished. Thanks very much for your help.

  55. David Stiller Says:

    Neal,

    Sure thing! Glad you nailed it. :)

  56. Brett Sherman Says:

    I’m trying your script, and I’m sure I’m doing something really stupid, but when I try to publish the flash file it says:

    **Error** Scene=Scene 1, layer=Actions, frame=20:Line 75: There is no property with the name ‘onMetaData’.
    netStream.onMetaData = function(evt:Object):Void {

    Now I know you use ns instead of netStream. But I’m adding this to an existing project where I use netStream in many different places, so I kept it. Here’s the code I use for that:
    var netStream:NetStream = new NetStream(netConn);

  57. Russ Says:

    It is was so much easier in Director i just don’t get why Flash is so complicated it calls it self a multimedia platform but you cant even control a video file and one that they created them self FLV why not embed a meta tag to tell flash when the video is completed like in quicktime and director.

    Just dont get macromedia for developing such a stupid way of showing video

  58. Russ Says:

    Example in director

    if movie.duration => movie.length then goto frame 5

    thats it

    so simple

  59. David Stiller Says:

    Russ,

    There are plenty of differences between Flash and Director — not the least of which being that Flash output is mainly intended for Web, while Director is intended for disc delivery — and of course, Director is much older than Flash, which means it’s had longer to work out its kinks.

    why not embed a meta tag to tell flash when the video is completed

    That’s entirely possible with Flash. In fact, it’s metadata that allows for the duration variable to take hold in some of the above suggestions. But I hear what you’re saying. Certain things truly are easier in Director, and some things truly are easier in Flash. The important thing, I think, is whether or not they’re possible. ;)

  60. David Stiller Says:

    Brett,

    Woops! Sorry, I missed your comment before Russ’s.

    Now I know you use ns instead of netStream. But I’m adding this to an existing project where I use netStream in many different places, so I kept it.

    Yeah, that’s odd. The name of your NetStream instance really shouldn’t matter (as long as you’re using a valid variable name, which you are).

    In a case like this, where the error simply seems baffling, I recommend you try to re-create the issue in a new, otherwise empty FLA. Bring it down to a bare bones scenario and get the most basic setup to to its thing. Often (for me, anyway), this sort of isolation brings useful insights to light.

  61. Neal Says:

    Hi David,

    Just to follow up on this, I was having problems with is on pc while on a mac it was all fine. Now that I have replaced:

    if (this.time > 0.5 && this.time >= (duration - 0.5)) {

    with:

    if (evt.code == “NetStream.Play.Stop”) {

    Seems to work perfectly now on both mac and pc. Hooray!!

    Thanks again, Neal

  62. David Stiller Says:

    Neal,

    Thanks for sharing this. I’ve been hesitant to suggest the NetStream event code approach because of comments I’ve seen on other blogs — and unfortunately I didn’t make notes on those comments, so I don’t even remember which blogs had them. Hearing enough success stories like yours will encourage me to update this article.

  63. Michelle Says:

    David,

    I have searched for a couple days trying to find out how you load and loop multiple external flvs with a single video component. I know this can be done, I just don’t know how to do it. If anyone could shed some light–that would be nice.

  64. Chris Says:

    Hi,
    I have a problem when using the FLVPlayback component and the code below:
    [code]import mx.video.*;
    videoPlayer.contentPath = videoUrl;
    var listenerObject:Object = new Object();
    listenerObject.complete = function(eventObject:Object):Void {
    if (videoPlayer.contentPath == videoUrl) {
    trace(”done”);
    }
    };
    videoPlayer.addEventListener(”complete”,listenerObject);[/code]

    In that if someone pauses, rewinds or moves the timeline / interferes in anyway the action doesnt fire when the video completes… Is there anyway around this? Because at the moment im stuck using a player with no control.

    Thanks in advance,
    Chris

  65. Chris Says:

    Scratch that, am now using the netstream approach, thanks

  66. David Stiller Says:

    To Michelle …

    Take a look at “How to Play Flash Video (FLV) Files Sequentially” and let me know if that does it for you. :)

    To Chris …

    Off the top of my head, I can’t imagine why user interaction would interfere with the FLVPlayback.complete event, but I’m certainly glad you found a solution that works for you!

  67. Kate Says:

    Hello,

    Your tutorials have helped me so much- thanks for them.

    I’ve built an flv player that uses xml and a combo box to choose which flv the user wishes to view.

    Everything works fine, except that the knob does not return to the beginning of the track once the flv has reached the end. I’ve read and tried everything I can see on your blogs, but being new at this, I just can’t figure out how to fix this. Please show me what to do to make my code work. Thanks in advance:

    var duration:Number = 0;
    var ratio:Number = 0;
    var idTracking:Number = 0;
    var idLoading:Number = 0;

    // Net Connection
    var nc:NetConnection = new NetConnection();
    nc.connect(null);
    var ns:NetStream = new NetStream(nc);
    myVideo.attachVideo(ns);
    ns.setBufferTime (3);
    //ns.play(”externalVideo.flv”); replaced by line 146
    //can use to play single file then comment out ns.play below

    ns.onMetaData = function(evt:Object):Void {
    duration = evt.duration;
    ratio = track._width / duration;
    idTracking = setInterval(updateKnob, 50);
    idLoading = setInterval(updateLoader, 50);
    };

    ns.onStatus = function(evt:Object):Void {
    if (this.time > 0 && this.time >= (duration - 0.5)) {
    trace(”Video complete”);
    clearInterval(idTracking);
    delete this.onStatus;
    }
    };

    // controls the draggable slider
    function updateKnob():Void {
    knob._x = track._x + ns.time * ratio;
    newBarMC._width = knob._x - track._x;
    }

    knob.onPress = function():Void {
    clearInterval(idTracking);
    ns.pause(true);
    this.onMouseMove = function():Void {
    if (track._xmouse > 0 && track._xmouse = 98) {
    loader._xscale = 100;
    clearInterval(idLoading);
    }
    }

    track.onRelease = function():Void {
    if (this._xmouse > 0 && this._xmouse

  68. lookitsdave Says:

    Hi David,

    Further to Damiano’s post on September 12th, 2007…

    I have used your script from How to Build an FLV Progress Bar (Part 2), and have left the trace(”Video complete”) line in. I am using this method to determine the end of a single flv stream upon which a movie appears on screen which, on clicking, starts the netstream again through seek (0) and ns.play.

    This all works fine on the first loop - upon completion the “Video complete” output is generated, the movie appears and on clicking, the flv starts again. On subsequent loops however, the end event is not triggered, hence no popup if the flv is watched 2 or more times.

    Any suggestions?

  69. David Stiller Says:

    lookitsdave,

    Probably time to look under the hood. :)

    In my suggested code, everything hinges on that onStatus event handler. I would start putting trace() statements in there to a) make sure it’s firing at all after the first play and b) find out what the values for this.time and duration are.

  70. Robert Brown Says:

    Hi again, Dave,

    Short and Sweet:

    Thanks for the additional info in your last message. I understood enough to know that I am NOT using the FLV player. Therefore, after reading more on your notes on “How to Determine the Completion of a Flash Movie,” I realize I should be using this script:

    var duration:Number = 0;
    var nc:NetConnection = new NetConnection();
    nc.connect(null);
    var ns:NetStream = new NetStream(nc);
    videoPlayer.attachVideo(ns);
    ns.play(”myVideo.flv”);

    ns.onMetaData = function(evt:Object):Void {
    duration = evt.duration;
    };
    ns.onStatus = function(evt:Object):Void {
    if (this.time > 0 && this.time >= duration) {
    trace(”Video complete”)
    delete this.onStatus;
    }
    }

    My question now is: Where do I interject the “gotoAndPlay (Scene, frame)” script to get the results I want?

    Also…I’m really not sure why my original script worked for the one movie I mentioned since I’m not using the FLV player. But that’s probably moot at this point.

    Thanks in advance,

    Robert

  71. David Stiller Says:

    To Kate …

    Thanks for sending me your code via email! :) Now I can see what’s going on. Here’s my take on it. If you want the knob to return to its starting point at the end of the video — at least, in this scenario — you’ll have to send it there yourself. The end of the video is “caught” in that onStatus event handler, so you could update it like this:

    ns.onStatus = function(evt:Object):Void {
      if (this.time > 0 && this.time >= duration) {
        trace("Video complete");
        clearInterval(idTracking);
        knob._x = track._x;
        delete this.onStatus;
      }
    }

    … which places knob at its original position against track.

    Now, here’s a bit more, and it’s important. Notice the delete line in this same handler? Once that delete executes, the onStatus function is removed. It’s simply gone. That means that the next video to be played through the same NetStream instance (ns), no longer has the benefit of it. You’ll want to update your handler like this:

    ns.onStatus = statusHandler;
    
    function statusHandler(evt:Object):Void {
      if (this.time > 0 && this.time >= (duration - 0.5)) {
        clearInterval(idTracking);
        knob._x = track._x;
        delete this.onStatus;
      }
    }

    The only difference, really, is that the function is now a named function, which goes by the arbitrary name statusHandler(). Why is this important? By giving the function a name, you can refer to it more easily down the line. You’ll want your ComboBox to be able to re-assign this event handler when it tells NetStream what new FLV to play:

    movList.change = function():Void {
      ns.play(cbMovie.getItemAt (cbMovie.selectedIndex).data);
      ns.onStatus = statusHandler;
      pauseButton._visible = true;
      playButton._visible = true;
    };

    See the re-assignment after that ns.play() line?

    Finally, when playing more than one video, you’ll want to update the onStatus handler altogether by adding one final element to the condition inside that if statement. See “How to Play Flash Video (FLV) Files Sequentially” for details on a “ready” Boolean variable. :)

    To Robert …

    Agreed. I’m not sure why your earlier script (in comments of another post) worked either, but stranger things have happened. ;) Sometimes it really is okay to just roll with what’s working now.

    I should point out that my suggestion of comparing time against duration isn’t the only way to go. If I remember right, your other post used the info property of the NetStream.onStatus event — that’s a different approach, and many people have success with it. In the above snippet, the trace() function is your give-away: that’s where the end of the video is found, so you could replace this line …

    trace("Video complete");

    … with your gotoAndPlay() statement. If you wanted to keep the trace() statement for testing purposes (it only shows in the Output panel in Flash), you could put gotoAndPlay() immediately below that.

  72. Brandon Says:

    David ::

    Fantastic blog you have, this is the first time I have ever seen it and will definitely be subscribing to your RSS.

    My question is, is there any reason the “complete” listener would trigger with one set of videos, but fail to trigger with another set of videos? I have a video player that loads up a playlist from a database & plays the videos sequentially. All of the functionality to play them one after another is implemented, and when I tested it with a set of FLV’s that I typically use for testing it worked perfectly. Yet when I put in the actual set of FLV’s that will be used when the player goes live the “complete” listener fails to trigger.

    Any insight would be appreciated. And again, great job providing people with a fantastic resource!

  73. David Stiller Says:

    Brandon,

    What you’re seeing can be the result of improperly encoded FLVs, or simply FLVs that were encoded without metadata. If you’re on a Windows machine, you can download FLV MetaData Injector, by Manitu Group, and see if that will help. It’s a freeware app that adds metadata to FLV files.

  74. mrwizzer Says:

    How about if, instead of having the url hardcoded in the contentPath of the paramaters property inspector, you’re using actionscript to determine the URL? (i.e. via nc.connect(”rtmp://flash.myserver.net/myvideo.flv”); )

    Your code isn’t working for me, and I can only assume it’s because I don’t have the content path hard coded in the property inspector.

    Great blog, by the way!

  75. David Stiller Says:

    mrwizzer,

    Hrm … hard coding or not shouldn’t make a difference, actually. If you’re using nc.connect(), that tells me you’re using a Video object, rather than the FLVPlayback component. If you’re not using a component, you’ll have to employ something like the code suggested under the “Another answer, short and sweet” heading. Does that work for you?

  76. Chris Says:

    Hi David!

    First of all, wonderful blog. As a teacher, it is wonderful to find that someone has managed to combine so many skills together with such a pleasant and patient delivery style!

    I am trying to teach myself Actionscript, and have put together a couple of decent little apps to help teach number sense to pre-kindergarten students. So far, I am finding the learning curve to be a bit steep! I am reading Essential Actionscript, but must have been through the first 50 pages about 10 times now. Sometimes I think that trying to figure out what the book is teaching me, while at the same time creating with the Adobe authoring tool can be confusing.

    For example, in reading about packages, it seems rather clear until I go to the authoring tool and don’t seem to have a need for packages… so it is difficult for me to “see” or “explore with” what the book is trying to teach me.

    Well, I’ve gone on long enough now… I actually have a QUESTION here!

    1. I have an instance of FLVPlayback on the stage. However, I don’t want this to be played until the student has earned it as a reward. So I issued

    videoPlayer.stop();
    videoPlayer.visible=false;

    What I can’t figure out is why, in function which is called later, the

    videoPlayer.play();
    videoPlayer.visible=true;

    shows the video, but does not play it. It just sits at its first frame.

    2. The article to which I am replying is for AS2. Do you have code to determine that FLVPlayback has completed for AS3?

    Thank you for putting up with my rambling, and my lack of much AS knowledge.

  77. Chris Says:

    I seem to have solved one video problem, and perhaps introduced another.

    videoPlayer.load(”videoClip”);

    and

    videoPlayer.play(”videoClip”);

    are working fine. But the output screen shows this error: Error #2044: Unhandled IOErrorEvent:. text=Error #2032: Stream Error.
    at MethodInfo-610()

    How do I add an IOError listener to the FLVPlayback? Assuming that is what I need to do…

  78. Chris Says:

    Back again! Solved the Stream Error… seems it was related to a sound file. So the video is working perfectly. Hooray!

  79. tunghoy Says:

    Dave, once again, your advice was spot on! Nobody else (including Adobe Live Docs) gave me anything that worked.

  80. David Stiller Says:

    To Chris …

    Ah, wow, glad to hear that! I’ve been so behind in blog replies lately … I was just getting ready to start thinking about your questions, but then I saw that you found the solution yourself! Kudos!

    To tunghoy …

    Thanks!

  81. Joe B. Says:

    I just want to thank you David for taking the time to make this blog and making it what it is…It is so great and has helped me so much.

    So I wanted to give you a very appreciated “Thank You!”

    Joe

  82. David Stiller Says:

    Joe,

    Glad to hear that. Thanks!

  83. jerrspud Says:

    this saved me. I’ve been trying to figure this out for a week. Thank you so much!!!! ;-)

  84. David Stiller Says:

    jerrspud,

    Rockin’!

  85. Dean Phillips Says:

    I’ve been having a slight problem with flv video.

    When I load in video externally with actionscript (there is an Embedded Video object on stage named theVideo and the actionscript is calling in video dynamically) - the video loads and plays fine to the end. But when I hit Stop on the controls half way through the video and then hit Play again, the video starts back at the beginning like it should but immediately before it restarts, the last frame that it played before I clicked stop flickers on screen briefly. It is more prominent with videos that have black backgrounds it seems. Anyone else had this issue?

    Thanks
    Dean
    deanphillips2005@hotmail.co.uk

  86. David Stiller Says:

    Dean,

    I can’t say I’ve never seen that — but that’s only because it doesn’t sound especially familiar to me. I’m curious, too, if anyone else has seen this (or at least, has seen it often enough to reliably reproduce it). Maybe what you’re seeing is related to framerate, as well as background color?

  87. jeep Says:

    Dear David,

    Thank you very much, i’ve been working this out for the whole day since this morning when i realise that my FTP server does not support FLV. And google brought me here, and you’ve save my life!
    Now, it works!

    Thanks,
    jeep

  88. Nicholas Says:

    Hi there,

    I both understand and know how to use the FLVplayback component and the MetConnection and NetStream ActionScript, but what I cannot figure out is how I can play more than one .flv video file. What I want to be able to do is have three .flv videos in a directory, named say:

    video1.flv
    video2.flv
    video3.flv

    Each time I convert a ivdeo into the .flv video format and name it one of the above names, I want to be able to place it into the desired directory and have it overwrite the old .flv video file and playback in iether the FLVplayback component or useing the NetConeection and NetStream ActionScript.

    Thanks in advance, Nicholas.

  89. David Stiller Says:

    To jeep …

    Glad to hear that! :)

    To Nicholas …

    What you describe — overwriting FLV files on a server — isn’t something Flash Player can do (and I figure you know that), but by all means, the idea is a good one. You can certainly upload and overwrite existing files with an FTP client. As long as they’re named the same thing (here, always video1.flv, video2.flv, and video3.flv), Flash Player will simply load the newest ones. Just reference those files names in your code. What’s your question?

  90. Nicholas Says:

    Hi David, thanks for that post.

    I have managed to acomplish what I was after. Although, now I have run into a new problem.
    I have created an FLVplayback component which loads .flv video files externaly, given the .flv is named one of the selected names in the array below.

    Here is the ActionScript I have used thus far:

    var videoList:Array = new Array();
    videoList[0] = “video1.flv”;
    videoList[1] = “video2.flv”;
    videoList[2] = “video3.flv”;
    videoList[3] = “video4.flv”;
    var currentlyPlaying = 0;

    videoPlayer.contentPath = videoList[currentlyPlaying];
    videoPlayer.play();
    videoPlayer.bufferingBar = bufferClip;
    trace(currentlyPlaying);

    var listenerObject:Object = new Object();
    listenerObject.complete = function(eventObject:Object):Void {
    currentlyPlaying++;
    if (currentlyPlaying >= videoList.length) {
    currentlyPlaying = 0;
    }
    trace(currentlyPlaying);
    videoPlayer.contentPath = videoList[currentlyPlaying];
    videoPlayer.play();
    };
    videoPlayer.addEventListener(”complete”, listenerObject);

    If one of the .flv video files is missing from the directory the FLVplayback will continue to buffer and look for the missing .flv video file rather than continue to the next .flv video file.
    Would you David or anyone out there possibly know the solution to this problem?

    Many thanks, Nicholas.

  91. Nicholas Says:

    Anyone out there??

    :P

    Nicholas.

  92. David Stiller Says:

    Nicholas,

    Times are a bit tight lately. I’m working on two books at the moment, and it’s taking quite a toll. ;)

    What you need, here, is a way to determine when an FLV load has gone bad. The AS2 FLVPlayback class features a stateChange event that lets you know when the component starts playing, pausing, rewinding, and so on — and it even includes info on connection errors, such as when an FLV file is not present.

    Continuing on with your variable naming convention, consider the following new event handler:

    listenerObject.stateChange = function (eventObject:Object):Void {
      trace(eventObject.state);
    };
    
    videoPlayer.addEventListener("stateChange", listenerObject);

    When a video fails to load, you’ll see “connectionError” in the Output panel. Instead, you may want to increment currentlyPlaying and update the contentPath property again. That would skip to the next video. Or you could handle that particular sort of status change event in some other way.

  93. Nicholas Says:

    Hi Dave,

    Thank you very much! ;)

    Although, as good as you are at Flash I am unfortunately not.
    With the above ActionScript you gave me, Do I replace the old script or simlply add it?

    In regards to the updating of the currentlyPlaying and contentPath, I dont quite understand…

    By any chance are your two books based on Flash? Because I would realy love to have a copy of my own!! Hope all goes well.

    Thanks, Nick

  94. David Stiller Says:

    Nicholas,

    In the code you pasted, you already have a complete handler present:

    listenerObject.complete = function(eventObject:Object):Void {
      currentlyPlaying++;
      if (currentlyPlaying >= videoList.length) {
        currentlyPlaying = 0;
      }
      trace(currentlyPlaying);
      videoPlayer.contentPath = videoList[currentlyPlaying];
      videoPlayer.play();
    };

    That event handler references currentlyPlaying and contentPath, and I’m proposing that you add a second event handler that does the same thing for a video that fails to load. Your second event handler would presumably do the same thing — to an extent. The stateChange event handler should probably not loop currentlyPlaying to the beginning again, because that loop would repeat forever in the off-chance that none of the video files are present.

    So … you’ll continue to have your complete handler, but you’ll also add a stateChange handler:

    listenerObject.complete = function(eventObject:Object):Void {
      currentlyPlaying++;
      if (currentlyPlaying >= videoList.length) {
        currentlyPlaying = 0;
      }
      trace(currentlyPlaying);
      videoPlayer.contentPath = videoList[currentlyPlaying];
      videoPlayer.play();
    };
    listenerObject.stateChange = function(eventObject:Object):Void {
      if (eventObject.state == "connectionError") {
        currentlyPlaying++;
        if (currentlyPlaying < videoList.length) {
          videoPlayer.contentPath = videoList[currentlyPlaying];
          videoPlayer.play();
        }
      }
    };
    videoPlayer.addEventListener("complete", listenerObject);
    videoPlayer.addEventListener("stateChange", listenerObject);
  95. Nicholas Says:

    OK David,

    I completely understand now. Except, if “video4.flv” is missing from the directory the videoPlayer continues to buffer. Rather than skip to the first video and start over.
    The videoPlayer works and skips to the next .flv file, it is only when the last .flv is missing that it does not skip to the first .flv and start over.

    Thank you very much for contribution thus far!
    Nick.

  96. professional Says:

    Hello. I think you are eactly thinking like Sukrat. I really loved the post.

  97. Artur Trzebunia Says:

    David,

    Thank you for pointing me to your blog site. I’ve read the tutorials on working with cue points in Flash and understand this topic so much better. I finally understand how Flash recognizes cue points with specific names.

    I also understand your tutorial on how to determine when video reaches completion using onMetadata and onStatus. Taking this a step forward, how do I tell the video to return to the beginning AND STOP once the video reaches the end or the stop button is pressed? I’ve tried using ns.seek(0), but this statement returns the video to the beginning and starts playing again.

    Thanks for all your help.

  98. Jetty Says:

    Hi david,
    I just want to get video complete message for a embedded video in a time line OR the meachanisim we need to use for getting the video playback complete message
    Pls send the code to my e-mail

Leave a Reply