1 /* GStreamer
2 *
3 * Copyright (C) <2015> Centricular Ltd
4 * @author: Edward Hervey <edward@centricular.com>
5 * @author: Jan Schmidt <jan@centricular.com>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #if 0
24 /* Not needed for now - we're including gstdecodebin3-parse.c into gstdecodebin3.c */
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28
29 #include <glib.h>
30 #include <glib-object.h>
31 #include <glib/gprintf.h>
32 #include <gst/gst.h>
33 #include <gst/pbutils/pbutils.h>
34
35 #include "gstplayback.h"
36 #endif
37
38 #define CUSTOM_EOS_QUARK _custom_eos_quark_get ()
39 #define CUSTOM_EOS_QUARK_DATA "custom-eos"
40 static GQuark
_custom_eos_quark_get(void)41 _custom_eos_quark_get (void)
42 {
43 static gsize g_quark;
44
45 if (g_once_init_enter (&g_quark)) {
46 gsize quark = (gsize) g_quark_from_static_string ("decodebin3-custom-eos");
47 g_once_init_leave (&g_quark, quark);
48 }
49 return g_quark;
50 }
51
52 /* Streams that come from demuxers (input/upstream) */
53 /* FIXME : All this is hardcoded. Switch to tree of chains */
54 struct _DecodebinInputStream
55 {
56 GstDecodebin3 *dbin;
57 GstStream *pending_stream; /* Extra ref */
58 GstStream *active_stream;
59
60 DecodebinInput *input;
61
62 GstPad *srcpad; /* From demuxer */
63
64 /* id of the pad event probe */
65 gulong output_event_probe_id;
66
67 /* id of the buffer blocking probe on the input (demuxer src) pad */
68 gulong input_buffer_probe_id;
69
70 /* Whether we saw an EOS on input. This should be treated accordingly
71 * when the stream is no longer used */
72 gboolean saw_eos;
73 };
74
75 static void parsebin_pad_added_cb (GstElement * demux, GstPad * pad,
76 DecodebinInput * input);
77 static void parsebin_pad_removed_cb (GstElement * demux, GstPad * pad,
78 DecodebinInput * input);
79
80 /* WITH SELECTION_LOCK TAKEN! */
81 static gboolean
pending_pads_are_eos(DecodebinInput * input)82 pending_pads_are_eos (DecodebinInput * input)
83 {
84 GList *tmp;
85
86 for (tmp = input->pending_pads; tmp; tmp = tmp->next) {
87 PendingPad *ppad = (PendingPad *) tmp->data;
88 if (ppad->saw_eos == FALSE)
89 return FALSE;
90 }
91
92 return TRUE;
93 }
94
95 /* WITH SELECTION_LOCK TAKEN! */
96 static gboolean
all_inputs_are_eos(GstDecodebin3 * dbin)97 all_inputs_are_eos (GstDecodebin3 * dbin)
98 {
99 GList *tmp;
100 /* First check input streams */
101 for (tmp = dbin->input_streams; tmp; tmp = tmp->next) {
102 DecodebinInputStream *input = (DecodebinInputStream *) tmp->data;
103 if (input->saw_eos == FALSE)
104 return FALSE;
105 }
106
107 /* Check pending pads */
108 if (!pending_pads_are_eos (dbin->main_input))
109 return FALSE;
110 for (tmp = dbin->other_inputs; tmp; tmp = tmp->next)
111 if (!pending_pads_are_eos ((DecodebinInput *) tmp->data))
112 return FALSE;
113
114 GST_DEBUG_OBJECT (dbin, "All streams are EOS");
115 return TRUE;
116 }
117
118 /* WITH SELECTION_LOCK TAKEN! */
119 static void
check_all_streams_for_eos(GstDecodebin3 * dbin)120 check_all_streams_for_eos (GstDecodebin3 * dbin)
121 {
122 GList *tmp;
123
124 if (!all_inputs_are_eos (dbin))
125 return;
126
127 /* We know all streams are EOS, properly clean up everything */
128 for (tmp = dbin->input_streams; tmp; tmp = tmp->next) {
129 DecodebinInputStream *input = (DecodebinInputStream *) tmp->data;
130 GstPad *peer = gst_pad_get_peer (input->srcpad);
131
132 /* Send EOS and then remove elements */
133 if (peer) {
134 gst_pad_send_event (peer, gst_event_new_eos ());
135 gst_object_unref (peer);
136 }
137 GST_FIXME_OBJECT (input->srcpad, "Remove input stream");
138 }
139 }
140
141 /* Get the intersection of parser caps and available (sorted) decoders */
142 static GstCaps *
get_parser_caps_filter(GstDecodebin3 * dbin,GstCaps * caps)143 get_parser_caps_filter (GstDecodebin3 * dbin, GstCaps * caps)
144 {
145 GList *tmp;
146 GstCaps *filter_caps = gst_caps_new_empty ();
147
148 g_mutex_lock (&dbin->factories_lock);
149 gst_decode_bin_update_factories_list (dbin);
150 for (tmp = dbin->decoder_factories; tmp; tmp = tmp->next) {
151 GstElementFactory *factory = (GstElementFactory *) tmp->data;
152 GstCaps *tcaps, *intersection;
153 const GList *tmps;
154
155 GST_LOG ("Trying factory %s",
156 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
157 for (tmps = gst_element_factory_get_static_pad_templates (factory); tmps;
158 tmps = tmps->next) {
159 GstStaticPadTemplate *st = (GstStaticPadTemplate *) tmps->data;
160 if (st->direction != GST_PAD_SINK || st->presence != GST_PAD_ALWAYS)
161 continue;
162 tcaps = gst_static_pad_template_get_caps (st);
163 intersection =
164 gst_caps_intersect_full (tcaps, caps, GST_CAPS_INTERSECT_FIRST);
165 filter_caps = gst_caps_merge (filter_caps, intersection);
166 gst_caps_unref (tcaps);
167 }
168 }
169 g_mutex_unlock (&dbin->factories_lock);
170 GST_DEBUG_OBJECT (dbin, "Got filter caps %" GST_PTR_FORMAT, filter_caps);
171 return filter_caps;
172 }
173
174 static gboolean
check_parser_caps_filter(GstDecodebin3 * dbin,GstCaps * caps)175 check_parser_caps_filter (GstDecodebin3 * dbin, GstCaps * caps)
176 {
177 GList *tmp;
178 gboolean res = FALSE;
179
180 g_mutex_lock (&dbin->factories_lock);
181 gst_decode_bin_update_factories_list (dbin);
182 for (tmp = dbin->decoder_factories; tmp; tmp = tmp->next) {
183 GstElementFactory *factory = (GstElementFactory *) tmp->data;
184 GstCaps *tcaps;
185 const GList *tmps;
186
187 GST_LOG ("Trying factory %s",
188 gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
189 for (tmps = gst_element_factory_get_static_pad_templates (factory); tmps;
190 tmps = tmps->next) {
191 GstStaticPadTemplate *st = (GstStaticPadTemplate *) tmps->data;
192 if (st->direction != GST_PAD_SINK || st->presence != GST_PAD_ALWAYS)
193 continue;
194 tcaps = gst_static_pad_template_get_caps (st);
195 if (gst_caps_can_intersect (tcaps, caps)) {
196 res = TRUE;
197 gst_caps_unref (tcaps);
198 goto beach;
199 }
200 gst_caps_unref (tcaps);
201 }
202 }
203 beach:
204 g_mutex_unlock (&dbin->factories_lock);
205 GST_DEBUG_OBJECT (dbin, "Can intersect : %d", res);
206 return res;
207 }
208
209 /* Probe on the output of a parser chain (the last
210 * src pad) */
211 static GstPadProbeReturn
parse_chain_output_probe(GstPad * pad,GstPadProbeInfo * info,DecodebinInputStream * input)212 parse_chain_output_probe (GstPad * pad, GstPadProbeInfo * info,
213 DecodebinInputStream * input)
214 {
215 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
216
217 if (GST_IS_EVENT (GST_PAD_PROBE_INFO_DATA (info))) {
218 GstEvent *ev = GST_PAD_PROBE_INFO_EVENT (info);
219
220 GST_DEBUG_OBJECT (pad, "Got event %s", GST_EVENT_TYPE_NAME (ev));
221 switch (GST_EVENT_TYPE (ev)) {
222 case GST_EVENT_STREAM_START:
223 {
224 GstStream *stream = NULL;
225 guint group_id = GST_GROUP_ID_INVALID;
226
227 if (!gst_event_parse_group_id (ev, &group_id)) {
228 GST_FIXME_OBJECT (pad,
229 "Consider implementing group-id handling on stream-start event");
230 group_id = gst_util_group_id_next ();
231 }
232
233 GST_DEBUG_OBJECT (pad, "Got stream-start, group_id:%d, input %p",
234 group_id, input->input);
235 if (set_input_group_id (input->input, &group_id)) {
236 ev = gst_event_make_writable (ev);
237 gst_event_set_group_id (ev, group_id);
238 GST_PAD_PROBE_INFO_DATA (info) = ev;
239 }
240 input->saw_eos = FALSE;
241
242 gst_event_parse_stream (ev, &stream);
243 /* FIXME : Would we ever end up with a stream already set on the input ?? */
244 if (stream) {
245 if (input->active_stream != stream) {
246 MultiQueueSlot *slot;
247 if (input->active_stream)
248 gst_object_unref (input->active_stream);
249 input->active_stream = stream;
250 /* We have the beginning of a stream, get a multiqueue slot and link to it */
251 SELECTION_LOCK (input->dbin);
252 slot = get_slot_for_input (input->dbin, input);
253 link_input_to_slot (input, slot);
254 SELECTION_UNLOCK (input->dbin);
255 } else
256 gst_object_unref (stream);
257 }
258 }
259 break;
260 case GST_EVENT_CAPS:
261 {
262 GstCaps *caps = NULL;
263 gst_event_parse_caps (ev, &caps);
264 GST_DEBUG_OBJECT (pad, "caps %" GST_PTR_FORMAT, caps);
265 if (caps && input->active_stream)
266 gst_stream_set_caps (input->active_stream, caps);
267 }
268 break;
269 case GST_EVENT_EOS:
270 input->saw_eos = TRUE;
271 if (all_inputs_are_eos (input->dbin)) {
272 GST_DEBUG_OBJECT (pad, "real input pad, marking as EOS");
273 SELECTION_LOCK (input->dbin);
274 check_all_streams_for_eos (input->dbin);
275 SELECTION_UNLOCK (input->dbin);
276 } else {
277 GstPad *peer = gst_pad_get_peer (input->srcpad);
278 if (peer) {
279 /* Send custom-eos event to multiqueue slot */
280 GstEvent *event;
281
282 GST_DEBUG_OBJECT (pad,
283 "Got EOS end of input stream, post custom-eos");
284 event = gst_event_new_eos ();
285 gst_event_set_seqnum (event, gst_event_get_seqnum (ev));
286 gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (event),
287 CUSTOM_EOS_QUARK, (gchar *) CUSTOM_EOS_QUARK_DATA, NULL);
288 gst_pad_send_event (peer, event);
289 gst_object_unref (peer);
290 } else {
291 GST_FIXME_OBJECT (pad, "No peer, what should we do ?");
292 }
293 }
294 ret = GST_PAD_PROBE_DROP;
295 break;
296 case GST_EVENT_FLUSH_STOP:
297 GST_DEBUG_OBJECT (pad, "Clear saw_eos flag");
298 input->saw_eos = FALSE;
299 default:
300 break;
301 }
302 } else if (GST_IS_QUERY (GST_PAD_PROBE_INFO_DATA (info))) {
303 GstQuery *q = GST_PAD_PROBE_INFO_QUERY (info);
304 GST_DEBUG_OBJECT (pad, "Seeing query %s", GST_QUERY_TYPE_NAME (q));
305 /* If we have a parser, we want to reply to the caps query */
306 /* FIXME: Set a flag when the input stream is created for
307 * streams where we shouldn't reply to these queries */
308 if (GST_QUERY_TYPE (q) == GST_QUERY_CAPS
309 && (info->type & GST_PAD_PROBE_TYPE_PULL)) {
310 GstCaps *filter = NULL;
311 GstCaps *allowed;
312 gst_query_parse_caps (q, &filter);
313 allowed = get_parser_caps_filter (input->dbin, filter);
314 GST_DEBUG_OBJECT (pad,
315 "Intercepting caps query, setting %" GST_PTR_FORMAT, allowed);
316 gst_query_set_caps_result (q, allowed);
317 gst_caps_unref (allowed);
318 ret = GST_PAD_PROBE_HANDLED;
319 } else if (GST_QUERY_TYPE (q) == GST_QUERY_ACCEPT_CAPS) {
320 GstCaps *prop = NULL;
321 gst_query_parse_accept_caps (q, &prop);
322 /* Fast check against target caps */
323 if (gst_caps_can_intersect (prop, input->dbin->caps))
324 gst_query_set_accept_caps_result (q, TRUE);
325 else {
326 gboolean accepted = check_parser_caps_filter (input->dbin, prop);
327 /* check against caps filter */
328 gst_query_set_accept_caps_result (q, accepted);
329 GST_DEBUG_OBJECT (pad, "ACCEPT_CAPS query, returning %d", accepted);
330 }
331 ret = GST_PAD_PROBE_HANDLED;
332 }
333 }
334
335 return ret;
336 }
337
338 static DecodebinInputStream *
create_input_stream(GstDecodebin3 * dbin,GstStream * stream,GstPad * pad,DecodebinInput * input)339 create_input_stream (GstDecodebin3 * dbin, GstStream * stream, GstPad * pad,
340 DecodebinInput * input)
341 {
342 DecodebinInputStream *res = g_new0 (DecodebinInputStream, 1);
343
344 GST_DEBUG_OBJECT (pad, "Creating input stream for stream %p %s (input:%p)",
345 stream, gst_stream_get_stream_id (stream), input);
346
347 res->dbin = dbin;
348 res->input = input;
349 res->pending_stream = gst_object_ref (stream);
350 res->srcpad = pad;
351
352 /* Put probe on output source pad (for detecting EOS/STREAM_START/FLUSH) */
353 res->output_event_probe_id =
354 gst_pad_add_probe (pad,
355 GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM
356 | GST_PAD_PROBE_TYPE_EVENT_FLUSH,
357 (GstPadProbeCallback) parse_chain_output_probe, res, NULL);
358
359 /* Add to list of current input streams */
360 SELECTION_LOCK (dbin);
361 dbin->input_streams = g_list_append (dbin->input_streams, res);
362 SELECTION_UNLOCK (dbin);
363 GST_DEBUG_OBJECT (pad, "Done creating input stream");
364
365 return res;
366 }
367
368 /* WITH SELECTION_LOCK TAKEN! */
369 static void
remove_input_stream(GstDecodebin3 * dbin,DecodebinInputStream * stream)370 remove_input_stream (GstDecodebin3 * dbin, DecodebinInputStream * stream)
371 {
372 MultiQueueSlot *slot;
373
374 GST_DEBUG_OBJECT (dbin, "Removing input stream %p (%s)", stream,
375 stream->active_stream ? gst_stream_get_stream_id (stream->active_stream) :
376 "<NONE>");
377
378 /* Unlink from slot */
379 if (stream->srcpad) {
380 GstPad *peer;
381 peer = gst_pad_get_peer (stream->srcpad);
382 if (peer) {
383 gst_pad_unlink (stream->srcpad, peer);
384 gst_object_unref (peer);
385 }
386 }
387
388 slot = get_slot_for_input (dbin, stream);
389 if (slot) {
390 slot->pending_stream = NULL;
391 slot->input = NULL;
392 GST_DEBUG_OBJECT (dbin, "slot %p cleared", slot);
393 }
394
395 if (stream->active_stream)
396 gst_object_unref (stream->active_stream);
397 if (stream->pending_stream)
398 gst_object_unref (stream->pending_stream);
399
400 dbin->input_streams = g_list_remove (dbin->input_streams, stream);
401
402 g_free (stream);
403 }
404
405
406 /* FIXME : HACK, REMOVE, USE INPUT CHAINS */
407 static GstPadProbeReturn
parsebin_buffer_probe(GstPad * pad,GstPadProbeInfo * info,DecodebinInput * input)408 parsebin_buffer_probe (GstPad * pad, GstPadProbeInfo * info,
409 DecodebinInput * input)
410 {
411 GstDecodebin3 *dbin = input->dbin;
412 GList *tmp, *unused_slot = NULL;
413
414 GST_DEBUG_OBJECT (pad, "Got a buffer ! UNBLOCK !");
415
416 /* Any data out the demuxer means it's not creating pads
417 * any more right now */
418
419 /* 1. Re-use existing streams if/when possible */
420 GST_FIXME_OBJECT (dbin, "Re-use existing input streams if/when possible");
421
422 /* 2. Remove unused streams (push EOS) */
423 GST_DEBUG_OBJECT (dbin, "Removing unused streams");
424 SELECTION_LOCK (dbin);
425 tmp = dbin->input_streams;
426 while (tmp != NULL) {
427 DecodebinInputStream *input_stream = (DecodebinInputStream *) tmp->data;
428 GList *next = tmp->next;
429
430 if (input_stream->input != input) {
431 tmp = next;
432 continue;
433 }
434
435 GST_DEBUG_OBJECT (dbin, "Checking input stream %p", input_stream);
436 if (input_stream->input_buffer_probe_id) {
437 GST_DEBUG_OBJECT (dbin,
438 "Removing pad block on input %p pad %" GST_PTR_FORMAT, input_stream,
439 input_stream->srcpad);
440 gst_pad_remove_probe (input_stream->srcpad,
441 input_stream->input_buffer_probe_id);
442 }
443 input_stream->input_buffer_probe_id = 0;
444
445 if (input_stream->saw_eos) {
446 remove_input_stream (dbin, input_stream);
447 tmp = dbin->input_streams;
448 } else
449 tmp = next;
450 }
451 SELECTION_UNLOCK (dbin);
452
453 GST_DEBUG_OBJECT (dbin, "Creating new streams (if needed)");
454 /* 3. Create new streams */
455 for (tmp = input->pending_pads; tmp; tmp = tmp->next) {
456 GstStream *stream;
457 PendingPad *ppad = (PendingPad *) tmp->data;
458
459 stream = gst_pad_get_stream (ppad->pad);
460 if (stream == NULL) {
461 GST_ERROR_OBJECT (dbin, "No stream for pad ????");
462 } else {
463 MultiQueueSlot *slot;
464 DecodebinInputStream *input_stream;
465 /* The remaining pads in pending_pads are the ones that require a new
466 * input stream */
467 input_stream = create_input_stream (dbin, stream, ppad->pad, ppad->input);
468 /* See if we can link it straight away */
469 input_stream->active_stream = stream;
470
471 SELECTION_LOCK (dbin);
472 slot = get_slot_for_input (dbin, input_stream);
473 link_input_to_slot (input_stream, slot);
474 SELECTION_UNLOCK (dbin);
475
476 /* Remove the buffer and event probe */
477 gst_pad_remove_probe (ppad->pad, ppad->buffer_probe);
478 gst_pad_remove_probe (ppad->pad, ppad->event_probe);
479 g_free (ppad);
480 }
481 }
482
483 g_list_free (input->pending_pads);
484 input->pending_pads = NULL;
485
486 /* Weed out unused multiqueue slots */
487 SELECTION_LOCK (dbin);
488 for (tmp = dbin->slots; tmp; tmp = tmp->next) {
489 MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
490 GST_LOG_OBJECT (dbin, "Slot %d input:%p", slot->id, slot->input);
491 if (slot->input == NULL) {
492 unused_slot =
493 g_list_append (unused_slot, gst_object_ref (slot->sink_pad));
494 }
495 }
496 SELECTION_UNLOCK (dbin);
497
498 for (tmp = unused_slot; tmp; tmp = tmp->next) {
499 GstPad *sink_pad = (GstPad *) tmp->data;
500 GST_DEBUG_OBJECT (sink_pad, "Sending EOS to unused slot");
501 gst_pad_send_event (sink_pad, gst_event_new_eos ());
502 }
503
504 if (unused_slot)
505 g_list_free_full (unused_slot, (GDestroyNotify) gst_object_unref);
506
507 return GST_PAD_PROBE_OK;
508 }
509
510 static GstPadProbeReturn
parsebin_pending_event_probe(GstPad * pad,GstPadProbeInfo * info,PendingPad * ppad)511 parsebin_pending_event_probe (GstPad * pad, GstPadProbeInfo * info,
512 PendingPad * ppad)
513 {
514 GstDecodebin3 *dbin = ppad->dbin;
515 /* We drop all events by default */
516 GstPadProbeReturn ret = GST_PAD_PROBE_DROP;
517 GstEvent *ev = GST_PAD_PROBE_INFO_EVENT (info);
518
519 GST_DEBUG_OBJECT (pad, "Got event %p %s", ev, GST_EVENT_TYPE_NAME (ev));
520 switch (GST_EVENT_TYPE (ev)) {
521 case GST_EVENT_EOS:
522 {
523 GST_DEBUG_OBJECT (pad, "Pending pad marked as EOS, removing");
524 ppad->input->pending_pads =
525 g_list_remove (ppad->input->pending_pads, ppad);
526 gst_pad_remove_probe (ppad->pad, ppad->buffer_probe);
527 gst_pad_remove_probe (ppad->pad, ppad->event_probe);
528 g_free (ppad);
529
530 check_all_streams_for_eos (dbin);
531 }
532 break;
533 default:
534 break;
535 }
536
537 return ret;
538 }
539
540 static void
parsebin_pad_added_cb(GstElement * demux,GstPad * pad,DecodebinInput * input)541 parsebin_pad_added_cb (GstElement * demux, GstPad * pad, DecodebinInput * input)
542 {
543 GstDecodebin3 *dbin = input->dbin;
544 PendingPad *ppad;
545 GList *tmp;
546
547 GST_DEBUG_OBJECT (dbin, "New pad %s:%s (input:%p)", GST_DEBUG_PAD_NAME (pad),
548 input);
549
550 ppad = g_new0 (PendingPad, 1);
551 ppad->dbin = dbin;
552 ppad->input = input;
553 ppad->pad = pad;
554
555 ppad->event_probe =
556 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
557 (GstPadProbeCallback) parsebin_pending_event_probe, ppad, NULL);
558 ppad->buffer_probe =
559 gst_pad_add_probe (pad,
560 GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER,
561 (GstPadProbeCallback) parsebin_buffer_probe, input, NULL);
562
563 input->pending_pads = g_list_append (input->pending_pads, ppad);
564
565 /* Check if all existing input streams have a buffer probe set */
566 for (tmp = dbin->input_streams; tmp; tmp = tmp->next) {
567 DecodebinInputStream *input_stream = (DecodebinInputStream *) tmp->data;
568 if (input_stream->input == input &&
569 input_stream->input_buffer_probe_id == 0) {
570 GST_DEBUG_OBJECT (input_stream->srcpad, "Adding blocking buffer probe");
571 input_stream->input_buffer_probe_id =
572 gst_pad_add_probe (input_stream->srcpad,
573 GST_PAD_PROBE_TYPE_BLOCK | GST_PAD_PROBE_TYPE_BUFFER,
574 (GstPadProbeCallback) parsebin_buffer_probe, input_stream->input,
575 NULL);
576 }
577 }
578 }
579
580 static void
parsebin_pad_removed_cb(GstElement * demux,GstPad * pad,DecodebinInput * inp)581 parsebin_pad_removed_cb (GstElement * demux, GstPad * pad, DecodebinInput * inp)
582 {
583 GstDecodebin3 *dbin = inp->dbin;
584 DecodebinInputStream *input = NULL;
585 GList *tmp;
586 GST_DEBUG_OBJECT (pad, "removed");
587
588 for (tmp = dbin->input_streams; tmp; tmp = tmp->next) {
589 DecodebinInputStream *cand = (DecodebinInputStream *) tmp->data;
590 if (cand->srcpad == pad)
591 input = cand;
592 }
593 /* If there are no pending pads, this means we will definitely not need this
594 * stream anymore */
595 if (input) {
596 GST_DEBUG_OBJECT (pad, "stream %p", input);
597 if (inp->pending_pads == NULL) {
598 MultiQueueSlot *slot;
599
600 GST_DEBUG_OBJECT (pad, "Remove input stream %p", input);
601
602 SELECTION_LOCK (dbin);
603 slot = get_slot_for_input (dbin, input);
604
605 remove_input_stream (dbin, input);
606 if (slot && g_list_find (dbin->slots, slot) && slot->is_drained) {
607 /* if slot is still there and already drained, remove it in here */
608 if (slot->output) {
609 DecodebinOutputStream *output = slot->output;
610 GST_DEBUG_OBJECT (pad,
611 "Multiqueue was drained, Remove output stream");
612
613 dbin->output_streams = g_list_remove (dbin->output_streams, output);
614 free_output_stream (dbin, output);
615 }
616 GST_DEBUG_OBJECT (pad, "No pending pad, Remove multiqueue slot");
617 if (slot->probe_id)
618 gst_pad_remove_probe (slot->src_pad, slot->probe_id);
619 slot->probe_id = 0;
620 dbin->slots = g_list_remove (dbin->slots, slot);
621 free_multiqueue_slot_async (dbin, slot);
622 }
623 SELECTION_UNLOCK (dbin);
624 } else {
625 input->srcpad = NULL;
626 if (input->input_buffer_probe_id)
627 gst_pad_remove_probe (pad, input->input_buffer_probe_id);
628 input->input_buffer_probe_id = 0;
629 }
630 }
631 }
632