(3) 编码数据的读取。
获取未解码数据是通过WMASource 的read 函数读取的。WMA 数据是以数据包为单位的,同文件中的数据包大小相同。每个数据包中有多帧数据,每个数据包的起始位置减去第一个数据包的起始位置再除以包的大小等于一个整数,这个整数就是该数据包之前数据包的个数。每个数据包的第一个Byte 一般都等于0x82.第二个Byte 以后是该数据包的相关信息。
根据包的相关数据就可以获取该包中的未解码数据。
WMASource 的read 读取未解码数据时,首先会判断从WMADecoder 传来的options 是否为空,如果不为空,并可以从options 中获取一个播放时间seek-TimeUs,就通过seekTimeUs、总播放时间和总数据包的个数算出要播放数据包的起始位置,然后从该起始位置获取一个数据包的数据,并从该数据包中获取有效数据的大小、起始位置、时间等数据,最后把该有效数据和时间放在WMADecoder 传来的Buffer 里。
WMASource 的Read 被调用时, 如果传来的Options 为空或是不能从Options 中获取时间seek-TimeUs,就会从WMA 文件中读取一个数据包,根据其中的有效数据的大小、起始位置获取有效数据,并获取该数据包中的时间,然后把该有效数据和时间放在WMADecoder 传来的buffer 里。第一个数据包的起始位置就是解析头文件时获取的第一个数据包的偏移量,所以第一次调用WMASource 的read 时,就是从这个偏移量的下个位置读取第一个数据包的。在WMASource 中有一个专门记录读取位置的指针。每次读取1 个数据包后,该指针就会指向数据包末尾的下一个位置,当下一次WMASource 的read 读取未解码数据时,如果不是音乐定点播放,就会从该指针所指的位置开始读取数据包。
(4) 编码数据的解码和输出。
AwesomePlayer 通过OMXCodec 中的Create 函数创建WMADecoder,所以在OMXCodec 中注册WMADecoder的相关信息:
FACTORY_CREATE( WMADecoder)
…
static sp < MediaSource > InstantiateSoftwareCodec(const char * name,const sp < MediaSource >&source) {
…
static const FactoryInfo kFactoryInfo[]= {
…
FACTORY_REF( WMADecoder) } } ;
…
static const CodecInfo kDecoderInfo[]= {
…
{ MEDIA_MIMETYPE_AUDIO_WMA,“WMADecoder”}
} ;
在创建WMADecoder 时,把之前创建的WMASource传给WMADecoder.在WMADecoder 构造函数中,WMADecoder 从WMASource 中获取Metadata,并从Metadata 获取sampleRate、numChannels、duration等。在WMADecoder 的start 函数中,通过调用avcodec_open 函数,来分配解码所需的空间、创建并初始化解码所需的相关参数。在WMADecoder 析构函数中会调用WMADecoder 的Stop 函数。在Stop 函数中会释放所有相关空间。
WMA 音频解码主要是在WMADecoder 的read 函数中完成的: 首先,先会判断是否是音乐定点播放,如果不是,WMADecoder 会调用WMAExtractor 的read函数读取一个未解码的数据包; 然后,对该数据进行解码,将解码后的音频数据存放在MediaBuffer 的Data( ) 中, 再设置MediaBuffer 的mRangeOffset 和mRangeLength,在读取数据包时会从包中获取该数据包中的时间戳,把该时间戳存放在MediaBuffer 的Meta_ data ( ) 中的kKeyTime 里; 最后,WMAdecoder把该MediaBuffer 传回给AudioPlayer.如果是音乐定点播放,首先,WMADecoder 会从AudioPlayer 传过来的ReadOption 中获取播放时间( option - > getSeekTo( &seekTimeUs,&mode ) ) , 在调用WMASource 的read 函数来读取未解码音频数据时会把该时间( seek-TimeUs) 传给WMASource.WMASource 的read 函数获取到该时间后,通过计算得出该时间要播放的音频数据包的起始位置,然后读取该数据包并传给WMADecoder对其进行解码,最后将该解码后的音频数据传给AudioPlayer.
3 实验结果
基于Android 平台的多媒体系统进行设计的WMA 音频播放,在Android 多媒体框架的本地实现核心Stagefright 框架里,添加WMA 音频格式。实现Android 对WMA 音频格式的支持,使Android 手机可以播放WMA 音频格式的文件。经过实际测试,播放效果达到了预期的要求,声音清晰、音质好。图4 为增加WMA 音频播放模块后Android 源码编译结果的截图。图5 为播放WMA 格式文件时对播放界面的截图。图6 为拉动滚动条后正常运行的截图。
图4 Android 源代码编译结果
图5 WMA音频文件播放
图6 WMA音频文件播放
4 结束语
基于Android 多媒体模块中的Stagefright 框架,在智能手机上实现了对WMA 音频格式的支持,使Android 智能手机可以播放WMA 音频格式的媒体文件或流媒体。该设计在现有基础上实现了对Android操作系统中多媒体系统功能的增强。目前Android 平台手机仍然不支持RMVB、WAV 等视频格式,所以Android 多媒体系统的功能还需继续增强和扩展。