mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-09 18:27:00 +00:00
refactor: remove dead wxMediaCtrl2 player
wxMediaCtrl2 was never instantiated on any platform (USE_WX_MEDIA_CTRL_2 is 0 everywhere); wxMediaCtrl3 replaced it. Delete wxMediaCtrl2.cpp/h, drop them from the Win/Linux source list and the gettext list.txt, and collapse the preprocessor-dead #if USE_WX_MEDIA_CTRL_2 gate in MediaPlayCtrl.h. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -193,7 +193,6 @@ src/slic3r/GUI/ObjColorDialog.cpp
|
|||||||
src/slic3r/GUI/SyncAmsInfoDialog.cpp
|
src/slic3r/GUI/SyncAmsInfoDialog.cpp
|
||||||
src/slic3r/GUI/WipeTowerDialog.cpp
|
src/slic3r/GUI/WipeTowerDialog.cpp
|
||||||
src/slic3r/GUI/wxExtensions.cpp
|
src/slic3r/GUI/wxExtensions.cpp
|
||||||
src/slic3r/GUI/wxMediaCtrl2.cpp
|
|
||||||
src/slic3r/GUI/WebUserLoginDialog.cpp
|
src/slic3r/GUI/WebUserLoginDialog.cpp
|
||||||
src/slic3r/GUI/WebGuideDialog.cpp
|
src/slic3r/GUI/WebGuideDialog.cpp
|
||||||
src/slic3r/GUI/KBShortcutsDialog.hpp
|
src/slic3r/GUI/KBShortcutsDialog.hpp
|
||||||
|
|||||||
@@ -794,8 +794,6 @@ else ()
|
|||||||
list(APPEND SLIC3R_GUI_SOURCES
|
list(APPEND SLIC3R_GUI_SOURCES
|
||||||
GUI/AVVideoDecoder.cpp
|
GUI/AVVideoDecoder.cpp
|
||||||
GUI/AVVideoDecoder.hpp
|
GUI/AVVideoDecoder.hpp
|
||||||
GUI/wxMediaCtrl2.cpp
|
|
||||||
GUI/wxMediaCtrl2.h
|
|
||||||
GUI/wxMediaCtrl3.cpp
|
GUI/wxMediaCtrl3.cpp
|
||||||
GUI/wxMediaCtrl3.h
|
GUI/wxMediaCtrl3.h
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -8,14 +8,7 @@
|
|||||||
#ifndef MediaPlayCtrl_h
|
#ifndef MediaPlayCtrl_h
|
||||||
#define MediaPlayCtrl_h
|
#define MediaPlayCtrl_h
|
||||||
|
|
||||||
#define USE_WX_MEDIA_CTRL_2 0
|
|
||||||
|
|
||||||
#if USE_WX_MEDIA_CTRL_2
|
|
||||||
#include "wxMediaCtrl2.h"
|
|
||||||
#define wxMediaCtrl3 wxMediaCtrl2
|
|
||||||
#else
|
|
||||||
#include "wxMediaCtrl3.h"
|
#include "wxMediaCtrl3.h"
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <wx/panel.h>
|
#include <wx/panel.h>
|
||||||
|
|
||||||
|
|||||||
@@ -1,649 +0,0 @@
|
|||||||
#include "wxMediaCtrl2.h"
|
|
||||||
#include "libslic3r/Time.hpp"
|
|
||||||
#include "I18N.hpp"
|
|
||||||
#include "GUI_App.hpp"
|
|
||||||
#include "libslic3r/Utils.hpp"
|
|
||||||
#include <wx/log.h>
|
|
||||||
#include <wx/msgdlg.h>
|
|
||||||
#include "LinuxDisplayBackend.hpp"
|
|
||||||
#include <boost/filesystem/operations.hpp>
|
|
||||||
#include <string>
|
|
||||||
#ifdef __WIN32__
|
|
||||||
#include <winuser.h>
|
|
||||||
#include <versionhelpers.h>
|
|
||||||
#include <wx/msw/registry.h>
|
|
||||||
#include <shellapi.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __LINUX__
|
|
||||||
#include "Printer/gstbambusrc.h"
|
|
||||||
#include <gst/gst.h> // main gstreamer header
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(__LINUX__) && defined(__WXGTK__)
|
|
||||||
#include <gtk/gtk.h>
|
|
||||||
#include <wx/nativewin.h>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
bool ensure_gstreamer_initialized_for_liveview()
|
|
||||||
{
|
|
||||||
GError* error = nullptr;
|
|
||||||
if (!gst_init_check(nullptr, nullptr, &error)) {
|
|
||||||
BOOST_LOG_TRIVIAL(error) << "wxMediaCtrl2: gst_init_check failed before native Wayland liveview setup"
|
|
||||||
<< (error ? std::string(": ") + error->message : std::string());
|
|
||||||
if (error)
|
|
||||||
g_error_free(error);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_gstreamer_feature_available(const char* feature)
|
|
||||||
{
|
|
||||||
if (!ensure_gstreamer_initialized_for_liveview())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
GstElementFactory* factory = gst_element_factory_find(feature);
|
|
||||||
if (!factory)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
gst_object_unref(factory);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void set_gstreamer_feature_rank(const char* feature, guint rank)
|
|
||||||
{
|
|
||||||
GstElementFactory* factory = gst_element_factory_find(feature);
|
|
||||||
if (!factory)
|
|
||||||
return;
|
|
||||||
|
|
||||||
gst_plugin_feature_set_rank(GST_PLUGIN_FEATURE(factory), rank);
|
|
||||||
gst_object_unref(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
void configure_wayland_gstreamer_liveview_path()
|
|
||||||
{
|
|
||||||
static bool configured = false;
|
|
||||||
if (configured)
|
|
||||||
return;
|
|
||||||
configured = true;
|
|
||||||
|
|
||||||
if (!ensure_gstreamer_initialized_for_liveview())
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Prefer software decode for Bambu liveview on Wayland/NVIDIA, where
|
|
||||||
// zero-copy GL/DMABUF display paths can be fragile. Keep hardware
|
|
||||||
// decoders available as lower-ranked fallbacks for VAAPI/NVDEC/V4L2-only
|
|
||||||
// installations instead of passing preflight and then blocking autoplug.
|
|
||||||
set_gstreamer_feature_rank("avdec_h264", GST_RANK_PRIMARY + 300);
|
|
||||||
set_gstreamer_feature_rank("openh264dec", GST_RANK_PRIMARY + 100);
|
|
||||||
set_gstreamer_feature_rank("nvh264dec", GST_RANK_MARGINAL);
|
|
||||||
set_gstreamer_feature_rank("vaapih264dec", GST_RANK_MARGINAL);
|
|
||||||
set_gstreamer_feature_rank("vah264dec", GST_RANK_MARGINAL);
|
|
||||||
set_gstreamer_feature_rank("v4l2h264dec", GST_RANK_MARGINAL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // defined(__LINUX__) && defined(__WXGTK__)
|
|
||||||
|
|
||||||
#ifdef __LINUX__
|
|
||||||
extern "C" int gst_bambu_last_error;
|
|
||||||
|
|
||||||
class WXDLLIMPEXP_MEDIA
|
|
||||||
wxGStreamerMediaBackend : public wxMediaBackendCommonBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
GstElement *m_playbin; // GStreamer media element
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wxMediaCtrl2::wxMediaCtrl2(wxWindow *parent)
|
|
||||||
{
|
|
||||||
#if defined(__LINUX__) && defined(__WXGTK__)
|
|
||||||
m_native_wayland = Slic3r::GUI::is_running_on_wayland();
|
|
||||||
if (m_native_wayland && is_gstreamer_feature_available("gtksink"))
|
|
||||||
configure_wayland_gstreamer_liveview_path();
|
|
||||||
else if (m_native_wayland) {
|
|
||||||
m_gtk_sink_error = _L("Native Wayland liveview requires the GStreamer GTK video sink. Please install the gtksink plugin for GStreamer, then restart OrcaSlicer.");
|
|
||||||
BOOST_LOG_TRIVIAL(warning) << "wxMediaCtrl2: native Wayland liveview disabled because GStreamer gtksink is unavailable";
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef __WIN32__
|
|
||||||
auto hModExe = GetModuleHandle(NULL);
|
|
||||||
// BOOST_LOG_TRIVIAL(info) << "wxMediaCtrl2: GetModuleHandle " << hModExe;
|
|
||||||
auto NvOptimusEnablement = (DWORD *) GetProcAddress(hModExe, "NvOptimusEnablement");
|
|
||||||
auto AmdPowerXpressRequestHighPerformance = (int *) GetProcAddress(hModExe, "AmdPowerXpressRequestHighPerformance");
|
|
||||||
if (NvOptimusEnablement) {
|
|
||||||
// BOOST_LOG_TRIVIAL(info) << "wxMediaCtrl2: NvOptimusEnablement " << *NvOptimusEnablement;
|
|
||||||
*NvOptimusEnablement = 0;
|
|
||||||
}
|
|
||||||
if (AmdPowerXpressRequestHighPerformance) {
|
|
||||||
// BOOST_LOG_TRIVIAL(info) << "wxMediaCtrl2: AmdPowerXpressRequestHighPerformance " << *AmdPowerXpressRequestHighPerformance;
|
|
||||||
*AmdPowerXpressRequestHighPerformance = 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#if defined(__LINUX__) && defined(__WXGTK__)
|
|
||||||
if (m_native_wayland)
|
|
||||||
wxControl::Create(parent, wxID_ANY, wxDefaultPosition, wxDefaultSize);
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
wxMediaCtrl::Create(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxMEDIACTRLPLAYERCONTROLS_NONE);
|
|
||||||
#ifdef __LINUX__
|
|
||||||
gstbambusrc_register();
|
|
||||||
#ifdef __WXGTK__
|
|
||||||
if (m_native_wayland && m_gtk_sink_error.empty())
|
|
||||||
m_use_gtk_sink = CreateGtkSinkPlayer();
|
|
||||||
if (m_native_wayland && !m_use_gtk_sink && m_gtk_sink_error.empty())
|
|
||||||
m_gtk_sink_error = _L("Failed to initialize the native Wayland GStreamer video sink. Please check your GStreamer GTK plugin installation.");
|
|
||||||
#endif
|
|
||||||
if (!m_use_gtk_sink && m_imp) {
|
|
||||||
auto playbin = reinterpret_cast<wxGStreamerMediaBackend *>(m_imp)->m_playbin;
|
|
||||||
g_object_set(G_OBJECT(playbin),
|
|
||||||
"audio-sink", nullptr,
|
|
||||||
nullptr);
|
|
||||||
} else if (!m_use_gtk_sink) {
|
|
||||||
BOOST_LOG_TRIVIAL(warning) << "wxMediaCtrl2: wxMediaCtrl backend is unavailable";
|
|
||||||
}
|
|
||||||
Bind(wxEVT_MEDIA_LOADED, [this](auto & e) {
|
|
||||||
m_loaded = true;
|
|
||||||
wxMediaEvent event(wxEVT_MEDIA_STATECHANGED);
|
|
||||||
event.SetId(0);
|
|
||||||
event.SetEventObject(this);
|
|
||||||
wxPostEvent(this, event);
|
|
||||||
});
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
wxMediaCtrl2::~wxMediaCtrl2()
|
|
||||||
{
|
|
||||||
#if defined(__LINUX__) && defined(__WXGTK__)
|
|
||||||
DestroyGtkSinkPlayer();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(__LINUX__) && defined(__WXGTK__)
|
|
||||||
bool wxMediaCtrl2::CreateGtkSinkPlayer()
|
|
||||||
{
|
|
||||||
GstElement *playbin = gst_element_factory_make("playbin", "orca-wayland-gtk-playbin");
|
|
||||||
if (!playbin)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
GError *error = nullptr;
|
|
||||||
GstElement *video_sink = gst_parse_bin_from_description(
|
|
||||||
"videoconvert ! videoscale ! video/x-raw,format=BGRx ! gtksink name=orca_wayland_gtksink sync=false",
|
|
||||||
TRUE,
|
|
||||||
&error);
|
|
||||||
if (!video_sink) {
|
|
||||||
BOOST_LOG_TRIVIAL(warning) << "wxMediaCtrl2: failed to create gtksink video bin"
|
|
||||||
<< (error ? std::string(": ") + error->message : std::string());
|
|
||||||
if (error)
|
|
||||||
g_error_free(error);
|
|
||||||
gst_object_unref(playbin);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GstElement *gtk_sink = gst_bin_get_by_name(GST_BIN(video_sink), "orca_wayland_gtksink");
|
|
||||||
if (!gtk_sink) {
|
|
||||||
BOOST_LOG_TRIVIAL(warning) << "wxMediaCtrl2: failed to find gtksink in video bin";
|
|
||||||
gst_object_unref(video_sink);
|
|
||||||
gst_object_unref(playbin);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
GtkWidget *gtk_widget = nullptr;
|
|
||||||
g_object_get(G_OBJECT(gtk_sink), "widget", >k_widget, nullptr);
|
|
||||||
if (!gtk_widget) {
|
|
||||||
BOOST_LOG_TRIVIAL(warning) << "wxMediaCtrl2: gtksink did not expose a GtkWidget";
|
|
||||||
gst_object_unref(gtk_sink);
|
|
||||||
gst_object_unref(video_sink);
|
|
||||||
gst_object_unref(playbin);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
gtk_widget_show(gtk_widget);
|
|
||||||
m_gtk_video_window = new wxNativeWindow(this, wxID_ANY, gtk_widget);
|
|
||||||
m_gtk_video_window->Show();
|
|
||||||
g_object_unref(gtk_widget);
|
|
||||||
|
|
||||||
g_object_set(G_OBJECT(playbin),
|
|
||||||
"video-sink", video_sink,
|
|
||||||
"audio-sink", nullptr,
|
|
||||||
nullptr);
|
|
||||||
gst_object_unref(video_sink);
|
|
||||||
|
|
||||||
m_gtk_playbin = playbin;
|
|
||||||
m_gtk_sink = gtk_sink;
|
|
||||||
|
|
||||||
GstBus *bus = gst_element_get_bus(playbin);
|
|
||||||
m_gtk_bus_watch_id = gst_bus_add_watch(bus, [](GstBus *, GstMessage *message, gpointer data) -> gboolean {
|
|
||||||
auto *self = static_cast<wxMediaCtrl2 *>(data);
|
|
||||||
if (!self || !self->m_gtk_playbin)
|
|
||||||
return G_SOURCE_REMOVE;
|
|
||||||
|
|
||||||
switch (GST_MESSAGE_TYPE(message)) {
|
|
||||||
case GST_MESSAGE_ERROR:
|
|
||||||
{
|
|
||||||
GError *error = nullptr;
|
|
||||||
gchar *debug = nullptr;
|
|
||||||
gst_message_parse_error(message, &error, &debug);
|
|
||||||
BOOST_LOG_TRIVIAL(warning) << "wxMediaCtrl2: gtksink pipeline error"
|
|
||||||
<< (error ? std::string(": ") + error->message : std::string())
|
|
||||||
<< (debug ? std::string(" debug: ") + debug : std::string());
|
|
||||||
if (error)
|
|
||||||
g_error_free(error);
|
|
||||||
if (debug)
|
|
||||||
g_free(debug);
|
|
||||||
|
|
||||||
self->m_error = gst_bambu_last_error ? gst_bambu_last_error : 2;
|
|
||||||
self->m_loaded = false;
|
|
||||||
self->m_gtk_state = wxMEDIASTATE_STOPPED;
|
|
||||||
self->PostGtkSinkStateEvent(self->GetId());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case GST_MESSAGE_EOS:
|
|
||||||
self->m_loaded = false;
|
|
||||||
self->m_gtk_state = wxMEDIASTATE_STOPPED;
|
|
||||||
self->PostGtkSinkStateEvent(self->GetId());
|
|
||||||
break;
|
|
||||||
case GST_MESSAGE_STATE_CHANGED:
|
|
||||||
if (GST_MESSAGE_SRC(message) == GST_OBJECT(self->m_gtk_playbin)) {
|
|
||||||
GstState old_state;
|
|
||||||
GstState new_state;
|
|
||||||
GstState pending_state;
|
|
||||||
gst_message_parse_state_changed(message, &old_state, &new_state, &pending_state);
|
|
||||||
|
|
||||||
if (new_state == GST_STATE_PLAYING) {
|
|
||||||
self->m_loaded = true;
|
|
||||||
self->m_gtk_state = wxMEDIASTATE_PLAYING;
|
|
||||||
self->PostGtkSinkStateEvent();
|
|
||||||
} else if (new_state == GST_STATE_PAUSED && old_state < GST_STATE_PAUSED) {
|
|
||||||
// Treat only upward READY/NULL -> PAUSED as load completion.
|
|
||||||
// PLAYING -> PAUSED is a normal teardown step before NULL.
|
|
||||||
self->m_loaded = true;
|
|
||||||
self->m_gtk_state = wxMEDIASTATE_PAUSED;
|
|
||||||
self->PostGtkSinkStateEvent();
|
|
||||||
} else if (new_state <= GST_STATE_READY && old_state >= GST_STATE_PAUSED) {
|
|
||||||
self->m_loaded = false;
|
|
||||||
self->m_gtk_state = wxMEDIASTATE_STOPPED;
|
|
||||||
self->PostGtkSinkStateEvent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return G_SOURCE_CONTINUE;
|
|
||||||
}, this);
|
|
||||||
gst_object_unref(bus);
|
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(info) << "wxMediaCtrl2: using GTK native Wayland video sink";
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void wxMediaCtrl2::DestroyGtkSinkPlayer()
|
|
||||||
{
|
|
||||||
if (m_gtk_bus_watch_id) {
|
|
||||||
g_source_remove(m_gtk_bus_watch_id);
|
|
||||||
m_gtk_bus_watch_id = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_gtk_playbin) {
|
|
||||||
gst_element_set_state(m_gtk_playbin, GST_STATE_NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_gtk_video_window) {
|
|
||||||
m_gtk_video_window->Destroy();
|
|
||||||
m_gtk_video_window = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_gtk_playbin) {
|
|
||||||
gst_object_unref(m_gtk_playbin);
|
|
||||||
m_gtk_playbin = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_gtk_sink) {
|
|
||||||
gst_object_unref(m_gtk_sink);
|
|
||||||
m_gtk_sink = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void wxMediaCtrl2::PostGtkSinkStateEvent(int id)
|
|
||||||
{
|
|
||||||
wxMediaEvent event(wxEVT_MEDIA_STATECHANGED);
|
|
||||||
event.SetId(id);
|
|
||||||
event.SetEventObject(this);
|
|
||||||
wxPostEvent(this, event);
|
|
||||||
}
|
|
||||||
#endif // defined(__LINUX__) && defined(__WXGTK__)
|
|
||||||
|
|
||||||
#define CLSID_BAMBU_SOURCE L"{233E64FB-2041-4A6C-AFAB-FF9BCF83E7AA}"
|
|
||||||
|
|
||||||
void wxMediaCtrl2::Load(wxURI url)
|
|
||||||
{
|
|
||||||
#ifdef __WIN32__
|
|
||||||
InvalidateBestSize();
|
|
||||||
if (m_imp == nullptr) {
|
|
||||||
static bool notified = false;
|
|
||||||
if (!notified) CallAfter([] {
|
|
||||||
auto res = wxMessageBox(_L("Windows Media Player is required for this task! Do you want to enable 'Windows Media Player' for your operation system?"), _L("Error"), wxOK | wxCANCEL);
|
|
||||||
if (res == wxOK) {
|
|
||||||
wxString url = IsWindows10OrGreater()
|
|
||||||
? "ms-settings:optionalfeatures?activationSource=SMC-Article-14209"
|
|
||||||
: "https://support.microsoft.com/en-au/windows/get-windows-media-player-81718e0d-cfce-25b1-aee3-94596b658287";
|
|
||||||
wxExecute("cmd /c start " + url, wxEXEC_HIDE_CONSOLE);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
m_error = 100;
|
|
||||||
wxMediaEvent event(wxEVT_MEDIA_STATECHANGED);
|
|
||||||
event.SetId(GetId());
|
|
||||||
event.SetEventObject(this);
|
|
||||||
wxPostEvent(this, event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
wxRegKey key11(wxRegKey::HKCU, L"SOFTWARE\\Classes\\CLSID\\" CLSID_BAMBU_SOURCE L"\\InProcServer32");
|
|
||||||
wxRegKey key12(wxRegKey::HKCR, L"CLSID\\" CLSID_BAMBU_SOURCE L"\\InProcServer32");
|
|
||||||
wxString path = key11.Exists() ? key11.QueryDefaultValue()
|
|
||||||
: key12.Exists() ? key12.QueryDefaultValue() : wxString{};
|
|
||||||
wxRegKey key2(wxRegKey::HKCR, "bambu");
|
|
||||||
wxString clsid;
|
|
||||||
if (key2.Exists())
|
|
||||||
key2.QueryRawValue("Source Filter", clsid);
|
|
||||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(": clsid %1% path %2%") % clsid % path;
|
|
||||||
|
|
||||||
std::string data_dir_str = Slic3r::data_dir();
|
|
||||||
boost::filesystem::path data_dir_path(data_dir_str);
|
|
||||||
auto dll_path = data_dir_path / "plugins" / "BambuSource.dll";
|
|
||||||
if (path.empty() || !wxFile::Exists(path) || clsid != CLSID_BAMBU_SOURCE) {
|
|
||||||
if (boost::filesystem::exists(dll_path)) {
|
|
||||||
CallAfter(
|
|
||||||
[dll_path] {
|
|
||||||
int res = wxMessageBox(_L("BambuSource has not correctly been registered for media playing! Press Yes to re-register it. You will be promoted twice"), _L("Error"), wxYES_NO);
|
|
||||||
if (res == wxYES) {
|
|
||||||
std::string regContent = R"(Windows Registry Editor Version 5.00
|
|
||||||
[HKEY_CLASSES_ROOT\bambu]
|
|
||||||
"Source Filter"="{233E64FB-2041-4A6C-AFAB-FF9BCF83E7AA}"
|
|
||||||
)";
|
|
||||||
|
|
||||||
auto reg_path = (fs::temp_directory_path() / fs::unique_path()).replace_extension(".reg");
|
|
||||||
std::ofstream temp_reg_file(reg_path.c_str());
|
|
||||||
if (!temp_reg_file) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
temp_reg_file << regContent;
|
|
||||||
temp_reg_file.close();
|
|
||||||
auto sei_params = L"/q /s " + reg_path.wstring();
|
|
||||||
SHELLEXECUTEINFO sei{sizeof(sei), SEE_MASK_NOCLOSEPROCESS, NULL, L"open",
|
|
||||||
L"regedit", sei_params.c_str(),SW_HIDE,SW_HIDE};
|
|
||||||
::ShellExecuteEx(&sei);
|
|
||||||
|
|
||||||
wstring quoted_dll_path = L"\"" + dll_path.wstring() + L"\"";
|
|
||||||
SHELLEXECUTEINFO info{sizeof(info), 0, NULL, L"runas", L"regsvr32", quoted_dll_path.c_str(), SW_HIDE };
|
|
||||||
::ShellExecuteEx(&info);
|
|
||||||
fs::remove(reg_path);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
CallAfter([] {
|
|
||||||
wxMessageBox(_L("Missing BambuSource component registered for media playing! Please re-install OrcaSlicer or seek community help."), _L("Error"), wxOK);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
m_error = clsid != CLSID_BAMBU_SOURCE ? 101 : path.empty() ? 102 : 103;
|
|
||||||
wxMediaEvent event(wxEVT_MEDIA_STATECHANGED);
|
|
||||||
event.SetId(GetId());
|
|
||||||
event.SetEventObject(this);
|
|
||||||
wxPostEvent(this, event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (path != dll_path) {
|
|
||||||
static bool notified = false;
|
|
||||||
if (!notified) CallAfter([dll_path] {
|
|
||||||
int res = wxMessageBox(_L("Using a BambuSource from a different install, video play may not work correctly! Press Yes to fix it."), _L("Warning"), wxYES_NO | wxICON_WARNING);
|
|
||||||
if (res == wxYES) {
|
|
||||||
auto path = dll_path.wstring();
|
|
||||||
if (path.find(L' ') != std::wstring::npos)
|
|
||||||
path = L"\"" + path + L"\"";
|
|
||||||
SHELLEXECUTEINFO info{sizeof(info), 0, NULL, L"open", L"regsvr32", path.c_str(), SW_HIDE};
|
|
||||||
::ShellExecuteEx(&info);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
notified = true;
|
|
||||||
}
|
|
||||||
wxRegKey keyWmp(wxRegKey::HKCU, "SOFTWARE\\Microsoft\\MediaPlayer\\Player\\Extensions\\.");
|
|
||||||
keyWmp.Create();
|
|
||||||
long permissions = 0;
|
|
||||||
if (keyWmp.HasValue("Permissions"))
|
|
||||||
keyWmp.QueryValue("Permissions", &permissions);
|
|
||||||
if ((permissions & 32) == 0) {
|
|
||||||
permissions |= 32;
|
|
||||||
keyWmp.SetValue("Permissions", permissions);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
url = wxURI(url.BuildURI().append("&hwnd=").append(boost::lexical_cast<std::string>(GetHandle())).append("&tid=").append(
|
|
||||||
boost::lexical_cast<std::string>(GetCurrentThreadId())));
|
|
||||||
#endif
|
|
||||||
#ifdef __WXGTK3__
|
|
||||||
GstElementFactory *factory;
|
|
||||||
int hasplugins = 1;
|
|
||||||
|
|
||||||
factory = gst_element_factory_find("h264parse");
|
|
||||||
if (!factory) {
|
|
||||||
hasplugins = 0;
|
|
||||||
} else {
|
|
||||||
gst_object_unref(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
factory = gst_element_factory_find("openh264dec");
|
|
||||||
if (!factory) {
|
|
||||||
factory = gst_element_factory_find("avdec_h264");
|
|
||||||
}
|
|
||||||
if (!factory) {
|
|
||||||
factory = gst_element_factory_find("vaapih264dec");
|
|
||||||
}
|
|
||||||
if (!factory) {
|
|
||||||
factory = gst_element_factory_find("vah264dec");
|
|
||||||
}
|
|
||||||
if (!factory) {
|
|
||||||
factory = gst_element_factory_find("nvh264dec");
|
|
||||||
}
|
|
||||||
if (!factory) {
|
|
||||||
factory = gst_element_factory_find("v4l2h264dec");
|
|
||||||
}
|
|
||||||
if (!factory) {
|
|
||||||
hasplugins = 0;
|
|
||||||
} else {
|
|
||||||
gst_object_unref(factory);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasplugins) {
|
|
||||||
CallAfter([] {
|
|
||||||
wxMessageBox(_L("Your system is missing H.264 codecs for GStreamer, which are required to play video. (Try installing the gstreamer1.0-plugins-bad or gstreamer1.0-libav packages, then restart Orca Slicer?)"), _L("Error"), wxOK);
|
|
||||||
});
|
|
||||||
m_error = 101;
|
|
||||||
wxMediaEvent event(wxEVT_MEDIA_STATECHANGED);
|
|
||||||
event.SetId(GetId());
|
|
||||||
event.SetEventObject(this);
|
|
||||||
wxPostEvent(this, event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
wxLog::EnableLogging(false);
|
|
||||||
#endif
|
|
||||||
m_error = 0;
|
|
||||||
m_loaded = false;
|
|
||||||
#if defined(__LINUX__) && defined(__WXGTK__)
|
|
||||||
if (m_use_gtk_sink && m_gtk_playbin) {
|
|
||||||
const std::string uri = std::string(url.BuildURI().ToUTF8().data());
|
|
||||||
gst_element_set_state(m_gtk_playbin, GST_STATE_NULL);
|
|
||||||
g_object_set(G_OBJECT(m_gtk_playbin), "uri", uri.c_str(), nullptr);
|
|
||||||
m_gtk_state = wxMEDIASTATE_STOPPED;
|
|
||||||
GstStateChangeReturn state = gst_element_set_state(m_gtk_playbin, GST_STATE_PAUSED);
|
|
||||||
if (state == GST_STATE_CHANGE_FAILURE) {
|
|
||||||
m_error = gst_bambu_last_error ? gst_bambu_last_error : 2;
|
|
||||||
PostGtkSinkStateEvent(GetId());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!m_imp) {
|
|
||||||
m_error = m_native_wayland && !m_gtk_sink_error.empty() ? 104 : 100;
|
|
||||||
m_loaded = false;
|
|
||||||
if (m_native_wayland && !m_gtk_sink_error.empty() && !m_gtk_sink_error_notified) {
|
|
||||||
m_gtk_sink_error_notified = true;
|
|
||||||
const wxString message = m_gtk_sink_error;
|
|
||||||
CallAfter([message] {
|
|
||||||
wxMessageBox(message, _L("Error"), wxOK);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
wxMediaEvent event(wxEVT_MEDIA_STATECHANGED);
|
|
||||||
event.SetId(GetId());
|
|
||||||
event.SetEventObject(this);
|
|
||||||
wxPostEvent(this, event);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
wxMediaCtrl::Load(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
void wxMediaCtrl2::Play()
|
|
||||||
{
|
|
||||||
#if defined(__LINUX__) && defined(__WXGTK__)
|
|
||||||
if (m_use_gtk_sink && m_gtk_playbin) {
|
|
||||||
GstStateChangeReturn state = gst_element_set_state(m_gtk_playbin, GST_STATE_PLAYING);
|
|
||||||
if (state == GST_STATE_CHANGE_FAILURE) {
|
|
||||||
m_error = gst_bambu_last_error ? gst_bambu_last_error : 2;
|
|
||||||
m_gtk_state = wxMEDIASTATE_STOPPED;
|
|
||||||
PostGtkSinkStateEvent(GetId());
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!m_imp) {
|
|
||||||
m_error = m_native_wayland && !m_gtk_sink_error.empty() ? 104 : 100;
|
|
||||||
if (m_native_wayland && !m_gtk_sink_error.empty() && !m_gtk_sink_error_notified) {
|
|
||||||
m_gtk_sink_error_notified = true;
|
|
||||||
const wxString message = m_gtk_sink_error;
|
|
||||||
CallAfter([message] {
|
|
||||||
wxMessageBox(message, _L("Error"), wxOK);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
PostGtkSinkStateEvent(GetId());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
wxMediaCtrl::Play();
|
|
||||||
}
|
|
||||||
|
|
||||||
void wxMediaCtrl2::Stop()
|
|
||||||
{
|
|
||||||
#if defined(__LINUX__) && defined(__WXGTK__)
|
|
||||||
if (m_use_gtk_sink && m_gtk_playbin) {
|
|
||||||
gst_element_set_state(m_gtk_playbin, GST_STATE_NULL);
|
|
||||||
m_gtk_state = wxMEDIASTATE_STOPPED;
|
|
||||||
m_loaded = false;
|
|
||||||
PostGtkSinkStateEvent(0);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!m_imp)
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
wxMediaCtrl::Stop(); }
|
|
||||||
|
|
||||||
void wxMediaCtrl2::SetIdleImage(wxString const &image) {}
|
|
||||||
|
|
||||||
wxMediaState wxMediaCtrl2::GetState()
|
|
||||||
{
|
|
||||||
#if defined(__LINUX__) && defined(__WXGTK__)
|
|
||||||
if (m_use_gtk_sink && m_gtk_playbin)
|
|
||||||
return m_gtk_state;
|
|
||||||
if (!m_imp)
|
|
||||||
return wxMEDIASTATE_STOPPED;
|
|
||||||
#endif
|
|
||||||
return wxMediaCtrl::GetState();
|
|
||||||
}
|
|
||||||
|
|
||||||
int wxMediaCtrl2::GetLastError() const
|
|
||||||
{
|
|
||||||
#ifdef __LINUX__
|
|
||||||
#ifdef __WXGTK__
|
|
||||||
if (m_use_gtk_sink && m_error)
|
|
||||||
return m_error;
|
|
||||||
#endif
|
|
||||||
if (m_error)
|
|
||||||
return m_error;
|
|
||||||
return gst_bambu_last_error;
|
|
||||||
#else
|
|
||||||
return m_error;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
wxSize wxMediaCtrl2::GetVideoSize() const
|
|
||||||
{
|
|
||||||
#ifdef __LINUX__
|
|
||||||
// Gstreamer doesn't give us a VideoSize until we're playing, which
|
|
||||||
// confuses the MediaPlayCtrl into claiming that it is stuck
|
|
||||||
// "Loading...". Fake it out for now.
|
|
||||||
return m_loaded ? wxSize(1280, 720) : wxSize{};
|
|
||||||
#else
|
|
||||||
wxSize size = m_imp ? m_imp->GetVideoSize() : wxSize(0, 0);
|
|
||||||
if (size.GetWidth() > 0)
|
|
||||||
const_cast<wxSize&>(m_video_size) = size;
|
|
||||||
return size;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
wxSize wxMediaCtrl2::DoGetBestSize() const
|
|
||||||
{
|
|
||||||
return {-1, -1};
|
|
||||||
}
|
|
||||||
|
|
||||||
void wxMediaCtrl2::DoSetSize(int x, int y, int width, int height, int sizeFlags)
|
|
||||||
{
|
|
||||||
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
|
|
||||||
if (sizeFlags & wxSIZE_USE_EXISTING) return;
|
|
||||||
#if defined(__LINUX__) && defined(__WXGTK__)
|
|
||||||
// Keep the native GStreamer video window filling the client area.
|
|
||||||
if (m_gtk_video_window) {
|
|
||||||
const wxSize client_size = GetClientSize();
|
|
||||||
m_gtk_video_window->SetSize(0, 0, client_size.GetWidth(), client_size.GetHeight());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
wxMediaCtrl_OnSize(this, m_video_size, width, height);
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef __WIN32__
|
|
||||||
|
|
||||||
WXLRESULT wxMediaCtrl2::MSWWindowProc(WXUINT nMsg,
|
|
||||||
WXWPARAM wParam,
|
|
||||||
WXLPARAM lParam)
|
|
||||||
{
|
|
||||||
// The stream source sends WM_USER+1000 with a synchronous SendMessage from its own threads,
|
|
||||||
// so this runs re-entrantly on the UI thread at whatever message-retrieval point the player
|
|
||||||
// happens to be in - often nested inside an Orca log statement. Never BOOST_LOG_TRIVIAL here:
|
|
||||||
// boost::log is not re-entrant on one thread, and doing so corrupted its per-thread record
|
|
||||||
// state, crashing later in unrelated places (the player, the log filter, a plug-in heap free).
|
|
||||||
// Post the string out (as the stat branch does) and log it on a clean stack instead.
|
|
||||||
if (nMsg == WM_USER + 1000) {
|
|
||||||
wxString msg((wchar_t const *) lParam);
|
|
||||||
if (wParam == 1) {
|
|
||||||
if (msg.EndsWith("]")) {
|
|
||||||
int n = msg.find_last_of('[');
|
|
||||||
if (n != wxString::npos) {
|
|
||||||
long val = 0;
|
|
||||||
if (msg.SubString(n + 1, msg.Length() - 2).ToLong(&val))
|
|
||||||
m_error = (int) val;
|
|
||||||
}
|
|
||||||
} else if (msg.Contains("stat_log")) {
|
|
||||||
wxCommandEvent evt(EVT_MEDIA_CTRL_STAT);
|
|
||||||
evt.SetEventObject(this);
|
|
||||||
evt.SetString(msg.Mid(msg.Find(' ') + 1));
|
|
||||||
wxPostEvent(this, evt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
return wxMediaCtrl::MSWWindowProc(nMsg, wParam, lParam);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
//
|
|
||||||
// wxMediaCtrl2.h
|
|
||||||
// libslic3r_gui
|
|
||||||
//
|
|
||||||
// Created by cmguo on 2021/12/7.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef wxMediaCtrl2_h
|
|
||||||
#define wxMediaCtrl2_h
|
|
||||||
|
|
||||||
#include "wx/uri.h"
|
|
||||||
#include "wx/mediactrl.h"
|
|
||||||
|
|
||||||
wxDECLARE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
|
|
||||||
|
|
||||||
void wxMediaCtrl_OnSize(wxWindow * ctrl, wxSize const & videoSize, int width, int height);
|
|
||||||
|
|
||||||
#if defined(__LINUX__) && defined(__WXGTK__)
|
|
||||||
typedef struct _GstElement GstElement;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class wxMediaCtrl2 : public wxMediaCtrl
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
wxMediaCtrl2(wxWindow *parent);
|
|
||||||
~wxMediaCtrl2();
|
|
||||||
|
|
||||||
void Load(wxURI url);
|
|
||||||
|
|
||||||
void Play();
|
|
||||||
|
|
||||||
void Stop();
|
|
||||||
|
|
||||||
void SetIdleImage(wxString const & image);
|
|
||||||
|
|
||||||
wxMediaState GetState();
|
|
||||||
|
|
||||||
int GetLastError() const;
|
|
||||||
|
|
||||||
wxSize GetVideoSize() const;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
wxSize DoGetBestSize() const override;
|
|
||||||
|
|
||||||
void DoSetSize(int x, int y, int width, int height, int sizeFlags) override;
|
|
||||||
|
|
||||||
#ifdef __WIN32__
|
|
||||||
WXLRESULT MSWWindowProc(WXUINT nMsg,
|
|
||||||
WXWPARAM wParam,
|
|
||||||
WXLPARAM lParam) override;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
private:
|
|
||||||
#if defined(__LINUX__) && defined(__WXGTK__)
|
|
||||||
bool CreateGtkSinkPlayer();
|
|
||||||
void DestroyGtkSinkPlayer();
|
|
||||||
void PostGtkSinkStateEvent(int id = 0);
|
|
||||||
|
|
||||||
bool m_native_wayland = false;
|
|
||||||
bool m_use_gtk_sink = false;
|
|
||||||
wxString m_gtk_sink_error;
|
|
||||||
bool m_gtk_sink_error_notified = false;
|
|
||||||
GstElement *m_gtk_playbin = nullptr;
|
|
||||||
GstElement *m_gtk_sink = nullptr;
|
|
||||||
unsigned int m_gtk_bus_watch_id = 0;
|
|
||||||
wxWindow *m_gtk_video_window = nullptr;
|
|
||||||
wxMediaState m_gtk_state = wxMEDIASTATE_STOPPED;
|
|
||||||
#endif
|
|
||||||
wxString m_idle_image;
|
|
||||||
int m_error = 0;
|
|
||||||
bool m_loaded = false;
|
|
||||||
wxSize m_video_size{16, 9};
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* wxMediaCtrl2_h */
|
|
||||||
Reference in New Issue
Block a user