audiobuffersplit: Added max-silence-time property

This commit is contained in:
Vivia Nikolaidou 2019-02-21 15:16:37 +00:00 committed by Sebastian Dröge
parent 7c767f3fcd
commit ce0be4d1ac
2 changed files with 117 additions and 82 deletions

View file

@ -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;
} }

View file

@ -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 {