video/gtk4: Copy non-contiguous sysmem buffers

As the texture builder only supports contiguous buffers. This follows
the gtkgstsink implementation.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/2271>
This commit is contained in:
Robert Mader 2025-07-03 03:42:24 +02:00 committed by GStreamer Marge Bot
parent d2308a964e
commit 7b561354eb
2 changed files with 45 additions and 11 deletions

View file

@ -9,9 +9,10 @@
//
// SPDX-License-Identifier: MPL-2.0
use gst_video::prelude::*;
use crate::sink::imp::PaintableSink;
use crate::sink::imp::CAT;
use gst_gl::prelude::*;
use gst_video::subclass::prelude::*;
use gtk::{gdk, glib};
use std::{
collections::{HashMap, HashSet},
@ -692,6 +693,7 @@ impl Frame {
impl Frame {
pub(crate) fn new(
dbg_obj: &PaintableSink,
buffer: &gst::Buffer,
info: &VideoInfo,
orientation: Orientation,
@ -809,11 +811,44 @@ impl Frame {
let mut frame = Self {
frame: match frame {
Some(frame) => frame,
None => MappedFrame::SysMem {
frame: gst_video::VideoFrame::from_buffer_readable(buffer.clone(), info)
.map_err(|_| gst::FlowError::Error)?,
orientation,
},
None => {
let readable_frame = match buffer.n_memory() {
1 => buffer.clone(),
_ => {
gst::debug!(CAT, imp = dbg_obj, "Buffer is not contiguous, copying");
let mut copy_buffer = gst::Buffer::with_size(info.size()).unwrap();
{
let copy_buffer = copy_buffer.get_mut().unwrap();
buffer
.copy_into(copy_buffer, gst::BUFFER_COPY_METADATA, 0..0)
.unwrap();
let frame = gst_video::VideoFrameRef::from_buffer_ref_readable(
buffer, info,
)
.unwrap();
let mut copy_frame =
gst_video::VideoFrameRef::from_buffer_ref_writable(
copy_buffer,
info,
)
.unwrap();
frame.copy(&mut copy_frame).unwrap();
}
copy_buffer
}
};
MappedFrame::SysMem {
frame: gst_video::VideoFrame::from_buffer_readable(readable_frame, info)
.map_err(|_| gst::FlowError::Error)?,
orientation,
}
}
},
overlays: vec![],
};

View file

@ -719,11 +719,10 @@ impl VideoSinkImpl for PaintableSink {
}
}
};
let frame = Frame::new(buffer, info, orientation, wrapped_context.as_ref()).inspect_err(
|_err| {
let frame = Frame::new(self, buffer, info, orientation, wrapped_context.as_ref())
.inspect_err(|_err| {
gst::error!(CAT, imp = self, "Failed to map video frame");
},
)?;
})?;
self.pending_frame.lock().unwrap().replace(frame);
let sender = self.sender.lock().unwrap();