Search code examples
gstreamerwxwidgetsgtk3

Impossible to convert 'WXWidget' in 'GtkWidget *


Here is my code :

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

were pnlView is define as wxPanel* pnlView;

But the consol give me this error : Impossible to convert 'WXWidget' in 'GtkWidget * at the line where I initialize video_window

Can someone has any idea how to fix it ?

I just want to add my gstreamer window in my wxWindow

Thank you


Solution

  • I've never used gstreamer, but I do sometimes use libvlc which is probably very similar. When using libvlc to render into a wxWindow, I need to wait until the wxWindow is fully created before I can set vlc to use it. This is done by adding an event handler for the window creation event.

    The process of declaring and binding the event handler looks like this:

    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
        ...
    }
    

    For libvlc, my window creation event handler looks like this:

    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
    }
    

    Based on the code you posted, I think the body of an event handler that will work for you should look something like this:

    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
    }
    

    Edit:

    Here's a simple example of using GStreamer to draw onto a wxWindow on GTK. This shows how to use the wxEVT_CREATE to get the XID for a window and how to use GStreamer's bus sync handler callback to pass that XID to GStreamer at the correct time.

    This is basically a mashup of the 2nd tutorial and the code snippet from the GstVideoOverlay page adjusted for wxWidgets. Since this is based on the 2nd tutorial, it just shows a test pattern. The source variable can be changed to show other videos.

    Obviously this assumes GTK is using X11. Some adjustments would be needed if Wayland is used instead, but I don't have a running distro that uses Wayland to test on, so I don't know what changes are needed there.

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

    On mint it looks like this:

    enter image description here

    On windows it looks like this:

    enter image description here