mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-10 10:47:16 +00:00
NEW: reimpl wxMediaCtrl from ffmpeg
Jira: none Change-Id: I46a47118a7649b2a50fcce8911e2888342ef25de (cherry picked from commit d6c7f08769c8cfdbbf0e80ad280c9b3408a3c27d) (cherry picked from commit 94d91be60bfe9bbbcdd21f85b46abc3faf126f17)
This commit is contained in:
267
src/slic3r/GUI/wxMediaCtrl3.cpp
Normal file
267
src/slic3r/GUI/wxMediaCtrl3.cpp
Normal file
@@ -0,0 +1,267 @@
|
||||
#include "wxMediaCtrl3.h"
|
||||
#include "AVVideoDecoder.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#ifdef __WIN32__
|
||||
#include <versionhelpers.h>
|
||||
#include <wx/msw/registry.h>
|
||||
#include <shellapi.h>
|
||||
#endif
|
||||
|
||||
//wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
|
||||
|
||||
BEGIN_EVENT_TABLE(wxMediaCtrl3, wxWindow)
|
||||
|
||||
// catch paint events
|
||||
EVT_PAINT(wxMediaCtrl3::paintEvent)
|
||||
|
||||
END_EVENT_TABLE()
|
||||
|
||||
struct StaticBambuLib : BambuLib
|
||||
{
|
||||
static StaticBambuLib &get();
|
||||
};
|
||||
|
||||
wxMediaCtrl3::wxMediaCtrl3(wxWindow *parent)
|
||||
: wxWindow(parent, wxID_ANY)
|
||||
, BambuLib(StaticBambuLib::get())
|
||||
, m_thread([this] { PlayThread(); })
|
||||
{
|
||||
SetBackgroundColour(*wxBLACK);
|
||||
}
|
||||
|
||||
wxMediaCtrl3::~wxMediaCtrl3()
|
||||
{
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
m_url.reset(new wxURI);
|
||||
m_frame = wxImage(m_idle_image);
|
||||
m_cond.notify_all();
|
||||
}
|
||||
m_thread.join();
|
||||
}
|
||||
|
||||
void wxMediaCtrl3::Load(wxURI url)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
m_video_size = wxDefaultSize;
|
||||
m_error = 0;
|
||||
m_url.reset(new wxURI(url));
|
||||
m_cond.notify_all();
|
||||
}
|
||||
|
||||
void wxMediaCtrl3::Play()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
if (m_state != wxMEDIASTATE_PLAYING) {
|
||||
m_state = wxMEDIASTATE_PLAYING;
|
||||
wxMediaEvent event(wxEVT_MEDIA_STATECHANGED);
|
||||
event.SetId(GetId());
|
||||
event.SetEventObject(this);
|
||||
wxPostEvent(this, event);
|
||||
}
|
||||
}
|
||||
|
||||
void wxMediaCtrl3::Stop()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
m_url.reset();
|
||||
m_frame = wxImage(m_idle_image);
|
||||
m_cond.notify_all();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
void wxMediaCtrl3::SetIdleImage(wxString const &image)
|
||||
{
|
||||
if (m_idle_image == image)
|
||||
return;
|
||||
m_idle_image = image;
|
||||
if (m_url == nullptr) {
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
m_frame = wxImage(m_idle_image);
|
||||
assert(m_frame.IsOk());
|
||||
Refresh();
|
||||
}
|
||||
}
|
||||
|
||||
wxMediaState wxMediaCtrl3::GetState()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
return m_state;
|
||||
}
|
||||
|
||||
int wxMediaCtrl3::GetLastError()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
return m_error;
|
||||
}
|
||||
|
||||
wxSize wxMediaCtrl3::GetVideoSize()
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
return m_video_size;
|
||||
}
|
||||
|
||||
wxSize wxMediaCtrl3::DoGetBestSize() const
|
||||
{
|
||||
return {-1, -1};
|
||||
}
|
||||
|
||||
static void adjust_frame_size(wxSize & frame, wxSize const & video, wxSize const & window)
|
||||
{
|
||||
if (video.x * window.y < video.y * window.x)
|
||||
frame = { video.x * window.y / video.y, window.y };
|
||||
else
|
||||
frame = { window.x, video.y * window.x / video.x };
|
||||
}
|
||||
|
||||
void wxMediaCtrl3::paintEvent(wxPaintEvent &evt)
|
||||
{
|
||||
wxPaintDC dc(this);
|
||||
auto size = GetSize();
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
if (!m_frame.IsOk())
|
||||
return;
|
||||
auto size2 = m_frame.GetSize();
|
||||
if (size2.x != m_frame_size.x && size2.y == m_frame_size.y)
|
||||
size2.x = m_frame_size.x;
|
||||
if (size2.x != size.x && size2.y != size.y) {
|
||||
auto scale = std::min(double(size.x) / size2.x, double(size.y) / size2.y);
|
||||
dc.SetUserScale(scale, scale);
|
||||
adjust_frame_size(size2, size2, size);
|
||||
}
|
||||
size2 = (size - size2) / 2;
|
||||
dc.DrawBitmap(m_frame, size2.x, size2.y);
|
||||
}
|
||||
|
||||
void wxMediaCtrl3::DoSetSize(int x, int y, int width, int height, int sizeFlags)
|
||||
{
|
||||
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
|
||||
if (sizeFlags & wxSIZE_USE_EXISTING) return;
|
||||
wxMediaCtrl_OnSize(this, m_video_size, width, height);
|
||||
}
|
||||
|
||||
void wxMediaCtrl3::bambu_log(void *ctx, int level, tchar const *msg2)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
wxString msg(msg2);
|
||||
#else
|
||||
wxString msg = wxString::FromUTF8(msg2);
|
||||
#endif
|
||||
if (level == 1) {
|
||||
if (msg.EndsWith("]")) {
|
||||
int n = msg.find_last_of('[');
|
||||
if (n != wxString::npos) {
|
||||
long val = 0;
|
||||
wxMediaCtrl3 *ctrl = (wxMediaCtrl3 *) ctx;
|
||||
if (msg.SubString(n + 1, msg.Length() - 2).ToLong(&val)) {
|
||||
std::unique_lock<std::mutex> lk(ctrl->m_mutex);
|
||||
ctrl->m_error = (int) val;
|
||||
}
|
||||
}
|
||||
} else if (msg.Contains("stat_log")) {
|
||||
wxCommandEvent evt(EVT_MEDIA_CTRL_STAT);
|
||||
wxMediaCtrl3 *ctrl = (wxMediaCtrl3 *) ctx;
|
||||
evt.SetEventObject(ctrl);
|
||||
evt.SetString(msg.Mid(msg.Find(' ') + 1));
|
||||
wxPostEvent(ctrl, evt);
|
||||
}
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << msg.ToUTF8().data();
|
||||
}
|
||||
|
||||
void wxMediaCtrl3::PlayThread()
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
std::shared_ptr<wxURI> url;
|
||||
std::unique_lock<std::mutex> lk(m_mutex);
|
||||
while (true) {
|
||||
m_cond.wait(lk, [this, &url] { return m_url != url; });
|
||||
url = m_url;
|
||||
if (url == nullptr)
|
||||
continue;
|
||||
if (!url->HasScheme())
|
||||
break;
|
||||
lk.unlock();
|
||||
Bambu_Tunnel tunnel = nullptr;
|
||||
int error = Bambu_Create(&tunnel, m_url->BuildURI().ToUTF8());
|
||||
if (error == 0) {
|
||||
Bambu_SetLogger(tunnel, &wxMediaCtrl3::bambu_log, this);
|
||||
error = Bambu_Open(tunnel);
|
||||
if (error == 0)
|
||||
error = Bambu_would_block;
|
||||
}
|
||||
lk.lock();
|
||||
while (error == int(Bambu_would_block)) {
|
||||
m_cond.wait_for(lk, 100ms);
|
||||
if (m_url != url) {
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
lk.unlock();
|
||||
error = Bambu_StartStream(tunnel, true);
|
||||
lk.lock();
|
||||
}
|
||||
Bambu_StreamInfo info;
|
||||
if (error == 0)
|
||||
error = Bambu_GetStreamInfo(tunnel, 0, &info);
|
||||
AVVideoDecoder decoder;
|
||||
if (error == 0) {
|
||||
decoder.open(info);
|
||||
m_video_size = { info.format.video.width, info.format.video.height };
|
||||
adjust_frame_size(m_frame_size, m_video_size, GetSize());
|
||||
NotifyStopped();
|
||||
}
|
||||
Bambu_Sample sample;
|
||||
while (error == 0) {
|
||||
lk.unlock();
|
||||
error = Bambu_ReadSample(tunnel, &sample);
|
||||
lk.lock();
|
||||
while (error == int(Bambu_would_block)) {
|
||||
m_cond.wait_for(lk, 100ms);
|
||||
if (m_url != url) {
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
lk.unlock();
|
||||
error = Bambu_ReadSample(tunnel, &sample);
|
||||
lk.lock();
|
||||
}
|
||||
if (error == 0) {
|
||||
if (m_url != url) {
|
||||
error = 1;
|
||||
break;
|
||||
}
|
||||
lk.unlock();
|
||||
wxBitmap bm;
|
||||
decoder.decode(sample);
|
||||
decoder.toWxBitmap(bm, m_frame_size);
|
||||
lk.lock();
|
||||
if (bm.IsOk())
|
||||
m_frame = bm;
|
||||
CallAfter([this] { Refresh(); });
|
||||
}
|
||||
}
|
||||
if (tunnel) {
|
||||
lk.unlock();
|
||||
Bambu_Close(tunnel);
|
||||
Bambu_Destroy(tunnel);
|
||||
tunnel = nullptr;
|
||||
lk.lock();
|
||||
}
|
||||
if (m_url == url)
|
||||
m_error = error;
|
||||
m_video_size = wxDefaultSize;
|
||||
NotifyStopped();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void wxMediaCtrl3::NotifyStopped()
|
||||
{
|
||||
m_state = wxMEDIASTATE_STOPPED;
|
||||
wxMediaEvent event(wxEVT_MEDIA_STATECHANGED);
|
||||
event.SetId(GetId());
|
||||
event.SetEventObject(this);
|
||||
wxPostEvent(this, event);
|
||||
}
|
||||
Reference in New Issue
Block a user