首页 > 解决方案 > 无法在“GtkWidget”中转换“WXWidget”*

问题描述

这是我的代码:

/// Get the Gtk2+ window ID of wxPanel pnlview for GStreamer output
GtkWidget* video_window = pnlView->GetHandle();

// Without this line, GStreamer will create its own new window for the video stream.        
gtk_widget_realize(video_window);

GdkWindow *videoareaXwindow = gtk_widget_get_window(video_window);

data.xid = GDK_WINDOW_XID(videoareaXwindow) // Get xid for setting overlay later

pnlView定义为wxPanel* pnlView;

但是控制台给了我这个错误:Impossible to convert 'WXWidget' in 'GtkWidget *在我初始化的那一行video_window

有人知道如何解决吗?

我只想在我的 wxWindow 中添加我的 gstreamer 窗口

谢谢

标签: gstreamerwxwidgetsgtk3

解决方案


我从未使用过 gstreamer,但我有时会使用可能非常相似的 libvlc。使用 libvlc 渲染到 wxWindow 时,我需要等到 wxWindow 完全创建后才能设置 vlc 使用它。这是通过为窗口创建事件添加事件处理程序来完成的。

声明和绑定事件处理程序的过程如下所示:

class MainWindow : public wxFrame
{
    ...
    // Event handlers
    void OnRendererWinCreated(wxWindowCreateEvent& event);
}

MainWindow::MainWindow(...)
{
   ...
#ifdef __WXGTK__
    // On GTK+, we have to wait until the window is actually created before we
    // can tell VLC to use it for output. So wait for the window create event.
    pnlView->Bind(wxEVT_CREATE, &MainWindow::OnRendererWinCreated, this);
#elif defined(__WXMSW__)
    m_player.setHwnd(pnlView->GetHandle());
#endif
    ...
}

对于 libvlc,我的窗口创建事件处理程序如下所示:

void MainWindow::OnRendererWinCreated(wxWindowCreateEvent& event)
{
#ifdef __WXGTK__
    m_player.setXwindow(
        gdk_x11_window_get_xid(gtk_widget_get_window(pnlView->GetHandle()))
        );

    pnlView->Unbind(wxEVT_CREATE,&MainWindow::OnRendererWinCreated,this);
#endif
}

根据您发布的代码,我认为适合您的事件处理程序的主体应该如下所示:

void MainWindow::OnRendererWinCreated(wxWindowCreateEvent& event)
{
#ifdef __WXGTK__
    /// Get the Gtk2+ window ID of wxPanel pnlview for GStreamer output
    GtkWidget* video_window = pnlView->GetHandle();

    GdkWindow *videoareaXwindow = gtk_widget_get_window(video_window);

    data.xid = GDK_WINDOW_XID(videoareaXwindow) // Get xid for setting overlay later

    pnlView->Unbind(wxEVT_CREATE,&MainWindow::OnRendererWinCreated,this);
#endif
}

编辑:

这是一个使用 GStreamer 在 GTK 上的 wxWindow 上绘制的简单示例。这显示了如何使用wxEVT_CREATE获取窗口的 XID 以及如何使用 GStreamer 的总线同步处理程序回调在正确的时间将该 XID 传递给 GStreamer。

这基本上是第二个教程和GstVideoOverlay页面中针对 wxWidgets 调整的代码片段的混搭。由于这是基于第二个教程,它只是显示了一个测试模式。source可以更改该变量以显示其他视频。

显然,这是假设 GTK 使用的是 X11。如果改用 Wayland,则需要进行一些调整,但我没有使用 Wayland 进行测试的正在运行的发行版,所以我不知道那里需要进行哪些更改。

#include "wx/wx.h"

#ifdef __WXGTK__
    #include <gdk/gdkx.h>
    #include <gtk/gtk.h>
#endif

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

class MainWindow : public wxFrame
{
public:
    MainWindow(const wxString& title);
    ~MainWindow();

private:
    // Event handlers
    void OnRendererWinCreated(wxWindowCreateEvent&);
    void OnPlay(wxCommandEvent&);
    void OnStop(wxCommandEvent&);

    // Helper function
    void LoadVideo();
    void PlayHelper();

    // wx controls
    wxWindow* m_renderWindow;
    wxButton* m_playButton;
    wxButton* m_stopButton;

    // GStreamer data
    GstElement* m_pipeline;
    guintptr m_xid;
};

MainWindow::MainWindow(const wxString& title) : wxFrame(NULL, wxID_ANY, title)
{
    // Create the UI widgets.
    wxPanel* bg = new wxPanel(this,wxID_ANY);
    m_renderWindow = new wxWindow(bg,wxID_ANY);
    m_playButton = new wxButton(bg,wxID_ANY,"Play");
    m_stopButton = new wxButton(bg,wxID_ANY,"Stop");
    m_renderWindow->SetBackgroundColour(*wxBLACK);
    m_playButton->Enable(true);
    m_stopButton->Enable(false);

    // Layout the UI.
    wxBoxSizer* szr1 = new wxBoxSizer(wxVERTICAL);
    wxBoxSizer* szr2 = new wxBoxSizer(wxHORIZONTAL);
    szr2->Add(m_playButton, wxSizerFlags(0).Border(wxLEFT|wxRIGHT|wxBOTTOM));
    szr2->Add(m_stopButton, wxSizerFlags(0).Border(wxRIGHT|wxBOTTOM));

    szr1->Add(m_renderWindow, wxSizerFlags(1).Expand().Border(wxBOTTOM));
    szr1->Add(szr2, wxSizerFlags(0));
    bg->SetSizer(szr1);
    Layout();

    // Set up the event handlers.
#ifdef __WXGTK__
    m_renderWindow->Bind(wxEVT_CREATE, &MainWindow::OnRendererWinCreated, this);
    m_playButton->Enable(false);
#endif
    m_playButton->Bind(wxEVT_BUTTON, &MainWindow::OnPlay, this);
    m_stopButton->Bind(wxEVT_BUTTON, &MainWindow::OnStop, this);

    // Initialize GStreamer.
    m_xid = 0;
    m_pipeline = NULL;
    gst_init(NULL, NULL);
}

MainWindow::~MainWindow()
{
    if ( m_pipeline )
    {
        gst_element_set_state(m_pipeline, GST_STATE_NULL);
        gst_object_unref(m_pipeline);
    }
}

void MainWindow::OnRendererWinCreated(wxWindowCreateEvent&)
{
#ifdef __WXGTK__
    // This event is no longer needed.
    m_renderWindow->Unbind(wxEVT_CREATE,&MainWindow::OnRendererWinCreated,this);

    // Get the XID for this window.
    m_xid = GDK_WINDOW_XID(gtk_widget_get_window(m_renderWindow->GetHandle()));

    // We can now load and play the video, so enable the play button.
    m_playButton->Enable(true);
#endif
}

void MainWindow::OnPlay(wxCommandEvent&)
{
    if ( m_pipeline )
    {
        PlayHelper();
    }
    else
    {
        LoadVideo();
    }
}

void MainWindow::OnStop(wxCommandEvent&)
{
    if ( m_pipeline )
    {
        GstStateChangeReturn ret =
            gst_element_set_state(m_pipeline, GST_STATE_PAUSED);

        if ( ret == GST_STATE_CHANGE_FAILURE )
        {
            wxLogWarning("Unable to set the pipeline to the paused state.");
            gst_object_unref(m_pipeline);
            m_pipeline = NULL;
            m_playButton->Enable(true);
            m_stopButton->Enable(false);
        }
        else
        {
            m_playButton->Enable(true);
            m_stopButton->Enable(false);
        }
    }
}

void MainWindow::LoadVideo()
{
    // Create the elements
    GstElement *source = gst_element_factory_make("videotestsrc", "source");
#ifdef __WXGTK__
    GstElement *sink = gst_element_factory_make("xvimagesink", "sink");
    gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(sink), m_xid);
#elif defined __WXMSW__
    GstElement *sink = gst_element_factory_make("d3dvideosink", "sink");
    WXWidget hwnd = m_renderWindow->GetHandle();
    gst_video_overlay_set_window_handle(GST_VIDEO_OVERLAY(sink),
                                        reinterpret_cast<guintptr>(hwnd));
#endif

    //Create the empty pipeline
    m_pipeline = gst_pipeline_new ("test-pipeline");

    if ( !m_pipeline || !source || !sink )
    {
        wxLogError("Not all elements could be created.");
        return;
    }

    // Build the pipeline
    gst_bin_add_many(GST_BIN(m_pipeline), source, sink, NULL);
    if ( gst_element_link(source, sink) != TRUE )
    {
        wxLogWarning("Elements could not be linked.");
        gst_object_unref(m_pipeline);
        m_pipeline = NULL;
        return;
    }

    // Modify the source's properties
    g_object_set(source, "pattern", 0, NULL);

    PlayHelper();
}

void MainWindow::PlayHelper()
{
    GstStateChangeReturn ret =
        gst_element_set_state(m_pipeline, GST_STATE_PLAYING);

    if ( ret == GST_STATE_CHANGE_FAILURE )
    {
        wxLogWarning("Unable to set the pipeline to the playing state.");
        gst_object_unref(m_pipeline);
        m_pipeline = NULL;
        m_playButton->Enable(true);
        m_stopButton->Enable(false);
    }
    else
    {
        m_playButton->Enable(false);
        m_stopButton->Enable(true);
    }
}

class MyApp : public wxApp
{
public:
    bool OnInit() override
    {
        MainWindow* mainWindow = new MainWindow("wxWidgets GStreamer demo");
        mainWindow->Show();
        return true;
    }
};

wxIMPLEMENT_APP(MyApp);

薄荷看起来像这样:

在此处输入图像描述

在 Windows 上,它看起来像这样:

在此处输入图像描述


推荐阅读