mirror of
https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs.git
synced 2025-09-08 12:37:46 +00:00
video/gtk4: Initial colorimetry support
Similar to GtkGstSink. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-rs/-/merge_requests/2022>
This commit is contained in:
parent
85455c937f
commit
6450381017
3 changed files with 109 additions and 20 deletions
|
@ -388,7 +388,7 @@ foreach glib_version : glib_versions
|
||||||
endforeach
|
endforeach
|
||||||
|
|
||||||
if get_option('gtk4').allowed() and gtk_dep.found()
|
if get_option('gtk4').allowed() and gtk_dep.found()
|
||||||
gtk4_versions = ['4.16','4.14','4.12','4.10']
|
gtk4_versions = ['4.20','4.18','4.16','4.14','4.12','4.10']
|
||||||
foreach gtk4_version : gtk4_versions
|
foreach gtk4_version : gtk4_versions
|
||||||
if gtk_dep.version().version_compare(f'>=@gtk4_version@')
|
if gtk_dep.version().version_compare(f'>=@gtk4_version@')
|
||||||
found_features += {'gtk': 'gtk_v' + gtk4_version.underscorify()}
|
found_features += {'gtk': 'gtk_v' + gtk4_version.underscorify()}
|
||||||
|
|
|
@ -56,6 +56,8 @@ gtk_v4_10 = ["gtk/v4_10"]
|
||||||
gtk_v4_12 = ["gtk/v4_12", "gtk_v4_10"]
|
gtk_v4_12 = ["gtk/v4_12", "gtk_v4_10"]
|
||||||
gtk_v4_14 = ["gtk/v4_14", "gtk_v4_12"]
|
gtk_v4_14 = ["gtk/v4_14", "gtk_v4_12"]
|
||||||
gtk_v4_16 = ["gtk/v4_16", "gtk_v4_14"]
|
gtk_v4_16 = ["gtk/v4_16", "gtk_v4_14"]
|
||||||
|
gtk_v4_18 = ["gtk/v4_18", "gtk_v4_16"]
|
||||||
|
gtk_v4_20 = ["gtk/v4_20", "gtk_v4_18"]
|
||||||
|
|
||||||
[package.metadata.capi]
|
[package.metadata.capi]
|
||||||
min_version = "0.9.21"
|
min_version = "0.9.21"
|
||||||
|
|
|
@ -241,6 +241,40 @@ fn video_format_to_memory_format(f: gst_video::VideoFormat) -> gdk::MemoryFormat
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "gtk_v4_20")]
|
||||||
|
fn colorimetry_to_color_state(colorimetry: gst_video::VideoColorimetry) -> Option<gdk::ColorState> {
|
||||||
|
// Ignore incomplete colorimetries and fall back to format dependent default color states in
|
||||||
|
// GTK. This should make it easier to detect buggy sources and avoid confusing and unexpected
|
||||||
|
// output.
|
||||||
|
if colorimetry.primaries() == gst_video::VideoColorPrimaries::Unknown
|
||||||
|
|| colorimetry.transfer() == gst_video::VideoTransferFunction::Unknown
|
||||||
|
|| colorimetry.matrix() == gst_video::VideoColorMatrix::Unknown
|
||||||
|
|| colorimetry.range() == gst_video::VideoColorRange::Unknown
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let color_params = gdk::CicpParams::new();
|
||||||
|
|
||||||
|
color_params.set_color_primaries(colorimetry.primaries().to_iso());
|
||||||
|
color_params.set_transfer_function(colorimetry.transfer().to_iso());
|
||||||
|
color_params.set_matrix_coefficients(colorimetry.matrix().to_iso());
|
||||||
|
|
||||||
|
match colorimetry.range() {
|
||||||
|
gst_video::VideoColorRange::Range0_255 => color_params.set_range(gdk::CicpRange::Full),
|
||||||
|
gst_video::VideoColorRange::Range16_235 => color_params.set_range(gdk::CicpRange::Narrow),
|
||||||
|
_ => panic!("Unhandled range"),
|
||||||
|
}
|
||||||
|
|
||||||
|
match color_params.build_color_state() {
|
||||||
|
Ok(color_state) => Some(color_state),
|
||||||
|
Err(error) => {
|
||||||
|
println!("Could not build color state: {}", error);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn video_frame_to_memory_texture(
|
fn video_frame_to_memory_texture(
|
||||||
frame: gst_video::VideoFrame<gst_video::video_frame::Readable>,
|
frame: gst_video::VideoFrame<gst_video::video_frame::Readable>,
|
||||||
cached_textures: &mut HashMap<TextureCacheId, gdk::Texture>,
|
cached_textures: &mut HashMap<TextureCacheId, gdk::Texture>,
|
||||||
|
@ -261,14 +295,36 @@ fn video_frame_to_memory_texture(
|
||||||
let height = frame.height();
|
let height = frame.height();
|
||||||
let rowstride = frame.plane_stride()[0] as usize;
|
let rowstride = frame.plane_stride()[0] as usize;
|
||||||
|
|
||||||
let texture = gdk::MemoryTexture::new(
|
let texture = {
|
||||||
width as i32,
|
#[cfg(feature = "gtk_v4_20")]
|
||||||
height as i32,
|
{
|
||||||
format,
|
let info = frame.info().clone();
|
||||||
&glib::Bytes::from_owned(FrameWrapper(frame)),
|
|
||||||
rowstride,
|
let mut builder = gdk::MemoryTextureBuilder::new()
|
||||||
)
|
.set_width(width as i32)
|
||||||
.upcast::<gdk::Texture>();
|
.set_height(height as i32)
|
||||||
|
.set_format(format)
|
||||||
|
.set_bytes(Some(&glib::Bytes::from_owned(FrameWrapper(frame))))
|
||||||
|
.set_stride(rowstride);
|
||||||
|
|
||||||
|
if let Some(color_state) = colorimetry_to_color_state(info.colorimetry()) {
|
||||||
|
builder = builder.set_color_state(&color_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.build()
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "gtk_v4_20"))]
|
||||||
|
{
|
||||||
|
gdk::MemoryTexture::new(
|
||||||
|
width as i32,
|
||||||
|
height as i32,
|
||||||
|
format,
|
||||||
|
&glib::Bytes::from_owned(FrameWrapper(frame)),
|
||||||
|
rowstride,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.upcast::<gdk::Texture>()
|
||||||
|
};
|
||||||
|
|
||||||
cached_textures.insert(TextureCacheId::Memory(ptr), texture.clone());
|
cached_textures.insert(TextureCacheId::Memory(ptr), texture.clone());
|
||||||
used_textures.insert(TextureCacheId::Memory(ptr));
|
used_textures.insert(TextureCacheId::Memory(ptr));
|
||||||
|
@ -345,17 +401,40 @@ fn video_frame_to_gl_texture(
|
||||||
};
|
};
|
||||||
let sync_point = (*sync_meta.as_ptr()).data;
|
let sync_point = (*sync_meta.as_ptr()).data;
|
||||||
|
|
||||||
gdk::GLTextureBuilder::new()
|
let builder = {
|
||||||
.set_context(Some(gdk_context))
|
#[cfg(feature = "gtk_v4_20")]
|
||||||
.set_id(texture_id as u32)
|
{
|
||||||
.set_width(width as i32)
|
let mut mut_builder = gdk::GLTextureBuilder::new()
|
||||||
.set_height(height as i32)
|
.set_context(Some(gdk_context))
|
||||||
.set_format(format)
|
.set_id(texture_id as u32)
|
||||||
.set_sync(Some(sync_point))
|
.set_width(width as i32)
|
||||||
.build_with_release_func(move || {
|
.set_height(height as i32)
|
||||||
// Unmap and drop the GStreamer GL texture once GTK is done with it and not earlier
|
.set_format(format)
|
||||||
drop(frame);
|
.set_sync(Some(sync_point));
|
||||||
})
|
|
||||||
|
if let Some(color_state) =
|
||||||
|
colorimetry_to_color_state(frame.info().colorimetry())
|
||||||
|
{
|
||||||
|
mut_builder = mut_builder.set_color_state(&color_state);
|
||||||
|
}
|
||||||
|
mut_builder
|
||||||
|
}
|
||||||
|
#[cfg(not(feature = "gtk_v4_20"))]
|
||||||
|
{
|
||||||
|
gdk::GLTextureBuilder::new()
|
||||||
|
.set_context(Some(gdk_context))
|
||||||
|
.set_id(texture_id as u32)
|
||||||
|
.set_width(width as i32)
|
||||||
|
.set_height(height as i32)
|
||||||
|
.set_format(format)
|
||||||
|
.set_sync(Some(sync_point))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
builder.build_with_release_func(move || {
|
||||||
|
// Unmap and drop the GStreamer GL texture once GTK is done with it and not earlier
|
||||||
|
drop(frame);
|
||||||
|
})
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "gtk_v4_12"))]
|
#[cfg(not(feature = "gtk_v4_12"))]
|
||||||
{
|
{
|
||||||
|
@ -409,6 +488,14 @@ fn video_frame_to_dmabuf_texture(
|
||||||
.set_width(width)
|
.set_width(width)
|
||||||
.set_height(height)
|
.set_height(height)
|
||||||
.set_n_planes(n_planes);
|
.set_n_planes(n_planes);
|
||||||
|
|
||||||
|
#[cfg(feature = "gtk_v4_20")]
|
||||||
|
{
|
||||||
|
if let Some(color_state) = colorimetry_to_color_state(info.colorimetry()) {
|
||||||
|
builder = builder.set_color_state(Some(color_state).as_ref());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for plane in 0..(n_planes as usize) {
|
for plane in 0..(n_planes as usize) {
|
||||||
unsafe {
|
unsafe {
|
||||||
builder = builder.set_fd(plane as u32, fds[plane]);
|
builder = builder.set_fd(plane as u32, fds[plane]);
|
||||||
|
|
Loading…
Reference in a new issue