天天看点

基于QT的mplayer播放器 .

转载来自:http://blog.csdn.net/songjinshi/article/details/6521320

一、项目概述

Mplayer。它支持大量的多媒体文件格式,像常见的音频文件如mp3/wav/mid,常见的视频文件如avi/vcd/dvd/rm等等,各种视频编/解码方式也是应有尽有。

我们项目的目标是在liunx下,用QT做一个MPlayer皮肤,能够实现播放器的常见

功能,如:播放、停止、快进、快退、上/下一曲等。并把程序移植到ARM平台上。

二、功能体验

本节主要目的是让大家在学习具体实现过程前,先体验下播放器的功能。

1、PC端功能体验

将“项目代码/工程代码”目录下的mplayer.tar.gz拷贝linux系统中(主机环境配置好以后,参照第四节的实现过程)。

#tar xvfz mplayer.tar.gz

#./mplayer

2、目标平台功能体验

l         将“项目代码/工程镜像”文件夹中的zImage、rootfs.cramfs烧写到目标板(或者采用nfs方式)。分区情况为:

Boot: 0 - 40000   size=0x40000

Kernel:40000 – 240000  size=0x200000

Rootfs: 240000 -3740000  size=0x3500000

启动参数为:

setenv root=1f02 init=/linuxrc rootfstype=cramfs console=ttySAC0,115200 display=sam240

setenv bootcmd setenv bootcmd nand read 30008000 40000 200000 /; go 30008000

l         启动系统后运行:

#. ./Qtopia.sh

#cd mymplayer

#./mymplayer -qws

三、实现原理

先来考虑考虑如何为mplayer编写前端界面的问题。有两种思路,一种是把mplayer解剖,直接修改他里面的代码,这样我们做得界面就能够和mplayer一体了(当然也能够通过link mplayer用到的任何的库和.o文档,把他无缝的集成在程式里面);第二种方法就是mplayer所谓的slave模式。

mplayer '/home/linux/1.mp3' -quiet -slave

现在来探讨一下slave模式:所谓的slave模式,就是mplayer在运行过程中能够接收用户的输入命令行,具体支持哪些命令行,能够通过mplayer -input cmdlist这条命令来得到,在Mplayer源码的slave.txt中也有对这些命令有详细的讲解。Slave模式下工作的Mplayer可以和系统的标准输入、输出进行信息交互。我们可以用linux C编程来完成对slave模式工作的Mplayer进行控制和信息获取。

如:

mkfifo(“/tmp/fifo”,0777);

可以使用popen()来打开Mplayer

FILE* mp;

mp=popen(“mplyer /home/linux/1.mp3 -quiet –slave –input file=/tmp/fifo,”r”);

可以通过管道/tmp/fifo给mplayer发送命令,通过mp获取mplay的返回数据

如:system(“echo /”mute 0/” > /tmp/fifo”);//写命令

fgets(buf,1000,mp);//读取mplay返回数据

而Qt给我们提供了更方便的实现方法。

通过定义一个QProcess对象调用已编译好的Mplayer。

QProcess *process = new QProcess();

process->setProcessChannelMode(QProcess::MergedChannels);

Process->start(“mplayer –ac mad xxxxx”);

在命令中添加 -slave 和 -quiet就可以通过命令设置Mplayer实现相应的功能。在mplayer源码中的,slave.txt中对这些命令有详细的讲解。

Process->start(“mplayer –slave –quiet –ac mad xxxxx”);

1、暂停功能

通过如下代码可以设置Mplayer暂停。

process->write(“pause/n”);

执行这段代码的时候如果是播放状态就会暂停,暂停状态时就会继续播放。

2、获取播放文件的总时间和当前播放进度

执行下面代码时,Mplayer将时间在标准输出显示。

process->write("get_time_pos/n");

process->write("get_time_length/n");

通过如下代码即可读出我们需要的信息:

connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(back_message_slots()));

process有可读取的信息时,发出信号,在槽函数back_message_slots()中读取信息。

void MPlayer::back_message_slots()

{

while(process->canReadLine())

{

QString message(process->readLine());

//message即为读取的信息我们可以根据需要取我们要的信息如

//文件总时间为:ANS_LENGTH=23.00

//当前时间为:ANS_TIME_POSITION=23.00

}

}

3、快进功能

seek <value> [type]

Seek to some place in the movie.

0 is a relative seek of +/- <value> seconds (default).

1 is a seek to <value> % in the movie.

2 is a seek to an absolute position of <value> seconds.

下面代码即可实现快进功能:

process->write(“seek ** 1/n”);

4、音量调节

volume <value> [abs]

Increase/decrease volume or set it to <value> if [abs] is nonzero.

下面代码即可实现快进功能:

Process->write(“volume -1/n”);           //音量减小

Process->write(“volume +1/n”);          //音量增加

5、静音功能

mute [value]

Toggle sound output muting or set it to [value] when [value] >= 0

(1 == on, 0 == off).

下面代码即可实现快进功能:

process->write("mute 0/n");         //开启静音

process->write("mute 1/n");         //关闭静音

6、定位视频窗口

通过上面的代码基本功能实现了,可是播放视频的时候发现又弹出一个窗口。并没有出现在我们的窗口里。

如下代码即可时间窗口的定位。

QString common = "mplayer -slave -quiet -ac mad -zoom movie/" + file_name + " -wid " + QString::number(widget->winId());

process->start(common);

红色部分实现窗口的定位。Widget是一个QWidget对象。通过winId可以获得一个数字,-wid既将视频输出定位到widget窗体部件中。

注意:-wid参数只在X11、directX和OpenGL中适用。

四、PC环境下的实现过程

1、PC环境搭建

主机环境:Red Hat Enterprise Linux 5.0

交叉编译工具:gcc-3.4.5-glibc-2.3.6

主机编译工具:gcc-4.1.2

(1)主机端安装mplayer

l         将“项目代码/mplay源码”目录下的MPlayer-1.0rc2.tar.bz2、libmad-0.15.1b.tar.gz(1个mp3解码库)拷贝到linux系统中,如:/home/linux/mplayer目录下

l         安装libmad-0.15.1b.tar.gz

#tar xvfz libmad-0.15.1b.tar.gz

#cd libmad-0.15.1b

#./configure

#make

#mkdir /lib/lib

#mkdir /lib/include

#cp mad.h /lib/include

#cp .libs/libmad.a /lib/lib

l         安装mplayer

#tar xvfj MPlayer-1.0.rc2.tar.bz2

#cd MPlayer-1.0rc2

#./configure --with-extraincdir=/lib/include --with-extralibdir=/lib/lib

#make

#make install

此时可以试着播放一下mp3、avi等文件了

# mplayer -ac mad 1.mp3

# mplayer -ac mad 2.avi

(2)安装、移植qtopia-4.2.0

注:需要先按照5.2节将tslib按照好

l         将“项目代码/qtopia源码”目录下的qtopia-opensource-src-4.2.0.tar.gz拷贝到linux系统中,如:/home/linux/Qtopia目录下

# tar zxvf qtopia-opensource-src-4.2.0.tar.gz

# mv qtopia-opensource-4.2.0 source

# mkdir target  //创建在source同级目录下创建目录target

修改源码包

# cd source

# cd src/libraries/qtopiabase/

# cp custom-linux-cassiopeia-g++.h custom-linux-arm-g++.h

# cp custom-linux-cassiopeia-g++.cpp custom-linux-arm-g++.cpp

修改时区信息

# vi src/libraries/qtopia/qtimezone.cpp

将114行的 /usr/share/zoneinfo/ 改为/Qtipia/zoneinfo/ ,保存退出。

# vi src/settings/systemtime/settime.cpp

将318行的 /usr/share/zoneinfo/ 改为/Qtipia/zoneinfo/ ,保存退出。

l         裁减Qtopia core的库(下列操作后在屏幕上会出现一个光标,否则没有光标。根据需求配置)

# vi qtopiacore/qconfig-qpe.h

首先注释掉关于鼠标光标的宏定义,让程序运行时,触摸屏中央有光标出现:

// Qtopia Core

其它宏定义根据需要进行注释。

保存后将qconfig-qpe.h拷贝到global目录。

# cp qtopiacore/qconfig-qpe.h qtopiacore/qt/src/corelib/global/qconfig-qpe.h (必须进行的操作)

注释掉其他文件里的QT_NO_QWS_CURSOR的定义

# vi qtopiacore/qt/src/corelib/global/qfeatures.h

注释掉如下内容:

保存退出。

# vi qtopiacore/qt/src/corelib/global/qglobal.h

注释掉以下内容:

//# define QT_NO_QWS_CURSOR

#vim qtopiacore/qt/tools/qvfb/qvfbshmem.cpp

注释掉asm/page.h

//#include <asm/page.h>

#vim qtopiacore/qt/tools/qvfb/qvfbmmap.cpp

注释掉asm/page.h

//#include <asm/page.h>

并修改如下内容

unsigned char *data;

uint data_offset_value = sizeof(QVFbHeader);

if (data_offset_value % PAGE_SIZE)

data_offset_value += PAGE_SIZE - (data_offset_value % PAGE_SIZE);

为:

unsigned char *data;

uint data_offset_value = sizeof(QVFbHeader);

const int page_size = getpagesize();

if (data_offset_value % page_size)

data_offset_value += page_size - (data_offset_value % page_size);

# vim src/libraries/qtopiabase/qmemoryfile_unix.cpp +128

修改

f = :pen(tmpFile.toLatin1(), O_CREAT | O_WRONLY);

为:

f = :pen(tmpFile.toLatin1(), O_CREAT | O_WRONLY ,0777);

l         修改交叉工具

#vim qtopiacore/qt/mkspecs/qws/linux-arm-g++/qmake.conf

将文件中的arm-linux-***全部修改为arm-softfloat-linux-gnu-**

这样做的前提是我的交叉工具链是arm-softfloat-linux-gnu,如果你的是arm-linux就不用改了。

l         生成Makefile

#cd ../target    //为了不破坏源码,选择在此目录下配置、编译源码

#../source/configure -release -image /Qtopia -prefix /Qtopia -xplatform linux-arm-g++ -arch arm -no-qvfb -displaysize 320x240 -no-modem -extra-qtopiacore-config "-release -xplatform qws/linux-arm-g++ -embedded arm -qconfig qpe -depths 4,8,16,32 -qt-sql-sqlite -no-mouse-linuxtp -qt-mouse-tslib -I/home/linux/tslib/include -L/home/linux/tslib/lib " 2>../configureERR.txt

注意:这里/Qtopia是最后Qtopia的安装路径,安装到主机的某个路径下,最终这个路径和目标板上的路径必须一致。

主要配置选项说明如下:

-xplatform linux-arm-g++ -arch arm

目标平台为arm-linux,体系结构为arm。

-no-qvfb

目标平台已支持framebuffer,因而不使用虚拟帧缓冲。

-extra-qtopiacore-config

为Qtopia core 配置选项。

-xplatform qws/linux-arm-g++ -embedded arm

目标平台编译配置文件使用qtopiacore/qt/mkspecs/qws/linux-arm-g++目录下的配置文件,嵌入式平台为arm。

-qconfig qpe

使用配置文件qconfig-qpe.h,若使用qconfig-large.h配置文件,则使用-qconfig large选项。

-qt-sql-sqlite

数据库支持Sqlite。

-qt-kbd-usb

键盘支持usb协议。

-no-mouse-linuxtp -qt-mouse-tslib

-I/home/linux/tslib/include -L/home/linux/tslib/lib

触摸屏协议不支持linuxtp,支持tslib,并在后面添加上刚才编译的tslib的头文件和库。

2>../qtopiaconfigureERR.txt

最后将配置过程中的错误输出到qtopiaconfigureERR.txt文件中。

l         编译

#make

#make install

l         将安装和的目录考到nfsroot目录下

#cp /Qtopia /rootfs -a

(3)熟悉主机开发环境

l         提供给PC端的开发工具

上面的qtopia编译安装完成后,会在咱们前面创建的target目录下生成很多开发工具。

先看一下供主机端使用的工具

[[email protected] bin]# pwd

/home/linux/Qtopia/target/qtopiacore/host/bin

[[email protected] bin]# ls

assistant  linguist  lupdate  qmake  rcc        uic

designer   lrelease  moc      qvfb   templates  uic3

如果系统以前有其它qt开发工具,把环境变量修改一下,保证它们不要和我们这几个工具冲突。下面可以试一下你的designer了。

#./designer

2、在PC端实现基于qt前端的mplayer播放器

创建工程目录/home/linux/mplayer

(1)搭建ui界面

利用前面安装的designer搭建ui界面,并将其保存至/home/linux/mplayer/mplayer.ui

#./designer

圆角矩形标注: 加了一个widget,留作mplayer的播放区

(2)编写程序

在/home/linux/mymplayer/下创建mplayer.cpp、mplayer.h、main.cpp 、image.qrc

Main.cpp

#include <QApplication>

#include "mplayer.h"

int main(int argc, char **argv)

{

QApplication app(argc, argv);

MPlayer player;   //实例最终的MPlayer类

player.show();     //显示界面

return app.exec();  //运行程序

}

mplayer.h

#ifndef _MPLAYER_H

#define _MPLAYER_H

#include <QIcon>

#include <QProcess>

#include <QTimer>

#include <QStringList>

#include <QDir>

#include <QTime>

#include <QString>

#include "ui_mplayer.h"

class MPlayer:public QDialog,private Ui_Dialog

{

Q_OBJECT

public:

MPlayer(QWidget *parent = 0);

public:

QTime int_to_time(int);

public slots:            

void play_pause_slots(); //暂停

void stop_slots();      //停止

void previous_slots();   //上一曲

void next_slots();       //下一曲

void seek_slots(int);

void get_time_slots();        //得到播放时间

void set_volume_slots(int);    //设置音量

void set_sound_slots();       //静音

void playerReward_slots();    //快退

void playerForward_slots();    //快进

void back_message_slots();    //更新显示信息

private:

QProcess *process;

QStringList files;

QDir directory;

int file_count;

QString file_name;

bool isPlay;

bool isSound;

bool isStop;

QTimer *timer;

int file_length;

int curr_time;

};

#endif

mplayer.cpp

#include "mplayer.h"

#include <QDebug>

#include <unistd.h>

MPlayer::MPlayer(QWidget *parent)Dialog(parent)

{

setupUi(this);  //初始化界面

isPlay = true;

isSound = true;

isStop = false;

//play

QIcon icon_play;

icon_play.addPixmap(QPixmap(QString::fromUtf8("images/pause_enabled.png")), QIcon::Normal, QIcon::Off);

pushButton_2->setIcon(icon_play);

//stop

QIcon icon_stop;

icon_stop.addPixmap(QPixmap(QString::fromUtf8("images/stop_enabled.png")), QIcon::Normal, QIcon::Off);

pushButton_3->setIcon(icon_stop);

//reward

QIcon icon_reward;

icon_reward.addPixmap(QPixmap(QString::fromUtf8("images/reward_enabled.png")), QIcon::Normal, QIcon::Off);

pushButton_4->setIcon(icon_reward);

//forward

QIcon icon_forward;

icon_forward.addPixmap(QPixmap(QString::fromUtf8("images/forward_enabled.png")), QIcon::Normal, QIcon::Off);

pushButton_5->setIcon(icon_forward);

//sound

QIcon icon_sound;

icon_sound.addPixmap(QPixmap(QString::fromUtf8("images/sound_enabled.png")), QIcon::Normal, QIcon::Off);

pushButton->setIcon(icon_sound);

QIcon icon_previous;

icon_previous.addPixmap(QPixmap(QString::fromUtf8("images/previous_disabled.png")), QIcon::Normal, QIcon::Off);

pushButton_6->setIcon(icon_previous);

QIcon icon_next;

icon_next.addPixmap(QPixmap(QString::fromUtf8("images/next_enabled.png")), QIcon::Normal, QIcon::Off);

pushButton_7->setIcon(icon_next);

pushButton->setFlat(true);

pushButton_2->setFlat(true);

pushButton_3->setFlat(true);

pushButton_4->setFlat(true);

pushButton_5->setFlat(true);

pushButton_6->setFlat(true);

pushButton_7->setFlat(true);

directory.setPath("./movie");

files = directory.entryList(QDir::AllEntries,QDir::Time);

file_name = files[2]; //文件0和1为 ”.” ”..”,所以从文件2开始播放

file_count = 2;

label_3->setText(files[2]);

horizontalSlider->setPageStep(1);

process = new QProcess(this);

process->setProcessChannelMode(QProcess::MergedChannels);

connect(pushButton_2,SIGNAL(clicked()),this,SLOT(play_pause_slots()));

connect(pushButton_3,SIGNAL(clicked()),this,SLOT(stop_slots()));

connect(pushButton_4,SIGNAL(clicked()),this,SLOT(playerReward_slots()));

connect(pushButton_5,SIGNAL(clicked()),this,SLOT(playerForward_slots()));

connect(pushButton_6,SIGNAL(clicked()),this,SLOT(previous_slots()));

connect(pushButton_7,SIGNAL(clicked()),this,SLOT(next_slots()));

//connect(horizontalSlider,SIGNAL(valueChanged(int)),this,SLOT(seek_slots(int)));

connect(spinBox,SIGNAL(valueChanged(int)),this,SLOT(set_volume_slots(int))); 

connect(pushButton,SIGNAL(clicked()),this,SLOT(set_sound_slots()));

connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(back_message_slots()));

//当process可以读到Mplayer的返回信息时,产生readyReadStandardOutput()信号

//process->start("mplayer -slave -quiet -ac mad 2.avi");

//add -wid QWidget->winId();

QString common = "mplayer -slave -quiet -ac mad -zoom movie/" + file_name + " -wid " + QString::number(widget->winId()); //这里的widget是ui中MPlayer的显示区

process->start(common);      //开始运行程序

spinBox->setValue(40);     

timer = new QTimer(this);

connect(timer,SIGNAL(timeout()),this,SLOT(get_time_slots()));

//定时获取MPlayer的时间信息

timer->start(1000); //启动定时器 1秒timeout 1次

}

void MPlayer::play_pause_slots()

{

if(!isPlay)

{

if(isStop)

{

file_name = files[file_count];

QString common = "mplayer -slave -quiet -ac mad -zoom movie/" + file_name + " -wid " + QString::number(widget->winId());

process->start(common);

QIcon icon_stop;

icon_stop.addPixmap(QPixmap(QString::fromUtf8("images/stop_enabled.png")), QIcon::Normal, QIcon::Off);

pushButton_3->setIcon(icon_stop);

isStop = false;

}

else

{

process->write("pause/n");

}

QIcon icon_play;

icon_play.addPixmap(QPixmap(QString::fromUtf8("images/pause_enabled.png")), QIcon::Normal, QIcon::Off);

pushButton_2->setIcon(icon_play);

isPlay = true;

}

else

{

QIcon icon_pause;

icon_pause.addPixmap(QPixmap(QString::fromUtf8("images/play_enabled.png")), QIcon::Normal, QIcon::Off);

pushButton_2->setIcon(icon_pause);

isPlay = false;

process->write("pause/n");

}

}

void MPlayer::stop_slots()

{

if(!isStop)

{

process->write("quit/n");

QIcon icon_pause;

icon_pause.addPixmap(QPixmap(QString::fromUtf8("images/play_enabled.png")), QIcon::Normal, QIcon::Off);

pushButton_2->setIcon(icon_pause);

isPlay = false;

QIcon icon_stop;

icon_stop.addPixmap(QPixmap(QString::fromUtf8("images/stop_disabled.png")), QIcon::Normal, QIcon::Off);

pushButton_3->setIcon(icon_stop);

isStop = true;

label->setText("00:00:00");

label_2->setText("00:00:00");

}

}

void MPlayer::previous_slots()

{

if(file_count > 2)

{

if(file_count == (files.size()-1))

{

QIcon icon_next;

icon_next.addPixmap(QPixmap(QString::fromUtf8("images/next_enabled.png")), QIcon::Normal, QIcon::Off);

pushButton_7->setIcon(icon_next);

}

process->write("quit/n");

process = new QProcess(this);

connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(back_message_slots()));

file_count--;

if(!isStop)

{

file_name = files[file_count];

QString common = "mplayer -slave -quiet -ac mad -zoom movie/" + file_name + " -wid " + QString::number(widget->winId());

process->start(common);

}

if(file_count == 2)

{

QIcon icon_previous;

icon_previous.addPixmap(QPixmap(QString::fromUtf8("images/previous_disabled.png")), QIcon::Normal, QIcon::Off);

pushButton_6->setIcon(icon_previous);

}

label_3->setText(files[file_count]);

}

}

void MPlayer::next_slots()

{

if(file_count < (files.size()-1))

{

if(file_count == 2)

{

QIcon icon_previous;

icon_previous.addPixmap(QPixmap(QString::fromUtf8("images/previous_enabled.png")), QIcon::Normal, QIcon::Off);

pushButton_6->setIcon(icon_previous);

}

process->write("quit/n");     

process = new QProcess(this);

connect(process,SIGNAL(readyReadStandardOutput()),this,SLOT(back_message_slots()));

file_count++;

if(!isStop)

{

file_name = files[file_count];

QString common = "mplayer -slave -quiet -ac mad -zoom movie/" + file_name + " -wid " + QString::number(widget->winId());

process->start(common);

}

if(file_count == (files.size()-1))

{   

QIcon icon_next;

icon_next.addPixmap(QPixmap(QString::fromUtf8("images/next_disabled.png")), QIcon::Normal, QIcon::Off);

pushButton_7->setIcon(icon_next);

}

}

label_3->setText(files[file_count]);

}

void MPlayer::seek_slots(int seek_num)

{

qDebug()<<seek_num;

if(process && process->state() == QProcess::Running )

{

process->write(QString("seek " + QString::number(qMin(seek_num,100)) + "1/n").toAscii());

}

}

void MPlayer::get_time_slots()

{

if(isPlay)

{

process->write("get_time_pos/n");

process->write("get_time_length/n");

}

}

void MPlayer::set_volume_slots(int volume)

{

qDebug()<<volume;

process->write(QString("volume +" + QString::number(volume) + " /n").toAscii());

//process->write(QString("volume +1/n").toAscii());

}

void MPlayer::set_sound_slots()

{

if(isSound)

{

process->write("mute 1/n");

QIcon icon_sound;

icon_sound.addPixmap(QPixmap(QString::fromUtf8("images/nosound_enabled.png")), QIcon::Normal, QIcon::Off);

pushButton->setIcon(icon_sound);

isSound = false;

}

else

{

process->write("mute 0/n");

QIcon icon_sound;

icon_sound.addPixmap(QPixmap(QString::fromUtf8("images/sound_enabled.png")), QIcon::Normal, QIcon::Off);

pushButton->setIcon(icon_sound);

isSound = true;

}

}

void MPlayer::playerReward_slots()

{

//bool ok;

//int m=moviePosition.toInt(&ok);

if (process && process->state()==QProcess::Running && !isPlay)

{

//QString cmd="seek "+QString::number(qMax(m-10,0))+" 1/n";

//process->write(cmd.toAscii());

qDebug()<<"Reward";

}

}

void MPlayer::playerForward_slots()

{

//     groupBox->setVisible(false);

//bool ok;

//int m=moviePosition.toInt(&ok);

}

void MPlayer::back_message_slots()

{

while(process->canReadLine())

{

QString message(process->readLine());

QStringList message_list = message.split("=");

if(message_list[0] == "ANS_TIME_POSITION")

{

curr_time = message_list[1].toDouble();//toInt();

QTime time = int_to_time(curr_time);

label->setText(time.toString("hh:mm:ss"));

horizontalSlider->setValue(100 * curr_time / file_length);

}

else if(message_list[0] == "ANS_LENGTH")

{

file_length = message_list[1].toDouble();//toInt();

QTime time = int_to_time(file_length);

label_2->setText(time.toString("hh:mm:ss"));     

}

}

}

QTime MPlayer::int_to_time(int second)

{

int sec = 0, min = 0, hour = 0;

QTime time;

if(second < 60)    

{

sec = second;

min = 0;

hour = 0;

}

if(second >= 60 && second < 3600)

{

sec = second % 60;

min = second / 60;

hour = 0;

}

if(second >= 3600)

{

sec = second % 60;

min = (second / 60) % 60;

hour = second / 3600;

}

time.setHMS(hour,min,sec);

return time;

}

image.qrc

<RCC>

<qresource prefix="images" >

<file>images/player_play.png</file>

<file>images/player_stop.png</file>

<file>images/player_pause.png</file>

<file>images/play_enabled.png</file>

<file>images/pause_enabled.png</file>

<file>images/reward_enabled.png</file>

<file>images/forward_enabled.png</file>

<file>images/stop_enabled.png</file>

<file>images/sound_enabled.png</file>

<file>images/nosound_enabled.png</file>

<file>images/previous_enabled.png</file>

<file>images/previous_disabled.png</file>

<file>images/next_enabled.png</file>

<file>images/next_disabled.png</file>

</qresource>

</RCC>

(3)编译工程

l         拷贝qmake到当前工程目录下

#cp /home/linux/Qtopia/target/qtopiacore/host/bin/qmake ./

l         生成项目文件、

#qmake –project

l         生成Makefile

#qmake

l         编译

#make

成功后,可以生成mplayer可执行程序

l         建立movie和images

#mkdir movie

#mkdir images

[[email protected] mplayer]# ls movie/

1.mp3  2.avi  3.avi  4.avi  5.avi

[[email protected] mplayer]# ls images

forward_enabled.png  nosound_enabled.png  player_play.png        reward_enabled.png

images               pause_enabled.png    player_stop.png        sound_enabled.png

next_disabled.png    play_enabled.png     previous_disabled.png  stop_disabled.png

next_enabled.png     player_pause.png     previous_enabled.png   stop_enabled.png

l         运行程序

[[email protected] mplayer]#./mplayer

五、移植到ARM平台过程

1、内核要求

要求内核支持framebuffer驱动、OSS音频驱动、支持input事件的触摸屏驱动。

2、目标板上部署qt环境

将前面交叉编译好的/Qtopia目录拷贝到nfsroot目录下

#cp /Qtopia /rootfs –a

注:rootfs为目标平台的nfs根文件系统位置

3、文件系统中移植tslib

(下面的步骤是在ubantu-8.10环境下编译的,其它的系统基本相同)

(1)拷贝“项目代码/tslib源码”目录下的tslib-1.4.tar.gz到linux系统

(2)# tar -zxvf tslib-1.4.tar.gz

# cd tslib-1.4

# ./autogen.sh

这一步需要安装一些工具,如:在ubantu系统下可以执行:sudo apt-get install automake

(3)执行autogen.sh脚本所生成的Makefile文件

请打入以下命令:

echo "ac_cv_func_malloc_0_nonnull=yes" >$ARCH-linux.cache

./configure --host=arm-softfloat-linux-gnu  --prefix=/home/linux/tslib --cache-file=$ARCH-linux.cache

--host是指你的交叉编译器的前最;例如:你的交叉编译器是arm-linux-gcc,则--host=arm-linux.如果是arm-softfloat-linux-gnu-gcc

则--host=arm-softfloat-linux-gnu

--prefix 是你执行make install 的时候编译后生成的可执行文件和库文件以及配置文所安装的目录;

configure文件下还有好多选项,你可以执行./configure --help 来进行选择其他项,不过在这里这些选项就够了。

(4)#make

#make install

(5)把指定安装目录下的mytslib的文件都copy到你所挂载的根文件下

#cp -rf /home/linux/tslib/*    /rootfs/tslib

(6)修改/rootfs/tslib下的etc目录中ts.cong文件

#vi ts.conf  将第二行的#module_raw input修改成module_raw input 注意一定要顶格写否则程序执行时会发生读取ts.conf错误

(7)启动你的开发板

在终端上设置一下环境变量:

export TSLIB_ROOT=/mytslib

export TSLIB_TSDEVICE=/dev/event0

export LD_LIBRARY_PATH=/mytslib/libLD_LIBRARY_PATH

export QWS_SIZE=320x240

export TSLIB_FBDEVICE=/dev/fb0

export TSLIB_PLUGINDIR=/mytslib/lib/ts

export TSLIB_CONSOLEDEVICE=none

export TSLIB_CONFFILE=/mytslib/etc/ts.conf

export POINTERCAL_FILE=/etc/pointercal

export QWS_MOUSE_PROTO=Tslib:/dev/event0

export TSLIB_CALIBFILE=/etc/pointercal

export QWS_DISPLAY="LinuxFb:mmWidth100:mmHeight130:0"

export TSLIB_TSEVENTTYYPE=H3600

为了实现Tslib的正确运行,需要对如下的Tslib的环境变量进行配置:

TSLIB_TSDEVICE  //触摸屏设备文件名。

TSLIB_CALIBFILE  //校准的数据文件,由ts_calibrate校准程序生成。

SLIB_CONFFILE  //配置文件名。

TSLIB_PLUGINDIR //插件目录

TSLIB_CONSOLEDEVICE //控制台设备文件名

TSLIB_FBDEVICE  //设备名

以上环境变量在实际开发中的实际配置可以根据实际情况决定。而这些指定的设备节点一定要和你的开发板上的/dev目录下的设备节点相对应。

为了不浪费时间我们把上面的这些设置写入一个脚本里面:参见5.6节

(8)就可以运行mytslib/bin下的测试文件,如ts_calibrate校准程序。

4、文件系统中移植mplayer播放器

需要在目标板上也移植开源的mplayer播放器,步骤如下:

l         编译libmad

重新配置前面针对主机编译过的libmad

#./configure --enable-fpm=arm --host=arm-linux --disable-shared /

--disable-debugging --prefix=/usr/local/arm/3.4.1/lib /

CC=arm-linux-gcc

#make

就可以编译出libmad了。注意--prefix配置选项表示libmad库和头文件在哪个目录生成,比如本例中make install后在/usr/local/arm/3.4.1/lib目录下就多了include和lib两个目录。这与mplayer的配置选项--with-extraincdir指定的目录是相符的。如果没找到编译生成的lib库和include头文件。则在当前编译目录下的mad.h以及.libs目录下的libmad.a拷到你自己指定的目录下

l         编译mplayer

./configure --cc=arm-linux-gcc --host-cc=gcc --target=arm-linux --enable-static /

--prefix=/tmp/mplayer-rc2 --disable-win32dll --disable-dvdread /

--enable-fbdev --disable-mencoder --disable-live --disable-mp3lib /

--enable-mad --enable-libavcodec_a --language=zh_CN /

--disable-armv5te --disable-armv6 /

--with-extraincdir=/usr/local/arm/3.4.1/lib/include /

--with-extralibdir=/usr/local/arm/3.4.1/lib/lib

几点注意:—host-cc参数指定X86的gcc,不指定的话,有些必须用gcc编译的,make会交叉编译,就会出错

--cc指定交叉工具链名称

--with-extraincdir与--with-extralibdir指定刚才交叉编译libmad生成的mad.h与liblibmad.a存放路径

编译过程中会出现如下错误:

armv4l/dsputil_arm_s.S:79:error:selected processor does not support 'pld[r1]'

【解决办法】

修改dsputil_arm_s.S,在前面添加上:

#ifndef HAVE_PLD

.macro pld reg

.endm

#endif

5、主机交叉编译工程

(1)针对目标平台调整UI

由于目标平台的液晶是320*240分辨率的,所以需要调整下UI的大小。将UI的整个窗口大小调整为320*240。

(2)交叉编译工程

l         拷贝针对目标平台的qmake工具到工程目录下

#cp /home/linux/Qtopia/target/qtopiacore/target/bin/qmake ./

l         生成项目文件

#qmake –project

l         生成Makefile文件

#qmake

l         编译生成目标文件mymplayer

#make

6、设置环境变量脚本文件Qtopia.sh

#vim Qtopia.sh

!/bin/sh

export TSLIB_ROOT=/tslib

export TSLIB_TSDEVICE=/dev/event0

export LD_LIBRARY_PATH=/tslib/libLD_LIBRARY_PATH

export QWS_SIZE=320x240

export TSLIB_FBDEVICE=/dev/fb0

export TSLIB_PLUGINDIR=/tslib/lib/ts

export TSLIB_CONSOLEDEVICE=none

export TSLIB_CONFFILE=/tslib/etc/ts.conf

export POINTERCAL_FILE=/etc/pointercal

export QWS_MOUSE_PROTO=Tslib:/dev/event0

export TSLIB_CALIBFILE=/etc/pointercal

export TSLIB_TSEVENTTYYPE=H3600i

export LD_LIBRARY_PATH=/Qtopia/libLD_LIBRARY_PATH

export QWS_SW_CURSOR

export set HOME=/root

export set QPEDIR=/Qtopia

export set QWS_KEYBOARD="TTY:/dev/tty1"

export QWS_DISPLAY="LinuxFb:mmWidth60:mmHeight65:0"   

7、通过nfs方式测试程序

(1)设置uboot参数

setenv bootcmd tftp 30008000 zImage /; go zImage

setenv bootargs root=nfs nfsroot=192.168.1.112:/rootfs ip=192.168.1.202 init=/linuxrc console=ttySAC0,115200 devfs=mount display=sam240

(2)启动目标系统

l         将“项目代码/工程镜像”目录下的zImage拷贝到tftp服务目录/tftpboot下

l         开启nfs、tftp服务,服务目录分别为/rootfs /tftpboot

l         启动系统

l         运行测试程序

#. ./Qtopia.sh  //设置环境变量

#cd mymplayer

#./mymplayer –qws  //运行程序

8、QT程序国际化

利用/home/linux/Qtopia/target/qtopiacore/host/bin下面的几个工具给程序做汉化工作

(1)修改pro文件

在.pro文件添加如下内容:

TRANSLATIONS = zh_CN.ts

(2)生成ts文件

#lupdate mymplayer.pro

生成zh_CN.ts文件

(3)生成qm翻译文件

#linguist zh_CN.ts

(4)拷贝字体文件到目标系统

l         从C:/WINDOWS/Fonts选择一个字体,如simsun.ttc

cp simsun.ttc /rootfs/Qtopia/lib/fonts           //simsun.ttc 是宋体字库

l         修改fonts中文件fontdir,添加如下内容

simsun simsun.ttc TTC n 50 120 u    

(5)修改源码

修改main.cpp为如下形式

#include <QApplication>

#include "mplayer.h"

#include <QtCore/QTextCodec>

#include <QTranslator>

int main(int argc, char **argv)

{

QApplication app(argc, argv);

QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")) ;//设置编码为UTF8

app.setFont(QFont("simsun", 10));                            //设置显示字体为汉字

QTranslator *translator = new QTranslator( 0 );                              //导入中文化qm文件

translator->load( "zh_CN.qm", "." );

app.installTranslator( translator );

MPlayer player;

player.show();

return app.exec();

}

9、目标机独立测试

(1)裁剪系统

(2)制作cramfs镜像

继续阅读