How to embed video in GTK+ application window using GStreamer & XOverlay?

11,767

Solution 1

You need to do something like this:

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

Create new XV video sink. Set it as video sink of your playbin. Attach xv video sink to your drawingarea window ID. You also need to add drawingarea to some container before that.

Your program produces warnings and gtk errors, they may be source of some of your problems better fix them.

Solution 2

gst_x_overlay_set_window_handle interface is deprecated now in recent gstreamer library. New interface is gst_video_overlay_set_window_handle. A simple supplementation can be sited from https://web.archive.org/web/20190628124320/http://wikistack.com/how-to-make-your-own-media-player-in-linux-using-gtk-and-gstreamer/

Share:
11,767
phongvcao
Author by

phongvcao

Updated on June 04, 2022

Comments

  • phongvcao
    phongvcao about 2 years

    I am trying to write a small media player using GTK+ and GStreamer and currently using the XOverlay Interface to embed the video in a GtkDrawing Area INSIDE the mainwindow.

    The program was compiled using this command:

    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`
    


    The problem is that the video was displayed in a SEPARATED window (instead of under the toolbar of the main window):

    The video should be displayed under the mainwindow's toolbar

    Here is the source code of the program:

    #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;
    }
    


    Thank you for helping me with this problem! I have spent almost 3 days scratching over my head for this. The XOverlay reference on GStreamer website is so confusing... :(

    Please tell me if you need any additional information... Thank you!!

  • phongvcao
    phongvcao about 13 years
    Thank you for your response! I already edited the code above according to what you said. Then I compiled the source and got this error: "/home/phongcao/cacao.cc:61: error: ‘gst_x_overlay_set_window_handle’ was not declared in this scope". Not sure if this is a bug of GStreamer or my fault... Can you please copy paste the code above and try to compile on your machine to see if GStreamer works... Thank you very much Banthar!!
  • Piotr Praszmo
    Piotr Praszmo about 13 years
    @phngcv: It works fine for me. Try updating your GStreamer or change this function to gst_x_overlay_set_xwindow_id. If that doesn't help, open gst/interfaces/xoverlay.h and check what functions are declared.
  • Mindbane
    Mindbane over 12 years
    Just to warn you the line gst_x_overlay_set_window_handle(GST_X_OVERLAY(x_overlay), GDK_WINDOW_XID(drawingarea->window)); is not thread safe. You need to put a handler on the realize signal to get the xid with GDK_WINDOW_XID(drawingarea->window); save that value and the use it later with gst_x_overlay_set_window_handle.