如何将 libvlcpp 嵌入到 wx(v3) panel/frame
How to embed libvlcpp into wx(v3) panel/frame
我想使用 wx(版本 3 及更高版本)和 libvlcpp 制作简单的跨平台播放器,但我不知道如何将 libvlcpp window 绑定到面板(位于框架内)中wx.
main_window *frame = new main_window(nullptr,wxID_ANY,wxT("Player"));
VLC::Instance instance = VLC::Instance(0, nullptr);
VLC::Media media = VLC::Media(instance, "/home/projects/vlc_test/ap.mp4", VLC::Media::FromPath);
VLC::MediaPlayer mp = VLC::MediaPlayer(media);
// frame->SetExtraStyle(4);
mp.setHwnd(frame->m_panel_vlc->GetHandle()); // this is not working !!!, btw m_panel_vlc is a public member
while(mp.play()){}
vlc_stop(mp); // a wraper for stopping
frame->Show(true);
部分输出:
[h264 @ 0x7f6b087ffd00] [0000000002454130] main input error: input control fifo overflow, trashing type=0
thread_get_buffer() failed
[0000000002454130] main input error: input control fifo overflow, trashing type=0
[h264 @ 0x7f6b087ffd00] decode_slice_header error
[h264 @ 0x7f6b087ffd00] no frame!
[0000000002454130] main input error: input control fifo overflow, trashing type=0```
这是使用 vlcpp 绘制到 wxWidgets window 的完整示例(至少对于 windows)。它基于 libvlc example,只是我将其更改为使用 vlcpp 并使用了一些稍微更现代的 wxWidgets 功能。
#include <wx/wx.h>
#include <wx/filename.h>
#ifdef __WXGTK__
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#endif
#include <vlcpp/vlc.hpp>
#include <climits>
#define TIMELINE_MAX (INT_MAX-9)
#define VOLUME_MAX 100
wxDEFINE_EVENT(vlcEVT_POS,wxThreadEvent);
wxDEFINE_EVENT(vlcEVT_END,wxThreadEvent);
static wxEvtHandler* gs_handler = NULL;
void OnPositionChanged_VLC(float f)
{
if ( gs_handler )
{
wxThreadEvent* event = new wxThreadEvent(vlcEVT_POS);
event->SetPayload<float>(f);
wxQueueEvent(gs_handler,event);
}
}
void OnEndReached_VLC()
{
if ( gs_handler )
{
wxThreadEvent* event = new wxThreadEvent(vlcEVT_END);
wxQueueEvent(gs_handler,event);
}
}
class MainWindow : public wxFrame {
public:
MainWindow(const wxString& title);
private:
// Event handlers
void OnPositionChanged(wxThreadEvent& event);
void OnEndReached(wxThreadEvent& event);
void OnOpen(wxCommandEvent& event);
void OnPlayPause(wxCommandEvent& event);
void OnStop(wxCommandEvent& event);
void OnPositionChanged_USR(wxCommandEvent& event);
void OnVolumeChanged(wxCommandEvent& event);
void OnVolumeClicked(wxMouseEvent& event);
void OnTimelineClicked(wxMouseEvent& event);
void OnRendererWinCreated(wxWindowCreateEvent& event);
// Helper functions.
void Play();
void Pause();
void Stop();
void SetTimeline(float value);
void BindTimeline();
void UnbindTimeline();
// Video player controls.
wxButton* m_playPauseButton;
wxButton* m_stopButton;
wxSlider* m_timeline;
wxSlider* m_volumeSlider;
wxWindow* m_playerWidget;
// VLC objects
VLC::Instance m_vlc;
VLC::MediaPlayer m_player;
};
MainWindow::MainWindow(const wxString& title) : wxFrame(NULL, wxID_ANY, title)
{
// Setup menubar.
wxMenuBar* menubar = new wxMenuBar;
wxMenu*file = new wxMenu;
file->Append(wxID_OPEN, "&Open");
menubar->Append(file, "&File");
SetMenuBar(menubar);
Bind(wxEVT_MENU, &MainWindow::OnOpen, this, wxID_OPEN, wxID_OPEN);
// Create the main background panel for the frame.
wxPanel* bgPanel = new wxPanel(this, wxID_ANY);
// Create the window the VLC will draw to.
m_playerWidget = new wxWindow(bgPanel, wxID_ANY);
// Create the timeline slider.
m_timeline = new wxSlider(bgPanel, wxID_ANY, 0, 0, TIMELINE_MAX);
// Create play button, the stop button, and the volume slider.
m_playPauseButton = new wxButton(bgPanel, wxID_ANY, "Play");
m_stopButton = new wxButton(bgPanel, wxID_ANY, "Stop");
m_volumeSlider = new wxSlider(bgPanel, wxID_ANY, VOLUME_MAX, 0, VOLUME_MAX);
// Set the video window black and disable the timeline and buttons.
m_playerWidget->SetBackgroundColour(*wxBLACK);
m_timeline->Enable(false);
m_playPauseButton->Enable(false);
m_stopButton->Enable(false);
// Use sizers to arrange the controls on the frame.
wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
vbox->Add(m_playerWidget, wxSizerFlags(1).Expand().Border(wxALL));
vbox->Add(m_timeline, wxSizerFlags(0).Expand().Border(wxLEFT|wxRIGHT|wxBOTTOM));
wxBoxSizer *hbox = new wxBoxSizer(wxHORIZONTAL);
hbox->Add(m_playPauseButton, wxSizerFlags(0).Border(wxLEFT|wxRIGHT|wxBOTTOM));
hbox->Add(m_stopButton,wxSizerFlags(0).Border(wxRIGHT|wxBOTTOM));
hbox->AddStretchSpacer();
hbox->Add(m_volumeSlider,wxSizerFlags(0).Border(wxRIGHT|wxBOTTOM));
vbox->Add(hbox,wxSizerFlags(0).Expand());
bgPanel->SetSizer(vbox);
Layout();
// Bind event handlers for the wxWidgets controls.
m_playPauseButton->Bind(wxEVT_BUTTON, &MainWindow::OnPlayPause, this);
m_stopButton->Bind(wxEVT_BUTTON, &MainWindow::OnStop, this);
m_volumeSlider->Bind(wxEVT_SLIDER,&MainWindow::OnVolumeChanged,this);
BindTimeline();
m_timeline->Bind(wxEVT_LEFT_UP, &MainWindow::OnTimelineClicked,this);
m_volumeSlider->Bind(wxEVT_LEFT_UP, &MainWindow::OnVolumeClicked,this);
// Bind the events that will be thrown from VLC callbacks.
Bind(vlcEVT_POS, &MainWindow::OnPositionChanged, this);
Bind(vlcEVT_END, &MainWindow::OnEndReached, this);
// Set up the VLC objects.
m_vlc = VLC::Instance(0, nullptr);
m_player = VLC::MediaPlayer(m_vlc);
#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.
m_playerWidget->Bind(wxEVT_CREATE, &MainWindow::OnRendererWinCreated, this);
#elif defined(__WXMSW__)
m_player.setHwnd(m_playerWidget->GetHandle());
#endif
// Get the player's event manager and register to callbacks.
VLC::MediaPlayerEventManager& eventManager = m_player.eventManager();
eventManager.onPositionChanged(OnPositionChanged_VLC);
eventManager.onEndReached(OnEndReached_VLC);
// Set this frame to a global variable so that it can be used with the
// VLC callbacks.
gs_handler = this;
}
void MainWindow::OnRendererWinCreated(wxWindowCreateEvent& event)
{
#ifdef __WXGTK__
m_player.setXwindow(gdk_x11_window_get_xid(gtk_widget_get_window(m_playerWidget->GetHandle())));
m_playerWidget->Unbind(wxEVT_CREATE,&MainWindow::OnRendererWinCreated,this);
#endif
}
void MainWindow::OnPositionChanged(wxThreadEvent& event)
{
float factor = event.GetPayload<float>();
SetTimeline(factor);
}
void MainWindow::OnEndReached(wxThreadEvent& event)
{
Stop();
}
void MainWindow::OnOpen(wxCommandEvent& event)
{
wxFileDialog openFileDialog(this, "Choose File");
if (openFileDialog.ShowModal() == wxID_CANCEL)
{
return;
}
else
{
wxFileName filename = wxFileName::FileName(openFileDialog.GetPath());
filename.MakeRelativeTo();
std::string s2(filename.GetFullPath().utf8_str());
VLC::Media media(m_vlc, s2, VLC::Media::FromPath);
m_player.setMedia(media);
Play();
}
}
void MainWindow::OnPlayPause(wxCommandEvent& event)
{
if ( m_player.isPlaying () )
{
Pause();
}
else
{
Play();
}
}
void MainWindow::OnStop(wxCommandEvent& event)
{
Stop();
}
void MainWindow::OnPositionChanged_USR(wxCommandEvent& event)
{
m_player.setPosition((float) event.GetInt() / (float) TIMELINE_MAX);
}
void MainWindow::OnVolumeChanged(wxCommandEvent& event)
{
m_player.setVolume(m_volumeSlider->GetValue());
}
void MainWindow::OnVolumeClicked(wxMouseEvent& event)
{
wxSize size = m_volumeSlider->GetSize();
float position = (float) event.GetX() / (float) size.GetWidth();
int volume = static_cast<int>(position*VOLUME_MAX);
m_volumeSlider->SetValue(volume);
m_player.setVolume(volume);
event.Skip();
}
void MainWindow::OnTimelineClicked(wxMouseEvent& event)
{
wxSize size = m_timeline->GetSize();
float position = (float) event.GetX() / (float) size.GetWidth();
m_player.setPosition(position);
SetTimeline(position);
event.Skip();
}
void MainWindow::Play()
{;
m_player.play();
m_playPauseButton->SetLabel("Pause");
m_playPauseButton->Enable(true);
m_stopButton->Enable(true);
m_timeline->Enable(true);
}
void MainWindow::Pause()
{
m_player.pause();
m_playPauseButton->SetLabel("Play");
}
void MainWindow::Stop()
{
Pause();
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(4, 0, 0, 0)
m_player.stopAsync();
#else
m_player.stop();
#endif
m_stopButton->Enable(false);
SetTimeline(0.0);
m_timeline->Enable(false);
}
void MainWindow::SetTimeline(float value) {
if ( value < 0.0 )
{
value = 0.0;
}
if ( value > 1.0 )
{
value = 1.0;
}
UnbindTimeline();
m_timeline->SetValue((int) (value * TIMELINE_MAX));
BindTimeline();
}
void MainWindow::BindTimeline()
{
m_timeline->Bind(wxEVT_SLIDER, &MainWindow::OnPositionChanged_USR, this);
}
void MainWindow::UnbindTimeline()
{
m_timeline->Unbind(wxEVT_SLIDER, &MainWindow::OnPositionChanged_USR, this);
}
class MyApp : public wxApp {
public:
virtual bool OnInit();
};
bool MyApp::OnInit() {
MainWindow* mainWindow = new MainWindow("wxWidgets libVLC demo");
mainWindow->Show();
return true;
}
wxIMPLEMENT_APP(MyApp);
wxGTK3 在 linux mint 上看起来像这样:
我从来没有用过vlcpp,所以我不是这里的专家。但它不允许您将数据对象传递给回调。有了 libvlc 的 c 接口,你可以使用这个数据对象传递一个 wxWidgets 事件处理程序,然后在回调中使用那个事件处理程序将 vlc 事件传递给 wxWidgets。由于 vlcpp 不允许您传递数据对象,我不得不为 wxWidgets 事件处理程序使用一个丑陋的全局变量。
除非我遗漏了什么并且有一种方法可以为 vlc 回调传递数据对象,否则这看起来像是 vlcpp 中的一个真正的主要缺陷 api。
我想使用 wx(版本 3 及更高版本)和 libvlcpp 制作简单的跨平台播放器,但我不知道如何将 libvlcpp window 绑定到面板(位于框架内)中wx.
main_window *frame = new main_window(nullptr,wxID_ANY,wxT("Player"));
VLC::Instance instance = VLC::Instance(0, nullptr);
VLC::Media media = VLC::Media(instance, "/home/projects/vlc_test/ap.mp4", VLC::Media::FromPath);
VLC::MediaPlayer mp = VLC::MediaPlayer(media);
// frame->SetExtraStyle(4);
mp.setHwnd(frame->m_panel_vlc->GetHandle()); // this is not working !!!, btw m_panel_vlc is a public member
while(mp.play()){}
vlc_stop(mp); // a wraper for stopping
frame->Show(true);
部分输出:
[h264 @ 0x7f6b087ffd00] [0000000002454130] main input error: input control fifo overflow, trashing type=0
thread_get_buffer() failed
[0000000002454130] main input error: input control fifo overflow, trashing type=0
[h264 @ 0x7f6b087ffd00] decode_slice_header error
[h264 @ 0x7f6b087ffd00] no frame!
[0000000002454130] main input error: input control fifo overflow, trashing type=0```
这是使用 vlcpp 绘制到 wxWidgets window 的完整示例(至少对于 windows)。它基于 libvlc example,只是我将其更改为使用 vlcpp 并使用了一些稍微更现代的 wxWidgets 功能。
#include <wx/wx.h>
#include <wx/filename.h>
#ifdef __WXGTK__
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
#endif
#include <vlcpp/vlc.hpp>
#include <climits>
#define TIMELINE_MAX (INT_MAX-9)
#define VOLUME_MAX 100
wxDEFINE_EVENT(vlcEVT_POS,wxThreadEvent);
wxDEFINE_EVENT(vlcEVT_END,wxThreadEvent);
static wxEvtHandler* gs_handler = NULL;
void OnPositionChanged_VLC(float f)
{
if ( gs_handler )
{
wxThreadEvent* event = new wxThreadEvent(vlcEVT_POS);
event->SetPayload<float>(f);
wxQueueEvent(gs_handler,event);
}
}
void OnEndReached_VLC()
{
if ( gs_handler )
{
wxThreadEvent* event = new wxThreadEvent(vlcEVT_END);
wxQueueEvent(gs_handler,event);
}
}
class MainWindow : public wxFrame {
public:
MainWindow(const wxString& title);
private:
// Event handlers
void OnPositionChanged(wxThreadEvent& event);
void OnEndReached(wxThreadEvent& event);
void OnOpen(wxCommandEvent& event);
void OnPlayPause(wxCommandEvent& event);
void OnStop(wxCommandEvent& event);
void OnPositionChanged_USR(wxCommandEvent& event);
void OnVolumeChanged(wxCommandEvent& event);
void OnVolumeClicked(wxMouseEvent& event);
void OnTimelineClicked(wxMouseEvent& event);
void OnRendererWinCreated(wxWindowCreateEvent& event);
// Helper functions.
void Play();
void Pause();
void Stop();
void SetTimeline(float value);
void BindTimeline();
void UnbindTimeline();
// Video player controls.
wxButton* m_playPauseButton;
wxButton* m_stopButton;
wxSlider* m_timeline;
wxSlider* m_volumeSlider;
wxWindow* m_playerWidget;
// VLC objects
VLC::Instance m_vlc;
VLC::MediaPlayer m_player;
};
MainWindow::MainWindow(const wxString& title) : wxFrame(NULL, wxID_ANY, title)
{
// Setup menubar.
wxMenuBar* menubar = new wxMenuBar;
wxMenu*file = new wxMenu;
file->Append(wxID_OPEN, "&Open");
menubar->Append(file, "&File");
SetMenuBar(menubar);
Bind(wxEVT_MENU, &MainWindow::OnOpen, this, wxID_OPEN, wxID_OPEN);
// Create the main background panel for the frame.
wxPanel* bgPanel = new wxPanel(this, wxID_ANY);
// Create the window the VLC will draw to.
m_playerWidget = new wxWindow(bgPanel, wxID_ANY);
// Create the timeline slider.
m_timeline = new wxSlider(bgPanel, wxID_ANY, 0, 0, TIMELINE_MAX);
// Create play button, the stop button, and the volume slider.
m_playPauseButton = new wxButton(bgPanel, wxID_ANY, "Play");
m_stopButton = new wxButton(bgPanel, wxID_ANY, "Stop");
m_volumeSlider = new wxSlider(bgPanel, wxID_ANY, VOLUME_MAX, 0, VOLUME_MAX);
// Set the video window black and disable the timeline and buttons.
m_playerWidget->SetBackgroundColour(*wxBLACK);
m_timeline->Enable(false);
m_playPauseButton->Enable(false);
m_stopButton->Enable(false);
// Use sizers to arrange the controls on the frame.
wxBoxSizer *vbox = new wxBoxSizer(wxVERTICAL);
vbox->Add(m_playerWidget, wxSizerFlags(1).Expand().Border(wxALL));
vbox->Add(m_timeline, wxSizerFlags(0).Expand().Border(wxLEFT|wxRIGHT|wxBOTTOM));
wxBoxSizer *hbox = new wxBoxSizer(wxHORIZONTAL);
hbox->Add(m_playPauseButton, wxSizerFlags(0).Border(wxLEFT|wxRIGHT|wxBOTTOM));
hbox->Add(m_stopButton,wxSizerFlags(0).Border(wxRIGHT|wxBOTTOM));
hbox->AddStretchSpacer();
hbox->Add(m_volumeSlider,wxSizerFlags(0).Border(wxRIGHT|wxBOTTOM));
vbox->Add(hbox,wxSizerFlags(0).Expand());
bgPanel->SetSizer(vbox);
Layout();
// Bind event handlers for the wxWidgets controls.
m_playPauseButton->Bind(wxEVT_BUTTON, &MainWindow::OnPlayPause, this);
m_stopButton->Bind(wxEVT_BUTTON, &MainWindow::OnStop, this);
m_volumeSlider->Bind(wxEVT_SLIDER,&MainWindow::OnVolumeChanged,this);
BindTimeline();
m_timeline->Bind(wxEVT_LEFT_UP, &MainWindow::OnTimelineClicked,this);
m_volumeSlider->Bind(wxEVT_LEFT_UP, &MainWindow::OnVolumeClicked,this);
// Bind the events that will be thrown from VLC callbacks.
Bind(vlcEVT_POS, &MainWindow::OnPositionChanged, this);
Bind(vlcEVT_END, &MainWindow::OnEndReached, this);
// Set up the VLC objects.
m_vlc = VLC::Instance(0, nullptr);
m_player = VLC::MediaPlayer(m_vlc);
#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.
m_playerWidget->Bind(wxEVT_CREATE, &MainWindow::OnRendererWinCreated, this);
#elif defined(__WXMSW__)
m_player.setHwnd(m_playerWidget->GetHandle());
#endif
// Get the player's event manager and register to callbacks.
VLC::MediaPlayerEventManager& eventManager = m_player.eventManager();
eventManager.onPositionChanged(OnPositionChanged_VLC);
eventManager.onEndReached(OnEndReached_VLC);
// Set this frame to a global variable so that it can be used with the
// VLC callbacks.
gs_handler = this;
}
void MainWindow::OnRendererWinCreated(wxWindowCreateEvent& event)
{
#ifdef __WXGTK__
m_player.setXwindow(gdk_x11_window_get_xid(gtk_widget_get_window(m_playerWidget->GetHandle())));
m_playerWidget->Unbind(wxEVT_CREATE,&MainWindow::OnRendererWinCreated,this);
#endif
}
void MainWindow::OnPositionChanged(wxThreadEvent& event)
{
float factor = event.GetPayload<float>();
SetTimeline(factor);
}
void MainWindow::OnEndReached(wxThreadEvent& event)
{
Stop();
}
void MainWindow::OnOpen(wxCommandEvent& event)
{
wxFileDialog openFileDialog(this, "Choose File");
if (openFileDialog.ShowModal() == wxID_CANCEL)
{
return;
}
else
{
wxFileName filename = wxFileName::FileName(openFileDialog.GetPath());
filename.MakeRelativeTo();
std::string s2(filename.GetFullPath().utf8_str());
VLC::Media media(m_vlc, s2, VLC::Media::FromPath);
m_player.setMedia(media);
Play();
}
}
void MainWindow::OnPlayPause(wxCommandEvent& event)
{
if ( m_player.isPlaying () )
{
Pause();
}
else
{
Play();
}
}
void MainWindow::OnStop(wxCommandEvent& event)
{
Stop();
}
void MainWindow::OnPositionChanged_USR(wxCommandEvent& event)
{
m_player.setPosition((float) event.GetInt() / (float) TIMELINE_MAX);
}
void MainWindow::OnVolumeChanged(wxCommandEvent& event)
{
m_player.setVolume(m_volumeSlider->GetValue());
}
void MainWindow::OnVolumeClicked(wxMouseEvent& event)
{
wxSize size = m_volumeSlider->GetSize();
float position = (float) event.GetX() / (float) size.GetWidth();
int volume = static_cast<int>(position*VOLUME_MAX);
m_volumeSlider->SetValue(volume);
m_player.setVolume(volume);
event.Skip();
}
void MainWindow::OnTimelineClicked(wxMouseEvent& event)
{
wxSize size = m_timeline->GetSize();
float position = (float) event.GetX() / (float) size.GetWidth();
m_player.setPosition(position);
SetTimeline(position);
event.Skip();
}
void MainWindow::Play()
{;
m_player.play();
m_playPauseButton->SetLabel("Pause");
m_playPauseButton->Enable(true);
m_stopButton->Enable(true);
m_timeline->Enable(true);
}
void MainWindow::Pause()
{
m_player.pause();
m_playPauseButton->SetLabel("Play");
}
void MainWindow::Stop()
{
Pause();
#if LIBVLC_VERSION_INT >= LIBVLC_VERSION(4, 0, 0, 0)
m_player.stopAsync();
#else
m_player.stop();
#endif
m_stopButton->Enable(false);
SetTimeline(0.0);
m_timeline->Enable(false);
}
void MainWindow::SetTimeline(float value) {
if ( value < 0.0 )
{
value = 0.0;
}
if ( value > 1.0 )
{
value = 1.0;
}
UnbindTimeline();
m_timeline->SetValue((int) (value * TIMELINE_MAX));
BindTimeline();
}
void MainWindow::BindTimeline()
{
m_timeline->Bind(wxEVT_SLIDER, &MainWindow::OnPositionChanged_USR, this);
}
void MainWindow::UnbindTimeline()
{
m_timeline->Unbind(wxEVT_SLIDER, &MainWindow::OnPositionChanged_USR, this);
}
class MyApp : public wxApp {
public:
virtual bool OnInit();
};
bool MyApp::OnInit() {
MainWindow* mainWindow = new MainWindow("wxWidgets libVLC demo");
mainWindow->Show();
return true;
}
wxIMPLEMENT_APP(MyApp);
wxGTK3 在 linux mint 上看起来像这样:
我从来没有用过vlcpp,所以我不是这里的专家。但它不允许您将数据对象传递给回调。有了 libvlc 的 c 接口,你可以使用这个数据对象传递一个 wxWidgets 事件处理程序,然后在回调中使用那个事件处理程序将 vlc 事件传递给 wxWidgets。由于 vlcpp 不允许您传递数据对象,我不得不为 wxWidgets 事件处理程序使用一个丑陋的全局变量。
除非我遗漏了什么并且有一种方法可以为 vlc 回调传递数据对象,否则这看起来像是 vlcpp 中的一个真正的主要缺陷 api。