Jump to content

A Code-Only Solution to Creating Your Own Video Player in ActionScript 3.0

  chco's Photo
Posted Dec 21 2010 07:48 AM

Creating your own player exclusively with ActionScript can reduce file size and allow you to customize functionality. The excerpt below from Learning ActionScript 3.0, Second Edition will take you through the process to do so.
In this exercise, you’ll write a class called BasicVideo to create a simple video player that does not use the FLVPlayback component. As a result, the generated SWF file is less than 4K.

The main video class

Line 1 declares the package, and lines 3 through 9 import the required classes. Line 11 declares the class and extends MovieClip so we can use its accessible properties, methods, and events of that class. Lines 13 through 17 declare private class properties—available throughout the class.

1    package com.learningactionscript3.video {
3        import flash.display.MovieClip;
4        import flash.events.AsyncErrorEvent;
5        import flash.events.MouseEvent;
6        import flash.events.NetStatusEvent;
7        import flash.net.NetConnection;
8        import flash.net.NetStream;
9        import flash.media.Video;
11        public class BasicVideo extends MovieClip {
13            private var _conn:NetConnection;
14            private var _stream:NetStream;
15            private var _vid:Video;
16            private var _vidPlaying:Boolean;
17            private var _source:String;

Lines 19 through 36 contain the class constructor. It accepts one string parameter for the video path to allow you to select a video when instantiating the class. Later, we’ll add a getter and setter to let you to do this by setting a property instead.

Lines 22 through 24 use the two main classes required to play videos with ActionScript. Line 22 creates an instance of the NetConnection class, which establishes a bi-directional connection between the user’s player and a server delivering data, such as a video streaming server. It’s a bit like the cable running between your house and the cable television company. You connect to the server using the connect() method in line 23. In this example, however, we’re not using a server, so we’ll pass null into this method. In this case, the class is designed to connect to a local file.

Line 24 creates an instance of the NetStream class and is associated with the NetConnection instance by passing the latter into the former’s constructor. A NetStream instance is a channel of a NetConnection instance, a little like a single cable channel, and transmits data in one direction. For example, a server can send data and a client can receive data.

Line 26 creates an instance of the Video class, which is the display object used to show the video. This is a bit like a television set. The NetStream instance is then attached to the video in line 27, a little like picking the cable channel you want to watch. Line 28 adds the video instance to the main class instance so it can become part of the display list.

Lines 30 through 33 create a custom object that will serve as a data client for the class. Select data will automatically be sent out when playing the video and if this object (or a similar object like a custom class created for the same purpose) does not exist, errors will occur. For example, any metadata that exists in the video, either by default or that was added during encoding, will be sent soon after the video begins loading. Similarly, any cue points that were embedded in the video will be sent when encountered. Lines 31 and 32 assign the onMetaData() and onCuePoint() methods to their corresponding properties so Flash Player knows where to send the appropriate information. This association is formalized when the object is assigned to the client property of the NetStream instance in line 33. Finally, event listeners are added to the class in line 35, which we will talk about after the code block.

18        //constructor
19        public function BasicVideo(path:String="") {
20            _source = path;
22            _conn = new NetConnection();
23            _conn.connect(null);
24            _stream = new NetStream(_conn);
26            _vid = new Video();
27            _vid.attachNetStream(_stream);
28            addChild(_vid);
30            var _infoClient:Object = new Object();
31            _infoClient.onMetaData = this.onMetaData;
32            _infoClient.onCuePoint = this.onCuePoint;
33            _stream.client = _infoClient;
35            addEventListeners();
36        }

Lines 38 through 47 add two event listeners each to the NetConnection and NetStream instances. The NET_STATUS event is dispatched when status updates become available from either instance. Similarly, the ASYNC_ERROR event is dispatched when an asynchronous error occurs in either instance. An asynchronous error is an error that’s not dependent on a specific (synchronized) order of execution. That is, it need not be the sequential result of another task performed by the class. This event is typically dispatched when a server calls a method that’s not defined in the client.

When either event is received, the methods in lines 49 through 60 are called. Both trace information so you can see what’s going on, but onNetStatus() also toggles the value of the _vidPlaying property. When a status update indicates that the video has started, the _vidPlaying property is set to true. When the status indicates that the video has stopped it sets the property to false.

37        //event listeners
38        private function addEventListeners():void {
39            _conn.addEventListener(NetStatusEvent.NET_STATUS,
40                                   onNetStatus,false,0,true);
41             _conn.addEventListener(AsyncErrorEvent.ASYNC_ERROR,
42                                   onAsyncError,false,0,true);
43             _stream.addEventListener(NetStatusEvent.NET_STATUS,
44                                     onNetStatus,false,0,true);
45             _stream.addEventListener(AsyncErrorEvent.ASYNC_ERROR,
46                                     onAsyncError,false,0,true);
47        }
49        private function onAsyncError(evt:AsyncErrorEvent):void {
50            trace(evt.text);
51            }
53            private function onNetStatus(evt:NetStatusEvent):void {
54                trace(evt.info.level + ": " + evt.info.code);
55                if (evt.info.code == "NetStream.Play.Start") {
56                     _vidPlaying = true;
57                } else if (evt.info.code == "NetStream.Play.Stop") {
58                     _vidPlaying = false;
59                }
60          }

Lines 62 through 74 contain the methods triggered by the metadata and cue points received during video playback. Line 63 traces the duration metadata field to demonstrate reacting to incoming information. You can add metadata during the encoding process, and encoding software can also automatically create metadata for you. Available metadata fields range from such basic items as duration, creation and modified date, width, height, and so on, to the highly specialized, like the DICOM collection of medical fields, depending on the encoder. Adobe Media Encoder supports an impressive array of available metadata.

Lines 67 through 69 trace the time, name, and type properties of any cue point received, and lines 70 through 73 trace any parameters added to that cue point when it was created.

61        //client methods
62        private function onMetaData(info:Object):void {
63            trace("MetaData duration:", info.duration);
64        }
66        private function onCuePoint(info:Object):void {
67            trace("CuePoint time:", info.time);
68            trace("CuePoint type:", info.type);
69            trace("CuePoint name:", info.name);
70            for (var prop in info.parameters) {
71                trace("Cue point parameter " + prop + ": " +
72                     info.parameters[prop]);
73            }
74        }

Finally, lines 76 through 101 contain the public methods, getters, and setters available outside the class. Lines 76 through 93 contain methods to play, pause, and stop the video, all of which are configured to receive mouse events. However, they also all include default values for the event, making it possible to call the methods directly, rather than as a result of an event. We’ll see this demonstrated in the main document class.

The playVideo() method in lines 76 through 83 first checks to see if the _vidPlaying property is true. If so, it calls the resume() method of the NetStream instance. This is because the class changes this property value when a status event indicates that the stream has been started or stopped, but not paused. Therefore, if a play button is clicked and the property is true, the video has been paused and should be resumed. If the property is false, the play() method is called, using the path in the _source property to indicate which video to play. In either case, the _vidPlaying property is set to true to record the fact that the video is playing.

The pauseVideo() method in lines 85 through 87 calls the togglePause() method. This is a nice feature because it will automatically pause the video if it’s playing and play the video if it’s paused.

Lines 89 through 93 contain the stopVideo() method. This method closes the stream (which is a bit like turning off your cable set top box), clears the Video instance (which is akin to turning off your television), and sets the _vidPlaying property to false.

Finally, lines 95 through 101 provide a getter and setter to allow the retrieval and assignment of the _source property from outside the class.

75        //public player methods and getter/setter
76        public function playVideo(evt:MouseEvent=null):void {
77            if (_vidPlaying) {
78                _stream.resume();
79            } else {
80                _stream.play(_source);
81            }
82            _vidPlaying = true;
83        }
85        public function pauseVideo(evt:MouseEvent=null):void {
86            _stream.togglePause();
87        }
89        public function stopVideo(evt:MouseEvent=null):void {
90            _stream.close();
91            _vid.clear();
92            _vidPlaying = false;
93        }
95        public function set source(path:String):void {
96            _source = path;
97        }
99        public function get source():String {
100            return _source;
101       }
102    }
103  }

The document class

The BasicVideo_UI class is a document class that instantiates BasicVideo and creates a simple interface with a play, pause, and stop button. Lines 1 through 7 declare the package and import the required classes. Lines 9 through 12 declare the class (which extends MovieClip so it can easily function as a document class) and declare two private properties. The first is a movie clip container to hold the video and buttons, so you can easily position the video interface anywhere on the stage. The second stores a reference to the BasicVideo instance so it can be used throughout the class.

Lines 14 through 27 contain the class constructor. Lines 15 through 17 create a container to hold the video and buttons, but also use the drawBackground() method (lines 29 through 36) to draw a black background the size of the video into the container. This is so, when clearing the video object after stopping playback, the video doesn’t look like it’s disappearing. (The function simply creates a movie clip, draws a black rectangle into it, and returns it to the point in the script where the function was called.)

Lines 19 through 21 create an instance of the BasicVideo class, assign the source property of the instance to the appropriate video path, and add the BasicVideo instance to the container. Line 22 demonstrates how to call the BasicVideo public method playVideo() directly, rather than from an event. This means you can automatically start the video playing without requiring a mouse click from the user.

The remainder of the class creates three buttons and assigns a listener to each to control the video.

1    package {
3        import flash.display.Graphics;
4        import flash.display.MovieClip;
5        import flash.events.MouseEvent;
6        import com.learningactionscript3.ui.RoundRectButton;
7        import com.learningactionscript3.video.BasicVideo;
9        public class BasicVideo_UI extends MovieClip {
11            private var _container:MovieClip;
12            private var _vidPlayer:BasicVideo;
14            public function BasicVideo_UI() {
15                 _container = drawBackground();
16                 _container.x = _container.y = 20;
17                 addChild(_container);
19                 _vidPlayer = new BasicVideo();
20                 _vidPlayer.source = "nero.flv";
21                 _container.addChild(_vidPlayer);
22                 _vidPlayer.playVideo();
24                 createButton(20, "Play", playVideo);
25                 createButton(120, "Pause", pauseVideo);
26                 createButton(220, "Stop", stopVideo);
27            }
29            private function drawBackground():MovieClip {
30                 var sp:MovieClip = new MovieClip();
31                 var g:Graphics = sp.graphics;
32                 g.beginFill(0x000000);
33                 g.drawRect(0, 0, 320, 240);
34                 g.endFill();
35                 return sp;
36            }
38            private function createButton(xLoc:Number, labl:String,
39                                          func:Function):void {
40                var btn:RoundRectButton =
41                    new RoundRectButton(80, 20, 10, 2, 0x000099,
42                                        labl, 0xFFFFFF);
43                btn.x = xLoc;
44                btn.y = 250;
45                btn.addEventListener(MouseEvent.CLICK, func,
46                                     false, 0, true);
47                _container.addChild(btn);
48            }
50            private function playVideo(evt:MouseEvent=null):void {
51                _vidPlayer.playVideo();
52            }
54            private function pauseVideo(evt:MouseEvent=null):void {
55                _vidPlayer.pauseVideo();
56            }
58            private function stopVideo(evt:MouseEvent=null):void {
59                _vidPlayer.stopVideo();
60            }
61       }
62  }

Although this exercise doesn’t create a full-featured video controller, it demonstrates the basics required to create the remaining functionality on your own, with help from the ActionScript 3.0 Language and Component Reference. Having completed this exercise, try to build a progress bar or a seek option. How you design your controller is up to you.

Learning ActionScript 3.0

Learn more about this topic from Learning ActionScript 3.0, 2nd Edition.

If you're new to ActionScript 3.0, or want to enhance your skill set, this bestselling book is the ideal guide. Designers, developers, and programmers alike will find Learning ActionScript 3.0 invaluable for navigating ActionScript 3.0's learning curve. You'll learn the language by getting a clear look at essential topics such as logic, event handling, displaying content, classes, and much more. Updated for Flash Professional CS5, this revised and expanded edition delivers hands-on exercises and full-color code samples to help you increase your abilities as you progress through the book.

See what you'll learn

0 Replies