Contact Me


Recent Posts


Categories


Archives


Tags

3d actionscript Actionscript 2 Actionscript 3 api APIs as2 as3 brand caching carousel channel code compress contest contract CSS Flash flv fp10 free freelance gadget gadgets gdata google JavaScript jquery mvc papervision papervision3d PHP player playlist puremvc pv3d search tube tutorial twitter video widget XML you youtube

Recent Comments

  • Ahmed: Good old flexlib, what component are you using?
  • omer: Great article, help me allot. The only problem that I facing now is that I use flexlib component and I...
  • Ahmed: Well not designed, I merely consulted, gave my ideas, helped them with ux and code and deployment too!...
  • Zain Hasan: Oh wow, I am crazy about Olympism and today I came too knw that “best of us” is designed by...
  • Ahmed: Anything I can do to help, I need to update this plugin, need to implement oembed too

Links


Help end world hunger

Actionscript 3 Cue Points

Today I was working on finalising the video player for the competition web site 1Click2Fame.com. Since this video player will be multi purpose, for example, it will be used as a “chromeless” style player but may also have a “chrome” where the user can interact by voting for acts and so on, it needs the ability to record metrics such as user interaction and more importantly cue points.

The team at 1Click2Fame.com are not only interested in seeing what video a user watched, but how long they watched it for, especially if they voted for or against it winning. So cue cue points!

Now just a little about cue points in Actionscript 3: they’re not easy. You see in Actionscript 2 you could use the “Media.addCuePoint()” class function that allowed you to define the cue point’s string and the seconds where the cue point will be fired. It seems this function slipped out of the net when they wrote Actionscript 3, but we still live on.

So how do you add cue points in Actionscript 3? Well it seems you either:

  1. Bake them into your FLV media during encoding
  2. Use the FLVPlayback component in the Flash IDE

So neither option is particularly flexible. Well until you feast your eyes on my solution!

So we understand that cue points are moments in time on a video stream, so if we can hook into that stream and dispatch events when those moments of time are hit, then we have a cue point system! Let’s look at some code:

What we want to do is create a class-wide array, let’s call it “cuePoints”, and we’ll populate this array with the seconds of our cue points, like so:

1
2
3
4
5
6
7
8
9
10
11
12
package
{  
    class CuePointsTest
    {
        private var cuePoints:Array                             = [ ];
       
        public function set addCuePoint(seconds:Number):void
        {
            cuePoints.push( seconds );
        }
    }
}

So you would add a cue point like so:

1
2
3
var cuePointsTest:CuePointsTest = new CuePointsTest();

cuePointsTest.addCuePoint( 12 );

So now we’ve added the cue points, we need to check against the time of the stream. When loading a video in Actionscript 3 you use the “NetStream()” class, here’s a nice tutorial. Now once we’ve got the stream playing, using “NetSteam.play( url )”, we can add an event listener to the class to fire a function on ever frame. We can then get the stream’s current time and check against the cue points, like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
package
{  
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.NetStatusEvent;
    import flash.media.Video;
    import flash.net.NetConnection;
    import flash.net.NetStream;

    public class VideoPlayer extends Sprite
    {
        private var cuePoints:Array                             = [ ];
        private var lastFiredCuePoint:Number                    = 0;
        private var metaData:Object                             = { };
        private var video:Video                                 = new Video();
       
        private var stream:NetStream;
       
        public function VideoPlayer()
        {
            var connection:NetConnection = new NetConnection();
           
            connection.connect( null );
           
            stream = new NetStream( connection );
           
            stream.client = { onMetaData: handleOnMetaData };
           
            video.smoothing = true;
           
            video.attachNetStream( stream );
           
            addChild( video );
        }
       
        public function play(url:String):void
        {
            stream.play( url );
           
            addEventListener( Event.ENTER_FRAME, handleEnterFrame );
        }
       
        private function handleEnterFrame(e:Event):void
        {
            if ( cuePoints.length > 0 )
            {
                checkForCuePoints();
            }
        }
       
        private function checkForCuePoints():void
        {
            var time:Number = playingTime.current;
            var checkTime:Number = Math.floor( time );
            var test:Number = ArrayUtil.search( cuePoints, checkTime );
            var cuePoint:Number;
           
            if ( test > -1 )
            {
                cuePoint = cuePoints[ test ];
               
                if ( cuePoint > lastFiredCuePoint )
                {
                    dispatchEvent( new VideoPlayerEvent( VideoPlayerEvent.CUE_POINT, { point: cuePoint } ) );
                   
                    lastFiredCuePoint = cuePoint;
                }
               
            }
        }
       
        public function addCuePoint(seconds:Number):void
        {
            cuePoints.push( seconds );
        }
       
        private function handleOnMetaData(info:Object):void
        {
            metaData = info;
        }
       
        public function get playingTime():Object
        {
            var time:Object = { };
           
            time.current = stream.time;
            time.total = metaData.duration;
       
            return time;
        }
    }
}

So just a quick break down:

This is a standard FLV player status, the bit we’re interested in is the “checkForCuePoints()” function. What happens here is that first we get the current time of the video, we then floor it, so get it to the nearest second, and then we test it. I’m using a utility I wrote called “ArrayUtil()”, the code is below, it simply searches an array for a value and returns the index of that value.

Once we have this value we can then test to see if that cue point has been fired, if it hasn’t we then fire it. And to make sure that we don’t fire the same cue point more than once, we assign the last fired cue point as the value of the variable “lastFiredCuePoint” for our test. Simple eh?

Now of course there is some latency, about 1/10th of a second, but that’s not bad is it? Here’s the ArrayUtil class I’ve written:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.firestartermedia.lib.as3.utils
{
    public class ArrayUtil
    {      
        public static function search(array:Array, value:Object):Number
        {
            var found:Boolean = false;
           
            for ( var i:Number = 0; i < array.length; i++)
            {
                if ( array[ i ] == value )
                {
                    found = true;
                   
                    break;
                }
            }
           
            return ( found ? i : -1 );
        }
    }
}

So, I hope that makes sense. Remember, I’m going to publish the full player classes soon so don’t fret if you want them all! Also, if you are confused, just comment and I’ll happily help out.


4 Responses to “Actionscript 3 Cue Points”

Leave a Reply

Your comment:

Allowed tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>
Fork me on GitHub