mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-18 07:47:17 +00:00
parent
e2a483f0f9
commit
3e0f1b84a4
4 changed files with 96 additions and 5 deletions
|
@ -95,13 +95,15 @@ static const GstElementDetails rganalysis_details = {
|
||||||
|
|
||||||
/* Default property value. */
|
/* Default property value. */
|
||||||
#define FORCED_DEFAULT TRUE
|
#define FORCED_DEFAULT TRUE
|
||||||
|
#define DEFAULT_MESSAGE FALSE
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_NUM_TRACKS,
|
PROP_NUM_TRACKS,
|
||||||
PROP_FORCED,
|
PROP_FORCED,
|
||||||
PROP_REFERENCE_LEVEL
|
PROP_REFERENCE_LEVEL,
|
||||||
|
PROP_MESSAGE
|
||||||
};
|
};
|
||||||
|
|
||||||
/* The ReplayGain algorithm is intended for use with mono and stereo
|
/* The ReplayGain algorithm is intended for use with mono and stereo
|
||||||
|
@ -272,6 +274,11 @@ gst_rg_analysis_class_init (GstRgAnalysisClass * klass)
|
||||||
"Reference level [dB]", 0.0, 150., RG_REFERENCE_LEVEL,
|
"Reference level [dB]", 0.0, 150., RG_REFERENCE_LEVEL,
|
||||||
G_PARAM_READWRITE));
|
G_PARAM_READWRITE));
|
||||||
|
|
||||||
|
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_MESSAGE,
|
||||||
|
g_param_spec_boolean ("message", "Message",
|
||||||
|
"Post statics messages",
|
||||||
|
DEFAULT_MESSAGE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||||
|
|
||||||
trans_class = (GstBaseTransformClass *) klass;
|
trans_class = (GstBaseTransformClass *) klass;
|
||||||
trans_class->start = GST_DEBUG_FUNCPTR (gst_rg_analysis_start);
|
trans_class->start = GST_DEBUG_FUNCPTR (gst_rg_analysis_start);
|
||||||
trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_rg_analysis_set_caps);
|
trans_class->set_caps = GST_DEBUG_FUNCPTR (gst_rg_analysis_set_caps);
|
||||||
|
@ -290,6 +297,7 @@ gst_rg_analysis_init (GstRgAnalysis * filter, GstRgAnalysisClass * gclass)
|
||||||
|
|
||||||
filter->num_tracks = 0;
|
filter->num_tracks = 0;
|
||||||
filter->forced = FORCED_DEFAULT;
|
filter->forced = FORCED_DEFAULT;
|
||||||
|
filter->message = DEFAULT_MESSAGE;
|
||||||
filter->reference_level = RG_REFERENCE_LEVEL;
|
filter->reference_level = RG_REFERENCE_LEVEL;
|
||||||
|
|
||||||
filter->ctx = NULL;
|
filter->ctx = NULL;
|
||||||
|
@ -302,6 +310,7 @@ gst_rg_analysis_set_property (GObject * object, guint prop_id,
|
||||||
{
|
{
|
||||||
GstRgAnalysis *filter = GST_RG_ANALYSIS (object);
|
GstRgAnalysis *filter = GST_RG_ANALYSIS (object);
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (filter);
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_NUM_TRACKS:
|
case PROP_NUM_TRACKS:
|
||||||
filter->num_tracks = g_value_get_int (value);
|
filter->num_tracks = g_value_get_int (value);
|
||||||
|
@ -312,10 +321,14 @@ gst_rg_analysis_set_property (GObject * object, guint prop_id,
|
||||||
case PROP_REFERENCE_LEVEL:
|
case PROP_REFERENCE_LEVEL:
|
||||||
filter->reference_level = g_value_get_double (value);
|
filter->reference_level = g_value_get_double (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_MESSAGE:
|
||||||
|
filter->message = 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;
|
||||||
}
|
}
|
||||||
|
GST_OBJECT_UNLOCK (filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -324,6 +337,7 @@ gst_rg_analysis_get_property (GObject * object, guint prop_id,
|
||||||
{
|
{
|
||||||
GstRgAnalysis *filter = GST_RG_ANALYSIS (object);
|
GstRgAnalysis *filter = GST_RG_ANALYSIS (object);
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (filter);
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_NUM_TRACKS:
|
case PROP_NUM_TRACKS:
|
||||||
g_value_set_int (value, filter->num_tracks);
|
g_value_set_int (value, filter->num_tracks);
|
||||||
|
@ -334,12 +348,35 @@ gst_rg_analysis_get_property (GObject * object, guint prop_id,
|
||||||
case PROP_REFERENCE_LEVEL:
|
case PROP_REFERENCE_LEVEL:
|
||||||
g_value_set_double (value, filter->reference_level);
|
g_value_set_double (value, filter->reference_level);
|
||||||
break;
|
break;
|
||||||
|
case PROP_MESSAGE:
|
||||||
|
g_value_set_boolean (value, filter->message);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
GST_OBJECT_UNLOCK (filter);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_rg_analysis_post_message (gpointer rganalysis, GstClockTime timestamp,
|
||||||
|
GstClockTime duration, gdouble rglevel)
|
||||||
|
{
|
||||||
|
GstRgAnalysis *filter = GST_RG_ANALYSIS (rganalysis);
|
||||||
|
if (filter->message) {
|
||||||
|
GstMessage *m;
|
||||||
|
|
||||||
|
m = gst_message_new_element (GST_OBJECT_CAST (rganalysis),
|
||||||
|
gst_structure_new ("rganalysis",
|
||||||
|
"timestamp", G_TYPE_UINT64, timestamp,
|
||||||
|
"duration", G_TYPE_UINT64, duration,
|
||||||
|
"rglevel", G_TYPE_DOUBLE, rglevel, NULL));
|
||||||
|
|
||||||
|
gst_element_post_message (GST_ELEMENT_CAST (rganalysis), m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_rg_analysis_start (GstBaseTransform * base)
|
gst_rg_analysis_start (GstBaseTransform * base)
|
||||||
{
|
{
|
||||||
|
@ -353,6 +390,10 @@ gst_rg_analysis_start (GstBaseTransform * base)
|
||||||
filter->has_album_peak = FALSE;
|
filter->has_album_peak = FALSE;
|
||||||
|
|
||||||
filter->ctx = rg_analysis_new ();
|
filter->ctx = rg_analysis_new ();
|
||||||
|
GST_OBJECT_LOCK (filter);
|
||||||
|
rg_analysis_init_silence_detection (filter->ctx, gst_rg_analysis_post_message,
|
||||||
|
filter);
|
||||||
|
GST_OBJECT_UNLOCK (filter);
|
||||||
filter->analyze = NULL;
|
filter->analyze = NULL;
|
||||||
|
|
||||||
GST_LOG_OBJECT (filter, "started");
|
GST_LOG_OBJECT (filter, "started");
|
||||||
|
@ -452,13 +493,10 @@ gst_rg_analysis_transform_ip (GstBaseTransform * base, GstBuffer * buf)
|
||||||
if (filter->skip)
|
if (filter->skip)
|
||||||
return GST_FLOW_OK;
|
return GST_FLOW_OK;
|
||||||
|
|
||||||
/* Buffers made up of silence have no influence on the analysis: */
|
|
||||||
if (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP))
|
|
||||||
return GST_FLOW_OK;
|
|
||||||
|
|
||||||
GST_LOG_OBJECT (filter, "processing buffer of size %u",
|
GST_LOG_OBJECT (filter, "processing buffer of size %u",
|
||||||
GST_BUFFER_SIZE (buf));
|
GST_BUFFER_SIZE (buf));
|
||||||
|
|
||||||
|
rg_analysis_start_buffer (filter->ctx, GST_BUFFER_TIMESTAMP (buf));
|
||||||
filter->analyze (filter->ctx, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
|
filter->analyze (filter->ctx, GST_BUFFER_DATA (buf), GST_BUFFER_SIZE (buf),
|
||||||
filter->depth);
|
filter->depth);
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ struct _GstRgAnalysis
|
||||||
guint num_tracks;
|
guint num_tracks;
|
||||||
gdouble reference_level;
|
gdouble reference_level;
|
||||||
gboolean forced;
|
gboolean forced;
|
||||||
|
gboolean message;
|
||||||
|
|
||||||
/* State machinery for skipping. */
|
/* State machinery for skipping. */
|
||||||
gboolean ignore_tags;
|
gboolean ignore_tags;
|
||||||
|
|
|
@ -109,6 +109,14 @@ struct _RgAnalysisCtx
|
||||||
|
|
||||||
RgAnalysisAcc track;
|
RgAnalysisAcc track;
|
||||||
RgAnalysisAcc album;
|
RgAnalysisAcc album;
|
||||||
|
void (*post_message) (gpointer analysis,
|
||||||
|
GstClockTime timestamp, GstClockTime duration, gdouble rglevel);
|
||||||
|
gpointer analysis;
|
||||||
|
/* The timestamp of the current incoming buffer. */
|
||||||
|
GstClockTime buffer_timestamp;
|
||||||
|
/* Number of samples processed in current buffer, during emit_signal,
|
||||||
|
this will always be on an RMS window boundary. */
|
||||||
|
guint buffer_n_samples_done;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Filter coefficients for the IIR filters that form the equal
|
/* Filter coefficients for the IIR filters that form the equal
|
||||||
|
@ -406,6 +414,13 @@ rg_analysis_new (void)
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
reset_silence_detection (RgAnalysisCtx * ctx)
|
||||||
|
{
|
||||||
|
ctx->buffer_timestamp = GST_CLOCK_TIME_NONE;
|
||||||
|
ctx->buffer_n_samples_done = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Adapt to given sample rate. Does nothing if already the current
|
/* Adapt to given sample rate. Does nothing if already the current
|
||||||
* rate (returns TRUE then). Returns FALSE only if given sample rate
|
* rate (returns TRUE then). Returns FALSE only if given sample rate
|
||||||
* is not supported. If the configured rate changes, the last
|
* is not supported. If the configured rate changes, the last
|
||||||
|
@ -458,10 +473,28 @@ rg_analysis_set_sample_rate (RgAnalysisCtx * ctx, gint sample_rate)
|
||||||
/ 1000);
|
/ 1000);
|
||||||
|
|
||||||
reset_filters (ctx);
|
reset_filters (ctx);
|
||||||
|
reset_silence_detection (ctx);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rg_analysis_init_silence_detection (RgAnalysisCtx * ctx,
|
||||||
|
void (*post_message) (gpointer analysis, GstClockTime timestamp,
|
||||||
|
GstClockTime duration, gdouble rglevel), gpointer analysis)
|
||||||
|
{
|
||||||
|
ctx->post_message = post_message;
|
||||||
|
ctx->analysis = analysis;
|
||||||
|
reset_silence_detection (ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rg_analysis_start_buffer (RgAnalysisCtx * ctx, GstClockTime buffer_timestamp)
|
||||||
|
{
|
||||||
|
ctx->buffer_timestamp = buffer_timestamp;
|
||||||
|
ctx->buffer_n_samples_done = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rg_analysis_destroy (RgAnalysisCtx * ctx)
|
rg_analysis_destroy (RgAnalysisCtx * ctx)
|
||||||
{
|
{
|
||||||
|
@ -665,6 +698,7 @@ rg_analysis_analyze (RgAnalysisCtx * ctx, const gfloat * samples_l,
|
||||||
* ctx->out_r[ctx->window_n_samples_done + i];
|
* ctx->out_r[ctx->window_n_samples_done + i];
|
||||||
|
|
||||||
ctx->window_n_samples_done += n_samples_current;
|
ctx->window_n_samples_done += n_samples_current;
|
||||||
|
ctx->buffer_n_samples_done += n_samples_current;
|
||||||
|
|
||||||
g_return_if_fail (ctx->window_n_samples_done <= ctx->window_n_samples);
|
g_return_if_fail (ctx->window_n_samples_done <= ctx->window_n_samples);
|
||||||
|
|
||||||
|
@ -674,6 +708,15 @@ rg_analysis_analyze (RgAnalysisCtx * ctx, const gfloat * samples_l,
|
||||||
ctx->window_n_samples * 0.5 + 1.e-37);
|
ctx->window_n_samples * 0.5 + 1.e-37);
|
||||||
gint ival = CLAMP ((gint) val, 0,
|
gint ival = CLAMP ((gint) val, 0,
|
||||||
(gint) G_N_ELEMENTS (ctx->track.histogram) - 1);
|
(gint) G_N_ELEMENTS (ctx->track.histogram) - 1);
|
||||||
|
/* Compute the per-window gain */
|
||||||
|
const gdouble gain = PINK_REF - (gdouble) ival / STEPS_PER_DB;
|
||||||
|
const GstClockTime timestamp = (ctx->buffer_timestamp
|
||||||
|
+ ctx->buffer_n_samples_done * GST_SECOND / ctx->sample_rate
|
||||||
|
- RMS_WINDOW_MSECS * GST_MSECOND);
|
||||||
|
|
||||||
|
ctx->post_message (ctx->analysis, timestamp,
|
||||||
|
RMS_WINDOW_MSECS * GST_MSECOND, -gain);
|
||||||
|
|
||||||
|
|
||||||
ctx->track.histogram[ival]++;
|
ctx->track.histogram[ival]++;
|
||||||
ctx->window_square_sum = 0.;
|
ctx->window_square_sum = 0.;
|
||||||
|
@ -736,6 +779,7 @@ rg_analysis_track_result (RgAnalysisCtx * ctx, gdouble * gain, gdouble * peak)
|
||||||
accumulator_clear (&ctx->track);
|
accumulator_clear (&ctx->track);
|
||||||
|
|
||||||
reset_filters (ctx);
|
reset_filters (ctx);
|
||||||
|
reset_silence_detection (ctx);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -774,4 +818,5 @@ rg_analysis_reset (RgAnalysisCtx * ctx)
|
||||||
reset_filters (ctx);
|
reset_filters (ctx);
|
||||||
accumulator_clear (&ctx->track);
|
accumulator_clear (&ctx->track);
|
||||||
accumulator_clear (&ctx->album);
|
accumulator_clear (&ctx->album);
|
||||||
|
reset_silence_detection (ctx);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#define __RG_ANALYSIS_H__
|
#define __RG_ANALYSIS_H__
|
||||||
|
|
||||||
#include <glib.h>
|
#include <glib.h>
|
||||||
|
#include <gst/gst.h>
|
||||||
|
|
||||||
G_BEGIN_DECLS
|
G_BEGIN_DECLS
|
||||||
|
|
||||||
|
@ -47,6 +48,12 @@ gboolean rg_analysis_track_result (RgAnalysisCtx * ctx, gdouble * gain,
|
||||||
gdouble * peak);
|
gdouble * peak);
|
||||||
gboolean rg_analysis_album_result (RgAnalysisCtx * ctx, gdouble * gain,
|
gboolean rg_analysis_album_result (RgAnalysisCtx * ctx, gdouble * gain,
|
||||||
gdouble * peak);
|
gdouble * peak);
|
||||||
|
void rg_analysis_init_silence_detection (
|
||||||
|
RgAnalysisCtx * ctx,
|
||||||
|
void (*post_message) (gpointer analysis, GstClockTime timestamp, GstClockTime duration, gdouble rglevel),
|
||||||
|
gpointer analysis);
|
||||||
|
void rg_analysis_start_buffer (RgAnalysisCtx * ctx,
|
||||||
|
GstClockTime buffer_timestamp);
|
||||||
void rg_analysis_reset_album (RgAnalysisCtx * ctx);
|
void rg_analysis_reset_album (RgAnalysisCtx * ctx);
|
||||||
void rg_analysis_reset (RgAnalysisCtx * ctx);
|
void rg_analysis_reset (RgAnalysisCtx * ctx);
|
||||||
void rg_analysis_destroy (RgAnalysisCtx * ctx);
|
void rg_analysis_destroy (RgAnalysisCtx * ctx);
|
||||||
|
|
Loading…
Reference in a new issue