今天在開發過程中遇到了圖片載入器與視頻播放器無法正常讀取媒體資源的問題。
在代碼中 圖片路徑是正確的,圖片無法正常讀出。而視頻部分採取相同的代碼,卻可以正常讀出。
讀取圖片代碼如下:
讀取視頻代碼如下:
其中2個的地址相似都為:/Assets/XXXX/XXX.XXX
讀取圖片錯誤資訊如下:
後對比視頻檔案與圖片檔案時發現問題。
原來圖片和視頻的產生操作(build action)設定有差別。
視頻的為:內容(content) 圖片的為:Rescoure
查閱MSDN後發現,兩種產生操作最後擷取資源有很大的差異,並且對效能有很大影響。
首先介紹build action
Action |
說明 |
None |
資源既不會被整合到程式集內,也不會打包到xap包中。不過我們可以通過設定CopyToOutputDirectory選項讓其自動拷貝到xap包所在目錄。 這種情況下, 訪問這個圖片的相對Uri需要以"/"開始。 適用情境:在大多數情況下,我們希望把video/audio檔案放到xap的外面,因為這種檔案一般都比較大,會影響silverlight應用的載入,而且一般的視頻音頻檔案都是壓縮格式的,放到xap中也不會起到減少他們檔案大小的作用。 類似圖片視頻這種資源檔產生操作為None時和他們沒有被添加到項目裡是一樣的,都可以用絕對Uri進行引用。 |
Compile |
不適合用於資源檔。類檔案要用"Compile"產生操作, 就是指項目裡.cs或.vb檔案。 |
Content |
資源會被打包在Xap包裡面。這種情況下, 訪問這個圖片的相對Uri需要以"/"開始。在這種方式下,如果沒有在xap中找到圖片檔案,那麼silverlight會自動從當前xap應用所在的檔案夾下來找所需圖片檔案, 如果還沒有找到那麼就觸發ImageFailed事件, 這種方式比較適合在多個程式集引用相同檔案時採用。 |
Embedded Resource |
這種方式會把檔案嵌入到程式集中,Silverlight無法通過Uri引用在xaml和C#裡對這個檔案進行使用,微軟不建議在Silverlight採用這種方式在程式集裡嵌入資源。如果有這種需求可以用Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream(string path)相關的方法得到檔案的Stream引用。 |
ApplicationDefinition |
Silverlight程式的入口xaml檔案(預設就是App.xaml)應該設定為這個"應用定義"。其他檔案都不適合用這個。 |
Page |
不適合用於資源檔。所有的使用者控制項,頁面和子表單(Usercontrol/Page/Childwindow)的xaml檔案應該採用的產生操作。 如果改為別的方式那麼會導致後台對應的代碼檔案無法連結到這個xaml檔案。 採用"Page" build action時xaml裡的錯誤會導致工程無法正確產生。 |
CodeAnalysisDictionary |
程式碼分析使用,Silverlight中可以忽略 |
Resource |
資源會被打包在程式集內部。 選擇這種產生方式後,該資源檔會被嵌入到該應用的程式集中,就是說開啟產生的xap是看不到這個檔案的。 可以用相對於當前的XAML檔案的相對Uri訪問,<Image Source="sl.png" />或是<Image Source="./sl.png" />, 在子檔案夾裡的可以用<Image Source=”./images/sl.png” />訪問到。最保險的方式是採用特有的程式集資源URI訪問,格式為 <Image Source="/{assemblyShortName};component/sl.png"/>,這種方式還可以引用到xap中的其他程式集中的圖片。這種產生方式的系統資源可以直接用Application.GetResourceStream(uri).Stream在代碼裡來得到。 |
SplashScreen |
"SplashScreen"是這個選項是WPF的啟動畫面使用的。Silverlight啟動載入畫面是用的其他方式實現的,所以在Silverlight裡不要用這個方式。 |
EntityDeploy |
這個是EntityFramework採用的產生方式,在Silverlight裡是沒用。 |
需要關注的是,對於媒體資源通常使用Content與Resource兩種不同的方式。
採取Content時,資源會被打包在Xap包裡面。這種情況下, 訪問這個圖片的相對Uri需要以"/"開始。在這種方式下,如果沒有在xap中找到圖片檔案,那麼silverlight會自動從當前xap應用所在的檔案夾下來找所需圖片檔案, 如果還沒有找到那麼就觸發ImageFailed事件, 這種方式比較適合在多個程式集引用相同檔案時採用。
擷取媒體資源方式:直接採用/檔案夾/檔案即可擷取到資源檔。
採用Resource時,資源會被打包在程式集內部。 選擇這種產生方式後,該資源檔會被嵌入到該應用的程式集中,就是說開啟產生的xap是看不到這個檔案的。 可以用相對於當前的XAML檔案的相對Uri訪問,<Image Source="sl.png" />或是<Image Source="./sl.png" />, 在子檔案夾裡的可以用<Image Source=”./images/sl.png” />訪問到。最保險的方式是採用特有的程式集資源URI訪問,格式為 <Image Source="/{assemblyShortName};component/sl.png"/>,這種方式還可以引用到xap中的其他程式集中的圖片。這種產生方式的系統資源可以直接用Application.GetResourceStream(uri).Stream在代碼裡來得到。
擷取媒體資源方式:/{assemblyShortName};component/sl.png 的方式來擷取,其中assemblyShortName為程式集名稱。
本次問題中,針對圖片檔案使用了 Resource,而視頻檔案使用了Content。所以出現了問題。
在MSDN中說明,出於效能考慮,媒體資源需要設定為 內容(Content),說明如下:
對 Windows Phone 上的ApsaraVideo for Media Processing進行最佳化以使用檔案和網路流,而不是使用記憶體中的流。這意味著應用程式中包括的任何媒體檔案(例如聲音效果)應該將其“產生操作”設定為“內容”而不是“資源”。當媒體檔案作為內容編譯時間,它會作為鬆散檔案與應用程式檔案 (.XAP) 一起儲存,而不是儲存在應用程式檔案中。當媒體檔案作為資源編譯時間,通常通過檢索檔案流來訪問,這可能會降低效能。此外,當播放編譯為內容的媒體檔案時,會直接進行播放。當媒體檔案作為資源編譯時間,播放之前需要將內容複寫到 Windows Phone 上的檔案,這會降低效能。
參考地址:http://msdn.microsoft.com/zh-cn/library/ff967560(v=VS.92).aspx
http://www.cnblogs.com/listenfly/archive/2011/11/03/2235059.html