GTK开发视频播放器
按照第三方库和软件包:
sudo apt-get install libgtk-3-dev
sudo apt-get install libgtk-3-doc
sudo apt-get install vlc libvlc-dev
其中使用了gtk第三方库,具体API请看官网https://developer.gnome.org/gtk3/stable/index.html
gtk构建gtk界面
#include<gtk/gtk.h> #include<gdk/gdkx.h> #include<glib.h> #define BORDER_WIDTH 6 int main(int argc, char *argv[]) { GtkWidget *window, *vbox, *hbox, *menubar, *filemenu, *fileitem, *filemenu_openitem, *hbuttonbox, *player_widget, *stop_button, *full_screen_button, *preocess_scale, *playpause_button, *process_scale, *play_icon_image, *pause_icon_image, *stop_icon_image; GtkAdjustment *process_adjust; /* 每个gtk程序都必须要有的 *两个参数对应main函数的两个参数 *用于在命令行执行程序时解析参数 */ gtk_init(&argc, &argv); /* 创建一个window并完成初始化,如设置为顶层窗口,宽度和高度、标题等 *并绑定destroy信号,以便在关闭gtk窗口时程序可以完全退出 */ window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(window), 400, 300); g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL); gtk_container_set_border_width(GTK_CONTAINER(window), 0); gtk_window_set_title(GTK_WINDOW(window), "GTK+ libVLC Demo"); /* * 创建一个方向垂直间距为0的box容器,并添加到前面创建的window里 */ vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_container_add(GTK_CONTAINER(window), vbox); /* * 创建一个menubar和两个menuitem分别为菜单里“文件”和“打开” * 由于他们是上下级菜单的关系 * 所以需要一个单独menu来防止“open_menu_item”,也就是代码中的filemenu_openitem * */ menubar = gtk_menu_bar_new(); fileitem = gtk_menu_item_new_with_label("File"); filemenu_openitem = gtk_menu_item_new_with_label("Open"); filemenu = gtk_menu_new(); gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), filemenu_openitem); /* * 将filemenu设置为上一级fileitem的子菜单, * 然后将fileitem添加到menumbar,最后将menumbar添加到vbox中 * */ gtk_menu_item_set_submenu(GTK_MENU_ITEM(fileitem), filemenu); gtk_menu_shell_append(GTK_MENU_SHELL(menubar), fileitem); gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0); /* *创建一个draw_area控件,用作视频播放显示区域,并放进vbox中 * */ player_widget = gtk_drawing_area_new(); gtk_box_pack_start(GTK_BOX(vbox), player_widget, TRUE, TRUE, 0); /* *再创建一个hbox作为vbox的子容器,一个hbuttonbox作为hbox的子容器 * hbutton里面放置两个button * 再将一个scale(滚动条,用作视频播放进度条)添加到hbox,再将hbox放到最外面的vbox中 * */ hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0); hbuttonbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL); gtk_container_set_border_width(GTK_CONTAINER(hbuttonbox), BORDER_WIDTH); gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox), GTK_BUTTONBOX_START); playpause_button = gtk_button_new_from_icon_name("media-playback-start", GTK_ICON_SIZE_BUTTON); stop_button = gtk_button_new_from_icon_name("media-playback-stop", GTK_ICON_SIZE_BUTTON); gtk_box_pack_start(GTK_BOX(hbuttonbox), playpause_button, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbuttonbox), stop_button, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), hbuttonbox, FALSE, FALSE, 0); process_adjust = gtk_adjustment_new(0.00, 0.00, 100.00, 1.00, 0.00, 0.00); process_scale = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, process_adjust); gtk_box_pack_start(GTK_BOX(hbox), process_scale, TRUE, TRUE, 0); gtk_scale_set_draw_value (GTK_SCALE(process_scale), FALSE); gtk_scale_set_has_origin (GTK_SCALE(preocess_scale), 0); gtk_scale_set_value_pos(GTK_SCALE(process_scale), 0); gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0); //显示所有控件,并运行gtk程序 gtk_widget_show_all(window); gtk_main(); return 0; }
编译运行:
gcc gui.c -o gui `pkg-config --libs --cflags gtk+-3.0`
./gui
运行结果:
播放视频:
在以上代码基础上添加播放视频功能:
makefiel
CFLAGS=`pkg-config --cflags gtk+-3.0 libvlc` LIBS=`pkg-config --libs gtk+-3.0 libvlc` all: gcc vlcgtk.c -o vlcgtk -Wall $(LIBS) $(CFLAGS) clean: rm vlcgtk
源码
#include<stdlib.h> #include<gtk/gtk.h> #include<gdk/gdkx.h> #include<glib.h> #include <glib/gi18n.h> #include<vlc/vlc.h> #define BORDER_WIDTH 6 void destroy(GtkWidget *widget, gpointer data); void player_widget_on_realize(GtkWidget *widget, gpointer data); void on_open(GtkWidget *widget, gpointer data); void open_media(const char *uri); void on_playpause(GtkWidget *widget, gpointer data); void on_stop(GtkWidget *widget, gpointer data); void play(void); void pause_player(void); gboolean _update_scale(gpointer data); void on_value_change(GtkWidget *widget, gpointer data); libvlc_media_t *media; libvlc_media_player_t *media_player; //libvlc_instance_t *vlc_inst; libvlc_instance_t *vlc_inst; GtkWidget *playpause_button, *play_icon_image, *pause_icon_image, *stop_icon_image, *process_scale; GtkAdjustment *process_adjueset; float video_length, current_play_time; int main(int argc, char *argv[]) { GtkWidget *window, *vbox, *hbox, *menubar, *filemenu, *fileitem, *filemenu_openitem, *player_widget, *hbuttonbox, *stop_button; gtk_init(&argc, &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); gtk_window_set_default_size(GTK_WINDOW(window), 800, 600); g_signal_connect(window, "destroy", G_CALLBACK(destroy), NULL); gtk_container_set_border_width(GTK_CONTAINER(window), 0); gtk_window_set_title(GTK_WINDOW(window), "GTK+ libVLC Demo"); vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, FALSE); gtk_container_add(GTK_CONTAINER(window), vbox); hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, FALSE); menubar = gtk_menu_bar_new(); filemenu = gtk_menu_new(); fileitem = gtk_menu_item_new_with_label("File"); filemenu_openitem = gtk_menu_item_new_with_label("Open"); gtk_menu_shell_append(GTK_MENU_SHELL(filemenu), filemenu_openitem); gtk_menu_item_set_submenu(GTK_MENU_ITEM(fileitem), filemenu); gtk_menu_shell_append(GTK_MENU_SHELL(menubar), fileitem); gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0); g_signal_connect(filemenu_openitem, "activate", G_CALLBACK(on_open), window); player_widget = gtk_drawing_area_new(); gtk_box_pack_start(GTK_BOX(vbox), player_widget, TRUE, TRUE, 0); playpause_button = gtk_button_new_from_icon_name("media-playback-start", GTK_ICON_SIZE_BUTTON); stop_button = gtk_button_new_from_icon_name("media-playback-stop", GTK_ICON_SIZE_BUTTON); //信号处理函数 g_signal_connect(playpause_button, "clicked", G_CALLBACK(on_playpause), NULL); g_signal_connect(stop_button, "clicked", G_CALLBACK(on_stop), NULL); hbuttonbox = gtk_button_box_new(GTK_ORIENTATION_HORIZONTAL); gtk_container_set_border_width(GTK_CONTAINER(hbuttonbox), BORDER_WIDTH); gtk_button_box_set_layout(GTK_BUTTON_BOX(hbuttonbox), GTK_BUTTONBOX_START); gtk_box_pack_start(GTK_BOX(hbuttonbox), playpause_button, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbuttonbox), stop_button, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), hbuttonbox, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(hbox), hbox, FALSE, TRUE, 0); vlc_inst = libvlc_new(0, NULL); media_player = libvlc_media_player_new(vlc_inst); g_signal_connect(G_OBJECT(player_widget), "realize", G_CALLBACK(player_widget_on_realize), media_player); process_adjueset = gtk_adjustment_new(0.00, 0.00, 100.00, 1.00, 0.00, 0.00); process_scale = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, process_adjueset); gtk_box_pack_start(GTK_BOX(hbox), process_scale, TRUE, TRUE, 0); gtk_scale_set_draw_value (GTK_SCALE(process_scale), FALSE); gtk_scale_set_has_origin(GTK_SCALE(process_scale), TRUE); gtk_scale_set_value_pos(GTK_SCALE(process_scale), 5); g_signal_connect(G_OBJECT(process_scale), "value_changend", G_CALLBACK(on_value_change), NULL); gtk_widget_show_all(window); gtk_main(); libvlc_media_player_release(media_player); libvlc_release(vlc_inst); return 0; } void destroy(GtkWidget *widget, gpointer data) { gtk_main_quit(); } void player_widget_on_realize(GtkWidget *widget, gpointer data) { libvlc_media_player_set_xwindow((libvlc_media_player_t*)data, GDK_WINDOW_XID(gtk_widget_get_window(widget))); } //信号处理函数 void on_open(GtkWidget *widget, gpointer data) { GtkWidget *dialog; GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_OPEN; dialog = gtk_file_chooser_dialog_new("open file", GTK_WINDOW(widget), action, _("Cancle"), GTK_RESPONSE_CANCEL, _("Open"), GTK_RESPONSE_ACCEPT, NULL); if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) { char *uri; uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(dialog)); open_media(uri); g_free(uri); } gtk_widget_destroy(dialog); } //传入视频文件uri,使用libvlc播放视频文件 void open_media(const char *uri) { media = libvlc_media_new_location(vlc_inst, uri); libvlc_media_player_set_media(media_player, media); current_play_time = 0.0f; gtk_scale_set_value_pos(GTK_SCALE(process_scale), current_play_time); play(); g_timeout_add(500, _update_scale, process_scale); libvlc_media_release(media); } //使用libvlc传入当前的播放器,获取播放状态 void on_playpause(GtkWidget *widget, gpointer data) { if (libvlc_media_player_is_playing(media_player) == 1) { pause_player(); } else { play(); } } void on_stop(GtkWidget *widget, gpointer data) { pause_player(); libvlc_media_player_stop(media_player); } //该函数为一个GSourceFunc函数类型,要求必须要有返回值,返回类型为gboolen //如果下次继续执行该定时,须返回`G\_SOURCE\_CONTINUE`,否则返回`G\_SOURCE\_REMOVE` gboolean _update_scale(gpointer data) { video_length = libvlc_media_player_get_length(media_player); current_play_time = libvlc_media_player_get_time(media_player); g_signal_handlers_block_by_func(G_OBJECT(process_scale), on_value_change, NULL); gtk_adjustment_set_value(process_adjueset, current_play_time/video_length*100); g_signal_handlers_unblock_by_func(G_OBJECT(process_scale), on_value_change, NULL); return G_SOURCE_CONTINUE; } //通过adjuest对象获取拖动到的进度数值(根据之前设定为1-100的范围) //然后使用libvlc设定播放位置(根据百分百设定,故要除以100) void on_value_change(GtkWidget *widget, gpointer data) { float scale_value = gtk_adjustment_get_value(process_adjueset); libvlc_media_player_set_position(media_player, scale_value/100); } //play函数播放视频,并将播放按钮的图标换成暂停的图标 void play(void) { libvlc_media_player_play(media_player); pause_icon_image = gtk_image_new_from_icon_name("media-playback-pause", GTK_ICON_SIZE_BUTTON); gtk_button_set_image(GTK_BUTTON(playpause_button), pause_icon_image); } void pause_player(void) { libvlc_media_player_pause(media_player); play_icon_image = gtk_image_new_from_icon_name("media-playback-start", GTK_ICON_SIZE_BUTTON); gtk_button_set_image(GTK_BUTTON(playpause_button), play_icon_image); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)