From fef6601094e9d9a42a1239c4f575116e5d6ad27f Mon Sep 17 00:00:00 2001 From: Jerome Colle Date: Tue, 3 Sep 2024 15:07:31 +0200 Subject: [PATCH] dav1ddec: add properties for film grain synthesis and in-loop filters Part-of: --- docs/plugins/gst_plugins_cache.json | 47 ++++++++++++++++++++++- video/dav1d/src/dav1ddec/imp.rs | 59 +++++++++++++++++++++++++++++ video/dav1d/src/dav1ddec/mod.rs | 3 ++ 3 files changed, 108 insertions(+), 1 deletion(-) diff --git a/docs/plugins/gst_plugins_cache.json b/docs/plugins/gst_plugins_cache.json index 82bcfdcd..340c02e9 100644 --- a/docs/plugins/gst_plugins_cache.json +++ b/docs/plugins/gst_plugins_cache.json @@ -1603,6 +1603,30 @@ } }, "properties": { + "apply-grain": { + "blurb": "Enable out-of-loop normative film grain filter", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "false", + "mutable": "ready", + "readable": true, + "type": "gboolean", + "writable": true + }, + "inloop-filters": { + "blurb": "Flags to enable in-loop post processing filters", + "conditionally-available": false, + "construct": false, + "construct-only": false, + "controllable": false, + "default": "(none)", + "mutable": "ready", + "readable": true, + "type": "GstDav1dInloopFilterType", + "writable": true + }, "max-frame-delay": { "blurb": "Maximum delay in frames for the decoder (set to 1 for low latency, 0 to be equal to the number of logical cores. -1 to choose between these two based on pipeline liveness)", "conditionally-available": false, @@ -1637,7 +1661,28 @@ }, "filename": "gstdav1d", "license": "MIT/X11", - "other-types": {}, + "other-types": { + "GstDav1dInloopFilterType": { + "kind": "flags", + "values": [ + { + "desc": "Enable deblocking filter", + "name": "deblock", + "value": "0x00000001" + }, + { + "desc": "Enable Constrained Directional Enhancement Filter", + "name": "cdef", + "value": "0x00000002" + }, + { + "desc": "Enable loop restoration filter", + "name": "restoration", + "value": "0x00000004" + } + ] + } + }, "package": "gst-plugin-dav1d", "source": "gst-plugin-dav1d", "tracers": {}, diff --git a/video/dav1d/src/dav1ddec/imp.rs b/video/dav1d/src/dav1ddec/imp.rs index 52e9ea2f..955a8309 100644 --- a/video/dav1d/src/dav1ddec/imp.rs +++ b/video/dav1d/src/dav1ddec/imp.rs @@ -18,8 +18,40 @@ use once_cell::sync::Lazy; use std::sync::{Mutex, MutexGuard}; +#[glib::flags(name = "GstDav1dInloopFilterType")] +pub(crate) enum InloopFilterType { + #[flags_value(name = "Enable deblocking filter", nick = "deblock")] + DEBLOCK = dav1d::InloopFilterType::DEBLOCK.bits(), + #[flags_value( + name = "Enable Constrained Directional Enhancement Filter", + nick = "cdef" + )] + CDEF = dav1d::InloopFilterType::CDEF.bits(), + #[flags_value(name = "Enable loop restoration filter", nick = "restoration")] + RESTORATION = dav1d::InloopFilterType::RESTORATION.bits(), +} + +impl From for dav1d::InloopFilterType { + fn from(inloop_filter_type: InloopFilterType) -> Self { + let mut dav1d_inloop_filter_type = dav1d::InloopFilterType::empty(); + if inloop_filter_type.contains(InloopFilterType::DEBLOCK) { + dav1d_inloop_filter_type.set(dav1d::InloopFilterType::DEBLOCK, true); + } + if inloop_filter_type.contains(InloopFilterType::CDEF) { + dav1d_inloop_filter_type.set(dav1d::InloopFilterType::CDEF, true); + } + if inloop_filter_type.contains(InloopFilterType::RESTORATION) { + dav1d_inloop_filter_type.set(dav1d::InloopFilterType::RESTORATION, true); + } + + dav1d_inloop_filter_type + } +} + const DEFAULT_N_THREADS: u32 = 0; const DEFAULT_MAX_FRAME_DELAY: i64 = -1; +const DEFAULT_APPLY_GRAIN: bool = false; +const DEFAULT_INLOOP_FILTERS: InloopFilterType = InloopFilterType::empty(); struct State { decoder: dav1d::Decoder, @@ -33,6 +65,8 @@ struct State { struct Settings { n_threads: u32, max_frame_delay: i64, + apply_grain: bool, + inloop_filters: InloopFilterType, } impl Default for Settings { @@ -40,6 +74,8 @@ impl Default for Settings { Settings { n_threads: DEFAULT_N_THREADS, max_frame_delay: DEFAULT_MAX_FRAME_DELAY, + apply_grain: DEFAULT_APPLY_GRAIN, + inloop_filters: DEFAULT_INLOOP_FILTERS, } } } @@ -656,6 +692,19 @@ impl ObjectImpl for Dav1dDec { .default_value(DEFAULT_MAX_FRAME_DELAY) .mutable_ready() .build(), + glib::ParamSpecBoolean::builder("apply-grain") + .nick("Enable film grain synthesis") + .blurb("Enable out-of-loop normative film grain filter") + .default_value(DEFAULT_APPLY_GRAIN) + .mutable_ready() + .build(), + glib::ParamSpecFlags::builder("inloop-filters") + .nick("Inloop filters") + .blurb("Flags to enable in-loop post processing filters") + .default_value(DEFAULT_INLOOP_FILTERS) + .mutable_ready() + .build() + ] }); @@ -672,6 +721,12 @@ impl ObjectImpl for Dav1dDec { "max-frame-delay" => { settings.max_frame_delay = value.get().expect("type checked upstream"); } + "apply-grain" => { + settings.apply_grain = value.get().expect("type checked upstream"); + } + "inloop-filters" => { + settings.inloop_filters = value.get().expect("type checked upstream"); + } _ => unimplemented!(), } } @@ -682,6 +737,8 @@ impl ObjectImpl for Dav1dDec { match pspec.name() { "n-threads" => settings.n_threads.to_value(), "max-frame-delay" => settings.max_frame_delay.to_value(), + "apply-grain" => settings.apply_grain.to_value(), + "inloop-filters" => settings.inloop_filters.to_value(), _ => unimplemented!(), } } @@ -841,6 +898,8 @@ impl VideoDecoderImpl for Dav1dDec { ); decoder_settings.set_n_threads(settings.n_threads); decoder_settings.set_max_frame_delay(max_frame_delay); + decoder_settings.set_apply_grain(settings.apply_grain); + decoder_settings.set_inloop_filters(dav1d::InloopFilterType::from(settings.inloop_filters)); let decoder = dav1d::Decoder::with_settings(&decoder_settings).map_err(|err| { gst::loggable_error!(CAT, "Failed to create decoder instance: {}", err) diff --git a/video/dav1d/src/dav1ddec/mod.rs b/video/dav1d/src/dav1ddec/mod.rs index 75805cff..27952f1c 100644 --- a/video/dav1d/src/dav1ddec/mod.rs +++ b/video/dav1d/src/dav1ddec/mod.rs @@ -18,6 +18,9 @@ glib::wrapper! { } pub fn register(plugin: &gst::Plugin) -> Result<(), glib::BoolError> { + #[cfg(feature = "doc")] + imp::InloopFilterType::static_type().mark_as_plugin_api(gst::PluginAPIFlags::empty()); + let rank = if gst::version() >= (1, 21, 2, 1) { // AOM av1dec rank was demoted in 1.22 dev cycle // https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/3287