mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-20 08:41:07 +00:00
opusdec: add 'stats' property
Allow users to retrieve the number of samples, and their duration, generated using PLC. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-base/-/merge_requests/641>
This commit is contained in:
parent
a4e49ba8c9
commit
989bbe29d8
2 changed files with 178 additions and 5 deletions
|
@ -90,7 +90,8 @@ enum
|
||||||
PROP_0,
|
PROP_0,
|
||||||
PROP_USE_INBAND_FEC,
|
PROP_USE_INBAND_FEC,
|
||||||
PROP_APPLY_GAIN,
|
PROP_APPLY_GAIN,
|
||||||
PROP_PHASE_INVERSION
|
PROP_PHASE_INVERSION,
|
||||||
|
PROP_STATS,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -156,6 +157,29 @@ gst_opus_dec_class_init (GstOpusDecClass * klass)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GstOpusDec:stats:
|
||||||
|
*
|
||||||
|
* Various decoder statistics. This property returns a GstStructure
|
||||||
|
* with name application/x-opusdec-stats with the following fields:
|
||||||
|
*
|
||||||
|
* * #guint64 `num-pushed`: the number of packets pushed out.
|
||||||
|
* * #guint64 `num-gap`: the number of gap packets received.
|
||||||
|
* * #guint64 `plc-num-samples`: the number of samples generated using PLC
|
||||||
|
* * #guint64 `plc-duration`: the total duration, in ns, of samples generated using PLC
|
||||||
|
* * #guint32 `bandwidth`: decoder last bandpass, in kHz, or 0 if unknown
|
||||||
|
* * #guint32 `sample-rate`: decoder sampling rate, or 0 if unknown
|
||||||
|
* * #guint32 `gain`: decoder gain adjustement, in Q8 dB units, or 0 if unknown
|
||||||
|
* * #guint32 `last-packet-duration`: duration, in samples, of the last packet successfully decoded or concealed, or 0 if unknown
|
||||||
|
* * #guint `channels`: the number of channels
|
||||||
|
*
|
||||||
|
* Since: 1.18
|
||||||
|
*/
|
||||||
|
g_object_class_install_property (gobject_class, PROP_STATS,
|
||||||
|
g_param_spec_boxed ("stats", "Statistics",
|
||||||
|
"Various statistics", GST_TYPE_STRUCTURE,
|
||||||
|
G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
|
||||||
|
|
||||||
GST_DEBUG_CATEGORY_INIT (opusdec_debug, "opusdec", 0,
|
GST_DEBUG_CATEGORY_INIT (opusdec_debug, "opusdec", 0,
|
||||||
"opus decoding element");
|
"opus decoding element");
|
||||||
}
|
}
|
||||||
|
@ -215,6 +239,13 @@ gst_opus_dec_start (GstAudioDecoder * dec)
|
||||||
gst_audio_decoder_set_latency (dec, 120 * GST_MSECOND, 120 * GST_MSECOND);
|
gst_audio_decoder_set_latency (dec, 120 * GST_MSECOND, 120 * GST_MSECOND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (dec);
|
||||||
|
odec->num_pushed = 0;
|
||||||
|
odec->num_gap = 0;
|
||||||
|
odec->plc_num_samples = 0;
|
||||||
|
odec->plc_duration = 0;
|
||||||
|
GST_OBJECT_UNLOCK (dec);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +369,7 @@ gst_opus_dec_parse_header (GstOpusDec * dec, GstBuffer * buf)
|
||||||
|
|
||||||
if (!gst_codec_utils_opus_parse_header (buf,
|
if (!gst_codec_utils_opus_parse_header (buf,
|
||||||
&dec->sample_rate,
|
&dec->sample_rate,
|
||||||
&dec->n_channels,
|
(guint8 *) & dec->n_channels,
|
||||||
&dec->channel_mapping_family,
|
&dec->channel_mapping_family,
|
||||||
&dec->n_streams,
|
&dec->n_streams,
|
||||||
&dec->n_stereo_streams,
|
&dec->n_stereo_streams,
|
||||||
|
@ -586,6 +617,10 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer)
|
||||||
" plus leftover %" GST_TIME_FORMAT, GST_TIME_ARGS (missing_duration),
|
" plus leftover %" GST_TIME_FORMAT, GST_TIME_ARGS (missing_duration),
|
||||||
GST_TIME_ARGS (dec->leftover_plc_duration));
|
GST_TIME_ARGS (dec->leftover_plc_duration));
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (dec);
|
||||||
|
dec->num_gap++;
|
||||||
|
GST_OBJECT_UNLOCK (dec);
|
||||||
|
|
||||||
/* add the leftover PLC duration to that of the buffer */
|
/* add the leftover PLC duration to that of the buffer */
|
||||||
missing_duration += dec->leftover_plc_duration;
|
missing_duration += dec->leftover_plc_duration;
|
||||||
|
|
||||||
|
@ -618,6 +653,11 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer)
|
||||||
" num frame samples: %d new leftover: %" GST_TIME_FORMAT,
|
" num frame samples: %d new leftover: %" GST_TIME_FORMAT,
|
||||||
GST_TIME_ARGS (aligned_missing_duration), samples,
|
GST_TIME_ARGS (aligned_missing_duration), samples,
|
||||||
GST_TIME_ARGS (dec->leftover_plc_duration));
|
GST_TIME_ARGS (dec->leftover_plc_duration));
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (dec);
|
||||||
|
dec->plc_num_samples += samples;
|
||||||
|
dec->plc_duration += aligned_missing_duration;
|
||||||
|
GST_OBJECT_UNLOCK (dec);
|
||||||
} else {
|
} else {
|
||||||
/* use maximum size (120 ms) as the number of returned samples is
|
/* use maximum size (120 ms) as the number of returned samples is
|
||||||
not constant over the stream. */
|
not constant over the stream. */
|
||||||
|
@ -766,6 +806,10 @@ opus_dec_chain_parse_data (GstOpusDec * dec, GstBuffer * buffer)
|
||||||
gst_buffer_replace (&dec->last_buffer, buffer);
|
gst_buffer_replace (&dec->last_buffer, buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (dec);
|
||||||
|
dec->num_pushed++;
|
||||||
|
GST_OBJECT_UNLOCK (dec);
|
||||||
|
|
||||||
res = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), outbuf, 1);
|
res = gst_audio_decoder_finish_frame (GST_AUDIO_DECODER (dec), outbuf, 1);
|
||||||
|
|
||||||
if (res != GST_FLOW_OK)
|
if (res != GST_FLOW_OK)
|
||||||
|
@ -841,8 +885,8 @@ gst_opus_dec_set_format (GstAudioDecoder * bdec, GstCaps * caps)
|
||||||
const GstAudioChannelPosition *posn = NULL;
|
const GstAudioChannelPosition *posn = NULL;
|
||||||
|
|
||||||
if (!gst_codec_utils_opus_parse_caps (caps, &dec->sample_rate,
|
if (!gst_codec_utils_opus_parse_caps (caps, &dec->sample_rate,
|
||||||
&dec->n_channels, &dec->channel_mapping_family, &dec->n_streams,
|
(guint8 *) & dec->n_channels, &dec->channel_mapping_family,
|
||||||
&dec->n_stereo_streams, dec->channel_mapping)) {
|
&dec->n_streams, &dec->n_stereo_streams, dec->channel_mapping)) {
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -943,6 +987,126 @@ gst_opus_dec_handle_frame (GstAudioDecoder * adec, GstBuffer * buf)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Called with object lock hold */
|
||||||
|
static guint32
|
||||||
|
get_bandwidth (GstOpusDec * self)
|
||||||
|
{
|
||||||
|
gint err;
|
||||||
|
gint32 bw;
|
||||||
|
|
||||||
|
if (!self->state)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err = opus_multistream_decoder_ctl (self->state, OPUS_GET_BANDWIDTH (&bw));
|
||||||
|
if (err != OPUS_OK) {
|
||||||
|
GST_WARNING_OBJECT (self, "Could not retrieve bandwith: %s",
|
||||||
|
opus_strerror (err));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (bw) {
|
||||||
|
case OPUS_BANDWIDTH_NARROWBAND:
|
||||||
|
return 4;
|
||||||
|
case OPUS_BANDWIDTH_MEDIUMBAND:
|
||||||
|
return 6;
|
||||||
|
case OPUS_BANDWIDTH_WIDEBAND:
|
||||||
|
return 8;
|
||||||
|
case OPUS_BANDWIDTH_SUPERWIDEBAND:
|
||||||
|
return 12;
|
||||||
|
case OPUS_BANDWIDTH_FULLBAND:
|
||||||
|
return 20;
|
||||||
|
default:
|
||||||
|
GST_WARNING_OBJECT (self, "Unknown bandwith enum: %d", bw);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called with object lock hold */
|
||||||
|
static guint32
|
||||||
|
get_sample_rate (GstOpusDec * self)
|
||||||
|
{
|
||||||
|
gint err;
|
||||||
|
gint32 rate;
|
||||||
|
|
||||||
|
if (!self->state)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err =
|
||||||
|
opus_multistream_decoder_ctl (self->state, OPUS_GET_SAMPLE_RATE (&rate));
|
||||||
|
if (err != OPUS_OK) {
|
||||||
|
GST_WARNING_OBJECT (self, "Could not retrieve sample rate: %s",
|
||||||
|
opus_strerror (err));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called with object lock hold */
|
||||||
|
static guint32
|
||||||
|
get_gain (GstOpusDec * self)
|
||||||
|
{
|
||||||
|
gint err;
|
||||||
|
gint32 gain;
|
||||||
|
|
||||||
|
if (!self->state)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err = opus_multistream_decoder_ctl (self->state, OPUS_GET_GAIN (&gain));
|
||||||
|
if (err != OPUS_OK) {
|
||||||
|
GST_WARNING_OBJECT (self, "Could not retrieve gain: %s",
|
||||||
|
opus_strerror (err));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return gain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called with object lock hold */
|
||||||
|
static guint32
|
||||||
|
get_last_packet_duration (GstOpusDec * self)
|
||||||
|
{
|
||||||
|
gint err;
|
||||||
|
gint32 duration;
|
||||||
|
|
||||||
|
if (!self->state)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
err =
|
||||||
|
opus_multistream_decoder_ctl (self->state,
|
||||||
|
OPUS_GET_LAST_PACKET_DURATION (&duration));
|
||||||
|
if (err != OPUS_OK) {
|
||||||
|
GST_WARNING_OBJECT (self, "Could not retrieve last packet duration: %s",
|
||||||
|
opus_strerror (err));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GstStructure *
|
||||||
|
gst_opus_dec_create_stats (GstOpusDec * self)
|
||||||
|
{
|
||||||
|
GstStructure *s;
|
||||||
|
|
||||||
|
GST_OBJECT_LOCK (self);
|
||||||
|
|
||||||
|
s = gst_structure_new ("application/x-opusdec-stats",
|
||||||
|
"num-pushed", G_TYPE_UINT64, self->num_pushed,
|
||||||
|
"num-gap", G_TYPE_UINT64, self->num_gap,
|
||||||
|
"plc-num-samples", G_TYPE_UINT64, self->plc_num_samples,
|
||||||
|
"plc-duration", G_TYPE_UINT64, self->plc_duration,
|
||||||
|
"bandwidth", G_TYPE_UINT, get_bandwidth (self),
|
||||||
|
"sample-rate", G_TYPE_UINT, get_sample_rate (self),
|
||||||
|
"gain", G_TYPE_UINT, get_gain (self),
|
||||||
|
"last-packet-duration", G_TYPE_UINT, get_last_packet_duration (self),
|
||||||
|
"channels", G_TYPE_UINT, self->n_channels, NULL);
|
||||||
|
|
||||||
|
GST_OBJECT_UNLOCK (self);
|
||||||
|
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gst_opus_dec_get_property (GObject * object, guint prop_id, GValue * value,
|
gst_opus_dec_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
GParamSpec * pspec)
|
GParamSpec * pspec)
|
||||||
|
@ -959,6 +1123,9 @@ gst_opus_dec_get_property (GObject * object, guint prop_id, GValue * value,
|
||||||
case PROP_PHASE_INVERSION:
|
case PROP_PHASE_INVERSION:
|
||||||
g_value_set_boolean (value, dec->phase_inversion);
|
g_value_set_boolean (value, dec->phase_inversion);
|
||||||
break;
|
break;
|
||||||
|
case PROP_STATS:
|
||||||
|
g_value_take_boxed (value, gst_opus_dec_create_stats (dec));
|
||||||
|
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;
|
||||||
|
|
|
@ -53,7 +53,7 @@ struct _GstOpusDec {
|
||||||
GstBuffer *vorbiscomment;
|
GstBuffer *vorbiscomment;
|
||||||
|
|
||||||
guint32 sample_rate;
|
guint32 sample_rate;
|
||||||
guint8 n_channels;
|
guint n_channels;
|
||||||
guint16 pre_skip;
|
guint16 pre_skip;
|
||||||
gint16 r128_gain;
|
gint16 r128_gain;
|
||||||
|
|
||||||
|
@ -77,6 +77,12 @@ struct _GstOpusDec {
|
||||||
GstClockTime last_known_buffer_duration;
|
GstClockTime last_known_buffer_duration;
|
||||||
|
|
||||||
gboolean phase_inversion;
|
gboolean phase_inversion;
|
||||||
|
|
||||||
|
/* Used to generate the 'stats' property. Protected by object lock */
|
||||||
|
guint64 num_pushed;
|
||||||
|
guint64 num_gap;
|
||||||
|
guint64 plc_num_samples;
|
||||||
|
guint64 plc_duration;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstOpusDecClass {
|
struct _GstOpusDecClass {
|
||||||
|
|
Loading…
Reference in a new issue