Improvement; USE_GST_OPENGL_SYNC_HANDLER now effective, with GST pipeline sharing OpenGL context. This allows MediaPlayer to keep the opengl texture in GPU without copying from CPU (no copy, no PBO needed). Settings::gst_glmemory_texturing can disable the feature. Performance gain is important (up to x2) mostly for high resolution videos.

This commit is contained in:
brunoherbelin
2025-12-21 15:06:37 +01:00
parent c2f60e434c
commit ef205abe8d
10 changed files with 240 additions and 124 deletions
+1 -2
View File
@@ -138,9 +138,8 @@ endif()
##### Preprocessor options
#####
# add_definitions(-DUSE_GST_OPENGL_SYNC_HANDLER)
add_definitions(-DUSE_GST_OPENGL_SYNC_HANDLER)
# add_definitions(-DUSE_GL_BUFFER_SUBDATA)
# add_definitions(-DIGNORE_GST_BUS_MESSAGE)
#####
##### Dependencies
+1 -5
View File
@@ -496,14 +496,10 @@ void FrameGrabber::addFrame (GstBuffer *buffer, GstCaps *caps)
// if initialization succeeded
if (initialized_) {
#ifdef IGNORE_GST_BUS_MESSAGE
// avoid filling up bus with messages
gst_bus_set_flushing(gst_element_get_bus(pipeline_), true);
#else
// set message handler for the pipeline's bus
gst_bus_set_sync_handler(gst_element_get_bus(pipeline_),
FrameGrabber::signal_handler, this, NULL);
#endif
// attach EOS detector
GstPad *pad = gst_element_get_static_pad (gst_bin_get_by_name (GST_BIN (pipeline_), "sink"), "sink");
gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, FrameGrabber::callback_event_probe, this, NULL);
+213 -51
View File
@@ -46,6 +46,7 @@
#endif
#ifdef USE_GST_OPENGL_SYNC_HANDLER
#include <gst/gl/gl.h>
#include "RenderingManager.h"
#endif
@@ -89,6 +90,11 @@ MediaPlayer::MediaPlayer()
pbo_index_ = 0;
pbo_next_index_ = 0;
#ifdef USE_GST_OPENGL_SYNC_HANDLER
// try to use GLMemory for zero-copy GPU textures
use_gl_memory_ = Settings::application.render.gst_glmemory_texturing;
#endif
// OpenGL texture
textureindex_ = 0;
}
@@ -341,6 +347,27 @@ GstBusSyncReply MediaPlayer::signal_handler(GstBus *, GstMessage *msg, gpointer
error->message);
g_error_free(error);
}
#ifdef USE_GST_OPENGL_SYNC_HANDLER
// setup OpenGL contexts for GStreamer elements from global Rendering opengl
else if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_NEED_CONTEXT) {
const gchar* contextType;
gst_message_parse_context_type(msg, &contextType);
if (!g_strcmp0(contextType, GST_GL_DISPLAY_CONTEXT_TYPE) && Rendering::manager().global_display) {
GstContext *displayContext = gst_context_new(GST_GL_DISPLAY_CONTEXT_TYPE, TRUE);
gst_context_set_gl_display(displayContext, Rendering::manager().global_display);
gst_element_set_context(GST_ELEMENT(msg->src), displayContext);
gst_context_unref (displayContext);
}
if (!g_strcmp0(contextType, "gst.gl.app_context") && Rendering::manager().global_gl_context) {
GstContext *appContext = gst_context_new("gst.gl.app_context", TRUE);
GstStructure* structure = gst_context_writable_structure(appContext);
gst_structure_set(structure, "context", GST_TYPE_GL_CONTEXT, Rendering::manager().global_gl_context, nullptr);
gst_element_set_context(GST_ELEMENT(msg->src), appContext);
gst_context_unref (appContext);
}
}
#endif
// drop all messages to avoid filling up the stack
gst_message_unref (msg);
@@ -441,12 +468,43 @@ void MediaPlayer::execute_open()
// instruct the sink to send samples synched in time
gst_base_sink_set_sync (GST_BASE_SINK(sink), true);
// instruct sink to use the required caps
GstCaps *caps = gst_caps_new_simple ("video/x-raw",
"format", G_TYPE_STRING, "RGBA",
"width", G_TYPE_INT, media_.width,
"height", G_TYPE_INT, media_.height,
NULL);
// Configure appsink caps
// When using glsinkbin, appsink must accept GLMemory caps
GstCaps *caps = nullptr;
#ifdef USE_GST_OPENGL_SYNC_HANDLER
if (media_.isimage)
use_gl_memory_ = false; // disable GLMemory for images to avoid issues with some plugins
if (use_gl_memory_) {
// Create caps that accept BOTH GLMemory and system memory
// This allows glsinkbin to link properly
caps = gst_caps_new_simple("video/x-raw",
"format", G_TYPE_STRING, "RGBA",
NULL);
// Add GLMemory variant
GstCaps *gl_caps = gst_caps_new_simple("video/x-raw",
"format", G_TYPE_STRING, "RGBA",
NULL);
GstCapsFeatures *gl_features = gst_caps_features_new("memory:GLMemory", NULL);
gst_caps_set_features(gl_caps, 0, gl_features);
// Append GLMemory caps as preferred option
gst_caps_append(gl_caps, caps);
caps = gl_caps;
}
else
#endif
{
// Standard CPU caps with dimensions
caps = gst_caps_new_simple("video/x-raw",
"format", G_TYPE_STRING, "RGBA",
"width", G_TYPE_INT, media_.width,
"height", G_TYPE_INT, media_.height,
NULL);
}
gst_app_sink_set_caps (GST_APP_SINK(sink), caps);
gst_caps_unref (caps);
@@ -454,6 +512,10 @@ void MediaPlayer::execute_open()
gst_app_sink_set_max_buffers( GST_APP_SINK(sink), 5);
gst_app_sink_set_drop (GST_APP_SINK(sink), true);
// set message handler for the pipeline's bus
bus_ = gst_element_get_bus(pipeline_);
gst_bus_set_sync_handler(bus_, MediaPlayer::signal_handler, this, NULL);
// set the callbacks
GstAppSinkCallbacks callbacks;
#if GST_VERSION_MINOR > 18 && GST_VERSION_MAJOR > 0
@@ -474,14 +536,30 @@ void MediaPlayer::execute_open()
gst_app_sink_set_callbacks (GST_APP_SINK(sink), &callbacks, this, NULL);
gst_app_sink_set_emit_signals (GST_APP_SINK(sink), false);
// set playbin sink
g_object_set ( G_OBJECT (pipeline_), "video-sink", sink, NULL);
// Wrap appsink with glsinkbin for automatic GLMemory handling
GstElement *video_sink = sink; // Default to appsink
#ifdef USE_GST_OPENGL_SYNC_HANDLER
// capture bus signals to force a unique opengl context for all GST elements
Rendering::LinkPipeline(GST_PIPELINE (pipeline_));
if (use_gl_memory_) {
// Try to create glsinkbin to automatically handle GL upload and conversion
GstElement *glsinkbin = gst_element_factory_make("glsinkbin", "glsink");
if (glsinkbin) {
// glsinkbin wraps our appsink and automatically inserts:
// - glupload (for GLMemory)
// - glcolorconvert (for NV12/I420 -> RGBA conversion in shaders)
g_object_set(G_OBJECT(glsinkbin), "sink", sink, NULL);
video_sink = glsinkbin;
}
else {
use_gl_memory_ = false;
}
}
#endif
// set playbin sink (either glsinkbin wrapper or direct appsink)
g_object_set ( G_OBJECT (pipeline_), "video-sink", video_sink, NULL);
// set to desired state (PLAY or PAUSE)
GstStateChangeReturn ret = gst_element_set_state (GST_ELEMENT(pipeline_), desired_state_);
if (ret == GST_STATE_CHANGE_FAILURE) {
@@ -497,15 +575,6 @@ void MediaPlayer::execute_open()
timeline_.setEnd(d);
}
bus_ = gst_element_get_bus(pipeline_);
#ifdef IGNORE_GST_BUS_MESSAGE
// avoid filling up bus with messages
gst_bus_set_flushing(bus_, true);
#else
// set message handler for the pipeline's bus
gst_bus_set_sync_handler(bus_, MediaPlayer::signal_handler, this, NULL);
#endif
// all good
Log::Info("MediaPlayer %s Opened '%s' (%s %d x %d, %d kbps)", std::to_string(id_).c_str(),
SystemToolkit::filename(uri_).c_str(), media_.codec_name.c_str(),
@@ -660,11 +729,6 @@ void MediaPlayer::execute_open()
gst_object_unref (sink);
gst_caps_unref (caps);
#ifdef USE_GST_OPENGL_SYNC_HANDLER
// capture bus signals to force a unique opengl context for all GST elements
Rendering::LinkPipeline(GST_PIPELINE (pipeline_));
#endif
// set to desired state (PLAY or PAUSE)
GstStateChangeReturn ret = gst_element_set_state (pipeline_, desired_state_);
if (ret == GST_STATE_CHANGE_FAILURE) {
@@ -681,13 +745,8 @@ void MediaPlayer::execute_open()
}
bus_ = gst_element_get_bus(pipeline_);
#ifdef IGNORE_GST_BUS_MESSAGE
// avoid filling up bus with messages
gst_bus_set_flushing(bus_, true);
#else
// set message handler for the pipeline's bus
gst_bus_set_sync_handler(bus_, MediaPlayer::signal_handler, this, NULL);
#endif
// all good
Log::Info("MediaPlayer %s Opened '%s' (%s %d x %d)", std::to_string(id_).c_str(),
@@ -753,15 +812,14 @@ void MediaPlayer::pipeline_terminate( GstElement *p, GstBus *b )
if (ret == GST_STATE_CHANGE_ASYNC)
gst_element_get_state(p, NULL, NULL, 1000000);
#ifndef IGNORE_GST_BUS_MESSAGE
// empty pipeline bus (if used)
// empty pipeline bus
GstMessage *msg = NULL;
do {
if (msg)
gst_message_unref (msg);
msg = gst_bus_timed_pop_filtered(b, 1000000, GST_MESSAGE_ANY);
} while (msg != NULL);
#endif
// unref bus
gst_object_unref( GST_OBJECT(b) );
@@ -1159,11 +1217,49 @@ void MediaPlayer::init_texture(guint index)
// fill texture frame with frame at given index
if (frame_[index].buffer) {
GstMapInfo map;
gst_buffer_map(frame_[index].buffer, &map, GST_MAP_READ);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, media_.width, media_.height,
GL_RGBA, GL_UNSIGNED_BYTE, map.data);
gst_buffer_unmap (frame_[index].buffer, &map);
#ifdef USE_GST_OPENGL_SYNC_HANDLER
// Try GLMemory fast path first
bool gl_memory_used = false;
if ( use_gl_memory_ ) {
GstMemory *mem = gst_buffer_peek_memory(frame_[index].buffer, 0);
if (mem && gst_is_gl_memory(mem)) {
GstGLMemory *gl_mem = (GstGLMemory*) mem;
guint gst_tex_id = gst_gl_memory_get_texture_id(gl_mem);
if (gst_tex_id > 0) {
// Copy from GStreamer GL texture to our texture using FBO
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, gst_tex_id, 0);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
media_.width, media_.height);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fbo);
gl_memory_used = true;
}
} else {
// Not GLMemory - disable optimization
use_gl_memory_ = false;
}
}
// Fallback to CPU path if GLMemory not available
if (!gl_memory_used)
#endif
{
GstMapInfo map;
gst_buffer_map(frame_[index].buffer, &map, GST_MAP_READ);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, media_.width, media_.height,
GL_RGBA, GL_UNSIGNED_BYTE, map.data);
gst_buffer_unmap (frame_[index].buffer, &map);
}
}
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
@@ -1171,24 +1267,34 @@ void MediaPlayer::init_texture(guint index)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// initialize decoderName once (forced update)
decoder_name_ = "";
// use Pixel Buffer Objects only for performance needs of videos
if ( !isImage() ) {
// set pbo image size
pbo_size_ = media_.height * media_.width * 4;
#ifdef USE_GST_OPENGL_SYNC_HANDLER
if (use_gl_memory_)
Log::Info("MediaPlayer %s Uses %s decoding and OpenGL GLMemory texturing (zero-copy).", std::to_string(id_).c_str(), decoderName().c_str());
else
#endif
{
// set pbo image size
pbo_size_ = media_.height * media_.width * 4;
// create pixel buffer objects,
if (pbo_[0])
glDeleteBuffers(2, pbo_);
glGenBuffers(2, pbo_);
// create pixel buffer objects,
if (pbo_[0])
glDeleteBuffers(2, pbo_);
glGenBuffers(2, pbo_);
// should be good to go
pbo_index_ = 0;
pbo_next_index_ = 1;
// should be good to go
pbo_index_ = 0;
pbo_next_index_ = 1;
// initialize decoderName once (forced update)
decoder_name_ = "";
Log::Info("MediaPlayer %s Uses %s decoding and OpenGL PBO texturing.", std::to_string(id_).c_str(), decoderName().c_str());
Log::Info("MediaPlayer %s Uses %s decoding and OpenGL PBO texturing.", std::to_string(id_).c_str(), decoderName().c_str());
}
}
else
Log::Info("MediaPlayer %s Uses %s decoding and standard OpenGL texturing.", std::to_string(id_).c_str(), decoderName().c_str());
glBindTexture(GL_TEXTURE_2D, 0);
}
@@ -1204,6 +1310,49 @@ void MediaPlayer::fill_texture(guint index)
init_texture(index);
}
else if (!isImage()) {
#ifdef USE_GST_OPENGL_SYNC_HANDLER
// Try GLMemory fast path first (zero-copy GPU texture)
if (use_gl_memory_ && frame_[index].buffer) {
GstMemory *mem = gst_buffer_peek_memory(frame_[index].buffer, 0);
if (mem && gst_is_gl_memory(mem)) {
// FAST PATH: Direct GL texture extraction from GStreamer
GstGLMemory *gl_mem = (GstGLMemory*) mem;
guint gst_tex_id = gst_gl_memory_get_texture_id(gl_mem);
if (gst_tex_id > 0) {
// Use FBO to copy from GStreamer's texture to our texture
// This ensures we maintain ownership and texture lifecycle
GLuint fbo;
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
GL_TEXTURE_2D, gst_tex_id, 0);
glBindTexture(GL_TEXTURE_2D, textureindex_);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0,
media_.width, media_.height);
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
glDeleteFramebuffers(1, &fbo);
// Success - no need for CPU path
return;
}
}
else {
// First buffer is not GLMemory - disable GLMemory optimization for this source
// This happens with images, some network streams, or when glupload fails
use_gl_memory_ = false;
Log::Info("MediaPlayer %s GLMemory not available, falling back to CPU transfer.",
std::to_string(id_).c_str());
}
}
#endif
// FALLBACK: CPU path (standard PBO or direct upload)
// Use GST mapping to access pointer to RGBA data
GstMapInfo map;
gst_buffer_map(frame_[index].buffer, &map, GST_MAP_READ);
@@ -1413,11 +1562,9 @@ void MediaPlayer::update()
if (need_loop && desired_state_ == GST_STATE_PLAYING) // avoid repeated call
execute_loop_command();
#ifndef IGNORE_GST_BUS_MESSAGE
GstMessage *msg = gst_bus_pop_filtered(bus_, GST_MESSAGE_ANY);
if (msg != NULL)
gst_message_unref(msg);
#endif
force_update_ = false;
}
@@ -1731,6 +1878,21 @@ GstFlowReturn MediaPlayer::callback_new_preroll (GstAppSink *sink, gpointer p)
// send frames to media player only if ready
MediaPlayer *m = static_cast<MediaPlayer *>(p);
if (m && m->opened_) {
#ifdef USE_GST_OPENGL_SYNC_HANDLER
// Debug: Log negotiated caps on first frame to verify GLMemory
if (m->use_gl_memory_) {
GstCaps *caps = gst_sample_get_caps(sample);
if (caps) {
// Check if GLMemory was actually negotiated
GstCapsFeatures *features = gst_caps_get_features(caps, 0);
if (!features || !gst_caps_features_contains(features, "memory:GLMemory")) {
m->use_gl_memory_ = false;
}
}
}
#endif
// fill frame from buffer
if ( !m->fill_frame(buf, MediaPlayer::PREROLL) )
ret = GST_FLOW_ERROR;
+6 -1
View File
@@ -18,7 +18,7 @@ class Visitor;
#define MAX_PLAY_SPEED 20.0
#define MIN_PLAY_SPEED 0.1
#define N_VFRAME 5
#define N_VFRAME 15
struct MediaInfo {
@@ -403,6 +403,11 @@ private:
guint pbo_index_, pbo_next_index_;
guint pbo_size_;
#ifdef USE_GST_OPENGL_SYNC_HANDLER
// for GLMemory optimization
bool use_gl_memory_;
#endif
// gst pipeline control
void execute_open();
void execute_play_command(bool on);
+4 -1
View File
@@ -3353,6 +3353,7 @@ void Navigator::RenderMainPannelSettings()
static bool vsync = (Settings::application.render.vsync > 0);
static bool multi = (Settings::application.render.multisampling > 0);
static bool gpu = Settings::application.render.gpu_decoding;
static bool glmemory = Settings::application.render.gst_glmemory_texturing;
static bool audio = Settings::application.accept_audio;
bool change = false;
// hardware support deserves more explanation
@@ -3371,13 +3372,14 @@ void Navigator::RenderMainPannelSettings()
change |= ImGuiToolkit::ButtonSwitch( "Audio (experimental)", &audio);
#ifndef NDEBUG
change |= ImGuiToolkit::ButtonSwitch( "Gst-GLMemory texturing", &glmemory);
change |= ImGuiToolkit::ButtonSwitch( "Vertical synchronization", &vsync);
change |= ImGuiToolkit::ButtonSwitch( "Multisample antialiasing", &multi);
#endif
if (change) {
need_restart = ( vsync != (Settings::application.render.vsync > 0) ||
multi != (Settings::application.render.multisampling > 0) ||
gpu != Settings::application.render.gpu_decoding ||
glmemory != Settings::application.render.gst_glmemory_texturing ||
audio != Settings::application.accept_audio );
}
@@ -3386,6 +3388,7 @@ void Navigator::RenderMainPannelSettings()
if (ImGui::Button( ICON_FA_POWER_OFF " Quit & restart to apply", ImVec2(ImGui::GetContentRegionAvail().x - 50, 0))) {
Settings::application.render.vsync = vsync ? 1 : 0;
Settings::application.render.multisampling = multi ? 3 : 0;
Settings::application.render.gst_glmemory_texturing = glmemory;
Settings::application.render.gpu_decoding = gpu;
Settings::application.accept_audio = audio;
if (UserInterface::manager().TryClose())
+4 -53
View File
@@ -51,6 +51,10 @@
#include <gst/gl/x11/gstgldisplay_x11.h>
#endif
#ifdef USE_GST_OPENGL_SYNC_HANDLER
#include <GLFW/glfw3native.h>
#endif
// standalone image loader
#include <stb_image.h>
@@ -168,59 +172,6 @@ void inhibitScreensaver (bool)
{}
#endif
#ifdef USE_GST_OPENGL_SYNC_HANDLER
GLFW_EXPOSE_NATIVE_X11
#include <GLFW/glfw3native.h>
//
// Discarded because not working under OSX - kept in case it would become useful
//
// Linking pipeline to the rendering instance ensures the opengl contexts
// created by gstreamer inside plugins (e.g. glsinkbin) is the same
//
static GstGLContext *global_gl_context = NULL;
static GstGLDisplay *global_display = NULL;
static GstBusSyncReply bus_sync_handler( GstBus *, GstMessage * msg, gpointer )
{
if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_NEED_CONTEXT) {
const gchar* contextType;
gst_message_parse_context_type(msg, &contextType);
if (!g_strcmp0(contextType, GST_GL_DISPLAY_CONTEXT_TYPE)) {
GstContext *displayContext = gst_context_new(GST_GL_DISPLAY_CONTEXT_TYPE, TRUE);
gst_context_set_gl_display(displayContext, global_display);
gst_element_set_context(GST_ELEMENT(msg->src), displayContext);
gst_context_unref (displayContext);
g_info ("Managed %s\n", contextType);
}
if (!g_strcmp0(contextType, "gst.gl.app_context")) {
GstContext *appContext = gst_context_new("gst.gl.app_context", TRUE);
GstStructure* structure = gst_context_writable_structure(appContext);
gst_structure_set(structure, "context", GST_TYPE_GL_CONTEXT, global_gl_context, nullptr);
gst_element_set_context(GST_ELEMENT(msg->src), appContext);
gst_context_unref (appContext);
g_info ("Managed %s\n", contextType);
}
}
gst_message_unref (msg);
return GST_BUS_DROP;
}
void Rendering::LinkPipeline( GstPipeline *pipeline )
{
// capture bus signals to force a unique opengl context for all GST elements
GstBus* m_bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
gst_bus_set_sync_handler (m_bus, (GstBusSyncHandler) bus_sync_handler, pipeline, NULL);
gst_object_unref (m_bus);
}
#endif
bool openGLExtensionAvailable(const char *extensionname)
{
+5 -2
View File
@@ -170,8 +170,9 @@ public:
static bool shouldHaveEnoughMemory(glm::vec3 resolution, int flags);
#ifdef USE_GST_OPENGL_SYNC_HANDLER
// for opengl pipeline in gstreamer
static void LinkPipeline( GstPipeline *pipeline );
// for opengl pipeline in gstreamer
GstGLContext *global_gl_context;
GstGLDisplay *global_display;
#endif
protected:
@@ -202,6 +203,8 @@ private:
Screenshot screenshot_;
bool request_screenshot_;
};
+2
View File
@@ -211,6 +211,7 @@ void Settings::Save(uint64_t runtime, const std::string &filename)
RenderNode->SetAttribute("vsync", application.render.vsync);
RenderNode->SetAttribute("multisampling", application.render.multisampling);
RenderNode->SetAttribute("gpu_decoding", application.render.gpu_decoding);
RenderNode->SetAttribute("gst_glmemory_texturing", application.render.gst_glmemory_texturing);
RenderNode->SetAttribute("ratio", application.render.ratio);
RenderNode->SetAttribute("res", application.render.res);
RenderNode->SetAttribute("custom_width", application.render.custom_width);
@@ -567,6 +568,7 @@ void Settings::Load(const std::string &filename)
rendernode->QueryIntAttribute("vsync", &application.render.vsync);
rendernode->QueryIntAttribute("multisampling", &application.render.multisampling);
rendernode->QueryBoolAttribute("gpu_decoding", &application.render.gpu_decoding);
rendernode->QueryBoolAttribute("gst_glmemory_texturing", &application.render.gst_glmemory_texturing);
rendernode->QueryIntAttribute("ratio", &application.render.ratio);
rendernode->QueryIntAttribute("res", &application.render.res);
rendernode->QueryIntAttribute("custom_width", &application.render.custom_width);
+2
View File
@@ -197,6 +197,7 @@ struct RenderConfig
float fading;
bool gpu_decoding;
bool gpu_decoding_available;
bool gst_glmemory_texturing;
RenderConfig() {
disabled = false;
@@ -209,6 +210,7 @@ struct RenderConfig
fading = 0.0;
gpu_decoding = true;
gpu_decoding_available = false;
gst_glmemory_texturing = true;
}
};
+2 -9
View File
@@ -333,13 +333,9 @@ void Stream::execute_open()
gst_base_sink_set_sync (GST_BASE_SINK(sink), !live_);
bus_ = gst_element_get_bus(pipeline_);
#ifdef IGNORE_GST_BUS_MESSAGE
// avoid filling up bus with messages
gst_bus_set_flushing(bus_, true);
#else
// set message handler for the pipeline's bus
gst_bus_set_sync_handler(bus_, stream_signal_handler, this, NULL);
#endif
// all good
Log::Info("Stream %s Opened '%s' (%d x %d)", std::to_string(id_).c_str(), description.c_str(), width_, height_);
@@ -392,7 +388,6 @@ void Stream::pipeline_terminate( GstElement *p, GstBus *b )
if (ret == GST_STATE_CHANGE_ASYNC)
gst_element_get_state (p, NULL, NULL, 1000000);
#ifndef IGNORE_GST_BUS_MESSAGE
// empty pipeline bus (if used)
GstMessage *msg = NULL;
do {
@@ -400,7 +395,7 @@ void Stream::pipeline_terminate( GstElement *p, GstBus *b )
gst_message_unref (msg);
msg = gst_bus_timed_pop_filtered(b, 1000000, GST_MESSAGE_ANY);
} while (msg != NULL);
#endif
// unref bus
gst_object_unref( GST_OBJECT(b) );
@@ -796,11 +791,9 @@ void Stream::update()
play(false);
}
#ifndef IGNORE_GST_BUS_MESSAGE
GstMessage *msg = gst_bus_pop_filtered(bus_, GST_MESSAGE_ANY);
if (msg != NULL)
gst_message_unref(msg);
#endif
}
double Stream::updateFrameRate() const