mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 12:11:13 +00:00
audiobuffersplit: Added max-silence-time property
This commit is contained in:
parent
7c767f3fcd
commit
ce0be4d1ac
2 changed files with 117 additions and 82 deletions
|
@ -47,6 +47,7 @@ enum
|
||||||
PROP_DISCONT_WAIT,
|
PROP_DISCONT_WAIT,
|
||||||
PROP_STRICT_BUFFER_SIZE,
|
PROP_STRICT_BUFFER_SIZE,
|
||||||
PROP_GAPLESS,
|
PROP_GAPLESS,
|
||||||
|
PROP_MAX_SILENCE_TIME,
|
||||||
LAST_PROP
|
LAST_PROP
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -56,6 +57,7 @@ enum
|
||||||
#define DEFAULT_DISCONT_WAIT (1 * GST_SECOND)
|
#define DEFAULT_DISCONT_WAIT (1 * GST_SECOND)
|
||||||
#define DEFAULT_STRICT_BUFFER_SIZE (FALSE)
|
#define DEFAULT_STRICT_BUFFER_SIZE (FALSE)
|
||||||
#define DEFAULT_GAPLESS (FALSE)
|
#define DEFAULT_GAPLESS (FALSE)
|
||||||
|
#define DEFAULT_MAX_SILENCE_TIME (0)
|
||||||
|
|
||||||
#define parent_class gst_audio_buffer_split_parent_class
|
#define parent_class gst_audio_buffer_split_parent_class
|
||||||
G_DEFINE_TYPE (GstAudioBufferSplit, gst_audio_buffer_split, GST_TYPE_ELEMENT);
|
G_DEFINE_TYPE (GstAudioBufferSplit, gst_audio_buffer_split, GST_TYPE_ELEMENT);
|
||||||
|
@ -123,6 +125,15 @@ gst_audio_buffer_split_class_init (GstAudioBufferSplitClass * klass)
|
||||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||||
GST_PARAM_MUTABLE_READY));
|
GST_PARAM_MUTABLE_READY));
|
||||||
|
|
||||||
|
g_object_class_install_property (gobject_class, PROP_MAX_SILENCE_TIME,
|
||||||
|
g_param_spec_uint64 ("max-silence-time",
|
||||||
|
"Maximum time of silence to insert",
|
||||||
|
"Do not insert silence in gapless mode if the gap exceeds this "
|
||||||
|
"period (in ns) (0 = disabled)",
|
||||||
|
0, G_MAXUINT64, DEFAULT_MAX_SILENCE_TIME,
|
||||||
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS |
|
||||||
|
GST_PARAM_MUTABLE_READY));
|
||||||
|
|
||||||
gst_element_class_set_static_metadata (gstelement_class,
|
gst_element_class_set_static_metadata (gstelement_class,
|
||||||
"Audio Buffer Split", "Audio/Filter",
|
"Audio Buffer Split", "Audio/Filter",
|
||||||
"Splits raw audio buffers into equal sized chunks",
|
"Splits raw audio buffers into equal sized chunks",
|
||||||
|
@ -253,6 +264,9 @@ gst_audio_buffer_split_set_property (GObject * object, guint property_id,
|
||||||
case PROP_GAPLESS:
|
case PROP_GAPLESS:
|
||||||
self->gapless = g_value_get_boolean (value);
|
self->gapless = g_value_get_boolean (value);
|
||||||
break;
|
break;
|
||||||
|
case PROP_MAX_SILENCE_TIME:
|
||||||
|
self->max_silence_time = g_value_get_uint64 (value);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -288,6 +302,9 @@ gst_audio_buffer_split_get_property (GObject * object, guint property_id,
|
||||||
case PROP_GAPLESS:
|
case PROP_GAPLESS:
|
||||||
g_value_set_boolean (value, self->gapless);
|
g_value_set_boolean (value, self->gapless);
|
||||||
break;
|
break;
|
||||||
|
case PROP_MAX_SILENCE_TIME:
|
||||||
|
g_value_set_uint64 (value, self->max_silence_time);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||||
break;
|
break;
|
||||||
|
@ -420,6 +437,11 @@ gst_audio_buffer_split_handle_discont (GstAudioBufferSplit * self,
|
||||||
{
|
{
|
||||||
gboolean discont;
|
gboolean discont;
|
||||||
GstFlowReturn ret = GST_FLOW_OK;
|
GstFlowReturn ret = GST_FLOW_OK;
|
||||||
|
guint avail = gst_adapter_available (self->adapter);
|
||||||
|
guint avail_samples = avail / bpf;
|
||||||
|
guint64 new_offset;
|
||||||
|
GstClockTime current_timestamp;
|
||||||
|
GstClockTime current_timestamp_end;
|
||||||
|
|
||||||
GST_OBJECT_LOCK (self);
|
GST_OBJECT_LOCK (self);
|
||||||
discont =
|
discont =
|
||||||
|
@ -430,71 +452,77 @@ gst_audio_buffer_split_handle_discont (GstAudioBufferSplit * self,
|
||||||
NULL);
|
NULL);
|
||||||
GST_OBJECT_UNLOCK (self);
|
GST_OBJECT_UNLOCK (self);
|
||||||
|
|
||||||
if (discont) {
|
if (!discont)
|
||||||
guint avail = gst_adapter_available (self->adapter);
|
return ret;
|
||||||
guint avail_samples = avail / bpf;
|
|
||||||
guint64 new_offset;
|
|
||||||
GstClockTime current_timestamp;
|
|
||||||
GstClockTime current_timestamp_end;
|
|
||||||
|
|
||||||
/* Reset */
|
/* Reset */
|
||||||
self->drop_samples = 0;
|
self->drop_samples = 0;
|
||||||
|
|
||||||
if (self->segment.rate < 0.0) {
|
if (self->segment.rate < 0.0) {
|
||||||
current_timestamp =
|
current_timestamp =
|
||||||
self->resync_time - gst_util_uint64_scale (self->current_offset +
|
self->resync_time - gst_util_uint64_scale (self->current_offset +
|
||||||
avail_samples, GST_SECOND, rate);
|
avail_samples, GST_SECOND, rate);
|
||||||
current_timestamp_end =
|
current_timestamp_end =
|
||||||
self->resync_time - gst_util_uint64_scale (self->current_offset,
|
self->resync_time - gst_util_uint64_scale (self->current_offset,
|
||||||
GST_SECOND, rate);
|
GST_SECOND, rate);
|
||||||
|
} else {
|
||||||
|
current_timestamp =
|
||||||
|
self->resync_time + gst_util_uint64_scale (self->current_offset,
|
||||||
|
GST_SECOND, rate);
|
||||||
|
current_timestamp_end =
|
||||||
|
self->resync_time + gst_util_uint64_scale (self->current_offset +
|
||||||
|
avail_samples, GST_SECOND, rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self->gapless) {
|
||||||
|
if (self->current_offset == -1) {
|
||||||
|
/* We only set resync time on the very first buffer */
|
||||||
|
self->current_offset = 0;
|
||||||
|
self->resync_time = GST_BUFFER_PTS (buffer);
|
||||||
|
discont = FALSE;
|
||||||
} else {
|
} else {
|
||||||
current_timestamp =
|
GST_DEBUG_OBJECT (self,
|
||||||
self->resync_time + gst_util_uint64_scale (self->current_offset,
|
"Got discont in gapless mode: Current timestamp %" GST_TIME_FORMAT
|
||||||
GST_SECOND, rate);
|
", current end timestamp %" GST_TIME_FORMAT
|
||||||
current_timestamp_end =
|
", timestamp after discont %" GST_TIME_FORMAT,
|
||||||
self->resync_time + gst_util_uint64_scale (self->current_offset +
|
GST_TIME_ARGS (current_timestamp),
|
||||||
avail_samples, GST_SECOND, rate);
|
GST_TIME_ARGS (current_timestamp_end),
|
||||||
}
|
GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
|
||||||
|
|
||||||
if (self->gapless) {
|
new_offset =
|
||||||
if (self->current_offset == -1) {
|
gst_util_uint64_scale (GST_BUFFER_PTS (buffer) - self->resync_time,
|
||||||
/* We only set resync time on the very first buffer */
|
rate, GST_SECOND);
|
||||||
self->current_offset = 0;
|
if (GST_BUFFER_PTS (buffer) < self->resync_time) {
|
||||||
self->resync_time = GST_BUFFER_PTS (buffer);
|
guint64 drop_samples;
|
||||||
} else {
|
|
||||||
GST_DEBUG_OBJECT (self,
|
|
||||||
"Got discont in gapless mode: Current timestamp %" GST_TIME_FORMAT
|
|
||||||
", current end timestamp %" GST_TIME_FORMAT
|
|
||||||
", timestamp after discont %" GST_TIME_FORMAT,
|
|
||||||
GST_TIME_ARGS (current_timestamp),
|
|
||||||
GST_TIME_ARGS (current_timestamp_end),
|
|
||||||
GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
|
|
||||||
|
|
||||||
new_offset =
|
new_offset =
|
||||||
gst_util_uint64_scale (GST_BUFFER_PTS (buffer) - self->resync_time,
|
gst_util_uint64_scale (self->resync_time -
|
||||||
rate, GST_SECOND);
|
GST_BUFFER_PTS (buffer), rate, GST_SECOND);
|
||||||
if (GST_BUFFER_PTS (buffer) < self->resync_time) {
|
drop_samples = self->current_offset + avail_samples + new_offset;
|
||||||
guint64 drop_samples;
|
|
||||||
|
|
||||||
new_offset =
|
GST_DEBUG_OBJECT (self,
|
||||||
gst_util_uint64_scale (self->resync_time -
|
"Dropping %" G_GUINT64_FORMAT " samples (%" GST_TIME_FORMAT ")",
|
||||||
GST_BUFFER_PTS (buffer), rate, GST_SECOND);
|
drop_samples, GST_TIME_ARGS (gst_util_uint64_scale (drop_samples,
|
||||||
drop_samples = self->current_offset + avail_samples + new_offset;
|
GST_SECOND, rate)));
|
||||||
|
discont = FALSE;
|
||||||
|
} else if (new_offset > self->current_offset + avail_samples) {
|
||||||
|
guint64 silence_samples =
|
||||||
|
new_offset - (self->current_offset + avail_samples);
|
||||||
|
const GstAudioFormatInfo *info = gst_audio_format_get_info (format);
|
||||||
|
GstClockTime silence_time =
|
||||||
|
gst_util_uint64_scale (silence_samples, GST_SECOND, rate);
|
||||||
|
|
||||||
|
if (silence_time > self->max_silence_time) {
|
||||||
GST_DEBUG_OBJECT (self,
|
GST_DEBUG_OBJECT (self,
|
||||||
"Dropping %" G_GUINT64_FORMAT " samples (%" GST_TIME_FORMAT ")",
|
"Not inserting %" G_GUINT64_FORMAT " samples of silence (%"
|
||||||
drop_samples, GST_TIME_ARGS (gst_util_uint64_scale (drop_samples,
|
GST_TIME_FORMAT " exceeds maximum %" GST_TIME_FORMAT ")",
|
||||||
GST_SECOND, rate)));
|
silence_samples, GST_TIME_ARGS (silence_time),
|
||||||
} else if (new_offset > self->current_offset + avail_samples) {
|
GST_TIME_ARGS (self->max_silence_time));
|
||||||
guint64 silence_samples =
|
} else {
|
||||||
new_offset - (self->current_offset + avail_samples);
|
|
||||||
const GstAudioFormatInfo *info = gst_audio_format_get_info (format);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self,
|
GST_DEBUG_OBJECT (self,
|
||||||
"Inserting %" G_GUINT64_FORMAT " samples of silence (%"
|
"Inserting %" G_GUINT64_FORMAT " samples of silence (%"
|
||||||
GST_TIME_FORMAT ")", silence_samples,
|
GST_TIME_FORMAT ")", silence_samples,
|
||||||
GST_TIME_ARGS (gst_util_uint64_scale (silence_samples, GST_SECOND,
|
GST_TIME_ARGS (silence_time));
|
||||||
rate)));
|
|
||||||
|
|
||||||
/* Insert silence buffers to fill the gap in 1s chunks */
|
/* Insert silence buffers to fill the gap in 1s chunks */
|
||||||
while (silence_samples > 0) {
|
while (silence_samples > 0) {
|
||||||
|
@ -517,41 +545,47 @@ gst_audio_buffer_split_handle_discont (GstAudioBufferSplit * self,
|
||||||
|
|
||||||
silence_samples -= n_samples;
|
silence_samples -= n_samples;
|
||||||
}
|
}
|
||||||
} else if (new_offset < self->current_offset + avail_samples) {
|
discont = FALSE;
|
||||||
guint64 drop_samples =
|
|
||||||
self->current_offset + avail_samples - new_offset;
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (self,
|
|
||||||
"Dropping %" G_GUINT64_FORMAT " samples (%" GST_TIME_FORMAT ")",
|
|
||||||
drop_samples, GST_TIME_ARGS (gst_util_uint64_scale (drop_samples,
|
|
||||||
GST_SECOND, rate)));
|
|
||||||
self->drop_samples = drop_samples;
|
|
||||||
}
|
}
|
||||||
}
|
} else if (new_offset < self->current_offset + avail_samples) {
|
||||||
} else {
|
guint64 drop_samples =
|
||||||
GST_DEBUG_OBJECT (self,
|
self->current_offset + avail_samples - new_offset;
|
||||||
"Got discont: Current timestamp %" GST_TIME_FORMAT
|
|
||||||
", current end timestamp %" GST_TIME_FORMAT
|
|
||||||
", timestamp after discont %" GST_TIME_FORMAT,
|
|
||||||
GST_TIME_ARGS (current_timestamp),
|
|
||||||
GST_TIME_ARGS (current_timestamp_end),
|
|
||||||
GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
|
|
||||||
|
|
||||||
if (self->strict_buffer_size) {
|
GST_DEBUG_OBJECT (self,
|
||||||
gst_adapter_clear (self->adapter);
|
"Dropping %" G_GUINT64_FORMAT " samples (%" GST_TIME_FORMAT ")",
|
||||||
ret = GST_FLOW_OK;
|
drop_samples, GST_TIME_ARGS (gst_util_uint64_scale (drop_samples,
|
||||||
} else {
|
GST_SECOND, rate)));
|
||||||
ret =
|
self->drop_samples = drop_samples;
|
||||||
gst_audio_buffer_split_output (self, TRUE, rate, bpf,
|
discont = FALSE;
|
||||||
samples_per_buffer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self->current_offset = 0;
|
|
||||||
self->accumulated_error = 0;
|
|
||||||
self->resync_time = GST_BUFFER_PTS (buffer);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (discont) {
|
||||||
|
/* We might end up in here also in gapless mode, if the above code decided
|
||||||
|
* that no silence is to be inserted, because e.g. the gap is too big */
|
||||||
|
GST_DEBUG_OBJECT (self,
|
||||||
|
"Got discont: Current timestamp %" GST_TIME_FORMAT
|
||||||
|
", current end timestamp %" GST_TIME_FORMAT
|
||||||
|
", timestamp after discont %" GST_TIME_FORMAT,
|
||||||
|
GST_TIME_ARGS (current_timestamp),
|
||||||
|
GST_TIME_ARGS (current_timestamp_end),
|
||||||
|
GST_TIME_ARGS (GST_BUFFER_PTS (buffer)));
|
||||||
|
|
||||||
|
if (self->strict_buffer_size) {
|
||||||
|
gst_adapter_clear (self->adapter);
|
||||||
|
ret = GST_FLOW_OK;
|
||||||
|
} else {
|
||||||
|
ret =
|
||||||
|
gst_audio_buffer_split_output (self, TRUE, rate, bpf,
|
||||||
|
samples_per_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
self->current_offset = 0;
|
||||||
|
self->accumulated_error = 0;
|
||||||
|
self->resync_time = GST_BUFFER_PTS (buffer);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,6 +63,7 @@ struct _GstAudioBufferSplit {
|
||||||
|
|
||||||
gboolean strict_buffer_size;
|
gboolean strict_buffer_size;
|
||||||
gboolean gapless;
|
gboolean gapless;
|
||||||
|
GstClockTime max_silence_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _GstAudioBufferSplitClass {
|
struct _GstAudioBufferSplitClass {
|
||||||
|
|
Loading…
Reference in a new issue