You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用GtkVideo在GTK4窗口播放视频遇空白屏问题求助

GTK4 GtkVideo播放视频空白问题解决方法及替代方案

问题排查与修复步骤

1. 检查依赖组件

GtkVideo依赖GStreamer提供媒体解码能力,缺失对应插件会导致视频无法加载:

  • Debian/Ubuntu系统执行:
    sudo apt install gstreamer1.0-gtk4 gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-libav
    
  • Fedora/RHEL系统执行:
    sudo dnf install gtk4-gstreamer gstreamer1-plugins-good gstreamer1-plugins-bad-free gstreamer1-libav
    

2. 修正原代码问题

原代码存在几处关键问题:

  • gtk_media_stream_play调用时机过早,媒体资源尚未加载完成
  • 存在不必要的return 0(activate为void类型函数)
  • 未释放g_file_new_for_path创建的GFile对象(内存泄漏)

修正后的代码:

#include <gtk/gtk.h>

static void activate(GtkApplication *app, gpointer user_data)
{
    GtkWidget *window;
    GtkWidget *video;
    GFile *file;

    // 创建主应用窗口
    window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "GTK4 Video Player");
    gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);

    // 创建GtkVideo并启用自动播放
    video = gtk_video_new();
    gtk_video_set_autoplay(GTK_VIDEO(video), TRUE);

    // 加载视频文件并释放资源
    file = g_file_new_for_path("my_video.mp4");
    gtk_video_set_file(GTK_VIDEO(video), file);
    g_object_unref(file);

    // 将视频部件添加到窗口
    gtk_window_set_child(GTK_WINDOW(window), video);

    // 显示窗口
    gtk_widget_show(window);
}

int main(int argc, char *argv[])
{
    GtkApplication *app;
    int status;

    app = gtk_application_new("org.gtk.example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

3. 编译与运行

使用pkg-config链接必要库进行编译:

gcc -o gtk4-video-player gtk4-video-player.c $(pkg-config --cflags --libs gtk4 gstreamer-1.0 gstreamer-video-1.0)

确保my_video.mp4位于程序运行的当前目录,或替换为绝对路径后执行程序。

替代方案:直接使用GStreamer GTK4 Sink

如果GtkVideo仍无法正常工作,可以直接基于GStreamer构建播放管道,示例代码如下:

#include <gtk/gtk.h>
#include <gst/gst.h>
#include <gst/video/videooverlay.h>

static GstElement *pipeline;

static void activate(GtkApplication *app, gpointer user_data)
{
    GtkWidget *window;
    GtkWidget *video_widget;
    GstElement *source, *decodebin, *videoconvert, *sink;

    // 创建主窗口
    window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "GStreamer GTK4 Player");
    gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);

    // 初始化GStreamer管道元素
    pipeline = gst_pipeline_new("video-pipeline");
    source = gst_element_factory_make("filesrc", "file-source");
    decodebin = gst_element_factory_make("decodebin3", "decoder");
    videoconvert = gst_element_factory_make("videoconvert", "converter");
    sink = gst_element_factory_make("gtk4sink", "video-sink");

    if (!pipeline || !source || !decodebin || !videoconvert || !sink) {
        g_printerr("Failed to create GStreamer elements\n");
        return;
    }

    // 设置视频文件路径
    g_object_set(source, "location", "my_video.mp4", NULL);

    // 获取GTK播放部件并添加到窗口
    g_object_get(sink, "widget", &video_widget, NULL);
    gtk_window_set_child(GTK_WINDOW(window), video_widget);

    // 将元素添加到管道
    gst_bin_add_many(GST_BIN(pipeline), source, decodebin, videoconvert, sink, NULL);

    // 链接源元素与解码器
    if (!gst_element_link(source, decodebin)) {
        g_printerr("Failed to link source and decodebin\n");
        gst_object_unref(pipeline);
        return;
    }

    // 处理解码器的pad-added信号,动态链接到转换元素
    g_signal_connect(decodebin, "pad-added", G_CALLBACK(
        (void (*)(GstElement*, GstPad*, gpointer))
        ([](GstElement *decodebin, GstPad *pad, gpointer data) {
            GstElement *videoconvert = data;
            GstPad *sink_pad = gst_element_get_static_pad(videoconvert, "sink");
            if (gst_pad_is_compatible(pad, sink_pad)) {
                gst_pad_link(pad, sink_pad);
            }
            gst_object_unref(sink_pad);
        }), videoconvert);

    // 链接转换元素与输出sink
    if (!gst_element_link(videoconvert, sink)) {
        g_printerr("Failed to link videoconvert and sink\n");
        gst_object_unref(pipeline);
        return;
    }

    // 启动播放管道
    gst_element_set_state(pipeline, GST_STATE_PLAYING);

    // 显示窗口
    gtk_widget_show(window);

    // 窗口关闭时停止管道并释放资源
    g_signal_connect(window, "destroy", G_CALLBACK(
        (void (*)(GtkWidget*, gpointer))
        ([](GtkWidget *window, gpointer data) {
            GstElement *pipeline = data;
            gst_element_set_state(pipeline, GST_STATE_NULL);
            gst_object_unref(pipeline);
        }), pipeline);
}

int main(int argc, char *argv[])
{
    GtkApplication *app;
    int status;

    // 初始化GStreamer
    gst_init(&argc, &argv);

    app = gtk_application_new("org.gtk.gstreamer-example", G_APPLICATION_FLAGS_NONE);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

编译命令:

gcc -o gstreamer-gtk4-player gstreamer-gtk4-player.c $(pkg-config --cflags --libs gtk4 gstreamer-1.0 gstreamer-video-1.0)

内容的提问来源于stack exchange,提问作者teena meheren

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 04:05:55