基于Phonon+QT的音视频播放器设计与实现
目 录
摘 要 2
第一章 软件需求说明书 1
1.1 引言 1
1.2 业务流程整体说明 1
第二章 需求分析报告 3
2.1 引言 3
2.2 任务概述 3
2.3 功能需求 3
2.4 性能需求 4
2.5 运行环境描述 4
第三章 软件设计书 5
3.1 引言 5
3.2 软件结构 5
3.3 程序描述 6
3.3.1 模块 1.功能模块 6
3.3.2 模块 2.用户操作 7
3.3.3 模块 3.列表操作 8
3.3.5 模块 4.音频调节 9
第四章 程序设计说明书 9
4.1 引言 9
4.2 各功能核心代码和界面说明 10
4.2.1 功能一:背景图片 10
4.2.2 功能二:添加/删除歌曲 11
4.2.3 功能三:播放/暂停 12
4.2.4 功能四:上一集/下一集 13
第五章 软件测试说明书 14
5.1 引言 14
5.2 计划 14
5.3 测试用例 15
5.4 测试计划执行情况 17
5.5 评价 17
第六章 用户手册 18
6.1 引言 18
6.2 系统功能介绍 18
6.3 运行环境说明 19
附录 19
致谢 20
6.1 引言
随着计算机的普及,其各种应用技术也随之迅速发展,多媒体技术就是发展最 迅速的应用技术之一。多媒体工具也大大的拓展了计算机的应用领域,是非计算 机专业人员最常使用的应用工具之一。借助高速发展的互联网络,各种各样的媒 体播放器将多媒体概念表现的淋漓尽致,潜移默化地影响着人们的生产和生活。
如今人们随着生活水平的提高,对视频享受方面的要求也越来越高,人们不 单仅仅满足于电视或电脑上欣赏高品质的音视频。本文转载自http://www.biyezuopin.vip/onews.asp?id=14572基于这一背景,所以想开发一 款视频播放器。
编写目的 本手册主要用来指导用户正确使用软件并解决常见问题,使用对象为本软
件的最终使用者
6.2 系统功能介绍
资源添加:可从本地文件夹中添加一个被支持的播放资源文件 资源删除:可从播放列表中删除一个或多个资源文件 播放按钮:播放已被暂停的资源
暂停按钮:暂停已播放的资源 音量调节:设置静音,或者改变音量大小 进度调节:拖动进度条,改变播放文件的当前播放进度 上/下一集:可对当前已播放的资源进行上一集 or 下一集的切换 画面显示:显示播放画面,支持 1080P
退出程序:程序关闭
6.3 运行环境说明
简单说明运行本软件所要求的:
硬件设备环境,例如液晶电脑、笔记本电脑等;
系统软件的环境,例如 Windows 系统、Linux 系统
应用软件环境,例如 QT、Linux 等。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include"denglu.h"
#include <QFileDialog>
#include <QAction>
#include <QStringList>
#include <QDesktopServices>
#include<QSqlQuery>
#include <QUrl>
#include <QDebug>
#include "ui_playlist.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle(tr("影音播放器"));
mObject = new Phonon::MediaObject(this);
vWidget = new Phonon::VideoWidget(ui->frameVideo);
vWidget->setAspectRatio(Phonon::VideoWidget::AspectRatioWidget);
aOutput = new Phonon::AudioOutput(Phonon::MusicCategory, this);
Phonon::createPath(mObject, vWidget);
Phonon::createPath(mObject, aOutput);
sSlider = new Phonon::SeekSlider(mObject, ui->frameSeek);
vSlider = new Phonon::VolumeSlider(aOutput, ui->frameVolume);
aOutput->setVolume(1);
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()),this, SLOT(updateTime()));
//setMouseTracking(true);
connect(mObject,SIGNAL(currentSourceChanged(Phonon::MediaSource)),this,SLOT(changename(Phonon::MediaSource)));
num=1;
list = new playlist(this);
list->installEventFilter(this);//事件过滤器
connect(list->ui->listWidget,SIGNAL(itemDoubleClicked(QListWidgetItem *)),SLOT(tableWidget_cellDoubleClicked(QListWidgetItem *)));//双击列表项目
//安装事件过滤器
//Widget类对象拦截发往vWidget对象的事件
vWidget->installEventFilter(this);
ui->frameVideo->installEventFilter(this);
ui->play->setIcon(QIcon(":/images/gtk-media-play-ltr.png"));
image = QImage(640,480,QImage::Format_RGB32); //初始化画布的大小,使用32位颜色
backColor = qRgb(255,255,255); //画布初始化背景色使用白色
image.fill(backColor);
image.load(":/images/beijing.jpg");
update();
connect(mObject,SIGNAL(aboutToFinish()),this,SLOT(mediaAboutToFinish()));
QSqlQuery query;
query.prepare("select *from filepath");
query.exec();
while(query.next())
{
QString path = query.value(0).toString();
Phonon::MediaSource source(path);
videoSourceList.append(source);//在当前列表后加入一条记录
mObject->setCurrentSource(Phonon::MediaSource(path));
QString name1;
name1=getname(name1);
name1=QString("%1.%2").arg(num).arg(path);
num++;
list->ui->listWidget->addItem(name1);//添加到列表
}
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::openfile()
{
QStringList thelist = QFileDialog::getOpenFileNames(
this, tr("播放文件"), tr("/"), "*.mp3;*.avi;*.mpg;;*.*");
if(thelist.isEmpty())
return;
foreach(QString name,thelist)
{
Phonon::MediaSource source(name);
videoSourceList.append(source);//在当前列表后加入一条记录
mObject->setCurrentSource(Phonon::MediaSource(name));
QSqlQuery query;
qDebug()<<name;
query.prepare("insert into filepath(path) values(?)");
query.bindValue(0,name);
query.exec();
name=getname(name);
name=QString("%1.%2").arg(num).arg(name);
num++;
list->ui->listWidget->addItem(name);//添加到列表
}
}
void MainWindow::wheelEvent(QWheelEvent *w)//滚轮事件
{
if(w->delta() > 0 )//上滚
{
qreal newvolume = aOutput->volume() + (qreal)0.05;
if(newvolume >= (qreal)1)
newvolume = (qreal)1;
aOutput->setVolume(newvolume);
}
else//下滚
{
qreal newvolume = aOutput->volume() - (qreal)0.05;
if(newvolume <= (qreal)0)
newvolume = (qreal)0;
aOutput->setVolume(newvolume);
}
}
void MainWindow::changeEvent(QEvent *e)
{
QWidget::changeEvent(e);
switch (e->type()) {
case QEvent::LanguageChange:
ui->retranslateUi(this);
break;
default:
break;
}
}
void MainWindow::keyPressEvent(QKeyEvent *t)
{
if(t->key()==Qt::Key_Space)
{
if(ifpause == true)
{
playmedia();
}
else
{
timer->stop();
mObject->pause();
ui->play->setIcon(QIcon(":/images/gtk-media-play-ltr.png"));
ifpause=true;
}
}
}
void MainWindow::resizeEvent(QResizeEvent *event)
{
vWidget->setGeometry(
ui->frameVideo->rect());
sSlider->setGeometry(
ui->frameSeek->rect());
vSlider->setGeometry(
ui->frameVolume->rect());
}
void MainWindow::paintEvent(QPaintEvent *)
{
QPainter painter;
painter.begin(this);
painter.drawImage(0,0,image);
painter.end();
}
void MainWindow::mouseMoveEvent(QMouseEvent *e)
{
//qDebug()<<e->pos();
}
void MainWindow::updateTime()
{
int th, tm, ts;
int ch, cm, cs;
th = mObject->totalTime()/1000/60/60;
tm = mObject->totalTime()/1000/60%60;
ts = mObject->totalTime()/1000%60;
ch = mObject->currentTime()/1000/60/60;
cm = mObject->currentTime()/1000/60%60;
cs = mObject->currentTime()/1000%60;
ui->labelTime->setText(QString("%1:%2:%3/%4:%5:%6").arg(ch).arg(cm).arg(cs).arg(th).arg(tm).arg(ts));
}
/*
* 事件过滤器
*/
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
if(vWidget == (Phonon::VideoWidget*)watched)
{//事件发往的对象是要拦截的对象吗?
if(event->type() == QEvent::MouseButtonDblClick)
{//事件类型是否是感兴趣的事件?
if(vWidget->isFullScreen())
{
vWidget->exitFullScreen();
resizeEvent(NULL);
if(this->isFullScreen())
setGeometry(posx,posy+40,w,h);
mObject->play();
}else
{
posx=this->x();//保存窗口大小位置
posy=this->y();
w=this->width();
h=this->height();
vWidget->enterFullScreen();
mObject->play();
}
return true;
}
if(event->type() == QEvent::KeyPress)
{
QKeyEvent * k = (QKeyEvent *)event;
if(k->key() == Qt::Key_Escape)
{//Escape键退出全屏
if(vWidget->isFullScreen())
{
vWidget->exitFullScreen();
resizeEvent(NULL);
if(this->isFullScreen())//还原原窗口位置大小
setGeometry(posx,posy+40,w,h);
return true;
}
}
}
if(event->type() == QEvent::MouseButtonPress)
{//左键快捷菜单
if(ifpause == true)
{
playmedia();
ui->stop->setEnabled(true);
}
else
{
mObject->pause(); //暂停播放
timer->stop();
ui->play->setIcon(QIcon(":/images/gtk-media-play-ltr.png"));
ifpause=true;
}
}
if(event->type() == QEvent::MouseMove)
{
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if(vWidget->isFullScreen())
{
if(mouseEvent->y()>800)
{
vWidget->exitFullScreen();
this->showFullScreen();
}
}
if(this->isFullScreen())
{
if(mouseEvent->y()<800)
{
vWidget->enterFullScreen();
}
}
}
}
if(watched == ui->frameVideo)
{
if(event->type() == QEvent::DragEnter)
{
QDragEnterEvent *dragEnterEvent = static_cast<QDragEnterEvent*>(event);
if(dragEnterEvent->mimeData()->hasFormat("text/uri-list"))
dragEnterEvent->acceptProposedAction();
}
if(event->type() == QEvent::Drop)
{
QDropEvent *dropEvent = static_cast<QDropEvent*>(event);
QList<QUrl> urls = dropEvent->mimeData()->urls();
if(urls.isEmpty())
{
return false;
}
QString fileName = urls.first().toLocalFile();
if (fileName.isEmpty())
{
return false;
}
int l =urls.length();
for(int i=0; i<l; i++)
{
QString string = urls.at(i).toString();
Phonon::MediaSource source(string);
videoSourceList.append(source);//在当前列表后加入一条记录
string=getname(string);
string=QString("%1.%2").arg(num).arg(string);
num++;
list->ui->listWidget->addItem(string);//添加到列表
}
mObject->setCurrentSource(Phonon::MediaSource(urls.at(l-1).toString()));
playmedia();
}
}
if(watched == list)//过滤表格的事件
{
if(event->type() == QEvent::ContextMenu)
{//右键快捷菜单
//#if 0
menu = new QMenu(this);
QAction * playthismedia = menu->addAction(tr("播放"));
QAction * remove = menu->addAction(tr("删除当前行"));
QAction * addlist = menu->addAction(tr("添加"));
QAction * removeall = menu->addAction(tr("清空列表"));
playthismedia->setIcon(QIcon(":/images/play1.png"));
remove->setIcon(QIcon(":/images/remove.png"));
addlist->setIcon(QIcon(":/images/gtk-open.png"));
removeall->setIcon(QIcon(":/images/remove.png"));
playthismedia->setCheckable(true);
remove->setCheckable(true);
addlist->setCheckable(true);
removeall->setCheckable(true);
connect(playthismedia, SIGNAL(triggered(bool)),this, SLOT(actionplaymedia(bool)));
connect(remove, SIGNAL(triggered(bool)),this, SLOT(actionremove(bool)));
connect(addlist, SIGNAL(triggered(bool)),this, SLOT(actionadd(bool)));
connect(removeall, SIGNAL(triggered(bool)),this, SLOT(actionremoveall(bool)));
//#endif
menu->exec(QCursor::pos());
}
if(event->type() == QEvent::DragEnter)
{
QDragEnterEvent *dragEnterEvent = static_cast<QDragEnterEvent*>(event);
if(dragEnterEvent->mimeData()->hasFormat("text/uri-list"))
dragEnterEvent->acceptProposedAction();
}
if(event->type() == QEvent::Drop)
{
QDropEvent *dropEvent = static_cast<QDropEvent*>(event);
QList<QUrl> urls = dropEvent->mimeData()->urls();
if(urls.isEmpty())
{
return false;
}
QString fileName = urls.first().toLocalFile();
if (fileName.isEmpty())
{
return false;
}
int l =urls.length();
for(int i=0; i<l; i++)
{
QString string = urls.at(i).toString();
Phonon::MediaSource source(string);
videoSourceList.append(source);//在当前列表后加入一条记录
string=getname(string);
string=QString("%1.%2").arg(num).arg(string);
num++;
list->ui->listWidget->addItem(string);//添加到列表
}
}
}
return false;
}
void MainWindow::on_open_triggered()
{
openfile();
playmedia();
}
void MainWindow::on_play_clicked()
{
if(ifpause==true)
{
playmedia();
ui->stop->setEnabled(true);
}
else
{
mObject->pause(); //暂停播放
timer->stop();
ui->play->setIcon(QIcon(":/images/gtk-media-play-ltr.png"));
ifpause=true;
}
}
void MainWindow::on_stop_clicked()
{
mObject->stop(); //停止播放
timer->stop();
ui->play->setIcon(QIcon(":/images/gtk-media-play-ltr.png"));
ui->stop->setEnabled(false);
ifpause=true;
}
void MainWindow::on_displayAuto_triggered()//画面设置
{
vWidget->setAspectRatio(Phonon::VideoWidget::AspectRatioAuto);
}
void MainWindow::on_displaywidget_triggered()//画面设置
{
vWidget->setAspectRatio(Phonon::VideoWidget::AspectRatioWidget);
}
void MainWindow::on_display4_3_triggered()//画面设置
{
vWidget->setAspectRatio(Phonon::VideoWidget::AspectRatio4_3);
}
void MainWindow::on_display15_9_triggered()//画面设置
{
vWidget->setAspectRatio(Phonon::VideoWidget::AspectRatio16_9);
}
void MainWindow::on_displayfull_triggered()//画面设置
{
posx=this->x();//保存窗口大小位置
posy=this->y();
w=this->width();
h=this->height();
vWidget->enterFullScreen();
mObject->play();
}
void MainWindow::playmedia()//播放文件
{
ui->play->setIcon(QIcon(":/images/gtk-media-pause.png"));
mObject->play(); //播放媒体
setWindowTitle(playing);
timer->start(1000);
ifpause=false;
}
void MainWindow::on_openfile_clicked()//打开文件
{
openfile();
playmedia();
}
void MainWindow::on_exit_triggered()//退出
{
close();
}
void MainWindow::on_fullcreen_clicked()//全屏
{
if(this->isFullScreen())
{
setGeometry(posx,posy+40,w,h);
}
else
{
posx=this->x();//保存窗口大小位置
posy=this->y();
w=this->width();
h=this->height();
vWidget->enterFullScreen();
}
}
void MainWindow::on_last_clicked()//上一部
{
int index = videoSourceList.indexOf(mObject->currentSource()) - 1;
if(index<0)
{
index=videoSourceList.size()-1;
}
mObject->stop();
mObject->setCurrentSource(videoSourceList.at(index));
playmedia();
}
void MainWindow::on_next_clicked()//下一部
{
int index = videoSourceList.indexOf(mObject->currentSource()) + 1;
if(index < videoSourceList.size())
{
mObject->stop();
mObject->setCurrentSource(videoSourceList.at(index));
playmedia();
}
else
{
index=0;
mObject->stop();
mObject->setCurrentSource(videoSourceList.at(index));
playmedia();
}
}
void MainWindow::on_list_clicked(bool checked)//打开列表
{
if(checked)
{
if((this->width()>=1200)&&(this->x()>=-10))
list->setGeometry(this->x()+this->width()-180,this->y()+30,200,this->height());//使播放列表适应主窗口大小
else
list->setGeometry(this->x()+this->width()+10,this->y()+30,200,this->height());//使播放列表适应主窗口大小
list->timer1->start(10);
list->show();
}
else
list->close();
}
void MainWindow::tableWidget_cellDoubleClicked(QListWidgetItem *t)
{
mObject->stop();
mObject->clearQueue();
int i=list->ui->listWidget->row(t);
mObject->setCurrentSource(Phonon::MediaSource(videoSourceList[i]));
playmedia();
}
QString MainWindow::getname(QString str)//获取不包含路径名的文件名
{
while((str.contains("\\",Qt::CaseSensitive))||(str.contains("/",Qt::CaseSensitive)))
{
str.replace(0,1,"");
}
return str;
}
void MainWindow::mediaAboutToFinish() //影片快结束时
{
int index = videoSourceList.indexOf(mObject->currentSource()) + 1; //下一部
if(videoSourceList.size() > index)
mObject->enqueue(videoSourceList.at(index));//注意:不会产生状态的改变state
}
void MainWindow::actionplaymedia(bool checked)//播放当前选项
{
if(list->ui->listWidget->count()!=0)
{
mObject->stop();
mObject->clearQueue();
mObject->setCurrentSource(Phonon::MediaSource(videoSourceList[list->ui->listWidget->currentRow()]));//获取当前行数
playmedia();
}
}
void MainWindow::actionremove(bool checked)//删除当前选项
{
int j = list->ui->listWidget->currentRow();
list->ui->listWidget->takeItem(j);
videoSourceList.removeAt(j);
num--;
int i;
for(i=j;i<list->ui->listWidget->count();i++) //更新列表
{
QString name= videoSourceList.at(i).fileName();
name=getname(name);
name=QString("%1.%2").arg(i+1).arg(name);
list->ui->listWidget->item(i)->setText(name);
}
}
void MainWindow::actionadd(bool checked)//添加到列表
{
QStringList thelist = QFileDialog::getOpenFileNames(
this, tr("播放文件"), tr("/"), "*.mp3;*.avi;*.mpg;;*.*");
if(thelist.isEmpty())
return;
foreach(QString name,thelist)
{
Phonon::MediaSource source(name);
videoSourceList.append(source);//在当前列表后加入一条记录
name=getname(name);
name=QString("%1.%2").arg(num).arg(name);
num++;
list->ui->listWidget->addItem(name);//添加到列表
}
}
void MainWindow::actionremoveall(bool checked)//清空列表
{
mObject->stop();
list->ui->listWidget->clear();
mObject->clear();
videoSourceList.clear();
num=1;
}
void MainWindow::changename(Phonon::MediaSource newvideo)
{
playing=QString("%1 %2").arg(tr("影音播放器")).arg(getname(newvideo.fileName()));
}
void MainWindow::on_denglu_triggered()
{
denglu dl;
connect(&dl,SIGNAL(sent(QString)),this,SLOT(recive(QString)));
dl.exec();
}
void MainWindow::recive(QString str)
{
ui->label_2->setText(str);
list->ui->listWidget->clear();
mObject->clear();
videoSourceList.clear();
num=1;
// void actionremoveall(bool checked);
QSqlQuery query;
query.prepare("select *from userpath where user = ?");
query.bindValue(0, ui->label_2->text());
query.exec();
while(query.next())
{
QString path = query.value(1).toString();
Phonon::MediaSource source(path);
videoSourceList.append(source);//在当前列表后加入一条记录
mObject->setCurrentSource(Phonon::MediaSource(path));
QString name1;
name1=getname(name1);
name1=QString("%1.%2").arg(num).arg(path);
num++;
list->ui->listWidget->addItem(name1);//添加到列表
}
}