base: audioencoder: Keep serialize event behind buffers

If a serialized event arrives behind a buffer, it should not be send before
it. This fixes the pending event handling so that only early pending events,
the one that arrrived or was generated while the adapter was empty get send
before pushing buffer. All other events are not pushed after.

This issue lead the latency tracer to think our audio encoder did not have any
latency. This was testing with opusenc in a live pipeline.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1266>
This commit is contained in:
Nicolas Dufresne 2021-10-28 17:09:34 -04:00
parent e1c0628bb9
commit 6bd1f2753a

View file

@ -171,6 +171,7 @@ typedef struct _GstAudioEncoderContext
/* MT-protected (with LOCK) */
GstClockTime min_latency;
GstClockTime max_latency;
gboolean negotiated;
GList *headers;
gboolean new_headers;
@ -239,6 +240,11 @@ struct _GstAudioEncoderPrivate
/* pending serialized sink events, will be sent from finish_frame() */
GList *pending_events;
/* these are initial events or events that came in while there was nothing
* in the adapter. these events shall be sent after negotiation but before
* we push the following buffer. */
GList *early_pending_events;
};
@ -499,8 +505,11 @@ gst_audio_encoder_reset (GstAudioEncoder * enc, gboolean full)
enc->priv->tags_merge_mode = GST_TAG_MERGE_APPEND;
enc->priv->tags_changed = FALSE;
g_list_foreach (enc->priv->pending_events, (GFunc) gst_event_unref, NULL);
g_list_free (enc->priv->pending_events);
g_list_free_full (enc->priv->early_pending_events,
(GDestroyNotify) gst_event_unref);
enc->priv->early_pending_events = NULL;
g_list_free_full (enc->priv->pending_events,
(GDestroyNotify) gst_event_unref);
enc->priv->pending_events = NULL;
}
@ -597,11 +606,31 @@ gst_audio_encoder_push_event (GstAudioEncoder * enc, GstEvent * event)
return gst_pad_push_event (enc->srcpad, event);
}
static inline void
gst_audio_encoder_push_early_pending_events (GstAudioEncoder * enc)
{
GstAudioEncoderPrivate *priv = enc->priv;
if (priv->early_pending_events) {
GList *pending_events, *l;
pending_events = priv->early_pending_events;
priv->early_pending_events = NULL;
GST_DEBUG_OBJECT (enc, "Pushing early pending events");
for (l = pending_events; l; l = l->next)
gst_audio_encoder_push_event (enc, l->data);
g_list_free (pending_events);
}
}
static inline void
gst_audio_encoder_push_pending_events (GstAudioEncoder * enc)
{
GstAudioEncoderPrivate *priv = enc->priv;
gst_audio_encoder_push_early_pending_events (enc);
if (priv->pending_events) {
GList *pending_events, *l;
@ -795,9 +824,9 @@ gst_audio_encoder_finish_frame (GstAudioEncoder * enc, GstBuffer * buf,
if (G_LIKELY (buf))
priv->got_data = TRUE;
gst_audio_encoder_push_pending_events (enc);
gst_audio_encoder_push_early_pending_events (enc);
/* send after pending events, which likely includes segment event */
/* send after early pending events, which likely includes segment event */
gst_audio_encoder_check_and_push_pending_tags (enc);
/* remove corresponding samples from input */
@ -1013,6 +1042,10 @@ gst_audio_encoder_finish_frame (GstAudioEncoder * enc, GstBuffer * buf,
ret = gst_pad_push (enc->srcpad, buf);
GST_LOG_OBJECT (enc, "buffer pushed: %s", gst_flow_get_name (ret));
/* Now push the events that followed after the buffer got into the
* adapter. */
gst_audio_encoder_push_pending_events (enc);
} else {
/* merely advance samples, most work for that already done above */
priv->samples += samples;
@ -1578,8 +1611,8 @@ gst_audio_encoder_sink_event_default (GstAudioEncoder * enc, GstEvent * event)
/* and follow along with segment */
enc->input_segment = seg;
enc->priv->pending_events =
g_list_append (enc->priv->pending_events, event);
enc->priv->early_pending_events =
g_list_append (enc->priv->early_pending_events, event);
GST_AUDIO_ENCODER_STREAM_UNLOCK (enc);
res = TRUE;
@ -1696,8 +1729,13 @@ gst_audio_encoder_sink_event_default (GstAudioEncoder * enc, GstEvent * event)
gst_pad_event_default (enc->sinkpad, GST_OBJECT_CAST (enc), event);
} else {
GST_AUDIO_ENCODER_STREAM_LOCK (enc);
enc->priv->pending_events =
g_list_append (enc->priv->pending_events, event);
if (gst_adapter_available (enc->priv->adapter) == 0) {
enc->priv->early_pending_events =
g_list_append (enc->priv->early_pending_events, event);
} else {
enc->priv->pending_events =
g_list_append (enc->priv->pending_events, event);
}
GST_AUDIO_ENCODER_STREAM_UNLOCK (enc);
res = TRUE;
}
@ -2732,10 +2770,10 @@ gst_audio_encoder_negotiate_default (GstAudioEncoder * enc)
GST_DEBUG_OBJECT (enc, "Setting srcpad caps %" GST_PTR_FORMAT, caps);
if (enc->priv->pending_events) {
if (enc->priv->early_pending_events) {
GList **pending_events, *l;
pending_events = &enc->priv->pending_events;
pending_events = &enc->priv->early_pending_events;
GST_DEBUG_OBJECT (enc, "Pushing pending events");
for (l = *pending_events; l;) {
@ -2814,6 +2852,8 @@ gst_audio_encoder_negotiate_unlocked (GstAudioEncoder * enc)
if (G_LIKELY (klass->negotiate))
ret = klass->negotiate (enc);
enc->priv->ctx.negotiated = TRUE;
return ret;
}