MP3播放程序简单记录

关键词:SPL,Mini2440,嵌入式,软件产品线
作者:BIce 创建时间:2012-05-27 01:32:42

 

最近由于论文的需要,做了一个简单的嵌入式播放器程序,程序于本周五大体完成。在开发过程中遇到了一些问题,遂在进行下一项工作前先简单对这个小项目进行下总结。

1.    开发环境

1.1 硬件环境

         既然是嵌入式程序,理所应当的需要硬件的支持,本项目的开发采用友善之臂的Mini2440开发板作为硬件平台。所用到的部件主要有:板上按键(6个)、LCD触摸屏、音频录制播放设备。

1.2 软件环境

         由于之前对嵌入式开发涉猎的比较少,仅仅在实验课上对C51Arm编程有简单的了解,本次开发选取了比较简单的开发方式。

1)    本次开发中是在目标载体操作系统上进行开发的(Mini2440自带的Linux 2.6操作系统),不是裸机开发。

2)    程序界面使用Qtopia 2.0进行开发(内置QT 2.3)。

3)    开发环境使用Ubuntu进行,配置了交叉编译环境和VI环境。

4)    程序的播放功能使用了板上自带的madplay和对mini2440进行移植的mplayer,没有进行实际播放解码的程序书写。

2. 主要方面

         本次要开发的MP3播放程序是一个软件产品线的样例系统,主要设计的功能有三个,音频播放,视频播放,以及录音功能。这三个功能都是播放器常用功能,功能需求就不再赘述,主要说下每部分的大体实现方式和遇到的问题。

2.1 输入板上按键

         播放器的输入有两个部分,一个是触摸屏的输入,一个是板上六个按键,由于我们使用了Qtopia,它自己已经完成了对触摸屏的输入转换,所以这部分不用我们操心,而主要需要做的是板上按键的输入处理。

         板上按键Mini2440已经提供了驱动,主要操作的接口即为文件/dev/buttons,我们可以通过轮询的方式来获取按键的状态,但是由于我们使用了QT框架,而QT又使用了比较特别的桩、插槽机制,就需要将按键与QT相结合起来,这是我遇到的第一个个问题。经过调研,主要的解决方案有两个:

1)   使用QT QWS Server方式来对/dev/buttons进行扫描处理,捕获板上按键状态,再进行对应的事件处理。

2)   将板上按键转化为标准的Linux键盘事件,也就是Linux模拟标准键盘事件(将板上按键转化为1~6的数字键按键)。在QT中对对应的标准按键进行处理即可,比较方便(解耦合哇)。

在实际的使用中,第一种方式由于需要和QT进行比较深度的整合,再加之我对QT不是很熟悉,QWS方式的实验未通过,没有成功,即选用了第二种方法

Windows不同,Linux下的键盘模拟方式没有像Windows下的sendMessage()函数这么方便,它的大体的思路是先创建一个虚拟键盘设备,挂接到Linux上(模拟事件的前提是要有键盘设备,如果是普通机器的话,肯定有键盘设备,就不用创建虚拟设备了,但是由于开发板没有键盘设备,就需要模拟一个键盘设备给操作系统),然后通过一个线程(或者进程)对/dev/buttons进行轮询,扫描板上按键的状态,然后向此虚拟设备写入对应的键盘事件信息,进而对键盘事件进行模拟。

在模拟创建Linux键盘设备供系统使用上,我使用了UInput模块User Lever Input:一种模拟各种Linux设备的程序,在2.6内核已经被整合到内核中),但是Mini2440默认的系统是没有包含这个扩展的,需要我们进行二次编译,方法有两种,一种是重新编译内核,一种是以模块的方式编译Uinput模块,由于没有编译过Linux内核,遂选择模块的编译方式。在Linux内核源码目录中修改.config文件(可借助make menuconfig命令),找到User Lever Input选项,选择模块编译UInput,执行make modules即可编译好uinput.ko模块文件,通过拷贝的方式将此文件传至开发板,执行insmod uinput.ko命令加载uinput.ko内核模块,我们就可以正常的使用uinput了。具体的使用见网上,不再列出。

至此,我们通过对将板上按键模拟成标准Linux键盘事件,再由QT进行键盘事件的绑定,完成了对Mini2440上按键的处理

2.2 音频输出

         在音频的输出上,我采用了使用mini2440移植的madplay播放工具来进行播放来简化播放器工作。madplay是一个Linux的开源命令行播放器工具,支持很多格式,使用很方便。

         在进行播放过程中,使用system命令调用madplay xxx.mp3 &的方式播放音乐,使用killall –CONT madplay &的方式来暂停播放,使用killall -9 madplay 的命令来结束播放。(虽然QT中有支持调用外部指令的QProcess类,由于我的交叉编译环境没有配好,使用QProcess的时候总是会提升QProcess的实现找不到,遂用system代替)。

2.3 视频输出

         在视频输出上,和音频输出类似,我使用了一个很好用的Linux开源播放器来执行视频播放任务:mplayerMplayer是一款很强大的播放器软件,它支持多种解码格式,开源,有多种模式,非常好用(其实音频也可以直接用Mplayer就可以)。

         Mplayer移植到Mini2440有一些需要注意的地方,网上文档很多就不再重复,这里仅仅说下遇到的问题。Mplayer有一个slave模式,可以让它变成某程序的后台程序,接收发送的指令来完成任务,功能十分强大,但是有一点不好的是,Mplayer如果想嵌入到某个控件中的话,在Windows下或者支持X系统,OpenGl系统下,可以通过-wid 嵌入窗口id的方式来进行,这样就可以完成无缝嵌入,但是在mini2440上市没有X系统的支持的,如果想要真正的嵌入,只能移植X系统或者OpenGl,这样的工作量是很大的,风险也很大;另外一个解决的办法就是不嵌入,通过调整mplayer播放窗口坐标的方式来让它“看起来”像是嵌入到我们的程序中一样。

         但是调整播放坐标也不是很容易,在mini2440上的测试结果是,播放窗口大小是可以用mplayer内置命令可调的,但是窗口坐标则是怎么调整也不管用的,最后的解决办法是,通过修改Mplayer源码中的vf_vo.c文件中的180多行左右的,一条语句,强制把Mplayer的播放坐标控制在某个坐标上(如30,50),这样在播放视频的时候看起来就像Mplayer嵌入到我们的界面中了。

         关于Mplayer的控制,有三种方案,一种是用和上面说过Madplay一样控制方式,一种是使用QProcess进行控制,一种是使用Mplayerslave模式,并使用管道pipe来对Mplayer进行控制通信,这里我们选择第三种办法。

 

2.4 编译程序

         Linux中,编写C/C++程序,非常重要的一点就是要手动给出Makefile文件,来完成对程序的编译,由于QT使用了比较复杂的编译逻辑(比如对声明Q_OBJECT的类进行预编译),加之需要配合交叉编译环境,就加大了编译的难度。还好Qtopia提供了比较好的工具progentmake,其中前者得到项目文件,后者得到Makefile,很大程度上简化了我们的工作,在修改程序时也可以比较简单的进行编译和构建,很好用啊

2.5 录音功能

         录音功能也一样是一个比较硬件相关的功能,(最开始的时候邮购的开发板的录音功能就不好用,后来几经周折才解决哇。)关于录音的功能实现的比较简单,只实现了一条录音的录制与播放。

         实现的时候,播放使用mplayer进行播放,与上面的方式类似,不再赘述。

         在声音录制的过程中,比较复杂,分几个部分简单说明:

1)    录制是基于OSS,启动一个线程来初始化音频设备,并循环对声音设备/dev/dsp进行录音音频采样,得到PCM数据并存储。

2)    当用户按下录音停止时,修改录音进程的全局录音变量(使用多线程和Mutex),使录音进程停止录音并完成PCM数据的书写,之后本进程读取录音PCM数据,并对其加上一个Wave文件44字节的文件头,将其修改为wav格式的音频文件。

3)    当用户单击播放时,使用mplayer进行录音wav文件的播放控制。

3. 结语

         简单的MP3播放器程序已经完成,为了简化工作,使用了很多现有工具,并且也避开了很多复杂的问题,感觉这样的开发与嵌入式不是很类似,倒是基本就是Unix程序设计,可能和传统嵌入式相关的应该是裸机程序开发或者设备驱动开发吧。

         恩一期工作完成,马上开始后续的SPL相关工作,加油。

留言功能已取消,如需沟通,请邮件联系博主sunswk@sina.com,谢谢:)