无法在 'GtkWidget * 中转换 'WXWidget'

Impossible to convert 'WXWidget' in 'GtkWidget *

这是我的代码:

/// 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;

但是 consol 给我这个错误:Impossible to convert 'WXWidget' in 'GtkWidget * 在我初始化 video_window

的行

有人知道如何解决吗?

我只想在我的 wxWindow

中添加我的 gstreamer window

谢谢

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

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

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,我的 window 创建事件处理程序如下所示:

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 获取 window 的 XID,以及如何使用 GStreamer 的总线同步处理程序回调在正确的时间将该 XID 传递给 GStreamer。

这基本上是针对 wxWidgets 调整的 2nd tutorial and the code snippet from the GstVideoOverlay 页面的混搭。由于这是基于第二个教程,因此它只显示了一个测试模式。可以更改 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 上看起来像这样: