エントリー

※はじめに、ことわっておきますが、べつに HTML5 vs Flash という話ではありませんので、あしからず。そんな穏やかじゃない話は、したくはないのです。

「ウェブブラウザ上で動画を再生できる技術の主なものをひと通り復習してみましょう」ってのがコンセプト。

『HTML5が大勝利で、Flashはオワコンで、ファイナルアンサー!』などと言いたい方は、回れ右して、ご自分の巣に、もんでやす(=「お帰りください」という意味の方言)。
 『HTML5のvideoタグ?なにそれ?』って方や、『FlashのStageVideoってなんぞそれ?』って方や、『動画のHTML上への色んな貼っつけ方法を一通り見たいです!』って方はもちろんのこと、ぶっちゃけ『HTML5もFlashもおまいらみんなが自由に好きな方使えばいいじゃん』って方も、ぜひ「続きを読む」から、ひととおりご覧ください。

 

【※このエントリーは、後日、ちゃんと参考資料とかデータを整理して、比較してもらいやすいように、整形する予定です。また、記事の内容についても、後日しっかりと推敲する予定です。 現時点では、このエントリーは「メモ書き」程度とご認識ください※】

 

動画をウェブブラウザ上で再生する方法

【問題】

さて、あなたの手元に公開したい動画ファイル(この動画ファイルのファイル形式は、あなたが思い浮かべたものなら何でも構いません)があります。
 ここであなたなら、どんな方法で、動画をHTMLファイル上に貼っつけますか?(ただし、動画共有サイトは使わないものとします。)

 

 

【答案(例)】

もしかすると、根っからの Classic Macintosh 使いの方は、 QuickTime (.mov) ファイル<Object> または <Embed> タグを使って、QuickTimeプラグインで再生、という方法を(信じがたいですが、現在でも)実行しちゃうかもしれません。
 そして同様に、根っこからの Windows 9x/me/2k 使いの方は Windows Media Video (.wmv) ファイル<Object> または <Embed> タグを使って、WindowsMediaPlayerプラグインで再生、という方法を(いまでも一部サイトでこういった方法が見られるから怖いけど)実行しちゃうかもしれません。
 新しい物好きな方は、 WebM on2-VP8 (.webm) ファイルOgg Theora (.ogg) ファイルH.264/MPEG-4 AVC (.mp4) ファイル の3種類を大変ですが用意して、 HTML5<Video> タグを使って、ネイティブに再生、という方法を実行するかもしれません。
 ある程度のデベロッパの方なら、自分の習得している技術を使って、ウェブブラウザ上で動画を再生しちゃうかもしれません(例: Flash, Flex, Silverlight, Java Applet, etc...)。

 

・・・と、まぁ、色〜〜んな方法があるわけです。

動画プレイヤーのプラグインさんや、Silverlightたん、Javaたんも居る中で、「HTML5くん VS Flashくん」の議論をしちゃうと、はみられた子がかわいそうなのです。

なので、ここでは、私が思いついた方法のうち、主なものをできるだけ多く載っけてみて、比較してみるのです。
 こんにちではやや古くて見かけなくなった子だったり、短所ばかりな子も出てくるかもしれませんが、どうかイジメないでやってください。

とりあえず私は、主にこんなのを思いつきました: (※後述にて、実際に試したものについては、太字で表示してます)

  • ObjectまたはEmbedタグに直接動画ファイルを貼っつけて、ユーザのマシンにインスコされている動画プレイヤーのプラグインで再生してもらう方法(例:wmvを貼りつけてWindowsMediaPlayerのプラグイン呼び出しmovを貼り付けてQuickTimePlayerのプラグイン呼び出し、rmを貼り付けてRealPlayerのプラグイン呼び出し、など) (要 動画形式に対応する動画再生プレイヤーのブラウザプラグイン)。
  • Javaで動画再生するプログラム組んで、そしてAppletタグを使ってJava Appletを貼り付けちゃう方法 (要 Java Runtime Plug-in)。
  • FlexやFlash、ActionScriptで動画再生するプログラム組んで、そしてObjectタグを使ってSWFを貼り付けちゃう方法 (要 Flash Player Plug-in)
  • .net framework の WPF で動画再生するプログラム組んで、そしてSilverlight使って貼り付けちゃう方法 (要 Silverlight Plug-in)
  • JavaFXで動画再生するプログラム組んで、そしてObjectタグを使ってJavaFXを貼り付けちゃう方法 (要 Java Runtime Plug-in)
  • プラグインで動画を再生する方法は、ここまでで挙げたもの以外にもいろいろ思いついたけど、ほんとにオワコンなものやマイナーなものが多いので割愛。
  • HTML5のVideoタグ使って、ネイティブに動画を再生させちゃう方法 (要 おニューでナウい、ウェブブラウザ)

 

んじゃ、実際に試してみたものを、詳しく見て行きますよ!

 

 

・・・と、その前に。

* 用意した動画ファイルについて

試す前に、まずは、貼り付けるための・再生するための「動画」ファイルがないと、元も子もありません。

というわけで、KS-PROUCT の kakeru さんが 配布されている「初音ミクの消失PV完全版のソース(.aep)ファイル」を使用させてもらいました。

miku_syoshitsu.aep

その配布されているソースファイルの形式は .aep (Afetr Effects CS4 Project) なので、After Effetcs CS5 (64bit) を起動して、編集を開始しますた。

使わせてもらったソースは、タイトル部分の15秒(450フレーム)のコンポジットのソースです。

Logo Composite

具体的に行った編集は、umi.aviの色変更エフェクトをすこしいじったのと、タイトルの文字を変更したのみです。

海の色変更エフェクト

このタイトル部分のコンポジットビデオだけをレンダリングして、以下の7種類の動画形式にエンコードしました。なお、ビデオのみ書き出し、オーディオは書き出ししていません。

Video Formats

  • (.f4v) Flash Video, H.264 / MPEG-4 AVC, level-5.1, VBR 1-pass
  • (.flv) Flash Video, On2 VP6, CBR 1-pass
  • (.mov) Apple QuickTime Video, H.264 / MPEG-4 AVC, level-2.1, VBR 2-pass
  • (.mp4) MPEG-4 Video, H.264 / MPEG-4 AVC, level-5.1, VBR 1-pass
  • (.ogv) Ogg Theora Video, Theora (based on On2 VP3)
  • (.webm) Google WebM Video, On2 VP8
  • (.wmv) Windows Media Video, Windows Media Video 9 Advanced Profile, quority-100%

 

 

* 実際に試してみた

動画ファイルも(面倒だったけど)いろんな種類を用意できたところで、さっそく、HTMLファイル中に動画を貼っつけるいろんな方法を試していくよ!

 

1.1. Using <Object> Element & Invoke Apple QuickTime Plug-in

さんぷるぺーじ (※要 QuickTimePlayer)

『リンゴからかよ!?』、というツッコミはさて置いて、非常に昔ながらの方法ですね、これ。

どんな方法かというと、.movファイルをHTMLソースコード中に直接<object>タグまたは<embed>タグで貼りつけて、ユーザ(閲覧者)の端末環境に入っているであろうApple QuickTime Plug-inで動画再生する、という方法です。

Appleが言っているQuickTimeの普及率を考えると、ほぼ間違いなく再生されるのではないでしょうか?まず、Mac使いの人なら、間違いなく再生されますし。 (※実際のQuickTimeの普及率は半分くらいらしいですが、リンゴ教団の信者に消されちゃうので、大きな声で言ってはいけません!)
 ん?『MS WindowsにQuickTime入れてる人が少ない』って?
  ― そのツッコミに対し宗教団体Apple教団から用意された答えは、『Win(DOS/V互換機)を窓から捨てて、Macを買えば、幸せになれると思うよ』です、たぶん。
 UNIX/LinuxのGUIユーザには、QuickTime Playerとかどうでもいい話ですか、そうですか(UNIX/Linuxでは、X Window SystemのKDEやGnomeなどに標準で付いてくる動画プレイヤーのWebブラウザプラグインで、QuickTimeファイルもフツーに再生できちゃうのだ)。

  • プラグイン普及率
  • HTMLソース

QuickTime Player Web Browser Plug-in: 59.32% (Jan '2011)

html index.html

	<object width="512" height="302" classid="clsid:02BF25D5-8C17-4B23-BC80-D3488ABDDC6B" codebase="http://www.apple.com/qtactivex/qtplugin.cab">
		<param name="src" value="http://chsmea.net/~mioproject/sample_video/takoyaki.mov">
		<param name="autoplay" value="true">
		<param name="controller" value="true">
		<param name="loop" value="true">
		<embed src="http://chsmea.net/~mioproject/sample_video/takoyaki.mov" width="512" height="302" loop="true" autoplay="true" controller="true" pluginspage="http://www.apple.com/quicktime/download/">
		</embed>
	</object> 

 

 

1.2. Using <Object> Element & Invoke Windows Media Player Plug-in

さんぷるぺーじ (※要 WindowsMediaPlayer)

『窓のほうが後に紹介されるのかよ!?』、というツッコミはさて置いて、これも非常に昔ながらの方法ですね。

どんな方法かというと、.wavファイルをHTMLソースコード中に直接<object>タグまたは<embed>タグで貼りつけて、ユーザ(閲覧者)の端末環境に入っているであろうWindows Media Player Plug-inで動画再生する、という方法です。

Microsoftが言っているWindowsの普及率を考えると、ほぼ間違いなく再生されるのではないでしょうか?まず、Windows使いの人なら、間違いなく再生されますし。 (※最近のWindowsの普及率は、リンゴやLinuxにシェアを奪われて失速気味なので、MSはそろそろ、Win以外のOSでのSilverlightの普及率を必死になって上げないとマズいと思うよ!)
 ん?『Windows Media Playerのウェブブラウザプラグインなんか、入れたくない!』って?
  ― そのツッコミに対し、私も賛成です。・・・でも、Win上の MS Internet Explorer は、最初からこのプラグインがONになってるよ、残念でした。
 UNIX/LinuxのGUIユーザには、WindowsMediaPlayerとかどうでもいい話ですか、そうですか(UNIX/Linuxでは、X Window SystemのKDEやGnomeなどに標準で付いてくる動画プレイヤーのWebブラウザプラグインで、WindowsMediaファイルもフツーに再生できちゃうのだ)。

  • プラグイン普及率
  • HTMLソース

Windows Media Player Web Browser Plug-in: 65.47% (Jan '2011)

html index.html

	<object id="player" width="512" height="288" classid="clsid:6BF52A52-394A-11d3-B153-00C04F79FAA6">
		<param name="autoStart" value="true">
		<param name="URL" value="http://chsmea.net/~mioproject/sample_video/takoyaki.wmv">
		<embed name="WMP" type="application/x-mplayer2" pluginspage="http://www.microsoft.com/Windows/MediaPlayer/" src="http://chsmea.net/~mioproject/sample_video/takoyaki.wmv" width="512" height="288" autostart="1" showcontrols="1"></embed>
	</object>

 

 

1.3. Using <Object> Element & Invoke Flash Player 9.0+ Plug-in & Play the Video with Flex 3.5 mx:VideoDisplay Component that Using Video Class

さんぷるぺーじ (※要 FlashPlayer9.0 or Flash Player Lite 4.0以上)

『Flashはオワコン!』、というツッコミはさて置いて、これもやや古い方法ですね。

どんな方法かというと、.swfファイルをHTMLソースコード中に<object>タグまたは<embed>タグで貼りつけて、ユーザ(閲覧者)の端末環境に入っているであろうFlash Player Plug-inを呼んで、そのAdobe(/Macromedia)Flexプログラムの中で.flvファイルの動画再生の制御を行う、という方法です。

うん、完全にFlex/Flashデベロッパ用。でも、FlashとかFlexが全然わからなくても、動画共有サイトとかにうpしてから、「ブログパーツを埋め込む」とか「この動画をウェブページに貼り付ける」、などとすると、自然的にこの技術を使っていることになります。おそらくですが、リンゴのトップのお方が「Flashは大っきらい」って言っている矛先は、この方法、だと思います。だって、この方法、ビデオ再生に、GPUアクセラレーションも全くされず、CPUだけで全部処理しちゃう(Windowsだと半分くらいのCPUリソースを食うし、MacOSXだとAppleがMacOSでのAPI実装を公開していなかった(Closedにしていた)ためにAdobeがしっかり作り込めずに100%のCPUリソースを食ってしまっていた)もんで、とても重いんです。また、それだけでなく、電力も沢山食うのです。でもでも、Flash Player 9.0+ の非常に高い普及率もあって、この方法が世界中で最も利用されているような気がします。なお、Flash Player 9.0 が出てくる(flash.media.Videoクラスが実装される)までは、どうやってFlashで動画を再生していたのかというと、FlashのSWFファイルに直接動画を埋め込むとかMacromediaが実装していたStreamクラスを使ったりとか、まぁいろいろ方法はありましたが、前者の方法だとMacromedia Flash MX/2004/8という値段が高いオーサリングソフトが必要だったり、後者の方法だとかなりActionScript 2.0のプログラミングスキルが必要だったり、という感じでした。

ほとんどの環境でほぼ間違いなく再生できるこの方法なのですが、最近のiPhoneやiPad、MacBookなどからコンピュータライフを始めた方は、もしかするとFlashを見たこともないかもしれませんね(青い箱しか表示されない)・・・。 (リンゴのトップのお方が『Apple製品には、Flashの"F"すらも一切表示させない!』という内容の発言を言い残してますから)

  • プラグイン普及率
  • HTMLソース
  • プログラムソース

Flash Player 9.0+ Web Browser Plug-in: 99.6% (Dec '2010)

html index.html

	<object data="./VideoPlayer.swf" type="application/x-shockwave-flash" id="flex" width="511" height="288">
		<param name="movie" value="./VideoPlayer.swf" />
	</object>

mxml VideoPlayer.mxml

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
				layout="absolute"
				width="511"
				height="288">
	
	<mx:Script>
		<![CDATA[
			
			import mx.events.VideoEvent;
			
			protected function video_rewindHandler(e:VideoEvent):void{
				if (this.video.playing == false) this.video.play();
			}
			
		]]>
	</mx:Script>
	
	<mx:VideoDisplay id="video"
					 x="0"
					 y="0"
					 width="511"
					 height="288"
					 source="http://chsmea.net/~mioproject/sample_video/takoyaki.flv"
					 autoPlay="true"
					 autoRewind="true"
					 rewind="video_rewindHandler(event)" />
</mx:Application>

 

 

1.4. Using <Object> Element & Invoke Flash Player 10.1+ Plug-in & Play the Video with Flex 4.1 s:VideoDisplay Component that Using Video Class (Enable H.264 Decode GPU Acceleration)

さんぷるぺーじ (※要 (Win|Linux) FlashPlayer 10.1 以上, (MacOSX) Flash Player 10.1.82.76 以上)

『だからFlashはオワコンだってばよ!』、というツッコミはさて置いて、これはやや新しい方法です。現在だと、ニコ動に使われてます。

どんな方法かというと、.swfファイルをHTMLソースコード中に<object>タグまたは<embed>タグで貼りつけて、ユーザ(閲覧者)の端末環境に入っているであろうFlash Player Plug-inを呼んで、そのAdobe(/Macromedia)Flexプログラムの中で.f4vファイル(H.264ビデオ)の動画再生の制御を行い、Flash Player 10.1の新機能で、H.264ビデオの動画再生時にH.264のデコード処理にCPUではなくGPUを使ってもらう、という方法です。技術的に言うと、これもさっきのと同じでflash.media.Videoクラスを使うんだけど、動画ファイルが.f4vってのがミソです。

うん、これも、完全にFlex/Flashデベロッパ用。でも、FlashとかFlexが全然わからなくても、これに関しても動画共有サイトとかにうpしてから、「ブログパーツを埋め込む」とか「この動画をウェブページに貼り付ける」、などとすると、自然的にこの技術を使っていることになってることが、チラチラ見られます、ニコ動とかね(※でも、YouTubeやニコ動以外の多くの動画共有サイトでは1.3.で紹介した従来の方法のままだったりします)。

ただ、Flash Player 10.1 (MacOSX では 10.1.82.76) 以上でないと、H.264のデコード処理にGPUが使われないので、注意。 (※なぜ、Mac版のみリリースが大幅に遅れ、AdobeがAppleに言われたい放題になっていたのかというと、リンゴのトップがFlashをせんどと叩いておきながら、リンゴがMacでのGPUアクセラレーションのAPIを一切公開しなかったから。なお、MacOSXでのGPUを使ってH.264動画のデコードをローレベルで扱うためのフレームワーク(技術文書)を公開したのは、Appleのジョブズが、『AppleではiOSやMacOSXなどは完全にオープンでやってて、一方Flashは完全にクローズだ』と公開書簡で言い張る直前のことで、正直なところ公開時期が汚い!、というか、実際にはFlashのSWFの仕様やFlexフレームワークは全部オープンソースなんだが。。。 ・・・おっと、これ以上言うと、Apple信者から消されてしまうので、このくらいにしておこう。)

  • プラグイン普及率
  • HTMLソース
  • プログラムソース

Flash Player 10.1+ Web Browser Plug-in: 85.3% (Dec '2010)

html index.html

	<object data="./VideoPlayer.swf" type="application/x-shockwave-flash" id="flex" width="511" height="288">
		<param name="movie" value="./VideoPlayer.swf" />
	</object>

mxml VideoPlayer.mxml

<?xml version="1.0" encoding="utf-8"?>
<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"
			   width="511"
			   height="288">
	<s:VideoDisplay id="video"
					x="0"
					y="0"
					width="511"
					height="288"
					source="http://chsmea.net/~mioproject/sample_video/takoyaki.f4v"
					autoPlay="true"
					loop="true"
					autoRewind="true" />
</s:Application>

 

 

1.5. Using <Object> Element & Invoke Flash Player 10.2+ Plug-in & Play the Video with Stage Video (Enable H.264 Decode GPU Acceleration & Enable H.264 Display GPU Acceleration)

さんぷるぺーじ (※要 FlashPlayer 10.2 以上)

『Flashうぜーーー!』、というツッコミはさて置いて、これは非常に新しい方法です。現在だと、YouTubeのHD動画再生に使われてます。

どんな方法かというと、.swfファイルをHTMLソースコード中に<object>タグまたは<embed>タグで貼りつけて、ユーザ(閲覧者)の端末環境に入っているであろうFlash Player Plug-inを呼んで、そのActionScript 3.0 プログラムの中で.f4vファイル(H.264ビデオ)の動画再生の制御を行い、Flash Player 10.2の新機能であるStage Videoで、H.264ビデオの動画再生時にH.264のデコード処理と合成処理にCPUではなくGPUを使ってもらう、という方法です。技術的に言うと、flash.media.StageVideoクラスってのを使います。

StageVideo

おっと、flash.media.StageVideoクラスはFlexじゃ使えないんだ。完全にActionScript3.0 100%じゃなきゃいけない、ってことで、完全にFlashデベロッパ専用。

でも、ActionScript3.0とかStageVideoとかが全然わからなくても、これに関しても動画共有サイトとかにうpしてから、「ブログパーツを埋め込む」とか「この動画をウェブページに貼り付ける」、などとすると、自然的にこの技術を使っていることになってることが、チラチラ見られます、YouTubeとかね(※でも、YouTube以外の多くの動画共有サイトでは1.3.か1.4.で紹介した従来の方法または比較的新しい方法のままだったりします)。

ただ、Flash Player 10.2 以上でないと、H.264のデコード処理&合成処理にGPUが使われないので、注意。

ほとんどの処理がGPUで行われるので、CPUの消費リソースは超高画質でHDサイズの動画であっても10%くらいしか消費しません。デコードもGPUで行われ、レンダリングもGPUで行われるので、ぬるぬる再生されます。またモバイル端末では、大幅なバッテリの節約になります。

なお、HTML5のVideoタグによるネイティブなH.264のHD動画再生よりも、Flash Player 10.2のStageVideoによるH.264のHD動画再生の方がぬるぬる再生される上にCPU消費率もダントツに少ないという実験結果も出ています。さらには、多くのAndroidなモバイル端末でも、バッテリのもちが、HTML5のVideoタグよりもFlashPlayer10.2のStageVideoの方が良い結果になったようです。・・・でも、もちろん例外はあるぞ(一部のAndroid端末だと、逆に電力消費量が著しく上がったパターンもある)。

  • プラグイン普及率
  • HTMLソース
  • プログラムソース

Flash Player 10.2+ Web Browser Plug-in: 62.9% (Jul '2011)

html index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
	<title>Displaying Video with Flash Stage Video</title>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
	<style type="text/css" media="screen"> 
		#flashContent { display:none; }
	</style>
	<script type="text/javascript" src="swfobject.js"></script>
	<script type="text/javascript">
		// For version detection, set to min. required Flash Player version, or 0 (or 0.0.0), for no version detection. 
		var swfVersionStr = "10.2.0";
		// To use express install, set to playerProductInstall.swf, otherwise the empty string. 
		var xiSwfUrlStr = "playerProductInstall.swf";
		var flashvars = {};
		var params = {};
		params.quality = "high";
		params.bgcolor = "#ffffff";
		params.wmode = "direct";
		params.allowscriptaccess = "sameDomain";
		params.allowfullscreen = "true";
		var attributes = {};
		attributes.id = "VideoPlayer";
		attributes.name = "VideoPlayer";
		attributes.align = "left";
		swfobject.embedSWF(
			"VideoPlayer.swf", "flashContent", 
			"511", "288", 
			swfVersionStr, xiSwfUrlStr, 
			flashvars, params, attributes);
		// JavaScript enabled so display the flashContent div in case it is not replaced with a swf object.
		swfobject.createCSS("#flashContent", "display:block;text-align:left;");
	</script>
</head>
<body>
	<h1>[Flash Player 10.2+] Stage Video - H.264 Decode & Display GPU Acceleration (f4v H.264/MPEG4-AVC)</h1>
	<div id="flashContent">
		<p>動画を再生するためには、Adobe Flash Player 10.2.0 以上が必要です。</p>
		<script type="text/javascript"> 
			var pageHost = ((document.location.protocol == "https:") ? "https://" : "http://"); 
			document.write("<a href='http://www.adobe.com/go/getflashplayer'><img src='" 
			                + pageHost + "www.adobe.com/images/shared/download_buttons/get_flash_player.gif' alt='Get Adobe Flash player' /></a>" ); 
		</script> 
	</div>
	<noscript>
		<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="511" height="288" id="VideoPlayer">
			<param name="movie" value="VideoPlayer.swf" />
			<param name="quality" value="high" />
			<param name="wmode" value="direct" />
			<param name="bgcolor" value="#ffffff" />
			<param name="allowScriptAccess" value="sameDomain" />
			<param name="allowFullScreen" value="true" />
			<!--[if !IE]>-->
			<object type="application/x-shockwave-flash" data="VideoPlayer.swf" width="511" height="288">
				<param name="quality" value="high" />
				<param name="wmode" value="direct" />
				<param name="bgcolor" value="#ffffff" />
				<param name="allowScriptAccess" value="sameDomain" />
				<param name="allowFullScreen" value="true" />
			<!--<![endif]-->
			<!--[if gte IE 6]>-->
				<p>動画を再生するためには、Adobe Flash Player 10.2.0 以上が必要です。</p>
			<!--<![endif]-->
				<a href="http://www.adobe.com/go/getflashplayer">
					<img src="http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif" alt="Get Adobe Flash Player" />
				</a>
			<!--[if !IE]>-->
			</object>
			<!--<![endif]-->
		</object>
	</noscript>
	<p style="clear:both;"> </p>
	<p>Source: f4v</p>
</body>
</html>

js swfobject.js

/*!	SWFObject v2.2 <http://code.google.com/p/swfobject/> 
	is released under the MIT License <http://www.opensource.org/licenses/mit-license.php> 
*/

var swfobject = function() {
	
	var UNDEF = "undefined",
		OBJECT = "object",
		SHOCKWAVE_FLASH = "Shockwave Flash",
		SHOCKWAVE_FLASH_AX = "ShockwaveFlash.ShockwaveFlash",
		FLASH_MIME_TYPE = "application/x-shockwave-flash",
		EXPRESS_INSTALL_ID = "SWFObjectExprInst",
		ON_READY_STATE_CHANGE = "onreadystatechange",
		
		win = window,
		doc = document,
		nav = navigator,
		
		plugin = false,
		domLoadFnArr = [main],
		regObjArr = [],
		objIdArr = [],
		listenersArr = [],
		storedAltContent,
		storedAltContentId,
		storedCallbackFn,
		storedCallbackObj,
		isDomLoaded = false,
		isExpressInstallActive = false,
		dynamicStylesheet,
		dynamicStylesheetMedia,
		autoHideShow = true,
	
	/* Centralized function for browser feature detection
		- User agent string detection is only used when no good alternative is possible
		- Is executed directly for optimal performance
	*/	
	ua = function() {
		var w3cdom = typeof doc.getElementById != UNDEF && typeof doc.getElementsByTagName != UNDEF && typeof doc.createElement != UNDEF,
			u = nav.userAgent.toLowerCase(),
			p = nav.platform.toLowerCase(),
			windows = p ? /win/.test(p) : /win/.test(u),
			mac = p ? /mac/.test(p) : /mac/.test(u),
			webkit = /webkit/.test(u) ? parseFloat(u.replace(/^.*webkit\/(\d+(\.\d+)?).*$/, "$1")) : false, // returns either the webkit version or false if not webkit
			ie = !+"\v1", // feature detection based on Andrea Giammarchi's solution: http://webreflection.blogspot.com/2009/01/32-bytes-to-know-if-your-browser-is-ie.html
			playerVersion = [0,0,0],
			d = null;
		if (typeof nav.plugins != UNDEF && typeof nav.plugins[SHOCKWAVE_FLASH] == OBJECT) {
			d = nav.plugins[SHOCKWAVE_FLASH].description;
			if (d && !(typeof nav.mimeTypes != UNDEF && nav.mimeTypes[FLASH_MIME_TYPE] && !nav.mimeTypes[FLASH_MIME_TYPE].enabledPlugin)) { // navigator.mimeTypes["application/x-shockwave-flash"].enabledPlugin indicates whether plug-ins are enabled or disabled in Safari 3+
				plugin = true;
				ie = false; // cascaded feature detection for Internet Explorer
				d = d.replace(/^.*\s+(\S+\s+\S+$)/, "$1");
				playerVersion[0] = parseInt(d.replace(/^(.*)\..*$/, "$1"), 10);
				playerVersion[1] = parseInt(d.replace(/^.*\.(.*)\s.*$/, "$1"), 10);
				playerVersion[2] = /[a-zA-Z]/.test(d) ? parseInt(d.replace(/^.*[a-zA-Z]+(.*)$/, "$1"), 10) : 0;
			}
		}
		else if (typeof win.ActiveXObject != UNDEF) {
			try {
				var a = new ActiveXObject(SHOCKWAVE_FLASH_AX);
				if (a) { // a will return null when ActiveX is disabled
					d = a.GetVariable("$version");
					if (d) {
						ie = true; // cascaded feature detection for Internet Explorer
						d = d.split(" ")[1].split(",");
						playerVersion = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
					}
				}
			}
			catch(e) {}
		}
		return { w3:w3cdom, pv:playerVersion, wk:webkit, ie:ie, win:windows, mac:mac };
	}(),
	
	/* Cross-browser onDomLoad
		- Will fire an event as soon as the DOM of a web page is loaded
		- Internet Explorer workaround based on Diego Perini's solution: http://javascript.nwbox.com/IEContentLoaded/
		- Regular onload serves as fallback
	*/ 
	onDomLoad = function() {
		if (!ua.w3) { return; }
		if ((typeof doc.readyState != UNDEF && doc.readyState == "complete") || (typeof doc.readyState == UNDEF && (doc.getElementsByTagName("body")[0] || doc.body))) { // function is fired after onload, e.g. when script is inserted dynamically 
			callDomLoadFunctions();
		}
		if (!isDomLoaded) {
			if (typeof doc.addEventListener != UNDEF) {
				doc.addEventListener("DOMContentLoaded", callDomLoadFunctions, false);
			}		
			if (ua.ie && ua.win) {
				doc.attachEvent(ON_READY_STATE_CHANGE, function() {
					if (doc.readyState == "complete") {
						doc.detachEvent(ON_READY_STATE_CHANGE, arguments.callee);
						callDomLoadFunctions();
					}
				});
				if (win == top) { // if not inside an iframe
					(function(){
						if (isDomLoaded) { return; }
						try {
							doc.documentElement.doScroll("left");
						}
						catch(e) {
							setTimeout(arguments.callee, 0);
							return;
						}
						callDomLoadFunctions();
					})();
				}
			}
			if (ua.wk) {
				(function(){
					if (isDomLoaded) { return; }
					if (!/loaded|complete/.test(doc.readyState)) {
						setTimeout(arguments.callee, 0);
						return;
					}
					callDomLoadFunctions();
				})();
			}
			addLoadEvent(callDomLoadFunctions);
		}
	}();
	
	function callDomLoadFunctions() {
		if (isDomLoaded) { return; }
		try { // test if we can really add/remove elements to/from the DOM; we don't want to fire it too early
			var t = doc.getElementsByTagName("body")[0].appendChild(createElement("span"));
			t.parentNode.removeChild(t);
		}
		catch (e) { return; }
		isDomLoaded = true;
		var dl = domLoadFnArr.length;
		for (var i = 0; i < dl; i++) {
			domLoadFnArr[i]();
		}
	}
	
	function addDomLoadEvent(fn) {
		if (isDomLoaded) {
			fn();
		}
		else { 
			domLoadFnArr[domLoadFnArr.length] = fn; // Array.push() is only available in IE5.5+
		}
	}
	
	/* Cross-browser onload
		- Based on James Edwards' solution: http://brothercake.com/site/resources/scripts/onload/
		- Will fire an event as soon as a web page including all of its assets are loaded 
	 */
	function addLoadEvent(fn) {
		if (typeof win.addEventListener != UNDEF) {
			win.addEventListener("load", fn, false);
		}
		else if (typeof doc.addEventListener != UNDEF) {
			doc.addEventListener("load", fn, false);
		}
		else if (typeof win.attachEvent != UNDEF) {
			addListener(win, "onload", fn);
		}
		else if (typeof win.onload == "function") {
			var fnOld = win.onload;
			win.onload = function() {
				fnOld();
				fn();
			};
		}
		else {
			win.onload = fn;
		}
	}
	
	/* Main function
		- Will preferably execute onDomLoad, otherwise onload (as a fallback)
	*/
	function main() { 
		if (plugin) {
			testPlayerVersion();
		}
		else {
			matchVersions();
		}
	}
	
	/* Detect the Flash Player version for non-Internet Explorer browsers
		- Detecting the plug-in version via the object element is more precise than using the plugins collection item's description:
		  a. Both release and build numbers can be detected
		  b. Avoid wrong descriptions by corrupt installers provided by Adobe
		  c. Avoid wrong descriptions by multiple Flash Player entries in the plugin Array, caused by incorrect browser imports
		- Disadvantage of this method is that it depends on the availability of the DOM, while the plugins collection is immediately available
	*/
	function testPlayerVersion() {
		var b = doc.getElementsByTagName("body")[0];
		var o = createElement(OBJECT);
		o.setAttribute("type", FLASH_MIME_TYPE);
		var t = b.appendChild(o);
		if (t) {
			var counter = 0;
			(function(){
				if (typeof t.GetVariable != UNDEF) {
					var d = t.GetVariable("$version");
					if (d) {
						d = d.split(" ")[1].split(",");
						ua.pv = [parseInt(d[0], 10), parseInt(d[1], 10), parseInt(d[2], 10)];
					}
				}
				else if (counter < 10) {
					counter++;
					setTimeout(arguments.callee, 10);
					return;
				}
				b.removeChild(o);
				t = null;
				matchVersions();
			})();
		}
		else {
			matchVersions();
		}
	}
	
	/* Perform Flash Player and SWF version matching; static publishing only
	*/
	function matchVersions() {
		var rl = regObjArr.length;
		if (rl > 0) {
			for (var i = 0; i < rl; i++) { // for each registered object element
				var id = regObjArr[i].id;
				var cb = regObjArr[i].callbackFn;
				var cbObj = {success:false, id:id};
				if (ua.pv[0] > 0) {
					var obj = getElementById(id);
					if (obj) {
						if (hasPlayerVersion(regObjArr[i].swfVersion) && !(ua.wk && ua.wk < 312)) { // Flash Player version >= published SWF version: Houston, we have a match!
							setVisibility(id, true);
							if (cb) {
								cbObj.success = true;
								cbObj.ref = getObjectById(id);
								cb(cbObj);
							}
						}
						else if (regObjArr[i].expressInstall && canExpressInstall()) { // show the Adobe Express Install dialog if set by the web page author and if supported
							var att = {};
							att.data = regObjArr[i].expressInstall;
							att.width = obj.getAttribute("width") || "0";
							att.height = obj.getAttribute("height") || "0";
							if (obj.getAttribute("class")) { att.styleclass = obj.getAttribute("class"); }
							if (obj.getAttribute("align")) { att.align = obj.getAttribute("align"); }
							// parse HTML object param element's name-value pairs
							var par = {};
							var p = obj.getElementsByTagName("param");
							var pl = p.length;
							for (var j = 0; j < pl; j++) {
								if (p[j].getAttribute("name").toLowerCase() != "movie") {
									par[p[j].getAttribute("name")] = p[j].getAttribute("value");
								}
							}
							showExpressInstall(att, par, id, cb);
						}
						else { // Flash Player and SWF version mismatch or an older Webkit engine that ignores the HTML object element's nested param elements: display alternative content instead of SWF
							displayAltContent(obj);
							if (cb) { cb(cbObj); }
						}
					}
				}
				else {	// if no Flash Player is installed or the fp version cannot be detected we let the HTML object element do its job (either show a SWF or alternative content)
					setVisibility(id, true);
					if (cb) {
						var o = getObjectById(id); // test whether there is an HTML object element or not
						if (o && typeof o.SetVariable != UNDEF) { 
							cbObj.success = true;
							cbObj.ref = o;
						}
						cb(cbObj);
					}
				}
			}
		}
	}
	
	function getObjectById(objectIdStr) {
		var r = null;
		var o = getElementById(objectIdStr);
		if (o && o.nodeName == "OBJECT") {
			if (typeof o.SetVariable != UNDEF) {
				r = o;
			}
			else {
				var n = o.getElementsByTagName(OBJECT)[0];
				if (n) {
					r = n;
				}
			}
		}
		return r;
	}
	
	/* Requirements for Adobe Express Install
		- only one instance can be active at a time
		- fp 6.0.65 or higher
		- Win/Mac OS only
		- no Webkit engines older than version 312
	*/
	function canExpressInstall() {
		return !isExpressInstallActive && hasPlayerVersion("6.0.65") && (ua.win || ua.mac) && !(ua.wk && ua.wk < 312);
	}
	
	/* Show the Adobe Express Install dialog
		- Reference: http://www.adobe.com/cfusion/knowledgebase/index.cfm?id=6a253b75
	*/
	function showExpressInstall(att, par, replaceElemIdStr, callbackFn) {
		isExpressInstallActive = true;
		storedCallbackFn = callbackFn || null;
		storedCallbackObj = {success:false, id:replaceElemIdStr};
		var obj = getElementById(replaceElemIdStr);
		if (obj) {
			if (obj.nodeName == "OBJECT") { // static publishing
				storedAltContent = abstractAltContent(obj);
				storedAltContentId = null;
			}
			else { // dynamic publishing
				storedAltContent = obj;
				storedAltContentId = replaceElemIdStr;
			}
			att.id = EXPRESS_INSTALL_ID;
			if (typeof att.width == UNDEF || (!/%$/.test(att.width) && parseInt(att.width, 10) < 310)) { att.width = "310"; }
			if (typeof att.height == UNDEF || (!/%$/.test(att.height) && parseInt(att.height, 10) < 137)) { att.height = "137"; }
			doc.title = doc.title.slice(0, 47) + " - Flash Player Installation";
			var pt = ua.ie && ua.win ? "ActiveX" : "PlugIn",
				fv = "MMredirectURL=" + encodeURI(window.location).toString().replace(/&/g,"%26") + "&MMplayerType=" + pt + "&MMdoctitle=" + doc.title;
			if (typeof par.flashvars != UNDEF) {
				par.flashvars += "&" + fv;
			}
			else {
				par.flashvars = fv;
			}
			// IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it,
			// because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
			if (ua.ie && ua.win && obj.readyState != 4) {
				var newObj = createElement("div");
				replaceElemIdStr += "SWFObjectNew";
				newObj.setAttribute("id", replaceElemIdStr);
				obj.parentNode.insertBefore(newObj, obj); // insert placeholder div that will be replaced by the object element that loads expressinstall.swf
				obj.style.display = "none";
				(function(){
					if (obj.readyState == 4) {
						obj.parentNode.removeChild(obj);
					}
					else {
						setTimeout(arguments.callee, 10);
					}
				})();
			}
			createSWF(att, par, replaceElemIdStr);
		}
	}
	
	/* Functions to abstract and display alternative content
	*/
	function displayAltContent(obj) {
		if (ua.ie && ua.win && obj.readyState != 4) {
			// IE only: when a SWF is loading (AND: not available in cache) wait for the readyState of the object element to become 4 before removing it,
			// because you cannot properly cancel a loading SWF file without breaking browser load references, also obj.onreadystatechange doesn't work
			var el = createElement("div");
			obj.parentNode.insertBefore(el, obj); // insert placeholder div that will be replaced by the alternative content
			el.parentNode.replaceChild(abstractAltContent(obj), el);
			obj.style.display = "none";
			(function(){
				if (obj.readyState == 4) {
					obj.parentNode.removeChild(obj);
				}
				else {
					setTimeout(arguments.callee, 10);
				}
			})();
		}
		else {
			obj.parentNode.replaceChild(abstractAltContent(obj), obj);
		}
	} 

	function abstractAltContent(obj) {
		var ac = createElement("div");
		if (ua.win && ua.ie) {
			ac.innerHTML = obj.innerHTML;
		}
		else {
			var nestedObj = obj.getElementsByTagName(OBJECT)[0];
			if (nestedObj) {
				var c = nestedObj.childNodes;
				if (c) {
					var cl = c.length;
					for (var i = 0; i < cl; i++) {
						if (!(c[i].nodeType == 1 && c[i].nodeName == "PARAM") && !(c[i].nodeType == 8)) {
							ac.appendChild(c[i].cloneNode(true));
						}
					}
				}
			}
		}
		return ac;
	}
	
	/* Cross-browser dynamic SWF creation
	*/
	function createSWF(attObj, parObj, id) {
		var r, el = getElementById(id);
		if (ua.wk && ua.wk < 312) { return r; }
		if (el) {
			if (typeof attObj.id == UNDEF) { // if no 'id' is defined for the object element, it will inherit the 'id' from the alternative content
				attObj.id = id;
			}
			if (ua.ie && ua.win) { // Internet Explorer + the HTML object element + W3C DOM methods do not combine: fall back to outerHTML
				var att = "";
				for (var i in attObj) {
					if (attObj[i] != Object.prototype[i]) { // filter out prototype additions from other potential libraries
						if (i.toLowerCase() == "data") {
							parObj.movie = attObj[i];
						}
						else if (i.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
							att += ' class="' + attObj[i] + '"';
						}
						else if (i.toLowerCase() != "classid") {
							att += ' ' + i + '="' + attObj[i] + '"';
						}
					}
				}
				var par = "";
				for (var j in parObj) {
					if (parObj[j] != Object.prototype[j]) { // filter out prototype additions from other potential libraries
						par += '<param name="' + j + '" value="' + parObj[j] + '" />';
					}
				}
				el.outerHTML = '<object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"' + att + '>' + par + '</object>';
				objIdArr[objIdArr.length] = attObj.id; // stored to fix object 'leaks' on unload (dynamic publishing only)
				r = getElementById(attObj.id);	
			}
			else { // well-behaving browsers
				var o = createElement(OBJECT);
				o.setAttribute("type", FLASH_MIME_TYPE);
				for (var m in attObj) {
					if (attObj[m] != Object.prototype[m]) { // filter out prototype additions from other potential libraries
						if (m.toLowerCase() == "styleclass") { // 'class' is an ECMA4 reserved keyword
							o.setAttribute("class", attObj[m]);
						}
						else if (m.toLowerCase() != "classid") { // filter out IE specific attribute
							o.setAttribute(m, attObj[m]);
						}
					}
				}
				for (var n in parObj) {
					if (parObj[n] != Object.prototype[n] && n.toLowerCase() != "movie") { // filter out prototype additions from other potential libraries and IE specific param element
						createObjParam(o, n, parObj[n]);
					}
				}
				el.parentNode.replaceChild(o, el);
				r = o;
			}
		}
		return r;
	}
	
	function createObjParam(el, pName, pValue) {
		var p = createElement("param");
		p.setAttribute("name", pName);	
		p.setAttribute("value", pValue);
		el.appendChild(p);
	}
	
	/* Cross-browser SWF removal
		- Especially needed to safely and completely remove a SWF in Internet Explorer
	*/
	function removeSWF(id) {
		var obj = getElementById(id);
		if (obj && obj.nodeName == "OBJECT") {
			if (ua.ie && ua.win) {
				obj.style.display = "none";
				(function(){
					if (obj.readyState == 4) {
						removeObjectInIE(id);
					}
					else {
						setTimeout(arguments.callee, 10);
					}
				})();
			}
			else {
				obj.parentNode.removeChild(obj);
			}
		}
	}
	
	function removeObjectInIE(id) {
		var obj = getElementById(id);
		if (obj) {
			for (var i in obj) {
				if (typeof obj[i] == "function") {
					obj[i] = null;
				}
			}
			obj.parentNode.removeChild(obj);
		}
	}
	
	/* Functions to optimize JavaScript compression
	*/
	function getElementById(id) {
		var el = null;
		try {
			el = doc.getElementById(id);
		}
		catch (e) {}
		return el;
	}
	
	function createElement(el) {
		return doc.createElement(el);
	}
	
	/* Updated attachEvent function for Internet Explorer
		- Stores attachEvent information in an Array, so on unload the detachEvent functions can be called to avoid memory leaks
	*/	
	function addListener(target, eventType, fn) {
		target.attachEvent(eventType, fn);
		listenersArr[listenersArr.length] = [target, eventType, fn];
	}
	
	/* Flash Player and SWF content version matching
	*/
	function hasPlayerVersion(rv) {
		var pv = ua.pv, v = rv.split(".");
		v[0] = parseInt(v[0], 10);
		v[1] = parseInt(v[1], 10) || 0; // supports short notation, e.g. "9" instead of "9.0.0"
		v[2] = parseInt(v[2], 10) || 0;
		return (pv[0] > v[0] || (pv[0] == v[0] && pv[1] > v[1]) || (pv[0] == v[0] && pv[1] == v[1] && pv[2] >= v[2])) ? true : false;
	}
	
	/* Cross-browser dynamic CSS creation
		- Based on Bobby van der Sluis' solution: http://www.bobbyvandersluis.com/articles/dynamicCSS.php
	*/	
	function createCSS(sel, decl, media, newStyle) {
		if (ua.ie && ua.mac) { return; }
		var h = doc.getElementsByTagName("head")[0];
		if (!h) { return; } // to also support badly authored HTML pages that lack a head element
		var m = (media && typeof media == "string") ? media : "screen";
		if (newStyle) {
			dynamicStylesheet = null;
			dynamicStylesheetMedia = null;
		}
		if (!dynamicStylesheet || dynamicStylesheetMedia != m) { 
			// create dynamic stylesheet + get a global reference to it
			var s = createElement("style");
			s.setAttribute("type", "text/css");
			s.setAttribute("media", m);
			dynamicStylesheet = h.appendChild(s);
			if (ua.ie && ua.win && typeof doc.styleSheets != UNDEF && doc.styleSheets.length > 0) {
				dynamicStylesheet = doc.styleSheets[doc.styleSheets.length - 1];
			}
			dynamicStylesheetMedia = m;
		}
		// add style rule
		if (ua.ie && ua.win) {
			if (dynamicStylesheet && typeof dynamicStylesheet.addRule == OBJECT) {
				dynamicStylesheet.addRule(sel, decl);
			}
		}
		else {
			if (dynamicStylesheet && typeof doc.createTextNode != UNDEF) {
				dynamicStylesheet.appendChild(doc.createTextNode(sel + " {" + decl + "}"));
			}
		}
	}
	
	function setVisibility(id, isVisible) {
		if (!autoHideShow) { return; }
		var v = isVisible ? "visible" : "hidden";
		if (isDomLoaded && getElementById(id)) {
			getElementById(id).style.visibility = v;
		}
		else {
			createCSS("#" + id, "visibility:" + v);
		}
	}

	/* Filter to avoid XSS attacks
	*/
	function urlEncodeIfNecessary(s) {
		var regex = /[\\\"<>\.;]/;
		var hasBadChars = regex.exec(s) != null;
		return hasBadChars && typeof encodeURIComponent != UNDEF ? encodeURIComponent(s) : s;
	}
	
	/* Release memory to avoid memory leaks caused by closures, fix hanging audio/video threads and force open sockets/NetConnections to disconnect (Internet Explorer only)
	*/
	var cleanup = function() {
		if (ua.ie && ua.win) {
			window.attachEvent("onunload", function() {
				// remove listeners to avoid memory leaks
				var ll = listenersArr.length;
				for (var i = 0; i < ll; i++) {
					listenersArr[i][0].detachEvent(listenersArr[i][1], listenersArr[i][2]);
				}
				// cleanup dynamically embedded objects to fix audio/video threads and force open sockets and NetConnections to disconnect
				var il = objIdArr.length;
				for (var j = 0; j < il; j++) {
					removeSWF(objIdArr[j]);
				}
				// cleanup library's main closures to avoid memory leaks
				for (var k in ua) {
					ua[k] = null;
				}
				ua = null;
				for (var l in swfobject) {
					swfobject[l] = null;
				}
				swfobject = null;
			});
		}
	}();
	
	return {
		/* Public API
			- Reference: http://code.google.com/p/swfobject/wiki/documentation
		*/ 
		registerObject: function(objectIdStr, swfVersionStr, xiSwfUrlStr, callbackFn) {
			if (ua.w3 && objectIdStr && swfVersionStr) {
				var regObj = {};
				regObj.id = objectIdStr;
				regObj.swfVersion = swfVersionStr;
				regObj.expressInstall = xiSwfUrlStr;
				regObj.callbackFn = callbackFn;
				regObjArr[regObjArr.length] = regObj;
				setVisibility(objectIdStr, false);
			}
			else if (callbackFn) {
				callbackFn({success:false, id:objectIdStr});
			}
		},
		
		getObjectById: function(objectIdStr) {
			if (ua.w3) {
				return getObjectById(objectIdStr);
			}
		},
		
		embedSWF: function(swfUrlStr, replaceElemIdStr, widthStr, heightStr, swfVersionStr, xiSwfUrlStr, flashvarsObj, parObj, attObj, callbackFn) {
			var callbackObj = {success:false, id:replaceElemIdStr};
			if (ua.w3 && !(ua.wk && ua.wk < 312) && swfUrlStr && replaceElemIdStr && widthStr && heightStr && swfVersionStr) {
				setVisibility(replaceElemIdStr, false);
				addDomLoadEvent(function() {
					widthStr += ""; // auto-convert to string
					heightStr += "";
					var att = {};
					if (attObj && typeof attObj === OBJECT) {
						for (var i in attObj) { // copy object to avoid the use of references, because web authors often reuse attObj for multiple SWFs
							att[i] = attObj[i];
						}
					}
					att.data = swfUrlStr;
					att.width = widthStr;
					att.height = heightStr;
					var par = {}; 
					if (parObj && typeof parObj === OBJECT) {
						for (var j in parObj) { // copy object to avoid the use of references, because web authors often reuse parObj for multiple SWFs
							par[j] = parObj[j];
						}
					}
					if (flashvarsObj && typeof flashvarsObj === OBJECT) {
						for (var k in flashvarsObj) { // copy object to avoid the use of references, because web authors often reuse flashvarsObj for multiple SWFs
							if (typeof par.flashvars != UNDEF) {
								par.flashvars += "&" + k + "=" + flashvarsObj[k];
							}
							else {
								par.flashvars = k + "=" + flashvarsObj[k];
							}
						}
					}
					if (hasPlayerVersion(swfVersionStr)) { // create SWF
						var obj = createSWF(att, par, replaceElemIdStr);
						if (att.id == replaceElemIdStr) {
							setVisibility(replaceElemIdStr, true);
						}
						callbackObj.success = true;
						callbackObj.ref = obj;
					}
					else if (xiSwfUrlStr && canExpressInstall()) { // show Adobe Express Install
						att.data = xiSwfUrlStr;
						showExpressInstall(att, par, replaceElemIdStr, callbackFn);
						return;
					}
					else { // show alternative content
						setVisibility(replaceElemIdStr, true);
					}
					if (callbackFn) { callbackFn(callbackObj); }
				});
			}
			else if (callbackFn) { callbackFn(callbackObj);	}
		},
		
		switchOffAutoHideShow: function() {
			autoHideShow = false;
		},
		
		ua: ua,
		
		getFlashPlayerVersion: function() {
			return { major:ua.pv[0], minor:ua.pv[1], release:ua.pv[2] };
		},
		
		hasFlashPlayerVersion: hasPlayerVersion,
		
		createSWF: function(attObj, parObj, replaceElemIdStr) {
			if (ua.w3) {
				return createSWF(attObj, parObj, replaceElemIdStr);
			}
			else {
				return undefined;
			}
		},
		
		showExpressInstall: function(att, par, replaceElemIdStr, callbackFn) {
			if (ua.w3 && canExpressInstall()) {
				showExpressInstall(att, par, replaceElemIdStr, callbackFn);
			}
		},
		
		removeSWF: function(objElemIdStr) {
			if (ua.w3) {
				removeSWF(objElemIdStr);
			}
		},
		
		createCSS: function(selStr, declStr, mediaStr, newStyleBoolean) {
			if (ua.w3) {
				createCSS(selStr, declStr, mediaStr, newStyleBoolean);
			}
		},
		
		addDomLoadEvent: addDomLoadEvent,
		
		addLoadEvent: addLoadEvent,
		
		getQueryParamValue: function(param) {
			var q = doc.location.search || doc.location.hash;
			if (q) {
				if (/\?/.test(q)) { q = q.split("?")[1]; } // strip question mark
				if (param == null) {
					return urlEncodeIfNecessary(q);
				}
				var pairs = q.split("&");
				for (var i = 0; i < pairs.length; i++) {
					if (pairs[i].substring(0, pairs[i].indexOf("=")) == param) {
						return urlEncodeIfNecessary(pairs[i].substring((pairs[i].indexOf("=") + 1)));
					}
				}
			}
			return "";
		},
		
		// For internal usage only
		expressInstallCallback: function() {
			if (isExpressInstallActive) {
				var obj = getElementById(EXPRESS_INSTALL_ID);
				if (obj && storedAltContent) {
					obj.parentNode.replaceChild(storedAltContent, obj);
					if (storedAltContentId) {
						setVisibility(storedAltContentId, true);
						if (ua.ie && ua.win) { storedAltContent.style.display = "block"; }
					}
					if (storedCallbackFn) { storedCallbackFn(storedCallbackObj); }
				}
				isExpressInstallActive = false;
			} 
		}
	};
}();

as VideoPlayer.as

package {
	
	import flash.display.Sprite;
	import flash.events.StageVideoAvailabilityEvent;
	import flash.events.TimerEvent;
	import flash.geom.Rectangle;
	import flash.media.StageVideo;
	import flash.media.StageVideoAvailability;
	import flash.net.NetConnection;
	import flash.net.NetStream;
	import flash.utils.Timer;
	
	[SWF (frameRate="60", width="511", height="288")]
	
	/**
	 * Displaying Video with Flash - Stage Video (H.264 Decode & Display GPU Acceleration)
	 * 
	 * @author mio
	 */
	public class VideoPlayer extends Sprite {
		
		/**
		 * Video source URL path.
		 */
		private const URL : String = "http://chsmea.net/~mioproject/sample_video/takoyaki.f4v";
		
		/**
		 * Video width (px).
		 */
		private const WIDTH : uint = 511;
		
		/**
		 * Video height (px).
		 */
		private const HEIGHT : uint = 288;
		
		/**
		 * Video duration (ms).
		 */
		private const DURATION : Number = 15000;
		
		/**
		 * Net connection.
		 */
		private var nc : NetConnection;
		
		/**
		 * Net stream.
		 */
		private var ns : NetStream;
		
		/**
		 * Stage Video.
		 * 
		 * @langversion 3.0
		 * @playerversion Flash 10.2
		 * @playerversion AIR 2.5
		 */
		private var sv : StageVideo;
		
		/**
		 * Constructor.
		 */
		public function VideoPlayer() {
			
			this.nc = new NetConnection();
			this.nc.connect(null);
			
			this.ns = new NetStream(this.nc);
			this.ns.client = {};
			
			this.stage.addEventListener(StageVideoAvailabilityEvent.STAGE_VIDEO_AVAILABILITY, stageVideoAvailabilityHandler);
			
		}
		
		/**
		 * Check Stage Video availablility and Play net stream via Stage Video.
		 */
		protected function stageVideoAvailabilityHandler(event : StageVideoAvailabilityEvent) : void {
			if (event.availability == StageVideoAvailability.AVAILABLE) {
				this.sv = this.stage.stageVideos[0];
				this.sv.attachNetStream(this.ns);
				this.sv.viewPort = new Rectangle(0, 0, WIDTH, HEIGHT);
				this.ns.play(URL);
				this.setAutoReWindAndPlay(DURATION);
			}
		}
		
		/**
		 * Set auto-rewind and auto-play.
		 * 
		 * @param duration video duration (ms).
		 * @param loop repeat count. default value is <code>0</code> (infinity loop).
		 */
		private function setAutoReWindAndPlay(duration : Number, loop : uint = 0) : void {
			var time : Timer = new Timer(duration + 500, loop);
			time.addEventListener(TimerEvent.TIMER, 
				function (event : TimerEvent) : void {
					ns.play(URL); // no this.
				}
			);
			time.start();
		}
		
	}
}

 

 

1.6. Using <Object> Element & Invoke Silverlight Plug-in & Play the Video with JM Silverlight Player

さんぷるぺーじ (※要 Silverlight Runtime)

藍澤光

『藍澤光たん、(*´Д`)<かわゆす』、というツッコミには、私も同意です。

これはどんな方法かというと、Silverlight ObjectをHTMLソースコード中にJavaScriptを用いて貼りつけて、ユーザ(閲覧者)の端末環境に入っているであろうSilverlight Runtimeを呼んで、そのWPF (XAML + VB.NET/VC++/C#/F#/JS,etc...) プログラムの中で.wmvファイルの動画再生の制御を行うっていうものです。

なお、Silverlight 3.0からは、WindowsMediaVideo以外にも、H.264の動画ファイルも再生可能となってます。しかし、現在最新版であるSilverlight 4.0では、動画再生にハードウェアアクセラレーションはサポートされていない。もちろん、HD画質の動画なんかをSilverlightで再生なんぞしようとしたら、CPUが暖房の代わりになってくれるでしょう。なお、Silverlight 5.0で動画再生時のGPUアクセラレーションがサポートされるみたい。あと、Silverlight 5.0では、Win32APIも叩けるようになってしまう予定だとか。これはすごいことになりそうだ(主に、ウイルスやブラクラ的な意味で)。

MS大っきらいな私が、Silverlightでの動画再生検証のために、わざわざMS Visual Studioを起動するわけがありません、うん。ということで、今回はサードパーティー製のライブラリを使って、サクっと用意しました。

また、MS Expression Encoder 4 Free/Proを使えば、H.264(mp4)ビデオまたはVC-1(wmv9)ビデオを再生するためのSilverlight動画プレイヤーを、動画のエンコード時にサクっと作成してくれます。これは、とても便利な機能だと思いました。

気になる、Silverlightでの動画再生なのですが、最新版のSilverlightで、ようやく2年前のFlashと同じくらいのパフォーマンスのようです。でも、Silverlight 5.0の登場で、最新版のFlashと比肩するものと思われます。

しかしいまのところ、MS Silverlightテクノロジは、Macromedia/Adobe Flexテクノロジの発展をなぞっているだけのようにしか見えません。まぁ、Silverlight 5.0は、Windows Phone 7の基盤にも使われるみたいなので、そろそろ独自的な発展をしてくれそうですね。

  • プラグイン普及率
  • HTMLソース
  • プログラムソース

Silverlight Web Browser Plug-in: 62.80% (Jan '2011)

html index.html

	<div name="mediaspace" id="mediaspace"></div>
	<script type='text/javascript' src="silverlight.js"></script>
	<script type='text/javascript' src="wmvplayer.js"></script>
	<script type="text/javascript">
		var cnt = document.getElementById("mediaspace");
		var src = 'wmvplayer.xaml';
		var cfg = {
			file: 'takoyaki.wmv',
			height: '288',
			width: '512',
			shownavigation: 'false',
			autostart: 'true',
			repeat: 'true'
		};
		var ply = new jeroenwijering.Player(cnt,src,cfg);
	</script>

js silverlight.js

///////////////////////////////////////////////////////////////////////////////
//
//  Silverlight.js   			version 2.0.30523.6
//
//  Copyright (c) Microsoft Corporation. All rights reserved.
//
///////////////////////////////////////////////////////////////////////////////

if (!window.Silverlight)
{
    window.Silverlight = { };
}

//////////////////////////////////////////////////////////////////
//
// _silverlightCount:
//
// Counter of globalized event handlers
//
//////////////////////////////////////////////////////////////////
Silverlight._silverlightCount = 0;

//////////////////////////////////////////////////////////////////
//
// fwlinkRoot:
//
// Prefix for fwlink URL's
//
//////////////////////////////////////////////////////////////////
Silverlight.fwlinkRoot='http://go2.microsoft.com/fwlink/?LinkID=';

//////////////////////////////////////////////////////////////////
//  
// onGetSilverlight:
//
// Called by Silverlight.GetSilverlight to notify the page that a user
// has requested the Silverlight installer
//
//////////////////////////////////////////////////////////////////
Silverlight.onGetSilverlight = null;

//////////////////////////////////////////////////////////////////
//
// onSilverlightInstalled:
//
// Called by Silverlight.WaitForInstallCompletion when the page detects
// that Silverlight has been installed. The event handler is not called
// in upgrade scenarios.
//
//////////////////////////////////////////////////////////////////
Silverlight.onSilverlightInstalled = function () {window.location.reload(false);};

//////////////////////////////////////////////////////////////////
//
// isInstalled:
//
// Checks to see if the correct version is installed
//
//////////////////////////////////////////////////////////////////
Silverlight.isInstalled = function(version)
{
    var isVersionSupported=false;
    var container = null;
    
    try 
    {
        var control = null;
        
        try
        {
            control = new ActiveXObject('AgControl.AgControl');
            if ( version == null )
            {
                isVersionSupported = true;
            }
            else if ( control.IsVersionSupported(version) )
            {
                isVersionSupported = true;
            }
            control = null;
        }
        catch (e)
        {
            var plugin = navigator.plugins["Silverlight Plug-In"] ;
            if ( plugin )
            {
                if ( version === null )
                {
                    isVersionSupported = true;
                }
                else
                {
                    var actualVer = plugin.description;
                    if ( actualVer === "1.0.30226.2")
                        actualVer = "2.0.30226.2";
                    var actualVerArray =actualVer.split(".");
                    while ( actualVerArray.length > 3)
                    {
                        actualVerArray.pop();
                    }
                    while ( actualVerArray.length < 4)
                    {
                        actualVerArray.push(0);
                    }
                    var reqVerArray = version.split(".");
                    while ( reqVerArray.length > 4)
                    {
                        reqVerArray.pop();
                    }
                    
                    var requiredVersionPart ;
                    var actualVersionPart
                    var index = 0;
                    
                    
                    do
                    {
                        requiredVersionPart = parseInt(reqVerArray[index]);
                        actualVersionPart = parseInt(actualVerArray[index]);
                        index++;
                    }
                    while (index < reqVerArray.length && requiredVersionPart === actualVersionPart);
                    
                    if ( requiredVersionPart <= actualVersionPart && !isNaN(requiredVersionPart) )
                    {
                        isVersionSupported = true;
                    }
                }
            }
        }
    }
    catch (e) 
    {
        isVersionSupported = false;
    }
    if (container) 
    {
        document.body.removeChild(container);
    }
    
    return isVersionSupported;
}
//////////////////////////////////////////////////////////////////
//
// WaitForInstallCompletion:
//
// Occasionally checks for Silverlight installation status. If it
// detects that Silverlight has been installed then it calls
// Silverlight.onSilverlightInstalled();. This is only supported
// if Silverlight was not previously installed on this computer.
//
//////////////////////////////////////////////////////////////////
Silverlight.WaitForInstallCompletion = function()
{
    if ( ! Silverlight.isBrowserRestartRequired && Silverlight.onSilverlightInstalled )
    {
        try
        {
            navigator.plugins.refresh();
        }
        catch(e)
        {
        }
        if ( Silverlight.isInstalled(null) )
        {
            Silverlight.onSilverlightInstalled();
        }
        else
        {
              setTimeout(Silverlight.WaitForInstallCompletion, 3000);
        }    
    }
}
//////////////////////////////////////////////////////////////////
//
// __startup:
//
// Performs startup tasks
//////////////////////////////////////////////////////////////////
Silverlight.__startup = function()
{
    Silverlight.isBrowserRestartRequired = Silverlight.isInstalled(null);
    if ( !Silverlight.isBrowserRestartRequired)
    {
        Silverlight.WaitForInstallCompletion();
    }
    if (window.removeEventListener) { 
       window.removeEventListener('load', Silverlight.__startup , false);
    }
    else { 
        window.detachEvent('onload', Silverlight.__startup );
    }
}

if (window.addEventListener) 
{
    window.addEventListener('load', Silverlight.__startup , false);
}
else 
{
    window.attachEvent('onload', Silverlight.__startup );
}

///////////////////////////////////////////////////////////////////////////////
// createObject:
//
// Inserts a Silverlight <object> tag or installation experience into the HTML
// DOM based on the current installed state of Silverlight. 
//
/////////////////////////////////////////////////////////////////////////////////

Silverlight.createObject = function(source, parentElement, id, properties, events, initParams, userContext)
{
    var slPluginHelper = new Object();
    var slProperties = properties;
    var slEvents = events;
    
    slPluginHelper.version = slProperties.version;
    slProperties.source = source;    
    slPluginHelper.alt = slProperties.alt;
    
    //rename properties to their tag property names. For bacwards compatibility
    //with Silverlight.js version 1.0
    if ( initParams )
        slProperties.initParams = initParams;
    if ( slProperties.isWindowless && !slProperties.windowless)
        slProperties.windowless = slProperties.isWindowless;
    if ( slProperties.framerate && !slProperties.maxFramerate)
        slProperties.maxFramerate = slProperties.framerate;
    if ( id && !slProperties.id)
        slProperties.id = id;
    
    // remove elements which are not to be added to the instantiation tag
    delete slProperties.ignoreBrowserVer;
    delete slProperties.inplaceInstallPrompt;
    delete slProperties.version;
    delete slProperties.isWindowless;
    delete slProperties.framerate;
    delete slProperties.data;
    delete slProperties.src;
    delete slProperties.alt;


    // detect that the correct version of Silverlight is installed, else display install

    if (Silverlight.isInstalled(slPluginHelper.version))
    {
        //move unknown events to the slProperties array
        for (var name in slEvents)
        {
            if ( slEvents[name])
            {
                if ( name == "onLoad" && typeof slEvents[name] == "function" && slEvents[name].length != 1 )
                {
                    var onLoadHandler = slEvents[name];
                    slEvents[name]=function (sender){ return onLoadHandler(document.getElementById(id), userContext, sender)};
                }
                var handlerName = Silverlight.__getHandlerName(slEvents[name]);
                if ( handlerName != null )
                {
                    slProperties[name] = handlerName;
                    slEvents[name] = null;
                }
                else
                {
                    throw "typeof events."+name+" must be 'function' or 'string'";
                }
            }
        }
        slPluginHTML = Silverlight.buildHTML(slProperties);
    }
    //The control could not be instantiated. Show the installation prompt
    else 
    {
        slPluginHTML = Silverlight.buildPromptHTML(slPluginHelper);
    }

    // insert or return the HTML
    if(parentElement)
    {
        parentElement.innerHTML = slPluginHTML;
    }
    else
    {
        return slPluginHTML;
    }

}

///////////////////////////////////////////////////////////////////////////////
//
//  buildHTML:
//
//  create HTML that instantiates the control
//
///////////////////////////////////////////////////////////////////////////////
Silverlight.buildHTML = function( slProperties)
{
    var htmlBuilder = [];

    htmlBuilder.push('<object type=\"application/x-silverlight\" data="data:application/x-silverlight,"');
    if ( slProperties.id != null )
    {
        htmlBuilder.push(' id="' + slProperties.id + '"');
    }
    if ( slProperties.width != null )
    {
        htmlBuilder.push(' width="' + slProperties.width+ '"');
    }
    if ( slProperties.height != null )
    {
        htmlBuilder.push(' height="' + slProperties.height + '"');
    }
    htmlBuilder.push(' >');
    
    delete slProperties.id;
    delete slProperties.width;
    delete slProperties.height;
    
    for (var name in slProperties)
    {
        if (slProperties[name])
        {
            htmlBuilder.push('<param name="'+Silverlight.HtmlAttributeEncode(name)+'" value="'+Silverlight.HtmlAttributeEncode(slProperties[name])+'" />');
        }
    }
    htmlBuilder.push('<\/object>');
    return htmlBuilder.join('');
}



//////////////////////////////////////////////////////////////////
//
// createObjectEx:
//
// takes a single parameter of all createObject 
// parameters enclosed in {}
//
//////////////////////////////////////////////////////////////////

Silverlight.createObjectEx = function(params)
{
    var parameters = params;
    var html = Silverlight.createObject(parameters.source, parameters.parentElement, parameters.id, parameters.properties, parameters.events, parameters.initParams, parameters.context);
    if (parameters.parentElement == null)
    {
        return html;
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////
//
// buildPromptHTML
//
// Builds the HTML to prompt the user to download and install Silverlight
//
///////////////////////////////////////////////////////////////////////////////////////////////
Silverlight.buildPromptHTML = function(slPluginHelper)
{
    var slPluginHTML = "";
    var urlRoot = Silverlight.fwlinkRoot;
    var shortVer = slPluginHelper.version ;
    if ( slPluginHelper.alt )
    {
        slPluginHTML = slPluginHelper.alt;
    }
    else
    {
        if (! shortVer )
        {
            shortVer="";
        }
        slPluginHTML = "<a href='javascript:Silverlight.getSilverlight(\"{1}\");' style='text-decoration: none;'><img src='{2}' alt='Get Microsoft Silverlight' style='border-style: none'/></a>";
        slPluginHTML = slPluginHTML.replace('{1}', shortVer );
        slPluginHTML = slPluginHTML.replace('{2}', urlRoot + '108181');
    }
    
    return slPluginHTML;
}

///////////////////////////////////////////////////////////////////////////////////////////////
//
// getSilverlight:
//
// Navigates the browser to the appropriate Silverlight installer
//
///////////////////////////////////////////////////////////////////////////////////////////////
Silverlight.getSilverlight = function(version)
{
    if (Silverlight.onGetSilverlight )
    {
        Silverlight.onGetSilverlight();
    }
    
    var shortVer = "";
    var reqVerArray = String(version).split(".");
    if (reqVerArray.length > 1)
    {
        var majorNum = parseInt(reqVerArray[0] );
        if ( isNaN(majorNum) || majorNum < 2 )
        {
            shortVer = "1.0";
        }
        else
        {
            shortVer = reqVerArray[0]+'.'+reqVerArray[1];
        }
    }
    
    var verArg = "";
    
    if (shortVer.match(/^\d+\056\d+$/) )
    {
        verArg = "&v="+shortVer;
    }
    
    Silverlight.followFWLink("114576" + verArg);
}


///////////////////////////////////////////////////////////////////////////////////////////////
//
// followFWLink:
//
// Navigates to a url based on fwlinkid
//
///////////////////////////////////////////////////////////////////////////////////////////////
Silverlight.followFWLink = function(linkid)
{
    top.location=Silverlight.fwlinkRoot+String(linkid);
}

///////////////////////////////////////////////////////////////////////////////////////////////
//
// HtmlAttributeEncode:
//
// Encodes special characters in input strings as charcodes
//
///////////////////////////////////////////////////////////////////////////////////////////////
Silverlight.HtmlAttributeEncode = function( strInput )
{
      var c;
      var retVal = '';

    if(strInput == null)
      {
          return null;
    }
      
      for(var cnt = 0; cnt < strInput.length; cnt++)
      {
            c = strInput.charCodeAt(cnt);

            if (( ( c > 96 ) && ( c < 123 ) ) ||
                  ( ( c > 64 ) && ( c < 91 ) ) ||
                  ( ( c > 43 ) && ( c < 58 ) && (c!=47)) ||
                  ( c == 95 ))
            {
                  retVal = retVal + String.fromCharCode(c);
            }
            else
            {
                  retVal = retVal + '&#' + c + ';';
            }
      }
      
      return retVal;
}
///////////////////////////////////////////////////////////////////////////////
//
//  default_error_handler:
//
//  Default error handling function 
//
///////////////////////////////////////////////////////////////////////////////

Silverlight.default_error_handler = function (sender, args)
{
    var iErrorCode;
    var errorType = args.ErrorType;

    iErrorCode = args.ErrorCode;

    var errMsg = "\nSilverlight error message     \n" ;

    errMsg += "ErrorCode: "+ iErrorCode + "\n";


    errMsg += "ErrorType: " + errorType + "       \n";
    errMsg += "Message: " + args.ErrorMessage + "     \n";

    if (errorType == "ParserError")
    {
        errMsg += "XamlFile: " + args.xamlFile + "     \n";
        errMsg += "Line: " + args.lineNumber + "     \n";
        errMsg += "Position: " + args.charPosition + "     \n";
    }
    else if (errorType == "RuntimeError")
    {
        if (args.lineNumber != 0)
        {
            errMsg += "Line: " + args.lineNumber + "     \n";
            errMsg += "Position: " +  args.charPosition + "     \n";
        }
        errMsg += "MethodName: " + args.methodName + "     \n";
    }
    alert (errMsg);
}

///////////////////////////////////////////////////////////////////////////////////////////////
//
// __cleanup:
//
// Releases event handler resources when the page is unloaded
//
///////////////////////////////////////////////////////////////////////////////////////////////
Silverlight.__cleanup = function ()
{
    for (var i = Silverlight._silverlightCount - 1; i >= 0; i--) {
        window['__slEvent' + i] = null;
    }
    Silverlight._silverlightCount = 0;
    if (window.removeEventListener) { 
       window.removeEventListener('unload', Silverlight.__cleanup , false);
    }
    else { 
        window.detachEvent('onunload', Silverlight.__cleanup );
    }
}

///////////////////////////////////////////////////////////////////////////////////////////////
//
// __getHandlerName:
//
// Generates named event handlers for delegates.
//
///////////////////////////////////////////////////////////////////////////////////////////////
Silverlight.__getHandlerName = function (handler)
{
    var handlerName = "";
    if ( typeof handler == "string")
    {
        handlerName = handler;
    }
    else if ( typeof handler == "function" )
    {
        if (Silverlight._silverlightCount == 0)
        {
            if (window.addEventListener) 
            {
                window.addEventListener('onunload', Silverlight.__cleanup , false);
            }
            else 
            {
                window.attachEvent('onunload', Silverlight.__cleanup );
            }
        }
        var count = Silverlight._silverlightCount++;
        handlerName = "__slEvent"+count;
        
        window[handlerName]=handler;
    }
    else
    {
        handlerName = null;
    }
    return handlerName;
}

xaml wmvplayer.xaml

<?xml version="1.0" encoding="utf-8"?>
<!--
JW WMV Player version 1.1, created with M$ Silverlight 1.0.

This file contains all logic for the JW WMV Player. For a functional setup,
the following two files are also needed:
- silverlight.js (for instantiating the silverlight plugin)
- wmvplayer.js (this file contains all the scripting logic)

More info: http://www.jeroenwijering.com/?item=JW_WMV_Player
-->

<Canvas xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="320" Height="260">




	<Canvas x:Name="PlayerDisplay" Width="320" Height="240" Background="#FF000000" Visibility="Collapsed">
		<Image x:Name="PlaceholderImage" Width="320" Height="240" />
		<MediaElement x:Name="VideoWindow" Width="320" Height="240" />
		<Canvas x:Name="PlayIcon" Width="40" Height="40" Canvas.Left="140" Canvas.Top="100">
			<Path x:Name="PlayIconBack" Width="40" Height="40" Fill="#77000000" Data="F1 M4,0 L36,0 C38,0 40,2 40,4 L40,36 C40,38 38,40 36,40 L4,40 C2,40 0,38 0,36 L0,4 C0,2 2,0 4,0 Z"/>
			<Path x:Name="PlayIconFront" Width="18" Height="18" Canvas.Left="12" Canvas.Top="11" Fill="#FFFFFFFF" Data="F1 M0,0 L18,9 L0,18 L0,0 Z"/>
		</Canvas>
    	<Canvas x:Name="MuteIcon" Width="40" Height="40" Canvas.Left="140" Canvas.Top="100" Visibility="Collapsed">
			<Path x:Name="MuteIconBack" Width="40" Height="40" Fill="#77000000" Data="F1 M4,0 L36,0 C38,0 40,2 40,4 L40,36 C40,38 38,40 36,40 L4,40 C2,40 0,38 0,36 L0,4 C0,2 2,0 4,0 Z"/>
			<Path x:Name="MuteIconFront" Width="18" Height="18" Canvas.Left="13" Canvas.Top="11" Fill="#FFFFFFFF" Data="F1 M0,4 L4,4 L4,14 L0,14 L0,4 M6,4 L11,0 L11,18 L6,14 L6,4 M14,8 L18,8 L18,10 L14,10 L14,8 Z"/>
		</Canvas>
		<Canvas x:Name="BufferIcon" Width="32" Height="32" Canvas.Left="148" Canvas.Top="98" Visibility="Collapsed">
	    	<Canvas.RenderTransform>
				<RotateTransform x:Name="BufferRotation" Angle="0" CenterX="16" CenterY="16" />
			</Canvas.RenderTransform>
			<Canvas.Triggers>
				<EventTrigger RoutedEvent="Canvas.Loaded">
					<BeginStoryboard>
						<Storyboard>
							<DoubleAnimationUsingKeyFrames Storyboard.TargetName="BufferRotation" Storyboard.TargetProperty="Angle" Duration="0:0:1.2" RepeatBehavior="Forever">
								<DiscreteDoubleKeyFrame Value="30" KeyTime="0:0:0.1" />
								<DiscreteDoubleKeyFrame Value="60" KeyTime="0:0:0.2" />
								<DiscreteDoubleKeyFrame Value="90" KeyTime="0:0:0.3" />
								<DiscreteDoubleKeyFrame Value="120" KeyTime="0:0:0.4" />
								<DiscreteDoubleKeyFrame Value="150" KeyTime="0:0:0.5" />
								<DiscreteDoubleKeyFrame Value="180" KeyTime="0:0:0.6" />
								<DiscreteDoubleKeyFrame Value="210" KeyTime="0:0:0.7" />
								<DiscreteDoubleKeyFrame Value="240" KeyTime="0:0:0.8" />
								<DiscreteDoubleKeyFrame Value="270" KeyTime="0:0:0.9" />
								<DiscreteDoubleKeyFrame Value="300" KeyTime="0:0:1" />
								<DiscreteDoubleKeyFrame Value="330" KeyTime="0:0:1.1" />
								<DiscreteDoubleKeyFrame Value="360" KeyTime="0:0:1.2" />
							</DoubleAnimationUsingKeyFrames>
						</Storyboard>
					</BeginStoryboard>
				</EventTrigger>
			</Canvas.Triggers> 
			<Path x:Name="BufferPath1" Width="2" Height="8" Canvas.Left="15" Canvas.Top="0" Stretch="Fill" Fill="#FFFFFFFF" Data="F1 M16,0 L16,0 C16.55,0 17,0.45 17,1 L17,7 C17,7.55 16.55,8 16,8 L16,8C 15.45,8 15,7.55 15,7 L15,1 C15,0.45 15.45,0 16,0 Z "/>
			<Path x:Name="BufferPath2" Width="5" Height="7.2" Canvas.Left="7.5" Canvas.Top="2" Stretch="Fill" Fill="#EEFFFFFF" Data="F1 M8,2.14 L8,2.14 C8.48,1.87 9.09,2.03 9.37,2.51 L12.366,7.71 C12.64,8.18 12.48,8.80 12,9.07 L12,9.07 C11.52,9.35 10.91,9.18 10.63,8.71 L7.63,3.51 C7.36,3.03 7.52,2.42 8,2.14 Z "/>
			<Path x:Name="BufferPath3" Width="7.2" Height="5" Canvas.Left="2" Canvas.Top="7.5" Stretch="Fill" Fill="#DDFFFFFF" Data="F1 M2.14,8. L2.14,8 C2.42,7.52 3.03,7.36 3.51,7.63 L8.71,10.63 C9.18,10.91 9.35,11.52 9.07,12 L9.07,12 C8.80,12.48 8.18,12.64 7.71,12.36 L2.51,9.37 C2.03,9.09 1.87,8.48 2.14,8 Z "/>
			<Path x:Name="BufferPath4" Width="8" Height="2" Canvas.Left="0" Canvas.Top="15" Stretch="Fill" Fill="#BBFFFFFF" Data="F1 M0,16 L0,16 C0,15.45 0.45,15 1,15 L7,15 C7.55,15 8,15.45 8,16 L8,16 C8,16.55 7.55,17 7,17 L1,17 C0.45,17 0,16.55 0,16 Z "/>
			<Path x:Name="BufferPath5" Width="7.2" Height="5" Canvas.Left="2" Canvas.Top="19.5" Stretch="Fill" Fill="#AAFFFFFF" Data="F1 M2.14,24 L2.14,24 C1.87,23.52 2.03,22.91 2.51,22.63 L7.71,19.63 C8.18,19.35 8.80,19.52 9.08,20 L9.07,20 C9.35,20.48 9.18,21.09 8.71,21.36 L3.51,24.37 C3.03,24.64 2.42,24.48 2.14,24 Z "/>
			<Path x:Name="BufferPath6" Width="5" Height="7.2" Canvas.Left="7.5" Canvas.Top="22.8" Stretch="Fill" Fill="#99FFFFFF" Data="F1 M8,29.86 L8,29.86 C7.52,29.58 7.36,28.97 7.63,28.49 L10.63,23.29 C10.91,22.82 11.52,22.65 12,22.93 L12,22.93 C12.48,23.20 12.64,23.82 12.37,24.29 L9.37,29.49 C9.09,29.97 8.48,30.13 8,29.86 Z "/>
			<Path x:Name="BufferPath7" Width="2" Height="8" Canvas.Left="15" Canvas.Top="24" Stretch="Fill" Fill="#77FFFFFF" Data="F1 M16,24 L16,24 C16.55,24 17,24.45 17,25 L17,31 C17,31.55 16.55,32 16,32 L16,32 C15.45,32 15,31.55 15,31 L15,25 C15,24.45 15.45,24 16,24 Z "/>
			<Path x:Name="BufferPath8" Width="5" Height="7.2" Canvas.Left="19.5" Canvas.Top="22.8" Stretch="Fill" Fill="#66FFFFFF" Data="F1 M20,22.93 L20,22.93 C20.48,22.65 21.09,22.82 21.36,23.29 L24.37,28.49 C24.64,28.97 24.48,29.58 24,29.86 L24,29.86 C23.52,30.13 22.91,29.97 22.63,29.49 L19.63,24.29 C19.36,23.82 19.52,23.20 20,22.93 Z "/>
			<Path x:Name="BufferPath9" Width="7.2" Height="5" Canvas.Left="22.8" Canvas.Top="19.5" Stretch="Fill" Fill="#55FFFFFF" Data="F1 M22.93,20 L22.93,20 C23.20,19.52 23.82,19.36 24.29,19.63 L29.49,22.63 C29.97,22.91 30.13,23.52 29.86,24 L29.86,24 C29.58,24.48 28.97,24.64 28.49,24.37 L23.29,21.37 C22.82,21.09 22.65,20.48 22.93,20 Z "/>
			<Path x:Name="BufferPath10" Width="8" Height="2" Canvas.Left="24" Canvas.Top="15" Stretch="Fill" Fill="#33FFFFFF" Data="F1 M24,16 L24,16 C24,15.45 24.45,15 25,15 L31,15 C31.55,15 32,15.45 32,16 L32,16 C32,16.55 31.55,17 31,17 L25,17 C24.45,17 24,16.55 24,16 Z "/>
			<Path x:Name="BufferPath11" Width="7.2" Height="5" Canvas.Left="22.8" Canvas.Top="7.5" Stretch="Fill" Fill="#22FFFFFF" Data="F1 M 22.93,12 L22.93,12 C22.65,11.52 22.82,10.91 23.29,10.63 L28.49,7.63 C28.97,7.36 29.58,7.52 29.86,8 L29.86,8 C30.13,8.48 29.97,9.09 29.49,9.37 L24.29,12.36 C23.82,12.64 23.20,12.48 22.93,12 Z "/>
			<Path x:Name="BufferPath12" Width="5" Height="7.2" Canvas.Left="19.5" Canvas.Top="2" Stretch="Fill" Fill="#11FFFFFF" Data="F1 M 20,9.07 L20,9.07 C19.52,8.80 19.36,8.18 19.63,7.71 L22.63,2.51 C22.91,2.03 23.52,1.87 24,2.14 L24,2.14 C24.48,2.42 24.64,3.03 24.37,3.51 L21.37,8.71 C21.09,9.18 20.48,9.35 20,9.07 Z "/>
		</Canvas>
		<TextBlock x:Name="BufferText" Canvas.Left="158" Canvas.Top="108" FontFamily="Verdana" FontSize="9" FontWeight="Bold" Foreground="#FFFFFFFF" Width="12" Height="10"/>
		<Canvas x:Name="OverlayCanvas" Width="300" Height="200" Canvas.Left="220" Canvas.Top="10" Visibility="Collapsed">
			<Canvas.Background>
				<ImageBrush x:Name="OverlayLogo" AlignmentX="Right" AlignmentY="Top" Stretch="None" />
			</Canvas.Background>
		</Canvas>
	</Canvas>




	<Canvas x:Name="PlayerControls" Width="320" Height="20" Canvas.Top="240" Visibility="Collapsed">
		<Rectangle x:Name="ControlbarBack" Width="320" Height="19" Fill="#FFFFFFFF" />


		<Canvas x:Name="VolumeButton" Width="24" Height="20" Canvas.Left="296">
			<Rectangle x:Name="VolumeShadow" Width="24" Height="1" Canvas.Top="19" Stretch="Fill" Fill="#55000000"/>
			<Path x:Name="VolumeStroke" Width="24" Height="19" Data="F1 M 0,0 L 24,0 L 24,19 L 0,19 L 0,18 L 23,18 L 23,1 L 0,1 0,0 Z ">
				<Path.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#C0000000" Offset="0"/>
							<GradientStop Color="#C0FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Path.Fill>
			</Path>
			<Rectangle x:Name="VolumeFill" Width="23" Height="17" Canvas.Top="1">
				<Rectangle.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#40000000" Offset="0"/>
							<GradientStop Color="#40FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Rectangle.Fill>
			</Rectangle>
			<Canvas x:Name="VolumeMask" Width="18" Height="19" Clip="F1 M1,9 L2,9 L2,10 L1,10 L1,9 M3,8.5 L4,8.5 L4,10.5 L3,10.5 L3,8.5 M5,8 L6,8 L6,11 L5,11 L5,8 M7,7.5 L8,7.5 L8,11.5 L7,11.5 L7,7.5 M9,7 L10,7 L10,12 L9,12 L9,7 M11,6.5 L12,6.5 L12,12.5 L11,12.5 L11,6.5 M13,6 L14,6 L14,13 L13,13 L13,6 M15,5.5 L16,5.5 L16,13.5 L15,13.5 L15,5.5 M17,5 L18,5 L18,14 L17,14 L17,5 Z">
				<Rectangle x:Name="VolumeSlider" Width="18" Height="15" Canvas.Top="2" Opacity="0.3" Fill="#FF000000"/>
				<Rectangle x:Name="VolumeHighlight" Width="18" Height="15" Canvas.Top="2" Fill="#FF000000"/>
				<Rectangle x:Name="VolumeSymbol" Width="1" Canvas.Top="6" Height="7" Fill="#00000000"/>
			</Canvas>
		</Canvas>


		<Canvas x:Name="MuteButton" Width="13" Height="20" Canvas.Left="283">
			<Rectangle x:Name="MuteShadow" Width="13" Height="1" Canvas.Top="19" Fill="#55000000"/>
			<Path x:Name="MuteStroke" Width="13" Height="19" Data="F 1 M 0,0 L 13,0 L 13,1 L 1,1 L 1,18 L 13,18 L 13,19 L 0,19 0,0 Z ">
				<Path.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#C0000000" Offset="0"/>
							<GradientStop Color="#C0FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Path.Fill>
			</Path>
			<Rectangle x:Name="MuteFill" Width="12" Height="17" Canvas.Left="1" Canvas.Top="1">
				<Rectangle.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#40000000" Offset="0"/>
							<GradientStop Color="#40FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Rectangle.Fill>
			</Rectangle>
			<Path x:Name="MuteOffSymbol" Width="5" Height="7" Canvas.Left="6" Canvas.Top="6" Fill="#FF000000" Data="F 1 M 0,2 L2,2 L 2,5 L0,5 L0,0 M3,1 L4,1 L4,0 L5,0 L5,7 L4,7 L4,6 L3,6 L3,1 Z "/>
			<Path x:Name="MuteSymbol" Width="5" Height="7" Canvas.Left="6" Canvas.Top="6" Opacity="0.3" Fill="#FF000000" Data="F 1 M 0,2 L2,2 L 2,5 L0,5 L0,0 M3,1 L4,1 L4,0 L5,0 L5,7 L4,7 L4,6 L3,6 L3,1 Z "/>
		</Canvas>


		<Canvas x:Name="FullscreenButton" Width="18" Height="20" Canvas.Left="265">
			<Rectangle x:Name="FullscreenShadow" Width="18" Height="1" Canvas.Top="19" Fill="#55000000"/>
			<Path x:Name="FullscreenStroke" Width="18" Height="19" Canvas.Left="0" Canvas.Top="0" Data="F1 M0,0 L18,0 L18,1 L1,1 L1,18 L18,18 L 18,19 L0,19 L0,0 Z ">
				<Path.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#C0000000" Offset="0"/>
							<GradientStop Color="#C0FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Path.Fill>
			</Path>
			<Rectangle x:Name="FullscreenFill" Width="17" Height="17" Canvas.Left="1" Canvas.Top="1">
				<Rectangle.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#40000000" Offset="0"/>
							<GradientStop Color="#40FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Rectangle.Fill>
			</Rectangle>
			<Path x:Name="FullscreenSymbol" Width="9" Height="9" Canvas.Left="5" Fill="#FF000000" Canvas.Top="5" Data="F1 M0,0 L2,0 L2,1 L1,1 L1,2 L0,2 L0,0 M0,7 L1,7 L1,8 L2,8 L2,9 L0,9 L0,7 M7,0 L9,0 L9,2 L8,2 L8,1 L7,1 L7,0 M8,7 L9,7 L9,9 L7,9 L7,8 L8,8 L8,7 M2,2 L7,2 L7,7 L2,7 L2,2 Z" />
			<Path x:Name="FullscreenOffSymbol" Width="9" Height="9" Canvas.Left="5" Fill="#00000000" Canvas.Top="5" Visibility="Collapsed" Data="F1 M1,0 L2,0 L2,2 L0,2 L0,1 L1,1 L1,0 M0,7 L2,7 L2,9 L1,9 L1,8 L0,8 L0,7 M7,0 L8,0 L8,1 L9,1 L9,2 L7,2 L7,0 M7,7 L9,7 L9,8 L8,8 L8,9 L7,9 L7,7 M2,2 L7,2 L7,7 L2,7 L2,2 Z" />
		</Canvas>


		<Canvas x:Name="LinkButton" Width="18" Height="20" Canvas.Left="247">
			<Rectangle x:Name="LinkShadow" Width="18" Height="1" Canvas.Top="19" Fill="#55000000"/>
			<Path x:Name="LinkStroke" Width="18" Height="19" Canvas.Left="0" Canvas.Top="0" Data="F1 M0,0 L18,0 L18,1 L1,1 L1,18 L18,18 L 18,19 L0,19 L0,0 Z ">
				<Path.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#C0000000" Offset="0"/>
							<GradientStop Color="#C0FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Path.Fill>
			</Path>
			<Rectangle x:Name="LinkFill" Width="17" Height="17" Canvas.Left="1" Canvas.Top="1">
				<Rectangle.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#40000000" Offset="0"/>
							<GradientStop Color="#40FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Rectangle.Fill>
			</Rectangle>
			<Path x:Name="LinkSymbol" Width="9" Height="9" Canvas.Left="5" Fill="#FF000000" Canvas.Top="5" Data="F1 M2,0 L7,0 L7,4 L9,4 L5,9 L4,9 L0,4 L2,4 L2,0 Z" />
		</Canvas>


		<Canvas x:Name="RemainingButton" Width="35" Height="20" Canvas.Left="207">
			<Rectangle x:Name="RemainingShadow" Width="35" Height="1" Canvas.Top="19" Fill="#55000000" />
			<Path x:Name="RemainingStroke" Width="35" Height="19" Stretch="Fill" Data="F1 M0,0 L35,0 L35,01 L0,1 L0,0 M 0,18 L35,18 L35,19 L0,19 L0,18 Z ">
				<Path.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#C0000000" Offset="0"/>
							<GradientStop Color="#C0FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Path.Fill>
			</Path>
			<Rectangle x:Name="RemainingFill" Width="35" Height="17" Canvas.Left="0" Canvas.Top="1">
				<Rectangle.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0.0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#40000000" Offset="0"/>
							<GradientStop Color="#40FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Rectangle.Fill>
			</Rectangle>
			<TextBlock x:Name="RemainingText" Text="00:00" Canvas.Left="1" Canvas.Top="4" FontFamily="Verdana" FontSize="9" FontWeight="Bold" />
		</Canvas>


		<Canvas x:Name="TimeButton" Width="133" Height="20" Canvas.Left="74" Canvas.Top="0">
			<Rectangle x:Name="TimeShadow" Width="133" Height="1" Canvas.Top="19" Fill="#55000000"/>
			<Path x:Name="TimeStroke" Width="133" Height="19" Stretch="Fill" Data="F1 M0,0 L168,0 L168,01 L0,1 L0,0 M0,18 L168,18 L168,19 L0,19 L0,18 Z ">
				<Path.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#C0000000" Offset="0"/>
							<GradientStop Color="#C0FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Path.Fill>
			</Path>
			<Rectangle x:Name="TimeFill" Width="133" Height="17" Canvas.Top="1" Stretch="Fill" >
				<Rectangle.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#40000000" Offset="0"/>
							<GradientStop Color="#40FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Rectangle.Fill>
			</Rectangle>
			<Rectangle x:Name="TimeSlider" Width="123" Height="5" Canvas.Top="7" Canvas.Left="5" Fill="#00000000" Opacity="0" />
			<Rectangle x:Name="DownloadProgress" Width="123" Height="5" Canvas.Top="7" Canvas.Left="5" Fill="#00000000" Opacity="0.3" />
			<Rectangle x:Name="TimeHighlight" Width="123" Height="5" Canvas.Top="7" Canvas.Left="5" Fill="#FF000000"/>
			<Rectangle x:Name="TimeSymbol" Width="2" Height="7" Canvas.Top="6" Canvas.Left="5" Fill="#FF000000"/>
		</Canvas>


		<Canvas x:Name="ElapsedButton" Width="35" Height="20" Canvas.Left="34">
			<Rectangle x:Name="ElapsedShadow" Width="35" Height="1" Canvas.Top="19" Fill="#55000000"/>
			<Path x:Name="ElapsedStroke" Width="40" Height="19" Data="F1 M0,0 L35,0 L35,01 L0,1 L0,0 M 0,18 L35,18 L35,19 L0,19 L0,18 Z ">
				<Path.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#C0000000" Offset="0"/>
							<GradientStop Color="#C0FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Path.Fill>
			</Path>
			<Rectangle x:Name="ElapsedFill" Width="35" Height="17" Canvas.Left="0" Canvas.Top="1">
				<Rectangle.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0.0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#40000000" Offset="0"/>
							<GradientStop Color="#40FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Rectangle.Fill>
			</Rectangle>
			<TextBlock x:Name="ElapsedText" Text="00:00" Canvas.Left="6" Canvas.Top="4" FontFamily="Verdana" FontSize="9" FontWeight="Bold" />
		</Canvas>


		<Canvas x:Name="StopButton" Width="17" Height="20" Canvas.Left="17">
			<Rectangle x:Name="StopShadow" Width="17" Height="1" Canvas.Top="19" Fill="#55000000"/>
			<Path x:Name="StopStroke" Width="17" Height="19" Canvas.Left="0" Canvas.Top="0" Data="F1 M 0,0 L17,0 L17,19 L0,19 L0,18 L16,18 L16,1 L0,1 L0,0 Z ">
				<Path.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#C0000000" Offset="0"/>
							<GradientStop Color="#C0FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Path.Fill>
			</Path>
			<Rectangle x:Name="StopFill" Width="16" Height="17" Canvas.Top="1">
				<Rectangle.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#40000000" Offset="0"/>
							<GradientStop Color="#40FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Rectangle.Fill>
			</Rectangle>
			<Path x:Name="StopSymbol" Width="6" Height="7" Canvas.Left="5" Fill="#FF000000" Canvas.Top="6" Data="F1 M0,0 L6,0 L6,7 L0,7 L0,0 Z " />
		</Canvas>


		<Canvas x:Name="PlayButton" Width="17" Height="20">
			<Rectangle x:Name="PlayShadow" Width="17" Height="1" Canvas.Top="19" Fill="#55000000"/>
			<Path x:Name="PlayStroke" Width="17" Height="19" Canvas.Left="0" Canvas.Top="0" Data="F0 M 0,0 L17,0 L17,19 L0,19 L0,0 M1,1 L16,1 L16,18 L1,18 L1,1 Z ">
				<Path.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#C0000000" Offset="0"/>
							<GradientStop Color="#C0FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Path.Fill>
			</Path>
			<Rectangle x:Name="PlayFill" Width="15" Height="17" Canvas.Left="1" Canvas.Top="1">
				<Rectangle.Fill>
					<LinearGradientBrush StartPoint="0.5,1" EndPoint="0.5,0">
						<LinearGradientBrush.GradientStops>
							<GradientStop Color="#40000000" Offset="0"/>
							<GradientStop Color="#40FFFFFF" Offset="1"/>
						</LinearGradientBrush.GradientStops>
					</LinearGradientBrush>
				</Rectangle.Fill>
			</Rectangle>
			<Path x:Name="PlayOffSymbol" Width="5" Height="7" Canvas.Left="6" Fill="#FF000000" Canvas.Top="6" Visibility="Collapsed" Data="F1 M0,0 L2,0 L2,7 L0,7 L0,0 M3,0 L5,0 L5,7 L3,7 L3,0 Z " />
			<Path x:Name="PlaySymbol" Width="6" Height="7" Canvas.Left="6" Fill="#FF000000" Canvas.Top="6" Data="F1 M0,0 L1,0 L1,1 L3,1 L3,2 L5,2 L5,3 L6,3 L6,4 L5,4 L5,5 L3,5 L3,6 L1,6 L1,7 L0,7 L0,0 Z" />
		</Canvas>


	</Canvas>


</Canvas>

js wmvplayer.js

/****************************************************************************
* JW WMV Player version 1.1, created with M$ Silverlight 1.0
*
* This file contains all logic for the JW WMV Player. For a functional setup,
* the following two files are also needed:
* - silverlight.js (for instantiating the silverlight plugin)
* - wmvplayer.xaml (or another XAML skin describing the player graphics)
*
* More info: http://www.jeroenwijering.com/?item=JW_WMV_Player
****************************************************************************/
if(typeof jeroenwijering == "undefined") {
	var jeroenwijering = new Object();
	jeroenwijering.utils = new Object();
}










/****************************************************************************
* The player wrapper; loads config variables and starts MVC cycle.
****************************************************************************/
jeroenwijering.Player = function(cnt,src,cfg) {
	this.controller;
	this.model;
	this.view;
	this.configuration = {
		backgroundcolor:'FFFFFF',
		windowless:'false',
		file:'',
		height:'260',
		image:'',
		backcolor:'FFFFFF',
		frontcolor:'000000',
		lightcolor:'000000',
		screencolor:'000000',
		width:'320',
		logo:'',
		overstretch:'false',
		shownavigation:'true',
		showstop:'false',
		showdigits:'true',
		usefullscreen:'true',
		usemute:'false',
		autostart:'false',
		bufferlength:'3',
		duration:'0',
		repeat:'false',
		sender:'',
		start:'0',
		volume:'90',
		link:'',
		linkfromdisplay:'false',
		linktarget:'_self'
	};
	for(itm in this.configuration) {
		if(cfg[itm] != undefined) {
			if (itm.indexOf('color') > 0) { 
				this.configuration[itm] = cfg[itm].substr(cfg[itm].length-6);
			} else {
				this.configuration[itm] = cfg[itm];
			}
		}
	}
	Silverlight.createObjectEx({
		source:src,
		parentElement:cnt,
		properties:{
			width:this.configuration['width'],
			height:this.configuration['height'],
			version:'1.0',
			inplaceInstallPrompt:true,
			isWindowless:this.configuration['windowless'],
			background:'#'+this.configuration['backgroundcolor']
		},
		events:{
			onLoad:this.onLoadHandler,
			onError:null
		},
		context:this
	});
}

jeroenwijering.Player.prototype = {
	addListener: function(typ,fcn) {
		this.view.listeners.push({type:typ,func:fcn});
	},

	getConfig: function() { 
		return this.configuration;
	},

	onLoadHandler: function(pid,tgt,sdr) {
		tgt.configuration['sender'] = sdr;
		tgt.controller = new jeroenwijering.Controller(tgt.configuration);
		tgt.view = new jeroenwijering.View(tgt.configuration,tgt.controller);
		tgt.model = new jeroenwijering.Model(tgt.configuration,tgt.controller,tgt.view);
		tgt.controller.startMVC(tgt.view,tgt.model);
	},

	sendEvent: function(typ,prm) {
		switch(typ.toUpperCase()) {
			case 'LINK':
				this.controller.setLink();
				break;
			case 'LOAD':
				this.controller.setLoad(prm);
				break;
			case 'MUTE':
				this.controller.setMute();
				break;
			case 'PLAY':
				this.controller.setPlay();
				break;
			case 'SCRUB':
				this.controller.setScrub(prm);
				break;
			case 'STOP':
				this.controller.setStop();
				break;
			case 'VOLUME':
				this.controller.setVolume(prm);
				break;
		}
	}
}










/****************************************************************************
* The controller of the player MVC triad, which processes all user input.
****************************************************************************/
jeroenwijering.Controller = function(cfg) {
	this.configuration = cfg;
}

jeroenwijering.Controller.prototype = {
	startMVC: function(vie,mdl) {
		this.view = vie;
		this.model = mdl;
		if(this.configuration['usemute'] == 'true') {
			this.view.onVolume(0);
			this.view.onMute(true);
			this.model.goVolume(0);
		} else {
			this.view.onVolume(this.configuration['volume']);
			this.model.goVolume(this.configuration['volume']);
		}
		if(this.configuration['autostart'] == 'true') {
			this.model.goStart();
		} else { 
			this.model.goPause();
		}
	},

	setState: function(old,stt) {
		this.state = stt;
		var pos = this.configuration['start'];
		if(old == 'Closed' && pos > 0) {
			setTimeout(jeroenwijering.utils.delegate(this,this.setScrub),200,pos);
		} 
	},

	setLink: function() {
		if (this.configuration['linktarget'].indexOf('javascript:') == 0) {
			return Function(this.configuration['linktarget']).apply();
		} else if (this.configuration['linktarget'] == '_blank') {
			window.open(this.configuration['link']);
		} else if (this.configuration['linktarget'] != '') {
			window.location = this.configuration['link'];
		}
	},

	setLoad: function(fil) {
		if(this.model.state != "Closed") {
			this.model.goStop(); 
		}
		this.configuration['file'] = fil;
		if(this.configuration['autostart'] == 'true') {
			setTimeout(jeroenwijering.utils.delegate(this.model,this.model.goStart),100);
		}
	},

	setMute: function() {
		if(this.configuration['usemute'] == 'true') {
			this.configuration['usemute'] = 'false';
			this.model.goVolume(this.configuration['volume']);
			this.view.onMute(false);
		} else {
			this.configuration['usemute'] = 'true';
			this.model.goVolume(0);
			this.view.onMute(true);
		}
	},

	setPlay: function() {
		if(this.state == 'Buffering' || this.state == 'Playing') {
			if(this.configuration['duration'] == 0) { 
				this.model.goStop();
			} else { 
				this.model.goPause();
			}
		} else {
			this.model.goStart();
		}
	},

	setScrub: function(sec) {
		if(sec < 2) {
			sec = 0;
		} else if (sec > this.configuration['duration']-4) {
			sec = this.configuration['duration']-4;
		}
		if(this.state == 'Buffering' || this.state == 'Playing') {
			this.model.goStart(sec);
		} else {
			this.model.goPause(sec);
		}
	},

	setStop: function() {
		this.model.goStop();
	},

	setVolume: function(pct) {
		if(pct < 0) { pct = 0; } else if(pct > 100) { pct = 100; }
		this.configuration['volume'] = Math.round(pct);
		this.model.goVolume(pct);
		this.view.onVolume(pct);
		if(this.configuration['usemute'] == 'true') {
			this.configuration['usemute'] = 'false';
			this.view.onMute(false);
		} 
	},

	setFullscreen: function() {
		var fss = !this.configuration['sender'].getHost().content.FullScreen;
		this.configuration['sender'].getHost().content.FullScreen = fss;
		jeroenwijering.utils.delegate(this.view,this.view.onFullscreen);
	}
}










/****************************************************************************
* The view of the player MVC triad, which manages the graphics.
****************************************************************************/
jeroenwijering.View = function(cfg,ctr) {
	this.configuration = cfg;
	this.listeners = Array();
	this.controller = ctr;
	this.fstimeout;
	this.fslistener;
	this.display = this.configuration['sender'].findName("PlayerDisplay");
	this.controlbar = this.configuration['sender'].findName("PlayerControls");
	this.configuration['sender'].getHost().content.onResize = 
		jeroenwijering.utils.delegate(this,this.resizePlayer);
	this.configuration['sender'].getHost().content.onFullScreenChange = 
		jeroenwijering.utils.delegate(this,this.onFullscreen);
	this.assignColorsClicks();
	this.resizePlayer();
}

jeroenwijering.View.prototype = {
	onBuffer: function(pct) {
		var snd = this.configuration['sender'];
		if(pct == 0) { 
			snd.findName("BufferText").Text = null;
		} else { 
			pct < 10 ? pct = "0"+pct: pct = ""+pct;
			snd.findName("BufferText").Text = pct;
		}
		this.delegate('BUFFER',[pct]);
	},

	onFullscreen: function(fss) {
		var snd = this.configuration['sender'];
		var fst = snd.getHost().content.FullScreen;
		if(fst) { 
			this.fstimeout = setTimeout(jeroenwijering.utils.delegate(this,
				this.hideFSControls),2000);
			this.fslistener = this.display.addEventListener('MouseMove',
				jeroenwijering.utils.delegate(this,this.showFSControls));
			snd.findName("FullscreenSymbol").Visibility = "Collapsed";
			snd.findName("FullscreenOffSymbol").Visibility = "Visible";
		} else {
			clearTimeout(this.fstimeout);
			this.display.removeEventListener("MouseMove",this.fslistener);
			this.controlbar.Visibility = "Visible";
			this.display.Cursor = "Hand";
			snd.findName("FullscreenSymbol").Visibility = "Visible";
			snd.findName("FullscreenOffSymbol").Visibility = "Collapsed";
		}
		this.resizePlayer();
		this.delegate('FULLSCREEN');
	},

	showFSControls: function(sdr,arg) {
		var vbt = sdr.findName('PlayerControls');
		var yps = arg.GetPosition(vbt).Y;
		clearTimeout(this.fstimeout);
		this.controlbar.Visibility = "Visible";
		this.display.Cursor = "Hand";
		if(yps < 0) { 
			this.fstimeout = setTimeout(jeroenwijering.utils.delegate(this,
				this.hideFSControls),2000);
		}
	},

	hideFSControls: function() {
		this.controlbar.Visibility = "Collapsed";
		this.display.Cursor = "None";
	},

	onLoad: function(pct) {
		var snd = this.configuration['sender'];
		var max = snd.findName("TimeSlider").Width;
		snd.findName("DownloadProgress").Width = Math.round(max*pct/100);
		this.delegate('LOAD',[pct]);
	},

	onMute: function(mut) {
		var snd = this.configuration['sender'];
		this.configuration['usemute'] = ''+mut;
		if(mut) {
			snd.findName("VolumeHighlight").Visibility = "Collapsed";
			snd.findName("MuteSymbol").Visibility = "Visible";
			snd.findName("MuteOffSymbol").Visibility = "Collapsed";
			if(this.state == 'Playing') {
				snd.findName("MuteIcon").Visibility = "Visible";
			}
		} else {
			snd.findName("VolumeHighlight").Visibility = "Visible";
			snd.findName("MuteSymbol").Visibility = "Collapsed";
			snd.findName("MuteOffSymbol").Visibility = "Visible";
			snd.findName("MuteIcon").Visibility = "Collapsed";
		}
		this.delegate('MUTE');
	},

	onState: function(old,stt) {
		var snd = this.configuration['sender'];
		this.state = stt;
		if(stt == 'Buffering' || stt == 'Playing' || stt == 'Opening') {
			snd.findName("PlayIcon").Visibility = "Collapsed";
			snd.findName("PlaySymbol").Visibility = "Collapsed";
			snd.findName("PlayOffSymbol").Visibility = "Visible";
			if (stt=='Playing') {
				snd.findName("BufferIcon").Visibility = "Collapsed";
				snd.findName("BufferText").Visibility = "Collapsed";
				if(this.configuration['usemute'] == 'true') {
					snd.findName("MuteIcon").Visibility = "Visible";
				}
			} else{
				snd.findName("BufferIcon").Visibility = "Visible";
				snd.findName("BufferText").Visibility = "Visible";
			}
		} else { 
			snd.findName("MuteIcon").Visibility = "Collapsed";
			snd.findName("BufferIcon").Visibility = "Collapsed";
			snd.findName("BufferText").Visibility = "Collapsed";
			snd.findName("PlayOffSymbol").Visibility = "Collapsed";
			snd.findName("PlaySymbol").Visibility = "Visible";
			if(this.configuration['linkfromdisplay'] == 'true') {
				snd.findName("PlayIcon").Visibility = "Collapsed";
			} else { 
				snd.findName("PlayIcon").Visibility = "Visible";
			}
		}
		try {
			if(!(old == 'Completed' && stt == 'Buffering') &&
				!(old == 'Buffering' && stt == 'Paused')) {
				playerStatusChange(old.toUpperCase(),stt.toUpperCase());
			}
		} catch (err) {}
		this.delegate('STATE',[old,stt]);
	},

	onTime: function(elp,dur) {
		var snd = this.configuration['sender'];
		var snd = this.configuration['sender'];
		var max = snd.findName("TimeSlider").Width;
		if(dur > 0) {
			var pos = Math.round(max*elp/dur);
			this.configuration['duration'] = dur;
			snd.findName("ElapsedText").Text = jeroenwijering.utils.timestring(elp);
			snd.findName("RemainingText").Text = jeroenwijering.utils.timestring(dur-elp);
			snd.findName("TimeSymbol").Visibility = "Visible";
			snd.findName("TimeSymbol")['Canvas.Left'] = pos+4;
			snd.findName("TimeHighlight").Width = pos-2;
		} else  { 
			snd.findName("TimeSymbol").Visibility = "Collapsed";
		}
		this.delegate('TIME',[elp,dur]);
	},

	onVolume: function(pct) {
		var snd = this.configuration['sender'];
		snd.findName("VolumeHighlight").Width = Math.round(pct/5);
		this.delegate('VOLUME',[pct]);
	},

	assignColorsClicks: function() {
		this.display.Cursor = "Hand";
		this.display.Background = "#FF"+this.configuration['screencolor'];
		if(this.configuration['linkfromdisplay'] == 'false') { 
			this.display.addEventListener('MouseLeftButtonUp',
				jeroenwijering.utils.delegate(this.controller,
				this.controller.setPlay));
		} else { 
			this.display.addEventListener('MouseLeftButtonUp',
				jeroenwijering.utils.delegate(this.controller,
				this.controller.setLink));
			this.display.findName("PlayIcon").Visibility = "Collapsed";
		}
		if(this.configuration['logo'] != '') {
			this.display.findName('OverlayCanvas').Visibility = "Visible";
			this.display.findName('OverlayLogo').ImageSource = 
				this.configuration['logo'];
		}
		this.controlbar.findName("ControlbarBack").Fill = 
			"#FF"+this.configuration['backcolor'];
		this.assignButton('Play',this.controller.setPlay);
		this.assignButton('Stop',this.controller.setStop);
		this.configuration['sender'].findName('ElapsedText').Foreground = 
			"#FF"+this.configuration['frontcolor'];
		this.assignSlider('Time',this.changeTime);
		this.configuration['sender'].findName('DownloadProgress').Fill = 
			"#FF"+this.configuration['frontcolor'];
		this.configuration['sender'].findName('RemainingText').Foreground = 
			"#FF"+this.configuration['frontcolor'];
		this.assignButton('Link',this.controller.setLink);
		this.assignButton('Fullscreen',this.controller.setFullscreen);
		this.assignButton('Mute',this.controller.setMute);
		this.assignSlider('Volume',this.changeVolume);
	},

	assignButton: function(btn,act) {
		var el1 = this.configuration['sender'].findName(btn+'Button');
		el1.Cursor = "Hand";
		el1.addEventListener('MouseLeftButtonUp',
			jeroenwijering.utils.delegate(this.controller,act));
		el1.addEventListener('MouseEnter',
			jeroenwijering.utils.delegate(this,this.rollOver));
		el1.addEventListener('MouseLeave',
			jeroenwijering.utils.delegate(this,this.rollOut));
		this.configuration['sender'].findName(btn+'Symbol').Fill = 
			"#FF"+this.configuration['frontcolor'];
		try {
			this.configuration['sender'].findName(btn+'OffSymbol').Fill = 
				"#FF"+this.configuration['frontcolor'];
		} catch(e) {}
	},

	assignSlider: function(sld,act) {
		var el1 = this.configuration['sender'].findName(sld+'Button');
		el1.Cursor = "Hand";
		el1.addEventListener('MouseLeftButtonUp',
			jeroenwijering.utils.delegate(this,act));
		el1.addEventListener('MouseEnter',
			jeroenwijering.utils.delegate(this,this.rollOver));
		el1.addEventListener('MouseLeave',
			jeroenwijering.utils.delegate(this,this.rollOut));
		this.configuration['sender'].findName(sld+'Slider').Fill = 
			"#FF"+this.configuration['frontcolor'];
		this.configuration['sender'].findName(sld+'Highlight').Fill = 
			"#FF"+this.configuration['frontcolor'];
		this.configuration['sender'].findName(sld+'Symbol').Fill = 
			"#FF"+this.configuration['frontcolor'];
	},

	delegate: function(typ,arg) {
		for(var i=0; i<this.listeners.length; i++) {
			if(this.listeners[i]['type'].toUpperCase() == typ) {
				this.listeners[i]['func'].apply(null,arg);
			}
		}
	},

	rollOver: function(sdr) {
		var str = sdr.Name.substr(0,sdr.Name.length-6);
		this.configuration['sender'].findName(str+'Symbol').Fill = 
			"#FF"+this.configuration['lightcolor'];
		try {
			this.configuration['sender'].findName(str+'OffSymbol').Fill = 
				"#FF"+this.configuration['lightcolor'];
		} catch(e) {}
	},

	rollOut: function(sdr) {
		var str = sdr.Name.substr(0,sdr.Name.length-6);
		this.configuration['sender'].findName(str+'Symbol').Fill = 
			"#FF"+this.configuration['frontcolor'];
		try {
			this.configuration['sender'].findName(str+'OffSymbol').Fill = 
				"#FF"+this.configuration['frontcolor'];
		} catch(e) {}
	},

	changeTime: function(sdr,arg) {
		var tbt = sdr.findName('TimeSlider');
		var xps = arg.GetPosition(tbt).X;
		var sec = Math.floor(xps/tbt.Width*this.configuration['duration']);
		this.controller.setScrub(sec);
	},

	changeVolume: function(sdr,arg) {
		var vbt = sdr.findName('VolumeButton');
		var xps = arg.GetPosition(vbt).X;
		this.controller.setVolume(xps*5);
	},

	resizePlayer: function() {
		var wid = this.configuration['sender'].getHost().content.actualWidth;
		var hei = this.configuration['sender'].getHost().content.actualHeight;
		var fss = this.configuration['sender'].getHost().content.FullScreen;
		if(this.configuration['shownavigation'] == 'true') {
			if(fss == true) {
				this.resizeDisplay(wid,hei);
				this.controlbar['Canvas.Left'] = Math.round(wid/2-250);
				this.resizeControlbar(500,hei-this.controlbar.Height-16);
				this.controlbar.findName('ControlbarBack')['Opacity'] = 0.5;
			} else { 
				this.resizeDisplay(wid,hei-20);
				this.controlbar['Canvas.Left'] = 0;
				this.resizeControlbar(wid,hei-this.controlbar.Height);
				this.controlbar.findName('ControlbarBack')['Opacity'] = 1;
			}
		} else {
			this.resizeDisplay(wid,hei);
		}
	},

	resizeDisplay: function(wid,hei) {
		this.stretchElement('PlayerDisplay',wid,hei);
		this.stretchElement('VideoWindow',wid,hei);
		this.stretchElement('PlaceholderImage',wid,hei);
		this.centerElement('PlayIcon',wid,hei);
		this.centerElement('MuteIcon',wid,hei);
		this.centerElement('BufferIcon',wid,hei);
		this.centerElement('BufferText',wid,hei);
		this.display.findName('OverlayCanvas')['Canvas.Left'] = wid -
			this.display.findName('OverlayCanvas').Width - 10;
		this.display.Visibility = "Visible";
	},

	resizeControlbar: function(wid,yps,alp) {
		this.controlbar['Canvas.Top'] = yps;
		this.stretchElement('PlayerControls',wid);
		this.stretchElement('ControlbarBack',wid);
		this.placeElement('PlayButton',0);
		var lft = 17;
		this.placeElement('VolumeButton',wid-24);
		this.placeElement('MuteButton',wid-37);
		var rgt = 37;
		if(this.configuration['showstop'] == 'true') {
			this.placeElement('StopButton',lft);
			lft += 17;
		} else {
			this.controlbar.findName('StopButton').Visibility="Collapsed";
		}
		if(this.configuration['usefullscreen'] == 'true') {
			rgt += 18;
			this.placeElement('FullscreenButton',wid-rgt);
		} else {
			this.controlbar.findName('FullscreenButton').Visibility = 
				"Collapsed";
		}
		if(this.configuration['link'] != '') {
			rgt += 18;
			this.placeElement('LinkButton',wid-rgt);
		} else {
			this.controlbar.findName('LinkButton').Visibility="Collapsed";
		}
		if(this.configuration['showdigits'] == 'true' && wid-rgt-lft> 160) {
			rgt += 35;
			this.controlbar.findName('RemainingButton').Visibility="Visible";
			this.controlbar.findName('ElapsedButton').Visibility="Visible";
			this.placeElement('RemainingButton',wid-rgt);
			this.placeElement('ElapsedButton',lft);
			lft +=35;
		} else {
			this.controlbar.findName('RemainingButton').Visibility = 
				"Collapsed";
			this.controlbar.findName('ElapsedButton').Visibility="Collapsed";
		}
		this.placeElement('TimeButton',lft);
		this.stretchElement('TimeButton',wid-lft-rgt);
		this.stretchElement('TimeShadow',wid-lft-rgt);
		this.stretchElement('TimeStroke',wid-lft-rgt);
		this.stretchElement('TimeFill',wid-lft-rgt);
		this.stretchElement('TimeSlider',wid-lft-rgt-10);
		this.stretchElement('DownloadProgress',wid-lft-rgt-10);
		var tsb = this.configuration['sender'].findName('TimeSymbol');
		this.stretchElement('TimeHighlight',tsb['Canvas.Left']-5);
		this.controlbar.Visibility = "Visible";
	},

	centerElement: function(nam,wid,hei) {
		var elm = this.configuration['sender'].findName(nam);
		elm['Canvas.Left'] = Math.round(wid/2 - elm.Width/2);
		elm['Canvas.Top'] = Math.round(hei/2 - elm.Height/2);
	},

	stretchElement: function(nam,wid,hei) {
		var elm = this.configuration['sender'].findName(nam);
		elm.Width = wid;
		if (hei != undefined) { elm.Height = hei; }
	},

	placeElement: function(nam,xps,yps) {
		var elm = this.configuration['sender'].findName(nam);
		elm['Canvas.Left'] = xps;
		if(yps) { elm['Canvas.Top'] = yps; }
	}
}










/****************************************************************************
* The model of the player MVC triad, which stores all playback logic.
****************************************************************************/
jeroenwijering.Model = function(cfg,ctr,vie) {
	this.configuration = cfg;
	this.controller = ctr;
	this.view = vie;
	this.video = this.configuration['sender'].findName("VideoWindow");
	this.preview = this.configuration['sender'].findName("PlaceholderImage");
	var str = {
		'true':'UniformToFill',
		'false':'Uniform',
		'fit':'Fill',
		'none':'None'
	}
	this.state = this.video.CurrentState;
	this.timeint;
	this.video.Stretch = str[this.configuration['overstretch']];
	this.preview.Stretch = str[this.configuration['overstretch']];
	this.video.BufferingTime = 
		jeroenwijering.utils.spanstring(this.configuration['bufferlength']);
	this.video.AutoPlay = true;
	this.video.AddEventListener("CurrentStateChanged",
		jeroenwijering.utils.delegate(this,this.stateChanged));
	this.video.AddEventListener("MediaEnded",
		jeroenwijering.utils.delegate(this,this.mediaEnded));
	this.video.AddEventListener("BufferingProgressChanged",
		jeroenwijering.utils.delegate(this,this.bufferChanged));
	this.video.AddEventListener("DownloadProgressChanged",
		jeroenwijering.utils.delegate(this,this.downloadChanged));
	if(this.configuration['image'] != '') {
		this.preview.Source = this.configuration['image'];
	}
}

jeroenwijering.Model.prototype = {
	goPause: function(sec) {
		this.video.pause();
		if(!isNaN(sec)) {
			this.video.Position = jeroenwijering.utils.spanstring(sec);
		}
		this.timeChanged();
	},

	goStart: function(sec) {
		this.video.Visibility = 'Visible';
		this.preview.Visibility = 'Collapsed';
		if(this.state == "Closed") {
			this.video.Source = this.configuration['file'];
		} else {
			this.video.play();
		}
		if(!isNaN(sec)) {
			this.video.Position = jeroenwijering.utils.spanstring(sec);
		}
	},

	goStop: function() {
		this.video.Visibility = 'Collapsed';
		this.preview.Visibility = 'Visible';
		this.goPause(0);
		this.video.Source = 'null';
		this.view.onBuffer(0);
		clearInterval(this.timeint);
	},

	goVolume: function(pct) {
		this.video.Volume = pct/100;
	},

	stateChanged: function() {
		var stt = this.video.CurrentState;
		if(stt != this.state) {
			this.controller.setState(this.state,stt);
			this.view.onState(this.state,stt);
			this.state = stt;
			this.configuration['duration'] = 
				Math.round(this.video.NaturalDuration.Seconds*10)/10;
			if(stt != "Playing" && stt != "Buffering" && stt != "Opening") {
				clearInterval(this.timeint);
			} else {
				this.timeint = setInterval(jeroenwijering.utils.delegate(
					this,this.timeChanged),100);
			}
		}
	},

	mediaEnded: function() {
		if(this.configuration['repeat'] == 'true') {
			this.goStart(0);
		} else {
			this.state = 'Completed';
			this.view.onState(this.state,'Completed');
			this.video.Visibility = 'Collapsed';
			this.preview.Visibility = 'Visible';
			this.goPause(0);
		}
	},

	bufferChanged: function() {
		var bfr = Math.round(this.video.BufferingProgress*100);
		this.view.onBuffer(bfr);
	},

	downloadChanged: function() {
		var dld = Math.round(this.video.DownloadProgress*100);
		this.view.onLoad(dld);
	},

	timeChanged: function() {
		var pos = Math.round(this.video.Position.Seconds*10)/10;
		this.view.onTime(pos,this.configuration['duration']);
	}
}










/****************************************************************************
* Some utility functions.
****************************************************************************/
jeroenwijering.utils.delegate = function(obj,fcn) {
	return function() {
		return fcn.apply(obj,arguments);
	}
}
jeroenwijering.utils.timestring = function(stp) {
	var hrs = Math.floor(stp/3600);
	var min = Math.floor(stp%3600/60);
	var sec = Math.round(stp%60);
	var str = "";
	sec > 9 ? str += sec: str +='0'+sec;
	min > 9 ? str = min+":"+str: str='0'+min+":"+str;
	hrs > 0 ? str = hrs+":"+str: null;
	return str;
}
jeroenwijering.utils.spanstring = function(stp) {
	var hrs = Math.floor(stp/3600);
	var min = Math.floor(stp%3600/60);
	var sec = Math.round(stp%60*10)/10;
	var str = hrs+':'+min+':'+sec;
	return str;
}

 

 

1.7. Using <Object> Element & Invoke Java Runtime Plug-in & Play the Video with JavaFX

さんぷるぺーじ (※要 Java Runtime)

『JavaFX?そんなのあったっけ?』、というツッコミをされる方は、おそらくそれが正しい反応です。

これはどんな方法かというと、.jar ファイルをHTMLソースコード中に<Applet>タグまたは<Object>タグで貼りつけて、ユーザ(閲覧者)の端末環境に入っているであろうJava Runtimeを呼んで、そのJava AppletJavaFX Script プログラムの中で.flvファイルの動画再生の制御を行うっていうものです。JavaFXの動画ファイルのサポートが、.flv (Flash Video)ってところが、ものすごくAdobe Flash/Flexを意識したテクノロジになってます。

今回は、JavaFXを用いた動画ファイル再生検証のために、私のマシンに入っているやや古いEclipse環境でプログラミングしたために、その古いバージョンのEclipse環境という理由で、JavaFX 1.2.1を使ってビルドしています。だいぶ古いです。

なお、JavaFXは、RIA(リッチインターネットアプリケーション)プラットフォームとしては比較的新しいもので、2008年に登場したものです。そして、競合しているMicrosoft Silverlightは、2007年に登場したもの。さらに競合しているMacromedia Flex (現 Adobe Flex)は、2004年に登場したもので、RIA界隈ではFlexが最も古参です。

このJavaFXを用いた方法、JavaFX Scriptが非常に楽ちんにコーディング出来て、サクっと作れるのですが、ただWeb上には、やっぱりJava Appletを用いることになるので、起動が重いです。そしてH.264などの高品質なビデオコーデックには対応していない点が、残念なところ。

でもまぁ、先に挙げたApple QuickTimeやMicrosoft Silverlightなどに比べて、Java Runtimeは比較的普及しているので、閲覧者さんには割とちゃんと再生してもらえる可能性が高い方法だとは思います。まぁ、Javaの起動が重いけどな・・・。しかも、最近のApple製品には、デフォルトでJava環境でさえインストールされなくなったので、Javaを手動インストールしておいてもらわないと、Flashと同様に、例の”青いオブジェクト”が表示されちゃうので注意です。

  • プラグイン普及率
  • HTMLソース
  • プログラムソース

Java Runtime Web Browser Plug-in: 78.54% (Jan '2011)

html index.html

	<script src="http://dl.javafx.com/1.2/dtfx.js"></script>
	<script>
		javafx (
			{
				archive: "VideoPlayer.jar",
				width: 511,
				height: 288,
				code: "VideoPlayer",
				name: "VideoPlayer"
			}
		);
	</script>

js dtfx.js

var idCounter=0;var pingEnable=true;var timedPings=10;var timedPingsInterval=10;var appletIdTime={};function dhtmlLoadScript(url){var e=document.createElement("script");e.src=url;e.type="text/javascript";document.getElementsByTagName("head")[0].appendChild(e);}
function takeTimeStamp(){if(pingEnable){var dtId="deployJavaApplet"+(++idCounter);appletIdTime[dtId]=new Date().getTime();}
return dtId;}
function processTemplate(errMessage){errMessage=errMessage.replace("MACOS_VERSION",dtfxObject.getMacOSVersion());errMessage=errMessage.replace("JAVA_VERSION",dtfxObject.getJavaVersion());return errMessage;}
function sendPing(dtId,pingType){if(pingEnable&&appletIdTime[dtId]!=0){var startTime=appletIdTime[dtId];var diffTime=new Date().getTime()-startTime;var href="http://dl.javafx.com/ping.js?t="+pingType+"&id="+dtId+"&v=1.2.3_b36&tm="+startTime+"&d="+diffTime
+"&j="+dtfxObject.thisJavaVersion;if(pingType.substr(0,4)=="done"){appletIdTime[dtId]=0;}
dhtmlLoadScript(href);}}
function setupPeriodicPing(){if(pingEnable&&timedPings>0){window.setTimeout(sendPeriodicPing,timedPingsInterval*1000);timedPings--;}}
function sendPeriodicPing(){if(pingEnable&&timedPings>=0){var unknownApplets=0;for(var id in appletIdTime){if(appletIdTime[id]!=0){sendPing(id,"timed"+timedPings);unknownApplets++;}}
if(unknownApplets>0){setupPeriodicPing();}}}
var _DTFX_JS_;if(typeof(_DTFX_JS_)=="undefined"){_DTFX_JS_="Already Loaded";var dtfxObject={browserIDs:[{id:"MSIE",varsToSearch:[navigator.userAgent],stringsToFind:["MSIE"]},{id:"Chrome",varsToSearch:[navigator.userAgent,navigator.vendor],stringsToFind:["Chrome","Google"]},{id:"Safari",varsToSearch:[navigator.userAgent,navigator.vendor],stringsToFind:["Safari","Apple Computer"]},{id:"Opera10",varsToSearch:[navigator.userAgent,navigator.userAgent],stringsToFind:["Opera","Version/10"]},{id:"Opera",varsToSearch:[navigator.userAgent],stringsToFind:["Opera"]},{id:"Netscape Family",varsToSearch:[navigator.appName],stringsToFind:["Netscape"]}],OSIDs:[{id:"Windows",varsToSearch:[navigator.userAgent],stringsToFind:["Windows"]},{id:"Mac",varsToSearch:[navigator.userAgent],stringsToFind:["Mac OS X"]},{id:"Linux",varsToSearch:[navigator.userAgent],stringsToFind:["Linux"]},{id:"SunOS",varsToSearch:[navigator.userAgent],stringsToFind:["SunOS"]},{id:"UNIX",varsToSearch:[navigator.userAgent],stringsToFind:["X11"]}],NoJava:[{id:"ChromeMac",varsToSearch:[navigator.userAgent,navigator.userAgent],stringsToFind:["Mac OS X","Chrome"]},{id:"iPhone",varsToSearch:[navigator.userAgent],stringsToFind:["iPhone"]},{id:"iPod",varsToSearch:[navigator.userAgent],stringsToFind:["iPod"]}],NoJavaDownload:[{id:"Mac",varsToSearch:[navigator.userAgent],stringsToFind:["Mac OS X"]}],browsersSupportingDirectJavaAccess:["Netscape Family"],browsersSupportingActiveX:["MSIE"],activeXVersionList:["1.8.0","1.7.0","1.6.0","1.5.0","1.4.2"],findEntryInList:function(listToUse){var myID=null;for(var i=0;i<listToUse.length;i++){var match=true;for(var j=0;j<listToUse[i].varsToSearch.length;j++){if(listToUse[i].varsToSearch[j].indexOf(listToUse[i].stringsToFind[j],0)==-1){match=false;break;}}
if(match){myID=listToUse[i].id;break;}}
return myID;},errorMessages:{ErrorMacJavaUpgradeRequired:null,ErrorMacOSVersionNotSupported:null,ErrorNonMacJavaInstallRequired:null,ErrorOpera10:null,ErrorChrome:null,ErrorJavaNotSupported:null},generateInPlaceErrorDisplay:function(displayMessage){var tagLeadChar="<";var tagEndChar=">";dtfxObject.smallErrorCode=tagLeadChar+'a href="http://java.com/"'+tagEndChar;dtfxObject.smallErrorCode+=tagLeadChar+'img src="http://orgrimmar.russia.sun.com:8080/java-coffee-cup-23x20.png'+'" border="0" width="23" height="20" alt="Java Coffee Cup"'+
tagEndChar;var stringOutput=dtfxObject.smallErrorCode;stringOutput+=displayMessage;stringOutput+=tagLeadChar+'/a'+tagEndChar;dtfxObject.smallErrorCode+=tagLeadChar+'/a'+tagEndChar;return stringOutput;},generatePopupErrorDisplay:function(displayMessage,popupMessageToUser){var tagLeadChar="<";var tagEndChar=">";dtfxObject.smallErrorCode=tagLeadChar+'a href="javascript:dtfxObject.explainAndInstall('+"'"+popupMessageToUser+"'"+')"'+
tagEndChar;dtfxObject.smallErrorCode+=tagLeadChar+'img src="http://orgrimmar.russia.sun.com:8080/java-coffee-cup-23x20.png'+'" border="0" width="23" height="20" alt="Java Coffee Cup"'+
tagEndChar;var stringOutput=dtfxObject.smallErrorCode;stringOutput+=displayMessage;stringOutput+=tagLeadChar+'/a'+tagEndChar;dtfxObject.smallErrorCode+=tagLeadChar+'/a'+tagEndChar;return stringOutput;},initErrorMsg:function(){dtfxObject.errorMessages.ErrorOpera10=dtfxObject.generatePopupErrorDisplay(" The application could not load because your browser does not support Java. Click for more options.","Please user another browser like Mozilla Firefox to view the application.");dtfxObject.errorMessages.ErrorChrome=dtfxObject.generatePopupErrorDisplay(" A newer version of Java is needed to view the application. Click to update Java now.");dtfxObject.errorMessages.ErrorJavaNotSupported=dtfxObject.generateInPlaceErrorDisplay(" The application uses Java, but Java is not supported by your system. Use a computer with another operating system to view this applicaiton.");dtfxObject.errorMessages.ErrorNonMacJavaInstallRequired=dtfxObject.generatePopupErrorDisplay(" A newer version of Java is needed to view the application. Click to update Java.","Click to update Java.");dtfxObject.errorMessages.ErrorMacJavaUpgradeRequired=dtfxObject.generatePopupErrorDisplay(" The application could not load. Click for details.","JavaFX requires Java 5.0 (1.5) or above.  Please use Software Update to upgrade your Java version.");dtfxObject.errorMessages.ErrorMacOSVersionNotSupported=dtfxObject.generatePopupErrorDisplay(" The application could not load. Click for details.","The application requires Mac OS 10.5 or newer. Please upgrade your OS to view the application. JavaFX requires Java 5.0 (1.5) or above.");},thisBrowser:null,getBrowser:function(){if(null===dtfxObject.thisBrowser){dtfxObject.thisBrowser=dtfxObject.findEntryInList(dtfxObject.browserIDs);if(null===dtfxObject.thisBrowser){dtfxObject.thisBrowser="unknown";}}
return dtfxObject.thisBrowser;},thisBrowserCanAccessJava:null,browserCanAccessJava:function(){if(null===dtfxObject.thisBrowserCanAccessJava){var browser=dtfxObject.getBrowser();dtfxObject.thisBrowserCanAccessJava=false;for(var i=0;i<dtfxObject.browsersSupportingDirectJavaAccess.length;++i){if(browser==dtfxObject.browsersSupportingDirectJavaAccess[i]){dtfxObject.thisBrowserCanAccessJava=true;break;}}}
return dtfxObject.thisBrowserCanAccessJava;},thisBrowserHasActiveX:null,browserHasActiveX:function(){if(null===dtfxObject.thisBrowserHasActiveX){var browser=dtfxObject.getBrowser();dtfxObject.thisBrowserHasActiveX=false;if(null!=window.ActiveXObject){for(var i=0;i<dtfxObject.browsersSupportingActiveX.length;++i){if(browser==dtfxObject.browsersSupportingActiveX[i]){dtfxObject.thisBrowserHasActiveX=true;break;}}}}
return dtfxObject.thisBrowserHasActiveX;},thisJavaVersion:null,getJavaVersion:function(){if(null===dtfxObject.thisJavaVersion){if((null===dtfxObject.thisJavaVersion)&&(dtfxObject.browserHasActiveX())){for(var v=0;v<dtfxObject.activeXVersionList.length;v++){try{var axo=new ActiveXObject("JavaWebStart.isInstalled."+
dtfxObject.activeXVersionList[v]+".0");dtfxObject.thisJavaVersion=dtfxObject.activeXVersionList[v];break;}catch(ignored){}}}
if(null===dtfxObject.thisJavaVersion){var bestVersionSeen=null;for(var i=0;i<navigator.mimeTypes.length;i++){var s=navigator.mimeTypes[i].type;var m=s.match(/^application\/x-java-applet;jpi-version=(.*)$/);if(m!==null){dtfxObject.thisJavaVersion=m[1];break;}
m=s.match(/^application\/x-java-applet;version=(.*)$/);if(m!==null){if((null===bestVersionSeen)||(m[1]>bestVersionSeen)){bestVersionSeen=m[1];}}}
if((null===dtfxObject.thisJavaVersion)&&(null!==bestVersionSeen)){dtfxObject.thisJavaVersion=bestVersionSeen;}}
if((null===dtfxObject.thisJavaVersion)&&dtfxObject.browserCanAccessJava()&&(typeof java=="object")){dtfxObject.thisJavaVersion=java.lang.System.getProperty("java.version");}
if(null===dtfxObject.thisJavaVersion){dtfxObject.thisJavaVersion="0 - unknown";}}
return dtfxObject.thisJavaVersion;},thisOSName:null,getSystemOS:function(){if(null===dtfxObject.thisOSName){dtfxObject.thisOSName=dtfxObject.findEntryInList(dtfxObject.OSIDs);if(null===dtfxObject.thisOSName){dtfxObject.thisOSName="unknown";}}
return dtfxObject.thisOSName;},thisMacOSVersion:null,getMacOSVersion:function(){if(null===dtfxObject.thisMacOSVersion){if("Mac"!=dtfxObject.getSystemOS()){dtfxObject.thisMacOSVersion="Not Mac";}
else{if(dtfxObject.browserCanAccessJava()){dtfxObject.thisMacOSVersion=java.lang.System.getProperty("os.version");}
if(null===dtfxObject.thisMacOSVersion){var av=navigator.appVersion;var m=av.match(/Mac OS X ([0-9_]*);/);if(null!==m){dtfxObject.thisMacOSVersion=m[1];dtfxObject.thisMacOSVersion=dtfxObject.thisMacOSVersion.split("_").join(".");}}}
if(null===dtfxObject.thisMacOSVersion){dtfxObject.thisMacOSVersion="unknown";}}
return dtfxObject.thisMacOSVersion;},overlayCount:0,nameSeed:0,getBogusJarFileName:function(){if(0===dtfxObject.nameSeed){dtfxObject.nameSeed=(new Date()).getTime();}
var uniqueNum=dtfxObject.nameSeed++;return"emptyJarFile-"+uniqueNum;},isVersionAvailable:function(){var ret=true;if(("Safari"==dtfxObject.getBrowser())&&("Mac"==dtfxObject.getSystemOS())&&(dtfxObject.getMacOSVersion().indexOf("10.4",0)===0)){ret=false;}
return ret;},javaSupport:null,getJavaSupportExists:function(){if(null===dtfxObject.javaSupport){var noSupportName=dtfxObject.findEntryInList(dtfxObject.NoJava);if(null===noSupportName){dtfxObject.javaSupport=true;}
else{dtfxObject.javaSupport=false;}}
return dtfxObject.javaSupport;},javaDownloadSupport:null,getJavaDownloadSupportExists:function(){if(null===dtfxObject.javaDownloadSupport){var noSupportName=dtfxObject.findEntryInList(dtfxObject.NoJavaDownload);if(null===noSupportName){dtfxObject.javaDownloadSupport=true;}
else{dtfxObject.javaDownloadSupport=false;}}
return dtfxObject.javaDownloadSupport;},errorMessageBoxes:null,errorMessageWidths:null,errorMessageHeights:null,onloadHandlerQueued:false,smallErrorCode:"",onloadCheckErrorDisplay:function(){var boxId;var width;var height;while(dtfxObject.errorMessageBoxes.length>0){boxId=dtfxObject.errorMessageBoxes.pop();width=dtfxObject.errorMessageWidths.pop();height=dtfxObject.errorMessageHeights.pop();var tableForBox=document.getElementById(boxId);if((tableForBox.offsetHeight!=height)||(tableForBox.offsetWidth!=width)){tableForBox.rows.item(0).cells.item(0).innerHTML=dtfxObject.smallErrorCode;}}},javafxString:function(launchParams,appletParams){var stringOutput="";var errorMessageToUser="";var appletID=takeTimeStamp();if(!dtfxObject.getJavaSupportExists()){errorMessageToUser=dtfxObject.errorMessages.ErrorJavaNotSupported;sendPing(appletID,"done_unsupportedbyjre");}else if("Opera10"===dtfxObject.getBrowser()){errorMessageToUser=dtfxObject.errorMessages.ErrorOpera10;sendPing(appletID,"done_opera10");}
else if(dtfxObject.isVersionAvailable()){var javaVersion=dtfxObject.getJavaVersion();sendPing(appletID,"start");if(("V"+javaVersion)<"V1.5"){if("Mac"==dtfxObject.getSystemOS()){var osVersion=dtfxObject.getMacOSVersion();if(("V"+osVersion)<"V10.4"){errorMessageToUser=dtfxObject.errorMessages.ErrorMacOSVersionNotSupported;sendPing(appletID,"done_oldmac");}
else{errorMessageToUser=dtfxObject.errorMessages.ErrorMacJavaUpgradeRequired;sendPing(appletID,"done_oldjremac");}}
else{if("Chrome"===dtfxObject.getBrowser()){errorMessageToUser=dtfxObject.errorMessages.ErrorChrome;}else{errorMessageToUser=dtfxObject.errorMessages.ErrorNonMacJavaInstallRequired;}
if("0 - unknown"==javaVersion){sendPing(appletID,"done_nojre");}else{sendPing(appletID,"done_oldjre");}}}}else{sendPing(appletID,"start2");}
var standardArchives=["applet-launcher"];switch(dtfxObject.getSystemOS()){case"Mac":standardArchives.push("javafx-rt-macosx-universal");break;case"Windows":standardArchives.push("javafx-rt-windows-i586");break;case"Linux":standardArchives.push("javafx-rt-linux-i586");break;case"SunOS":standardArchives.push("javafx-rt-solaris-i586");break;}
standardArchives.push(""+dtfxObject.getBogusJarFileName());var versionNumber="1.2.3_b36";var appletPlayer="org.jdesktop.applet.util.JNLPAppletLauncher";var tagLeadChar="<";var tagEndChar=">";var carriageReturn="\n";var appletTagParams={};appletTagParams.code=appletPlayer;var params={};params.codebase_lookup="false";params["subapplet.classname"]="com.sun.javafx.runtime.adapter.Applet";params.progressbar="false";params.classloader_cache="false";var loading_image_url=null;var loading_image_width=-1;var loading_image_height=-1;var key="";if(typeof launchParams!="string"){for(key in launchParams){switch(key.toLocaleLowerCase()){case"jnlp_href":params.jnlp_href=launchParams[key];break;case"version":versionNumber=launchParams[key];break;case"code":params.MainJavaFXScript=launchParams[key];break;case"name":params["subapplet.displayname"]=launchParams[key];break;case"draggable":params[key]=launchParams[key];break;case"displayhtml":if(launchParams[key]){tagLeadChar="<";tagEndChar=">";carriageReturn="<br>\n";}
break;case"loading_image_url":loading_image_url=launchParams[key];break;case"loading_image_width":loading_image_width=launchParams[key];break;case"loading_image_height":loading_image_height=launchParams[key];break;default:appletTagParams[key]=launchParams[key];break;}}}else{appletTagParams.archive=launchParams;}
if(errorMessageToUser!=""){var javaSupported=dtfxObject.getJavaSupportExists();if(javaSupported&&!document.getElementById('deployJava')){var script=document.createElement('script');script.id='deployJava';script.type='text/javascript';script.src='http://java.com/js/deployJava.js';var head=document.getElementsByTagName("head")[0];head.appendChild(script);}
var errId="errorWithJava"+(++dtfxObject.overlayCount);var w=appletTagParams.width;var h=appletTagParams.height;stringOutput+=tagLeadChar+'div id="JavaLaunchError" style="width:'+w+';height:'+h+';background:white"'+tagEndChar+
carriageReturn;stringOutput+=tagLeadChar+'table id="'+errId+'" width='+w+' height='+
h+' border=1 padding=0 margin=0'+tagEndChar+
carriageReturn;stringOutput+=tagLeadChar+'tr'+tagEndChar+tagLeadChar+'td align="center" valign="middle"'+tagEndChar+
carriageReturn;stringOutput+=processTemplate(errorMessageToUser);stringOutput+=tagLeadChar+'/td'+tagEndChar+tagLeadChar+'/tr'+
tagEndChar+tagLeadChar+'/table'+tagEndChar+
carriageReturn;stringOutput+=tagLeadChar+'/div'+tagEndChar+carriageReturn;dtfxObject.errorMessageBoxes.push(errId);dtfxObject.errorMessageWidths.push(w);dtfxObject.errorMessageHeights.push(h);if(!dtfxObject.onloadHandlerQueued){if(window.attachEvent){window.attachEvent("onload",dtfxObject.onloadCheckErrorDisplay);}
else if(window.addEventListener){window.addEventListener("load",dtfxObject.onloadCheckErrorDisplay,false);}
else{document.addEventListener("load",dtfxObject.onloadCheckErrorDisplay,false);}}
return stringOutput;}
params.jnlpNumExtensions=0;if(params.jnlp_href===undefined){var loc=appletTagParams.archive.indexOf(".jar,");if(-1==loc){loc=appletTagParams.archive.lastIndexOf(".jar");}
if(-1!=loc){params.jnlp_href=appletTagParams.archive.substr(0,loc)+"_browser.jnlp";}}
for(var i=0;i<standardArchives.length;i++){appletTagParams.archive+=","+"http://dl.javafx.com/"+standardArchives[i];if(versionNumber!==""){appletTagParams.archive+="__V"+versionNumber;}
appletTagParams.archive+=".jar";}
if(dtfxObject.fxOverlayEnabled()){var dtId="deployJavaApplet"+(++dtfxObject.overlayCount);params["deployJavaAppletID"]=dtId;var width=appletTagParams.width;var height=appletTagParams.height;var img;var imgWidth;var imgHeight;window.setTimeout(function(){fxAppletStarted(dtId);},180*1000);if(loading_image_url!==null&&loading_image_height>0&&loading_image_width>0){img=loading_image_url;imgWidth=loading_image_width;imgHeight=loading_image_height;}else{img='http://dl.javafx.com/';if(width>=100&&height>=100){img+='javafx-loading-100x100.gif';imgWidth=100;imgHeight=100;}else{img+='javafx-loading-25x25.gif';imgWidth=25;imgHeight=25;}}
stringOutput+=tagLeadChar+'div id="'+dtId+'Overlay'+'" style="width:'+width+';height:'+height+';position:absolute;background:white"'+tagEndChar+
carriageReturn;stringOutput+=tagLeadChar+'table width='+width+' height='+
height+' border=0 cellpadding=0'+' style="border-width:0px;border-spacing:0px 0px;margin:0px;padding:0px;"'+
tagEndChar+carriageReturn;stringOutput+=tagLeadChar+'tr'+tagEndChar+tagLeadChar+'td align="center" valign="middle"'+tagEndChar+
carriageReturn;stringOutput+=tagLeadChar+'img src="'+img+'" width='+
imgWidth+' height='+imgHeight+tagEndChar+
carriageReturn;stringOutput+=tagLeadChar+'/td'+tagEndChar+tagLeadChar+'/tr'+
tagEndChar+tagLeadChar+'/table'+tagEndChar+
carriageReturn;stringOutput+=tagLeadChar+'/div'+tagEndChar+carriageReturn;stringOutput+=tagLeadChar+'div id="'+dtId+'" style="position:relative;left:-10000px"'+
tagEndChar+carriageReturn;}
stringOutput+=tagLeadChar+"APPLET MAYSCRIPT"+carriageReturn;for(key in appletTagParams){stringOutput+=key+"=";if(typeof appletTagParams[key]=="number"){stringOutput+=appletTagParams[key];}else{stringOutput+="\""+appletTagParams[key]+"\"";}
stringOutput+=carriageReturn;}
stringOutput+=tagEndChar+carriageReturn;if(appletParams){for(key in appletParams){params[key]=appletParams[key];}}
if(pingEnable){params["pingAppletID"]=appletID;params["fxbuild"]='1.2.3_b36';params["pingTS"]=appletIdTime[appletID];}
for(key in params){stringOutput+=tagLeadChar+"param name=\""+key+"\" value=\""+params[key]+"\""+
tagEndChar+carriageReturn;}
stringOutput+=tagLeadChar+"/APPLET"+tagEndChar+carriageReturn;if(dtfxObject.fxOverlayEnabled()){stringOutput+=tagLeadChar+"/div"+tagEndChar+carriageReturn;}
return stringOutput;},fxOverlayEnabled:function(){return(dtfxObject.getBrowser()!="Netscape Family"&&dtfxObject.getBrowser()!="Opera")||dtfxObject.getSystemOS()!="Mac";},explainAndInstall:function(explanation){if(dtfxObject.getJavaDownloadSupportExists()&&dtfxObject.getJavaSupportExists()&&"Opera10"!==dtfxObject.getBrowser()){deployJava.returnPage=document.location;deployJava.installLatestJRE();}
else{alert(explanation);}},initDtfx:function(){dtfxObject.errorMessageBoxes=new Array();dtfxObject.errorMessageWidths=new Array();dtfxObject.errorMessageHeights=new Array();window.onunload=function(){appletIdTime={};};dtfxObject.initErrorMsg();}};dtfxObject.initDtfx();}
function javafx(launchParams,appletParams){if(idCounter==0){window.setTimeout(sendPeriodicPing,4000);}
var stringOutput=dtfxObject.javafxString(launchParams,appletParams);if(null!=stringOutput){document.write(stringOutput);}}
function javafxString(launchParams,appletParams){return dtfxObject.javafxString(launchParams,appletParams);}
function hideOverlay(id){var olay=document.getElementById(id+"Overlay");if(olay){if(olay.parentNode&&olay.parentNode.removeChild){olay.parentNode.removeChild(olay);}else{olay.style.visibility="hidden";}
document.getElementById(id).style.left="0px";}}
function fxAppletStarted(id){hideOverlay(id);sendPing(id,"done_ok");}
function fxAppletFailed(id,reason){hideOverlay(id);sendPing(id,"applet_failed_"+reason);}

java VideoPlayer.fx

import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.media.MediaPlayer;
import javafx.scene.media.Media;
import javafx.scene.media.MediaView;

/**
 * Displaying Video with JavaFX
 *
 * @author mio
 */

// Media Source
var media : Media = Media {
    source : "http://chsmea.net/~mioproject/sample_video/takoyaki.flv"
}

// Media Player
var player : MediaPlayer = MediaPlayer {
    media : media
    autoPlay : true
    repeatCount : MediaPlayer.REPEAT_FOREVER
}

// Stage
Stage {
    scene : Scene {
        width : media.width
        height : media.height
        content : MediaView {
            mediaPlayer : player
        }
    }
}

 

 

2. Using HTML5 <Video> Element & Native Play the Video

さんぷるぺーじ (※ .webm (On2VP8) 版)

さんぷるぺーじ (※ .mp4 (H.264) 版)

さんぷるぺーじ (※ .ogg (Theora) 版)

さんぷるぺーじ (※ マルチソース 版)

『HTML5最高ーーー!』、というコメントをされる方は、せっせと3種類(.webm, .mp4, .ogg)の動画ファイルをがんばってエンコードしてくださいね!

もちろん、そんなに3種類も動画エンコしてると、メモリ使用量がこんなことになっちゃいます・・・↓

これはどんな方法かというと、動画ファイルを直接HTML5ソースコード中に<Video>タグで貼りつると、ブラウザがマシンの環境を必死に引っ張り出しながら頑張ってネイティブに動画再生しちゃう、という方法です。

とくにプログラミングは必要ありませんし、数行(3行~5行)のコーディングでOKという、(コーディング面では)とてつもない手軽さ。だが、その手軽さとは裏腹に、ブラウザでサポートされる動画形式の乱立というとても面倒な問題が現在発生しており、3種類の動画ファイルをエンコして、用意してやらないと、特定のブラウザじゃどうやっても動画再生されない、などという事態が発生してしまいます。「動画を再生するには、マークアップではこうしてみませんか?」という部分が、(現在、草案ながらも)標準化されたのに、「じゃぁ再生してもらう動画のコーデックにはこれを使ってみませんか?」という部分で、大分裂なう、です。これには、H.264の特許使用料の問題があって、MSやら林檎やらMozillaやらGoogleなど、特にブラウザベンダの間で、これからのHTML5 Videoでサポートする動画コーデックの方向性で、いろいろモメているのです。

また、注意しなきゃいけないのは、ビデオ再生にハードウェアアクセラレーションがかかるかや、動画のコントロール機能などは、これまた完全にブラウザの環境依存(独自実装とも言う)で、Web界隈では、まだまだクロスブラウザで頭痛が続くことになりそうです。
HTML5がいくらオープンで標準化技術だといっても、それをレンダリングするソフトウェア(ブラウザ)が、どこもかしこも独自実装な部分が濃いので、結局苦労しちゃうことに。
 え?自由市場・自由競争社会だから仕方ないって? ― うん、そうだね。乱立してカオスになっているということは、デベロッパやエンドユーザにとっては(いろんな意味で)選択肢が増えて、より自由になっていると捉えることもできるわけで、各個が自分の好きなように技術を使えばいいんじゃない?

  • プラグイン普及率
  • HTMLソース

HTML5 Video Supported: 66.55% (Jul '2011, Japan)

html index.html

	<video width="511" height="288" autoplay loop>
		<source src="http://chsmea.net/~mioproject/sample_video/takoyaki.ogv" type="video/ogg">
		<source src="http://chsmea.net/~mioproject/sample_video/takoyaki.mp4" type="video/mp4">
		<source src="http://chsmea.net/~mioproject/sample_video/takoyaki.webm" type="video/webm">
	</video>

 

 

データ

 

 

まとめ

なにを選ぶのかは、あなたの自由です。

それぞれの技術には、長所も短所も存在しています。
 それらを自分なりに上手く使い分けていけばいいのです。

最も言いたかったことは、ただ、それだけです。

 

###なお、こんなの「まとめ」になっていないというコメントは、締め切りました###

 

 

【※このエントリーは、後日、ちゃんと参考資料とかデータを整理して、比較してもらいやすいように、整形する予定です。また、記事の内容についても、後日しっかりと推敲する予定です。 現時点では、このエントリーは「メモ書き」程度とご認識ください※】

ページ移動

トラックバック

  • トラックバックはまだありません。

トラックバックURL

http://chsmea.net/~mioproject/freo/trackback/167

コメント

  • コメントはまだありません。

コメント登録

  • コメントを入力してください。
登録フォーム
名前 *
URL
コメント *
閲覧制限 *
【スパム対策】 2 × 2 × 2 = ? (半角数字で)

ユーティリティ

user profile

calendar

042024/0506
S M T W T F S
- - - 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 -

tag cloud