setting the buffer time in OSMF

OSMF will automatically calculate a buffer for your video…but I needed to change it because my RTMP stream was stuttering.

I initially had:

player = new MediaPlayer();
player.bufferTime = 5 seconds;

But this didn’t seem to be affecting my buffer time. Well, it seems like you can only set the buffer time after the player has started playing:

player.play();
player.bufferTime = 5;

OSMF: making volume bars

I also decided to make some adjustable volume bars for my video player.

To make this work, open Flash and create a linked MovieClip called VolumeBars. Then inside this clip make four bars labelled:

VolumeBar25

VolumeBar50

VolumeBar75

VolumeBar100

This is a first go…any suggestions on how to optimize the code would be appreciated.

package
{
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.ColorTransform;
	import flash.geom.Rectangle;
	import flash.media.SoundTransform;
	import org.osmf.media.MediaPlayer;

	public class VolumeBars extends MovieClip
	{

		// graphics
		public var bar25:VolumeBar25 = new VolumeBar25();
		public var bar50:VolumeBar50 = new VolumeBar50();
		public var bar75:VolumeBar75 = new VolumeBar75();
		public var bar100:VolumeBar100 = new VolumeBar100();

		// toggles
		private var bar25Toggle:Boolean = true;
		private var bar50Toggle:Boolean = true;
		private var bar75Toggle:Boolean = false;
		private var bar100Toggle:Boolean = false;

		private var volumeValue:Number;

		// media player
		private var player:MediaPlayer;

		// default volume
		private var defaultVolume:Number = .5;

		// color when bar is ON
		private static const BAR_ON:uint = 0xFFFFFF;
		private var on:ColorTransform;

		// color when bar is ON
		private static const BAR_OFF:uint = 0x111111;
		private var off:ColorTransform;

		public function VolumeBars (player:MediaPlayer)
		{
			addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
			addEventListener(Event.REMOVED_FROM_STAGE,removed,false,0,true);
			this.player = player;
		}
		private function init(e:Event):void
		{
			volumeValue = .5;
			// trace("volumeValue:"+volumeValue);
			this.player = player;

			bar25.addEventListener(MouseEvent.MOUSE_OVER, bar25HandlerOn, false, 0, true);

			bar50.addEventListener(MouseEvent.MOUSE_OVER, bar50HandlerOn, false, 0, true);

			bar75.addEventListener(MouseEvent.MOUSE_OVER, bar75HandlerOn, false, 0, true);

			bar100.addEventListener(MouseEvent.MOUSE_OVER, bar100HandlerOn, false, 0, true);

			off = new ColorTransform();
			off.color = BAR_OFF;

			on = new ColorTransform();
			on.color = BAR_ON;

			// start off with 50% volume
			bar25.transform.colorTransform = on;
			bar50.transform.colorTransform = on;
			bar75.transform.colorTransform = off;
			bar100.transform.colorTransform = off;	

			bar25.buttonMode = true;
			bar50.buttonMode = true;
			bar75.buttonMode = true;
			bar100.buttonMode = true;	

		}
		private function removed(e:Event):void {

			bar25.removeEventListener(MouseEvent.MOUSE_OVER, bar25HandlerOn);

			bar50.removeEventListener(MouseEvent.MOUSE_OVER, bar50HandlerOn);

			bar75.removeEventListener(MouseEvent.MOUSE_OVER, bar75HandlerOn);

			bar100.removeEventListener(MouseEvent.MOUSE_OVER, bar100HandlerOn);

		}

		private function bar25HandlerOn(e:MouseEvent):void {
			if (!bar25) {
			bar25.transform.colorTransform = on;
			bar50.transform.colorTransform = off;
			bar75.transform.colorTransform = off;
			bar100.transform.colorTransform = off;
			player.volume = .25;
			bar25Toggle = true;
			} else {
			bar25.transform.colorTransform = off;
			bar50.transform.colorTransform = off;
			bar75.transform.colorTransform = off;
			bar100.transform.colorTransform = off;
			player.volume = 0;
			bar25Toggle = false;
			}

		}

		private function bar50HandlerOn(e:MouseEvent):void {
			if (!bar50) {
			bar25.transform.colorTransform = on;
			bar50.transform.colorTransform = on;
			bar75.transform.colorTransform = off;
			bar100.transform.colorTransform = off;
			player.volume = .50;
			bar50Toggle = true;
			} else {
			bar25.transform.colorTransform = on;
			bar50.transform.colorTransform = off;
			bar75.transform.colorTransform = off;
			bar100.transform.colorTransform = off;
			player.volume = .25;
			bar50Toggle = false;
			}

		}

		private function bar75HandlerOn(e:MouseEvent):void {
			if (!bar75Toggle) {
			bar25.transform.colorTransform = on;
			bar50.transform.colorTransform = on;
			bar75.transform.colorTransform = on;
			bar100.transform.colorTransform = off;
			player.volume = .75;
			bar75Toggle = true;
			} else {
			bar25.transform.colorTransform = on;
			bar50.transform.colorTransform = on;
			bar75.transform.colorTransform = off;
			bar100.transform.colorTransform = off;
			player.volume = .50;
			bar75Toggle = false;
			}

		}

		private function bar100HandlerOn(e:MouseEvent):void {
			if (!bar100Toggle) {
			bar25.transform.colorTransform = on;
			bar50.transform.colorTransform = on;
			bar75.transform.colorTransform = on;
			bar100.transform.colorTransform = on;
			player.volume = 1;
			bar100Toggle = true;
			} else {
			bar25.transform.colorTransform = on;
			bar50.transform.colorTransform = on;
			bar75.transform.colorTransform = on;
			bar100.transform.colorTransform = off;
			player.volume = .75;
			bar100Toggle = false;
			}

		}

	}	

	}

OSMF: making a seekbar

This is a first draft of a seekbar for my OSMF video player. To make the class work below, create a MediaPlayer in OSMF and pass it to this Seekbar class.

var seek:SeekBar = new SeekBar(myMediaPlayerInstance);

The seekbar is a linked MovieClip with 3 graphics which are linked MovieClips:

  • 1. a bar named Bar (again, another linked MovieClip)
  • 2. a progress bar (the same size, but a lighter colour) named Progress
  • 3. a small graphic called Seeker
  • package
    {
    	import flash.display.MovieClip;
    	import flash.events.Event;
    	import flash.events.MouseEvent;
    	import flash.events.ProgressEvent;
    	import flash.geom.Rectangle;
    	import flash.media.SoundTransform;
    	import org.osmf.media.MediaPlayer;
    
    	public class SeekBar extends MovieClip
    	{
    		public var background:Bar = new Bar();
    		public var progress:Progress = new Progress();
    		public var seeker:Seeker = new Seeker();
    
                    // measurements
    		private var startPoint:Number;
    		private var endPoint:Number;
    		private var currentPoint:Number;
    		private var totalWidth:Number;
    		private var player:MediaPlayer;
    		private var value:Number;
    		private var default_seek:Number;
    		private var seeking:Boolean = false;
    
    public function SeekBar(player:MediaPlayer)
    		{
    			addEventListener(Event.ADDED_TO_STAGE, init, false, 0, true);
    			addEventListener(Event.REMOVED_FROM_STAGE,removed,false,0,true);
    			this.player = player;
    		}
    		private function init(e:Event):void
    		{
    			seeker.buttonMode = true;
    			seeker.mouseChildren = false;
    			this.buttonMode = true;
    			seeker.x = 0;
    			progress.width = 0;
    			startPoint = background.x;
    			endPoint = background.x + background.width;
    			totalWidth = background.width;
    			seeker.addEventListener(MouseEvent.MOUSE_DOWN, startSeekDrag, false, 0, true);
    			stage.addEventListener(MouseEvent.MOUSE_UP, stopSeekDrag, false, 0, true);
    			addEventListener(Event.ENTER_FRAME, updateProgress, false, 0, true);
    			this.addEventListener(MouseEvent.CLICK, onSeekToClick, false, 0, true);
    		}
    		private function removed(e:Event):void
    		{// remove event listeners when the seekbar is removed from the stage
    			if (seeker) {
    				seeker.removeEventListener(MouseEvent.MOUSE_DOWN, startSeekDrag);
    			}
    			if (stage) {
    				stage.removeEventListener(MouseEvent.MOUSE_UP, stopSeekDrag);
    			}
    			removeEventListener(Event.ENTER_FRAME, updateProgress);
    			this.removeEventListener(MouseEvent.CLICK, onSeekToClick);
    		}
    		private function startSeekDrag(e:MouseEvent):void
    		{
    			seeker.startDrag(false, new Rectangle(startPoint, 0, endPoint, 0));
    			seeking = true;
    		}
    		private function updateProgress(e:Event):void
    		{
    			// moves the seeker and progress together
    			if (! seeking) {
    				seeker.x = ((player.currentTime * totalWidth) / player.duration);
    				moveSeeker();
    			} else {
    				moveSeeker();
    				seekToPoint();
    				player.play();
    			}
    		}
    		private function stopSeekDrag(e:MouseEvent):void
    		{
    			seeker.stopDrag();
    			moveSeeker();
    			seeking = false;
    		}
    		private function seekToPoint()
    		{
    			var c:Number = (seeker.x);
    			value = (c - startPoint) / totalWidth;
    			// returns a ratio;
    			if (player.canSeek == true) {
    				player.seek(value * player.duration);
    			} else {
    				trace("can't seek video");
    			}
    		}
    		private function moveSeeker():void
    		{
    			currentPoint = seeker.x + seeker.width;
    			progress.width = currentPoint - startPoint;
    		}
    		private function onSeekToClick(e:MouseEvent):void
    		{
    			removeEventListener(Event.ENTER_FRAME, updateProgress);
    			var seekPoint:Number = this.mouseX;
    			seeker.x = seekPoint;
    			moveSeeker();
    			seekToPoint();
    			addEventListener(Event.ENTER_FRAME, updateProgress, false, 0, true);
    		}
    	}
    }
    

    OSMF: playing multiple videos, but using only 1 connection

    So, on a project I’m on…I need to play multiple videos from a Flash Media Server, but only use 1 connection. Since I am just testing right now, if I open up too many connections I get the OSMF error message:

    Connection attempt rejected by FMS server

    After some help on the OSMF forums (thanks Brian Riggs!) I found this reference, and here is what I learned:

    You can create multiple Video Elements but use the same NetLoader for all of the Video Elements. By default, using only one NetLoader for all the same Video Elements ensures that there is only one connection.

    One Connection:

    var netLoader:NetLoader = new NetLoader();
    

    Many Connections

    var netLoader:NetLoader = new NetLoader(new NetConnectionFactory(false));

    The NetLoader instance (in this case, “netLoader”) gets passed to the Video Element:

    var netLoader:NetLoader = new NetLoader();
    
    var myVideo:VideoElement  = new VideoElement(new URLResource("rtmp://link-goes-here"), netLoader);

    If you don’t pass a NetLoader to a Video Element, the element will create a new NetLoader for itself (which is not what you want if you only want to have 1 connection for all of your videos).

    Next thing…each Video Element (or, Media Element) has a trait called a “LoadTrait”…this trait can load the video (loadTraitInstance.load) or unload the video (loadTraitInstance.unload).

    To make this work, you have to create a “Load Trait” for each video:

    var loadTraitInstance:LoadTrait = video1.getTrait(MediaTraitType.LOAD) as LoadTrait;
    loadTraitInstance.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange);
    loadTraitInstance.load(); // this load trait gets automatically "passed" to the NetLoader
    
    var NEXTloadTraitInstance:LoadTrait = video1.getTrait(MediaTraitType.LOAD) as LoadTrait;
    NEXTloadTraitInstance.addEventListener(LoadEvent.LOAD_STATE_CHANGE, onLoadStateChange);
    NEXTloadTraitInstance.load(); // the NetLoader "unloads" the last VideoElement and loads in another in the same connection

    as you load each video by its “LoadTrait”, the “LoadTrait” get passed into the NetLoader.

    If you load a series of videos by their load trait…the NetLoader instance handles everything and unloads the previous video before loading the next one.)

    OSMF: adding actionscript cue points to h.264 video

    Using the Open Source Media Framework from Adobe, you can now add Actionscript cue points on the fly to h.264 video. This is really great because you don’t have to use the .flv or .f4v wrapper. Also, these actionscript cue points using OSMF are supposed to be very accurate (within 250 milliseconds).

    Cue points are markers and need to be added to what is called timeline metadata.

    If your video element, is called, say, mediaElement, you create timeline metadata by writing:

    myTimelineMetadata = new TimelineMetadata(mediaElement);

    Then, you can create a Actionscript cue point:

    cuePoint = new CuePoint(CuePointType.ACTIONSCRIPT,  1 , "my cue point name" , null ); // 1 is the time

    Then you add the cue point (marker) to the timeline:

    myTimelineMetadata.addMarker(cuePoint);

    Download source files