全部博文(161)
分类: LINUX
2011-05-27 11:24:59
一、项目概述
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
Seek to some place in the movie.
0 is a relative seek of +/-
1 is a seek to
2 is a seek to an absolute position of
下面代码即可实现快进功能:
process->write(“seek ** 1\n”);
4、音量调节
volume
Increase/decrease volume or set it to
下面代码即可实现快进功能:
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
/*
#ifndef QT_NO_QWS_CURSOR
# define QT_NO_QWS_CURSOR
#endif
*/
/*
#ifndef QT_NO_QWS_MOUSE
# define QT_NO_QWS_MOUSE
#endif
#ifndef QT_NO_QWS_MOUSE_AUTO
# define QT_NO_QWS_MOUSE_AUTO
#endif
*/
其它宏定义根据需要进行注释。
保存后将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
注释掉如下内容:
/*
#if !defined(QT_NO_QWS_CURSOR) && (defined(QT_NO_CURSOR))
#define QT_NO_QWS_CURSOR
#endif
*/
保存退出。
# vi qtopiacore/qt/src/corelib/global/qglobal.h
注释掉以下内容:
//# define QT_NO_QWS_CURSOR
#vim qtopiacore/qt/tools/qvfb/qvfbshmem.cpp
注释掉asm/page.h
//#include
#vim qtopiacore/qt/tools/qvfb/qvfbmmap.cpp
注释掉asm/page.h
//#include
并修改如下内容
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目录下生成很多开发工具。
先看一下供主机端使用的工具
[root@localhost bin]# pwd
/home/linux/Qtopia/target/qtopiacore/host/bin
[root@localhost 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
/*****************************main.cpp*****************************/
#include
#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
#include
#include
#include
#include
#include
#include
#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
/*******************************mplayer.cpp **********************************/
#include "mplayer.h"
#include
#include
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]);
/*************************初始化进度条及QProcess类**************/
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()<
{
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()<
//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);
/* if (process && process->state()==QProcess::Running && !isPlay)
{
//QString cmd="seek "+QString::number(qMin(m+10,100))+" 1\n";
//process->write(cmd.toAscii());
qDebug()<<"Forward";
}*/
}
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
(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
[root@localhost mplayer]# ls movie/
1.mp3 2.avi 3.avi 4.avi 5.avi
[root@localhost 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 运行程序
[root@localhost 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
#include "mplayer.h"
#include
#include
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镜像