开源一个用于在Windows Phone上播放FLV视频文件的库
事实上早在2013年的时候博主就实现了不依赖任何第三方库
在WP8上播放FLV格式的视频文件(见这篇文章),只不过当时没有将源代码开放出来。时间过去了将近两年,但是似乎在GitHub上依然没有开源的方便易用的这方面的库,所以博主决定将这个库重写一遍开源出来。代码托管在GitHub
这个库支持Windows Phone Silverlight应用和Windows Runtime Universal应用,前者面向Windows Phone 8+,后者面向Windows Phone 8.1+和Windows 8.1+。
如何使用
这个库以简单易用为设计目标,在你的项目中使用这个库只需要写数行代码。
假设我们有一个MediaElement
控件,将其命名为mediaElement,并且在应用的安装目录下Assets文件夹中存在test.flv。
在Windows Phone Silverlight应用中需使用DawnPlayer.FlvMediaStreamSource
1 | var applicationFolder = Windows.ApplicationModel.Package.Current.InstalledLocation; |
在Windows Runtime Universal应用中需使用dawn_player.flv_media_stream_source
1 | var applicationFolder = Windows.ApplicationModel.Package.Current.InstalledLocation; |
实现细节
目前互联网上绝大多数的FLV格式的视频文件都是使用H.264(AVC)
作为视频编码,使用AAC
作为音频编码。对于同样使用这两种编码的MP4文件可以直接使用MediaElement进行播放,而FLV文件则不行。从MSDN上的文档可以知道H.264和AAC都在Windows Phone支持的编码之列。MediaElement之所以能够直接播放MP4文件是因为Windows Phone知道如何从MP4文件中分离出音、视频数据并对其各自进行解码和播放,但是Windows Phone并不知道如何从FLV文件中分离出音、视频数据。在这里MP4和FLV就好比是容器,将相同编码的音、视频数据以不同的格式封装成一个视频文件。
幸运的是,Windows Phone Silverlight(下文简称WPSL)和Windows Runtime(下文简称WinRT)都提供了一种叫MediaStreamSource
的机制,允许由应用程序来做音、视频的分离工作,然后将分离出来的音、视频Sample发送到媒体管道由系统来负责解码和播放,以此来移除容器相关,播放原本所不支持的容器格式。
这个库由以下这些部分组成:
一个AMF(Action Message Format)的解码器amf_decode.hpp
FLV的file body是由一个个的tag组成的,tag分为audio tag、video tag和script tag三种。script tag中有一个叫onMetaData的tag,当中包含了视频文件的时长、宽、高等元信息(meta data),这些信息使用AMF进行编码。这个AMF的解码器就是用来解析这些元信息的。此外对于一个用于在线播放的FLV文件,这个元信息通常还包含了一个名为keyframes的民间标准对象,这个对象存储着关键帧到关键帧所在tag文件偏移的映射表。一个FLV文件的解析器flv_parser.hpp
这是一个完全依照 _FLV Video File Format Specification Version 10_,使用纯C++实现,兼具性能和可移植性的FLV文件格式解析器,内部使用前面所说的AMF解码器来解码元信息。使用这个解析器解析前需要先注册感兴趣的解析事件,当解析器解析到特定的数据时会调用对应的回调函数。支持的解析事件包括on_script_tag
当解析成功一个script tag时会触发,注册这个事件以获取FLV视频的元信息。on_audio_specific_config
当解析成功一个AAC sequence header时会触发,注册这个事件以获得AudioSpecificConfig(ISO/IEC 14496-3)。这个AudioSpecicifConfig含有声道数(channel count)、采样率(sample rate)、比特率(bit rate)等信息。这些信息用于在Windows Phone Silverlight中构造AudioCodecPrivateData,在Windows Runtime中构造AudioEncodingProperties。on_avc_decoder_configuration_record
当解析成功一个AVC sequence header时触发,注册这个事件以获得SPS(sequence parameter set)和PPS(picture parameter set)。SPS和PPS可以用于构造VideoCodecPrivateData。on_audio_sample
当解析成功一个audio tag且获取到audio sample时触发,注册这个事件以接收audio sample。on_video_sample
当解析成功一个video tag且获取到video sample时触发,注册这个事件以接收video sample。一个分离控制器flv_player.hpp
这个分离器控制器负责调用分离器分离从文件中读取到的数据,以及处理打开、缓冲、seek等操作。在内部维护一个常驻线程和多个池化线程,绝大多数对外接口都是异步的。一个MediaStreamSource
虽然WPSL和WinRT都支持MediaStreamSource,但是这种机制的实现方式却大不相同(尽管如此DawnPlayer还是在WPSL和WinRT上共用了前面的解码器、分离器和控制器的全部代码)。在WPSL中是将分离控制器flv_player封装成FlvMediaStreamSource,这个类继承自抽象类MediaStreamSource,并实现了OpenMediaAsync、GetSampleAsync、SeekAsync和CloseMedia等方法。
而在WinRT中MediaStreamSource既不是抽象类也无法继承它(声明为sealed)。取而代之的是事件订阅机制。所以在WinRT中博主的做法是将分离器控制器封装成flv_media_stream_source,由这个类来处理订阅的Starting和SampleRequested等事件。