21151644_oFsG 
Ø Playing Video
Ø MediaElement

Subservient Cat是一個「虛擬寵物」的應用程式。與大多數貓不一樣,Subservient Cat非常聽從主人的指令!但是,使用者需要知道哪些命令它是能夠回應的。它又帶點遊戲的成分,因為使用者必須通過自己的摸索來發現這些命令。

該應用程式使用一段黑色貓咪(名字為Boo)的視訊短片作為主介面。因此,對於學習怎樣通過MediaElement控制項在應用程式中播放視頻來說,這是一個很好的例子。

Playing Video with MediaElement

如果我們想要使用者可以對視頻進行播放、暫停和其他的控制操作,最好的選擇就是使用Media Player 啟動器。但是,如果我們想要在應用程式的頁面中播放視頻內容,就可以選擇使用MediaElement。MediaElement是一個UI控制項,它可以通過自身的Source屬性來播放視頻檔。例如:

<MediaElement Source=」cat.wmv」/>

視頻原始檔案的路徑可以指向工程中包含的檔,或者是一個線上的網路視頻。預設情況下,MediaElement在載入時自動播放視頻(對於網路視頻來說,只要緩衝了足夠的視頻流,它就開始播放),但是,我們可以將AutoPlay屬性設置為false,來更改這種設置。在背後代碼中,我們可以使用MediaElement的Play、Pause 和 Stop方法。它還具有Position屬性,用於指示當前的播放位置(用一個時間段的值來標識)。另外,如果視頻支援查找的話,我們可以設置Position為一個播放的時間點。就和其他的Silverlight 元素一樣,MediaElement支援轉變和剪切操作,並且它還可以與其他元素混合。從介面上來看,使用MediaElement元素很直接。但是,也有很多需要說明的地方。下面例舉了5個需要注意的點:

1. 一個應用程式的frame只能包含一個MediaElement!

在一個frame中使用多個MediaElement的做法是不被支援的,而且程式會返回失敗。注意,這種限制比一個頁面使用一個MediaElement還要嚴格;任何時候,只能有一個MediaElement載入到frame上(無論MediaElement是處於停止、暫停或者是播放狀態)。因此,多個頁面只有不同時出現在navigation堆疊的情況下,才能使每個頁面包含各自的MediaElement。否則,如果我們需要播放多個視頻,那麼我們需要複用同一個MediaElement,或者將不使用的MediaElement從element tree中移除。

2. 在將視頻包含到應用程式時,確定其Build Action屬性值設置為Content,而非Resource!

這樣做可以提高視頻啟動的性能。在視頻檔作為資源嵌入時,在其播放前,應用程式會先對其進行加壓縮,然後暫時存放到隔離存儲空間(對於MediaElement使用的音訊檔來說,也同樣需要注意這個問題)。

3. 在MediaElement開始播放時,任何後臺的音訊播放(比如Zune播放的音樂)會暫停!

這正是為什麼MediaElement不被用於播放音效的主要原因。另外,即使視頻檔中沒有包含音訊,這一點也是要注意的。

4. MediaElement在模擬器的light主題下存在Bug!

這聽上去很奇怪,但確實是事實。在模擬器上測試MediaElement,我們必須確保它在dark主題下運行。但是別擔心,這個問題在真機中不存在。

5. MediaElement無法渲染完全不透明的效果!

如果MediaElement中存在其他元素,我們可以通過視頻清楚的看到它們,甚至是MediaElement的Opacity屬性設置為1(該屬性的預設值就是1)。這個是手機的media player(在其內部進行MediaElement的視頻渲染)和Silverlight之間合成的異常。詳見「Windows Phone支援的媒體檔案格式」(連結為HTTP://goo.gl/6NhuD),查看MediaElement支援的視頻格式;以及「推薦的視頻編碼參數設置」(連結為HTTP://goo.gl/ttPkO),查看哪種編碼形式最合適我們的應用。如果我們正在使用Expression Encoder,就可以使用其中專門針對Windows Phone (和 Zune HD)平臺已經預設值的參數來進行視頻編碼。



The User Interface

除了簡介頁面以外(這裡不作介紹),Subservient Cat應用程式使用了另一個頁面,也就是主頁面。主頁面的的root grid包含了三個不同的使用者控制項,如圖33.1所示。

1. 包含視頻播放的 MediaElement元素

2. 一個簡單的「intro screen」,介紹貓咪能夠執行的指令,之後應用程式會播放命令相對應的視頻片段。

3. 具有text box的panel,讓使用者猜測新的指令。

21151642_xyWt  

圖33.1 主頁面中三個主要的使用者控制項

注意:

➔ 視頻播放時,手機處於橫屏模式,所以它只是一個橫屏模式的頁面。但是,text box元素被用來給使用者猜測新的指令,所以背後的代碼暫時改變頁面的SupportedOrientations屬性值,使得焦點位於text box時,兩種螢幕模式都可以使用。這樣一來,具有硬體鍵盤的手機就可以讓使用者獲得更好的體驗。

➔ 應用程式欄具有三個按鈕:一個用於展示指令輸入面板,一個用於導航到簡介頁面,一個用於指示使用者已經發現的指令數量(在背後代碼中更新)。點擊最後一個按鈕還可以提示我們,是否有更多的指令等待我們去發現,因為對於我們使用者來說,指令的總數,是一個謎。應用程式欄功能表是通過代碼進行動態添加的,它包含了使用者已經發現的資訊清單,在使用者點擊其中任何一個指令時,貓咪就會做相應的動作。詳見圖33.2。

21151644_oFsG  

圖33.2 應用程式欄功能表提供快速獲取已發現的資訊清單,例如「yawn」。

➔ 雖然應用程式可以播放不同的視頻片段,但從性能的角度來看,事實上它使用了單個較長的視頻檔(cat.wmv)。背後的代碼會負責選擇其中合適的視頻片段進行播放。

➔ 通過CompositeTransform 來實現MediaElement的移動和擴大,因為「cat.wmv」原始檔案的頭和尾具有一些我們不想看到的黑條。

➔ MediaElement的Volume屬性(值的範圍為0~1)被設置為1(表示最大音量),因為其預設值是0.85。雖然播放的聲音最大只能達到使用者設置的值,但是這就確保了視頻檔中的細節部分(短暫的「喵」叫聲)也能夠被聽到。

注意:確保給MediaElement元素命名!

如果我們沒有給其命名,有可能marketplace發佈審核流程不會發現你使用了MediaElement,因此就不會確保我們的應用程式具有「media library」能力,而這個能力對於本應用程式來說是必須的。



The Code-Behind

➔ 主頁面的建構函式利用possibleCommands方法產生貓咪能夠識別的指令集,該指令集伴隨的聲音用其在「cat.wmv」檔中的起始和終止時程表示。

➔ 在 OnNavigatedTo 事件處理中,使用之前已經發現的指令來填充應用程式欄功能表。這些指令存放在discoveredCommands中,而discoveredCommands又是作為一個設置保存起來。

➔ 為了在應用程式欄按鈕圖示中展示已經發現的指令數量,該應用程式工程中包含了一些圖片,包括appbar.1.png、appbar.2.png和appbar.3.png等等。至於選用哪一個圖片,就需要根據discoveredCommands集合的數量來確定。

➔ 在頁面載入時,視頻就自動開始播放(因為代碼中的AutoPlay屬性沒有設置為false),但是我們不想播放整個視頻來展示貓咪的所有動作。相反,我們只應該播放視頻的前1.5秒。因此,在MediaElement的MediaOpened事件處理函數中(該事件在媒體檔案載入並準備播放時觸發),我們利用videoTimer在視頻播放1.48秒以後進行暫停。該暫停在videoTimer的Tick事件處理函數「VideoTimer_Tick」中完成。

注意:直到MediaOpened事件觸發,我們才能夠在MediaElement中播放視頻!

在設置MediaElement的原始檔案後(在XAML或者背後代碼中都可以完成),我們不能立即與媒體檔案進行交互。相反,我們必須等待MediaOpened事件的觸發。如果由於某些原因,媒體檔案無法載入,那麼MediaFailed事件就會被觸發。Subservient Cat應用程式沒有使用手動調用Play的方法,那是因為它使用了MediaElement的自動播放特性。但如果不使用其自動播放的特性,就必須在MediaElement_MediaOpened事件處理函數中調用Play方法。

注意:為什麼在手機連接到PC機的Zune後,無法播放手機上的視頻?

這個原因其實在前一章中已經解釋過。Zune是一個桌面應用程式,它會鎖定手機的媒體庫,這就導致了MediaElement無法載入媒體檔案。記住,如果我們需要調試應用程式中視頻播放相關的功能,可以使用Windows Phone Developer Tools 中提供的Windows Phone Connect Tool工具來連接手機,而不是通過Zune來連接。

在Subservient Cat應用程式中,我們可以通過MediaFailed事件來檢測這種情況。當然,我們假設這種情況的出現就是由於Zune的連接,因為對於應用程式來說,該視頻檔就是本地的檔。

➔ PlayClip方法可以使視頻暫停,回到beginTime參數指定的起始時間點,重新初始化videoTimer,使得視頻可以在endTime參數制定的終止時間停止播放。但是,由於設置MediaElement的Position會帶來一些不友好的效果,如視頻會快速前進或者快速回退到指定的時間點(而不是即刻的跳轉),應用程式的簡介頁面已經對這種過渡進行了視頻隱藏處理(我們不希望展示哪些有待使用者發掘的視頻片段)。Position的設置在BeginInvoke回呼函數中完成,使得簡介頁面可以進行顯示。如果不是這樣做的話,我們就會看到不想要的情況出現。視頻延時的長度設置為2秒,這段時間可以讓使用者在簡介頁面上流覽指令。我們沒有辦法獲知使用者真實消耗的時間,但2秒鐘已經足夠長的了。

注意:在我們設置MediaElement的Position參數後,效果無法即刻顯現!

相反,我們可以看到目標時間點之前或之後的一小段視頻,就像那種看快進或者是快退的效果。因為Subservient Cat應用程式使用的方法是:暫時採用其他的元素來遮蓋視頻。

在當前的Windows Phone版本中,MediaElement元素並不支援標記。使用標記來區分cat.wmv視頻檔中單獨的視頻片段,這是一個理想的方案,而且還可以大幅度減少背後的處理代碼。但是,使用DispatcherTimer來通知應用程式相關的視頻已經播放完畢,這也是一個可替代的方案。下面是需要注意的兩個事項:

1. 計時器的精度沒有達到「幀」的級別。本應用程式使用的視頻,在每個片段的最後使用了一些緩衝,以防videoTimer的Tick事件觸發滯後。

2. 如果我們想要彈出一個訊息方塊,視頻檔會在後臺繼續播放,但是計時器的Tick事件處理不能被調用。無論視頻播放多長時間,直到訊息方塊解除才能恢復Tick事件處理(MessageBox.Show是一個阻塞的操作)。這正是為何在原始程式碼中,首先使用DiscoveredButton_Click來暫停視頻的播放。

當我開始寫Subservient Cat應用程式的時候,我在OnNavigatedFrom事件中調用了MediaElement的Stop方法,因為在簡介頁面顯示,而主頁面處於堆疊中時,我擔心不必要的視頻播放會引來性能的下降。但是,事實證明這種擔心是多餘的,因為在頁面離開時,MediaElement會暫停所播放的視頻。如果我們不需要這種特性(例如,在其他頁面時,我還想聽到視頻播放的聲音),我們必須將MediaElement附加到某個幀,而不是一個特定的頁面。

MediaElement和隔離存儲空間中的檔

如果想要播放隔離存儲空間中的檔(例如,我們的應用程式下載並將它保存在此處),我們可以調用MediaElement的SetSource方法,該方法以一個流為參數,而不是一個URI。有了它,我們就可以傳入一個合適的IsolatedStorageFileStream。


原文連結:HTTP://www.cnblogs.com/dearsj001/archive/2012/08/21/101App4WP7_SubservientCat.html
 

 

創作者介紹
創作者 shadow 的頭像
shadow

資訊園

shadow 發表在 痞客邦 留言(0) 人氣()