因為項目的需要,近日調研了一下在 Windows Phone 手機上播放H264裸碼流的方法,期間參考了大量的網絡資源,最終得以解決這個問題,對如此具有鑽研和奉獻精神的他們表示誠摯的感謝!
在查閱資料的過程中,首先遇到的比較頭疼的問題就是太多的資料都是講述如何在SilverLight頁面上解碼HVU或H264數據呈現音視頻,雖然將這些代碼移植到 WP7 上很簡單,但是要呈現出視頻就不是那么簡單了,偶再一次的在這個問題上磨練了心智。書歸正傳,在移植過程中,總共遇到兩個大的問題,第一個是在模擬器上怎么也呈現不出視頻,第二個是在模擬器上呈現出視頻后,在真機上怎么也顯不出視頻。我擦,真的很凄慘啊,搞的偶吃不香睡不香,期間備受折磨啊,嗚嗚!
首先說第一個問題,在模擬器上顯示視頻。根據前輩們的指點,兩個條件是必須的:MediaElement控件和用來設置MediaElement數據源的繼承自MediaStreamSource的類(暫時命名為H264MediaStreamSource吧)。在調研這個問題時,我仔細閱讀了“在 Silverlight 應用程序中實現對 FLV 視頻格式的支持”這片文章,其中“如何解碼 FLV 文件中的 H.264 視頻流”這段研讀的很仔細,不過之后移植到Windows Phone 手機程序上,模擬器不顯視頻的原因也出自這里,因為作者的程序是Silverlight 應用程序,正如文中所言,一些屬性是不需要設置的,但是在Windows Phone程序中,這些屬性就必須設置了,譬如MediaSampleAttributeKeys和MediaStreamAttributeKeys枚舉中的寬高值。經過驗證,即便是在XAML里面設置了MediaElement的寬高值,如果在H264MediaStreamSource里面不設置MediaSampleAttributeKeys和MediaStreamAttributeKeys枚舉中的寬高值,再怎么樣在模擬器中也是顯示不了視頻圖像的。重載方法OpenMediaAsync的代碼如下:
protected override void OpenMediaAsync()
{
emptyDict[MediaSampleAttributeKeys.FrameWidth] = width.ToString();
emptyDict[MediaSampleAttributeKeys.FrameHeight] = height.ToString();
Dictionary<MediaStreamAttributeKeys, string> videoStreamAttributes = new Dictionary<MediaStreamAttributeKeys, string>();
videoStreamAttributes[MediaStreamAttributeKeys.CodecPrivateData] = "";
videoStreamAttributes[MediaStreamAttributeKeys.VideoFourCC] = "H264";
videoStreamAttributes[MediaStreamAttributeKeys.Width] = width.ToString();
videoStreamAttributes[MediaStreamAttributeKeys.Height] = height.ToString();
this.videoStreamDescription = new MediaStreamDescription(MediaStreamType.Video, videoStreamAttributes);
Dictionary<MediaSourceAttributesKeys, string> mediaSourceAttributes = new Dictionary<MediaSourceAttributesKeys, string>();
mediaSourceAttributes[MediaSourceAttributesKeys.Duration] = "0";
if (stream.CanSeek)
{
mediaSourceAttributes[MediaSourceAttributesKeys.CanSeek] = "1";
}
else
{
mediaSourceAttributes[MediaSourceAttributesKeys.CanSeek] = "0";
}
List<MediaStreamDescription> mediaStreamDescriptions = new List<MediaStreamDescription>();
mediaStreamDescriptions.Add(this.videoStreamDescription);
this.ReportOpenMediaCompleted(mediaSourceAttributes, mediaStreamDescriptions);
}
第二個問題是在關於在模擬器上能顯示視頻圖像,但是真機中不能顯示的問題,直接的現象就是怎么也不進GetSampleAsync這個接口!網上查了很久,好多老外也為這個問題糾結額,解決方法也是無意嘗試中得知:就是OpenMediaAsync這個方法中的一句話需要改變下而已,嗚嗚,天殺的!將videoStreamAttributes[MediaStreamAttributeKeys.CodecPrivateData] = ""的值改成你H264裸碼流第一幀中的SPS+PPS,類似於videoStreamAttributes[MediaStreamAttributeKeys.CodecPrivateData] = "000001674D4015965301004A2000000168E9238800",具體根據你的實際數值而定。
無論如何,解碼H264裸數據的問題總算解決了,接下來的必定還有好多未知的難題待解,戒驕戒躁,繼續加油咯!