如何使用 GStreamer 和 XOverlay 在 GTK+ 应用程序窗口中嵌入视频?

2024-03-29

我正在尝试使用 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`


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

这是该程序的源代码:

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


感谢您帮助我解决这个问题!我花了将近三天的时间为此绞尽脑汁。 GStreamer 网站上的 XOverlay 参考是如此令人困惑......:(

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


你需要做这样的事情:

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 错误,它们可能是某些问题的根源,最好解决它们。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何使用 GStreamer 和 XOverlay 在 GTK+ 应用程序窗口中嵌入视频? 的相关文章

  • pthread_create 编译返回错误

    我使用以下代码创建两个线程 header files include
  • 调试Windows服务

    Scenario 我有一个用 C 编写的 Windows 服务 我已经阅读了所有关于如何调试它的谷歌线程 但我仍然无法让它工作 我已经运行 PathTo NetFramework InstallUtil exe C MyService ex
  • 提升解析器中的 Spirit 段错误

    我一直在尝试将我在本科编译器中编写的一些 lex 和 yacc 代码转换为精神代码以学习精神 我发现了一个我似乎无法弄清楚的段错误 我这样写了词法分析器 namespace lex boost spirit lex enum Tokens
  • 在 Windows 上实现堆栈跟踪 [关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我正在为我正在编写的游戏实现一个崩溃报告工具 并且我想为该报告提供 相当 详细的本机堆栈跟踪 我已经在 GNU Linux 上实现
  • 如何在 javascript 中使用 .net 资源文件

    无论如何 我可以在 javascript 中访问我的资源文件 resx 吗 如果没有 那么是否有任何解决方法可以用不同语言的 javascript 显示消息 如果您的 javascript 在页面中 您可以使用 var globalReso
  • lua_resume 的 from 参数的含义

    From Lua 5 2 参考手册 http www lua org manual 5 2 manual html lua resume int lua resume lua State L lua State from int nargs
  • 从 C 调用带有字符串参数的 Go 函数?

    我可以从 C 调用一个没有参数的 Go 函数 按照下面的 https github com joeprivacy crefgo hello world 这通过编译go build和打印 Hello from Golang main func
  • 如果文本框不为空,如何添加并显示工具提示文本框 WPF

    需要显示提示 其中包含文本字段中的数据 文本框有数据时出现提示 只需使用绑定到 ToolTipService 附加属性即可 XAML
  • 使用 Xlib 捕获鼠标

    我想编写一个简单的 Xlib 程序来改变鼠标行为 举个例子 反转垂直移动 我在捕获事件时遇到问题 我想要代码 捕获控制器位置的变化 我向上移动鼠标 MotionEvent 计算新的光标位置 new x difference x 设置新的光标
  • 使用 Mono Cecil 添加 try-catch

    我正在使用 Mono Cecil 在另一个方法中注入代码 我想在我的代码周围添加一个 Try Catch 块 所以我写了一个带有 try catch 块的 HelloWorld exe 并反编译了它 Try Catch 的 Reflecto
  • 使用 JsonWriter 时,WriteStartConstructor 的用途是什么?

    标题说明了一切 我看到它 及其相应的结尾 吐出以下内容 new Foo 但我不明白什么new实际上是在反序列化时执行的 文档只是说它编写了一个 Json 构造函数 但没有说 Json 构造函数是什么is 此方法是作为增强功能的一部分引入的
  • 测试 WebApi 控制器时如何生成 Asp.net 用户身份

    我正在使用 Web API 2 在 web api 控制器中我使用过GetUserId使用 Asp net Identity 生成用户 ID 的方法 我必须为该控制器编写 MS 单元测试 如何从测试项目访问用户 ID 我在下面附上了示例代码
  • Windows 消息

    我需要发送带有自定义 ID 的自定义 Windows 消息 其他应用程序将侦听该消息 Windows 是否为内部消息保留任何预定义的消息 ID 范围 如 SQL Server 那样 内部消息最多为 50 000 The 文档 https m
  • 非数字输入导致死循环

    由于某种原因 如果用户输入了错误的数据类型 例如 j 或 循环将停止要求输入并继续显示 Enter an integer gt 一遍又一遍 如何让程序处理错误的输入 为什么输入非数字值会导致如此奇怪的行为 define SENTINEL 0
  • Azure:MissingRegistrationForLocation:未在位置“YYYY”中为资源类型“XXXX”注册订阅

    这最初是作为未找到订阅 https stackoverflow com questions 35071797 subscriptionnotfound the subscription resourcegroups could not be
  • 将 tiff 像素长宽比更改为正方形

    我正在尝试对多页 tiff 文件执行条形码识别 但是 tiff 文件是从传真服务器 我无法控制 发送给我的 该服务器以非方形像素长宽比保存 tiff 这导致图像由于纵横比而被严重挤压 我需要将 tiff 转换为方形像素长宽比 但不知道如何在
  • 生成唯一随机数的智能方法

    我想生成 00000001 到 99999999 范围内的唯一随机数序列 所以第一个可能是 00001010 第二个可能是 40002928 等等 最简单的方法是生成一个随机数并将其存储在数据库中 下次再执行一次并检查数据库中该数字是否已存
  • C++ 模板类问题中的类型条件

    使用海湾合作委员会4 2 我有这个条件类型的元模板 template
  • Phong 着色问题

    我正在根据以下内容编写着色器冯模型 http en wikipedia org wiki Phong reflection model 我正在尝试实现这个方程 其中 n 是法线 l 是光线方向 v 是相机方向 r 是光反射 维基百科文章中更
  • 为什么 typeof 函数在 C 中不起作用

    我使用GCC编译器 版本9 2 0 我想在 C 中使用 typeof 函数 但它会引发错误 错误 typeof 之前的预期表达式 如果您需要更多信息 请询问我 int a 5 double b the expected result is

随机推荐