各位看官,本人 不吃鱼刺的科技猫(tech_cat)熬个夜把之前的写的小项目拿了出来复习了一番,之前花了一段时间写了一个基于
linux的
mplayer的Qt界面化音乐
播放器。就在QT社区共享一下,与诸位大佬讨论一下技术,在这也感谢 QTCN 平台


。
文中哪里写的不对和不好,尽管赐教, tech_act 大恩不言谢

。
本次调试并解决大部分bug:
- 歌词和歌曲不同步
- 点击pause 按钮再点击下一首歌曲出现程序异常
- 在歌曲暂时的时候拖动音量条,歌曲时间进度不动
- 音量一开始为0,但是也有声音播放
- 按下pause按钮定时器不停止
- 等等诸多问题
下面为大家简单介绍一个所用原理和主要代码也给大家附上(本人没想到字数才5000,只能附上这些代码了,有需要的话可以交流)。
首先,本次的基本播放器小项目所用详细原理如下:
- 在QT 中创建父子进程,子进程 execlp 调用 linux 下的 mplayer 可执行程序,父进程通过创建的 有名管道用于向 mplayer 的slave模式(注:slave 模式用于用户开发mplayer模式)下写入命令,使播放器实现想要的功能,如seek value 、 get_time_length等等。
- 通过无名管道来获取子进程 mplayer 在 stdout 流中的数据情况,以便调试相应功能。
- 一开始本来想直接用文件 IO 来遍历文件获取歌单,想了一下还是用 标准 IO 兼容一些,文件不大,速率影响也不大;获取的歌单用 vector 进行动态存储,再通过 Qpushbutton 来触发信号 来连接槽函数,槽函数中用来 vector 的 iterator 来获取上下歌曲名; (注:若歌曲少的话,建议可以使用数组来存储,毕竟数组访问元素速度最快嘛)
- 再通过歌曲信息来进行对歌词解析存储,本次采用 vector 存储 class 类型,class 类中用有歌曲时间和歌词两个成员。本想用 链表进行存储的 但感觉会代码很乱, 各位看官怎么看?
- 最后就是一些小细节问题了,歌词显示用了Qlistwdight 控件等等。
然后呢,就是项目功能:
- 可以动态显示当前歌曲的歌名、作曲者、专辑歌词信息
- 歌词显示可以随进度变化而变化,使所唱的歌词实时显示
- 可以点击上一曲和下一曲以及暂停
- 拖动音量可以显示音量数值
- 点击文件夹图标可以显示歌单和关闭歌单
- 可以拖动时间进度条,随之歌曲和歌词同步等
下期说一下 用户
界面登录 注册的全面代码!

Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("MP3");
unlink("./myfifo");
pipe(pipe_fd);
int ret = mkfifo("./myfifo", O_CREAT | 0666);
if( ret < 0)
{
perror("mkfifo error:");
}
fd = open ("./myfifo", O_RDWR);
if( fd < 0)
{
perror("open rror");
}
s_pid = fork();
if( s_pid==0 )
{
dup2(pipe_fd[1],1);
execlp("mplayer","mplayer","-slave", "-idle", "-quiet", "-input","file=./myfifo",\
"/home/edu/QT/project/music_1/build-music_1-Desktop_Qt_5_4_2_GCC_64bit-Debug/song_new/StopLove.mp3",NULL);
}else{
sleep(1);
}
get_volume();
ui->volume->setRange(0,100);
get_play_list();
timer = new QTimer(this);
timer->start(1000);
memset(buff_clr,0,sizeof(buff_clr));
strcpy(buff_clr, "/home/edu/QT/project/music_1/build-music_1-Desktop_Qt_5_4_2_GCC_64bit-Debug/song_new/StopLove.mp3");
lrc = new Lrc(buff_clr);
set_lrccinfo(lrc);
ui->Pos->setMinimum(0);
ui->Pos->setMaximum(lrc->lrcVector.back()->lrc_time);
ui->listWidget->clear();
ui->song_list->hide();
connect(timer,SIGNAL(timeout()), this, SLOT(mytimer()));
// connect(this,&Widget::time_end, this, &Widget::on_N_clicked);
connect(this,SIGNAL(time_end()),this,SLOT(on_N_clicked()));
connect(ui->volume,SIGNAL(sliderPressed()), this,SLOT(trans_signal()));
connect(this,SIGNAL(volume_change_pause()), this,SLOT(on_P_clicked()));
connect(ui->Pos,SIGNAL(valueChanged(int)),this,SLOT(sliderValueChangedSlot(int)));
}
Widget::~Widget()
{
kill(s_pid,9);
delete ui;
}
if( time_pos == (lrc->lrcVector.back()->lrc_time ))
{
emit time_end();
}
}
//***************** get_timelength ********************
void Widget::get_time_length(void)
{
int ret = write(fd, "get_time_length\n",strlen("get_time_length\n"));
if(ret < 0)
{
qDebug()<<"write erro"<<endl;
}
int ret2 = read(pipe_fd[0], good_buff,sizeof(good_buff));
if(ret2 < 0)
{
perror("read error");
}
qDebug()<<good_buff;
int time_length = 0;
sscanf(good_buff, "ANS_LENGTH=%d",&time_length);
qDebug()<< " --------" << time_length;
int min = 0, sec = 0;
min = time_length/60;
sec = time_length%60;
char mytime[6]={'0'};
ui->current_time->setText(mytime);
sprintf(mytime,"%02d:%02d",min,sec);
qDebug()<< mytime;
ui->Tlength->setText(mytime);
ui->Pos->setMaximum(time_length);
memset(good_buff,0,sizeof(good_buff));
}
//pause
void Widget::on_P_clicked()
{
write(fd, "pause\n", strlen("pause\n"));
if( !time_flag )
{
ui->P->setIcon(QIcon(":/image/button_style/front1.png"));
time_flag = 1;
timer->stop();
}else{
ui->P->setIcon(QIcon(":/image/button_style/pause1.png"));
time_flag = 0;
timer->start();
}
}
//former song
void Widget::on_F_clicked()
{
memset(bad_buff,0,sizeof(bad_buff));
if(currentSong == playlist.begin())
{
currentSong = playlist.end(); //the point next ,so error
qDebug()<< "-------end of song --------"<< endl;
}
currentSong--;
std::string tempStr = (*currentSong).toStdString();
const char* cStr = tempStr.c_str();
char arr[128]={};
sprintf(arr,"loadfile /home/edu/QT/project/music_1/build-music_1-Desktop_Qt_5_4_2_GCC_64bit-Debug/song_new/%s\n",cStr);
//************************************************
memset(buff_clr,0,sizeof(buff_clr));
sprintf(buff_clr, "/home/edu/QT/project/music_1/build-music_1-Desktop_Qt_5_4_2_GCC_64bit-Debug/song_new/%s",cStr);
lrc = new Lrc(buff_clr);
set_lrccinfo(lrc);
ui->Pos->setMinimum(0);
ui->Pos->setMaximum(lrc->lrcVector.back()->lrc_time);
if( lrc->lrc_error_flag == -1)
{
QMessageBox::information(this,"worning","lrc is not exsits");
}
time_pos = -1 ;
time_flag = 0;
vector_pos = -1;
timer->start();
//**************************************************
qDebug() << "Loading file: " << arr;
write(fd, arr, strlen(arr));
}
//next song
void Widget::on_N_clicked()
{
qDebug()<<"time______end---------";
this->timer->stop();
currentSong++;
if(currentSong == playlist.end())
{
currentSong = playlist.begin(); //the point next ,so error
qDebug()<< "-------begin of song --------"<< endl;
}
std::string tempStr = (*currentSong).toStdString();
const char* cStr = tempStr.c_str();
char arr[128]={};
sprintf(arr,"loadfile /home/edu/QT/project/music_1/build-music_1-Desktop_Qt_5_4_2_GCC_64bit-Debug/song_new/%s\n",cStr);
//************************************************
memset(buff_clr,0,sizeof(buff_clr));
sprintf(buff_clr, "/home/edu/QT/project/music_1/build-music_1-Desktop_Qt_5_4_2_GCC_64bit-Debug/song_new/%s",cStr);
lrc = new Lrc(buff_clr);
set_lrccinfo(lrc);
ui->Pos->setMinimum(0);
ui->Pos->setMaximum(lrc->lrcVector.back()->lrc_time);
if( lrc->lrc_error_flag == -1)
{
QMessageBox::information(this,"worning","lrc is not exsits");
}
//**************************************************
qDebug() << "Loading file: " << arr;
write(fd, arr, strlen(arr));
qDebug()<< "from---------";
timer->start();
qDebug()<<"latter-------";
time_pos = -1;
time_flag = 0;
vector_pos=-1;
}
//get song-list
void Widget::get_play_list(void)
{
char *path_song = "/home/edu/QT/project/music_1/build-music_1-Desktop_Qt_5_4_2_GCC_64bit-Debug/song_new";
DIR *dir = opendir(path_song);
struct dirent *p = NULL;
if( dir )
{
while( p = readdir(dir) )
{
if( strcasecmp(p->d_name + strlen(p->d_name)-4, ".mp3") == 0)
{
playlist.push_back(p->d_name);
}
}
}else {
perror(" dir NULL :");
}
//show songs
ui->song_list->setPlainText("歌单:");
for(const
QString &song :playlist)
{
qDebug("%s",qPrintable(song)) ;
ui->song_list->append(song);
song_num++;
}
qDebug()<< song_num << endl;
currentSong = playlist.begin();
}
//****************** get_volume **************************
void Widget::get_volume(void)
{
read(pipe_fd[0],bad_buff,sizeof(bad_buff));
memset(bad_buff,0,sizeof(bad_buff));
int ret = write(fd, "get_property volume\n",strlen("get_property volume\n"));
if(ret < 0)
{
qDebug()<<"write erro"<<endl;
}
int ret2 = read(pipe_fd[0], good_buff,sizeof(good_buff));
if(ret2 < 0)
{
perror("read error");
}
qDebug()<<"@@@@@@@@@@@@@@@@@@@@@"<<good_buff<<endl;
int G_volume = 0;
sscanf(good_buff, "ANS_volume=%d",&G_volume);
memset(good_buff,0,sizeof(good_buff));
qDebug()<< " --------" << G_volume;
ui->volume->setValue(G_volume+1);
ui->volume_1->setValue(G_volume+1);
}
//show volume
void Widget::on_volume_1_valueChanged(int arg1)
{
ui->volume->setValue(arg1);
}
//adapt volume
void Widget::on_volume_valueChanged(int value)
{
ui->volume_1->setValue(value);
sprintf(buff,"volume %d 1\n",value);
qDebug()<<"buff:"<<buff<<endl;
write(fd, buff, strlen(buff));
memset(buff, 0, sizeof(buff));
}
//adapt pos
void Widget::sliderValueChangedSlot(int value)
{
time_flag = 0;
usleep(10);
this->timer->stop();
if(value != time_pos)
{
char str[128] = {};
double precent = std::round((double)value /lrc->lrcVector.back()->lrc_time *100 );
sprintf(str, "seek %lf 1\n", precent);
qDebug()<< str;
//write(fd, "seek %d 2\n", value - time_pos);
if(write(fd, (char *)str, strlen(str)) < 0)
{
printf("write error");
return ;
}
// timer->start();
}
//设置时间标签
int min = 0, sec = 0;
min = value /60;
sec = value % 60;
char mytime[6] = "";
sprintf(mytime,"%02d:%02d",min,sec);
ui->current_time->setText(mytime);
// //更改歌词位置
time_pos = value;
if(time_pos != lrc->lrcVector[vector_pos]->lrc_time)
{
if(time_pos < lrc->lrcVector[vector_pos]->lrc_time)
{
while (vector_pos > 0 && time_pos < lrc->lrcVector[vector_pos]->lrc_time)
{
vector_pos--;
}
} else {
while (vector_pos < lrc->lrcVector.size() - 1 && time_pos > lrc->lrcVector[vector_pos]->lrc_time) {
vector_pos++;
}
//change pause
void Widget::trans_signal()
{
if(time_flag ==1)
{
emit volume_change_pause();
}
}
void Widget::on_sing_list_clicked()
{
if(!flag_list)
{
flag_list = 1;
ui->song_list->show();
}else{
flag_list = 0;
ui->song_list->hide();
}
}