Невозможно преобразовать «wxWidget» в «GtkWidget *

#gstreamer #wxwidgets #gtk3

Вопрос:

Вот мой код :

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

Может у кого-нибудь есть какие-нибудь идеи, как это исправить ?

Я просто хочу добавить свое окно gstreamer в свое wxWindow

Спасибо

Ответ №1:

Я никогда не использовал gstreamer, но иногда я использую libvlc, который, вероятно, очень похож. При использовании libvlc для визуализации в wxWindow мне нужно дождаться полного создания wxWindow, прежде чем я смогу настроить vlc для его использования. Это делается путем добавления обработчика событий для события создания окна.

Процесс объявления и привязки обработчика событий выглядит следующим образом:

 class MainWindow : public wxFrame
{
    ...
    // Event handlers
    void OnRendererWinCreated(wxWindowCreateEventamp; 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, amp;MainWindow::OnRendererWinCreated, this);
#elif defined(__WXMSW__)
    m_player.setHwnd(pnlView->GetHandle());
#endif
    ...
}
 

Для libvlc мой обработчик событий создания окна выглядит следующим образом:

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

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

Основываясь на коде, который вы опубликовали, я думаю, что тело обработчика событий, который будет работать для вас, должно выглядеть примерно так:

 void MainWindow::OnRendererWinCreated(wxWindowCreateEventamp; 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,amp;MainWindow::OnRendererWinCreated,this);
#endif
}
 

Редактировать:

Вот простой пример использования GStreamer для рисования на wxWindow в GTK. Это показывает, как использовать wxEVT_CREATE XID для получения окна и как использовать обратный вызов обработчика синхронизации шины GStreamer для передачи этого XID в GStreamer в нужное время.

Это в основном мэшап 2-го урока и фрагмент кода со страницы GstVideoOverlay, адаптированный для wxWidgets. Поскольку это основано на 2-м уроке, он просто показывает тестовый шаблон. 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 wxStringamp; title);
    ~MainWindow();

private:
    // Event handlers
    void OnRendererWinCreated(wxWindowCreateEventamp;);
    void OnPlay(wxCommandEventamp;);
    void OnStop(wxCommandEventamp;);

    // 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 wxStringamp; 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, amp;MainWindow::OnRendererWinCreated, this);
    m_playButton->Enable(false);
#endif
    m_playButton->Bind(wxEVT_BUTTON, amp;MainWindow::OnPlay, this);
    m_stopButton->Bind(wxEVT_BUTTON, amp;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(wxWindowCreateEventamp;)
{
#ifdef __WXGTK__
    // This event is no longer needed.
    m_renderWindow->Unbind(wxEVT_CREATE,amp;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(wxCommandEventamp;)
{
    if ( m_pipeline )
    {
        PlayHelper();
    }
    else
    {
        LoadVideo();
    }
}

void MainWindow::OnStop(wxCommandEventamp;)
{
    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 это выглядит так:

введите описание изображения здесь

Комментарии:

1. Извините, что принял ответ быстро, но я могу скомпилировать свою программу, и мне удается отобразить поток Gstreamer в другом окне. Однако, когда я использую ваш метод, консоль сообщает мне, что поток запущен, но в моем окне WX ничего не добавляется (и gstreamer не открывает другое окно для потока :/ У вас есть идея?

2. Спасибо за вашу помощь. но я всегда сталкиваюсь с одной и той же проблемой, что бы я ни пытался. В строке, где я использую GetHandle() У меня такая проблема : Невозможно преобразовать «wxWidget» в «GtkWidget *

3. Для информации, я нахожусь в Windows. Можно ли использовать GTK с x11 на нем?

4. Я обновил ответ 1 в последний раз, чтобы показать, как это сделать в Windows. В Windows вам не нужно ждать создания окна и делать все остальное. Вы просто получаете HWND с помощью GetHandle (), а затем передаете его gst_video_overlay_set_window_handle функции (после приведения HWND в guintptr).

5. Большое вам спасибо, это отлично работает 🙂