Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c++

c

gtk

gstreamer

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!!

like image 970
phongvcao Avatar asked May 20 '11 22:05

phongvcao


2 Answers

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.

like image 94
Piotr Praszmo Avatar answered Sep 27 '22 21:09

Piotr Praszmo


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/

like image 39
Jay Bhaskar Avatar answered Sep 27 '22 20:09

Jay Bhaskar