cutter: add audio-level-meta

Set GstAudioLevelMeta on buffers

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5771>
This commit is contained in:
Ignazio Pillai 2023-12-01 14:49:37 +01:00 committed by GStreamer Marge Bot
parent 60d9cfc954
commit 34741e1db2
3 changed files with 58 additions and 1 deletions

View file

@ -4293,6 +4293,18 @@
} }
}, },
"properties": { "properties": {
"audio-level-meta": {
"blurb": "Set GstAudioLevelMeta on buffers",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "false",
"mutable": "null",
"readable": true,
"type": "gboolean",
"writable": true
},
"leaky": { "leaky": {
"blurb": "do we leak buffers when below threshold ?", "blurb": "do we leak buffers when below threshold ?",
"conditionally-available": false, "conditionally-available": false,

View file

@ -54,6 +54,7 @@ GST_DEBUG_CATEGORY_STATIC (cutter_debug);
#define CUTTER_DEFAULT_THRESHOLD_LEVEL 0.1 #define CUTTER_DEFAULT_THRESHOLD_LEVEL 0.1
#define CUTTER_DEFAULT_THRESHOLD_LENGTH (500 * GST_MSECOND) #define CUTTER_DEFAULT_THRESHOLD_LENGTH (500 * GST_MSECOND)
#define CUTTER_DEFAULT_PRE_LENGTH (200 * GST_MSECOND) #define CUTTER_DEFAULT_PRE_LENGTH (200 * GST_MSECOND)
#define EPSILON 1e-35f
static GstStaticPadTemplate cutter_src_factory = GST_STATIC_PAD_TEMPLATE ("src", static GstStaticPadTemplate cutter_src_factory = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC, GST_PAD_SRC,
@ -81,7 +82,8 @@ enum
PROP_THRESHOLD_DB, PROP_THRESHOLD_DB,
PROP_RUN_LENGTH, PROP_RUN_LENGTH,
PROP_PRE_LENGTH, PROP_PRE_LENGTH,
PROP_LEAKY PROP_LEAKY,
PROP_AUDIO_LEVEL_META,
}; };
#define gst_cutter_parent_class parent_class #define gst_cutter_parent_class parent_class
@ -135,6 +137,17 @@ gst_cutter_class_init (GstCutterClass * klass)
g_param_spec_boolean ("leaky", "Leaky", g_param_spec_boolean ("leaky", "Leaky",
"do we leak buffers when below threshold ?", "do we leak buffers when below threshold ?",
FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstCutter:audio-level-meta:
*
* If %TRUE, generate or update GstAudioLevelMeta on output buffers.
*
* Since: 1.24
*/
g_object_class_install_property (gobject_class, PROP_AUDIO_LEVEL_META,
g_param_spec_boolean ("audio-level-meta", "Audio Level Meta",
"Set GstAudioLevelMeta on buffers", FALSE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
GST_DEBUG_CATEGORY_INIT (cutter_debug, "cutter", 0, "Audio cutting"); GST_DEBUG_CATEGORY_INIT (cutter_debug, "cutter", 0, "Audio cutting");
@ -175,6 +188,7 @@ gst_cutter_init (GstCutter * filter)
filter->pre_run_length = 0 * GST_SECOND; filter->pre_run_length = 0 * GST_SECOND;
filter->pre_buffer = NULL; filter->pre_buffer = NULL;
filter->leaky = FALSE; filter->leaky = FALSE;
filter->audio_level_meta = FALSE;
} }
static GstMessage * static GstMessage *
@ -293,6 +307,23 @@ gst_cutter_event (GstPad * pad, GstObject * parent, GstEvent * event)
return ret; return ret;
} }
static void
set_audio_level_meta (GstBuffer * buffer, guint8 level)
{
GstAudioLevelMeta *meta;
/* Update the existing meta, if any, so we can have an upstream element
* filling the voice activity part of the meta. */
meta = gst_buffer_get_audio_level_meta (buffer);
if (meta) {
meta->level = level;
} else {
/* Assume audio does not contain voice, it can be detected by another
* downstream element. */
gst_buffer_add_audio_level_meta (buffer, level, FALSE);
}
}
static GstFlowReturn static GstFlowReturn
gst_cutter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) gst_cutter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
{ {
@ -355,6 +386,13 @@ gst_cutter_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
GST_LOG_OBJECT (filter, "buffer stats: NMS %f, RMS %f, audio length %f", NMS, GST_LOG_OBJECT (filter, "buffer stats: NMS %f, RMS %f, audio length %f", NMS,
RMS, gst_guint64_to_gdouble (duration)); RMS, gst_guint64_to_gdouble (duration));
if (filter->audio_level_meta) {
gdouble RMSdB = 20 * log10 (RMS + EPSILON);
buf = gst_buffer_make_writable (buf);
set_audio_level_meta (buf, -RMSdB);
}
if (RMS < filter->threshold_level) if (RMS < filter->threshold_level)
filter->silent_run_length += gst_guint64_to_gdouble (duration); filter->silent_run_length += gst_guint64_to_gdouble (duration);
else { else {
@ -469,6 +507,9 @@ gst_cutter_set_property (GObject * object, guint prop_id,
/* set if the pre-record buffer is leaky or not */ /* set if the pre-record buffer is leaky or not */
filter->leaky = g_value_get_boolean (value); filter->leaky = g_value_get_boolean (value);
break; break;
case PROP_AUDIO_LEVEL_META:
filter->audio_level_meta = g_value_get_boolean (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -500,6 +541,9 @@ gst_cutter_get_property (GObject * object, guint prop_id,
case PROP_LEAKY: case PROP_LEAKY:
g_value_set_boolean (value, filter->leaky); g_value_set_boolean (value, filter->leaky);
break; break;
case PROP_AUDIO_LEVEL_META:
g_value_set_boolean (value, filter->audio_level_meta);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;

View file

@ -62,6 +62,7 @@ struct _GstCutter
double pre_run_length; /* how long is it currently ? */ double pre_run_length; /* how long is it currently ? */
GList *pre_buffer; /* list of GstBuffers in pre-record buffer */ GList *pre_buffer; /* list of GstBuffers in pre-record buffer */
gboolean leaky; /* do we leak an overflowing prebuffer ? */ gboolean leaky; /* do we leak an overflowing prebuffer ? */
gboolean audio_level_meta; /* whether or not generate GstAudioLevelMeta */
GstAudioInfo info; GstAudioInfo info;
GstSegment segment; GstSegment segment;