【问题标题】:How to embed libvlcpp into wx(v3) panel/frame如何将 libvlcpp 嵌入到 wx(v3) 面板/框架中
【发布时间】:2021-03-31 00:27:45
【问题描述】:

我想使用 wx(版本 3 及更高版本)和 libvlcpp 制作简单的跨平台播放器,但我不知道如何将 libvlcpp 窗口绑定到 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```

【问题讨论】:

    标签: c++ wxwidgets libvlc


    【解决方案1】:

    这是使用 vlcpp 绘制到 wxWidgets 窗口的完整示例(至少对于 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);
    
    

    在 linux mint 上使用 wxGTK3,它看起来像这样:

    我从来没有使用过 vlcpp,所以我不是这里的专家。但它不允许您将数据对象传递给回调。使用 libvlc 的 c 接口,您可以使用此数据对象传递 wxWidgets 事件处理程序,然后在回调中使用该事件处理程序将 vlc 事件传递给 wxWidgets。由于 vlcpp 不允许您传递数据对象,因此我不得不为 wxWidgets 事件处理程序使用一个丑陋的全局变量。

    除非我遗漏了一些东西并且有一种方法可以为 vlc 回调传递数据对象,否则这看起来像是 vlcpp api 中的一个真正重大缺陷。

    【讨论】:

    • 感谢您的努力和帮助,m_player.setHwnd(playerWidget-&gt;GetHandle()); 部分在 linux 中有点不同我正在尝试知道如何使它成为 wx 中窗口的一部分,目前它忽略此代码或错误,(它似乎可以在 Windows 上运行)但在 linux 中我必须处理 gtk/gdk 和一些 X11 工作
    • 在 GTK 上,您需要调用 setXwindow 而不是 setHwnd。但是还有一个额外的复杂性,您需要等到完全创建窗口。我编辑了示例以展示如何等待窗口创建事件并展示如何从 wxWindow 获取 XID。该示例适用于 wxGTK3。我认为 wxGTK2 可能会有所不同,但我不记得需要更改什么。
    • 我用g++ wxvlc.cpp `wx-config --cxxflags --libs` `pkg-config --cflags --libs gtk+-3.0` -lvlc -I/home/user/projects/Player/Source/include -o foobar 编译它非常好,谢谢。
    猜你喜欢
    • 1970-01-01
    • 2021-10-08
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 2012-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多