Navigation Menu

Skip to content

Commit

Permalink
Get the servosrc gstreamer plugin to use a GL buffer pool
Browse files Browse the repository at this point in the history
  • Loading branch information
Alan Jeffrey committed Dec 6, 2019
1 parent 2d2cd2b commit bd1e4f8
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 21 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions ports/gstplugin/Cargo.toml
Expand Up @@ -23,6 +23,7 @@ gstreamer = { version = "0.14", features = ["subclassing"] }
gstreamer-base = { version = "0.14", features = ["subclassing"] }
gstreamer-gl = { version = "0.14" }
gstreamer-gl-sys = { version = "0.8" }
gstreamer-sys = { version = "0.8" }
gstreamer-video = { version = "0.14", features = ["subclassing"] }
log = "0.4"
lazy_static = "1.4"
Expand Down
12 changes: 6 additions & 6 deletions ports/gstplugin/README.md
Expand Up @@ -29,15 +29,14 @@ GST_PLUGIN_PATH=target/gstplugins \
! glimagesink rotate-method=vertical-flip
```

*Note*: the following don't work, for some reason the pipeline isn't providing GLMemory.

To stream over the network:
```
GST_PLUGIN_PATH=target/gstplugins \
gst-launch-1.0 servosrc \
! videorate \
! video/x-raw\(memory:GLMemory\),framerate=50/1,width=1920,height=1080,format=RGBA \
! video/x-raw\(memory:GLMemory\),framerate=50/1,width=512,height=256 \
! glcolorconvert \
! gldownload \
! videoconvert \
! videoflip video-direction=vert \
! theoraenc \
! oggmux \
Expand All @@ -47,10 +46,11 @@ To stream over the network:
To save to a file:
```
GST_PLUGIN_PATH=target/gstplugins \
gst-launch-1.0 servosrc \
! videorate \
! video/x-raw\(memory:GLMemory\),framerate=50/1,width=1920,height=1080,format=RGBA \
! video/x-raw\(memory:GLMemory\),framerate=50/1,width=512,height=256 \
! glcolorconvert \
! gldownload \
! videoconvert \
! videoflip video-direction=vert \
! theoraenc \
! oggmux \
Expand Down
78 changes: 67 additions & 11 deletions ports/gstplugin/servosrc.rs
Expand Up @@ -17,6 +17,7 @@ use glib::glib_object_impl;
use glib::glib_object_subclass;
use glib::object::Cast;
use glib::object::Object;
use glib::object::ObjectType;
use glib::subclass::object::ObjectClassSubclassExt;
use glib::subclass::object::ObjectImpl;
use glib::subclass::object::ObjectImplExt;
Expand All @@ -32,12 +33,15 @@ use gstreamer::gst_loggable_error;
use gstreamer::subclass::element::ElementClassSubclassExt;
use gstreamer::subclass::element::ElementImpl;
use gstreamer::subclass::ElementInstanceStruct;
use gstreamer::BufferRef;
use gstreamer::Buffer;
use gstreamer::BufferPool;
use gstreamer::BufferPoolExt;
use gstreamer::BufferPoolExtManual;
use gstreamer::Caps;
use gstreamer::CoreError;
use gstreamer::Element;
use gstreamer::ErrorMessage;
use gstreamer::FlowError;
use gstreamer::FlowSuccess;
use gstreamer::Format;
use gstreamer::LoggableError;
use gstreamer::PadDirection;
Expand Down Expand Up @@ -93,6 +97,7 @@ pub struct ServoSrc {
swap_chain: SwapChain,
url: Mutex<Option<String>>,
info: Mutex<Option<VideoInfo>>,
buffer_pool: Mutex<Option<BufferPool>>,
}

struct ServoSrcGfx {
Expand Down Expand Up @@ -431,11 +436,13 @@ impl ObjectSubclass for ServoSrc {
let swap_chain = ackr.recv().expect("Failed to get swap chain");
let info = Mutex::new(None);
let url = Mutex::new(None);
let buffer_pool = Mutex::new(None);
Self {
sender,
swap_chain,
info,
url,
buffer_pool,
}
}

Expand Down Expand Up @@ -498,17 +505,58 @@ thread_local! {
static GL: RefCell<Option<Rc<Gl>>> = RefCell::new(None);
}
impl BaseSrcImpl for ServoSrc {
fn set_caps(&self, _src: &BaseSrc, outcaps: &Caps) -> Result<(), LoggableError> {
fn set_caps(&self, src: &BaseSrc, outcaps: &Caps) -> Result<(), LoggableError> {
// Save the video info for later use
let info = VideoInfo::from_caps(outcaps)
.ok_or_else(|| gst_loggable_error!(CATEGORY, "Failed to get video info"))?;
*self.info.lock().unwrap() = Some(info);

// Get the downstream GL context
let mut gst_gl_context = std::ptr::null_mut();
let el = src.upcast_ref::<Element>();
unsafe {
gstreamer_gl_sys::gst_gl_query_local_gl_context(
el.as_ptr(),
gstreamer_sys::GST_PAD_SRC,
&mut gst_gl_context,
);
}
if gst_gl_context.is_null() {
return Err(gst_loggable_error!(CATEGORY, "Failed to get GL context"));
}

// Create a new buffer pool for GL memory
let gst_gl_buffer_pool =
unsafe { gstreamer_gl_sys::gst_gl_buffer_pool_new(gst_gl_context) };
if gst_gl_buffer_pool.is_null() {
return Err(gst_loggable_error!(
CATEGORY,
"Failed to create buffer pool"
));
}
let pool = unsafe { BufferPool::from_glib_borrow(gst_gl_buffer_pool) };

// Configure the buffer pool with the negotiated caps
let mut config = pool.get_config();
let (_, size, min_buffers, max_buffers) = config.get_params().unwrap_or((None, 0, 0, 1024));
config.set_params(Some(outcaps), size, min_buffers, max_buffers);
pool.set_config(config)
.map_err(|_| gst_loggable_error!(CATEGORY, "Failed to update config"))?;

// Save the buffer pool for later use
*self.buffer_pool.lock().expect("Poisoned lock") = Some(pool);

Ok(())
}

fn get_size(&self, _src: &BaseSrc) -> Option<u64> {
u64::try_from(self.info.lock().ok()?.as_ref()?.size()).ok()
}

fn is_seekable(&self, _: &BaseSrc) -> bool {
false
}

fn start(&self, _src: &BaseSrc) -> Result<(), ErrorMessage> {
info!("Starting");
let guard = self
Expand All @@ -528,13 +576,20 @@ impl BaseSrcImpl for ServoSrc {
Ok(())
}

fn fill(
&self,
src: &BaseSrc,
_offset: u64,
_length: u32,
buffer: &mut BufferRef,
) -> Result<FlowSuccess, FlowError> {
fn create(&self, src: &BaseSrc, _offset: u64, _length: u32) -> Result<Buffer, FlowError> {
// Get the buffer pool
let pool_guard = self.buffer_pool.lock().unwrap();
let pool = pool_guard.as_ref().ok_or(FlowError::NotNegotiated)?;

// Activate the pool if necessary
if !pool.is_active() {
pool.set_active(true).map_err(|_| FlowError::Error)?;
}

// Get a buffer to fill
let buffer = pool.acquire_buffer(None)?;

// Get the GL memory from the buffer
let memory = buffer.get_all_memory().ok_or_else(|| {
gst_element_error!(src, CoreError::Failed, ["Failed to get memory"]);
FlowError::Error
Expand All @@ -549,6 +604,7 @@ impl BaseSrcImpl for ServoSrc {
FlowError::Error
})?;

// Get the data out of the memory
let gl_context = unsafe { GLContext::from_glib_borrow(gl_memory.mem.context) };
let draw_texture_id = gl_memory.tex_id;
let draw_texture_target = unsafe { gst_gl_texture_target_to_gl(gl_memory.tex_target) };
Expand Down Expand Up @@ -710,6 +766,6 @@ impl BaseSrcImpl for ServoSrc {
})?;

let _ = self.sender.send(ServoSrcMsg::Heartbeat);
Ok(FlowSuccess::Ok)
Ok(buffer)
}
}
9 changes: 5 additions & 4 deletions ports/gstplugin/test.html
Expand Up @@ -5,10 +5,11 @@
<p>Start the video stream with:</p>

<pre>
gst-launch-1.0 servosrc \
! queue \
! video/x-raw,framerate=25/1,width=512,height=512 \
! videoconvert \
gst-launch-1.0 servosrc url=https://mrdoob.neocities.org/018/ \
! videorate \
! video/x-raw\(memory:GLMemory\),framerate=50/1,width=512,height=256 \
! glcolorconvert \
! gldownload \
! videoflip video-direction=vert \
! theoraenc \
! oggmux \
Expand Down

0 comments on commit bd1e4f8

Please sign in to comment.