gstreamer - 无法在“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 窗口
谢谢
解决方案
我从未使用过 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 上,它看起来像这样:
推荐阅读
- java - MockServer静态导入文档中描述的方法还是我应该传递我自己的方法?
- angular - Angular Universal 从 8 升级到 11 时无法读取属性“种类”的未定义错误
- database - 如何防止 DataGrip 显示来自另一个查询控制台的结果?
- android - 如何链接复数
- hibernate - 检查两个实体之间是否存在关系休眠
- matlab - MATLAB中的逻辑类型混淆
- javascript - 暂停执行 javascript 代码,直到收到来自 api 调用的响应
- android - 关于HMS Push Kit的问题:token的最大数量限制不能超过1000?
- spring - Spring 集成每 10 秒聚合一次消息
- embedded - OpenOCD 多适配器类型配置