Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/sdroege/gst-plugin-rs.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/video
diff options
context:
space:
mode:
authorSebastian Dröge <sebastian@centricular.com>2022-11-30 12:55:05 +0300
committerSebastian Dröge <sebastian@centricular.com>2022-11-30 12:59:53 +0300
commit599d3a4d8a03ff96efb17076a0da1646c681920c (patch)
tree4f19e7b09d000679b2e61e06c41f9ef74930020c /video
parent975f0141be9353e3334c6df36d388fce97acf337 (diff)
gtk4: Make GL support fully optional
Don't depend on gstreamer-gl if it's not enabled, and don't try doing anything with the GDK GL context at all. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/995>
Diffstat (limited to 'video')
-rw-r--r--video/gtk4/Cargo.toml8
-rw-r--r--video/gtk4/src/sink/frame.rs123
-rw-r--r--video/gtk4/src/sink/imp.rs185
3 files changed, 189 insertions, 127 deletions
diff --git a/video/gtk4/Cargo.toml b/video/gtk4/Cargo.toml
index f7f3388c..f92eb322 100644
--- a/video/gtk4/Cargo.toml
+++ b/video/gtk4/Cargo.toml
@@ -16,7 +16,7 @@ gdk_x11 = { package = "gdk4-x11", git = "https://github.com/gtk-rs/gtk4-rs", fea
gst = { package = "gstreamer", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", features = ["v1_16"] }
gst_base = { package = "gstreamer-base", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" }
gst_video = { package = "gstreamer-video", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs" }
-gst_gl = { package = "gstreamer-gl", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", features = ["v1_16"] }
+gst_gl = { package = "gstreamer-gl", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", features = ["v1_16"], optional = true }
gst_gl_wayland = { package = "gstreamer-gl-wayland", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", features = ["v1_16"], optional = true }
gst_gl_x11 = { package = "gstreamer-gl-x11", git = "https://gitlab.freedesktop.org/gstreamer/gstreamer-rs", features = ["v1_16"], optional = true }
@@ -36,9 +36,9 @@ gst-plugin-version-helper = { path="../../version-helper" }
[features]
default = []
static = []
-wayland = ["gdk_wayland", "gst_gl_wayland"]
-x11glx = ["gdk_x11", "gst_gl_x11"]
-x11egl = ["gdk_x11", "gst_gl_egl"]
+wayland = ["gdk_wayland", "gst_gl", "gst_gl_wayland"]
+x11glx = ["gdk_x11", "gst_gl", "gst_gl_x11"]
+x11egl = ["gdk_x11", "gst_gl", "gst_gl_egl"]
capi = []
doc = ["gst/v1_18"]
diff --git a/video/gtk4/src/sink/frame.rs b/video/gtk4/src/sink/frame.rs
index 119bed37..430150ae 100644
--- a/video/gtk4/src/sink/frame.rs
+++ b/video/gtk4/src/sink/frame.rs
@@ -9,6 +9,9 @@
//
// SPDX-License-Identifier: MPL-2.0
+use gst_video::prelude::*;
+
+#[cfg(feature = "gst_gl")]
use gst_gl::prelude::*;
use gtk::{gdk, glib};
use std::collections::{HashMap, HashSet};
@@ -17,6 +20,7 @@ use std::collections::{HashMap, HashSet};
pub(crate) struct Frame {
frame: gst_video::VideoFrame<gst_video::video_frame::Readable>,
overlays: Vec<Overlay>,
+ #[cfg(feature = "gst_gl")]
gst_context: Option<gst_gl::GLContext>,
}
@@ -90,6 +94,7 @@ fn video_frame_to_memory_texture(
(texture, pixel_aspect_ratio)
}
+#[cfg(feature = "gst_gl")]
fn video_frame_to_gl_texture(
frame: &gst_video::VideoFrame<gst_video::video_frame::Readable>,
cached_textures: &mut HashMap<usize, gdk::Texture>,
@@ -127,7 +132,7 @@ fn video_frame_to_gl_texture(
impl Frame {
pub(crate) fn into_textures(
self,
- gdk_context: Option<&gdk::GLContext>,
+ #[allow(unused_variables)] gdk_context: Option<&gdk::GLContext>,
cached_textures: &mut HashMap<usize, gdk::Texture>,
) -> Vec<Texture> {
let mut textures = Vec::with_capacity(1 + self.overlays.len());
@@ -135,18 +140,26 @@ impl Frame {
let width = self.frame.width();
let height = self.frame.height();
- let (texture, pixel_aspect_ratio) =
- if let (Some(gdk_ctx), Some(gst_ctx)) = (gdk_context, self.gst_context.as_ref()) {
- video_frame_to_gl_texture(
- &self.frame,
- cached_textures,
- &mut used_textures,
- gdk_ctx,
- gst_ctx,
- )
- } else {
+ let (texture, pixel_aspect_ratio) = {
+ #[cfg(not(feature = "gst_gl"))]
+ {
video_frame_to_memory_texture(self.frame, cached_textures, &mut used_textures)
- };
+ }
+ #[cfg(feature = "gst_gl")]
+ {
+ if let (Some(gdk_ctx), Some(gst_ctx)) = (gdk_context, self.gst_context.as_ref()) {
+ video_frame_to_gl_texture(
+ &self.frame,
+ cached_textures,
+ &mut used_textures,
+ gdk_ctx,
+ gst_ctx,
+ )
+ } else {
+ video_frame_to_memory_texture(self.frame, cached_textures, &mut used_textures)
+ }
+ }
+ };
textures.push(Texture {
texture,
@@ -182,47 +195,67 @@ impl Frame {
pub(crate) fn new(
buffer: &gst::Buffer,
info: &gst_video::VideoInfo,
- have_gl_context: bool,
+ #[allow(unused_variables)] have_gl_context: bool,
) -> Result<Self, gst::FlowError> {
- let mut gst_context = None;
-
// Empty buffers get filtered out in show_frame
debug_assert!(buffer.n_memory() > 0);
- let is_buffer_gl = buffer
- .peek_memory(0)
- .downcast_memory_ref::<gst_gl::GLBaseMemory>()
- .is_some();
+ let mut frame;
- let frame = if !is_buffer_gl || !have_gl_context {
- gst_video::VideoFrame::from_buffer_readable(buffer.clone(), info)
- .map_err(|_| gst::FlowError::Error)?
- } else {
- let gst_ctx = buffer
+ #[cfg(not(feature = "gst_gl"))]
+ {
+ frame = Self {
+ frame: gst_video::VideoFrame::from_buffer_readable(buffer.clone(), info)
+ .map_err(|_| gst::FlowError::Error)?,
+ overlays: vec![],
+ };
+ }
+ #[cfg(feature = "gst_gl")]
+ {
+ let is_buffer_gl = buffer
.peek_memory(0)
.downcast_memory_ref::<gst_gl::GLBaseMemory>()
- .map(|m| m.context())
- .expect("Failed to retrieve the GstGL Context.");
-
- gst_context = Some(gst_ctx.clone());
-
- if let Some(meta) = buffer.meta::<gst_gl::GLSyncMeta>() {
- meta.set_sync_point(gst_ctx);
- gst_video::VideoFrame::from_buffer_readable_gl(buffer.clone(), info)
- .map_err(|_| gst::FlowError::Error)?
+ .is_some();
+
+ if !is_buffer_gl || !have_gl_context {
+ frame = Self {
+ frame: gst_video::VideoFrame::from_buffer_readable(buffer.clone(), info)
+ .map_err(|_| gst::FlowError::Error)?,
+ overlays: vec![],
+ gst_context: None,
+ };
} else {
- let mut buffer = buffer.clone();
- {
- let buffer = buffer.make_mut();
- let meta = gst_gl::GLSyncMeta::add(buffer, gst_ctx);
+ let gst_ctx = buffer
+ .peek_memory(0)
+ .downcast_memory_ref::<gst_gl::GLBaseMemory>()
+ .map(|m| m.context())
+ .expect("Failed to retrieve the GstGL Context.");
+
+ let mapped_frame = if let Some(meta) = buffer.meta::<gst_gl::GLSyncMeta>() {
meta.set_sync_point(gst_ctx);
- }
- gst_video::VideoFrame::from_buffer_readable_gl(buffer, info)
- .map_err(|_| gst::FlowError::Error)?
+ gst_video::VideoFrame::from_buffer_readable_gl(buffer.clone(), info)
+ .map_err(|_| gst::FlowError::Error)?
+ } else {
+ let mut buffer = buffer.clone();
+ {
+ let buffer = buffer.make_mut();
+ let meta = gst_gl::GLSyncMeta::add(buffer, gst_ctx);
+ meta.set_sync_point(gst_ctx);
+ }
+ gst_video::VideoFrame::from_buffer_readable_gl(buffer, info)
+ .map_err(|_| gst::FlowError::Error)?
+ };
+
+ frame = Self {
+ frame: mapped_frame,
+ overlays: vec![],
+ gst_context: Some(gst_ctx.clone()),
+ };
}
- };
+ }
- let overlays = frame
+ frame.overlays = frame
+ .frame
.buffer()
.iter_meta::<gst_video::VideoOverlayCompositionMeta>()
.flat_map(|meta| {
@@ -258,10 +291,6 @@ impl Frame {
})
.collect();
- Ok(Self {
- frame,
- overlays,
- gst_context,
- })
+ Ok(frame)
}
}
diff --git a/video/gtk4/src/sink/imp.rs b/video/gtk4/src/sink/imp.rs
index 0a690ab4..ad436af5 100644
--- a/video/gtk4/src/sink/imp.rs
+++ b/video/gtk4/src/sink/imp.rs
@@ -13,25 +13,29 @@ use super::SinkEvent;
use crate::sink::frame::Frame;
use crate::sink::paintable::Paintable;
-use glib::translate::*;
use glib::Sender;
use gtk::prelude::*;
use gtk::{gdk, glib};
-use gst::prelude::*;
use gst::subclass::prelude::*;
use gst_base::subclass::prelude::*;
-use gst_gl::prelude::GLContextExt as GstGLContextExt;
-use gst_gl::prelude::*;
use gst_video::subclass::prelude::*;
use once_cell::sync::Lazy;
-use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Mutex, MutexGuard};
use crate::utils;
use fragile::Fragile;
+#[cfg(feature = "gst_gl")]
+use glib::translate::*;
+#[cfg(feature = "gst_gl")]
+use gst_gl::prelude::GLContextExt as GstGLContextExt;
+#[cfg(feature = "gst_gl")]
+use gst_gl::prelude::*;
+#[cfg(feature = "gst_gl")]
+use std::sync::atomic::{AtomicBool, Ordering};
+
static CAT: Lazy<gst::DebugCategory> = Lazy::new(|| {
gst::DebugCategory::new(
"gstgtk4paintablesink",
@@ -46,10 +50,14 @@ pub struct PaintableSink {
info: Mutex<Option<gst_video::VideoInfo>>,
sender: Mutex<Option<Sender<SinkEvent>>>,
pending_frame: Mutex<Option<Frame>>,
+ #[cfg(feature = "gst_gl")]
gst_display: Mutex<Option<gst_gl::GLDisplay>>,
+ #[cfg(feature = "gst_gl")]
gst_app_context: Mutex<Option<gst_gl::GLContext>>,
+ #[cfg(feature = "gst_gl")]
gst_context: Mutex<Option<gst_gl::GLContext>>,
cached_caps: Mutex<Option<gst::Caps>>,
+ #[cfg(feature = "gst_gl")]
have_gl_context: AtomicBool,
}
@@ -274,78 +282,87 @@ impl BaseSinkImpl for PaintableSink {
// TODO: Provide a preferred "window size" here for higher-resolution rendering
query.add_allocation_meta::<gst_video::VideoOverlayCompositionMeta>(None);
+ #[cfg(not(feature = "gst_gl"))]
{
- // Early return if there is no context initialized
- let gst_context_guard = self.gst_context.lock().unwrap();
- if gst_context_guard.is_none() {
- gst::debug!(
- CAT,
- imp: self,
- "Found no GL Context during propose_allocation."
- );
- return Ok(());
- }
+ Ok(())
}
- // GL specific things
- let (caps, need_pool) = query.get_owned();
+ #[cfg(feature = "gst_gl")]
+ {
+ {
+ // Early return if there is no context initialized
+ let gst_context_guard = self.gst_context.lock().unwrap();
+ if gst_context_guard.is_none() {
+ gst::debug!(
+ CAT,
+ imp: self,
+ "Found no GL Context during propose_allocation."
+ );
+ return Ok(());
+ }
+ }
- if caps.is_empty() {
- return Err(gst::loggable_error!(CAT, "No caps where specified."));
- }
+ // GL specific things
+ let (caps, need_pool) = query.get_owned();
- if let Some(f) = caps.features(0) {
- if !f.contains("memory:GLMemory") {
- gst::debug!(
- CAT,
- imp: self,
- "No 'memory:GLMemory' feature in caps: {}",
- caps
- )
+ if caps.is_empty() {
+ return Err(gst::loggable_error!(CAT, "No caps where specified."));
+ }
+
+ if let Some(f) = caps.features(0) {
+ if !f.contains("memory:GLMemory") {
+ gst::debug!(
+ CAT,
+ imp: self,
+ "No 'memory:GLMemory' feature in caps: {}",
+ caps
+ )
+ }
}
- }
- let info = gst_video::VideoInfo::from_caps(&caps)
- .map_err(|_| gst::loggable_error!(CAT, "Failed to get VideoInfo from caps"))?;
+ let info = gst_video::VideoInfo::from_caps(&caps)
+ .map_err(|_| gst::loggable_error!(CAT, "Failed to get VideoInfo from caps"))?;
- let size = info.size() as u32;
+ let size = info.size() as u32;
- {
- let gst_context = { self.gst_context.lock().unwrap().clone().unwrap() };
- let buffer_pool = gst_gl::GLBufferPool::new(&gst_context);
+ {
+ let gst_context = { self.gst_context.lock().unwrap().clone().unwrap() };
+ let buffer_pool = gst_gl::GLBufferPool::new(&gst_context);
- if need_pool {
- gst::debug!(CAT, imp: self, "Creating new Pool");
+ if need_pool {
+ gst::debug!(CAT, imp: self, "Creating new Pool");
- let mut config = buffer_pool.config();
- config.set_params(Some(&caps), size, 0, 0);
- config.add_option("GstBufferPoolOptionGLSyncMeta");
+ let mut config = buffer_pool.config();
+ config.set_params(Some(&caps), size, 0, 0);
+ config.add_option("GstBufferPoolOptionGLSyncMeta");
- if let Err(err) = buffer_pool.set_config(config) {
- return Err(gst::loggable_error!(
- CAT,
- format!("Failed to set config in the GL BufferPool.: {}", err)
- ));
+ if let Err(err) = buffer_pool.set_config(config) {
+ return Err(gst::loggable_error!(
+ CAT,
+ format!("Failed to set config in the GL BufferPool.: {}", err)
+ ));
+ }
}
- }
- // we need at least 2 buffer because we hold on to the last one
- query.add_allocation_pool(Some(&buffer_pool), size, 2, 0);
+ // we need at least 2 buffer because we hold on to the last one
+ query.add_allocation_pool(Some(&buffer_pool), size, 2, 0);
- if gst_context.check_feature("GL_ARB_sync")
- || gst_context.check_feature("GL_EXT_EGL_sync")
- {
- query.add_allocation_meta::<gst_gl::GLSyncMeta>(None)
+ if gst_context.check_feature("GL_ARB_sync")
+ || gst_context.check_feature("GL_EXT_EGL_sync")
+ {
+ query.add_allocation_meta::<gst_gl::GLSyncMeta>(None)
+ }
}
- }
- Ok(())
+ Ok(())
+ }
}
fn query(&self, query: &mut gst::QueryRef) -> bool {
gst::log!(CAT, imp: self, "Handling query {:?}", query);
match query.view_mut() {
+ #[cfg(feature = "gst_gl")]
gst::QueryViewMut::Context(q) => {
// Avoid holding the locks while we respond to the query
// The objects are ref-counted anyway.
@@ -396,11 +413,20 @@ impl VideoSinkImpl for PaintableSink {
gst::FlowError::NotNegotiated
})?;
- let frame = Frame::new(buffer, info, self.have_gl_context.load(Ordering::Relaxed))
- .map_err(|err| {
- gst::error!(CAT, imp: self, "Failed to map video frame");
- err
- })?;
+ let have_gl_context = {
+ #[cfg(not(feature = "gst_gl"))]
+ {
+ false
+ }
+ #[cfg(feature = "gst_gl")]
+ {
+ self.have_gl_context.load(Ordering::Relaxed)
+ }
+ };
+ let frame = Frame::new(buffer, info, have_gl_context).map_err(|err| {
+ gst::error!(CAT, imp: self, "Failed to map video frame");
+ err
+ })?;
self.pending_frame.lock().unwrap().replace(frame);
let sender = self.sender.lock().unwrap();
@@ -441,15 +467,19 @@ impl PaintableSink {
}
fn configure_caps(&self) {
+ #[allow(unused_mut)]
let mut tmp_caps = Self::pad_templates()[0].caps().clone();
- // Filter out GL caps from the template pads if we have no context
- if !self.have_gl_context.load(Ordering::Relaxed) {
- tmp_caps = tmp_caps
- .iter_with_features()
- .filter(|(_, features)| !features.contains("memory:GLMemory"))
- .map(|(s, c)| (s.to_owned(), c.to_owned()))
- .collect::<gst::Caps>();
+ #[cfg(feature = "gst_gl")]
+ {
+ // Filter out GL caps from the template pads if we have no context
+ if !self.have_gl_context.load(Ordering::Relaxed) {
+ tmp_caps = tmp_caps
+ .iter_with_features()
+ .filter(|(_, features)| !features.contains("memory:GLMemory"))
+ .map(|(s, c)| (s.to_owned(), c.to_owned()))
+ .collect::<gst::Caps>();
+ }
}
self.cached_caps
@@ -459,18 +489,18 @@ impl PaintableSink {
}
fn create_paintable(&self, paintable_storage: &mut MutexGuard<Option<Fragile<Paintable>>>) {
- let ctx = self.realize_context();
+ #[allow(unused_mut)]
+ let mut ctx = None;
- let ctx = if let Some(c) = ctx {
- if let Ok(c) = self.initialize_gl_wrapper(c) {
- self.have_gl_context.store(true, Ordering::Relaxed);
- Some(c)
- } else {
- None
+ #[cfg(feature = "gst_gl")]
+ {
+ if let Some(c) = self.realize_context() {
+ if let Ok(c) = self.initialize_gl_wrapper(c) {
+ self.have_gl_context.store(true, Ordering::Relaxed);
+ ctx = Some(c);
+ }
}
- } else {
- None
- };
+ }
self.configure_caps();
self.initialize_paintable(ctx, paintable_storage);
@@ -505,6 +535,7 @@ impl PaintableSink {
*self.sender.lock().unwrap() = Some(sender);
}
+ #[cfg(feature = "gst_gl")]
fn realize_context(&self) -> Option<Fragile<gdk::GLContext>> {
gst::debug!(CAT, imp: self, "Realizing GDK GL Context");
@@ -551,6 +582,7 @@ impl PaintableSink {
utils::invoke_on_main_thread(cb)
}
+ #[cfg(feature = "gst_gl")]
fn initialize_gl_wrapper(
&self,
context: Fragile<gdk::GLContext>,
@@ -560,6 +592,7 @@ impl PaintableSink {
utils::invoke_on_main_thread(move || self_.imp().initialize_gl(context))
}
+ #[cfg(feature = "gst_gl")]
fn initialize_gl(
&self,
context: Fragile<gdk::GLContext>,