无界面播放器
一、首先需要一个存放音乐文件的路径
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <glob.h>
#include <signal.h>
int menu(void);
void fun(int sig);
void clean(void);
glob_t song; //定义结构体变量
pid_t pid;
int cur = 0;
int num = 0;
int main()
{
atexit(clean); //atexit注册退出清理函数 ,当程序退出时,执行clean函数
glob("/home/gys/Kugou/*.mp3",0,NULL,&song);
// song.gl_pathc 获取的相应格式的文件个数
// song.gl_pathv 打印文件名
for(int i=0;i<song.gl_pathc;i++)
{
printf("%s\n",song.gl_pathv[i]); //打印文件名
}
pid = fork(); //创建进程 pid承接返回值
if (pid == 0) //子进程
{
execlp("mpg123","mpg123",song.gl_pathv[cur],NULL);
//在当前进程中运行另外一个进程,当前进程空间会被新进程取代
//int execlp(const char *file, const char *arg, ...);
//参数 file 是要执行的程序的路径,arg 是一个字符串,表示新程序的名称。接下来的参数是可选的,用于传递给新程序的命令行参数列表,最后一个参数必须为 NULL。
}
else if (pid > 0) //父进程
{
signal(17,fun); //信号17:子进程只要状态发生变化,父进程就能够接收到17号信号;
//设置信号处理程序,即在接收到特定信号时执行指定的处理函数
//void (*signal(int signum, void (*handler)(int)))(int);
//signum -- 信号 handler-- 对信号的处理方式
while(1)
{
num = menu();
switch(num)
{
case 1: kill(pid,19); break; //信号19:暂停进程
case 2: kill(pid,18); break; //信号18:恢复进程
case 3: cur++; //信号9:杀死进程,下一首
kill(pid,9);
break;
case 4: cur--; //上一首
kill(pid,9);
break;
case 0: signal(17,SIG_IGN); kill(pid,9); return 0; //SIG_IGN:对信号的忽略
}
}
}
return 0;
}
int menu(void)
{
printf("\t\t1:暂停播发音乐\n");
printf("\t\t2:继续继续播放\n");
printf("\t\t3:播放下一首音乐\n");
printf("\t\t4:播放上一首音乐\n");
printf("\t\t0:退出\n");
printf("请输入选项: \n");
scanf("%d",&num);
return num;
}
void fun(int sig) //传入的信号
{
int sta;
pid_t res = waitpid(-1,&sta,WNOHANG); //waitpid:等待指定子进程结束
//pid_t waitpid(pid_t pid, int *wstatus,int options);
//pid:-1(等待任意子进程结束) wstatus:进程退出时的状态
//options:填写0,表示阻塞等待
//填写:WNOHANG,表示不阻塞。子进程退出,为其收尸,不退出,直接就运行下一行代码,不阻塞当前进程
if(res == pid) //排除暂停恢复导致17信号的干扰
{
if(WIFEXITED(sta)) //返回值为真,子程序是正常退出,cur++
//WIFEXITED 宏接受一个整型参数 status,通常是 waitpid 或 wait 系列函数返回的子进程状态信息。
//如果子进程正常退出,WIFEXITED 宏将返回一个非零值,否则返回 0。
{
cur++;
}
if(cur == song.gl_pathc) //下一首,cur++,直到最后一首歌曲
cur = 0; //cur设置为初始值
if(cur < 0) //上一首,cur--,如果cur小于0,cur初始值设置为文件数量
cur = song.gl_pathc-1;
pid = fork(); //歌曲播放完,子进程结束,重新创建子进程
if(pid == 0)
{
execlp("mpg123","mpg123",song.gl_pathv[cur],NULL); //播放音乐
}
}
}
void clean(void)
{
system("stty echo"); //system:在当前进程中,并发运行另外一个进程
//使用 stty echo 命令时,它会打开终端的回显功能,即用户输入的字符会立即显示在终端上。
printf("\033[?25h"); //[?25h 会显示终端窗口中的光标,使光标可见。
}
有界面播放器
GUI的使用
1)创建工程
修改软件语言环境:
想要使用什么控件,从组件中使用鼠标直接拖拽到界面区域
2)图片按钮 按下之后更换图片
播放和暂停使用的是图片按钮,这里可以添加4张照片,但是要两两一致,第一张和最后一张保持一致,第二张那个和第三张保持一致。
添加播放和暂停的照片。
按键到这里就完成了。
创建工程生成的文件
在lvgl-simulator文件下Make生成可执行程序
运行生成的可执行程序
在生成工程的主函数里添加功能
main.c
**/
#define _DEFAULT_SOURCE /* needed for usleep() */
#include <stdlib.h>
#include <unistd.h>
#define SDL_MAIN_HANDLED /*To fix SDL's "undefined reference to WinMain" issue*/
#include <SDL2/SDL.h>
#include "lvgl/lvgl.h"
#include "lv_drivers/display/monitor.h"
#include "lv_drivers/indev/mouse.h"
#include "lv_drivers/indev/mousewheel.h"
#include "lv_drivers/indev/keyboard.h"
#include "gui_guider.h"
#include "events_init.h"
#include "custom.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <glob.h>
#include <signal.h>
/*********************
* DEFINES
*********************/
/*On OSX SDL needs different handling*/
#if defined(__APPLE__) && defined(TARGET_OS_MAC)
# if __APPLE__ && TARGET_OS_MAC
#define SDL_APPLE
# endif
#endif
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void hal_init(void);
static int tick_thread(void * data);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
lv_ui guider_ui;
void clean(void);
void fun(int sig);
glob_t song; //定义结构体变量
pid_t pid;
int cur = 0;
int main(int argc, char ** argv)
{
atexit(clean); //atexit注册退出清理函数 ,当程序退出时,执行clean函数
glob("/home/gys/Kugou/*.mp3",0,NULL,&song); //打印歌单
// song.gl_pathc 获取的相应格式的文件个数
// song.gl_pathv 打印文件名
for(int i=0;i<song.gl_pathc;i++)
{
printf("%s\n",song.gl_pathv[i]); //打印文件名
}
pid = fork(); //创建进程 pid承接返回值
if (pid == 0) //子进程
{
execlp("mpg123","mpg123",song.gl_pathv[cur],NULL);
//在当前进程中运行另外一个进程,当前进程空间会被新进程取代
//int execlp(const char *file, const char *arg, ...);
//参数 file 是要执行的程序的路径,arg 是一个字符串,表示新程序的名称。接下来的参数是可选的,用于传递给新程序的命令行参数列表,最后一个参数必须为 NULL。
}
else if (pid > 0) //父进程
{
signal(17,fun); //信号17:子进程只要状态发生变化,父进程就能够接收到17号信号;
//设置信号处理程序,即在接收到特定信号时执行指定的处理函数
//void (*signal(int signum, void (*handler)(int)))(int);
//signum -- 信号 handler-- 对信号的处理方式
}
(void) argc; /*Unused*/
(void) argv; /*Unused*/
/*Initialize LittlevGL*/
lv_init();
/*Initialize the HAL (display, input devices, tick) for LittlevGL*/
hal_init();
/*Create a GUI-Guider app */
setup_ui(&guider_ui);
events_init(&guider_ui);
custom_init(&guider_ui);
while(1) {
/* Periodically call the lv_task handler.
* It could be done in a timer interrupt or an OS task too.*/
lv_task_handler();
usleep(5 * 1000);
#ifdef SDL_APPLE
SDL_Event event;
while(SDL_PollEvent(&event)) {
#if USE_MOUSE != 0
mouse_handler(&event);
#endif
#if USE_KEYBOARD
keyboard_handler(&event);
#endif
#if USE_MOUSEWHEEL != 0
mousewheel_handler(&event);
#endif
}
#endif
}
return 0;
}
/**********************
* STATIC FUNCTIONS
**********************/
/**
* Initialize the Hardware Abstraction Layer (HAL) for the Littlev graphics library
*/
static void hal_init(void)
{
/* Use the 'monitor' driver which creates window on PC's monitor to simulate a display*/
monitor_init();
/*Create a display buffer*/
static lv_disp_buf_t disp_buf1;
static lv_color_t buf1_1[480*10];
lv_disp_buf_init(&disp_buf1, buf1_1, NULL, 480*10);
/*Create a display*/
lv_disp_drv_t disp_drv;
lv_disp_drv_init(&disp_drv); /*Basic initialization*/
disp_drv.buffer = &disp_buf1;
disp_drv.flush_cb = monitor_flush; /*Used when `LV_VDB_SIZE != 0` in lv_conf.h (buffered drawing)*/
lv_disp_drv_register(&disp_drv);
/* Add the mouse as input device
* Use the 'mouse' driver which reads the PC's mouse*/
mouse_init();
lv_indev_drv_t indev_drv;
lv_indev_drv_init(&indev_drv); /*Basic initialization*/
indev_drv.type = LV_INDEV_TYPE_POINTER;
indev_drv.read_cb = mouse_read; /*This function will be called periodically (by the library) to get the mouse position and state*/
lv_indev_t * mouse_indev = lv_indev_drv_register(&indev_drv);
/* Tick init.
* You have to call 'lv_tick_inc()' in periodically to inform LittelvGL about how much time were elapsed
* Create an SDL thread to do this*/
SDL_CreateThread(tick_thread, "tick", NULL);
}
/**
* A task to measure the elapsed time for LittlevGL
* @param data unused
* @return never return
*/
static int tick_thread(void * data)
{
(void)data;
while(1) {
SDL_Delay(5); /*Sleep for 5 millisecond*/
lv_tick_inc(5); /*Tell LittelvGL that 5 milliseconds were elapsed*/
}
return 0;
}
void clean(void)
{
signal(17,SIG_IGN);
kill(pid,9);
system("stty echo"); //system:在当前进程中,并发运行另外一个进程
//使用 stty echo 命令时,它会打开终端的回显功能,即用户输入的字符会立即显示在终端上。
printf("\033[?25h"); //[?25h 会显示终端窗口中的光标,使光标可见。
}
void fun(int sig) //传入的信号
{
int sta;
pid_t res = waitpid(-1,&sta,WNOHANG); //waitpid:等待指定子进程结束
//pid_t waitpid(pid_t pid, int *wstatus,int options);
//pid:-1(等待任意子进程结束) wstatus:进程退出时的状态
//options:填写0,表示阻塞等待
//填写:WNOHANG,表示不阻塞。子进程退出,为其收尸,不退出,直接就运行下一行代码,不阻塞当前进程
if(res == pid) //排除暂停恢复导致17信号的干扰
{
if(WIFEXITED(sta)) //返回值为真,子程序是正常退出,cur++
//WIFEXITED 宏接受一个整型参数 status,通常是 waitpid 或 wait 系列函数返回的子进程状态信息。
//如果子进程正常退出,WIFEXITED 宏将返回一个非零值,否则返回 0。
{
cur++;
}
if(cur == song.gl_pathc) //下一首,cur++,直到最后一首歌曲
cur = 0; //cur设置为初始值
if(cur < 0) //上一首,cur--,如果cur小于0,cur初始值设置为文件数量
cur = song.gl_pathc-1;
pid = fork(); //歌曲播放完,子进程结束,重新创建子进程
if(pid == 0)
{
execlp("mpg123","mpg123",song.gl_pathv[cur],NULL); //播放音乐
}
}
}
void events_init(lv_ui *ui)
{
}
static void screen_img_2event_handler(lv_obj_t * obj, lv_event_t event)
{
switch (event)
{
case LV_EVENT_PRESSED:
{
printf("播放上一首\n");
cur--;
kill(pid,9);
}
break;
default:
break;
}
}
static void screen_img_3event_handler(lv_obj_t * obj, lv_event_t event)
{
switch (event)
{
case LV_EVENT_PRESSED:
{
printf("播放下一首\n");
cur++;
kill(pid,9);
}
break;
default:
break;
}
}
static void screen_imgbtn_1event_handler(lv_obj_t * obj, lv_event_t event)
{
switch (event)
{
case LV_EVENT_PRESSED:
{
printf("中间按钮被按下\n");
butt++;
if(butt % 2 == 0)
{
kill(pid,18);
}
else if(butt %2 != 0)
kill(pid,19);
break;
default:
break;
}
}
}
void events_init_screen(lv_ui *ui)
{
lv_obj_set_event_cb(ui->screen_img_2, screen_img_2event_handler);
lv_obj_set_event_cb(ui->screen_img_3, screen_img_3event_handler);
lv_obj_set_event_cb(ui->screen_imgbtn_1, screen_imgbtn_1event_handler);
}