基本功能
- 播放歌曲
- 前台控制:播放、暂停、上一首、下一首。
- 显示当前歌曲列表。
- 显示歌曲信息(歌曲总长度、当前播放时间、歌曲进度百分比、歌手名)。
- 自动播放下一首。
- 同步显示歌词(扩展)。
流程图
mplayer启动方式
execlp("mplayer", "mplayer", "-slave", "-quiet", "-idle", "-input", "file=./cmdfifo", name, NULL);
//cmdfifo是命名管道,当写入命令数据后,mplayer自动读取执行
//name是带路径的歌曲名称
参数:
- -slave 运行在从模式,从命令行读取以新行(\n)分隔开的命令行。
- -quiet 使得控制台输出消息较少。
- -idle 播放至文件结尾后,mplayer不退出。
- -input file=./cmdfifo 通过命令管道 ./cmdfifo获取命令。
- ./ShapeofMyHeart.mp3 歌曲的路径 +文件名。
- NULL exec 系统调用必备。
Mplayer在 slave模式下常用的命令
- loadfile string //播放 string指定的歌曲
- volume x 1 //设置音量
- mute 1/0 //静音开关, 1:静音, 0:取消静音
- pause //暂停 //取消暂停
- seek value //快进或退的秒数, value为正时,快进; value为负时,快退。
- get_percent_pos //获取文件的播放进度(百分比: 0-100)
- get_time_pos //获得文件的当前位置,以秒为单位,精确到小数点后 1位。
- get_file_name //获得当前播放的文件名
- get_time_length //获得文件的长度,以秒为单位
- get_meta_album //获得文件的“专辑”元数据
- get_meta_artist //获得文件的“艺术家”元数据
- get_meta_commnet //获得文件的“评论”元数据
- get_meta_genre //获得文件的“流派”元数据
- get_meta_title //获得文件的“标题”元数据
- get_meta_year //获得文件的“年份”元数据
程序下载
https://download.csdn.net/download/mrhjlong/9625748
main.c 代码
自我批评:
程序应减少使用较多的全局变量,防止函数里重命名就行覆盖,产生问题。
项目整体结构还可以调整地更好、更加清晰明了。
/*************************************************************************
> File Name: mplayer.c
> Author: mrhjlong
> Mail: mrhjlong@163.com
> Created Time: 2016年07月23日 星期六 15时27分19秒
************************************************************************/
#include "songplay.h"
extern int flag; //显示数据标志 1:显示 0:不显示
extern Song *pnow; //当前歌曲结点指针
extern Song *plast; //最后一个歌曲结点指针(使用的是双向链表,不是双向循环链表,可以改进)
extern int clsthread; //关闭线程标志
extern int flagpause; //暂停标志
extern int fdpp[2]; //无名管道
extern sem_t sem; //信号量
int main(void)
{
List_head *linklist = get_song_list("./");
node_print(linklist);
pnow = linklist->head;
char name[NAMESIZE] = {0};
strcat(name, "./");
strcat(name, pnow->name);
int ret = sem_init(&sem, 0, 1); //信号量初始化
if(ret == -1)
err_sys("sem_init error");
if(access("./cmdfifo", F_OK) == 0) //判断命名管道是否存在,有则删除,重新新建
{
// printf("cmdfifo exist\n");
unlink("./cmdfifo");
mkfifo("./cmdfifo", 0777);
}
else
{
mkfifo("./cmdfifo", 0777);
}
if(pipe(fdpp) < 0)
err_sys("pipe error");
fcntl(fdpp[0], F_SETFL, O_NONBLOCK); //无名管道设为非阻塞
pid_t pid = fork(); //创建进程
if(pid < 0)
err_sys("fork error");
else if(pid == 0) //子进程
{
close(fdpp[0]);
dup2(fdpp[1], 1); //将标准输出定向到无名管道的写入
execlp("mplayer", "mplayer", "-slave", "-quiet", "-idle", "-input", "file=./cmdfifo", name, NULL); //命名管道cmdfifo有命令数据,mplayer会自动读取
}
else //父进程
{
close(fdpp[1]);
sleep(1);
pthread_t get_tid1, get_tid2, get_tid3;
ret = 0;
//创建处理线程
ret = pthread_create(&get_tid1, NULL, getcmd_thread, (List_head *)linklist);
if(ret != 0)
err_sys("pthread_create error");
ret = pthread_create(&get_tid2, NULL, datacmd_thread, NULL);
if(ret != 0)
err_sys("pthread_create error");
//sleep(1);
//char data[1024] = {0};
//read(fd[0], data, 1024); //清除冗余信息
ret = pthread_create(&get_tid3, NULL, read_thread, (List_head *)linklist);
if(ret != 0)
err_sys("pthread_create error");
//等待线程结束
pthread_join(get_tid1, NULL);
pthread_join(get_tid2, NULL);
pthread_join(get_tid3, NULL);
sem_destroy(&sem); //销毁信号量
list_destroy(linklist); //销毁链表
}
//sleep(1);
return 0;
}
songplay.h 代码
/*************************************************************************
> File Name: songplay.h
> Author: mrhjlong
> Mail: mrhjlong@163.com
> Created Time: 2016年07月24日 星期日 13时08分01秒
************************************************************************/
#ifndef __SONGPLAY_H
#define __SONGPLAY_H
#include<stdio.h>
#include"common.h"
#include"songplay.h"
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<dirent.h>
#include<pthread.h>
#include<semaphore.h>
#define NAMESIZE 50
struct song
{
char name[NAMESIZE];
struct song *next;
struct song *prev;
};
struct list_head
{
struct song *head;
int song_num;
};
typedef struct song Song;
typedef struct list_head List_head;
//创建链表头
List_head *head_create(void);
//创建结点
Song *node_create(char *name);
//添加结点到链表尾部
void node_insert_tail(List_head *linklist, Song *pSong);
//打印整张链表
void node_print(List_head *linklist);
//查找结点数据,返回结点地址,失败返回NULL
Song *node_search(List_head *linklist, char *name);
//销毁整张链表
void list_destroy(List_head *linklist);
//获得歌曲链表
List_head *get_song_list(char *pathname);
//带空格的歌曲名转换格式,空格前加"\"
void chgform(char *name);
//切换歌曲
void chgsong(char *name);
//处理线程读取的数据
void deal_data(char *data);
//获取按键输入命令-线程
void *getcmd_thread(void *arg);
//读取数据并处理-线程
void *read_thread(void *arg);
//定时发送命令获取数据-线程
void *datacmd_thread(void *arg);
#endif