系统编程之实战小项目-利用LVGL 与 mplayer制作音频播放器
设计目标:利用LVGL 与 mplayer制作音频播放器
功能描述:
1.实现基本的音乐播放器功能 暂停,播放,音量调节 ,音乐切换
2.实现播放列表
3.实现进度条控制音乐
设计方案
基于lvgl9.0库进行设计播放器ui,播放列表,进度条,按钮,利用多线程进行调用mplayer播放器进行音乐暂停,播放,音量调节 ,音乐切换。
系统框架
界面设计:(ui没花太多时间设计,丑勿喷hh)
实现过程
主界面设置:
// ==========主界面 ================void my_main(void)
{//lv_obj_add_state(currentButton, LV_STATE_CHECKED);//向对象添加一个或多个状态。lv_obj_t * label;lv_obj_t * btn1 = lv_btn_create(lv_scr_act());lv_obj_add_event_cb(btn1, event_handler_up, LV_EVENT_CLICKED,"last");lv_obj_align(btn1, LV_ALIGN_BOTTOM_MID,-300, 0);label = lv_label_create(btn1);lv_label_set_text(label, "last");lv_obj_center(label);lv_obj_t *wplast = lv_img_create(label);lv_img_set_src(wplast,"S:/demo/lvgl_img/last.jpg");lv_obj_t * btn2 = lv_btn_create(lv_scr_act());lv_obj_add_event_cb(btn2, event_handler_dn, LV_EVENT_CLICKED,"next");lv_obj_align(btn2, LV_ALIGN_BOTTOM_MID,300, 0);label = lv_label_create(btn2);lv_label_set_text(label, "next");lv_obj_center(label);lv_obj_t *wpnext = lv_img_create(label);lv_img_set_src(wpnext,"S:/demo/lvgl_img/next.jpg");lv_obj_t * btn_start = lv_btn_create(lv_scr_act());lv_obj_add_event_cb(btn_start, event_handler_play, LV_EVENT_CLICKED,"play");lv_obj_align(btn_start, LV_ALIGN_BOTTOM_MID, 0, 0);label = lv_label_create(btn_start);lv_label_set_text(label, "play");lv_obj_center(label); lv_obj_t *wpplay = lv_img_create(label);lv_img_set_src(wpplay,"S:/demo/lvgl_img/play.jpg");lv_obj_t * btn_stop = lv_btn_create(lv_scr_act());lv_obj_add_event_cb(btn_stop, event_handler_play, LV_EVENT_CLICKED,"stop");lv_obj_align(btn_stop, LV_ALIGN_BOTTOM_MID, 0, -60);label = lv_label_create(btn_stop);lv_label_set_text(label, "stop");lv_obj_center(label); lv_obj_t *wpstop = lv_img_create(label);lv_img_set_src(wpstop,"S:/demo/lvgl_img/stop.jpg");lv_obj_t * btn_fast = lv_btn_create(lv_scr_act());lv_obj_add_event_cb(btn_fast, event_handler_play, LV_EVENT_CLICKED,"fast");lv_obj_align(btn_fast, LV_ALIGN_BOTTOM_MID,200, 0);label = lv_label_create(btn_fast);lv_label_set_text(label, "fast");lv_obj_center(label); lv_obj_t *wpfast = lv_img_create(label);lv_img_set_src(wpfast,"S:/demo/lvgl_img/fast.jpg"); lv_obj_t * btn_slow = lv_btn_create(lv_scr_act());lv_obj_add_event_cb(btn_slow, event_handler_play, LV_EVENT_CLICKED,"slow");lv_obj_align(btn_slow, LV_ALIGN_BOTTOM_MID,-200, 0);label = lv_label_create(btn_slow);lv_label_set_text(label, "slow");lv_obj_center(label); lv_obj_t *wpslow = lv_img_create(label);lv_img_set_src(wpslow,"S:/demo/lvgl_img/slow.jpg"); lv_obj_t * btn_control = lv_btn_create(lv_scr_act());lv_obj_add_event_cb(btn_control, event_handler_play, LV_EVENT_CLICKED,"control+");lv_obj_align(btn_control, LV_ALIGN_BOTTOM_LEFT,0, -250);label = lv_label_create(btn_control);lv_label_set_text(label, "control+");lv_obj_center(label); lv_obj_t *wpadd = lv_img_create(label);lv_img_set_src(wpadd,"S:/demo/lvgl_img/add.jpg");lv_obj_t * btn_control1 = lv_btn_create(lv_scr_act());lv_obj_add_event_cb(btn_control1, event_handler_play, LV_EVENT_CLICKED,"control-");lv_obj_align(btn_control1, LV_ALIGN_BOTTOM_LEFT,0, -180);label = lv_label_create(btn_control1);lv_label_set_text(label, "control-");lv_obj_center(label); lv_obj_t *wpredu = lv_img_create(label);lv_img_set_src(wpredu,"S:/demo/lvgl_img/reduce.jpg");/*创建进度滑动条*/slider = lv_slider_create(lv_scr_act());//设置宽度lv_obj_set_content_width(slider,600);lv_obj_align(slider, LV_ALIGN_BOTTOM_MID,0, -130);; //设置当前空间的原点坐标//滑动条的值被改变时发送事件lv_obj_add_event_cb(slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL);/*进度条在滑块下面创建一个标签 */slider_label = lv_label_create(lv_scr_act());lv_label_set_text(slider_label, "0:00");//设置位置lv_obj_align_to(slider_label, slider, LV_ALIGN_LEFT_MID, -50, 0);slider_label1 = lv_label_create(lv_scr_act());lv_label_set_text(slider_label1, "0:00");//设置位置lv_obj_align_to(slider_label1, slider, LV_ALIGN_RIGHT_MID, 40, 0); //进度条static lv_style_t style_indic;//初始化样式lv_style_init(&style_indic);lv_style_set_bg_opa(&style_indic, LV_OPA_COVER);lv_style_set_bg_color(&style_indic, lv_palette_main(LV_PALETTE_RED));lv_style_set_bg_grad_color(&style_indic, lv_palette_main(LV_PALETTE_BLUE));lv_style_set_bg_grad_dir(&style_indic, LV_GRAD_DIR_VER);//创建进度条lv_obj_t * bar1 = lv_bar_create(lv_scr_act());lv_obj_add_style(bar1, &style_indic, LV_PART_INDICATOR);lv_obj_set_size(bar1, 20, 200);lv_obj_align(bar1, LV_ALIGN_RIGHT_MID,-220, -30);lv_bar_set_range(bar1, -20, 40);//动画lv_anim_t a;lv_anim_init(&a);lv_anim_set_exec_cb(&a, set_temp);//设置一个函数使“var”动画化lv_anim_set_time(&a, 300);//设置动画的持续时间lv_anim_set_playback_time(&a, 300);//使动画回放到前进方向准备好时lv_anim_set_var(&a, bar1);//设置一个变量为animatelv_anim_set_values(&a, -20, 40);//设置动画的开始和结束值lv_anim_set_repeat_count(&a, LV_ANIM_REPEAT_INFINITE);//让动画重复自己。参数给0停止动画。lv_anim_start(&a);//创建进度条bar = lv_bar_create(lv_scr_act());lv_obj_add_style(bar, &style_indic, LV_PART_INDICATOR);lv_obj_set_size(bar, 20, 200);lv_obj_align(bar, LV_ALIGN_LEFT_MID, 190, -50);lv_bar_set_range(bar, 0, 100);volume = 100;lv_bar_set_value(bar, volume, LV_ANIM_OFF); /*进度条在上面创建一个标签 */volume_label = lv_label_create(lv_scr_act());lv_label_set_text(volume_label, "100");//设置位置lv_obj_align_to(volume_label, bar, LV_ALIGN_TOP_MID, 0, -20);lv_obj_t * label_imgs = lv_img_create(lv_scr_act());lv_obj_set_size(label_imgs,30,30);lv_obj_align_to(label_imgs, bar, LV_ALIGN_BOTTOM_MID, 0, 33);lv_img_set_src(label_imgs,"S:/demo/yinxiang.jpg"); }
通过按钮触发事件然后新建线程启动播放器mplayer命令:mplayer -slave -quiet -input file=/pipe bsj.mp3 播放下一首需要关闭原有的线程和mplayer进程 killall -9 mplayer
部分代码演示:
//播放暂停快进等按钮操作
static void event_handler_play(lv_event_t * e)
{lv_event_code_t code = lv_event_get_code(e);//获取传递的参数 char *bt = lv_event_get_user_data(e);char bufshow[1024] = {0};if(code == LV_EVENT_CLICKED) {if(strcmp(bt,"play") == 0){system("killall -9 mplayer") ; ;//关闭原有的进程pthread_create(&tid,NULL,music_task,NULL);sleep(1);//取消前一个调用的更新线程pthread_cancel(getstr_tid);pthread_cancel(upbar_tid); pthread_create(&getstr_tid,NULL,music_task_getstr,NULL);pthread_create(&upbar_tid,NULL,update_progree_bar,NULL); }if(strcmp(bt,"stop") == 0){ if(stop_state == 0){pthread_cancel(getstr_tid);pthread_cancel(upbar_tid); char cmd[1024]={"pause\n"};write(fd_pipe,cmd,strlen(cmd)); stop_state = 1;}else{pthread_create(&getstr_tid,NULL,music_task_getstr,NULL);pthread_create(&upbar_tid,NULL,update_progree_bar,NULL); char cmd[1024]={"pause\n"};write(fd_pipe,cmd,strlen(cmd)); stop_state = 0; }} if(strcmp(bt,"fast") == 0){char cmd[1024]={"seek +5\n"};write(fd_pipe,cmd,strlen(cmd)); }if(strcmp(bt,"slow") == 0){char cmd[1024]={"seek -5\n"};write(fd_pipe,cmd,strlen(cmd)); } if(strcmp(bt,"control+")== 0 ){volume ++ ;if(volume >= 100) volume =100;char cmd[1024]={0};sprintf(cmd,"volume %d 1\n",volume);write(fd_pipe,cmd,strlen(cmd)); char buf[12] = {0};sprintf(buf,"%d",volume);} if(strcmp(bt,"control-")==0){volume -- ;if(volume <= 0) volume =0; char cmd[1024]={0};sprintf(cmd,"volume %d 1\n",volume);write(fd_pipe,cmd,strlen(cmd)); lv_bar_set_value(bar, volume, LV_ANIM_OFF); char buf[12] = {0};sprintf(buf,"%d",volume);lv_label_set_text(volume_label, buf); } }
}
开启一个线程不断读取popen打开mplayer输出的东西打印到进度条标签实现进度条时间变化 根据进度条时间调节mplayer的播放时间
部分代码演示:
void *music_task_getstr(void *arg)
{//获取歌曲总时间char cmd[1024]={"get_time_length\n"};write(fd_pipe,cmd,strlen(cmd)); while(1){char msg[1024] = {0};while(1){// 通过 fgets 函数可以从管道文件中直接读取到视频播放进程所有输出的内容// 然后就可以为所欲为了char* p = fgets(msg , 1024 , fp );if (p == NULL ){break ;}if(strstr(msg,"ANS_LENGTH")){sscanf(msg,"ANS_LENGTH=%f",&music_total_time);printf("all time :%.2f\n",music_total_time);char buf[124] = {0};int m = (int)music_total_time / 60;int s = (int)music_total_time % 60;if(s <= 9){sprintf(buf,"0%d:0%d",m,s);}else{sprintf(buf,"0%d:%d",m,s);}printf("slider_label1 buf:%s\n",buf);//上锁pthread_mutex_lock(&mux);lv_label_set_text(slider_label1, buf);//显示歌曲总时间秒数 150s 150/60 150%60 2分30秒 //解锁pthread_mutex_unlock(&mux); }if(strstr(msg,"ANS_TIME_POSITION")){sscanf(msg,"ANS_TIME_POSITION=%f",&music_current_time);printf("all time :%.2f\n",music_current_time);}printf("读取到的信息:%s" , msg );}}
}
void *update_progree_bar(void *arg)
{while (1){char cmd[1024]={"get_time_pos\n"};write(fd_pipe,cmd,strlen(cmd)); char buf[124] = {0};int m = (int)music_current_time / 60;int s = (int)music_current_time % 60;if(s <= 9){sprintf(buf,"0%d:0%d",m,s);}else{sprintf(buf,"0%d:%d",m,s);}pthread_mutex_lock(&mux);lv_label_set_text(slider_label, buf);//显示进度秒数 150s 150/60 150%60 2分30秒 pthread_mutex_unlock(&mux); //更新滑块位置 0~100 播放时间/总时间int location = (music_current_time / music_total_time) *100 ;pthread_mutex_lock(&mux);lv_slider_set_value(slider,location, LV_ANIM_OFF); pthread_mutex_unlock(&mux); sleep(1);}}
对比歌曲文件显示歌曲对应的图片信息
部分代码演示:
//显示对应歌曲的图片 if(strstr(all_pic[music_index],"bsj.mp3")){lv_img_set_src(wp,"S:/demo/lvgl_img/bsj.jpg");}else if(strstr(all_pic[music_index],"yudao.mp3")){lv_img_set_src(wp,"S:/demo/lvgl_img/yudao.jpg");}else if(strstr(all_pic[music_index],"yanyuan.mp3")){lv_img_set_src(wp,"S:/demo/lvgl_img/yanyuan.jpg");}
项目优化
出现这个错误:
[Error] (25.685, +8120) _lv_inv_area: detected modifying dirty areas in render (in lv_refr.c line #
考虑到线程安全问题,自己创建的线程调用lv类函数时与lvgl本身刷图像时调用产生了冲突。解决方法直接百度lvgl线程安全
如果需要使用实际的任务或线程,则需要一个互斥锁,该互斥锁应在调用 lv_task_handler 之前被调用,并在其之后释放。同样,必须在与每个LVGL(lv _...)相关的函数调用和代码周围的其他任务和线程中使用相同的互斥锁。这样,就可以在真正的多任务环境中使用LVGL。只需使用互斥锁(mutex)即可避免同时调用 LVGL 函数。
项目难点
第一个是切换音乐 这里卡了有点久 关闭线程一直没用 然后才发现得杀死播放音乐的进程才能达到创建新的线程来播放下一首音乐
第二个是 进度条功能,我的思路是设计三个线程,一个线程用来获取poen打印mplayer的信息 一个线程用来更新时间标签 这里也有问题,在播放下一首的时候需要把之前线程取消再创建
心得体会
在做项目过程中进一步加深系统编程的知识内容的理解,认识到多线程在程序中使用的重要性,代码编写更加规范,提高自己对做项目的整体框架思路 使用lvgl来编写图形界面更加方便 进一步加深自己对框架编程的理解和运用
系统编程之实战小项目-利用LVGL 与 mplayer制作音频播放器相关推荐
- Vue快速入门(附实战小项目:记事本、天气预报、音乐播放器)
文章目录 一.前言 二.Vue.js安装 三.初始化Vue项目 四.项目目录解析 五.Vue核心指令 1.插值表达式 2.v-text 3.v-html 4.v-on 5.计数器实战 6.v-show ...
- 【敬初学者】Python基础学完了,该怎么知道自己学的怎么样呢?十个经典实战小项目附源码
前言 1.街霸游戏 1.1 KO街霸 程序完整源码 程序的输出界面 1.2 春丽VS巴洛克 参考源码 2.猜谜游戏 2.1简单的猜数字游戏 项目要求 参考源码 2.2 进阶的猜姓名游戏 项目要求 参考 ...
- 我用Python把抖音上的美女图片转字符画,期望的AI目标更进一步【机器学习算法实战小项目,k聚类算法图片转化字符画】
大家好,我是辣条. 最近在学习算法,今天给大家带来一个机器学习实战小项目 项目效果展示 学习目标 1.cv2转换图片数据 2.numpy提取图片矩阵数据 3.k均值算法获取图片的分类 工具使用 开 ...
- SparkSQL实战小项目之热门商品top3
SparkSQL实战小项目之热门商品top3 一.说明及需求分析 二.准备测试数据 三.思路分析 四.编码实现 五.验证结果 一.说明及需求分析 软件及环境: centos7 + hive-2.3.3 ...
- python画图代码-Python实战小程序利用matplotlib模块画图代码分享
Python中的数据可视化 matplotlib 是python最著名的绘图库,它提供了一整套和matlab相似的命令API,十分适合交互式地进行制图.而且也可以方便地将它作为绘图控件. 实战小程序: ...
- 用python画图代码-Python实战小程序利用matplotlib模块画图代码分享
Python中的数据可视化 matplotlib 是python最著名的绘图库,它提供了一整套和matlab相似的命令API,十分适合交互式地进行制图.而且也可以方便地将它作为绘图控件. 实战小程序: ...
- python画小汽车代码_Python实战小程序利用matplotlib模块画图代码分享
Python中的数据可视化 matplotlib 是python最著名的绘图库,它提供了一整套和matlab相似的命令API,十分适合交互式地进行制图.而且也可以方便地将它作为绘图控件. 实战小程序: ...
- libhv tcp实战小项目
libhv Tcp小项目实战 一.概述 1.包头 2.心跳 3.任务队列 二.包头 2字节 2字节 4字节 4字节 2字节 1字节 1字节 起始标志 版本号(N) Command(命令ID) 消息体长 ...
- linux数字音频播放器,Moode Audio Player数字音频播放系统的体验
Element14 Raspberry Pi 3B Raspberry Pi 3B ARM开发板封装 Volumio OS数字音频播放系统-主页控制主界面 上周末,我们为几台ARM微型计算机推出了Ra ...
- 【创新项目实训】Android移动开发教学app案例之音频播放器(二)
教学app案例之音频播放器(二) 一.开发环境 二.项目介绍 三.开始主界面 四.显示歌曲列表 五.播放音乐的服务 六.实现播放音乐 一.开发环境 软件环境: Android Studio 4.1.3 ...
最新文章
- python3中unicode怎么写_详解python3中ascii与Unicode使用
- 区块链2.0:智能合约
- 已知旋转矩阵求角度_如何推导旋转矩阵
- idea中Java项目连接服务器进行debug查看
- cookie无法读取bdstoken_第二章(第12节):cookie操作
- 中国 GDP 20 强城市排行榜(2001-2020)
- 昂贵的聘礼(枚举区间+最短路)
- 用Java来写常见的排序算法
- 不可阻挡的PowerShell :Red Teamer告诉你如何突破简单的AppLocker策略
- 豆瓣评分9.0以上,数据分析、爬虫、Python等书籍,45本包邮送到家!
- ENVI5.3.1使用Landsat 8影像进行主成分分析实例操作
- 按timestamp查询_04. 复杂查询
- java 删除目录下所有文件_Java删除文件、目录及目录下所有文件的方法实例
- 卸载IE8 恢复IE6 的两种方法
- 在 pandas 中画树状图,使用 squarify 画树状图
- 云端传输 轻松同步——Q盘项目小结
- Java实训——学生信息管理系统
- 【资源】资源分享(一)
- Python用Pillow(PIL)进行简单的图像操作(边缘增强、锐利、平滑等)
- 【输入法】不显示中文