/** * gst_segment_offset_running_time: * @segment: a #GstSegment structure. * @format: the format of the segment. * @offset: the offset to apply in the segment * * Adjust the values in @segment so that @offset is applied to all * future running-time calculations. * * Since: 1.2.3 * * Returns: %TRUE if the segment could be updated successfully. If %FALSE is * returned, @offset is not in @segment. */ gboolean gst_segment_offset_running_time (GstSegment * segment, GstFormat format, gint64 offset) { g_return_val_if_fail (segment != NULL, FALSE); g_return_val_if_fail (segment->format == format, FALSE); if (offset == 0) return TRUE; if (offset > 0) { /* positive offset, we can simply apply to the base time */ segment->base += offset; } else { offset = -offset; /* negative offset, first try to subtract from base */ if (segment->base > offset) { segment->base -= offset; } else { guint64 position; /* subtract all from segment.base, remainder in offset */ offset -= segment->base; segment->base = 0; position = gst_segment_position_from_running_time (segment, format, offset); if (position == -1) return FALSE; segment->offset = position - segment->start; } } return TRUE; }
/** * gst_segment_set_running_time: * @segment: a #GstSegment structure. * @format: the format of the segment. * @running_time: the running_time in the segment * * Adjust the start/stop and base values of @segment such that the next valid * buffer will be one with @running_time. * * Returns: %TRUE if the segment could be updated successfully. If %FALSE is * returned, @running_time is -1 or not in @segment. */ gboolean gst_segment_set_running_time (GstSegment * segment, GstFormat format, guint64 running_time) { guint64 position; guint64 start, stop; /* start by bringing the running_time into the segment position */ position = gst_segment_position_from_running_time (segment, format, running_time); /* we must have a valid position now */ if (G_UNLIKELY (position == -1)) return FALSE; start = segment->start; stop = segment->stop; if (G_LIKELY (segment->rate > 0.0)) { /* update the start and time values */ start = position; } else { /* reverse, update stop */ stop = position; } /* and base time is exactly the running time */ segment->time = gst_segment_to_stream_time (segment, format, start); segment->start = start; segment->stop = stop; segment->base = running_time; return TRUE; }
guint64 gst_segment_to_position (const GstSegment * segment, GstFormat format, guint64 running_time) { return gst_segment_position_from_running_time (segment, format, running_time); }
/* Called with the object lock for both the element and pad held, * as well as the aagg lock */ static gboolean gst_audio_aggregator_fill_buffer (GstAudioAggregator * aagg, GstAudioAggregatorPad * pad, GstBuffer * inbuf) { GstClockTime start_time, end_time; gboolean discont = FALSE; guint64 start_offset, end_offset; gint rate, bpf; GstAggregator *agg = GST_AGGREGATOR (aagg); GstAggregatorPad *aggpad = GST_AGGREGATOR_PAD (pad); g_assert (pad->priv->buffer == NULL); rate = GST_AUDIO_INFO_RATE (&pad->info); bpf = GST_AUDIO_INFO_BPF (&pad->info); pad->priv->position = 0; pad->priv->size = gst_buffer_get_size (inbuf) / bpf; if (!GST_BUFFER_PTS_IS_VALID (inbuf)) { if (pad->priv->output_offset == -1) pad->priv->output_offset = aagg->priv->offset; if (pad->priv->next_offset == -1) pad->priv->next_offset = pad->priv->size; else pad->priv->next_offset += pad->priv->size; goto done; } start_time = GST_BUFFER_PTS (inbuf); end_time = start_time + gst_util_uint64_scale_ceil (pad->priv->size, GST_SECOND, rate); /* Clipping should've ensured this */ g_assert (start_time >= aggpad->segment.start); start_offset = gst_util_uint64_scale (start_time - aggpad->segment.start, rate, GST_SECOND); end_offset = start_offset + pad->priv->size; if (GST_BUFFER_IS_DISCONT (inbuf) || GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_RESYNC) || pad->priv->new_segment || pad->priv->next_offset == -1) { discont = TRUE; pad->priv->new_segment = FALSE; } else { guint64 diff, max_sample_diff; /* Check discont, based on audiobasesink */ if (start_offset <= pad->priv->next_offset) diff = pad->priv->next_offset - start_offset; else diff = start_offset - pad->priv->next_offset; max_sample_diff = gst_util_uint64_scale_int (aagg->priv->alignment_threshold, rate, GST_SECOND); /* Discont! */ if (G_UNLIKELY (diff >= max_sample_diff)) { if (aagg->priv->discont_wait > 0) { if (pad->priv->discont_time == GST_CLOCK_TIME_NONE) { pad->priv->discont_time = start_time; } else if (start_time - pad->priv->discont_time >= aagg->priv->discont_wait) { discont = TRUE; pad->priv->discont_time = GST_CLOCK_TIME_NONE; } } else { discont = TRUE; } } else if (G_UNLIKELY (pad->priv->discont_time != GST_CLOCK_TIME_NONE)) { /* we have had a discont, but are now back on track! */ pad->priv->discont_time = GST_CLOCK_TIME_NONE; } } if (discont) { /* Have discont, need resync */ if (pad->priv->next_offset != -1) GST_DEBUG_OBJECT (pad, "Have discont. Expected %" G_GUINT64_FORMAT ", got %" G_GUINT64_FORMAT, pad->priv->next_offset, start_offset); pad->priv->output_offset = -1; pad->priv->next_offset = end_offset; } else { pad->priv->next_offset += pad->priv->size; } if (pad->priv->output_offset == -1) { GstClockTime start_running_time; GstClockTime end_running_time; guint64 start_output_offset; guint64 end_output_offset; start_running_time = gst_segment_to_running_time (&aggpad->segment, GST_FORMAT_TIME, start_time); end_running_time = gst_segment_to_running_time (&aggpad->segment, GST_FORMAT_TIME, end_time); /* Convert to position in the output segment */ start_output_offset = gst_segment_position_from_running_time (&agg->segment, GST_FORMAT_TIME, start_running_time); if (start_output_offset != -1) start_output_offset = gst_util_uint64_scale (start_output_offset - agg->segment.start, rate, GST_SECOND); end_output_offset = gst_segment_position_from_running_time (&agg->segment, GST_FORMAT_TIME, end_running_time); if (end_output_offset != -1) end_output_offset = gst_util_uint64_scale (end_output_offset - agg->segment.start, rate, GST_SECOND); if (start_output_offset == -1 && end_output_offset == -1) { /* Outside output segment, drop */ gst_buffer_unref (inbuf); pad->priv->buffer = NULL; pad->priv->position = 0; pad->priv->size = 0; pad->priv->output_offset = -1; GST_DEBUG_OBJECT (pad, "Buffer outside output segment"); return FALSE; } /* Calculate end_output_offset if it was outside the output segment */ if (end_output_offset == -1) end_output_offset = start_output_offset + pad->priv->size; if (end_output_offset < aagg->priv->offset) { /* Before output segment, drop */ gst_buffer_unref (inbuf); pad->priv->buffer = NULL; pad->priv->position = 0; pad->priv->size = 0; pad->priv->output_offset = -1; GST_DEBUG_OBJECT (pad, "Buffer before segment or current position: %" G_GUINT64_FORMAT " < %" G_GINT64_FORMAT, end_output_offset, aagg->priv->offset); return FALSE; } if (start_output_offset == -1 || start_output_offset < aagg->priv->offset) { guint diff; if (start_output_offset == -1 && end_output_offset < pad->priv->size) { diff = pad->priv->size - end_output_offset + aagg->priv->offset; } else if (start_output_offset == -1) { start_output_offset = end_output_offset - pad->priv->size; if (start_output_offset < aagg->priv->offset) diff = aagg->priv->offset - start_output_offset; else diff = 0; } else { diff = aagg->priv->offset - start_output_offset; } pad->priv->position += diff; if (pad->priv->position >= pad->priv->size) { /* Empty buffer, drop */ gst_buffer_unref (inbuf); pad->priv->buffer = NULL; pad->priv->position = 0; pad->priv->size = 0; pad->priv->output_offset = -1; GST_DEBUG_OBJECT (pad, "Buffer before segment or current position: %" G_GUINT64_FORMAT " < %" G_GINT64_FORMAT, end_output_offset, aagg->priv->offset); return FALSE; } } if (start_output_offset == -1 || start_output_offset < aagg->priv->offset) pad->priv->output_offset = aagg->priv->offset; else pad->priv->output_offset = start_output_offset; GST_DEBUG_OBJECT (pad, "Buffer resynced: Pad offset %" G_GUINT64_FORMAT ", current audio aggregator offset %" G_GINT64_FORMAT, pad->priv->output_offset, aagg->priv->offset); } done: GST_LOG_OBJECT (pad, "Queued new buffer at offset %" G_GUINT64_FORMAT, pad->priv->output_offset); pad->priv->buffer = inbuf; return TRUE; }