程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> C語言基於GTK+Libvlc實現的簡易視頻播放器,gtklibvlc

C語言基於GTK+Libvlc實現的簡易視頻播放器,gtklibvlc

編輯:C++入門知識

C語言基於GTK+Libvlc實現的簡易視頻播放器,gtklibvlc


小編心語:現下,各種視頻播放軟件層出不窮,競爭也越演越烈,不知道大家有木有這個想法,小編有時在想能不能做一款屬於自己的視頻播放器呢~小編特意去實驗樓,整理出了這篇關於如何實現簡易視頻播放器的博文。簡易播放器,你值得擁有~

友情提示:這裡只是前篇,只是一些簡單的功能,其他功能將會在後篇為大家介紹——

C語言基於GTK+Libvlc實現的簡易視頻播放器

一、課程說明

如果你學習過之前上線的pygtk實現有道詞典的項目課,那應該對gtk的使用有一些了解了,這個項目課學起來會相對輕松一些。 關於Gtk或者說是通常的圖形應用開發的一些基礎知識,我們會在以後的基礎課程中體現,項目課適合有一定基礎的用戶學習。

二、Gtk簡介

GTK+ 是一種圖形用戶界面(GUI)工具包。也就是說,它是一個庫(或者,實際上是若干個密切相關的庫的集合),它支持創建基於 GUI 的應用程序。可以把 GTK+ 想像成一個工具包,從這個工具包中可以找到用來創建 GUI 的許多已經准備好的構造塊。

最初,GTK+ 是作為另一個著名的開放源碼項目 —— GNU Image Manipulation Program (GIMP) —— 的副產品而創建的。在開發早期的 GIMP 版本時,Peter Mattis 和 Spencer Kimball 創建了 GTK(它代表 GIMP Toolkit),作為 Motif 工具包的替代,後者在那個時候不是免費的。(當這個工具包獲得了面向對象特性和可擴展性之後,才在名稱後面加上了一個加號。)

這差不多已經 10 年過去了。今天,在 GTK+ 的最新穩定版本 —— 2.8 版上(3.0測試中),仍然在進行許多活動,同時,GIMP 無疑仍然是使用 GTK+ 的最著名的程序之一,不過它已經不是惟一的使用 GTK+ 的程序了。已經為 GTK+ 編寫了成百上千的應用程序,而且至少有兩個主要的桌面環境(Xfce 和 GNOME)用 GTK+ 為用戶提供完整的工作環境。

GTK+雖然是用C語言寫的,但是您可以使用你熟悉的語言來使用GTK+,因為GTK+已經被綁定到幾乎所有流行的語言上,如:C++,PHP, Guile,Perl, Python, TOM, Ada95, Objective C, Free Pascal, and Eiffel

使用GTK+的優秀應用程序:

· GIMP-GNU圖像處理程序

· GNOME、XFCE等桌面環境和大部分窗口管理器都基於GTK+

· Inkscape-類似於Illustrator、CorelDraw的矢量圖形繪制工具

· Pidgin-支持多種協議(IRC、Gtalk、Yahoo Talk、MSN、QQ等等)的聊天工具

· Firefox 、Chrome-兩大流行浏覽器

· ...

 

 

三、Vlc簡介

1.簡介:

VLC多媒體播放器(英語:VLC media player,最初為VideoLAN Client,是VideoLAN計劃的開放源代碼多媒體播放器。)支持眾多音頻與視頻解碼器及文件格式,並支持DVD影音光盤,VCD影音光盤及各類流 協議。它也能作為單播或多播的流服務器在IPv4或IPv6的高速網絡連接下使用。調用FFmpeg計劃的解碼器與libdvdcss程序庫使其有播放多 媒體文件及加密DVD影碟的功能。

VLC自建的動態核心模塊,使所有的接口(interfaces)、視頻和音頻輸出(video and audio outputs)、控制(controls)、定標器(scalers)、解碼器(codecs)、音頻/視頻濾波器(audio/video filters)包含於統一的模塊之內,便於使用。在播放媒體文件時,無需用戶干預,VLC會根據不同的情況自行調度輸入協議(input protocol)、輸入文件的格式(input file format)、輸入轉碼器(input codec)、視頻卡功能(video card capabilities)和其他參數。

VLC media player具有跨平台的特性,可用於Linux、Microsoft Windows、Mac OS X、BeOS、OS/2、BSD、安卓、iOS、及Solaris。

2.libvlc

libvlc是VLC media player使用的多媒體框架的核心引擎和擴展編程接口,它可以幫助開發者開發廣泛的多媒體應用

libvlc多媒體框架結構如下:

 

libvlc API關系圖表如下:


 

 

 

LibVlc官方API文檔

四、gtk構建gtk界面

我們首先也只是布局和添加控件,之後再來實現業務邏輯,不多說,直接看圖,這就是我們要先實現的播放器大致的界面布局,不過這個界面將不會是我們最 終要實現的樣子,因為這是使用galde界面設計器創建的布局,大家初學時最好不要直接使用glade來進行布局,因為它會忽略很多細節。先從手寫代碼的 方式進行布局和添加控件,這樣有助於你更好的掌握那些控件的使用方法。

1.先了解這個布局的層次關系

 

window
|---vbox|-------menubar|-------drawingarea|-------hbox
        |---hbuttonbox
        |   |---playbutton
        |   |---stopbutton
        |---scale
        |---fullscreenbutton

 

2.實現這個布局的代碼如下:

//filename:gui.c
#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,
                *playpause_button,
                *process_scale,
                *play_icon_image,
                *pause_icon_image,
                *stop_icon_image;
    GtkAdjustment  *process_adjuest;

    // 每個gtk程序都必須要有的,兩個參數對應mian函數的兩個參數,用於在命令行執行程序時傳遞並解析參數
    gtk_init(&argc, &argv);

    // 創建一個window並完成初始化,如設置為頂層窗口,寬度和高度,標題等,並綁定destory信號,以便在關閉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添加進menubar,最後將menubar放置進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的子容器,hbuttonbox用於放置兩個button,
    // 再將一個scale(滾動條,用作視頻播放進度條,原本的process控件不能拖動)添加進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);

    //創建一個滾動條,使用一個自定義的adjust對象初始化
    process_adjuest = gtk_adjustment_new(0.00, 0.00, 100.00, 1.00, 0.00, 0.00);
    process_scale = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL,process_adjuest);
    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), 0);
    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);

    // 顯示所有控件,並運行gtk程序
    gtk_widget_show_all(window);
    gtk_main ();

    return 0;
}

 

 

 

 

 

如果你覺得有困難可以直接下載代碼:(以下內容是在實驗樓網站的虛擬平台上使用的,沒有使用實驗樓的不需要下面這個步驟)

$ wget https://raw.githubusercontent.com/shiyanlou/gtk-vlc-video-player/master/gui.c

3.代碼說明:

上述代碼,使用如下命令編譯和運行:

 

# 注意pgk-config...那裡不是單引號,是反單引號$ gcc gui.c -o gui `pkg-config --libs --cflags gtk+-3.0`$ ./gui

 

 

 

運行後,你將看到

代碼的解釋說明,已經盡可能在注釋中說明,代碼中一些gtk的API的使用和詳細說明,請參看官方API文檔,一些API的參數如果不太明確,你可以直接在代碼中修改為不同的值,然後編譯並運行代碼,觀察效果,幫助理解.

五、使用libvlc播放媒體文件通過gtk中顯示

1.使用libvlc創建一個媒體播放器對象

在mian函數中添加如下代碼:

    

 //setup vlc
    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);

 

 

2.使用filechooserdialog打開一個視頻文件

首先給菜單欄中的open添加一個點擊信號處理函數on_open,注意一般信號處 理函數的命令規則就是在函數名之前加上"on_",但這不是必需的,然後在on_open這個信號處理函數中,創建一個 filechoosedialog,並運行。打開文件,獲取到uri(?)後,將其傳遞給open_media函數,使用vlc打開並播放視頻文件。這裡 注意,要想讓vlc播放的視頻顯示在窗口中還需要給之前創建的draw_area控件綁定一個信號處理函數,這裡面會將vlc的播放器窗口繪制在控件中。

具體實現代碼如下:

添加信號處理

 

 

// 添加信號處理函數
g_signal_connect(filemenu_openitem, "activate", G_CALLBACK(on_open), window);

 

 

 

處理函數實現

 

// 信號處理函數 
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, _("Cancel"), 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/video_length*100);

    play();
    libvlc_media_release(media);
}

 

 

 

 

因為我們使用了libvlc所以上面代碼在編譯時需要加上libvlc的編譯和鏈接選項,可使用pkg-config工具獲得

比如:$ gcc -o videoplayer videoplayer.c `pkg-config --cflags --libs gtk+-3.0 libvlc`

 

 

一切正常的話,現在你的播放器應該已經可以播放出視頻了,如果你需要一個視頻文件來測試播放效果的話,你可以使用我提供的一個視頻文件,這是一個相當有趣的視頻,所以希望你一定要成功,然後你才能看到這個視頻的內容。

$ wget http://anything-about-doc.qiniudn.com/gtk_libvlc_video_player/video_demo_01.flv

 

六、實現簡單的播放控制,暫定/播放和停止

這個比較簡單了,就是為播放和停止按鈕分別綁定兩個點擊信號處理函數,並更具當前是否為播放狀態設置按鈕顯示為播放還是暫定,及實現視頻的暫定和繼續播放

具體代碼如下:

同樣先添加信號處理

(略)

 

處理函數實現

// 使用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);
}

// 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);
}

 

 

七、實現播放進度顯示和拖動進度條跳轉

1.視頻播放進度的顯示

要顯示播放進度,可以用兩種方式,第一種呢,自定義一個信號每當vlc的播放進度發生變化時就發送這個信號,然後將滾動條綁定該信號,在該信號的信 號處理函數中獲取vlc播放進度,並設置為滾動條的值;另一種是添加一個定時器,每隔一個時間比如0.5s去獲取vlc的播放進度,使用之前創建滾動條是 自定義的一個GtkAdjuestment對象了設置滾動條的進度。前一種方法比較復雜,這裡我們使用後一種

具體代碼如下:

在open_media函數中添加定時器

 

 

// 表示每隔500ms會調用\_update\_scale函數,並將process\_scale作為數據對象傳入
g_timeout_add(500,_update_scale,process_scale);

 

 

 

_update_scale函數實現

 

 

// 該函數為一個`GSourceFunc`函數類型,要求必須要有返回值,返回類型為`gboolean`,
// 如要下次繼續執行該定時器,須返回`G\_SOURCE\_CONTINUE`,否則返回`G\_SOURCE\_REMOVE`
gboolean _update_scale(gpointer data){
    // 獲取當前打開視頻的長度,時間單位為ms
    video_length = libvlc_media_player_get_length(media_player);    
    current_play_time = libvlc_media_player_get_time(media_player);
    gtk_adjustment_set_value(process_adjuest,current_play_time/video_length*100);
    return G_SOURCE_CONTINUE;
}

 

 

 

2.實現拖動進度條跳轉

這個功能可以給scale添加一個value\_changed信號處理函數就可以實現,只是這裡有個小問題就是,如果直接這樣實現的話,會跟上面的進度顯示發生點小沖突,以為上面的進度更新也會觸發這裡的信號處理函數,導致視頻一直在那來回卡動無法正常播放,這裡我們可以在更新進度條是使用臨時阻塞value\_changed信號的方式避免這個問題

具體代碼如下:

添加信號處理(略)

處理函數實現

// 通過adjuest對象獲取拖動到的進度數值(根據之前的設定為1-100的范圍),
// 然後使用libvlc設定播放位置(根據百分百設定,故要除以100)
void on_value_change(GtkWidget *widget, gpointer data)
{
    float scale_value = gtk_adjustment_get_value(process_adjuest);
    libvlc_media_player_set_position(media_player, scale_value/100);
}

 

 

修改_update_scale函數如下:

// 在更新進度條數值前先阻塞信號處理函數的執行,之後在取消阻塞
gboolean _update_scale(gpointer data){
    // 獲取當前打開視頻的長度,時間單位為ms
    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_adjuest,current_play_time/video_length*100);
    g_signal_handlers_unblock_by_func(G_OBJECT(process_scale), on_value_change, NULL);
    return G_SOURCE_CONTINUE;
}

 

 

七、總結

通 過上面的一些說明,相信你可以獨立構建一個實現基本功能的視頻播放器了,不過總的說來,它是在是太基礎了,簡單來講根本拿不出手啊,作為自己日常 使用都 會有問題,比如不能全屏,不能添加字幕,不能調節音量(抱歉當前我們的實驗環境可能也聽不到聲音,但對於一個播放器來說這一點我們還是要實現)等 等,這 些就請你期待下一節項目課吧,我將帶你一步一步添加功能,完善我們的視頻播放器

本節完整代碼下載(以下內容是在實驗樓網站的虛擬平台上使用的,沒有使用實驗樓的不需要下面這個步驟)

$ git clone https://github.com/shiyanlou/gtk-vlc-video-player.git

更多詳細步驟和代碼請登錄實驗樓官方網站:http://www.shiyanlou.com/courses/69

有更多基礎課、項目課歡迎大家登陸實驗樓官方網站http://www.shiyanlou.com。
現在登陸實驗樓更有感恩好禮相送http://www.shiyanlou.com/huodong/thanks.html

 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved