无界面播放器
一、首先需要一个存放音乐文件的路径
#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_APPLESDL_Event event;while(SDL_PollEvent(&event)) {
#if USE_MOUSE != 0mouse_handler(&event);
#endif#if USE_KEYBOARDkeyboard_handler(&event);
#endif#if USE_MOUSEWHEEL != 0mousewheel_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);
}