From 6fc6e934aaf903440f4178b02a18597b14f13ea0 Mon Sep 17 00:00:00 2001
From: Hou Qi <qi.hou@nxp.com>
Date: Mon, 22 May 2023 15:32:47 +0800
Subject: [PATCH] decodebin3: send sticky event to decoder after setting it to
 PAUSED

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4677>
---
 .../gst/playback/gstdecodebin3.c              | 51 +++++++++++++++++++
 1 file changed, 51 insertions(+)

diff --git a/subprojects/gst-plugins-base/gst/playback/gstdecodebin3.c b/subprojects/gst-plugins-base/gst/playback/gstdecodebin3.c
index 37cec16f41..bbdb27f8d4 100644
--- a/subprojects/gst-plugins-base/gst/playback/gstdecodebin3.c
+++ b/subprojects/gst-plugins-base/gst/playback/gstdecodebin3.c
@@ -888,6 +888,37 @@ decode_pad_set_target (GstGhostPad * pad, GstPad * target)
   return res;
 }
 
+typedef struct
+{
+  gboolean ret;
+  GstPad *peer;
+} SendStickyEventsData;
+
+static gboolean
+send_sticky_event (GstPad * pad, GstEvent ** event, gpointer user_data)
+{
+  SendStickyEventsData *data = user_data;
+
+  data->ret &= gst_pad_send_event (data->peer, gst_event_ref (*event));
+
+  return data->ret;
+}
+
+static gboolean
+send_sticky_events (GstDecodebin3 * dbin, GstPad * pad)
+{
+  SendStickyEventsData data;
+
+  data.ret = TRUE;
+  data.peer = gst_pad_get_peer (pad);
+
+  gst_pad_sticky_events_foreach (pad, send_sticky_event, &data);
+
+  gst_object_unref (data.peer);
+
+  return data.ret;
+}
+
 /* Call with INPUT_LOCK taken */
 static gboolean
 ensure_input_parsebin (GstDecodebin3 * dbin, DecodebinInput * input)
@@ -2968,6 +2999,26 @@ reconfigure_output_stream (DecodebinOutputStream * output,
         decoder_failed = TRUE;
         remove_decoder_link (output, slot);
       }
+
+      /* First lock element's sinkpad stream lock so no data reaches
+       * the possible new element added when caps are sent by element
+       * while we're still sending sticky events */
+      GST_PAD_STREAM_LOCK (output->decoder_sink);
+
+      if (gst_element_set_state (output->decoder,
+              GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE ||
+          !send_sticky_events (dbin, slot->src_pad)) {
+
+        GST_PAD_STREAM_UNLOCK (output->decoder_sink);
+        GST_WARNING_OBJECT (dbin,
+            "Decoder '%s' failed to reach PAUSED state",
+            GST_ELEMENT_NAME (output->decoder));
+        remove_decoder_link (output, slot);
+      } else {
+        /* Everything went well */
+        GST_PAD_STREAM_UNLOCK (output->decoder_sink);
+      }
+
       next_factory = next_factory->next;
     }
     gst_plugin_feature_list_free (factories);