欢迎使用优快云-markdown编辑器

本文介绍了一个基于GTK+和GStreamer的简单多媒体播放器的实现过程。该播放器支持基本的播放、暂停、停止等功能,并能通过界面操作加载媒体文件进行播放。文章详细展示了如何构建GUI界面以及处理各种播放事件。

首先定义了player.h的头文件,在里面声明了点击事件和页面更新的函数。

ifndef PLAYER_H

define PLAYER_H

include

endif

下面是player.c的函数
/**

gcc hellogtk.c -o hellogtk pkg-config --cflags --libs gtk+-2.0 --libs gstreamer-0.10

*/

include

include

include

include

include

include “player.h”

static GtkWidget *main_window;

static GtkWidget *play_button;

static GtkWidget *skip_button;

static GtkWidget *pause_button;

static GtkWidget *stop_button;

static GtkWidget *status_label;

static GtkWidget *song_label;

static GtkWidget *time_label;

static GtkWidget *seek_scale;

static GtkWidget *video_output;

static gpointer window;

static GstElement *play = NULL;

static GstElement *bin;

static guint timeout_source = 0;

static guint skip_time_source = 0;

static char *current_filename = NULL;

gboolean no_seek = FALSE;

gboolean is_pause_pressed = FALSE;

gboolean is_skip = FALSE;

// 打开文件

static void file_open(GtkAction *action)

{

GtkWidget *file_chooser = gtk_file_chooser_dialog_new(  

    "Open File", GTK_WINDOW(main_window),  

    GTK_FILE_CHOOSER_ACTION_OPEN,  

    GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,  

    GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,  

    NULL);  



if (gtk_dialog_run(GTK_DIALOG(file_chooser)) == GTK_RESPONSE_ACCEPT) {  

    char *filename;  

    filename = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(file_chooser));  

    // g_signal_emit_by_name(G_OBJECT(stop_button), "clicked");  

    if (current_filename) g_free(current_filename);  

    current_filename = filename;  

   g_print("current_filename===>%s",current_filename);

   //判断pause按钮是否按下

 gtk_widget_set_sensitive(GTK_WIDGET(pause_button), FALSE);  

   //chose the song to play 

    if (load_file(filename))  

        gtk_widget_set_sensitive(GTK_WIDGET(play_button), TRUE);  

}  

gtk_widget_destroy(file_chooser);  

}

// 退出

static void file_quit(GtkAction *action)

{

gtk_main_quit();  

}

// 关于

static void help_about(GtkAction *action)

{

GtkWidget *about_dialog = gtk_about_dialog_new();  

gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(about_dialog), "MediaPlayer");  

gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(about_dialog), "0.0.0");  

gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(about_dialog), "Copyright @ 2011, Figo");  



gtk_dialog_run(GTK_DIALOG(about_dialog));  

gtk_widget_destroy(about_dialog);  

}

static GtkActionEntry mainwindow_action_entries[] = {

{ "FileMenu", "NULL", "文件" },  

{  

    "OpenFile",  

    GTK_STOCK_OPEN,  

    "打开(O)",  

    "<control>O",  

    "Open a file for playback",  

    G_CALLBACK(file_open)  

},  

{  

    "QuitPlayer",  

    GTK_STOCK_QUIT,  

    "退出(Q)",  

    "<control>Q",  

    "Quit the media player",  

    G_CALLBACK(file_quit)  

},  



{ "HelpMenu", "NULL", "帮助" },  

{  

    "HelpAbout",  

    GTK_STOCK_ABOUT,  

    "关于",  

    "",  

    "About the media player",  

    G_CALLBACK(help_about)  

}  

};

GtkWidget *build_gui()

{

GtkWidget *main_vbox;  

GtkWidget *status_hbox;  

GtkWidget *controls_hbox;  

GtkWidget *saturation_controls_hbox;  



GtkActionGroup *actiongroup;  

GtkUIManager *ui_manager;  



actiongroup = gtk_action_group_new("MainwindowActiongroup");  

gtk_action_group_add_actions(actiongroup,  

    mainwindow_action_entries,  

    G_N_ELEMENTS(mainwindow_action_entries),  

    NULL);  



ui_manager = gtk_ui_manager_new();  

gtk_ui_manager_insert_action_group(ui_manager, actiongroup, 0);  

gtk_ui_manager_add_ui_from_string(  

    ui_manager,  

    "<ui>"  

    "    <menubar name='MainMenu'>"  

    "        <menu action='FileMenu'>"  

    "            <menuitem action='OpenFile'/>"  

    "            <separator name='fsep1'/>"  

    "            <menuitem action='QuitPlayer'/>"  

    "        </menu>"  

    "        <menu action='HelpMenu'>"  

    "            <menuitem action='HelpAbout'/>"  

    "        </menu>"         

    "    </menubar>"  

    "</ui>",  

    -1,  

    NULL);  





// 创建主 GtkVBOx. 其他所有都在它里面  

// 0:各个构件高度可能不同,6:构件之间的间距为6 像素  

main_vbox = gtk_vbox_new(0, 0);  



// 添加菜单栏  

gtk_box_pack_start(  

    GTK_BOX(main_vbox),  

    gtk_ui_manager_get_widget(ui_manager, "/ui/MainMenu"),  

    FALSE, FALSE, 0);  





    // 视频显示区域 

video_output = gtk_drawing_area_new (); 
gtk_box_pack_start (GTK_BOX (main_vbox), video_output, TRUE, TRUE, 0); 
//gtk_widget_set_size_request (video_output, 0x200, 0x100); 
gtk_widget_set_size_request (video_output, 672, 378); 
gtk_widget_show (video_output); 

// 滑动条控制  
seek_scale = gtk_hscale_new_with_range(0, 100, 1);  
gtk_scale_set_draw_value(GTK_SCALE(seek_scale), FALSE);  
gtk_range_set_update_policy(GTK_RANGE(seek_scale), GTK_UPDATE_DISCONTINUOUS);  
g_signal_connect(G_OBJECT(seek_scale), "value-changed", G_CALLBACK(seek_value_changed), NULL);  
gtk_box_pack_start(GTK_BOX(main_vbox), seek_scale, FALSE, FALSE, 0);  

// controls_hbox  
controls_hbox = gtk_hbox_new(TRUE, 6);  
gtk_box_pack_start_defaults(GTK_BOX(main_vbox), controls_hbox);  
// 播放按钮  
play_button = gtk_button_new_from_stock(GTK_STOCK_MEDIA_PLAY);  
// 设置“敏感”属性,FALSE 表示为灰色,不响应鼠标键盘事件  
gtk_widget_set_sensitive(play_button, FALSE);  
g_signal_connect(G_OBJECT(play_button), "clicked", G_CALLBACK(play_clicked), NULL);  
gtk_box_pack_start_defaults(GTK_BOX(controls_hbox), play_button);  
// 暂停按钮,为使按下时停留在按下状态,使用GtkToggleButton  
pause_button = gtk_toggle_button_new_with_label(GTK_STOCK_MEDIA_PAUSE);  
// 将按钮设置为固化按钮  
gtk_button_set_use_stock(GTK_BUTTON(pause_button), TRUE);  
gtk_widget_set_sensitive(pause_button, FALSE);  
g_signal_connect(G_OBJECT(pause_button), "clicked", G_CALLBACK(pause_clicked), NULL);  
gtk_box_pack_start_defaults(GTK_BOX(controls_hbox), pause_button);  

// 快进按钮
skip_button = gtk_button_new_from_stock(GTK_STOCK_MEDIA_FORWARD);
gtk_widget_set_sensitive(skip_button, FALSE);
g_signal_connect(G_OBJECT(skip_button), “clicked”, G_CALLBACK(skip_clicked), NULL);
gtk_box_pack_start_defaults(GTK_BOX(controls_hbox), skip_button);
// 停止按钮
stop_button = gtk_button_new_from_stock(GTK_STOCK_MEDIA_STOP);
gtk_widget_set_sensitive(stop_button, FALSE);
g_signal_connect(G_OBJECT(stop_button), “clicked”, G_CALLBACK(stop_clicked), NULL);
gtk_box_pack_start_defaults(GTK_BOX(controls_hbox), stop_button);

// status_hbox  
status_hbox = gtk_hbox_new(TRUE, 0);  
gtk_box_pack_start(GTK_BOX(main_vbox), status_hbox, FALSE, FALSE, 0);  
// 状态标签  
status_label = gtk_label_new("<b>已停止</b>");  
gtk_label_set_use_markup(GTK_LABEL(status_label), TRUE);  
gtk_misc_set_alignment(GTK_MISC(status_label), 0.0, 0.5);  
gtk_box_pack_start(GTK_BOX(status_hbox), status_label, TRUE, TRUE, 0);  
// 歌曲信息  
song_label = gtk_label_new("<b>无歌曲信息</b>");  
gtk_label_set_use_markup(GTK_LABEL(song_label), TRUE);  
gtk_misc_set_alignment(GTK_MISC(song_label), 0.0, 0.5);  
gtk_box_pack_start(GTK_BOX(status_hbox), song_label, TRUE, TRUE, 0); 
// 时间标签     
time_label = gtk_label_new("00:00:00");  
gtk_misc_set_alignment(GTK_MISC(time_label), 0.5, 1.0);  
gtk_box_pack_start(GTK_BOX(status_hbox), time_label, TRUE, TRUE, 0);    
return main_vbox;  

}
// destory main window
static void destroy(GtkWidget *widget, gpointer data)
{
gtk_main_quit();
}
// 更新播放时间
void gui_update_time(const gchar *time, const gint64 position, const gint64 length)
{
gtk_label_set_text(GTK_LABEL(time_label), time);
if (length > 0) {
no_seek = TRUE;
gtk_range_set_value(GTK_RANGE(seek_scale), ((gdouble)position / (gdouble)length) * 100.0);
no_seek = FALSE;
}
}
// 更新播放状态
void gui_status_update(PlayerState state)
{
switch (state) {
case STATE_STOP:
is_skip = FALSE;
gtk_widget_set_sensitive(GTK_WIDGET(stop_button), FALSE);
gtk_widget_set_sensitive(GTK_WIDGET(pause_button), FALSE);
gtk_widget_set_sensitive(GTK_WIDGET(skip_button), FALSE);
gtk_label_set_markup(GTK_LABEL(status_label), “已停止“);
gtk_range_set_value(GTK_RANGE(seek_scale), 0.0);
gtk_label_set_text(GTK_LABEL(time_label), “00:00:00”);
gtk_label_set_markup(GTK_LABEL(song_label), “无歌曲信息“);
break;
case STATE_SKIP:
gtk_label_set_markup(GTK_LABEL(status_label), “快速播放“);
break;
case STATE_PLAY:
gtk_widget_set_sensitive(GTK_WIDGET(stop_button), TRUE);
gtk_widget_set_sensitive(GTK_WIDGET(pause_button), TRUE);
gtk_widget_set_sensitive(GTK_WIDGET(skip_button), TRUE);
gtk_label_set_markup(GTK_LABEL(status_label), “播放中“);

       gtk_label_set_markup(GTK_LABEL(song_label), current_filename);         
        break;  
    case STATE_PAUSE:             
        gtk_label_set_markup(GTK_LABEL(status_label), "<b>已暂停</b>");  
        break;  
    default:  
        break;  
}  

}
//play按钮点击事件
static void play_clicked(GtkWidget *widget, gpointer data)
{
if (current_filename) {
if (play_file()) {
gtk_widget_set_sensitive(GTK_WIDGET(stop_button), TRUE);
gtk_widget_set_sensitive(GTK_WIDGET(skip_button), TRUE);
gtk_widget_set_sensitive(GTK_WIDGET(pause_button), TRUE);
// g_print(“Play was pressed\n”);
gui_status_update(STATE_PLAY);
g_print(“Play\n”);
}
else {
g_print(“Failed to play\n”);
}
}
}
//pause按钮点击事件
static void pause_clicked(GtkWidget *widget, gpointer data)
{
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
{
if(is_skip){
if(skip_time_source){
g_source_remove(skip_time_source);
skip_time_source = 0;}
}
gst_element_set_state(play,GST_STATE_PAUSED);
GstStateChangeReturn statechange;
statechange = gst_element_set_state(play, GST_STATE_PAUSED);
gtk_widget_set_sensitive(GTK_WIDGET(play_button), FALSE);
gtk_widget_set_sensitive(GTK_WIDGET(stop_button), FALSE);
gtk_widget_set_sensitive(GTK_WIDGET(skip_button), FALSE);
gui_status_update(STATE_PAUSE);
g_print(“Pause\n”);
// g_print(“Pause was pressed\n”);
}
else
{
// g_print(“Pause was pressed\n”);
if(is_skip){
skip_time_source = g_timeout_add(200, (GSourceFunc)skip_time_callback, play);;
}
gtk_widget_set_sensitive(GTK_WIDGET(play_button), TRUE);
gtk_widget_set_sensitive(GTK_WIDGET(skip_button), TRUE);
gst_element_set_state(play,GST_STATE_PLAYING);
gui_status_update(STATE_PLAY);
g_print(“Resume to play\n”);
}
}
//stop按钮点击事件
static void stop_clicked(GtkWidget *widget, gpointer data)
{
is_skip = FALSE;
if (timeout_source)
g_source_remove(timeout_source);
timeout_source = 0;
gtk_widget_set_sensitive(GTK_WIDGET(skip_button), FALSE);
// g_print(“Stop was pressed\n”);
gst_element_set_state(play,GST_STATE_NULL);
//停止之后正常播放,不在跳播
if (timeout_source){
g_source_remove(timeout_source);
timeout_source = 0;
}
if(skip_time_source){
g_source_remove(skip_time_source);
skip_time_source = 0;
}
timeout_source = g_timeout_add(200, (GSourceFunc)update_time_callback, play);
// gst_object_unref(GST_OBJECT(play));//不用销毁管道
gui_status_update(STATE_STOP);
g_print(“Deleting pipeline\n”);
g_print(“Stop\n”);
}
//skip按钮点击事件
static void skip_clicked(GtkWidget *widget, gpointer data)
{
is_skip = TRUE;
g_print(“skip_clicked\n”);
//取消正常播放的查询事件
if (timeout_source)
g_source_remove(timeout_source);
timeout_source = 0;
skip_time_source = g_timeout_add(200, (GSourceFunc)skip_time_callback, play);
gui_status_update(STATE_SKIP);
}
//快进播放模式更新页面
static gboolean skip_time_callback(GstElement *pipeline)
{
if(is_skip){
GstFormat fmt = GST_FORMAT_TIME;
gint64 position;
gint64 length;
gchar time_buffer[25];
if (gst_element_query_position(pipeline, &fmt, &position)
&& gst_element_query_duration(pipeline, &fmt, &length)) {
g_snprintf(time_buffer, 24, “%u:%02u:%02u”, GST_TIME_ARGS(position));
position += 4000000000;
//跳4秒播放一次
if (!gst_element_seek(play, 1.0, GST_FORMAT_TIME,
GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
position, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
g_print(“Failed to seek to desired position\n”);
// 播放完成
if(position >=length ){
if (skip_time_source)
g_source_remove(skip_time_source);
skip_time_source = 0;
gui_status_update(STATE_STOP);
}
gui_update_time(time_buffer, position, length);
}
return TRUE;
}
}
/* 进度条的拖动事件 */
static void seek_value_changed(GtkRange *range, gpointer data)
{
if (no_seek)
return;
gdouble val = gtk_range_get_value(range);
seek_to(val);
}
/* 处理进度条的拖动事件 */
void seek_to(gdouble percentage)
{
GstFormat fmt = GST_FORMAT_TIME;
gint64 length;
/* If it seems safe to attempt a seek… */
if (play && gst_element_query_duration(play, &fmt, &length)) {
/* …calculate where to seek to */
gint64 target = ((gdouble)length * (percentage / 100.0));
/* …and attempt the seek */
if (!gst_element_seek(play, 1.0, GST_FORMAT_TIME,
GST_SEEK_FLAG_FLUSH, GST_SEEK_TYPE_SET,
target, GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE))
g_print(“Failed to seek to desired position\n”);
}
}
//pipeline的信号处理函数
static gboolean bus_callback(GstBus *bus, GstMessage *message, gpointer data)
{
switch (GST_MESSAGE_TYPE(message)) {
case GST_MESSAGE_ERROR:
{
GError *err;
gchar *debug;
gst_message_parse_error(message, &err, &debug);
g_print(“Error: %s\n”, err->message);
g_error_free(err);
g_free(debug);
gtk_main_quit();
break;
}
case GST_MESSAGE_EOS:
{
g_print(“End of stream\n”);
// stop_playback();
// stop_clicked(GtkWidget *widget, gpointer data);
if (timeout_source)
g_source_remove(timeout_source);
timeout_source = 0;
gst_element_set_state(play, GST_STATE_NULL);
gui_status_update(STATE_STOP);
break;
}
default:
break;
}
return TRUE;
}
//创建一个pipeline
static gboolean build_gstreamer_pipeline(const gchar *uri)
{
// 创建一个playbin 元素
play = gst_element_factory_make (“playbin2”, “play”);
GstBus *bus;
bus = gst_pipeline_get_bus (GST_PIPELINE (play));
gst_bus_add_watch (bus, bus_callback, NULL);
gst_object_unref (bus);
g_object_set (G_OBJECT (play), “uri”, uri, NULL);
return TRUE;
}
// load file to play
gboolean load_file(const gchar *uri)
{
if (build_gstreamer_pipeline(uri))
return TRUE;
return FALSE;
}
static gboolean update_time_callback(GstElement *pipeline)
{
GstFormat fmt = GST_FORMAT_TIME;
gint64 position;
gint64 length;
gchar time_buffer[25];
if (gst_element_query_position(pipeline, &fmt, &position)
&& gst_element_query_duration(pipeline, &fmt, &length)) {
g_snprintf(time_buffer, 24, “%u:%02u:%02u”, GST_TIME_ARGS(position));
g_print(“duration====%llu,position===%llu\n”,length,position);
gui_update_time(time_buffer, position, length);
}
return TRUE;
}
gboolean play_file()
{
if (play) {
/* Start playing */
gst_element_set_state(play, GST_STATE_PLAYING);
gui_status_update(STATE_PLAY);
/* Connect a callback to trigger every 200 milliseconds to
* update the GUI with the playback progress. We remember
* the ID of this source so that we can remove it when we stop
* playing */
timeout_source = g_timeout_add(200, (GSourceFunc)update_time_callback, play);
return TRUE;
}
return FALSE;
}
int main(int argc, char *argv[])
{
// 初始化 GTK+
gtk_init(&argc, &argv);
gst_init(&argc, &argv);
// 创建窗口
main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
// 设置窗口标题
gtk_window_set_title(GTK_WINDOW(main_window), “MediaPlayer”);
// 主窗口销毁句柄
g_signal_connect(G_OBJECT(main_window), “destroy”, G_CALLBACK(destroy), NULL);
// 创建主窗口GUI
gtk_container_add(GTK_CONTAINER(main_window), build_gui());
// 显示
gtk_widget_show_all(GTK_WIDGET(main_window));
// 开始主循环
gtk_main();
return 0;
}

智慧医药系统(smart-medicine)是一款采用SpringBoot架构构建的Java Web应用程序。其界面设计简洁而富有现代感,核心特色在于融合了当前前沿的生成式人工智能技术——具体接入了阿里云的通义千问大型语言模型,以此实现智能医疗咨询功能,从而增强系统的技术先进性与实用价值。该系统主要定位为医学知识查询与辅助学习平台,整体功能结构清晰、易于掌握,既适合编程初学者进行技术学习,也可作为院校课程设计或毕业项目的参考实现。 中医舌诊作为传统医学的重要诊断手段,依据舌象的颜色、形状及苔质等特征来辨析生理状况与病理变化。近年来,随着计算科学的进步,人工智能技术逐步渗透到这一传统领域,形成了跨学科的研究与应用方向。所述的中医舌诊系统正是这一方向的实践产物,它运用AI算法对舌象进行自动化分析。系统以SpringBoot为基础框架,该框架依托Java语言,致力于简化Spring应用程序的初始化与开发流程,其突出优势在于能高效构建独立、可投入生产的应用,尤其契合微服务架构与云原生环境,大幅降低了开发者在配置方面的负担。 系统中整合的通义千问大语言模型属于生成式人工智能范畴,通过海量数据训练获得模拟人类语言的能力,可在限定领域内生成连贯文本,为用户提供近似专业医生的交互式咨询。该技术的引入有助于提升诊断过程的自动化水平与结果一致性。 在设计与体验层面,本系统强调逻辑明晰与操作简便,旨在降低用户的学习门槛,尤其适合中医知识的入门教学。整体交互模式接近百科全书式查询,功能模块精炼聚焦,因而非常适用于教育场景,例如学术项目展示或毕业设计答辩。通过直观的实践界面,使用者能够更深入地理解中医舌诊的理论与方法。 此外,系统界面遵循简约大气的设计原则,兼顾视觉美感与交互流畅性,以提升用户的专注度与使用意愿。结合AI的数据处理能力,系统可实现对舌象特征的快速提取与实时分析,这不仅为传统诊断方法增添了客观量化维度,也拓展了中医知识传播的途径。借助网络平台,该系统能够突破地域限制,使更多用户便捷地获取专业化的中医健康参考,从而推动传统医学在现代社会的应用与普及。 资源来源于网络分享,仅用于学习交流使用,请勿用于商业,如有侵权请联系我删除!
【掺铒光纤放大器(EDFA)模型】掺铒光纤放大器(EDFA)分析模型的模拟研究(Matlab代码实现)内容概要:本文介绍了掺铒光纤放大器(EDFA)分析模型的模拟研究,并提供了基于Matlab的代码实现方案。通过对EDFA的工作原理、增益特性、噪声系数等关键性能指标进行数学建模与仿真分析,帮助研究人员深入理解其在光通信系统中的作用机制。文档还列举了多个相关科研方向的技术支持内容,涵盖智能优化算法、路径规划、无人机应用、通信与信号处理、电力系统管理等多个领域,展示了Matlab在科学研究与工程仿真中的广泛应用能力。此外,文中附带网盘链接,便于获取完整的代码资源与开发工具包。; 适合人群:具备一定光学通信或电子信息背景,熟悉Matlab编程,从事科研或工程仿真的研究生、高校教师及技术研发人员。; 使用场景及目标:①用于光通信系统中EDFA性能的理论分析与仿真验证;②支持科研人员快速构建和测试EDFA模型,提升研究效率;③为教学实验、毕业设计及学术论文复现提供可靠的技术参考与代码基础。; 阅读建议:建议读者结合光通信基础知识,按照文档结构逐步运行并调试Matlab代码,重点关注模型参数设置与仿真结果分析,同时可利用提供的网盘资源拓展学习其他相关课题,深化对系统级仿真的理解。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值