2011-05-20 76 views
4

我正在嘗試使用GTK +和GStreamer編寫一個小型媒體播放器,並且目前使用XOverlay界面將視頻嵌入到GtkDrawing區域INSIDE的主窗口中。如何使用GStreamer&XOverlay在GTK +應用程序窗口中嵌入視頻?

該方案是使用該命令編譯:

g++ /home/phongcao/cacao.cc -o /home/phongcao/cacao `pkg-config --cflags --libs gtk+-2.0 gstreamer-0.10 gstreamer-plugins-base-0.10 gstreamer-interfaces-0.10` 


的問題是,視頻是(在工具欄的主窗口的下代替)顯示在一個SEPARATED窗口:

The video should be displayed under the mainwindow's toolbar

這是該程序的源代碼:

#include <gst/interfaces/xoverlay.h> 
#include <gtk/gtk.h> 
#include <gst/gst.h> 
#include <gdk/gdkx.h> 

GstElement *play; 
GtkAdjustment *progress; 
GtkWidget *mainwindow, *drawingarea; 

class TopWin 
{ 
public: 
    TopWin(); 
    ~TopWin(); 
    int Initialize(int argc, char *argv[]); 
    int Execute(); 
    static void FileChooser(GtkButton *button, GtkWindow *mainwindow); 
    static int Play(gchar *addr); 
    static gboolean print_position(GstElement *element); 
private: 
}; 

TopWin::TopWin() { 
} 

TopWin::~TopWin() { 
} 

gboolean TopWin::print_position(GstElement *play) { 
    GstFormat fmt = GST_FORMAT_TIME; 
    gint64 pos, len; 

    if (gst_element_query_position(play, &fmt, &pos) && gst_element_query_duration(play, &fmt, &len)) { 
    g_print("Time: %" GST_TIME_FORMAT "/%" GST_TIME_FORMAT "\r", GST_TIME_ARGS(pos), GST_TIME_ARGS(len)); 

    gtk_adjustment_set_value(GTK_ADJUSTMENT(progress), (pos*100)/len); 
    } 

    return TRUE; 
} 

int TopWin::Play(gchar *addr) { 
    GMainLoop *loop; 
    GstBus *bus; 

    loop = g_main_loop_new(NULL, FALSE); 

    play = gst_element_factory_make("playbin", "play"); 
    g_object_set(G_OBJECT(play), "uri", addr, NULL); 

    bus = gst_pipeline_get_bus(GST_PIPELINE(play)); 
    gst_object_unref(bus); 

    GstElement* x_overlay = gst_element_factory_make("xvimagesink", "videosink"); 

    g_object_set(G_OBJECT(play), "video-sink", x_overlay, NULL); 

    gst_x_overlay_set_window_handle(GST_X_OVERLAY(x_overlay), GDK_WINDOW_XID(drawingarea->window)); 

    gst_element_set_state(play, GST_STATE_NULL); 

    g_timeout_add(1000, (GSourceFunc) print_position, play); 

    gtk_adjustment_set_value(GTK_ADJUSTMENT(progress), 0); 

    gst_element_set_state(play, GST_STATE_PLAYING); 

    g_main_loop_run(loop); 

    gst_element_set_state(play, GST_STATE_NULL); 
    gst_object_unref(GST_OBJECT(play)); 

    gtk_widget_show_all(mainwindow); 
    gtk_widget_realize(drawingarea); 

    return 0; 
} 

void TopWin::FileChooser(GtkButton *button, GtkWindow *mainwindow) { 
    GtkWidget *filechooser; 
    gchar *uri; 

    filechooser = gtk_file_chooser_dialog_new("Open File...", mainwindow, GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OK, GTK_RESPONSE_OK, NULL); 

    gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(filechooser), FALSE); 

    gint response = gtk_dialog_run(GTK_DIALOG(filechooser)); 

    if (response == GTK_RESPONSE_OK) { 
    uri = gtk_file_chooser_get_uri(GTK_FILE_CHOOSER(filechooser)); 
    gtk_widget_destroy(filechooser); 
    Play(uri); 
    g_free(uri); 
    } 
    else if (response == GTK_RESPONSE_CANCEL) { 
    gtk_widget_destroy(filechooser); 
    } 
} 

int TopWin::Initialize(int argc, char *argv[]) { 
    GtkWidget *playbutton, *openbutton, *volumebutton; 
    GtkWidget *prefbutton, *notebook; 
    GtkWidget *vbox, *hbox; 
    GtkWidget *entry, *hscale; 

    gtk_init(&argc, &argv); 
    gst_init(&argc, &argv); 

    mainwindow = gtk_window_new(GTK_WINDOW_TOPLEVEL); 
    gtk_container_set_border_width(GTK_CONTAINER(mainwindow), 0); 
    g_signal_connect(G_OBJECT(mainwindow), "destroy", G_CALLBACK(gtk_main_quit), NULL); 

    playbutton = gtk_button_new(); 
    gtk_button_set_image(GTK_BUTTON(playbutton), gtk_image_new_from_stock(GTK_STOCK_MEDIA_PLAY, GTK_ICON_SIZE_SMALL_TOOLBAR)); 

    openbutton = gtk_button_new(); 
    gtk_button_set_image(GTK_BUTTON(openbutton), gtk_image_new_from_stock(GTK_STOCK_OPEN, GTK_ICON_SIZE_SMALL_TOOLBAR)); 
    g_signal_connect(G_OBJECT(openbutton), "clicked", G_CALLBACK(TopWin::FileChooser), (gpointer) mainwindow); 

    volumebutton = gtk_button_new(); 
    gtk_button_set_image(GTK_BUTTON(volumebutton), gtk_image_new_from_file("volume.png")); 

    prefbutton = gtk_button_new(); 
    gtk_button_set_image(GTK_BUTTON(prefbutton), gtk_image_new_from_stock(GTK_STOCK_EXECUTE, GTK_ICON_SIZE_SMALL_TOOLBAR)); 

    entry = gtk_entry_new(); 

    progress = GTK_ADJUSTMENT(gtk_adjustment_new(0.00, 0.00, 100.00, 1.00, 0.00, 0.00)); 

    hscale = gtk_hscale_new(progress); 
    gtk_scale_set_draw_value(GTK_SCALE(hscale), FALSE); 
    gtk_widget_set_size_request(hscale, 200, NULL); 

    hbox = gtk_hbox_new(FALSE, 0); 
    drawingarea = gtk_drawing_area_new(); 
    vbox = gtk_vbox_new(FALSE, 0); 

    gtk_box_pack_start(GTK_BOX(hbox), openbutton, FALSE, FALSE, 2); 
    gtk_box_pack_start(GTK_BOX(hbox), playbutton, FALSE, FALSE, 2); 

    gtk_box_pack_start(GTK_BOX(hbox), hscale, FALSE, FALSE, 2); 
    gtk_box_pack_start(GTK_BOX(hbox), volumebutton, FALSE, FALSE, 2); 
    gtk_box_pack_start(GTK_BOX(hbox), entry, TRUE, TRUE, 2); 
    gtk_box_pack_start(GTK_BOX(hbox), prefbutton, FALSE, FALSE, 2); 

    gtk_button_set_relief(GTK_BUTTON(playbutton), GTK_RELIEF_NONE); 
    gtk_button_set_relief(GTK_BUTTON(openbutton), GTK_RELIEF_NONE); 
    gtk_button_set_relief(GTK_BUTTON(volumebutton), GTK_RELIEF_NONE); 
    gtk_button_set_relief(GTK_BUTTON(prefbutton), GTK_RELIEF_NONE); 

    gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); 
    gtk_box_pack_start(GTK_BOX(vbox), drawingarea, FALSE, FALSE, 0); 

    gtk_container_add(GTK_CONTAINER(mainwindow), vbox); 

    gtk_widget_show_all(mainwindow); 

    gtk_widget_realize(drawingarea); 

    return 0; 
} 

int TopWin::Execute() { 
    gtk_main(); 

    return 0; 
} 

int main(int argc, char *argv[]) 
{ 
    int result = 0; 
    TopWin* topwin = new TopWin(); 

    if (0 == topwin->Initialize(argc, argv)) { 
    result = topwin->Execute(); 
    } 

    delete topwin; 

    return result; 
} 


謝謝你幫助我解決這個問題!爲此,我花了近3天的時間搔搔腦袋。上的GStreamer網站的XOverlay參考是如此混亂... :(

請告訴我,如果你需要任何額外的信息......謝謝!!

回答

7

你需要做這樣的事情:

GstElement* x_overlay=gst_element_factory_make ("xvimagesink", "videosink"); 
g_object_set(G_OBJECT(play),"video-sink",x_overlay,NULL); 
gst_x_overlay_set_window_handle(GST_X_OVERLAY(x_overlay), GDK_WINDOW_XID(drawingarea->window)); 

創建新XV視頻接收器。它設爲您的playbin的視頻接收。附加XV視頻接收到你的繪圖區的窗口的ID。你還需要在此之前,加drawingarea一些容器。

您的程序機生產線ces警告和gtk錯誤,他們可能是你的一些問題的根源,更好地解決它們。

+0

謝謝你的迴應!根據你所說的,我已經編輯了上面的代碼。然後我編譯源代碼並得到這個錯誤: 「/home/phongcao/cacao.cc:61:錯誤:'gst_x_overlay_set_window_handle'未在此範圍內聲明」。不知道這是一個GStreamer的錯誤還是我的錯...你可以複製粘貼上面的代碼,並嘗試在你的機器上編譯,看看GStreamer是否工作...非常感謝你Banthar! – phongvcao 2011-05-21 04:38:48

+0

@phngcv:它適合我。嘗試更新您的GStreamer或將此函數更改爲'gst_x_overlay_set_xwindow_id'。如果這沒有幫助,打開'gst/interfaces/xoverlay.h'並檢查聲明瞭哪些函數。 – 2011-05-21 08:00:45

+3

只是爲了警告你'gst_x_overlay_set_window_handle(GST_X_OVERLAY(x_overlay),GDK_WINDOW_XID(drawingarea-> window))行;'不是線程安全的。您需要在實現信號上放置一個處理程序,以便通過'GDK_WINDOW_XID(drawingarea-> window)獲取xid;'保存該值並稍後使用'gst_x_overlay_set_window_handle'。 – Mindbane 2011-12-29 15:18:46

相關問題