【问题标题】:How to embed video in GTK+ application window using GStreamer & XOverlay?如何使用 GStreamer 和 XOverlay 在 GTK+ 应用程序窗口中嵌入视频?
【发布时间】:2011-05-20 22:57:28
【问题描述】:

我正在尝试使用 GTK+ 和 GStreamer 编写一个小型媒体播放器,目前正在使用 XOverlay 接口将视频嵌入到 GtkDrawing 区域 INSIDE 主窗口中。

程序是使用这个命令编译的:

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 窗口中(而不是主窗口的工具栏下):

这是程序的源代码:

#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 参考非常令人困惑...... :(

如果您需要任何其他信息,请告诉我...谢谢!

【问题讨论】:

    标签: c++ c gtk gstreamer


    【解决方案1】:

    你需要做这样的事情:

    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 添加到某个容器中。

    您的程序会产生警告和 gtk 错误,它们可能是您的一些问题的根源,最好解决它们。

    【讨论】:

    • 感谢您的回复!我已经按照你说的编辑了上面的代码。然后我编译了源代码并得到了这个错误:“/home/phongcao/cacao.cc:61:错误:‘gst_x_overlay_set_window_handle’没有在这个范围内声明”。不确定这是 GStreamer 的错误还是我的错...您能否复制粘贴上面的代码并尝试在您的机器上编译以查看 GStreamer 是否有效...非常感谢 Banthar!
    • @phngcv:对我来说效果很好。尝试更新您的 GStreamer 或将此功能更改为 gst_x_overlay_set_xwindow_id。如果这没有帮助,请打开 gst/interfaces/xoverlay.h 并检查声明了哪些函数。
    • 只是提醒您gst_x_overlay_set_window_handle(GST_X_OVERLAY(x_overlay), GDK_WINDOW_XID(drawingarea-&gt;window)); 行不是线程安全的。您需要在实现信号上放置一个处理程序,以使用 GDK_WINDOW_XID(drawingarea-&gt;window); 获取 xid 保存该值并稍后使用 gst_x_overlay_set_window_handle
    【解决方案2】:

    gst_x_overlay_set_window_handle 接口现在在最近的 gstreamer 库中已弃用。新界面是gst_video_overlay_set_window_handle。一个简单的补充可以从https://web.archive.org/web/20190628124320/http://wikistack.com/how-to-make-your-own-media-player-in-linux-using-gtk-and-gstreamer/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-05
      • 1970-01-01
      • 2016-12-06
      • 1970-01-01
      相关资源
      最近更新 更多