C语言基于GTK+Libvlc实现的简易视频播放器(二)
生活随笔
收集整理的這篇文章主要介紹了
C语言基于GTK+Libvlc实现的简易视频播放器(二)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
簡易視頻播放器-全屏播放 一、課程說明
上一次我們使用gtk+libvlc實現了一個最簡單的視頻播放器,可以實現點擊按鈕暫定和停止播放視頻,以及同步顯示視頻播放進度,但即使作為一個視頻播放器,只有這些功能也還是不夠的,至少我們還應該有全屏播放的功能吧,所以這一次我們就來為上一次的視頻播放器添加上全屏播放功能。這個功能實現起來思路很簡單,只是具體實現過程中有很多坑罷了,需要我們注意很多細節問題,還要解決一些bug等等。這次我們的代碼出了增加功能之外,也還會對上一次的基礎代碼做一些修改。
二、功能實現思路
使用gtk提供的API函數,gtk_window_fullscreen可以將窗口設置為全屏,即隱藏標題欄、菜單欄和工具欄,同時隱藏窗口下端的視頻控制條,只保留視頻播放繪圖構件。在全屏狀態時視頻的播放控制及進度顯示,由另一個單獨的浮動彈出式窗體實現。通過點擊浮動控制窗體上的退出全屏按鈕使用API函數gtk_window_unfullscreen可以退出全屏狀態,此時再還原之前隱藏的正常模式下的控制條構件,及隱藏浮動彈出式窗體
三、要實現的功能點
1.全屏播放
我們先實現點擊全屏按鈕進入全屏狀態,所以要在之前的底部控制條添加一個全屏按鈕,并為其綁定一個點擊事件處理函數
full_screen_button = gtk_button_new_from_icon_name("view-fullscreen", GTK_ICON_SIZE_BUTTON);gtk_box_pack_end(GTK_BOX(hbox), full_screen_button, FALSE, FALSE, 0);g_signal_connect(full_screen_button, "clicked", G_CALLBACK(on_full_screen), NULL);
on_full_screen事件處理函數如下:
void on_full_screen(GtkWidget *widget, gpointer data){// 設置正常窗體進入全屏狀態gtk_window_fullscreen(GTK_WINDOW(window));// 設置一個已進入全屏狀態的標志,也可以通過GDK獲得窗口狀態,不過會略麻煩is_fullscreen = TRUE;// 隱藏窗口底部控制條和頂部菜單欄gtk_widget_hide(hbox);gtk_widget_hide(menubar);// 顯示進入全屏狀態后的浮動控制條窗體,后面會說明該窗體的具體實現gtk_widget_show_all(GTK_WIDGET(ctrl_window));// 根據當前播放狀態同步進入全屏狀態后的按鈕圖標,原本考慮在點擊按鈕時同時設置控制條上的按鈕圖標和浮動控制條上的// 但因為始終有一個為隱藏狀態,設置就會不成功反而會影響當前的按鈕圖標,故簡單的改在進入全屏狀態時單獨進行同步if(libvlc_media_player_is_playing(media_player) == 1)play_icon_image = gtk_image_new_from_icon_name("media-playback-pause", GTK_ICON_SIZE_BUTTON);elseplay_icon_image = gtk_image_new_from_icon_name("media-playback-start", GTK_ICON_SIZE_BUTTON);gtk_button_set_image(GTK_BUTTON(full_screen_pause_button), play_icon_image);...//下面還會有與實現自動隱藏浮動控制條窗體的代碼,后面會說明
on_quit_full_screen事件處理函數如下:
void on_quit_full_screen(GtkWidget *widget, gpointer data){gtk_window_unfullscreen(GTK_WINDOW(window));is_fullscreen = FALSE;gtk_widget_show(hbox);gtk_widget_show(menubar);gtk_widget_hide(ctrl_window);g_signal_handlers_block_by_func(G_OBJECT(player_widget), on_mouse_motion, NULL);}
2.創建一個浮動控制條窗體
因為我們是要創建一個特殊的窗體即沒有邊框,考慮這一點可以使用gtk的彈出窗體類型GTK_WINDOW_POPUP來創建,另外我們還需要固定該窗體的大小和位置,其上的構件基本和主窗體底部的控制條基本一致。下面我們單獨使用一個函數來創建和初始化該窗體
void control_window_init(){GtkWidget *ctrl_hbox, *quit_full_screen_button, *full_screen_stop_button;ctrl_window = gtk_window_new(GTK_WINDOW_POPUP);gtk_window_set_position(GTK_WINDOW(ctrl_window), GTK_WIN_POS_CENTER);//這里使用了兩個宏來設置該窗體的大小gtk_window_set_default_size(GTK_WINDOW(ctrl_window), CTRL_WINDOW_WIDTH, CTRL_WINDOW_HEIGHT);g_signal_connect(ctrl_window, "destroy", G_CALLBACK(gtk_main_quit), NULL);ctrl_hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, TRUE);gtk_container_add(GTK_CONTAINER(ctrl_window), ctrl_hbox);full_screen_pause_button = gtk_button_new_from_icon_name("media-playback-pause", GTK_ICON_SIZE_BUTTON);full_screen_stop_button = gtk_button_new_from_icon_name("media-playback-stop", GTK_ICON_SIZE_BUTTON);quit_full_screen_button = gtk_button_new_from_icon_name("view-restore", GTK_ICON_SIZE_BUTTON);gtk_box_pack_start(GTK_BOX(ctrl_hbox), full_screen_pause_button, FALSE, TRUE, 0);gtk_box_pack_start(GTK_BOX(ctrl_hbox), full_screen_stop_button, FALSE, TRUE, 0);gtk_box_pack_end(GTK_BOX(ctrl_hbox), quit_full_screen_button, FALSE, TRUE, 0);g_signal_connect(G_OBJECT(full_screen_pause_button), "clicked", G_CALLBACK(on_playpause), NULL);g_signal_connect(G_OBJECT(full_screen_stop_button), "clicked", G_CALLBACK(on_stop), NULL);g_signal_connect(G_OBJECT(quit_full_screen_button), "clicked", G_CALLBACK(on_quit_full_screen), NULL);ctrl_process_scale = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, process_adjuest);gtk_box_pack_start(GTK_BOX(ctrl_hbox), ctrl_process_scale, TRUE, TRUE, 0);gtk_scale_set_draw_value (GTK_SCALE(ctrl_process_scale), FALSE);gtk_scale_set_has_origin (GTK_SCALE(ctrl_process_scale), TRUE);gtk_scale_set_value_pos(GTK_SCALE(ctrl_process_scale), 0);g_signal_connect(G_OBJECT(ctrl_process_scale),"value_changed", G_CALLBACK(on_scale_value_change), NULL);}
3.設置浮動控制條窗體自動隱藏
還記得我們上一節實現同步進度條時用過的定時器么,g_timeout_add(),這里還是通過它來實現自動隱藏,我們設置超時5s自動隱藏浮動窗體。但超時要從什么開始計時呢?前面已經說過了嘛,即當我們鼠標沒有動作時即開始計時(準確的應該是,計時是循環計時的,我們只是通過判斷鼠標是否在動作來在計時器中設置是否隱藏)
首先我們應該解決如何知道鼠標是否移動,這就又要用到gtk/gdk的事件了,motion_notify_event事件就是在鼠標移動時被觸發的,那么我們可以為play_widget構件綁定該事件的事件處理,但是默認情況下,該構件的motion_notify_event事件是被屏蔽了的(因為不同的構件功能不同,如果都開啟所有事件,那必然會十分混亂),我們就得手動添加該事件,同時我們也開啟鼠標點擊事件,后面會用來實現單擊播放區域暫定等
在主窗體初始化函數中添加(上一節代碼的main函數中,這一節使用單獨的函數創建和初始化主窗體)
// 添加時間,打開屏蔽事件gtk_widget_add_events(GTK_WIDGET(player_widget), GDK_POINTER_MOTION_MASK | GDK_BUTTON_PRESS_MASK);// 綁定事件處理g_signal_connect(G_OBJECT(player_widget), "motion_notify_event", G_CALLBACK(on_mouse_motion), NULL);// 在非全屏狀態先阻塞該事件處理,進入全屏后再取消阻塞g_signal_handlers_block_by_func(G_OBJECT(player_widget), on_mouse_motion, NULL);
我們還要在進入全屏狀態后在on_full_screen添加定時器
g_signal_handlers_unblock_by_func(G_OBJECT(player_widget), on_mouse_motion, NULL);g_timeout_add(5000, (GSourceFunc)_hide_ctrl_window, NULL);
on_mouse_motion事件處理函數
void on_mouse_motion(GtkWidget *widget, gpointer data){// 設置是否移動狀態標志,避免在移動過程中定時器超時將浮動窗體和鼠標箭頭隱藏is_moving = TRUE;// 鼠標有動作,恢復隱藏窗體gtk_widget_show(GTK_WIDGET(ctrl_window));// 恢復鼠標箭頭gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)), cur);// 重新設置浮動窗體顯示位置width = gdk_screen_get_width(gdk_screen_get_default());height = gdk_screen_get_height(gdk_screen_get_default());// 水平屏幕居中,垂直距屏幕最下端50pixgtk_window_move(GTK_WINDOW(ctrl_window), (width-CTRL_WINDOW_WIDTH)/2, height-50);is_moving = FALSE;}
_hide_ctrl_window定時器處理函數
gboolean _hide_ctrl_window(gpointer data){if (!is_fullscreen || is_moving ) {return FALSE;}// 設置鼠標箭頭為GDK_BLANK_CURSOR,即空gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)), gdk_cursor_new(GDK_BLANK_CURSOR));// 隱藏浮動控制窗體gtk_widget_hide(GTK_WIDGET(ctrl_window));return TRUE;}
不過這里還有一個需要注意的地方,你之前可能會發現,默認情況下,即我們沒有添加自動隱藏的功能,當我們把鼠標移到播放區域時,一段時間不動它也是會被自動隱藏的,你可能會覺得這很好啊,那我們就可以省掉gdk_window_set_cursor了。我之前就是這么想的,不過后來發現這里會有問題,如果單單只是去掉這個鼠標是可以隱藏了,但是它也再不會出現了,除非移出播放顯示區。后來發現這是libvlc的問題,vlc它本身也實現了這個鼠標箭頭超時自動隱藏的功能,你使用如下命令會發現,vlc有一個設置這個超時時間的參數
$ vlc --help | grep mouse
但是我卻沒發現有禁止該功能的參數,所以沒辦法了,我只能給它設置一個盡可能大的超時時間值來達到禁用的功能。在代碼里面我們就需要手動在創建vlc的media_player時指定參數,如下:
const char * const vlc_args[] = {//libvlc 鼠標指針自動隱藏事件與gtk的“motion_notify_event”事件有沖突會導致一些問題,//故這里設置最大超時時間(相當于禁止vlc的該功能)"--mouse-hide-timeout=2147483647",//在 x 毫秒后隱藏光標和全屏控制器"--no-xlib"};...vlc_inst = libvlc_new(2 ,vlc_args);media_player = libvlc_media_player_new(vlc_inst);
4.單擊播放區域暫停/播放,雙擊全屏/退出全屏
這功能不用多解釋,基本每個播放器都會實現
前面我們為play_widget添加了點擊事件,下面只需為其綁定事件相應的處理處理即可。不過我們如何判斷是單擊還是雙擊呢?這需要通過GdkEvent來獲得
首先添加事件處理
g_signal_connect(player_widget, "button-press-event", G_CALLBACK(on_play_widget_button_press), NULL);
on_play_widget_button_press函數實現
void on_play_widget_button_press(GtkWidget *widget, GdkEvent *event, gpointer data){// 判斷為單擊還是雙擊if (event->button.type == GDK_BUTTON_PRESS){ //單擊// 直接手動調用前面綁定到暫停按鈕的事件處理函數on_playpause(widget, data);}else if(event->button.type == GDK_2BUTTON_PRESS){ //雙擊if(is_fullscreen)// 直接手動調用前面綁定到退出全屏按鈕的事件處理函數on_quit_full_screen(widget, data);elseon_full_screen(widget, data);}}
至此我們就實現了預期的全部功能點。
五、總結
這一節我們又為這個播放器增加了一些功能,但它依然很簡單,但相信最為一個學習gtk的入門小項目還是夠了,之后就期待感興趣的用戶能自己接著完善這個簡易播放器,讓其成為一個真正可以作為你日常使用的播放器(以下內容需要在實驗樓的虛擬平臺上運行,不添加也沒有關系,是為了幫助童鞋們更方便學習和理解)
本節完整代碼git
$ git <span class="hljs-keyword">clone</span> -b full_screen https:<span class="hljs-comment">//github.com/shiyanlou/gtk-vlc-video-player.git</span>
演示視頻
<span class="hljs-title">wget</span> <span class="hljs-url">http://anything-about-doc.qiniudn.com/gtk_libvlc_video_player/video_demo_02.mp4</span>
有更多基礎課、項目課歡迎大家登陸實驗樓官方網站http://www.shiyanlou.com。
現在登陸實驗樓更有感恩好禮相送http://www.shiyanlou.com/huodong/thanks.html
上一次我們使用gtk+libvlc實現了一個最簡單的視頻播放器,可以實現點擊按鈕暫定和停止播放視頻,以及同步顯示視頻播放進度,但即使作為一個視頻播放器,只有這些功能也還是不夠的,至少我們還應該有全屏播放的功能吧,所以這一次我們就來為上一次的視頻播放器添加上全屏播放功能。這個功能實現起來思路很簡單,只是具體實現過程中有很多坑罷了,需要我們注意很多細節問題,還要解決一些bug等等。這次我們的代碼出了增加功能之外,也還會對上一次的基礎代碼做一些修改。
二、功能實現思路
使用gtk提供的API函數,gtk_window_fullscreen可以將窗口設置為全屏,即隱藏標題欄、菜單欄和工具欄,同時隱藏窗口下端的視頻控制條,只保留視頻播放繪圖構件。在全屏狀態時視頻的播放控制及進度顯示,由另一個單獨的浮動彈出式窗體實現。通過點擊浮動控制窗體上的退出全屏按鈕使用API函數gtk_window_unfullscreen可以退出全屏狀態,此時再還原之前隱藏的正常模式下的控制條構件,及隱藏浮動彈出式窗體
三、要實現的功能點
- 全屏播放
- 全屏狀態浮動控制條
- 無鼠標動作時浮動控制條和鼠標指針自動隱藏
- 鼠標動作激活浮動控制條和鼠標指針
- 單擊播放區域暫停/播放,雙擊全屏/退出全屏
1.全屏播放
我們先實現點擊全屏按鈕進入全屏狀態,所以要在之前的底部控制條添加一個全屏按鈕,并為其綁定一個點擊事件處理函數
full_screen_button = gtk_button_new_from_icon_name("view-fullscreen", GTK_ICON_SIZE_BUTTON);gtk_box_pack_end(GTK_BOX(hbox), full_screen_button, FALSE, FALSE, 0);g_signal_connect(full_screen_button, "clicked", G_CALLBACK(on_full_screen), NULL);
on_full_screen事件處理函數如下:
on_quit_full_screen事件處理函數如下:
2.創建一個浮動控制條窗體
因為我們是要創建一個特殊的窗體即沒有邊框,考慮這一點可以使用gtk的彈出窗體類型GTK_WINDOW_POPUP來創建,另外我們還需要固定該窗體的大小和位置,其上的構件基本和主窗體底部的控制條基本一致。下面我們單獨使用一個函數來創建和初始化該窗體
3.設置浮動控制條窗體自動隱藏
還記得我們上一節實現同步進度條時用過的定時器么,g_timeout_add(),這里還是通過它來實現自動隱藏,我們設置超時5s自動隱藏浮動窗體。但超時要從什么開始計時呢?前面已經說過了嘛,即當我們鼠標沒有動作時即開始計時(準確的應該是,計時是循環計時的,我們只是通過判斷鼠標是否在動作來在計時器中設置是否隱藏)
首先我們應該解決如何知道鼠標是否移動,這就又要用到gtk/gdk的事件了,motion_notify_event事件就是在鼠標移動時被觸發的,那么我們可以為play_widget構件綁定該事件的事件處理,但是默認情況下,該構件的motion_notify_event事件是被屏蔽了的(因為不同的構件功能不同,如果都開啟所有事件,那必然會十分混亂),我們就得手動添加該事件,同時我們也開啟鼠標點擊事件,后面會用來實現單擊播放區域暫定等
在主窗體初始化函數中添加(上一節代碼的main函數中,這一節使用單獨的函數創建和初始化主窗體)
g_signal_handlers_unblock_by_func(G_OBJECT(player_widget), on_mouse_motion, NULL);g_timeout_add(5000, (GSourceFunc)_hide_ctrl_window, NULL);
on_mouse_motion事件處理函數
_hide_ctrl_window定時器處理函數
gboolean _hide_ctrl_window(gpointer data){if (!is_fullscreen || is_moving ) {return FALSE;}// 設置鼠標箭頭為GDK_BLANK_CURSOR,即空gdk_window_set_cursor(gtk_widget_get_window(GTK_WIDGET(window)), gdk_cursor_new(GDK_BLANK_CURSOR));// 隱藏浮動控制窗體gtk_widget_hide(GTK_WIDGET(ctrl_window));return TRUE;}
不過這里還有一個需要注意的地方,你之前可能會發現,默認情況下,即我們沒有添加自動隱藏的功能,當我們把鼠標移到播放區域時,一段時間不動它也是會被自動隱藏的,你可能會覺得這很好啊,那我們就可以省掉gdk_window_set_cursor了。我之前就是這么想的,不過后來發現這里會有問題,如果單單只是去掉這個鼠標是可以隱藏了,但是它也再不會出現了,除非移出播放顯示區。后來發現這是libvlc的問題,vlc它本身也實現了這個鼠標箭頭超時自動隱藏的功能,你使用如下命令會發現,vlc有一個設置這個超時時間的參數
$ vlc --help | grep mouse
但是我卻沒發現有禁止該功能的參數,所以沒辦法了,我只能給它設置一個盡可能大的超時時間值來達到禁用的功能。在代碼里面我們就需要手動在創建vlc的media_player時指定參數,如下:
const char * const vlc_args[] = {//libvlc 鼠標指針自動隱藏事件與gtk的“motion_notify_event”事件有沖突會導致一些問題,//故這里設置最大超時時間(相當于禁止vlc的該功能)"--mouse-hide-timeout=2147483647",//在 x 毫秒后隱藏光標和全屏控制器"--no-xlib"};...vlc_inst = libvlc_new(2 ,vlc_args);media_player = libvlc_media_player_new(vlc_inst);
4.單擊播放區域暫停/播放,雙擊全屏/退出全屏
這功能不用多解釋,基本每個播放器都會實現
前面我們為play_widget添加了點擊事件,下面只需為其綁定事件相應的處理處理即可。不過我們如何判斷是單擊還是雙擊呢?這需要通過GdkEvent來獲得
首先添加事件處理
g_signal_connect(player_widget, "button-press-event", G_CALLBACK(on_play_widget_button_press), NULL);
on_play_widget_button_press函數實現
void on_play_widget_button_press(GtkWidget *widget, GdkEvent *event, gpointer data){// 判斷為單擊還是雙擊if (event->button.type == GDK_BUTTON_PRESS){ //單擊// 直接手動調用前面綁定到暫停按鈕的事件處理函數on_playpause(widget, data);}else if(event->button.type == GDK_2BUTTON_PRESS){ //雙擊if(is_fullscreen)// 直接手動調用前面綁定到退出全屏按鈕的事件處理函數on_quit_full_screen(widget, data);elseon_full_screen(widget, data);}}
至此我們就實現了預期的全部功能點。
五、總結
這一節我們又為這個播放器增加了一些功能,但它依然很簡單,但相信最為一個學習gtk的入門小項目還是夠了,之后就期待感興趣的用戶能自己接著完善這個簡易播放器,讓其成為一個真正可以作為你日常使用的播放器(以下內容需要在實驗樓的虛擬平臺上運行,不添加也沒有關系,是為了幫助童鞋們更方便學習和理解)
本節完整代碼git
$ git <span class="hljs-keyword">clone</span> -b full_screen https:<span class="hljs-comment">//github.com/shiyanlou/gtk-vlc-video-player.git</span>
演示視頻
<span class="hljs-title">wget</span> <span class="hljs-url">http://anything-about-doc.qiniudn.com/gtk_libvlc_video_player/video_demo_02.mp4</span>
有更多基礎課、項目課歡迎大家登陸實驗樓官方網站http://www.shiyanlou.com。
現在登陸實驗樓更有感恩好禮相送http://www.shiyanlou.com/huodong/thanks.html
總結
以上是生活随笔為你收集整理的C语言基于GTK+Libvlc实现的简易视频播放器(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DIY一个高大上带提醒的计时器,简单实用
- 下一篇: Socket.IO聊天室~简单实用