【Android源码 栏目提醒】:网学会员为广大网友收集整理了,Android系统WMA文件播放功能 - 综合课件,希望对大家有所帮助!
Android系统WMA文件播放功能 摘要为增强
Android 多媒体系统的功能在
Android 智能手机上添加WMA 音频播放功能使
Android 平台支持WMA 格式播放WMA 格式文件。
基于
Android 多媒体系统的STagefright 框架通过创建WMA 的文件解析单元和解码单元使WMA 音频文件中的编码数据被正确地解码成原始数据并输出。
通过在
Android 平台测试机上反复播放WMA 音频文件播放声音清晰、音质良好。
WMA 可用于多种格式的编码文件中。
微软公司在WMA9 中大幅改进了其引擎实际上几乎可以在同文件同音质下比MP3 体积约小1 /3因此适合用于网络串流媒体及行动装置。
许多播放器软件也纷纷开发出支持WMA 格式的插件程序来但
Android 手机尚未支持该格式故在
Android 手机中添加WMA 音频解码格式具有一定意义。
1
Android 平台及其多媒体框架结构 1. 1
Android 系统
Android 是Google 与OHA Open HandsetAlliance 推出的开源手机操作系统。
Android 基于Linux 平台由操作系统、中间件、用户界面和应用软件组成。
Android 平台自底向上由4 个层次组成 Linux 内核层、运行时库和其他库层、应用框架层、应用程序层。
1 Linux Kernel.
Android 底层是一个基于Linux2. 6 内核来开发的独立操作系统该层主要用于提供系统的底层服务包括安全机制、内存管理、进程管理、网络堆栈和驱动等。
2 Libraries 和
Android Runtime.这一层主要与进程运行相关包含了一套C/C 函数库主要包括Libc、Media、FrAMEwork、WebKit、SGL、OpenGLES、FreeType、SQLite 等。
核心库提供了Java 编程核心库的大多数功能这些功能通过
Android 应用框架展现给开发人员另外每一个
Android 程序都有独立的Dalvik虚拟机为它提供运行环境。
3 ApplicatiON Framework.该层是
Android 平台专为应用程序开发而设计的。
开发者通过使用核心应用程序调用
Android 框架提供的API这个应用程序结构被设计成方便复用的组件该层由一系列的服务和系统构成。
4 Applications.
Android 本身附带一些核心的应用程序包 例如Email 客户端、浏览器、日历、Google 地图、SMS 短消息程序等。
1. 2 媒体播放器结构及多媒体实现的核心
Android 多媒体系统纵向跨越了
Android 系统的所有4 个层次 Java 应用程序层、Java 框架层、本地代码层、Linux 驱动层。
多媒体本地代码层是多媒体系统的重点。
Libmedia 库提供多媒体部分的本地框架Libstagefright 提供多媒体核心功能的实现。
图1
Android 媒体播放器的模块结构 上层的应用程序将媒体的URI 作为输入设置到媒体播放器中再经过应用框架、JNI 和本地框架一直到设置到StagefrightPlayer 中。
在这个过程中没有数据流的传递只是传递了URI 路径。
经Stagefright-Player 中的解析单元进行解析后读取音频流经过解码器的处理转换成原始数据。
音频原始数据将被送到音频输出环节中。
Stagefright 是
Android 多媒体本地实现的核心。
Stagefright 中包括的内容很多单从播放的角度来看StagefrightPlayer 输入的是文件或网络媒体流输出的是音视频输出设备基本功能包括了媒体流控制、文件解析、音视频文件解码等方面。
所以要实现
Android多媒体对WMA 音频格式媒体文件或流媒体的播放就需要扩展Stagefright 中的文件解析和音频解码等方面添加WMA 格式的文件解析单元和WMA音频文件解码单元。
2 多媒体系统增加WMA 音频格式的设计 从多媒体系统具体实现的角度来看WMA 音频格式播放主要经过WMA 格式文件解析、WMA 编码流解码、PCM 输出播放3 个阶段。
WMA 音频播放器的结构如图2 所示。
图2 WMA 音频播放器的结构 基于
Android 多媒体系统音频播放流程 在WMA 音频格式开发过程中主要有4 项工作 1 WMA文件的识别 2 WMA 文件的解析 3 编码数据的读取 4 编码数据的解码和输出。
2. 1 WMA 格式音频播放功能流程设计 通过调用AwesomePlayer 的setDataSource 函数来设置数据源 AwesomePlayer 通过调用MediaExtractor的Create 函数来识别该文件的格式MediaPlayer 判断该文件为WMA 格式后会创建一个WMAExtractor在创建WMAExtractor 的同时WMAExtractor 会解析文件头获取文件中的相关信息。
然后调用WMAExtractor的getTrack 函数创建一个WMASourceAwesomePlayer通过OMXCodec 创建一个WMADecoderAwesomePlayer 接着创建一个audioPlayer并把WMADecoder 做为数据源传给AudioPlayer并调用AudioPlayer 的start 函数 AudioPlayer 获取WMADecoder中的相关参数 文件类型、采样率、声道数并根据该数据开启AudioSink并把AudioSinkCallback做为回调函数传给AudioSink.AudioPlayer 先调用WMADecoder 解第一帧数据 并把该数据传给AudioSink去播放当播放完成后AudioSink 会调用回调函数AudioSinkCallback 再取解码后的数据AudioSinkCallback又会调用FillBuffer 函数获取解码后的原始数据解码后数据如果被取完后AudioPlayer又会调用WMADecoder 解下一帧数据给AudioSink来回反复直到文件中数全部被播放播放流程如图3所示。
在拉动滚动条时上层会传来SeekTime经AudioPlayer 传给WMADecoder 再传给WMAExtractorWMAExtractor 根据上层传来的SeekTime 判断出要播放的原始数据的起始位置然后从该位置读取一个数据包传给WMADecoder 解码。
图3 音频播放流程图 在整个WMA 格式解码播放过程中主要设计有两个模块 WMAExtractor 和WMADecoder.WMAExtractor主要执行WMA 格式文件解析和数据读取功能。
WMADecoder 主要执行解码功能 WMA 格式音频播放功能实现。
1 WMA 文件的识别。
在判断播放文件格式前AwesomePlayer 会提前把所支持的格式通过DataSource 中的RegisterDefault-Sniffers 函数注册进来。
判断播放文件格式时会逐一按次序把该文件和所支持的格式进行匹配最匹配的格式就是该文件的格式所以在Datasource 中的RegisterDefaultSniffers 函数中应添加如下代码 void DataSource: : RegisterDefaultSniffers …… RegisterSniffer SniffWMA WMA 文件开始有一个16 Byte 的标识表示是WMA: 30 26 B2 75 8E 66 CF 11 A6 D9 00 AA 62 CE6C.如果音频文件的前16 个字符和这16 Byte 相符那么就可以判断该文件为WMA 文件。
WMAExtractor中的SniffWMA 函数就是通过读取文件前16 Byte 来判断该文件是不是WMA 文件。
在SniffWMA 函数中如果判断前16 Byte 和WMA 的16 个标识字节相等就会把MEDIA_MIMETYPE _AUDIO_WMA 给mime-Type 指针标志着该音频文件类型为WMA 格式。
MEDIA_MIMETYPE_AUDIO_WMA 是在MediaDefs. h文件中定义在MediaDefs. cpp 文件中赋值 Extern const char MEDIA_MIMETYPE_AUDIO_WMA / /在MediaDefs. h 头文件中 const char MEDIA_MIMETYPE_AUDIO_WMA audio /wma / /MediaDefs. cpp 头文件 2 WMA 文件的解析。
WMAExtractor 从WMA 文件的第31 Byte 开始取16 Byte然后依次和file_header、stream_header、data_header、comment_header、extended_content_header 对比如果和file_header 相等则从下个Byte 开始依次获取文件大小、创建时间、数据包个数、…数据包大小。
然后再从下个Byte 开始读取16 Byte 再进行对比如果和extended_content_header 相等则可以从下个Byte 中依次获取名称、艺术家、版权、注释等非音频信息。
然后再接着读取16 Byte 进行比对直到和data_header 相等。
data_header 后就是音频文件解码数据data_header 的结束位置就是第一个数据包在文件中的偏移量。
WMAExtractor 会创建一个MetaData并把文件头中获取的sample_rate、Byte_rate、channels、duration都存入MetaData 中。
在WMAExtractor 的getMeta-Data 函数中把之前获取的非音频信息放入MetaData中 最后返回该MetaData.在WMAExtractor 的getTrack 函数中创建一个WMASource并把WMA 数据和MetaData 传给WMASource. 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 InstantiateSoftwareCodecconst char nameconst sp MediaSource source … static const FactoryInfo kFactoryInfo … FACTORY_REF WMADecoder … static const CodecInfo kDecoderInfo … MEDIA_MIMETYPE_AUDIO_WMAWMADecoder 在创建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 seekTimeUsmode 在调用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 多媒体系统的功能还需继续增强和扩展。