actionscript-3flex3cue-points

Early ActionScript movie cue points trigger too late


Before I start playing the movie, I add a couple of cue points, then register the callback, and trace everytime it gets hit, like this:

    private function onCuePoint(evt:CuePointEvent):void {
        var cuePointObject:Object = {name:evt.cuePointName, time:evt.cuePointTime, type:evt.cuePointType};          

        trace("onCuePoint: " + evt.cuePointName + "=" + cueDict[evt.cuePointName] + " @t=" + cuePointObject.time + " playtime=" + playheadTime);
    }

You'd think that cuePointObject.time would be roughly equal to the movie's playheadTime. Here's the output:

onCuePoint: cue3.4=cue3.4 @t=5.6 playtime=5.611
onCuePoint: cue1=cue1 @t=1 playtime=5.611
onCuePoint: cue2=cue2 @t=3 playtime=5.611
onCuePoint: cue2=cue2 @t=5 playtime=5.611
onCuePoint: cue3.1=cue3.1 @t=5 playtime=5.611
onCuePoint: cue3.1=cue3.1 @t=5.2 playtime=5.611
onCuePoint: cue3.2=cue3.2 @t=5.2 playtime=5.611
onCuePoint: cue3.2=cue3.2 @t=5.4 playtime=5.611
onCuePoint: cue3.3=cue3.3 @t=5.4 playtime=5.611
onCuePoint: cue3.3=cue3.3 @t=5.6000000000000005 playtime=5.611
onCuePoint: cue3.4=cue3.4 @t=5.8 playtime=5.888
onCuePoint: cue3.5=cue3.5 @t=5.8 playtime=5.888
onCuePoint: cue4=cue4 @t=10 playtime=9.92
onCuePoint: cue1=cue1 @t=11 playtime=11.221

It looks as though it waits until "cue3.4" is triggered and then the rest follow for some reason. They are added to the video as an array, which is sorted in the order in which they should appear, roughly, so cue3.4 is not first.


Solution

  • I found the problem after debugging for a while, so I'm posting the solution here in case anyone else stumbles upon it.

    It's a bug in Flex, I'm using v3.6 but I don't know if it's been fixed. When the cues are added to the CuePointManager, it does an insertion sort based on the cue's time. However, at one point in the algorithm it rounds the number like this:

    var compTime1:Number = Math.round(time * 1000);
    var compTime2:Number = Math.round(cuePoint.time * 1000);
    

    And then later, it checks the index that the comparison method returns (where it says the cue should get inserted) without using rounding:

    index = getCuePointIndex(cuePoints, true, copy.time, null, 0, 0);
    index = (cuePoints[index].time > copy.time) ? 0 : index + 1;
    

    My 3.3 cue that triggers at 5.6000000000000005 has that value because of a floating point error - I've added 0.2 to 5.4. So while getCuePointIndex returns the right index, it then gets set to 0 on that second line, putting it first in the list.

    My fix is to simply do the rounding on the cues' times myself before I add them:

    trace("pushing cue " + c.id + "@"+ c.time + " - "  + ((c.time + c.duration) * 1000) / 1000);
    cuePointArr.push({name:c.id + "_start", time:Math.round(c.time * 1000) / 1000,              type:"actionscript"});
    cuePointArr.push({name:c.id + "_stop",  time:Math.round((c.time + c.duration) * 1000) / 1000, type:"actionscript"});
    

    (note: I've since added the "_start" and "_stop" parts since I had an issue with having two cues with the same name)

    Hope this helps someone!