Windows Phone 实时播放H264裸码流
因为项目的需要,近日调研了一下在 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裸数据的问题总算解决了,接下来的必定还有好多未知的难题待解,戒骄戒躁,继续加油咯!