主体程序fms7yue.mxml:
<?xml version="1.0" encoding="utf-8"?>
<mx:WindowedApplication xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" width="820" height="650" borderColor="#000000" creationComplete="setup()" title="Flash Streaming Tool">
<mx:Style source="css/main.css"/>
<mx:Script source="ConnectionManager.as"/>
<mx:Script>
<![CDATA[
import com.zerlot.utils.OsDetection;
import net.hires.utils.Stats;
private var play_video:Video;
private var os:OsDetection;
private function setup():void{
play_video=new Video();
trace(play_video.width);
trace(play_video.height);
trace(this);
trace(this.width);
trace(bgcanvas.x);
trace(bgcanvas.y);
this.bgcanvas.rawChildren.addChildAt(play_video,1);
bgcanvas.width=play_video.width;
bgcanvas.height=play_video.height;
this.play_video.x=0;
this.play_video.y=0;
addChildAt(new Stats(),0);
os=new OsDetection();
this.addEventListener(NativeDragEvent.NATIVE_DRAG_ENTER,onDragEnter,false,0,true);
this.addEventListener(NativeDragEvent.NATIVE_DRAG_DROP,onDragDrop,false,0,true);
//this.invalidateDisplayList();
}
private function onChangehttp():void{
filetype.text="URL";
myrtmpurl.editable=false;
filepathname.text="http://domain/folder/.../*.flv";
myrtmpurl.visible=false;
rtmptitle.text="";
live_cb.visible=false;
live_cb.selected=false;
}
private function onChangertmp():void{
rtmptitle.text="RTMP URL";
filetype.text="Stream";
myrtmpurl.editable=true;
myrtmpurl.visible=true;
filepathname.text="sample";
live_cb.visible=true;
}
]]>
</mx:Script>
<mx:TextInput x="70" y="313" width="265" id="myrtmpurl" text="rtmp://hostname:port/application/instance"/>
<mx:Label x="10" y="316" text="RTMP URL" id="rtmptitle"/>
<mx:Panel x="366" y="13" width="429" height="578" layout="absolute" title="Streaming状态信息" styleName="mypanelTitle">
<mx:TextArea x="10" y="111" width="389" height="383" wordWrap="true" editable="false" enabled="true" id="FMS_Status"/>
<mx:Button x="308" y="502" label="保存到文件" id="saveoutput_btn" click="onSavefile()"/>
<mx:Button x="230" y="502" label="清除" width="70" id="clearstatus_btn" click="clearHistory()"/>
<mx:ProgressBar id="progress_bar" themeColor="#271FC9"
minimum="0" visible="true" maximum="100" label="当前播放进度 %3%%"
direction="right" mode="manual" width="389" labelPlacement="center" x="10" y="5"/>
<mx:ProgressBar id="buffer_bar" themeColor="#F20D7A"
minimum="0" visible="true" maximum="100" label="当前缓冲进度 %3%%"
direction="right" mode="manual" width="389" labelPlacement="center" y="28" x="10"/>
<mx:Label x="43" y="503" text="©2008 www.7yue.com" fontSize="14" color="black"/>
<mx:Image x="10" y="495" source="assets/version/version.png"/>
<mx:Text x="10" y="54" width="389" id="buffer_stats" color="#000000" text=""/>
</mx:Panel>
<mx:ComboBox x="70" y="355" width="79" editable="false" enabled="true" selectedIndex="0" id="media_type" change="changeMedia()">
<mx:ArrayCollection>
<mx:Object label="FLV" data="FLV"/>
<mx:Object label="MP3" data="MP3"/>
<mx:Object label="MP4" data="MP4"/>
<mx:Object label="ID3" data="ID3"/>
</mx:ArrayCollection>
</mx:ComboBox>
<mx:Label x="10" y="358" text="File Type"/>
<mx:Label x="10" y="401" text="Stream" id="filetype"/>
<mx:TextInput x="70" y="399" width="265" id="filepathname" text="sample" change="closeStream()"/>
<mx:Label x="10" y="446" text="Buffer"/>
<mx:Label x="10" y="496" text="Seek"/>
<mx:TextInput x="70" y="444" width="79" id="buffertime" text="2"/>
<mx:TextInput x="70" y="494" width="79" id="seektime"/>
<mx:Button x="179" y="495" label="搜索" id="gotoseek" click="onSeek()"/>
<mx:Button x="10" y="567" label="播放" id="fmsplay_btn" click="playBackVideo()"/>
<mx:Button x="70" y="567" label="停止" id="fmsstop_btn" click="closeNC()"/>
<mx:RadioButton x="10" y="535" label="流" id="video_method_stream" selected="true" color="#FFFFFF" click="onChangertmp()"/>
<mx:RadioButton x="70" y="535" label="渐进下载" id="video_method_progressive" color="#FFFFFF" click="onChangehttp()"/>
<mx:Label x="148" y="497" text="sec"/>
<mx:CheckBox x="180" y="444" label="直播" id="live_cb" color="#FFFFFF"/>
<mx:Canvas x="20" y="40" id="bgcanvas" borderStyle="solid" borderColor="white" borderThickness="1">
<mx:CheckBox x="0" y="0" label="自动调整大小" id="autoSize" color="#FFFFFF" click="onChangeSize()"/>
</mx:Canvas>
</mx:WindowedApplication>
// ActionScript file
import flash.desktop.ClipboardFormats;
import flash.desktop.NativeDragManager;
import flash.events.Event;
import flash.events.NativeDragEvent;
import flash.events.NetStatusEvent;
import flash.filesystem.File;
import flash.net.NetConnection;
import flash.net.NetStream;
private var my_nc:NetConnection;
[Bindable]
private var play_status:String="stop";
private var in_ns:NetStream;
private var checkUp:Object;
private var currentBW:Number;
private var streamObj:Object=new Object();
private var logfile:File;
private var video_duration:Number;
private var video_width:Number;
private var video_height:Number;
private var progress:Object;
public function playBackVideo():void {
// control path for pause/resume
if (play_status == "play") {
fmsplay_btn.label = "继续";
play_status = "pause";
in_ns.pause();
return;
} else if (play_status == "pause") {
// play resume
play_status = "play";
fmsplay_btn.label = "暂停";
in_ns.resume();
return;
}
//trace(rtmpurl);
createConnection();
}
private function createConnection():void{
if(video_method_stream.selected){
trace(video_method_stream.selected);
my_nc=new NetConnection();
my_nc.addEventListener(NetStatusEvent.NET_STATUS,checkConnect,false,0,true);
my_nc.connect(myrtmpurl.text,"streaming");
my_nc.client=new Client(FMS_Status);
checkUp=new Object();
}else if(video_method_progressive.selected){
trace("test progressive");
my_nc=new NetConnection();
my_nc.addEventListener(NetStatusEvent.NET_STATUS,checkConnect,false,0,true);
my_nc.connect(null,"progressive");
my_nc.client=new Client(FMS_Status);
checkUp=new Object();
}
}
private function checkConnect(nse:NetStatusEvent):void{
FMS_Status.text +="正在连接......"+"\n";
FMS_Status.text += "NetConnection onStatus"+"\n";
for (var i:String in nse.info) {
FMS_Status.text +=i+" : "+nse.info[i]+"\n";
}
if (nse.info.code == "NetConnection.Connect.Success") {
createStream(NetConnection(nse.target));
trace(nse.target);
}
}
private function createStream(nc:NetConnection):void{
FMS_Status.text+="NetStream状况: "+"\n";
in_ns=new NetStream(nc);
in_ns.bufferTime=0.5;
play_video.attachNetStream(in_ns);
if (!live_cb.selected) {
in_ns.play(filepathname.text,0);
} else {
in_ns.play(filepathname.text);
}
in_ns.addEventListener(NetStatusEvent.NET_STATUS,showStream);
}
private function showStream(nse:NetStatusEvent):void{
for(var i:String in nse.info){
FMS_Status.text+=i+": "+nse.info[i]+"\n";
}
if(nse.info.code=="NetStream.Play.Stop"){
play_status="stop";
fmsplay_btn.label="播放";
}
if(nse.info.code=="NetStream.Play.Start"){
play_status="play";
fmsplay_btn.label="暂停";
}
streamObj.onMetaData=onMetaDataHandler;
streamObj.onPlayStatus=onPlayStatusHandler;
in_ns.client=streamObj;
progress=new Progressmanager(in_ns,buffer_stats,buffer_bar,video_duration,progress_bar);
}
private function onPlayStatusHandler(info:Object):void{
for(var i:String in info){
FMS_Status.text+=i+":"+info[i]+"\n";
}
if(info.code=="NetStream.Play.Complete"){
play_status="stop";
in_ns.close();
fmsplay_btn.label="播放";
}
}
private function onMetaDataHandler(info:Object):void{
for (var i:String in info) {
FMS_Status.text +=i+": "+info[i]+"\n";
}
video_duration = info.duration;
if (autoSize.selected && info.width && info.height) {
video_width = play_video.width;
video_height = play_video.height;
play_video.width = info.width;
play_video.height = info.height;
} else {
video_width = info.width;
video_height = info.height;
}
switch(info.videocodecid){
case 2:
FMS_Status.text+="本视频是Sorenson H.263格式.\n";
break;
case 3:
FMS_Status.text+="本视频是Screen Video格式,只能支持FP7以上版本.\n";
break;
case 4:
FMS_Status.text+="本视频是On2 VP6格式.\n";
break;
case 5:
FMS_Status.text+="本视频是On2 VP6具备alpha通道格式.\n";
break;
default:
break;
}
// 设定真实的Buffer时间
// 可以动态的设置buffer时间
in_ns.bufferTime=Number(buffertime.text);
}
private function closeStream():void{
if(in_ns!=null){
play_status="stop";
in_ns.close();
progress.setBufferStats(play_status);
fmsplay_btn.label="播放";
}else{
return;
}
}
private function closeNC():void{
play_status="stop";
my_nc.close();
progress.setBufferStats(play_status);
fmsplay_btn.label="播放";
os=null;
}
private function clearHistory():void{
FMS_Status.text="";
}
private function changeMedia():void{
if(media_type.selectedItem.data == "MP3"){
filepathname.text = "mp3:";
}else if (media_type.selectedItem.data == "ID3"){
filepathname.text = "id3:";
}else if (media_type.selectedItem.data=="MP4"){
filepathname.text = "mp4:";
}else{
filepathname.text="";
}
}
private function onSeek():void{
in_ns.seek(Number(seektime.text));
}
private function onSavefile():void{
//logfile=File.applicationStorageDirectory;
//logfile=logfile.resolvePath("logs/");
//trace(logfile.url);
var dir:File =File.applicationDirectory;
//dir.resolvePath("logs");
trace(dir.url);
var docsDir:File = File.documentsDirectory;
try
{
docsDir.browseForSave("Save as:");
docsDir.addEventListener(Event.SELECT, saveData);
}
catch (error:Error)
{
trace("Failed:", error.message)
}
//dir.addEventListener(Event.SELECT, dirSelected);
//logfile.browseForDirectory("Select a directory");
}
private function saveData(event:Event):void{
var newFile:File = event.target as File;
var str:String = FMS_Status.text;
var stream:FileStream = new FileStream();
stream.open(newFile, FileMode.WRITE);
stream.writeUTFBytes(str);
stream.close();
}
private function onChangeSize():void{
if(video_height != 0 && video_width != 0) {
var temp_w:Number = play_video.width;
var temp_h:Number = play_video.height;
play_video.width = video_width;
play_video.height = video_height;
video_width = temp_w;
video_height = temp_h;
}
}
// Drag and Drop feature
private function onDragEnter(nde:NativeDragEvent):void{
var dragFile:Object=nde.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT);
trace(dragFile[0].name);
if (dragFile[0].extension=="flv" || dragFile[0].extension == "mov" || dragFile[0].extension == "mp4" || dragFile[0].extension== "mp3"){
NativeDragManager.acceptDragDrop(this);
}
}
private function onDragDrop(nde:NativeDragEvent):void{
var dragFile:Object=nde.clipboard.getData(ClipboardFormats.FILE_LIST_FORMAT);
trace(dragFile[0].url);
video_method_progressive.selected=true;
onChangehttp();
filepathname.text=dragFile[0].url;
}
Client.as,AS Class文件,带宽检测部分:
//如果FMS服务器端Application.xml的<BandwidthDetection enabled="true">,那么必须客户端包含以下代码
package
{
import mx.controls.TextArea;
internal class Client{
private var currentBW:Number;
private var checkUp:Object;
private var fms_obj:TextArea;
public function Client(fms:TextArea){
fms_obj=fms;
}
public function onBWCheck(... rest):Number {
return 0;
}
public function onBWDone(... rest):void {
if (rest.length>0) {
currentBW=rest[0];
// currentBW=nc.client.sendInfo();
trace("你的带宽速度是: "+currentBW +" Kbps.");
//FMS_Status.text+="你的带宽速度是: "+currentBW +" Kbps.\n"
trace("大约等于 "+Math.round(currentBW/1000)+ " Megabits每秒.");
//FMS_Status.text+="大约等于 "+Math.round(currentBW/1000)+ " Megabits每秒.\n"
fms_obj.text+="当前连接该FMS带宽速度是:"+currentBW +" Kbps.\n";
fms_obj.text+="大约等于 "+Math.round(currentBW/1000)+ " Megabits每秒.\n";
trace(fms_obj.text);
}
}
}
}
Progressmanager.as,AS类文件,计算流长度和表象化:
//动态显示Progresss进度
package
{
import flash.events.TimerEvent;
import flash.net.NetStream;
import flash.utils.Timer;
import mx.controls.ProgressBar;
import mx.controls.Text;
public class Progressmanager
{
private var _in_ns_obj:NetStream;
private var _buff_stats_obj:Text;
private var _play_status_str:String;
private var mytimer:Timer;
private var _buff_bar_obj:ProgressBar;
private var _progress_bar_obj:ProgressBar;
private var _video_duration_num:Number;
public function Progressmanager(ns:NetStream,ti:Text,bb:ProgressBar,vd:Number,pb:ProgressBar)
{
mytimer=new Timer(100,0);
_in_ns_obj=ns;
_buff_stats_obj=ti;
//_play_status_str=ps;
_buff_bar_obj=bb;
_video_duration_num=vd;
_progress_bar_obj=pb;
mytimer.addEventListener(TimerEvent.TIMER,onTimer);
mytimer.start();
}
private function onTimer(te:TimerEvent):void{
//设定播放缓存
var buffer:Number = Math.min(Math.round(_in_ns_obj.bufferLength/_in_ns_obj.bufferTime*100), 100);
if(!isNaN(_in_ns_obj.bufferLength)){
_buff_stats_obj.text= "当前Cache: "+_in_ns_obj.bufferLength+" 填充百分比:"+buffer+"%"+" 实时FPS: "+Math.round(_in_ns_obj.currentFPS*100)/100;
}
_buff_bar_obj.setProgress(buffer,100);
//设定播放进度
var preloadpercentage:Number=_in_ns_obj.time/_video_duration_num*100;
_progress_bar_obj.setProgress(preloadpercentage,100);
if (buffer == 0 && _in_ns_obj.currentFPS==0) {
mytimer.stop();
_progress_bar_obj.setProgress(0,100);
}
}
public function setBufferStats(ps:String):void{
_play_status_str=ps;
mytimer.stop();
if(_play_status_str=="stop"){
_progress_bar_obj.setProgress(0,100);
_buff_stats_obj.text="";
}else{
return;
}
}
}
}
/**
* Hi-ReS! Stats v1.3
*
* Released under MIT license:
* http://www.opensource.org/licenses/mit-license.php
*
* How to use:
*
* addChild( new Stats() );
*
* version log:
*
* 08.07.12 1.3 Mr.doob + Some speed and code optimisations
* 08.02.15 1.2 Mr.doob + Class renamed to Stats (previously FPS)
* 08.01.05 1.2 Mr.doob + Click changes the fps of flash (half up increases,
* half down decreases)
* 08.01.04 1.1 Mr.doob & Theo + Log shape for MEM
* + More room for MS
* + Shameless ripoff of Alternativa's FPS look ;)
* 07.12.13 1.0 Mr.doob + First version
**/
package net.hires.utils
{
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
import flash.system.System;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.utils.getTimer;
import mx.core.UIComponent;
public class Stats extends UIComponent
{
private var graph : BitmapData;
private var fpsText : TextField, msText : TextField, memText : TextField, format : TextFormat;
private var fps :int, timer : int, ms : int, msPrev : int = 0;
private var mem : Number = 0;
public function Stats( ):void
{
graph = new BitmapData( 60, 35, false, 0x000000 );
var gBitmap:Bitmap = new Bitmap( graph );
gBitmap.x= 60;
gBitmap.y = 0;
gBitmap.alpha
addChild(gBitmap);
format = new TextFormat( "_sans", 9 );
fpsText = new TextField();
msText = new TextField();
memText = new TextField();
fpsText.defaultTextFormat = msText.defaultTextFormat = memText.defaultTextFormat = format;
fpsText.width = msText.width = memText.width = 60;
fpsText.selectable = msText.selectable = memText.selectable = false;
fpsText.textColor = 0xFFFF00;
fpsText.text = "fps: ";
addChild(fpsText);
msText.y = 10;
msText.textColor = 0x00FF00;
msText.text = "ms: ";
addChild(msText);
memText.y = 20;
memText.textColor = 0x00FFFF;
memText.text = "mem: ";
addChild(memText);
addEventListener(MouseEvent.CLICK, mouseHandler);
addEventListener(Event.ENTER_FRAME, update);
}
private function mouseHandler( e:MouseEvent ):void
{
if (this.mouseY > this.height * .35)
stage.frameRate --;
else
stage.frameRate ++;
fpsText.text = "fps: " + fps + " / " + stage.frameRate;
}
private function update( e:Event ):void
{
timer = getTimer();
fps++;
if( timer - 1000 > msPrev )
{
msPrev = timer;
mem = Number( ( System.totalMemory / 1048576 ).toFixed(3) );
var fpsGraph : int = Math.min( 50, 50 / stage.frameRate * fps );
var memGraph:Number = Math.min( 50, Math.sqrt( Math.sqrt( mem * 5000 ) ) ) - 2;
graph.scroll( 1, 0 );
graph.fillRect( new Rectangle( 0, 0, 1, graph.height ), 0x000000 );
graph.setPixel( 0, graph.height - fpsGraph, 0xFFFF00);
graph.setPixel( 0, graph.height - ( ( timer - ms ) >> 1 ), 0x00FF00 );
graph.setPixel( 0, graph.height - memGraph, 0x00FFFF);
fpsText.text = "fps: " + fps + " / " + stage.frameRate;
memText.text = "mem: " + mem;
fps = 0;
}
msText.text = "ms: " + (timer - ms);
ms = timer;
}
}
}
package com.zerlot.utils
{
import flash.system.Capabilities;
public class OsDetection
{
public function OsDetection()
{
showCapabilites();
}
private function showCapabilites():void{
trace("对用户的摄像头和麦克风的访问是已经通过管理方式禁止:" + Capabilities.avHardwareDisable);
trace("系统是否支持与辅助功能通信: " + Capabilities.hasAccessibility);
trace("系统是否有音频功能: " + Capabilities.hasAudio);
trace("系统是否可以对音频流进行编码: " + Capabilities.hasAudioEncoder);
trace("系统是否支持嵌入的视频: " + Capabilities.hasEmbeddedVideo);
trace("系统是否具有 MP3 解码器: " + Capabilities.hasMP3);
trace("系统是否支持打印: " + Capabilities.hasPrinting);
trace("系统是否支持开发通过 Flash Media Server 运行的屏幕广播应用程序: " + Capabilities.hasScreenBroadcast);
trace("系统是否支持回放通过 Flash Media Server 运行的屏幕广播应用程序: " + Capabilities.hasScreenPlayback);
trace("系统是否可以播放音频流: " + Capabilities.hasStreamingAudio);
trace("系统是否可以对视频流例如来自 Web 摄像头的视频流进行编码: " + Capabilities.hasVideoEncoder);
trace("系统是特殊的Flash Player调试版本: " + Capabilities.isDebugger);
trace("行内容的系统的语言代码: " + Capabilities.language);
trace("对用户硬盘的读取权限是已经通过管理方式禁止: " + Capabilities.localFileReadDisable);
trace("指定 Flash Player 的运行版本或 AIR 运行时的制造商: " + Capabilities.manufacturer);
trace("当前的操作系统: " + Capabilities.os);
trace("屏幕的像素高宽比: " + Capabilities.pixelAspectRatio);
trace("运行时环境的类型: " + Capabilities.playerType);
trace("屏幕的每英寸点数dpi分辨率: " + Capabilities.screenDPI);
trace("屏幕的最大水平分辨率: " + Capabilities.screenResolutionX);
trace("屏幕的最大垂直分辨率: " + Capabilities.screenResolutionY);
trace("Flash Player 或 Adobe® AIR 平台和版本信息: " + Capabilities.version);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<application xmlns="http://ns.adobe.com/air/application/1.5">
<!-- The application identifier string, unique to this application. Required. -->
<id>fms7yue</id>
<!-- Used as the filename for the application. Required. -->
<filename>fms7yue</filename>
<!-- The name that is displayed in the AIR application installer. Optional. -->
<name>
<text xml:lang="zh_CN">Flash流媒体工具</text>
</name>
<!-- An application version designator (such as "v1", "2.5", or "Alpha 1"). Required. -->
<version>v1.1 r03</version>
<!-- Description, displayed in the AIR application installer. Optional. -->
<description>
<text xml:lang="zh_CN">Flash Streaming Tool v1.1 r03支持Http/RTMP方式流媒体播放及相关检测的工具。安装后请参考安装路径下的README文件</text>
</description>
<!-- Copyright information. Optional -->
<copyright>©2008 www.7yue.com</copyright>
<!-- Settings for the application's initial window. Required. -->
<initialWindow>
<!-- The main SWF or HTML file of the application. Required. -->
<!-- Note: In Flex Builder, the SWF reference is set automatically. -->
<content>fms7yue.swf</content>
<!-- The title of the main window. Optional. -->
<title>Flash Streaming Tool 1.1 r03</title>
<!-- The type of system chrome to use (either "standard" or "none"). Optional. Default standard. -->
<systemChrome>none</systemChrome>
<!-- Whether the window is transparent. Only applicable when systemChrome is false. Optional. Default false. -->
<transparent>true</transparent>
<!-- Whether the window is initially visible. Optional. Default false. -->
<visible>true</visible>
<!-- Whether the user can minimize the window. Optional. Default true. -->
<minimizable>true</minimizable>
<!-- Whether the user can maximize the window. Optional. Default true. -->
<maximizable>false</maximizable>
<!-- Whether the user can resize the window. Optional. Default true. -->
<resizable>false</resizable>
<!-- The window's initial width. Optional.
<width></width>-->
<!-- The window's initial height. Optional.
<height></height>-->
<!-- The window's initial x position. Optional. -->
<!-- <x></x> -->
<!-- The window's initial y position. Optional. -->
<!-- <y></y> -->
<!-- The window's minimum size, specified as a width/height pair, such as "400 200". Optional. -->
<!-- <minSize></minSize> -->
<!-- The window's initial maximum size, specified as a width/height pair, such as "1600 1200". Optional. -->
<!-- <maxSize></maxSize> -->
</initialWindow>
<!-- The subpath of the standard default installation location to use. Optional. -->
<!-- <installFolder></installFolder> -->
<!-- The subpath of the Windows Start/Programs menu to use. Optional. -->
<!-- <programMenuFolder></programMenuFolder> -->
<!-- The icon the system uses for the application. For at least one resolution,
specify the path to a PNG file included in the AIR package. Optional. -->
<icon>
<image16x16>assets/icon_016.png</image16x16>
<image32x32>assets/icon_032.png</image32x32>
<image48x48>assets/icon_048.png</image48x48>
<image128x128>assets/icon_128.png</image128x128>
</icon>
<!-- Whether the application handles the update when a user double-clicks an update version
of the AIR file (true), or the default AIR application installer handles the update (false).
Optional. Default false. -->
<!-- <customUpdateUI></customUpdateUI> -->
<!-- Whether the application can be launched when the user clicks a link in a web browser.
Optional. Default false. -->
<!-- <allowBrowserInvocation></allowBrowserInvocation> -->
<!-- Listing of file types for which the application can register. Optional. -->
<!-- <fileTypes> -->
<!-- Defines one file type. Optional. -->
<!-- <fileType> -->
<!-- The name that the system displays for the registered file type. Required. -->
<!-- <name></name> -->
<!-- The extension to register. Required. -->
<!-- <extension></extension> -->
<!-- The description of the file type. Optional. -->
<!-- <description></description> -->
<!-- The MIME type. Optional. -->
<!-- <contentType></contentType> -->
<!-- The icon to display for the file type. Optional. -->
<!-- <icon>
<image16x16></image16x16>
<image32x32></image32x32>
<image48x48></image48x48>
<image128x128></image128x128>
</icon> -->
<!-- </fileType> -->
<!-- </fileTypes> -->
</application>