微波EDA网,见证研发工程师的成长!
首页 > 测试测量 > 测试测量技术文库 > Android系统WMA文件播放功能的设计与实现

Android系统WMA文件播放功能的设计与实现

时间:12-18 来源:互联网 点击:

在整个WMA格式解码播放过程中,主要设计有两个模块:WMAExtractor和WMADecoder。WMAExtractor主要执行WMA格式文件解析和数据读取功能。WMADecoder主要执行解码功能;WMA格式音频播放功能实现。

(1)WMA文件的识别。
在判断播放文件格式前,AwesomePlayer会提前把所支持的格式通过DataSource中的RegisterDefaultSniffers函数注册进来。判断播放文件格式时,会逐一按次序把该文件和所支持的格式进行匹配,最匹配的格式就是该文件的格式,所以在Datasource中的RegisterDefauh Sniffers函数中应添加如下代码:

WMA文件开始有一个16 Byte的标识,表示是WMA:30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 62 CE 6C。如果音频文件的前16个字符和这16 Byte相符,那么就可以判断该文件为WMA文件。WMAExtraetor中的SniffWMA函数就是通过读取文件前16 Byte来判断该文件是不是WMA文件。在SniffWMA函数中,如果判断前16 Byte和WMA的16个标识字节相等,就会把MEDIA_MIMETYPE_AUDIO_WMA给mimeType指针,标志着该音频文件类型为WMA格式。MEDIA_MIMETYPE_AUDIO_WMA是在MediaDefs.h文件中定义,在MediaDefs.cpp文件中赋值:

(2)WMA文件的解析。
WMAExtmetor从WMA文件的第31 Byte开始取16 Byte,然后依次和file_header、stream_header、data_header、comment_header、exten-ded_content_header对比,如果和file_header相等,则从下个Byte开始依次获取文件大小、创建时间、数据包个数、…数据包大小。然后再从下个Byte开始读取16 Byte再进行对比,如果和extended_content_header相等,则可以从下个Byte中依次获取名称、艺术家、版权、注释等非音频信息。然后再接着读取16 Byte进行比对,直到和data_eader相等。data_header后就是音频文件解码数据,data_header的结束位置就是第一个数据包在文件中的偏移量。WMAExtractor会创建一个MetaData,并把文件头中获取的sample_rate、Byte_rate、channels、dura-tion都存入MetaData中。在WMAExtractor的getMetaData函数中,把之前获取的非音频信息放入MetaData中,最后返回该MetaData。在WMAEx-tractor的getTrack函数中,创建一个WMASource,并把WMA数据和MetaData传给WMASource。
(3)编码数据的读取。
获取未解码数据是通过WmASource的read函数读取的。WMA数据是以数据包为单位的,同文件中的数据包大小相同。每个数据包中有多帧数据,每个数据包的起始位置减去第—个数据包的起始位置再除以包的大小等于一个整数,这个整数就是该数据包之前数据包的个数。每个数据包的第一个Byte一般都等于0x82。第二个Byte以后是该数据包的相关信息。根据包的相关数据就可以获取该包中的未解码数据。
WMASource的read读取未解码数据时,首先会判断从WMADecoder传来的options是否为空,如果不为空,并可以从options中获取一个播放时间seekTimeUs,就通过seekTimeUs、总播放时间和总数据包的个数算出要播放数据包的起始位置,然后从该起始位置获取一个数据包的数据,并从该数据包中获取有效数据的大小、起始位置、时间等数据,最后把该有效数据和时间放在WMADecoder传来的Buffer里。
WMASource的Read被调用时,如果传来的Options为空或是不能从Options中获取时间seekTimeUs,就会从WMA文件中读取一个数据包,根据其中的有效数据的大小、起始位置获取有效数据,并获取该数据包中的时间,然后把该有效数据和时间放在WMADecoder传来的buffer里。第一个数据包的起始位置就是解析头文件时获取的第一个数据包的偏移量,所以第一次调用WMASource的read时,就是从这个偏移量的下个位置读取第一个数据包的。在WMASource中有一个专门记录读取位置的指针。每次读取1个数据包后,该指针就会指向数据包末尾的下一个位置,当下一次WMASource的read读取未解码数据时,如果不是音乐定点播放,就会从该指针所指的位置开始读取数据包。

(4)编码数据的解码和输出。
AwesomePlayer通过OMXCodec中的Create函数创建WMADecoder,所以在OMXCodec中注册WMADecoder的相关信息:

在创建WMADecoder时,把之前创建的WMASource传给WMADecoder。在WMADecoder构造函数中,WMADecoder从WMASource中获取Metadata,并从Metadata获取sampleRate、numChannels、duration等。在WMADecoder的start函数中,通过调用avcodec_open函数,来分配解码所需的空间、创建并初始化解码所需的相关参数。在WMADecoder析构函数中会调用WMADecoder的Stop函数。在Stop函数中会释放所有相关空间。
WMA音频解码主要是在WMADecoder的read函数中完成的:首先,先会判断是否是音乐定点播放,如果不是,WMADecoder会调用WMAExtrac-tor的read函数读取一个未解码的数据包;然后,对该数据进行解码,将解码后的音频数据存放在MediaBuffer的Data()中,再设置MediaBu-ffer的mRangeOffset和mRangeLength,在读取数据包时会从包中获取该数据包中的时间戳,把该时间戳存放在MediaBuffer的Meta_ data()中的kKeyTime里;最后,WMAdecoder把该MediaBuffer传回给AudioPlayer。如果是音乐定点播放,首先,WMADecoder会从AudioPtayer传过来的ReadOption中获取播放时间(option->getSeekTo(seekTimeUs,mode)),在调用WMASource的read函数来读取未解码音频数据时会把该时间(seekTimeUs)传给WMASource。WMASource的read函数获取到该时间后,通过计算得出该时间要播放的音频数据包的起始位置,然后读取该数据包并传给WMADecoder对其进行解码,最后将该解码后的音频数据传给AudioPlayer。

3 实验结果
基于Android平台的多媒体系统进行设计的WMA音频播放,在Android多媒体框架的本地实现核心Stagefright框架里,添加WMA音频格式。实现Android对WMA音频格式的支持,使Android手机可以播放WMA音频格式的文件。经过实际测试,播放效果达到了预期的要求,声音清晰、音质好。图4为增加WMA音频播放模块后Android源码编译结果的截图。图5为播放WMA格式文件时对播放界面的截图。图6为拉动滚动条后正常运行的截图。

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top