mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-05-14 00:52:04 +00:00
Linux: use GTK sink for Wayland Bambu liveview (#13432)
* Use GTK sink for Wayland liveview Keep native Wayland sessions on the GTK backend and use a GTK widget based GStreamer sink for Bambu liveview instead of the Wayland video overlay path, which can render black on NVIDIA/Hyprland. Keep the existing wxMediaCtrl path for X11 and continue preferring software H.264 decoding while demoting GL and hardware decoder paths that caused liveview crashes. * Narrow Linux liveview fix to native Wayland * Tighten native Wayland liveview setup * Tighten Wayland liveview teardown and rank setup * Package GStreamer gtksink for Wayland liveview --------- Co-authored-by: SoftFever <softfeverever@gmail.com>
This commit is contained in:
@@ -35,12 +35,13 @@ finish-args:
|
||||
|
||||
modules:
|
||||
|
||||
# JPEG codec for the liveview
|
||||
# JPEG codec and GTK video sink (Wayland liveview) for the liveview
|
||||
- name: gst-plugins-good
|
||||
buildsystem: meson
|
||||
config-opts:
|
||||
- -Dauto_features=disabled
|
||||
- -Djpeg=enabled
|
||||
- -Dgtk3=enabled
|
||||
- -Ddoc=disabled
|
||||
- -Dexamples=disabled
|
||||
- -Dtests=disabled
|
||||
|
||||
@@ -12,6 +12,7 @@ export REQUIRED_DEV_PACKAGES=(
|
||||
gettext
|
||||
git
|
||||
glew
|
||||
gst-plugins-good
|
||||
gstreamer
|
||||
gstreamermm
|
||||
gtk3
|
||||
|
||||
@@ -12,6 +12,7 @@ export REQUIRED_DEV_PACKAGES=(
|
||||
gettext
|
||||
git
|
||||
glew
|
||||
gst-plugins-good
|
||||
gstreamer
|
||||
gtk3
|
||||
libmspack
|
||||
|
||||
@@ -10,6 +10,7 @@ REQUIRED_DEV_PACKAGES=(
|
||||
g++
|
||||
gettext
|
||||
git
|
||||
gstreamer1.0-gtk3
|
||||
libcurl4-openssl-dev
|
||||
libdbus-1-dev
|
||||
libglew-dev
|
||||
|
||||
@@ -13,6 +13,7 @@ REQUIRED_DEV_PACKAGES=(
|
||||
gettext
|
||||
git
|
||||
gstreamer1-devel
|
||||
gstreamer1-plugins-good-gtk
|
||||
gstreamermm-devel
|
||||
gtk3-devel
|
||||
libmspack-devel
|
||||
|
||||
@@ -21,6 +21,7 @@ REQUIRED_DEV_PACKAGES=(
|
||||
media-libs/glew
|
||||
media-libs/gst-plugins-base:1.0
|
||||
media-libs/gstreamer:1.0
|
||||
media-plugins/gst-plugins-gtk:1.0
|
||||
net-misc/curl
|
||||
net-misc/wget
|
||||
sys-apps/dbus
|
||||
|
||||
@@ -13,6 +13,7 @@ REQUIRED_DEV_PACKAGES=(
|
||||
gettext
|
||||
git
|
||||
gstreamer-devel
|
||||
gstreamer-plugins-good-gtk
|
||||
gtk3-devel
|
||||
libmspack-devel
|
||||
libquadmath-devel
|
||||
|
||||
@@ -32,7 +32,8 @@ static std::map<int, std::string> error_messages = {
|
||||
{100, L("The player is not loaded, please click \"play\" button to retry.")},
|
||||
{101, L("The player is not loaded, please click \"play\" button to retry.")},
|
||||
{102, L("The player is not loaded, please click \"play\" button to retry.")},
|
||||
{103, L("The player is not loaded, please click \"play\" button to retry.")}
|
||||
{103, L("The player is not loaded, please click \"play\" button to retry.")},
|
||||
{104, L("The player is not loaded because the GStreamer GTK video sink is missing or failed to initialize.")}
|
||||
};
|
||||
|
||||
namespace Slic3r {
|
||||
@@ -838,6 +839,12 @@ void wxMediaCtrl2::DoSetSize(int x, int y, int width, int height, int sizeFlags)
|
||||
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
|
||||
#else
|
||||
wxMediaCtrl::DoSetSize(x, y, width, height, sizeFlags);
|
||||
#endif
|
||||
#if defined(__LINUX__) && defined(__WXGTK__)
|
||||
if (m_gtk_video_window) {
|
||||
const wxSize client_size = GetClientSize();
|
||||
m_gtk_video_window->SetSize(0, 0, client_size.GetWidth(), client_size.GetHeight());
|
||||
}
|
||||
#endif
|
||||
if (sizeFlags & wxSIZE_USE_EXISTING) return;
|
||||
wxSize size = m_video_size;
|
||||
@@ -853,4 +860,3 @@ void wxMediaCtrl2::DoSetSize(int x, int y, int width, int height, int sizeFlags)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
#include "libslic3r/Time.hpp"
|
||||
#include "I18N.hpp"
|
||||
#include "GUI_App.hpp"
|
||||
#include "LinuxDisplayBackend.hpp"
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <string>
|
||||
#ifdef __WIN32__
|
||||
#include <winuser.h>
|
||||
#include <versionhelpers.h>
|
||||
@@ -13,6 +15,78 @@
|
||||
#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
|
||||
{
|
||||
@@ -25,6 +99,15 @@ wxDEFINE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
|
||||
|
||||
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;
|
||||
@@ -39,20 +122,202 @@ wxMediaCtrl2::wxMediaCtrl2(wxWindow *parent)
|
||||
*AmdPowerXpressRequestHighPerformance = 0;
|
||||
}
|
||||
#endif
|
||||
wxMediaCtrl::Create(parent, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxMEDIACTRLPLAYERCONTROLS_NONE);
|
||||
#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__
|
||||
/* Register only after we have created the wxMediaCtrl, since only then are we guaranteed to have fired up Gstreamer's plugin registry. */
|
||||
auto playbin = reinterpret_cast<wxGStreamerMediaBackend *>(m_imp)->m_playbin;
|
||||
g_object_set (G_OBJECT (playbin),
|
||||
"audio-sink", NULL,
|
||||
NULL);
|
||||
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)
|
||||
@@ -178,6 +443,15 @@ void wxMediaCtrl2::Load(wxURI url)
|
||||
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 {
|
||||
@@ -199,30 +473,103 @@ void wxMediaCtrl2::Load(wxURI url)
|
||||
#endif
|
||||
m_error = 0;
|
||||
m_loaded = false;
|
||||
wxMediaCtrl::Load(url);
|
||||
|
||||
#ifdef __WXGTK3__
|
||||
#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() { wxMediaCtrl::Play(); }
|
||||
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();
|
||||
}
|
||||
|
||||
#ifdef __LINUX__
|
||||
extern "C" int gst_bambu_last_error;
|
||||
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;
|
||||
|
||||
@@ -13,6 +13,10 @@
|
||||
|
||||
wxDECLARE_EVENT(EVT_MEDIA_CTRL_STAT, wxCommandEvent);
|
||||
|
||||
#if defined(__LINUX__) && defined(__WXGTK__)
|
||||
typedef struct _GstElement GstElement;
|
||||
#endif
|
||||
|
||||
#ifdef __WXMAC__
|
||||
|
||||
class wxMediaCtrl2 : public wxWindow
|
||||
@@ -59,6 +63,7 @@ class wxMediaCtrl2 : public wxMediaCtrl
|
||||
{
|
||||
public:
|
||||
wxMediaCtrl2(wxWindow *parent);
|
||||
~wxMediaCtrl2();
|
||||
|
||||
void Load(wxURI url);
|
||||
|
||||
@@ -68,6 +73,8 @@ public:
|
||||
|
||||
void SetIdleImage(wxString const & image);
|
||||
|
||||
wxMediaState GetState();
|
||||
|
||||
int GetLastError() const;
|
||||
|
||||
wxSize GetVideoSize() const;
|
||||
@@ -84,6 +91,21 @@ protected:
|
||||
#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;
|
||||
|
||||
Reference in New Issue
Block a user