video/gtk4: Add YCbCr memory texture formats

In order to match gtkgstsink. GTK only handles contiguous buffers,
thus adapt the texture builder part accordingly.

TODO: fall back to a copy for non-contiguous buffers.
Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/2271>
This commit is contained in:
Robert Mader 2025-06-03 01:52:03 +02:00 committed by GStreamer Marge Bot
parent 51b8d3dc0e
commit d2308a964e
2 changed files with 106 additions and 9 deletions

View file

@ -217,12 +217,60 @@ pub(crate) struct Texture {
struct FrameWrapper(gst_video::VideoFrame<gst_video::video_frame::Readable>);
impl AsRef<[u8]> for FrameWrapper {
fn as_ref(&self) -> &[u8] {
self.0.plane_data(0).unwrap()
let raw = self.0.as_ptr();
let data = unsafe {
std::slice::from_raw_parts((*raw).map[0].data as *const u8, (*raw).map[0].size)
};
data
}
}
fn video_format_to_memory_format(f: gst_video::VideoFormat) -> gdk::MemoryFormat {
match f {
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Yuy2 => gdk::MemoryFormat::G8b8g8r8422,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Yvyu => gdk::MemoryFormat::G8r8g8b8422,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Uyvy => gdk::MemoryFormat::B8g8r8g8422,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Vyuy => gdk::MemoryFormat::R8g8b8g8422,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Nv12 => gdk::MemoryFormat::G8B8r8420,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Nv21 => gdk::MemoryFormat::G8R8b8420,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Nv16 => gdk::MemoryFormat::G8B8r8422,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Nv61 => gdk::MemoryFormat::G8R8b8422,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Nv24 => gdk::MemoryFormat::G8B8r8444,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::P01010le => gdk::MemoryFormat::G10x6B10x6r10x6420,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::P01010be => gdk::MemoryFormat::G10x6B10x6r10x6420,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::P012Le => gdk::MemoryFormat::G12x4B12x4r12x4420,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::P012Be => gdk::MemoryFormat::G12x4B12x4r12x4420,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::P016Le => gdk::MemoryFormat::G16B16r16420,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::P016Be => gdk::MemoryFormat::G16B16r16420,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Yuv9 => gdk::MemoryFormat::G8B8R8410,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Yvu9 => gdk::MemoryFormat::G8R8B8410,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Y41b => gdk::MemoryFormat::G8B8R8411,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::I420 => gdk::MemoryFormat::G8B8R8420,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Yv12 => gdk::MemoryFormat::G8R8B8420,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Y42b => gdk::MemoryFormat::G8B8R8422,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Y444 => gdk::MemoryFormat::G8B8R8444,
#[cfg(feature = "gtk_v4_14")]
gst_video::VideoFormat::Bgrx => gdk::MemoryFormat::B8g8r8x8,
#[cfg(feature = "gtk_v4_14")]
@ -312,34 +360,39 @@ fn video_frame_to_memory_texture(
let format = video_format_to_memory_format(frame.format());
let width = frame.width();
let height = frame.height();
let rowstride = frame.plane_stride()[0] as usize;
let texture = {
#[cfg(feature = "gtk_v4_20")]
{
let info = frame.info().clone();
let mut builder = gdk::MemoryTextureBuilder::new()
.set_width(width as i32)
.set_height(height as i32)
.set_format(format)
.set_bytes(Some(&glib::Bytes::from_owned(FrameWrapper(frame))))
.set_stride(rowstride);
.set_format(format);
if let Some(color_state) = videoinfo_to_color_state(&info) {
if let Some(color_state) = videoinfo_to_color_state(frame.info()) {
builder = builder.set_color_state(&color_state);
}
for plane in 0..(frame.n_planes() as usize) {
builder = builder
.set_offset(plane as u32, frame.plane_offset()[plane] as usize)
.set_stride_for_plane(plane as u32, frame.plane_stride()[plane] as usize);
}
builder = builder.set_bytes(Some(&glib::Bytes::from_owned(FrameWrapper(frame))));
builder.build()
}
#[cfg(not(feature = "gtk_v4_20"))]
{
let stride = frame.plane_stride()[0] as usize;
gdk::MemoryTexture::new(
width as i32,
height as i32,
format,
&glib::Bytes::from_owned(FrameWrapper(frame)),
rowstride,
stride,
)
}
.upcast::<gdk::Texture>()

View file

@ -296,6 +296,50 @@ impl ElementImpl for PaintableSink {
const GL_FORMATS: &[gst_video::VideoFormat] =
&[gst_video::VideoFormat::Rgba, gst_video::VideoFormat::Rgb];
const NON_GL_FORMATS: &[gst_video::VideoFormat] = &[
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Yuy2,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Yvyu,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Uyvy,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Vyuy,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Nv12,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Nv21,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Nv16,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Nv61,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Nv24,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::P01010le,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::P01010be,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::P012Le,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::P012Be,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::P016Le,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::P016Be,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Yuv9,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Yvu9,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Y41b,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::I420,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Yv12,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Y42b,
#[cfg(feature = "gtk_v4_20")]
gst_video::VideoFormat::Y444,
#[cfg(feature = "gtk_v4_14")]
gst_video::VideoFormat::Bgrx,
#[cfg(feature = "gtk_v4_14")]