#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
Переменную можно изменить, чтобы показывать другие видео.
#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. Большое вам спасибо, это отлично работает 🙂