EladElrom.com

Deep Dive Into Technology

Adobe Open Source Media Framework (OSMF) – revisit

About a year ago I have posted a blog post on how to get started with OSMF (see here). Since than the framework have gone a long way. OSMF 1.0 was released recently and I have given it a second look.

I want to give credit to Brian Riggs and David Hassoun for helping with the content of this blog entry.

OSMF is an open source AS3 media framework that supports the workflow around video playback and monetization. Video players have different features set. The skins are different, and the integration and architecture workflow are. They essentially do the same thing and can be created using the OSMF framework. The framework is based on the quality of the video player (OVP) and addresses the common challenges.
The foundation of the framework is Qos (quality of service) which focuses on Open Video Player (OVP) and provides a quick start for playing videos (smallest buffer size needed to start the video), efficient connection logic, and switching bitrates dynamically (recall the metric monitor service in OVP).

The framework can be used as follows:

  • Create a component user interface for integration of audio, videos, and images.
  • Plugin architecture for integration of the following: CDN, ad partners, publishers, analytics, social networks, and developers.

The framework by itself is not powerful without having partners embracing the frameworks – e.g. CDNs, publishers, ad analytics, social networks, and developers. This type of pluggable component can allow publishers to easily switch and test performance and service across different services.
Advantages:

  • Reduce the barrier of entry for new publishers – By offering a framework to integrate the different pieces of the video player, new publishers can get started quickly and with fewer resources and can scale up as requirements increase.
  • Provide flexible framework – OSMF provides an easy way to extend each component and allows these components to act as Lego pieces that can be compositable and extensible.
  • Leverage existing code – The OSMF framework uses the Flash Player from Open Video Player (OVP). No need to have duplication of efforts to solve basic problems.
  • Drive Standard and allow custom workflows – Many of the elements that connect to a video player are not standard yet, and Adobe OSMF will help standardize these components and allow them to be configured.
  • No runtimes or framework dependency – The framework is based on Flash 10 AS3 and is not dependant on any framework such as Flex SDK, Cairngorm, or others. With that said, some integrated elements may be created using a framework, but these are loosely coupled and can be replaced if needed.
  • Partners focus – There are two partners: publishers and CDNs. Each can focus on their expertise. CDN can focus on services and integration, and publishers can focus on user experience.
  • Integration with existing Adobe tools – Adobe OSMF will be integrated with other Adobe Suite tools and services such as Catalyst, Illustrator, FMS 3.5 and FMRMS.
  • Optimize – By having the ability to separate the core framework and each element as a separate SWC, you can increase performance by keeping file size to the minimum and remove components not used.

The Adobe OSMF framework consists of the following building blocks:

MediaPlayer - MediaPlayer class represents the controller class for media playback. You can play any type of media (video, audio, images, SWFs, etc.). Instead of using DisplayObject – use MediaPlayerSprite. To use the the media you can use the following methods: play(), pause(), seek() as well as the following properties: volume, autoRewind, loop. The events for the media are: seekingChange, volumeChange, complete

MediaElements & Traits – MediaElement class represents a unified media presentation (video, image, or a grouping of media that’s shown together). It takes a resource (URL, array of dynamic streams, etc.). You can than presents/plays the media using one or more MediaTraitBase. MediaTraitBase represents an intrinsic capability of a piece of media (ability to play, ability to seek, audio, etc.). This class is dynamic in nature, can come and go over the life of the media Trait APIs, it is also media-type-agnostic. Keep in mind that not all traits apply to all media types. For instace AudioElement doesn’t have DisplayObjectTrait and ImageElement doesn’t have PlayTrait.

Rules of thumb – A trait represents a media capability or characteristic. Trait cannot apply to every piece of media and must be something that a player developer might act upon. For instance: LoadTrait, PlayTrait, SeekTrait, DisplayObjectTrait.

As an example, take a look at the VideoElement traits in Figure:

110

Composite Elements – ParallelElement class represents a set of MediaElements that are presented in parallel. It is a media composition whose elements are presented in parallel. SerialElement class represents a set of MediaElements that are presented one after the other. These classes used together create two composite MediaElements that can represent complex, “tree-like” media experiences.

To better understand how it works take a look at Figure:

22

We have three video related MediaElements: (Episode), (Mid-Roll Ad) and (Episode, Continued). Together they create a media experience and are grouped as serialElement. Once you create the serialElement you can add that group to a parallelElement with other serialElement.

Composite Elements – A composite MediaElement is a MediaElement that exposes composite traits. Composite traits aggregate multiple traits of the same type. For instance, you can take two VideoElement and create a SerialElement and than have access to both playTrait properties from each VideoElement. Together these playTraits are CompositePlayTrait.

Proxy Elements – ProxyElement class wraps up (proxies) with another MediaElement. These class expose the same API. The class signature is as follow:

public function ProxyElement(wrappedElement:MediaElement)

By default, all methods, properties and events are passed through subclasses and can change. This can be used to modify the behavior of another MediaElement. Clients think they’re working with a VideoElement, when they’re actually working with a ProxyElement that wraps a VideoElement. This is incredibly useful for plugins.

Here are two examples of ProxyElement:

  • User Analytics – ProxyElement, which listens for changes to the wrapped MediaElement and reports them to a server.
  • Seamless Video Switching – ProxyElement, which wraps up two VideoElements, and switches from one to the other without rebuffering.

Take a look at the example in Figure below. Here we created a AnalyticsProxyElement element. The proxy listens to events from wrapped MediaElement and can reports the data back to Omniture API. The AnalyticsProxyElement does that by wrapping an UnseekableProxyElement that prevents seeking of the wrapped MediaElement.

32

Plugins – The real challenge is the third party integration. There are many 3rd party vendors that make a player such as CDNs, Ad Servers/Networks, Analytics Providers, “Social” Providers and many others.

To allow integration between the Player and the vendors OSMF created Player/Plugin contract, which declare what the plugin capabilities are.

Plugins don’t have free rein over the player. Meaning that the Players can load plugins, but Players don’t integrate with custom plugin APIs directly. The way it works is that OSMF acts as the broker between the player and the plugin.

There are ranges of different plugin types:

  • Media Plugins – declares new media types. For examples: Video plugin, image plugin
  • Loader Plugins – declare new ways of “loading” media. For example: Akamai plugin for connection authentication.
  • Proxy Plugins – declare ways to modify (or listen to) the behavior of media. For example: Plugin, which prevents seeking of all videos, Omniture reporting plugin.
  • R

  • eference Plugins – Declare the range of media they’d like to reference – example: Plugin, which creates an overlay ad SWF that can pause the main video when displayed.

For info about creating plugins, check ASDOC PluginInfo:
http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/org/osmf/media/PluginInfo.html

Metadata – There are two types of metadata: Resource-level Metadata and MediaElement Metadata.

Resource-level Metadata was created to address the challenge of how do I know what “http://example.com/myvideo” represents. MediaResourceBase.addMetadataValue method can be used to further qualify a resource with “static” data (e.g. MIME type). For instance, let’s say we want to assign the “video/x-flv” MIME type to the resource with a URL so we can know that it’s a video.

MediaElement Metadata was created to address the challenge of representing custom information about what’s playing. MediaElement.addMetadata method used to model metadata during playback.
For instance, let’s say that we have a dynamically generate “ad” vs. “episode” metadata, we want to be able to know that so we can have the UI update the chrome during ad breaks.

The OSMF Code is available here: www.osmf.org
To read more see the resources listed in this page: http://forums.adobe.com/message/2392184#2392184

Hello World example

To create a simple Hello Wrold visit the OSMF wesite:
http://blogs.adobe.com/osmf/2009/09/building_a_helloworld_app_with_osmf.html

Below is a minimalistic example of loading an image using Flex 4. We create sprite that contains a MediaPlayer to manage the display and control of the MediaElements we will be using. We then create and set the MediaElement (in our case ImageElement) with a resource and path. Lastly, we add the sprite to the UIComponent.

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx"
			   minWidth="1024" minHeight="768"
			   creationComplete="creationCompleteHandler()">

	<fx:Script>
		<![CDATA[
			import org.osmf.elements.ImageElement;
			import org.osmf.elements.VideoElement;
			import org.osmf.media.MediaPlayerSprite;
			import org.osmf.media.URLResource;

			//path of media to be displayed: Image
			private static const MEDIA_PATH:String = "http://mediapm.edgesuite.net/strobe/content/test/train.jpg";

			protected function creationCompleteHandler():void
			{
				//sprite that contains a MediaPlayer to manage display and control of MediaElements
				var playerSprite:MediaPlayerSprite = new MediaPlayerSprite();

				//creates and sets the MediaElement (ImageElement) with a resource and path
				playerSprite.media = new ImageElement( new URLResource( MEDIA_PATH ) );

				//Adds the sprite to the UIComponent defined in MXML
				mediaHolder.addChild( playerSprite );
			}

		]]>
	</fx:Script>

	<mx:UIComponent id="mediaHolder" />

</s:Application>

Below is a minimalistic example of creating a progressive download video player using OSMF and Flex 4. Just as in the image example we create a sprite that contains a MediaPlayer to manage the display and control of the MediaElements we will be using. We then create and set the MediaElement (in our case VideoElement) with a resource and path. Lastly, we add the sprite to the UIComponent.

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx"
			   minWidth="955" minHeight="600"
			   creationComplete="creationCompleteHandler()">

	<fx:Script>
		<![CDATA[
			import mx.core.UIComponent;

			import org.osmf.elements.VideoElement;
			import org.osmf.media.MediaPlayerSprite;
			import org.osmf.media.URLResource;

			//path of media to be displayed: Progressive Video
			private static const MEDIA_PATH:String = "http://mediapm.edgesuite.net/strobe/content/test/AFaerysTale_sylviaApostol_640_500_short.flv";

			protected function creationCompleteHandler():void
			{
				//sprite that contains a MediaPlayer to manage display and control of MediaElements
				var playerSprite:MediaPlayerSprite = new MediaPlayerSprite();

				//creates and sets the MediaElement (VideoElement) with a resource and path
				playerSprite.media = new VideoElement( new URLResource( MEDIA_PATH ) );

				//Adds the sprite to the UIComponent defined in MXML
				var component:UIComponent = new UIComponent();
				component.addChild( playerSprite );
				mediaHolder.addElement( component );
			}

		]]>
	</fx:Script>

	<s:Group id="mediaHolder" />

</s:Application>

In case we want to serve an audio file via progressive download, just use AudioElement instead of VideoElement.

Here is a minimalistic example of streaming a video using OSMF and Flex 4. The URL points to a streaming server and the OVP player will be able to recognize that and provide streaming instead of progressive download.

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx"
			   minWidth="1024" minHeight="768"
			   creationComplete="creationCompleteHandler()">

	<fx:Script>
		<![CDATA[
			import org.osmf.elements.ImageElement;
			import org.osmf.elements.VideoElement;
			import org.osmf.media.MediaPlayerSprite;
			import org.osmf.media.URLResource;

			//URI of connection/media to be displayed: RTMP - Streaming Video
			private static const MEDIA_PATH:String = "rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short";

			protected function creationCompleteHandler():void
			{
				//sprite that contains a MediaPlayer to manage display and control of MediaElements
				var playerSprite:MediaPlayerSprite = new MediaPlayerSprite();

				//creates and sets the MediaElement (VideoElement) with a resource and path
				playerSprite.media = new VideoElement( new URLResource( MEDIA_PATH ) );

				//Adds the sprite to the UIComponent defined in MXML
				mediaHolder.addChild( playerSprite );
			}

		]]>
	</fx:Script>

	<mx:UIComponent id="mediaHolder" />

</s:Application>

Here is an example of dynamic streaming using FMS server. We set the host URL for the steaming server and than we can add the profile files for the videos and the dynamic switching will be handles automatically by the OVP player based on the user’s bandwidth.

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx"
			   minWidth="1024" minHeight="768"
			   creationComplete="creationCompleteHandler()">

	<fx:Script>
		<![CDATA[
			import org.osmf.elements.VideoElement;
			import org.osmf.media.MediaPlayerSprite;
			import org.osmf.net.DynamicStreamingItem;
			import org.osmf.net.DynamicStreamingResource;

			//URI of host RTMP/E connection for streaming server
			private static const HOST:String = "rtmp://cp67126.edgefcs.net/ondemand";

			protected function creationCompleteHandler():void
			{
				//sprite that contains a MediaPlayer to manage display and control of MediaElements
				var playerSprite:MediaPlayerSprite = new MediaPlayerSprite();

				//Resource containing the pointers, bitrate, width, and height of each DynamicStreamingItem to be in the set
				var dsr:DynamicStreamingResource = new DynamicStreamingResource( HOST );
				dsr.streamItems.push( new DynamicStreamingItem( "mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_768x428_24.0fps_408kbps.mp4", 408, 768, 428) );
				dsr.streamItems.push( new DynamicStreamingItem( "mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_768x428_24.0fps_608kbps.mp4", 608, 768, 428) );
				dsr.streamItems.push( new DynamicStreamingItem( "mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_1024x522_24.0fps_908kbps.mp4", 908, 1024, 522) );
				dsr.streamItems.push( new DynamicStreamingItem( "mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_1024x522_24.0fps_1308kbps.mp4", 1308, 1024, 522) );
				dsr.streamItems.push( new DynamicStreamingItem( "mp4:mediapm/ovp/content/demo/video/elephants_dream/elephants_dream_1280x720_24.0fps_1708kbps.mp4", 1708, 1280, 720) );

				//Creates the MediaElement (VideoElement) adding the DynamicStreamingResource to it, and setting to as the mediaElement on the MediaPlayerSprite
				playerSprite.media = new VideoElement( dsr );

				//Adds the sprite to the UIComponent defined in MXML
				mediaHolder.addChild( playerSprite );
			}

		]]>
	</fx:Script>

	<mx:UIComponent id="mediaHolder" />

</s:Application>

You can download these examples from here:
http://www.eladelrom.com/blog/Flex/OSMF/OSMFExample.fxp

Last example (more advanced) shows you how to create a streaming video player and listen to events to recognize once the video is ready to play, as well as access properties in the video player and the net stream:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx"
			   minWidth="1024" minHeight="768">

	<fx:Script>
		<![CDATA[
			import org.osmf.elements.VideoElement;
			import org.osmf.events.DisplayObjectEvent;
			import org.osmf.events.MediaPlayerCapabilityChangeEvent;
			import org.osmf.media.MediaPlayer;
			import org.osmf.media.URLResource;

			private var playerContainer:Sprite = new Sprite;
			private var mediaPlayer:MediaPlayer = new MediaPlayer();

			private function playVideoURL(url:String):void
			{
				mediaPlayer.addEventListener( MediaPlayerCapabilityChangeEvent.CAN_PLAY_CHANGE, onVideoLoadedAndReady );
				mediaPlayer.addEventListener( DisplayObjectEvent.MEDIA_SIZE_CHANGE, onDimensionChange );

				var videoElement:VideoElement = new VideoElement(  new URLResource( url ) );

				mediaPlayer.media = videoElement;
				mediaHolder.addChild( playerContainer );
			}

			private function onVideoLoadedAndReady(event:MediaPlayerCapabilityChangeEvent):void
			{
				if (event.enabled  && mediaPlayer.canPlay)
					mediaPlayer.play()
			}

			private function onDimensionChange( event:DisplayObjectEvent ):void
			{
				mediaPlayer.displayObject.width = event.newWidth;
				mediaPlayer.displayObject.height = event.newHeight;

				mediaHolder.addChild( mediaPlayer.displayObject );
			}

		]]>
	</fx:Script>

	<s:Rect top="0" width="660" height="365"
			x="0" y="0">
		<s:fill>
			<s:SolidColor color="#000000"/>
		</s:fill>
	</s:Rect>

	<mx:UIComponent id="mediaHolder" />

	<s:TextInput id="mediaPath" width="400"  x="48" y="330"
				 text="rtmp://cp67126.edgefcs.net/ondemand/mediapm/strobe/content/test/SpaceAloneHD_sounas_640_500_short"/>
	<s:Button x="456" y="331" label="Play" click="playVideoURL(mediaPath.text)"/>
	<s:Button x="534" y="331" label="Pause" click="mediaPlayer.pause()"/>

</s:Application>

Where to go from here:

The toolkit and documentation is available for download at:
www.OpenSourceMediaFramework.com

OSMF developer forums:
http://forums.adobe.com/community/opensource/osmf/developers

OSMF User Group:
http://groups.adobe.com/groups/7af970e6e4/summary

The lost blog post: Getting started with building applications for the iPhone, iPod touch, or iPad using Flash Tools

I have written this article last year and didn’t released it since the information was under NDA and when CS5 came out Apple released iOS SDK which included section 3.3.2 and blocked applications built with Flash and other engines. Since than Apple relaxed section 3.3.2 allowing popular game engines and libraries to publish content, while still blocking Flash.

Although we don’t know if in the future the Apple app store will accept applications built with CS5, currently it’s still possible to create applications for the iPhone platform using Adobe Flash Professional CS5 and I figured I will release this blog post.

  1. Create application for the iPhone and iPad and publish them for usage for devices that are jailbroken
  2. Use the iPhone as another testing platform and publish your application on the AIRAndroid or other devices.
  3. Better understand the process which is similar to AIR Android

In this article I will be focusing on building an application for apple mobile devices using Flash Professional CS5. The way it works is that CS5 includes a Packager for the iPod, iPhone and iPad, which allows compiling the ActionScript bytecode into a native application code.

The applications are distributed on the iTune store as application installer files (.ipa files), just like any other native application. To make that possible a front end Ahead of Time (AOT) compilation is using the Low Level Virtual Machine (LLVM), see http://llvm.org/, compiler to output native ARM assembly code, instead of using the Just in Time (JIT) compilation. See figure 1.

15

Creating your first iPhone application using CS5

  1. Developer certification – The first step is to apply for a developer certification from Apple. You can purchase the certificate from here: http://developer.apple.com/iphone/program/. Keep in mind that this step can take few days. To apply for a commercial certificate I had to fax over my LLC article of incorporations.
  2. Provisioning Profile – Once you complete the registrations process, you need to create and install a Provisioning Profile and an iPhone Development Certificate. You can see instructions here: http://developer.apple.com/iphone/library/documentation/Xcode/Conceptual/iphone_development/128-Managing_Devices/devices.html – //apple_ref/doc/uid/TP40007959-CH4-SW2, under “Obtaining Your Development Certificate”
  3. Upload a CSR file – Login to member center (http://tiny.cc/kjnp3) and upload the CSR file to Apple at the iPhone developer site.
  4. Add certifications, device and app Id – Under select: iPhone Provisioning Portal add: development certificates, add devices, add App IDs and provisioning. See ‘How To’ in development center for more information and all the steps needed to complete these parts.
  5. Convert certificate to P12 file – The last step is converting the developer certificate into a P12 file, needed for CS5: Open Keychain Access. Next, select the private key associated with your iPhone Development Certificate and click: File > Export Items. Place a password and you’re done.

Creating ‘Hello World’ application

You are ready to create your first application. We will create minimalistic code and deploy it on the apple’s devices.

  1. Open Flash Professional CS5 and create a new Flash document: File > New Document > Select iPhone OS, see figure 2:
  2. 21

  3. Add text box – click text tool element and change the text to: Hello World
  4. Compile the application – Select Control > Test Movie > In AIR Debug Launcher (Mobile). Save the application as HelloWorld.fla
  5. Icons – iPhone applications have icons that appear in iTunes and on the iPhone screen. You will need to create three icons with the sizes based on the names:
    You can just create empty icons with one color for this app:

    • 29×29.png
    • 57×57.png
    • 512×512.png

  6. Default image – create an image in the size of 320×480 and name it: Default.png. Place the image in the root directory of the application. This image will be displayed while the application loads on the iPhone.
  7. iPhone application settings & creating ipa file

  8. Compile the application – now we are ready to compile, Choose File > iPhone OS Settings. The iPhone Settings window opens up, see Figure 3:
  9. 31

    General Tab

    The General tab includes the following settings:

  10. Output file – The file name
  11. App name – The name of the application
  12. Version – the version number of your application
  13. Aspect ratio – initial aspect ratio of the app (portrait or landscape).
  14. Full screen – full screen, or displays the iPhone status bar.
  15. Auto orientation – allow the content to be reorient when the iPhone is reoriented.
  16. Rendering – decide how display objects are rendered: CPU, GPU or Auto (not yet implemented)
  17. Included files – Add any supporting files and directories.
  18. 41

    Icon tab

  19. Icons tab – allow you to point to the location of the icons.

51

Application descriptor

The application descriptor file, just like in any AIR app, is an XML file that holds all the application’s properties.

The iPhone application setting in CS5 generates the app descriptor and you can also edit the file manually.

The template descriptor file for AIR generated by Flash CS5 doesn’t include iPhone block at this point, so you have to add it in manually to publish an application for the iPad.

Add the Following to the descriptor file after the block:

<!-- iPhone/iPad -specific capabilities -->
<iPhone>
     <!-- A list of plist key/value pairs to be added to the application Info.plist -->
     <!-- Setting UIDeviceFamily will limit to which device is targeted. 1 is for iPhone/iPod. 2 is for iPad. -->
     <infoAdditions>
          <![CDATA[
          <key>UIDeviceFamily</key>
          <array>
          <string>1</string>
          <string>2</string>
          </array>
          <key>UIStatusBarStyle</key>
          <string>UIStatusBarStyleBlackOpaque</string>
          <key>UIRequiresPersistentWiFi</key>
          <string>NO</string>
          ]]>
     </infoAdditions>

</iPhone>

As you can see, in the under the UIDeviceFamily, 1 means iPhone and 2 means iPad.

When you create an iPad app you need to set your FLA document to the iPad side: 768×1004 in order to fill the whole screen.

Currently CS5 doesn’t allow debugging of iPad apps, however you can tab directly into the AIR debugger app located here:
/Applications/Adobe Flash CS5/AIK2.0/bin/adl

And debug your application manually. The command is as follow:

adl -screensize iPad -profile mobileDevice application.xml

For the iPad the command on my machine looks like this:

./adl -screensize iPad -profile mobileDevice /Users/Elad/Desktop/19/iPad Hello World/HelloWorld-app.xml

Installing your iPhone application

To install the application on your device you must first ensure you have added the provisioning profile file, see: Creating your first iPhone application using CS5 under: Provisioning Profile.

The easiest way to install the application is to double click the ipa file and it will be added to iTune and then you can just sync your device and your done.

Use FlashBuilder 4 to write your iPhone code

Flash Professional was criticized for creating projects with heavy ActionScript code projects and was one of the main motivation of using Eclipse as the IDE for developing AS3 code. You can use Flash Professional CS5 to compile and Flash Builder 4 to edit the ActionScript 3.0 content of your application.

File > New > iPhone OS. Save the project as Main.fla

Under properties click the pencil icon or place the class name and than hit the pencil, see Figure:

61

When it asks you which application should edit the ActionScript 3 class choose FlashBuilder.

7

At this point, you FlashBuilder will open up and create a new Flash Professional project, see Figure:

81

FlashBuilder opens up and ask you if you want to switch to Flash Prospective, select to switch and hit Ok.

The entry point class get populated automatically:


package
{
	import flash.display.Sprite;

	public class Main extends Sprite
	{
		public function Main()
		{

		}
	}
}

Let’s just add a text field with Hello World, see below;


package
{
     import flash.display.Sprite;
     import flash.text.TextField;

     public class Main extends Sprite
     {
          public function Main()
          {
               var textField:TextField = new TextField();
               textField.text = "Hello World";

               this.addChild( textField );
          }
     }
}

You can now publish your application. In FlashBuilder select:
Project > Publish Movie. You can also select: Command + Enter (Mac) or Control + Enter (PC). See Figure:

91

Loading FXG graphic at runtime

Yesterday I posted a blog post about the fact that FXG code can increases your SWF container size and tax your CPU, so you should take that into account when deciding if it’s better to load images on runtime, embed assets or use FXG code. Adding optimized FXG or MXML Graphics (MXMLG) is the same in term of fact that the code you add will increase the application’s swf size so although it wont tax your CPU unless you add the child to the display object it will still increase your container size just like embedding assets.

There are many times when you do want to use FXG code. For instance you don’t want to degrade the designer’s graphic, or you want to keep the vector to scale high quality, change properties on runtime, etc. You still want to avoid increasing your container size.

There is a way. You can use the FXGStringConverter I created few months ago and load the FXG on runtime, just as you with images and other assets.

Take a look at a simple class that allow you to load the FXG and use it in your application:

<s:Group xmlns:fx="http://ns.adobe.com/mxml/2009"
		 xmlns:s="library://ns.adobe.com/flex/spark">

	<fx:Script>
		<![CDATA[

			import com.elad.framework.utils.fxgconverter.FXGStringConverter;

			[Bindable]
			public var xLocation:int = 0;

			[Bindable]
			public var yLocation:int = 0;

			private var _source:String;

			public function get source():String
			{
				return _source;
			}

			public function set source(value:String):void
			{
				_source = value;

				loadFxg();
			}

			private function loadFxg():void
			{
				var loader:URLLoader = new URLLoader();

				loader.addEventListener( Event.COMPLETE, onLoaded );
				loader.addEventListener( IOErrorEvent.IO_ERROR, onError );
				loader.load(new URLRequest(source));
			}

			private function onLoaded(event:Event):void
			{
				var fxgString:String = event.target.data;

				var group:Group = FXGStringConverter.convertFXGStringToComponent( fxgString, true );
				fxgHolder.addElement( group );
			}

			private function onError(event:IOErrorEvent):void
			{
				trace( event.text );
			}

		]]>
	</fx:Script>

	<s:Group id="fxgHolder" x="{xLocation}" y="{yLocation}" />

</s:Group>

Here’s an example where I am loading the FXG code on runtime and add it as a new element to the display object:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   minWidth="955" minHeight="600"
			   xmlns:local="*" xmlns:utils="utils.*">

	<utils:Fxg id="fxg" source="icon.fxg"
			   xLocation="100" yLocation="100" />

</s:Application>

I am using an FXG code from Adobe’s tutorials:

      <s:Group x="0" y="0">
          <s:Rect x="0.5" y="0.5" width="100" height="30">
            <s:fill>
              <s:LinearGradient x="0.5" y="15.5" scaleX="100" rotation="-0">
                <s:GradientEntry color="#ffffff" ratio="0"/>
                <s:GradientEntry ratio="1"/>
              </s:LinearGradient>
            </s:fill>
            <s:stroke>
              <s:SolidColorStroke
                color="#0000ff"
                caps="none"
                weight="1"
                joints="miter"
                miterLimit="4"/>
            </s:stroke>
          </s:Rect>
      </s:Group>

Result:

screen-shot-2010-06-17-at-82558-am

FXG code increases your swf container's size and tax your CPU

I am a big fan of FXG but I want to point out a caveat in regards to using FXG code in your Flash/Flex applications. FXG code increases your SWF container size and tax your CPU, so you should take that into account when deciding if it’s better to load images on runtime, embed assets or use FXG code.

In one of the applications that I am developing I took out only one FXG class and was able to reduce the size of my application from 1.9MB bytes to 1.6MB, see below:

With the FXG class:

screen-shot-2010-06-16-at-15903-pm

Without the FXG class:

screen-shot-2010-06-16-at-15801-pm

Now take a look at the profiler when using an application that is using the FXG code and without. It peaked from
1476K to 8594K.

With the FXG code:
screen-shot-2010-06-16-at-21643-pm

Without FXG code:
screen-shot-2010-06-16-at-21747-pm1

Keep in mind that the FXG code is consuming 7,633 lines of code so it’s an extreme case, but you may have cases where many FXG classes together can make that much of code.

Comparison of optimized FXG vs PNG

Added Wed June 23, 2010:
I want to point out that in the previous example I have used MXML Grahpic (AKA: MXMLG). Take a look at the same vector art exported into FXG from illustrator placed in the application as a .fxg file and imported into the application, see below:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:local="*">

	<local:wtb_avatar />

</s:Application>

The application is compiling the FXG into SWF primitives and is better optimized. Using the FXG file I have increased my memory used from 1483K to 1881K, see below:

screen-shot-2010-06-23-at-110024-am

screen-shot-2010-06-23-at-110108-am

At the same I have increased the size of the SWF container from 71Kb to 228Kb so the FXG code still added as an embedded asset and increased the application’s size significantly.

screen-shot-2010-06-23-at-110152-am

screen-shot-2010-06-23-at-110222-am

For the sake of argument, I have used an png file that looks exactly as the fxg art and the png file came out to be 66Kb.

Now I am embedding the asset into my application:

<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
			   xmlns:s="library://ns.adobe.com/flex/spark"
			   xmlns:mx="library://ns.adobe.com/flex/mx" xmlns:local="*">

	<s:BitmapImage source="@Embed(source='Woman.png')" />

</s:Application>

When I run the application the memory usage climbed to 2423K, which is more than the FXG, which was1881K. The SWF container size was smaller and turned to be 152Kb instead of 228Kb when I used FXG. So the optimized FXG gave me better performance but increased my SWF container. See screenshots below:

screen-shot-2010-06-23-at-122528-pm

screen-shot-2010-06-23-at-123712-pm

The conclusion is that every case need to be examined on a case to case basis. You can than decide what’s the best approach; using FXG, MXMLG, embed images, load images during runtime or load FXG during runtime (as I showed here). It is a matter of what you’re trying to achieve?

You should answer these questions which can help you decide:

  • Do you need to change properties or scale during runtime?
  • How many lines of code is your FXG file?
  • Do you need your graphic to be embedded or loaded at runtime?
  • How important is the quality of your graphic and do you care if the quality of the art will degrade?

Cheers :)