无法在 GTK+ 中嵌入 Gstreamer 视频 window
Unable to embed Gstreamer video in a GTK+ window
我正在尝试编写一个非常简单的 GTK+ 程序,它允许我使用 Gstreamer 播放视频。以下是代码:
#include <gtk/gtk.h>
#include <gst/gst.h>
#include <gst/video/videooverlay.h>
#include <gdk/gdkwin32.h>
static GstElement *playbin;
static guintptr window_handle = 0;
static void report_error(GstBus *playbin_bus, GstMessage *error_message, gpointer user_data) {
GError *error;
gchar *debug_info;
gst_message_parse_error(error_message, &error, &debug_info);
g_printerr("Error received from element %s: %s\n", GST_OBJECT_NAME(error_message->src), error->message);
g_printerr("Debugging information: %s\n", debug_info ? debug_info : "none");
g_clear_error(&error);
g_free(debug_info);
}
static GstBusSyncReply prepare_window_handle(GstBus *bus, GstMessage *message, GstPipeline * pipeline) {
if (!gst_is_video_overlay_prepare_window_handle_message(message)) {
return GST_BUS_PASS;
}
g_assert(window_handle != 0);
gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(playbin), window_handle);
gst_message_unref(message);
return GST_BUS_DROP;
}
static void realize_video_drawing_area(GtkWidget *video_drawing_area, gpointer user_data) {
GdkWindow *video_window = gtk_widget_get_window(video_drawing_area);
if (!gdk_window_ensure_native(video_window)) {
g_error("Couldn't create native window needed for GstVideoOverlay!");
}
window_handle = (guintptr) GDK_WINDOW_HWND(video_window);
}
static void play(GtkButton *play_button, gpointer user_data) {
gst_element_set_state(playbin, GST_STATE_PLAYING);
}
static void activate(GtkApplication *app, gpointer user_data) {
GtkWidget *window = gtk_application_window_new(app);
GtkWidget *root_pane = gtk_overlay_new();
gtk_container_add(GTK_CONTAINER(window), root_pane);
GtkWidget *video_drawing_area = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(root_pane), video_drawing_area);
gtk_widget_set_size_request(video_drawing_area, 800, 600);
gtk_widget_set_double_buffered(video_drawing_area, FALSE);
g_signal_connect(video_drawing_area, "realize", G_CALLBACK(realize_video_drawing_area), NULL);
GtkWidget *play_button = gtk_button_new_with_label("Play");
gtk_overlay_add_overlay(GTK_OVERLAY(root_pane), play_button);
gtk_widget_set_halign(play_button, GTK_ALIGN_END);
gtk_widget_set_valign(play_button, GTK_ALIGN_END);
gtk_widget_set_margin_end(play_button, 20);
gtk_widget_set_margin_bottom(play_button, 20);
g_signal_connect(G_OBJECT(play_button), "clicked", G_CALLBACK(play), NULL);
gtk_widget_show_all(window);
}
int main(int argc, char **argv) {
gst_init(&argc, &argv);
playbin = gst_element_factory_make("playbin", NULL);
g_object_set(playbin, "uri", "http://techslides.com/demos/sample-videos/small.ogv", NULL);
GstBus *playbin_bus = gst_element_get_bus(playbin);
gst_bus_enable_sync_message_emission(playbin_bus);
gst_bus_set_sync_handler(playbin_bus, (GstBusSyncHandler) prepare_window_handle, NULL, NULL);
gst_bus_add_signal_watch(playbin_bus);
g_signal_connect(playbin_bus, "message::error", G_CALLBACK(report_error), NULL);
gst_object_unref(playbin_bus);
GtkApplication *app = gtk_application_new("com.techn.videotest", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
return g_application_run(G_APPLICATION(app), argc, argv);
}
每当我按下 "Play" 时,音频播放开始,但我看不到视频。如果我注释掉行
gst_bus_set_sync_handler(playbin_bus, (GstBusSyncHandler) prepare_window_handle, NULL, NULL);
视频以单独的 D3D windows 开始,播放没有问题。我在控制台中看不到相关的错误消息,除非以下情况:
(video_test.exe:5172): GStreamer-WARNING **: Failed to load plugin 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstchromaprint.dll': 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstchromaprint.dll': The specified module could not be found.
(video_test.exe:5172): GStreamer-WARNING **: Failed to load plugin 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstfragmented.dll': 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstfragmented.dll': The specified module could not be found.
(video_test.exe:5172): GStreamer-WARNING **: Failed to load plugin 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstx264.dll': 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstx264.dll': The specified module could not be found.
(video_test.exe:5172): GStreamer-WARNING **: Failed to load plugin 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstx265.dll': 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstx265.dll': The specified procedure could not be found.
(video_test.exe:5172): GLib-GObject-WARNING **: attempt to override closure->va_marshal (63c488b0) with new marshal (66925ea8)
我正在使用以下命令行编译程序:
gcc video_test.c -o video_test `pkg-config --cflags --libs gtk+-3.0 gstreamer-1.0` -lgstvideo-1.0 -Wno-deprecated-declarations
我在 Windows 10 机器和 MinGW 32 位编译器上使用 MSYS2 环境。我有 1.0 版的 Gstreamer 和 3.0 版的 GTK+ 库。
我上个月在 windows 10 和 msys2 上将 gstreamer 与 gtk+3 集成时遇到了同样的问题。
Videooverlay 不起作用!请改用 gtksink。
尝试:
#include <gtk/gtk.h>
#include <gst/gst.h>
static GstElement *playbin, *sink;
static void play(GtkButton *play_button, gpointer user_data) {
gst_element_set_state(playbin, GST_STATE_PLAYING);
}
static void activate(GtkApplication *app, gpointer user_data) {
GtkWidget *window = gtk_application_window_new(app);
GtkWidget *root_pane = gtk_overlay_new();
gtk_container_add(GTK_CONTAINER(window), root_pane);
GtkWidget *video_drawing_area = gtk_drawing_area_new();
g_object_get (sink, "widget", &video_drawing_area, NULL);
gtk_widget_set_size_request(video_drawing_area, 800, 600);
gtk_container_add(GTK_CONTAINER(root_pane), video_drawing_area);
GtkWidget *play_button = gtk_button_new_with_label("Play");
gtk_overlay_add_overlay(GTK_OVERLAY(root_pane), play_button);
gtk_widget_set_halign(play_button, GTK_ALIGN_END);
gtk_widget_set_valign(play_button, GTK_ALIGN_END);
gtk_widget_set_margin_end(play_button, 20);
gtk_widget_set_margin_bottom(play_button, 20);
g_signal_connect(G_OBJECT(play_button), "clicked", G_CALLBACK(play), NULL);
gtk_widget_show_all(window);
}
int main(int argc, char **argv) {
gst_init(&argc, &argv);
playbin = gst_element_factory_make("playbin", NULL);
g_object_set(playbin, "uri", "http://techslides.com/demos/sample-videos/small.ogv", NULL);
sink = gst_element_factory_make ("gtksink", NULL);
g_object_set(playbin, "video-sink", sink, NULL);
GtkApplication *app = gtk_application_new("com.techn.videotest", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
return g_application_run(G_APPLICATION(app), argc, argv);
}
并编译它:
gcc videotest.c -o videotest `pkg-config --cflags --libs gtk+-3.0 gstreamer-video-1.0`
或尝试:
#include <gtk/gtk.h>
#include <gst/gst.h>
GstElement *pipeline, *src, *sink;
int main (int argc, char **argv)
{
gst_init (&argc, &argv);
gtk_init (&argc, &argv);
pipeline = gst_pipeline_new ("xvoverlay");
src = gst_element_factory_make ("videotestsrc", NULL);
sink = gst_element_factory_make ("gtksink", NULL);
gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
gst_element_link (src, sink);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
GtkWidget *area;
g_object_get (sink, "widget", &area, NULL);
gtk_container_add (GTK_CONTAINER (window), area);
gtk_widget_realize(area);
gtk_widget_show_all (window);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
gtk_main ();
return 0;
}
这个 SO 答案让我找到了解决方案:
我刚刚发现问题所在。就我而言,使用 gtksink 根本不合适。
我发现在 Windows Aero 主题关闭的情况下一切正常。进一步调查指出这是因为 'layered' W7 windows (WS_EX_LAYERED
window 属性)。
因此,从 GDK 源代码可以看出,有一个很好的规定解决方案:
如果环境变量 GDK_WIN32_LAYERED
设置为 0
,GDK 根本不使用分层 windows。也可以通过编程方式完成:
#ifdef WIN32
Glib::setenv ("GDK_WIN32_LAYERED", "0", false) ;
#endif
我正在尝试编写一个非常简单的 GTK+ 程序,它允许我使用 Gstreamer 播放视频。以下是代码:
#include <gtk/gtk.h>
#include <gst/gst.h>
#include <gst/video/videooverlay.h>
#include <gdk/gdkwin32.h>
static GstElement *playbin;
static guintptr window_handle = 0;
static void report_error(GstBus *playbin_bus, GstMessage *error_message, gpointer user_data) {
GError *error;
gchar *debug_info;
gst_message_parse_error(error_message, &error, &debug_info);
g_printerr("Error received from element %s: %s\n", GST_OBJECT_NAME(error_message->src), error->message);
g_printerr("Debugging information: %s\n", debug_info ? debug_info : "none");
g_clear_error(&error);
g_free(debug_info);
}
static GstBusSyncReply prepare_window_handle(GstBus *bus, GstMessage *message, GstPipeline * pipeline) {
if (!gst_is_video_overlay_prepare_window_handle_message(message)) {
return GST_BUS_PASS;
}
g_assert(window_handle != 0);
gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(playbin), window_handle);
gst_message_unref(message);
return GST_BUS_DROP;
}
static void realize_video_drawing_area(GtkWidget *video_drawing_area, gpointer user_data) {
GdkWindow *video_window = gtk_widget_get_window(video_drawing_area);
if (!gdk_window_ensure_native(video_window)) {
g_error("Couldn't create native window needed for GstVideoOverlay!");
}
window_handle = (guintptr) GDK_WINDOW_HWND(video_window);
}
static void play(GtkButton *play_button, gpointer user_data) {
gst_element_set_state(playbin, GST_STATE_PLAYING);
}
static void activate(GtkApplication *app, gpointer user_data) {
GtkWidget *window = gtk_application_window_new(app);
GtkWidget *root_pane = gtk_overlay_new();
gtk_container_add(GTK_CONTAINER(window), root_pane);
GtkWidget *video_drawing_area = gtk_drawing_area_new();
gtk_container_add(GTK_CONTAINER(root_pane), video_drawing_area);
gtk_widget_set_size_request(video_drawing_area, 800, 600);
gtk_widget_set_double_buffered(video_drawing_area, FALSE);
g_signal_connect(video_drawing_area, "realize", G_CALLBACK(realize_video_drawing_area), NULL);
GtkWidget *play_button = gtk_button_new_with_label("Play");
gtk_overlay_add_overlay(GTK_OVERLAY(root_pane), play_button);
gtk_widget_set_halign(play_button, GTK_ALIGN_END);
gtk_widget_set_valign(play_button, GTK_ALIGN_END);
gtk_widget_set_margin_end(play_button, 20);
gtk_widget_set_margin_bottom(play_button, 20);
g_signal_connect(G_OBJECT(play_button), "clicked", G_CALLBACK(play), NULL);
gtk_widget_show_all(window);
}
int main(int argc, char **argv) {
gst_init(&argc, &argv);
playbin = gst_element_factory_make("playbin", NULL);
g_object_set(playbin, "uri", "http://techslides.com/demos/sample-videos/small.ogv", NULL);
GstBus *playbin_bus = gst_element_get_bus(playbin);
gst_bus_enable_sync_message_emission(playbin_bus);
gst_bus_set_sync_handler(playbin_bus, (GstBusSyncHandler) prepare_window_handle, NULL, NULL);
gst_bus_add_signal_watch(playbin_bus);
g_signal_connect(playbin_bus, "message::error", G_CALLBACK(report_error), NULL);
gst_object_unref(playbin_bus);
GtkApplication *app = gtk_application_new("com.techn.videotest", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
return g_application_run(G_APPLICATION(app), argc, argv);
}
每当我按下 "Play" 时,音频播放开始,但我看不到视频。如果我注释掉行
gst_bus_set_sync_handler(playbin_bus, (GstBusSyncHandler) prepare_window_handle, NULL, NULL);
视频以单独的 D3D windows 开始,播放没有问题。我在控制台中看不到相关的错误消息,除非以下情况:
(video_test.exe:5172): GStreamer-WARNING **: Failed to load plugin 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstchromaprint.dll': 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstchromaprint.dll': The specified module could not be found.
(video_test.exe:5172): GStreamer-WARNING **: Failed to load plugin 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstfragmented.dll': 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstfragmented.dll': The specified module could not be found.
(video_test.exe:5172): GStreamer-WARNING **: Failed to load plugin 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstx264.dll': 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstx264.dll': The specified module could not be found.
(video_test.exe:5172): GStreamer-WARNING **: Failed to load plugin 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstx265.dll': 'C:\msys64\mingw32\lib\gstreamer-1.0\libgstx265.dll': The specified procedure could not be found.
(video_test.exe:5172): GLib-GObject-WARNING **: attempt to override closure->va_marshal (63c488b0) with new marshal (66925ea8)
我正在使用以下命令行编译程序:
gcc video_test.c -o video_test `pkg-config --cflags --libs gtk+-3.0 gstreamer-1.0` -lgstvideo-1.0 -Wno-deprecated-declarations
我在 Windows 10 机器和 MinGW 32 位编译器上使用 MSYS2 环境。我有 1.0 版的 Gstreamer 和 3.0 版的 GTK+ 库。
我上个月在 windows 10 和 msys2 上将 gstreamer 与 gtk+3 集成时遇到了同样的问题。
Videooverlay 不起作用!请改用 gtksink。
尝试:
#include <gtk/gtk.h>
#include <gst/gst.h>
static GstElement *playbin, *sink;
static void play(GtkButton *play_button, gpointer user_data) {
gst_element_set_state(playbin, GST_STATE_PLAYING);
}
static void activate(GtkApplication *app, gpointer user_data) {
GtkWidget *window = gtk_application_window_new(app);
GtkWidget *root_pane = gtk_overlay_new();
gtk_container_add(GTK_CONTAINER(window), root_pane);
GtkWidget *video_drawing_area = gtk_drawing_area_new();
g_object_get (sink, "widget", &video_drawing_area, NULL);
gtk_widget_set_size_request(video_drawing_area, 800, 600);
gtk_container_add(GTK_CONTAINER(root_pane), video_drawing_area);
GtkWidget *play_button = gtk_button_new_with_label("Play");
gtk_overlay_add_overlay(GTK_OVERLAY(root_pane), play_button);
gtk_widget_set_halign(play_button, GTK_ALIGN_END);
gtk_widget_set_valign(play_button, GTK_ALIGN_END);
gtk_widget_set_margin_end(play_button, 20);
gtk_widget_set_margin_bottom(play_button, 20);
g_signal_connect(G_OBJECT(play_button), "clicked", G_CALLBACK(play), NULL);
gtk_widget_show_all(window);
}
int main(int argc, char **argv) {
gst_init(&argc, &argv);
playbin = gst_element_factory_make("playbin", NULL);
g_object_set(playbin, "uri", "http://techslides.com/demos/sample-videos/small.ogv", NULL);
sink = gst_element_factory_make ("gtksink", NULL);
g_object_set(playbin, "video-sink", sink, NULL);
GtkApplication *app = gtk_application_new("com.techn.videotest", G_APPLICATION_FLAGS_NONE);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
return g_application_run(G_APPLICATION(app), argc, argv);
}
并编译它:
gcc videotest.c -o videotest `pkg-config --cflags --libs gtk+-3.0 gstreamer-video-1.0`
或尝试:
#include <gtk/gtk.h>
#include <gst/gst.h>
GstElement *pipeline, *src, *sink;
int main (int argc, char **argv)
{
gst_init (&argc, &argv);
gtk_init (&argc, &argv);
pipeline = gst_pipeline_new ("xvoverlay");
src = gst_element_factory_make ("videotestsrc", NULL);
sink = gst_element_factory_make ("gtksink", NULL);
gst_bin_add_many (GST_BIN (pipeline), src, sink, NULL);
gst_element_link (src, sink);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
GtkWidget *area;
g_object_get (sink, "widget", &area, NULL);
gtk_container_add (GTK_CONTAINER (window), area);
gtk_widget_realize(area);
gtk_widget_show_all (window);
gst_element_set_state (pipeline, GST_STATE_PLAYING);
gtk_main ();
return 0;
}
这个 SO 答案让我找到了解决方案:
我刚刚发现问题所在。就我而言,使用 gtksink 根本不合适。
我发现在 Windows Aero 主题关闭的情况下一切正常。进一步调查指出这是因为 'layered' W7 windows (WS_EX_LAYERED
window 属性)。
因此,从 GDK 源代码可以看出,有一个很好的规定解决方案:
如果环境变量 GDK_WIN32_LAYERED
设置为 0
,GDK 根本不使用分层 windows。也可以通过编程方式完成:
#ifdef WIN32
Glib::setenv ("GDK_WIN32_LAYERED", "0", false) ;
#endif