audiobasesink: drop GAP buffers, or all buffers in trickmode no-audio mode
Make the base audio sink throw away buffers marked GAP, or all incoming buffers when performing a trick play with GST_SEGMENT_TRICKMODE_NO_AUDIO flag set, and make sure to start the ringbuffer when that happens so the clock starts running. Preserve the timing calculations when rendering, so state is all updated the same, but just don't render samples. https://bugzilla.gnome.org/show_bug.cgi?id=735666
This commit is contained in:
parent
9491157f1a
commit
8557eead82
@ -182,6 +182,9 @@ static GstCaps *gst_audio_base_sink_fixate (GstBaseSink * bsink,
|
|||||||
static gboolean gst_audio_base_sink_query_pad (GstBaseSink * bsink,
|
static gboolean gst_audio_base_sink_query_pad (GstBaseSink * bsink,
|
||||||
GstQuery * query);
|
GstQuery * query);
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_audio_base_sink_render_samples (GstBaseSink * bsink,
|
||||||
|
GstBuffer * buf, GstClockTime time, GstClockTime duration);
|
||||||
|
|
||||||
/* static guint gst_audio_base_sink_signals[LAST_SIGNAL] = { 0 }; */
|
/* static guint gst_audio_base_sink_signals[LAST_SIGNAL] = { 0 }; */
|
||||||
|
|
||||||
@ -1062,7 +1065,8 @@ gst_audio_base_sink_wait_event (GstBaseSink * bsink, GstEvent * event)
|
|||||||
buffer = gst_buffer_new_and_alloc (n_samples * spec->info.bpf);
|
buffer = gst_buffer_new_and_alloc (n_samples * spec->info.bpf);
|
||||||
|
|
||||||
if (n_samples != 0) {
|
if (n_samples != 0) {
|
||||||
gst_buffer_map (buffer, &minfo, GST_MAP_WRITE);
|
if (!gst_buffer_map (buffer, &minfo, GST_MAP_WRITE))
|
||||||
|
return FALSE;
|
||||||
gst_audio_format_fill_silence (spec->info.finfo, minfo.data,
|
gst_audio_format_fill_silence (spec->info.finfo, minfo.data,
|
||||||
minfo.size);
|
minfo.size);
|
||||||
gst_buffer_unmap (buffer, &minfo);
|
gst_buffer_unmap (buffer, &minfo);
|
||||||
@ -1617,11 +1621,12 @@ gst_audio_base_sink_get_alignment (GstAudioBaseSink * sink,
|
|||||||
return align;
|
return align;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* buf may be NULL, to render silence/skip */
|
||||||
static GstFlowReturn
|
static GstFlowReturn
|
||||||
gst_audio_base_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
gst_audio_base_sink_render_samples (GstBaseSink * bsink,
|
||||||
|
GstBuffer * buf, GstClockTime time, GstClockTime duration)
|
||||||
{
|
{
|
||||||
guint64 in_offset;
|
GstClockTime stop, render_start, render_stop, sample_offset;
|
||||||
GstClockTime time, stop, render_start, render_stop, sample_offset;
|
|
||||||
GstClockTimeDiff sync_offset, ts_offset;
|
GstClockTimeDiff sync_offset, ts_offset;
|
||||||
GstAudioBaseSinkClass *bclass;
|
GstAudioBaseSinkClass *bclass;
|
||||||
GstAudioBaseSink *sink;
|
GstAudioBaseSink *sink;
|
||||||
@ -1630,8 +1635,7 @@ gst_audio_base_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
|||||||
guint64 ctime, cstop;
|
guint64 ctime, cstop;
|
||||||
gsize offset;
|
gsize offset;
|
||||||
GstMapInfo info;
|
GstMapInfo info;
|
||||||
gsize size;
|
guint samples = 0, written;
|
||||||
guint samples, written;
|
|
||||||
gint bpf, rate;
|
gint bpf, rate;
|
||||||
gint accum;
|
gint accum;
|
||||||
gint out_samples;
|
gint out_samples;
|
||||||
@ -1670,7 +1674,7 @@ gst_audio_base_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
|||||||
|
|
||||||
/* Before we go on, let's see if we need to payload the data. If yes, we also
|
/* Before we go on, let's see if we need to payload the data. If yes, we also
|
||||||
* need to unref the output buffer before leaving. */
|
* need to unref the output buffer before leaving. */
|
||||||
if (bclass->payload) {
|
if (buf && bclass->payload) {
|
||||||
out = bclass->payload (sink, buf);
|
out = bclass->payload (sink, buf);
|
||||||
|
|
||||||
if (!out)
|
if (!out)
|
||||||
@ -1682,19 +1686,31 @@ gst_audio_base_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
|||||||
bpf = GST_AUDIO_INFO_BPF (&ringbuf->spec.info);
|
bpf = GST_AUDIO_INFO_BPF (&ringbuf->spec.info);
|
||||||
rate = GST_AUDIO_INFO_RATE (&ringbuf->spec.info);
|
rate = GST_AUDIO_INFO_RATE (&ringbuf->spec.info);
|
||||||
|
|
||||||
size = gst_buffer_get_size (buf);
|
if (buf) {
|
||||||
if (G_UNLIKELY (size % bpf) != 0)
|
gsize size = gst_buffer_get_size (buf);
|
||||||
goto wrong_size;
|
if (G_UNLIKELY (size % bpf) != 0)
|
||||||
|
goto wrong_size;
|
||||||
|
|
||||||
samples = size / bpf;
|
samples = size / bpf;
|
||||||
|
} else if (duration != GST_CLOCK_TIME_NONE) {
|
||||||
|
/* Convert the passed duration to a number of samples */
|
||||||
|
samples = gst_util_uint64_scale_int (duration, rate, GST_SECOND);
|
||||||
|
}
|
||||||
out_samples = samples;
|
out_samples = samples;
|
||||||
|
|
||||||
in_offset = GST_BUFFER_OFFSET (buf);
|
/* Last ditch attempt to ensure that we only place silence if
|
||||||
time = GST_BUFFER_TIMESTAMP (buf);
|
* we are in trickmode no-audio mode by dropping the buffer contents.
|
||||||
|
* We then continue calculations based on the passed times/duration */
|
||||||
|
if (G_UNLIKELY ((bsink->segment.flags & GST_SEGMENT_FLAG_TRICKMODE_NO_AUDIO)
|
||||||
|
|| (buf && GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_GAP)))) {
|
||||||
|
GST_DEBUG_OBJECT (bsink,
|
||||||
|
"Received GAP or ignoring audio for trickplay. Dropping contents");
|
||||||
|
buf = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (sink,
|
GST_DEBUG_OBJECT (sink,
|
||||||
"time %" GST_TIME_FORMAT ", offset %" G_GUINT64_FORMAT ", start %"
|
"time %" GST_TIME_FORMAT ", start %"
|
||||||
GST_TIME_FORMAT ", samples %u", GST_TIME_ARGS (time), in_offset,
|
GST_TIME_FORMAT ", samples %u", GST_TIME_ARGS (time),
|
||||||
GST_TIME_ARGS (bsink->segment.start), samples);
|
GST_TIME_ARGS (bsink->segment.start), samples);
|
||||||
|
|
||||||
offset = 0;
|
offset = 0;
|
||||||
@ -1704,8 +1720,8 @@ gst_audio_base_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
|||||||
if (!GST_CLOCK_TIME_IS_VALID (time)) {
|
if (!GST_CLOCK_TIME_IS_VALID (time)) {
|
||||||
render_start = gst_audio_base_sink_get_offset (sink);
|
render_start = gst_audio_base_sink_get_offset (sink);
|
||||||
render_stop = render_start + samples;
|
render_stop = render_start + samples;
|
||||||
GST_DEBUG_OBJECT (sink, "Buffer of size %" G_GSIZE_FORMAT " has no time."
|
GST_DEBUG_OBJECT (sink, "Samples have no timestamp."
|
||||||
" Using render_start=%" G_GUINT64_FORMAT, size, render_start);
|
" Using render_start=%" G_GUINT64_FORMAT, render_start);
|
||||||
/* we don't have a start so we don't know stop either */
|
/* we don't have a start so we don't know stop either */
|
||||||
stop = -1;
|
stop = -1;
|
||||||
goto no_align;
|
goto no_align;
|
||||||
@ -1896,10 +1912,12 @@ gst_audio_base_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* always resync after a discont */
|
/* always resync after a discont */
|
||||||
if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT) ||
|
if (G_LIKELY (buf)) {
|
||||||
GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_RESYNC))) {
|
if (G_UNLIKELY (GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DISCONT) ||
|
||||||
GST_DEBUG_OBJECT (sink, "resync after discont/resync");
|
GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_RESYNC))) {
|
||||||
goto no_align;
|
GST_DEBUG_OBJECT (sink, "resync after discont/resync");
|
||||||
|
goto no_align;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* resync when we don't know what to align the sample with */
|
/* resync when we don't know what to align the sample with */
|
||||||
@ -1939,37 +1957,48 @@ no_align:
|
|||||||
/* we need to accumulate over different runs for when we get interrupted */
|
/* we need to accumulate over different runs for when we get interrupted */
|
||||||
accum = 0;
|
accum = 0;
|
||||||
align_next = TRUE;
|
align_next = TRUE;
|
||||||
gst_buffer_map (buf, &info, GST_MAP_READ);
|
if (G_LIKELY (buf)) {
|
||||||
do {
|
gst_buffer_map (buf, &info, GST_MAP_READ);
|
||||||
written =
|
do {
|
||||||
gst_audio_ring_buffer_commit (ringbuf, &sample_offset,
|
written =
|
||||||
info.data + offset, samples, out_samples, &accum);
|
gst_audio_ring_buffer_commit (ringbuf, &sample_offset,
|
||||||
|
info.data + offset, samples, out_samples, &accum);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (sink, "wrote %u of %u", written, samples);
|
GST_DEBUG_OBJECT (sink, "wrote %u of %u", written, samples);
|
||||||
/* if we wrote all, we're done */
|
/* if we wrote all, we're done */
|
||||||
if (G_LIKELY (written == samples))
|
if (G_LIKELY (written == samples))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* else something interrupted us and we wait for preroll. */
|
/* else something interrupted us and we wait for preroll. */
|
||||||
if ((ret = gst_base_sink_wait_preroll (bsink)) != GST_FLOW_OK)
|
if ((ret = gst_base_sink_wait_preroll (bsink)) != GST_FLOW_OK)
|
||||||
goto stopping;
|
goto stopping;
|
||||||
|
|
||||||
/* if we got interrupted, we cannot assume that the next sample should
|
/* if we got interrupted, we cannot assume that the next sample should
|
||||||
* be aligned to this one */
|
* be aligned to this one */
|
||||||
align_next = FALSE;
|
align_next = FALSE;
|
||||||
|
|
||||||
/* update the output samples. FIXME, this will just skip them when pausing
|
/* update the output samples. FIXME, this will just skip them when pausing
|
||||||
* during trick mode */
|
* during trick mode */
|
||||||
if (out_samples > written) {
|
if (out_samples > written) {
|
||||||
out_samples -= written;
|
out_samples -= written;
|
||||||
accum = 0;
|
accum = 0;
|
||||||
} else
|
} else
|
||||||
break;
|
break;
|
||||||
|
|
||||||
samples -= written;
|
samples -= written;
|
||||||
offset += written * bpf;
|
offset += written * bpf;
|
||||||
} while (TRUE);
|
} while (TRUE);
|
||||||
gst_buffer_unmap (buf, &info);
|
gst_buffer_unmap (buf, &info);
|
||||||
|
} else {
|
||||||
|
GstClockTime buffer_time = ringbuf->spec.buffer_time * GST_USECOND;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (sink, "Discarded audio content. Starting ringbuffer");
|
||||||
|
gst_audio_base_sink_force_start (sink);
|
||||||
|
/* Wait until the time when we would have written out this timestamp */
|
||||||
|
if (sink->priv->eos_time != -1 && sink->priv->eos_time > buffer_time)
|
||||||
|
gst_base_sink_wait (GST_BASE_SINK (sink),
|
||||||
|
sink->priv->eos_time - buffer_time, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
if (G_LIKELY (align_next))
|
if (G_LIKELY (align_next))
|
||||||
sink->next_sample = sample_offset;
|
sink->next_sample = sample_offset;
|
||||||
@ -2046,6 +2075,14 @@ sync_latency_failed:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static GstFlowReturn
|
||||||
|
gst_audio_base_sink_render (GstBaseSink * bsink, GstBuffer * buf)
|
||||||
|
{
|
||||||
|
GstClockTime ts = GST_BUFFER_TIMESTAMP (buf);
|
||||||
|
GstClockTime dur = GST_BUFFER_DURATION (buf);
|
||||||
|
return gst_audio_base_sink_render_samples (bsink, buf, ts, dur);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gst_audio_base_sink_create_ringbuffer:
|
* gst_audio_base_sink_create_ringbuffer:
|
||||||
* @sink: a #GstAudioBaseSink.
|
* @sink: a #GstAudioBaseSink.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user