1*4882a593SmuzhiyunFrom d1f8653d907d5a6b96dbe7e287a35cbc595a24f2 Mon Sep 17 00:00:00 2001
2*4882a593SmuzhiyunFrom: =?UTF-8?q?St=C3=A9phane=20Cerveau?= <scerveau@collabora.com>
3*4882a593SmuzhiyunDate: Mon, 9 Aug 2021 18:02:57 +0200
4*4882a593SmuzhiyunSubject: [PATCH 03/14] playbin: do not drain on first EOS
5*4882a593Smuzhiyun
6*4882a593SmuzhiyunIn a case of audio/video media, the decodebin
7*4882a593Smuzhiyunshould wait for each branch to be on EOS before
8*4882a593Smuzhiyundraining the others.
9*4882a593Smuzhiyun
10*4882a593SmuzhiyunA new signal "wait-on-eos" has been implemented
11*4882a593Smuzhiyunfor (uri)decodebin to tell that an EOS has been
12*4882a593Smuzhiyunreceived on a branch.
13*4882a593Smuzhiyun
14*4882a593SmuzhiyunIn the case of playbin2, it will compare
15*4882a593Smuzhiyunthe nb of active pads with the nb of EOS received
16*4882a593Smuzhiyunand decodebin will start to drain all the active pads when the nb
17*4882a593Smuzhiyunof EOS is equal to active pads (active combiners).
18*4882a593Smuzhiyun---
19*4882a593Smuzhiyun gst/playback/gstdecodebin2.c   | 37 ++++++++++++++++++++++++++++++++++
20*4882a593Smuzhiyun gst/playback/gstplaybin2.c     | 31 ++++++++++++++++++++++++++++
21*4882a593Smuzhiyun gst/playback/gsturidecodebin.c | 32 +++++++++++++++++++++++++++++
22*4882a593Smuzhiyun 3 files changed, 100 insertions(+)
23*4882a593Smuzhiyun
24*4882a593Smuzhiyundiff --git a/gst/playback/gstdecodebin2.c b/gst/playback/gstdecodebin2.c
25*4882a593Smuzhiyunindex 1849714..b84a30d 100644
26*4882a593Smuzhiyun--- a/gst/playback/gstdecodebin2.c
27*4882a593Smuzhiyun+++ b/gst/playback/gstdecodebin2.c
28*4882a593Smuzhiyun@@ -163,6 +163,9 @@ struct _GstDecodeBin
29*4882a593Smuzhiyun   GMutex expose_lock;           /* Protects exposal and removal of groups */
30*4882a593Smuzhiyun   GstDecodeChain *decode_chain; /* Top level decode chain */
31*4882a593Smuzhiyun   guint nbpads;                 /* unique identifier for source pads */
32*4882a593Smuzhiyun+  guint nbpads_eos;             /* number of pads in EOS */
33*4882a593Smuzhiyun+  gboolean wait_on_eos;         /* wait EOS on other pads */
34*4882a593Smuzhiyun+  GCond eos_cond;               /* condition to block the pad in EOS */
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun   GMutex factories_lock;
37*4882a593Smuzhiyun   guint32 factories_cookie;     /* Cookie from last time when factories was updated */
38*4882a593Smuzhiyun@@ -224,6 +227,8 @@ struct _GstDecodeBinClass
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun   /* fired when the last group is drained */
41*4882a593Smuzhiyun   void (*drained) (GstElement * element);
42*4882a593Smuzhiyun+  /* emitted when an EOS is received */
43*4882a593Smuzhiyun+    gboolean (*wait_on_eos) (GstElement * element, guint eos_received);
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun
46*4882a593Smuzhiyun /* signals */
47*4882a593Smuzhiyun@@ -236,6 +241,7 @@ enum
48*4882a593Smuzhiyun   SIGNAL_AUTOPLUG_SORT,
49*4882a593Smuzhiyun   SIGNAL_AUTOPLUG_QUERY,
50*4882a593Smuzhiyun   SIGNAL_DRAINED,
51*4882a593Smuzhiyun+  SIGNAL_WAIT_ON_EOS,
52*4882a593Smuzhiyun   LAST_SIGNAL
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun
55*4882a593Smuzhiyun@@ -870,6 +876,20 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
56*4882a593Smuzhiyun       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, drained),
57*4882a593Smuzhiyun       NULL, NULL, NULL, G_TYPE_NONE, 0, G_TYPE_NONE);
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun+  /**
60*4882a593Smuzhiyun+   * GstDecodeBin::wait-on-eos
61*4882a593Smuzhiyun+   * @bin: The decodebin
62*4882a593Smuzhiyun+   * @nb_eos: the number of EOS received
63*4882a593Smuzhiyun+   *
64*4882a593Smuzhiyun+   * This signal is emitted once decodebin has received an EOS.
65*4882a593Smuzhiyun+   *
66*4882a593Smuzhiyun+   * Since: 1.20
67*4882a593Smuzhiyun+   */
68*4882a593Smuzhiyun+  gst_decode_bin_signals[SIGNAL_WAIT_ON_EOS] =
69*4882a593Smuzhiyun+      g_signal_new ("wait-on-eos", G_TYPE_FROM_CLASS (klass),
70*4882a593Smuzhiyun+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodeBinClass, wait_on_eos),
71*4882a593Smuzhiyun+      NULL, NULL, NULL, G_TYPE_BOOLEAN, 1, G_TYPE_UINT);
72*4882a593Smuzhiyun+
73*4882a593Smuzhiyun   g_object_class_install_property (gobject_klass, PROP_CAPS,
74*4882a593Smuzhiyun       g_param_spec_boxed ("caps", "Caps", "The caps on which to stop decoding.",
75*4882a593Smuzhiyun           GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
76*4882a593Smuzhiyun@@ -1111,6 +1131,7 @@ gst_decode_bin_init (GstDecodeBin * decode_bin)
77*4882a593Smuzhiyun     gst_object_unref (pad);
78*4882a593Smuzhiyun   }
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun+  g_cond_init (&decode_bin->eos_cond);
81*4882a593Smuzhiyun   g_mutex_init (&decode_bin->expose_lock);
82*4882a593Smuzhiyun   decode_bin->decode_chain = NULL;
83*4882a593Smuzhiyun
84*4882a593Smuzhiyun@@ -1177,6 +1198,7 @@ gst_decode_bin_finalize (GObject * object)
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun   decode_bin = GST_DECODE_BIN (object);
87*4882a593Smuzhiyun
88*4882a593Smuzhiyun+  g_cond_clear (&decode_bin->eos_cond);
89*4882a593Smuzhiyun   g_mutex_clear (&decode_bin->expose_lock);
90*4882a593Smuzhiyun   g_mutex_clear (&decode_bin->dyn_lock);
91*4882a593Smuzhiyun   g_mutex_clear (&decode_bin->subtitle_lock);
92*4882a593Smuzhiyun@@ -4285,6 +4307,17 @@ gst_decode_pad_handle_eos (GstDecodePad * pad)
93*4882a593Smuzhiyun   }
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun   EXPOSE_LOCK (dbin);
96*4882a593Smuzhiyun+  dbin->nbpads_eos++;
97*4882a593Smuzhiyun+  g_signal_emit (G_OBJECT (dbin),
98*4882a593Smuzhiyun+      gst_decode_bin_signals[SIGNAL_WAIT_ON_EOS], 0, dbin->nbpads_eos,
99*4882a593Smuzhiyun+      &dbin->wait_on_eos);
100*4882a593Smuzhiyun+  g_cond_broadcast (&dbin->eos_cond);
101*4882a593Smuzhiyun+  GST_DEBUG_OBJECT (dbin, "dbin->nbpads_eos %u wait_on_eos %u",
102*4882a593Smuzhiyun+      dbin->nbpads_eos, dbin->wait_on_eos);
103*4882a593Smuzhiyun+
104*4882a593Smuzhiyun+  while (dbin->wait_on_eos)
105*4882a593Smuzhiyun+    g_cond_wait (&dbin->eos_cond, &dbin->expose_lock);
106*4882a593Smuzhiyun+
107*4882a593Smuzhiyun   if (dbin->decode_chain) {
108*4882a593Smuzhiyun     drain_and_switch_chains (dbin->decode_chain, pad, &last_group, &drained,
109*4882a593Smuzhiyun         &switched);
110*4882a593Smuzhiyun@@ -5326,6 +5359,10 @@ unblock_pads (GstDecodeBin * dbin)
111*4882a593Smuzhiyun     GST_DEBUG_OBJECT (dpad, "unblocked");
112*4882a593Smuzhiyun     gst_object_unref (dpad);
113*4882a593Smuzhiyun   }
114*4882a593Smuzhiyun+  dbin->nbpads = 0;
115*4882a593Smuzhiyun+  dbin->nbpads_eos = 0;
116*4882a593Smuzhiyun+  dbin->wait_on_eos = FALSE;
117*4882a593Smuzhiyun+  g_cond_broadcast (&dbin->eos_cond);
118*4882a593Smuzhiyun }
119*4882a593Smuzhiyun
120*4882a593Smuzhiyun static void
121*4882a593Smuzhiyundiff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c
122*4882a593Smuzhiyunindex 51751ff..4098fb9 100644
123*4882a593Smuzhiyun--- a/gst/playback/gstplaybin2.c
124*4882a593Smuzhiyun+++ b/gst/playback/gstplaybin2.c
125*4882a593Smuzhiyun@@ -337,6 +337,7 @@ struct _GstSourceGroup
126*4882a593Smuzhiyun   gulong notify_source_id;
127*4882a593Smuzhiyun   gulong source_setup_id;
128*4882a593Smuzhiyun   gulong drained_id;
129*4882a593Smuzhiyun+  gulong wait_on_eos_id;
130*4882a593Smuzhiyun   gulong autoplug_factories_id;
131*4882a593Smuzhiyun   gulong autoplug_select_id;
132*4882a593Smuzhiyun   gulong autoplug_continue_id;
133*4882a593Smuzhiyun@@ -3932,6 +3933,30 @@ drained_cb (GstElement * decodebin, GstSourceGroup * group)
134*4882a593Smuzhiyun   group->pending_about_to_finish = TRUE;
135*4882a593Smuzhiyun }
136*4882a593Smuzhiyun
137*4882a593Smuzhiyun+static gboolean
138*4882a593Smuzhiyun+wait_on_eos_cb (GstElement * decodebin, guint eos_received,
139*4882a593Smuzhiyun+    GstSourceGroup * group)
140*4882a593Smuzhiyun+{
141*4882a593Smuzhiyun+  GstPlayBin *playbin = group->playbin;
142*4882a593Smuzhiyun+  int i;
143*4882a593Smuzhiyun+  guint active_pads = 0;
144*4882a593Smuzhiyun+
145*4882a593Smuzhiyun+  for (i = 0; i < PLAYBIN_STREAM_LAST; i++) {
146*4882a593Smuzhiyun+    GstSourceCombine *combine = &group->combiner[i];
147*4882a593Smuzhiyun+    if (combine->has_active_pad)
148*4882a593Smuzhiyun+      active_pads++;
149*4882a593Smuzhiyun+  }
150*4882a593Smuzhiyun+
151*4882a593Smuzhiyun+  GST_DEBUG_OBJECT (playbin,
152*4882a593Smuzhiyun+      "%d eos received in group with uri %s, active pads %d", eos_received,
153*4882a593Smuzhiyun+      group->uri, active_pads);
154*4882a593Smuzhiyun+
155*4882a593Smuzhiyun+  if (eos_received < active_pads)
156*4882a593Smuzhiyun+    return TRUE;
157*4882a593Smuzhiyun+
158*4882a593Smuzhiyun+  return FALSE;
159*4882a593Smuzhiyun+}
160*4882a593Smuzhiyun+
161*4882a593Smuzhiyun /* Like gst_element_factory_can_sink_any_caps() but doesn't
162*4882a593Smuzhiyun  * allow ANY caps on the sinkpad template */
163*4882a593Smuzhiyun static gboolean
164*4882a593Smuzhiyun@@ -5401,6 +5426,10 @@ activate_group (GstPlayBin * playbin, GstSourceGroup * group, GstState target)
165*4882a593Smuzhiyun   group->drained_id =
166*4882a593Smuzhiyun       g_signal_connect (uridecodebin, "drained", G_CALLBACK (drained_cb),
167*4882a593Smuzhiyun       group);
168*4882a593Smuzhiyun+  /* is called when the uridecodebin received an EOS */
169*4882a593Smuzhiyun+  group->wait_on_eos_id =
170*4882a593Smuzhiyun+      g_signal_connect (uridecodebin, "wait-on-eos",
171*4882a593Smuzhiyun+      G_CALLBACK (wait_on_eos_cb), group);
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun   /* will be called when a new media type is found. We return a list of decoders
174*4882a593Smuzhiyun    * including sinks for decodebin to try */
175*4882a593Smuzhiyun@@ -5574,6 +5603,7 @@ error_cleanup:
176*4882a593Smuzhiyun       REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
177*4882a593Smuzhiyun       REMOVE_SIGNAL (group->uridecodebin, group->source_setup_id);
178*4882a593Smuzhiyun       REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
179*4882a593Smuzhiyun+      REMOVE_SIGNAL (group->uridecodebin, group->wait_on_eos_id);
180*4882a593Smuzhiyun       REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
181*4882a593Smuzhiyun       REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
182*4882a593Smuzhiyun       REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
183*4882a593Smuzhiyun@@ -5663,6 +5693,7 @@ deactivate_group (GstPlayBin * playbin, GstSourceGroup * group)
184*4882a593Smuzhiyun     REMOVE_SIGNAL (group->uridecodebin, group->notify_source_id);
185*4882a593Smuzhiyun     REMOVE_SIGNAL (group->uridecodebin, group->source_setup_id);
186*4882a593Smuzhiyun     REMOVE_SIGNAL (group->uridecodebin, group->drained_id);
187*4882a593Smuzhiyun+    REMOVE_SIGNAL (group->uridecodebin, group->wait_on_eos_id);
188*4882a593Smuzhiyun     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_factories_id);
189*4882a593Smuzhiyun     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_select_id);
190*4882a593Smuzhiyun     REMOVE_SIGNAL (group->uridecodebin, group->autoplug_continue_id);
191*4882a593Smuzhiyundiff --git a/gst/playback/gsturidecodebin.c b/gst/playback/gsturidecodebin.c
192*4882a593Smuzhiyunindex a128d92..7031600 100644
193*4882a593Smuzhiyun--- a/gst/playback/gsturidecodebin.c
194*4882a593Smuzhiyun+++ b/gst/playback/gsturidecodebin.c
195*4882a593Smuzhiyun@@ -148,6 +148,8 @@ struct _GstURIDecodeBinClass
196*4882a593Smuzhiyun
197*4882a593Smuzhiyun   /* emitted when all data is decoded */
198*4882a593Smuzhiyun   void (*drained) (GstElement * element);
199*4882a593Smuzhiyun+  /* emitted when an EOS is received */
200*4882a593Smuzhiyun+    gboolean (*wait_on_eos) (GstElement * element, guint eos_received);
201*4882a593Smuzhiyun };
202*4882a593Smuzhiyun
203*4882a593Smuzhiyun static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src_%u",
204*4882a593Smuzhiyun@@ -171,6 +173,7 @@ enum
205*4882a593Smuzhiyun   SIGNAL_AUTOPLUG_QUERY,
206*4882a593Smuzhiyun   SIGNAL_DRAINED,
207*4882a593Smuzhiyun   SIGNAL_SOURCE_SETUP,
208*4882a593Smuzhiyun+  SIGNAL_WAIT_ON_EOS,
209*4882a593Smuzhiyun   LAST_SIGNAL
210*4882a593Smuzhiyun };
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun@@ -713,6 +716,19 @@ gst_uri_decode_bin_class_init (GstURIDecodeBinClass * klass)
213*4882a593Smuzhiyun       G_SIGNAL_RUN_LAST,
214*4882a593Smuzhiyun       G_STRUCT_OFFSET (GstURIDecodeBinClass, drained), NULL, NULL, NULL,
215*4882a593Smuzhiyun       G_TYPE_NONE, 0, G_TYPE_NONE);
216*4882a593Smuzhiyun+  /**
217*4882a593Smuzhiyun+   * GstURIDecodeBin::wait-on-eos
218*4882a593Smuzhiyun+   * @bin: The decodebin
219*4882a593Smuzhiyun+   * @nb_eos: the number of EOS received
220*4882a593Smuzhiyun+   *
221*4882a593Smuzhiyun+   * This signal is emitted once decodebin has received an EOS.
222*4882a593Smuzhiyun+   *
223*4882a593Smuzhiyun+   * Since: 1.20
224*4882a593Smuzhiyun+   */
225*4882a593Smuzhiyun+  gst_uri_decode_bin_signals[SIGNAL_WAIT_ON_EOS] =
226*4882a593Smuzhiyun+      g_signal_new ("wait-on-eos", G_TYPE_FROM_CLASS (klass),
227*4882a593Smuzhiyun+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstURIDecodeBinClass, wait_on_eos),
228*4882a593Smuzhiyun+      NULL, NULL, NULL, G_TYPE_BOOLEAN, 1, G_TYPE_UINT);
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun   /**
231*4882a593Smuzhiyun    * GstURIDecodeBin::source-setup:
232*4882a593Smuzhiyun@@ -1838,6 +1854,20 @@ proxy_drained_signal (GstElement * decodebin, GstURIDecodeBin * dec)
233*4882a593Smuzhiyun   g_signal_emit (dec, gst_uri_decode_bin_signals[SIGNAL_DRAINED], 0, NULL);
234*4882a593Smuzhiyun }
235*4882a593Smuzhiyun
236*4882a593Smuzhiyun+
237*4882a593Smuzhiyun+static gboolean
238*4882a593Smuzhiyun+proxy_wait_on_eos_signal (GstElement * decodebin, guint eos_received,
239*4882a593Smuzhiyun+    GstURIDecodeBin * dec)
240*4882a593Smuzhiyun+{
241*4882a593Smuzhiyun+  gboolean result;
242*4882a593Smuzhiyun+
243*4882a593Smuzhiyun+  g_signal_emit (dec, gst_uri_decode_bin_signals[SIGNAL_WAIT_ON_EOS], 0,
244*4882a593Smuzhiyun+      eos_received, &result);
245*4882a593Smuzhiyun+  GST_DEBUG_OBJECT (dec, "wait-on-eos returned %d", result);
246*4882a593Smuzhiyun+
247*4882a593Smuzhiyun+  return result;
248*4882a593Smuzhiyun+}
249*4882a593Smuzhiyun+
250*4882a593Smuzhiyun /* make a decodebin and connect to all the signals */
251*4882a593Smuzhiyun static GstElement *
252*4882a593Smuzhiyun make_decoder (GstURIDecodeBin * decoder)
253*4882a593Smuzhiyun@@ -1881,6 +1911,8 @@ make_decoder (GstURIDecodeBin * decoder)
254*4882a593Smuzhiyun         G_CALLBACK (proxy_autoplug_query_signal), decoder);
255*4882a593Smuzhiyun     g_signal_connect (decodebin, "drained",
256*4882a593Smuzhiyun         G_CALLBACK (proxy_drained_signal), decoder);
257*4882a593Smuzhiyun+    g_signal_connect (decodebin, "wait-on-eos",
258*4882a593Smuzhiyun+        G_CALLBACK (proxy_wait_on_eos_signal), decoder);
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun     /* set up callbacks to create the links between decoded data
261*4882a593Smuzhiyun      * and video/audio/subtitle rendering/output. */
262*4882a593Smuzhiyun--
263*4882a593Smuzhiyun2.20.1
264*4882a593Smuzhiyun
265