Add support for Bambu Lab X1 series live video stream on Linux.
wxWidgets on Linux uses GStreamer as its back-end for wxMediaCtrl, which doesn't have a bambu: URI handler. On Windows, this is handled by a Windows Media subsystem plugin, and on Mac, this is handled with a BambuPlayer class. Luckily, the libBambuSource.so binary that is distributed with the network plugin package already contains support for receiving h.264 data from the network, and the API is the same as is used by the tiny bambusource.exe binary on Windows; we glue this into a GStreamer source plugin that registers a URI handler for bambu:. To make this work, we make a few additional changes elsewhere. GStreamer seems to have trouble rendering an Xv overlay onto a 32bpp X visual, but Bambu Slicer seems to request a 32bpp visual for some background transparency in the Notebook; it doesn't seem to use it in an interesting way on Linux, though, so we remove that request for transparency to allow Bambu Studio to render to a 24bpp visual. The media controller infrastructure also makes a few assumptions about when sizing information can be queried from a wxMediaCtrl backend that do not hold true on Linux; we either fix those assumptions, or fake them out, as needed. We also make a few changes needed to successfully compile C. This has only been tested with the GStreamer backend for wxWidgets -- notably, not the GStreamer-play backend (these are, astonishingly, two different things!). If you find that this seems not to work, consider *un*installing the libgstreamer-plugins-bad1.0-dev package and then rebuilding wxWidgets.
This commit is contained in:
parent
89d38fc6f6
commit
43a7f88c6c
|
@ -78,7 +78,9 @@ using namespace nlohmann;
|
|||
#include "slic3r/GUI/Camera.hpp"
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
|
||||
#ifdef __WXGTK__
|
||||
#include <X11/Xlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef SLIC3R_GUI
|
||||
#include "slic3r/GUI/GUI_Init.hpp"
|
||||
|
@ -332,6 +334,10 @@ int CLI::run(int argc, char **argv)
|
|||
// startup if gtk3 is used. This env var has to be set explicitly to
|
||||
// instruct the window manager to fall back to X server mode.
|
||||
::setenv("GDK_BACKEND", "x11", /* replace */ true);
|
||||
|
||||
// Also on Linux, we need to tell Xlib that we will be using threads,
|
||||
// lest we crash when we fire up GStreamer.
|
||||
XInitThreads();
|
||||
#endif
|
||||
|
||||
// Switch boost::filesystem to utf8.
|
||||
|
|
|
@ -437,6 +437,12 @@ else ()
|
|||
)
|
||||
endif ()
|
||||
|
||||
if (UNIX AND NOT APPLE)
|
||||
list(APPEND SLIC3R_GUI_SOURCES
|
||||
GUI/Printer/gstbambusrc.c
|
||||
)
|
||||
endif ()
|
||||
|
||||
add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES})
|
||||
target_include_directories(libslic3r_gui PRIVATE Utils)
|
||||
|
||||
|
@ -491,4 +497,10 @@ if (UNIX AND NOT APPLE)
|
|||
find_package(GTK${SLIC3R_GTK} REQUIRED)
|
||||
target_include_directories(libslic3r_gui PRIVATE ${GTK${SLIC3R_GTK}_INCLUDE_DIRS})
|
||||
target_link_libraries(libslic3r_gui ${GTK${SLIC3R_GTK}_LIBRARIES})
|
||||
|
||||
# We add GStreamer for bambu:/// support.
|
||||
pkg_check_modules(GSTREAMER REQUIRED gstreamer-1.0)
|
||||
pkg_check_modules(GST_BASE REQUIRED gstreamer-base-1.0)
|
||||
target_link_libraries(libslic3r_gui ${GSTREAMER_LIBRARIES} ${GST_BASE_LIBRARIES})
|
||||
target_include_directories(libslic3r_gui PRIVATE ${GSTREAMER_INCLUDE_DIRS} ${GST_BASE_INCLUDE_DIRS})
|
||||
endif ()
|
||||
|
|
|
@ -541,7 +541,11 @@ bool MediaPlayCtrl::get_stream_url(std::string *url)
|
|||
|
||||
void wxMediaCtrl2::DoSetSize(int x, int y, int width, int height, int sizeFlags)
|
||||
{
|
||||
#ifdef __WXMAC__
|
||||
wxWindow::DoSetSize(x, y, width, height, sizeFlags);
|
||||
#else
|
||||
wxMediaCtrl::DoSetSize(x, y, width, height, sizeFlags);
|
||||
#endif
|
||||
if (sizeFlags & wxSIZE_USE_EXISTING) return;
|
||||
wxSize size = GetVideoSize();
|
||||
if (size.GetWidth() <= 0)
|
||||
|
|
|
@ -258,5 +258,14 @@ void Notebook::Init()
|
|||
m_showEffect = m_hideEffect = wxSHOW_EFFECT_NONE;
|
||||
|
||||
m_showTimeout = m_hideTimeout = 0;
|
||||
|
||||
/* On Linux, Gstreamer wxMediaCtrl does not seem to get along well with
|
||||
* 32-bit X11 visuals (the overlay does not work). Is this a wxWindows
|
||||
* bug? Is this a Gstreamer bug? No idea, but it is our problem ...
|
||||
* and anyway, this transparency thing just isn't all that interesting,
|
||||
* so we just don't do it on Linux.
|
||||
*/
|
||||
#ifndef __WXGTK__
|
||||
SetBackgroundStyle(wxBG_STYLE_TRANSPARENT);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -21,6 +21,15 @@
|
|||
extern "C" {
|
||||
#endif // __cplusplus
|
||||
|
||||
#ifndef __cplusplus
|
||||
#include <stdbool.h>
|
||||
|
||||
/* We need these workarounds since we're compiling C source, not C++. */
|
||||
typedef enum Bambu_StreamType Bambu_StreamType;
|
||||
typedef struct Bambu_StreamInfo Bambu_StreamInfo;
|
||||
typedef struct Bambu_Sample Bambu_Sample;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef wchar_t tchar;
|
||||
#else
|
||||
|
|
|
@ -921,3 +921,7 @@ StaticBambuLib &StaticBambuLib::get()
|
|||
lib.Bambu_Create = Fake_Bambu_Create;
|
||||
return lib;
|
||||
}
|
||||
|
||||
extern "C" struct BambuLib *bambulib_get() {
|
||||
return &StaticBambuLib::get();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,554 @@
|
|||
/* bambusrc for gstreamer
|
||||
* integration with proprietary Bambu Lab blob for getting raw h.264 video
|
||||
*
|
||||
* Copyright (C) 2023 Joshua Wise <joshua@accelerated.tech>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
|
||||
* which case the following provisions apply instead of the ones
|
||||
* mentioned above:
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#include "gstbambusrc.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#ifndef EXTERNAL_GST_PLUGIN
|
||||
#define BAMBU_DYNAMIC
|
||||
#endif
|
||||
#include "BambuTunnel.h"
|
||||
|
||||
#ifdef BAMBU_DYNAMIC
|
||||
// From PrinterFileSystem.
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#else
|
||||
extern
|
||||
#endif
|
||||
struct BambuLib *bambulib_get();
|
||||
static struct BambuLib *_lib = NULL;
|
||||
#define BAMBULIB(x) (_lib->x)
|
||||
|
||||
#else
|
||||
#define BAMBULIB(x) (x)
|
||||
#endif
|
||||
|
||||
GST_DEBUG_CATEGORY_STATIC (gst_bambusrc_debug);
|
||||
#define GST_CAT_DEFAULT gst_bambusrc_debug
|
||||
|
||||
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_ALWAYS,
|
||||
GST_STATIC_CAPS("video/x-h264,framerate=0/1,parsed=(boolean)false,stream-format=(string)byte-stream"));
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_LOCATION,
|
||||
};
|
||||
|
||||
static void gst_bambusrc_uri_handler_init (gpointer g_iface,
|
||||
gpointer iface_data);
|
||||
static void gst_bambusrc_finalize (GObject * gobject);
|
||||
static void gst_bambusrc_dispose (GObject * gobject);
|
||||
|
||||
static void gst_bambusrc_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_bambusrc_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static GstStateChangeReturn gst_bambusrc_change_state (GstElement *
|
||||
element, GstStateChange transition);
|
||||
static GstFlowReturn gst_bambusrc_create (GstPushSrc * psrc,
|
||||
GstBuffer ** outbuf);
|
||||
static gboolean gst_bambusrc_start (GstBaseSrc * bsrc);
|
||||
static gboolean gst_bambusrc_stop (GstBaseSrc * bsrc);
|
||||
static gboolean gst_bambusrc_is_seekable (GstBaseSrc * bsrc);
|
||||
static gboolean gst_bambusrc_query (GstBaseSrc * bsrc, GstQuery * query);
|
||||
static gboolean gst_bambusrc_unlock (GstBaseSrc * bsrc);
|
||||
static gboolean gst_bambusrc_unlock_stop (GstBaseSrc * bsrc);
|
||||
static gboolean gst_bambusrc_set_location (GstBambuSrc * src,
|
||||
const gchar * uri, GError ** error);
|
||||
|
||||
#define gst_bambusrc_parent_class parent_class
|
||||
G_DEFINE_TYPE_WITH_CODE (GstBambuSrc, gst_bambusrc, GST_TYPE_PUSH_SRC,
|
||||
G_IMPLEMENT_INTERFACE (GST_TYPE_URI_HANDLER,
|
||||
gst_bambusrc_uri_handler_init));
|
||||
GST_ELEMENT_REGISTER_DEFINE (bambusrc, "bambusrc",
|
||||
GST_RANK_PRIMARY, GST_TYPE_BAMBUSRC);
|
||||
|
||||
static void
|
||||
gst_bambusrc_class_init (GstBambuSrcClass * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
GstBaseSrcClass *gstbasesrc_class;
|
||||
GstPushSrcClass *gstpushsrc_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
gstbasesrc_class = (GstBaseSrcClass *) klass;
|
||||
gstpushsrc_class = (GstPushSrcClass *) klass;
|
||||
|
||||
gobject_class->set_property = gst_bambusrc_set_property;
|
||||
gobject_class->get_property = gst_bambusrc_get_property;
|
||||
gobject_class->finalize = gst_bambusrc_finalize;
|
||||
gobject_class->dispose = gst_bambusrc_dispose;
|
||||
|
||||
g_object_class_install_property (gobject_class,
|
||||
PROP_LOCATION,
|
||||
g_param_spec_string ("location", "Location",
|
||||
"URI to pass to Bambu Lab blobs", "",
|
||||
(GParamFlags)(G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
|
||||
|
||||
gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
|
||||
|
||||
gst_element_class_set_static_metadata (gstelement_class, "Bambu Lab source",
|
||||
"Source/Network",
|
||||
"Receive data as a client over the network using the proprietary Bambu Lab blobs",
|
||||
"Joshua Wise <joshua@accelerated.tech>");
|
||||
gstelement_class->change_state =
|
||||
GST_DEBUG_FUNCPTR (gst_bambusrc_change_state);
|
||||
|
||||
gstbasesrc_class->start = GST_DEBUG_FUNCPTR (gst_bambusrc_start);
|
||||
gstbasesrc_class->stop = GST_DEBUG_FUNCPTR (gst_bambusrc_stop);
|
||||
gstbasesrc_class->unlock = GST_DEBUG_FUNCPTR (gst_bambusrc_unlock);
|
||||
gstbasesrc_class->unlock_stop =
|
||||
GST_DEBUG_FUNCPTR (gst_bambusrc_unlock_stop);
|
||||
gstbasesrc_class->is_seekable =
|
||||
GST_DEBUG_FUNCPTR (gst_bambusrc_is_seekable);
|
||||
gstbasesrc_class->query = GST_DEBUG_FUNCPTR (gst_bambusrc_query);
|
||||
|
||||
gstpushsrc_class->create = GST_DEBUG_FUNCPTR (gst_bambusrc_create);
|
||||
|
||||
GST_DEBUG_CATEGORY_INIT (gst_bambusrc_debug, "bambusrc", 0,
|
||||
"Bambu Lab src");
|
||||
}
|
||||
|
||||
static void
|
||||
gst_bambusrc_reset (GstBambuSrc * src)
|
||||
{
|
||||
gst_caps_replace (&src->src_caps, NULL);
|
||||
if (src->tnl) {
|
||||
BAMBULIB(Bambu_Close)(src->tnl);
|
||||
BAMBULIB(Bambu_Destroy)(src->tnl);
|
||||
src->tnl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_bambusrc_init (GstBambuSrc * src)
|
||||
{
|
||||
src->location = NULL;
|
||||
src->tnl = NULL;
|
||||
|
||||
gst_base_src_set_automatic_eos (GST_BASE_SRC (src), FALSE);
|
||||
gst_base_src_set_live(GST_BASE_SRC(src), TRUE);
|
||||
|
||||
gst_bambusrc_reset (src);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_bambusrc_dispose (GObject * gobject)
|
||||
{
|
||||
GstBambuSrc *src = GST_BAMBUSRC (gobject);
|
||||
|
||||
GST_DEBUG_OBJECT (src, "dispose");
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_bambusrc_finalize (GObject * gobject)
|
||||
{
|
||||
GstBambuSrc *src = GST_BAMBUSRC (gobject);
|
||||
|
||||
GST_DEBUG_OBJECT (src, "finalize");
|
||||
|
||||
g_free (src->location);
|
||||
if (src->tnl) {
|
||||
BAMBULIB(Bambu_Close)(src->tnl);
|
||||
BAMBULIB(Bambu_Destroy)(src->tnl);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->finalize (gobject);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_bambusrc_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstBambuSrc *src = GST_BAMBUSRC (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_LOCATION:
|
||||
{
|
||||
const gchar *location;
|
||||
|
||||
location = g_value_get_string (value);
|
||||
|
||||
if (location == NULL) {
|
||||
GST_WARNING ("location property cannot be NULL");
|
||||
goto done;
|
||||
}
|
||||
if (!gst_bambusrc_set_location (src, location, NULL)) {
|
||||
GST_WARNING ("badly formatted location");
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
done:
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_bambusrc_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec)
|
||||
{
|
||||
GstBambuSrc *src = GST_BAMBUSRC (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_LOCATION:
|
||||
g_value_set_string (value, src->location);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GstFlowReturn
|
||||
gst_bambusrc_create (GstPushSrc * psrc, GstBuffer ** outbuf)
|
||||
{
|
||||
GstBambuSrc *src;
|
||||
|
||||
src = GST_BAMBUSRC (psrc);
|
||||
|
||||
(void) src;
|
||||
GST_DEBUG_OBJECT (src, "create()");
|
||||
|
||||
int rv;
|
||||
struct Bambu_Sample sample;
|
||||
|
||||
if (!src->tnl) {
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
while ((rv = BAMBULIB(Bambu_ReadSample)(src->tnl, &sample)) == Bambu_would_block) {
|
||||
GST_DEBUG_OBJECT(src, "create would block");
|
||||
usleep(33333); /* 30Hz */
|
||||
}
|
||||
|
||||
if (rv == Bambu_stream_end) {
|
||||
return GST_FLOW_EOS;
|
||||
}
|
||||
|
||||
if (rv != Bambu_success) {
|
||||
return GST_FLOW_ERROR;
|
||||
}
|
||||
|
||||
*outbuf = gst_buffer_new_memdup(sample.buffer, sample.size);
|
||||
/* The NAL data already contains a timestamp (I think?), but we seem to
|
||||
* need to feed this in too -- otherwise the GStreamer pipeline gets upset
|
||||
* and starts triggering QoS events.
|
||||
*/
|
||||
if (!src->sttime) {
|
||||
src->sttime = sample.decode_time * 100ULL;
|
||||
}
|
||||
GST_BUFFER_DTS(*outbuf) = sample.decode_time * 100ULL - src->sttime;
|
||||
GST_BUFFER_PTS(*outbuf) = GST_CLOCK_TIME_NONE;
|
||||
GST_BUFFER_DURATION(*outbuf) = GST_CLOCK_TIME_NONE;
|
||||
|
||||
return GST_FLOW_OK;
|
||||
}
|
||||
|
||||
static void _log(void *ctx, int lvl, const char *msg) {
|
||||
GstBambuSrc *src = (GstBambuSrc *) ctx;
|
||||
GST_DEBUG_OBJECT(src, "bambu: %s", msg);
|
||||
BAMBULIB(Bambu_FreeLogMsg)(msg);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_bambusrc_start (GstBaseSrc * bsrc)
|
||||
{
|
||||
GstBambuSrc *src = GST_BAMBUSRC (bsrc);
|
||||
|
||||
GST_DEBUG_OBJECT (src, "start(\"%s\")", src->location);
|
||||
|
||||
if (src->tnl) {
|
||||
BAMBULIB(Bambu_Close)(src->tnl);
|
||||
BAMBULIB(Bambu_Destroy)(src->tnl);
|
||||
src->tnl = NULL;
|
||||
}
|
||||
|
||||
#ifdef BAMBU_DYNAMIC
|
||||
if (!_lib) {
|
||||
_lib = bambulib_get();
|
||||
if (!_lib->Bambu_Open) {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (BAMBULIB(Bambu_Create)(&src->tnl, src->location) != Bambu_success) {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BAMBULIB(Bambu_SetLogger)(src->tnl, _log, (void *)src);
|
||||
if (BAMBULIB(Bambu_Open)(src->tnl) != Bambu_success) {
|
||||
BAMBULIB(Bambu_Destroy)(src->tnl);
|
||||
src->tnl = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
int rv;
|
||||
while ((rv = BAMBULIB(Bambu_StartStream)(src->tnl, 1 /* video */)) == Bambu_would_block) {
|
||||
usleep(100000);
|
||||
}
|
||||
if (rv != Bambu_success) {
|
||||
BAMBULIB(Bambu_Close)(src->tnl);
|
||||
BAMBULIB(Bambu_Destroy)(src->tnl);
|
||||
src->tnl = NULL;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
src->sttime = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_bambusrc_stop (GstBaseSrc * bsrc)
|
||||
{
|
||||
GstBambuSrc *src;
|
||||
|
||||
src = GST_BAMBUSRC (bsrc);
|
||||
GST_DEBUG_OBJECT (src, "stop()");
|
||||
if (src->tnl) {
|
||||
BAMBULIB(Bambu_Close)(src->tnl);
|
||||
BAMBULIB(Bambu_Destroy)(src->tnl);
|
||||
src->tnl = NULL;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_bambusrc_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
GstStateChangeReturn ret;
|
||||
GstBambuSrc *src;
|
||||
|
||||
src = GST_BAMBUSRC (element);
|
||||
|
||||
(void) src;
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_CHANGE_READY_TO_NULL:
|
||||
//gst_bambusrc_session_close (src);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* Interrupt a blocking request. */
|
||||
static gboolean
|
||||
gst_bambusrc_unlock (GstBaseSrc * bsrc)
|
||||
{
|
||||
GstBambuSrc *src;
|
||||
|
||||
src = GST_BAMBUSRC (bsrc);
|
||||
GST_DEBUG_OBJECT (src, "unlock()");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Interrupt interrupt. */
|
||||
static gboolean
|
||||
gst_bambusrc_unlock_stop (GstBaseSrc * bsrc)
|
||||
{
|
||||
GstBambuSrc *src;
|
||||
|
||||
src = GST_BAMBUSRC (bsrc);
|
||||
GST_DEBUG_OBJECT (src, "unlock_stop()");
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_bambusrc_is_seekable (GstBaseSrc * bsrc)
|
||||
{
|
||||
GstBambuSrc *src = GST_BAMBUSRC (bsrc);
|
||||
|
||||
(void) src;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_bambusrc_query (GstBaseSrc * bsrc, GstQuery * query)
|
||||
{
|
||||
GstBambuSrc *src = GST_BAMBUSRC (bsrc);
|
||||
gboolean ret;
|
||||
GstSchedulingFlags flags;
|
||||
gint minsize, maxsize, align;
|
||||
|
||||
switch (GST_QUERY_TYPE (query)) {
|
||||
case GST_QUERY_URI:
|
||||
gst_query_set_uri (query, src->location);
|
||||
ret = TRUE;
|
||||
break;
|
||||
default:
|
||||
ret = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!ret)
|
||||
ret = GST_BASE_SRC_CLASS (parent_class)->query (bsrc, query);
|
||||
|
||||
switch (GST_QUERY_TYPE (query)) {
|
||||
case GST_QUERY_SCHEDULING:
|
||||
gst_query_parse_scheduling (query, &flags, &minsize, &maxsize, &align);
|
||||
flags = (GstSchedulingFlags)((int)flags | (int)GST_SCHEDULING_FLAG_SEQUENTIAL);
|
||||
gst_query_set_scheduling (query, flags, minsize, maxsize, align);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_bambusrc_set_location (GstBambuSrc * src, const gchar * uri,
|
||||
GError ** error)
|
||||
{
|
||||
if (src->location) {
|
||||
g_free (src->location);
|
||||
src->location = NULL;
|
||||
}
|
||||
|
||||
if (uri == NULL)
|
||||
return FALSE;
|
||||
|
||||
src->location = g_strdup (uri);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GstURIType
|
||||
gst_bambusrc_uri_get_type (GType type)
|
||||
{
|
||||
return GST_URI_SRC;
|
||||
}
|
||||
|
||||
static const gchar *const *
|
||||
gst_bambusrc_uri_get_protocols (GType type)
|
||||
{
|
||||
static const gchar *protocols[] = { "bambu", NULL };
|
||||
|
||||
return protocols;
|
||||
}
|
||||
|
||||
static gchar *
|
||||
gst_bambusrc_uri_get_uri (GstURIHandler * handler)
|
||||
{
|
||||
GstBambuSrc *src = GST_BAMBUSRC (handler);
|
||||
|
||||
/* FIXME: make thread-safe */
|
||||
return g_strdup (src->location);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_bambusrc_uri_set_uri (GstURIHandler * handler, const gchar * uri,
|
||||
GError ** error)
|
||||
{
|
||||
GstBambuSrc *src = GST_BAMBUSRC (handler);
|
||||
|
||||
return gst_bambusrc_set_location (src, uri, error);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_bambusrc_uri_handler_init (gpointer g_iface, gpointer iface_data)
|
||||
{
|
||||
GstURIHandlerInterface *iface = (GstURIHandlerInterface *) g_iface;
|
||||
|
||||
iface->get_type = gst_bambusrc_uri_get_type;
|
||||
iface->get_protocols = gst_bambusrc_uri_get_protocols;
|
||||
iface->get_uri = gst_bambusrc_uri_get_uri;
|
||||
iface->set_uri = gst_bambusrc_uri_set_uri;
|
||||
}
|
||||
|
||||
static gboolean gstbambusrc_init(GstPlugin *plugin)
|
||||
{
|
||||
return GST_ELEMENT_REGISTER (bambusrc, plugin);
|
||||
}
|
||||
|
||||
#ifndef EXTERNAL_GST_PLUGIN
|
||||
|
||||
// for use inside of Bambu Slicer
|
||||
void gstbambusrc_register()
|
||||
{
|
||||
static int did_register = 0;
|
||||
if (did_register)
|
||||
return;
|
||||
did_register = 1;
|
||||
|
||||
gst_plugin_register_static(GST_VERSION_MAJOR, GST_VERSION_MINOR, "bambusrc", "Bambu Lab source", gstbambusrc_init, "0.0.1", "GPL", "BambuStudio", "BambuStudio", "https://github.com/bambulab/BambuStudio");
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifndef PACKAGE
|
||||
#define PACKAGE "bambusrc"
|
||||
#endif
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, bambusrc, "Bambu Lab source", gstbambusrc_init, "0.0.1", "GPL", "BambuStudio", "https://github.com/bambulab/BambuStudio")
|
||||
|
||||
#endif
|
|
@ -0,0 +1,73 @@
|
|||
/* bambusrc for gstreamer
|
||||
* integration with proprietary Bambu Lab blob for getting raw h.264 video
|
||||
*
|
||||
* Copyright (C) 2023 Joshua Wise <joshua@accelerated.tech>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Alternatively, the contents of this file may be used under the
|
||||
* GNU Lesser General Public License Version 2.1 (the "LGPL"), in
|
||||
* which case the following provisions apply instead of the ones
|
||||
* mentioned above:
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#ifndef __GST_BAMBUSRC_H__
|
||||
#define __GST_BAMBUSRC_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <gst/base/gstpushsrc.h>
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GST_TYPE_BAMBUSRC (gst_bambusrc_get_type())
|
||||
G_DECLARE_FINAL_TYPE (GstBambuSrc, gst_bambusrc,
|
||||
GST, BAMBUSRC, GstPushSrc)
|
||||
|
||||
typedef void *Bambu_Tunnel;
|
||||
|
||||
struct _GstBambuSrc
|
||||
{
|
||||
GstPushSrc element;
|
||||
GstCaps *src_caps;
|
||||
gchar *location;
|
||||
Bambu_Tunnel tnl;
|
||||
GstClockTime sttime;
|
||||
};
|
||||
|
||||
extern void gstbambusrc_register();
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_BAMBUSRC_H__ */
|
|
@ -7,6 +7,10 @@
|
|||
#include <shellapi.h>
|
||||
#endif
|
||||
|
||||
#ifdef __LINUX__
|
||||
#include "Printer/gstbambusrc.h"
|
||||
#endif
|
||||
|
||||
wxMediaCtrl2::wxMediaCtrl2(wxWindow *parent)
|
||||
{
|
||||
#ifdef __WIN32__
|
||||
|
@ -24,6 +28,10 @@ wxMediaCtrl2::wxMediaCtrl2(wxWindow *parent)
|
|||
}
|
||||
#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. */
|
||||
gstbambusrc_register();
|
||||
#endif
|
||||
}
|
||||
|
||||
#define CLSID_BAMBU_SOURCE L"{233E64FB-2041-4A6C-AFAB-FF9BCF83E7AA}"
|
||||
|
@ -105,7 +113,14 @@ void wxMediaCtrl2::Stop() { wxMediaCtrl::Stop(); }
|
|||
|
||||
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 wxSize(1280, 720);
|
||||
#else
|
||||
return m_imp ? m_imp->GetVideoSize() : wxSize(0, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
wxSize wxMediaCtrl2::DoGetBestSize() const
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
|
@ -194,3 +196,5 @@
|
|||
#ifdef _WIN32
|
||||
#include "GUI/format.hpp"
|
||||
#endif // _WIN32
|
||||
|
||||
#endif // __cplusplus
|
||||
|
|
Loading…
Reference in New Issue