1 /* GStreamer output selector
2 * Copyright (C) 2008 Nokia Corporation. (contact <stefan.kost@nokia.com>)
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 /**
21 * SECTION:element-output-selector
22 * @title: output-selector
23 * @see_also: #GstOutputSelector, #GstInputSelector
24 *
25 * Direct input stream to one out of N output pads.
26 */
27
28 #ifdef HAVE_CONFIG_H
29 #include "config.h"
30 #endif
31
32 #include <string.h>
33
34 #include "gstoutputselector.h"
35 #include "gstcoreelementselements.h"
36
37 GST_DEBUG_CATEGORY_STATIC (output_selector_debug);
38 #define GST_CAT_DEFAULT output_selector_debug
39
40 static GstStaticPadTemplate gst_output_selector_sink_factory =
41 GST_STATIC_PAD_TEMPLATE ("sink",
42 GST_PAD_SINK,
43 GST_PAD_ALWAYS,
44 GST_STATIC_CAPS_ANY);
45
46 static GstStaticPadTemplate gst_output_selector_src_factory =
47 GST_STATIC_PAD_TEMPLATE ("src_%u",
48 GST_PAD_SRC,
49 GST_PAD_REQUEST,
50 GST_STATIC_CAPS_ANY);
51
52 #define GST_TYPE_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE (gst_output_selector_pad_negotiation_mode_get_type())
53 static GType
gst_output_selector_pad_negotiation_mode_get_type(void)54 gst_output_selector_pad_negotiation_mode_get_type (void)
55 {
56 static GType pad_negotiation_mode_type = 0;
57 static const GEnumValue pad_negotiation_modes[] = {
58 {GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_NONE, "None", "none"},
59 {GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ALL, "All", "all"},
60 {GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ACTIVE, "Active", "active"},
61 {0, NULL, NULL}
62 };
63
64 if (!pad_negotiation_mode_type) {
65 pad_negotiation_mode_type =
66 g_enum_register_static ("GstOutputSelectorPadNegotiationMode",
67 pad_negotiation_modes);
68 }
69 return pad_negotiation_mode_type;
70 }
71
72
73 enum
74 {
75 PROP_0,
76 PROP_ACTIVE_PAD,
77 PROP_RESEND_LATEST,
78 PROP_PAD_NEGOTIATION_MODE
79 };
80
81 #define DEFAULT_PAD_NEGOTIATION_MODE GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ALL
82
83 #define _do_init \
84 GST_DEBUG_CATEGORY_INIT (output_selector_debug, \
85 "output-selector", 0, "Output stream selector");
86 #define gst_output_selector_parent_class parent_class
87 G_DEFINE_TYPE_WITH_CODE (GstOutputSelector, gst_output_selector,
88 GST_TYPE_ELEMENT, _do_init);
89 GST_ELEMENT_REGISTER_DEFINE (output_selector, "output-selector", GST_RANK_NONE,
90 GST_TYPE_OUTPUT_SELECTOR);
91
92 static void gst_output_selector_dispose (GObject * object);
93 static void gst_output_selector_set_property (GObject * object,
94 guint prop_id, const GValue * value, GParamSpec * pspec);
95 static void gst_output_selector_get_property (GObject * object,
96 guint prop_id, GValue * value, GParamSpec * pspec);
97 static GstPad *gst_output_selector_request_new_pad (GstElement * element,
98 GstPadTemplate * templ, const gchar * unused, const GstCaps * caps);
99 static void gst_output_selector_release_pad (GstElement * element,
100 GstPad * pad);
101 static GstFlowReturn gst_output_selector_chain (GstPad * pad,
102 GstObject * parent, GstBuffer * buf);
103 static GstStateChangeReturn gst_output_selector_change_state (GstElement *
104 element, GstStateChange transition);
105 static gboolean gst_output_selector_event (GstPad * pad, GstObject * parent,
106 GstEvent * event);
107 static gboolean gst_output_selector_query (GstPad * pad, GstObject * parent,
108 GstQuery * query);
109 static void gst_output_selector_switch_pad_negotiation_mode (GstOutputSelector *
110 sel, gint mode);
111
112 static void
gst_output_selector_class_init(GstOutputSelectorClass * klass)113 gst_output_selector_class_init (GstOutputSelectorClass * klass)
114 {
115 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
116 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
117
118 gobject_class->dispose = gst_output_selector_dispose;
119
120 gobject_class->set_property = gst_output_selector_set_property;
121 gobject_class->get_property = gst_output_selector_get_property;
122
123 g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD,
124 g_param_spec_object ("active-pad", "Active pad",
125 "Currently active src pad", GST_TYPE_PAD,
126 G_PARAM_READWRITE | GST_PARAM_MUTABLE_PLAYING |
127 G_PARAM_STATIC_STRINGS));
128 g_object_class_install_property (gobject_class, PROP_RESEND_LATEST,
129 g_param_spec_boolean ("resend-latest", "Resend latest buffer",
130 "Resend latest buffer after a switch to a new pad", FALSE,
131 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
132 g_object_class_install_property (gobject_class, PROP_PAD_NEGOTIATION_MODE,
133 g_param_spec_enum ("pad-negotiation-mode", "Pad negotiation mode",
134 "The mode to be used for pad negotiation",
135 GST_TYPE_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE,
136 DEFAULT_PAD_NEGOTIATION_MODE,
137 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
138
139 gst_element_class_set_static_metadata (gstelement_class, "Output selector",
140 "Generic", "1-to-N output stream selector",
141 "Stefan Kost <stefan.kost@nokia.com>");
142 gst_element_class_add_static_pad_template (gstelement_class,
143 &gst_output_selector_sink_factory);
144 gst_element_class_add_static_pad_template (gstelement_class,
145 &gst_output_selector_src_factory);
146
147 gstelement_class->request_new_pad =
148 GST_DEBUG_FUNCPTR (gst_output_selector_request_new_pad);
149 gstelement_class->release_pad =
150 GST_DEBUG_FUNCPTR (gst_output_selector_release_pad);
151
152 gstelement_class->change_state = gst_output_selector_change_state;
153
154 gst_type_mark_as_plugin_api (GST_TYPE_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE,
155 0);
156 }
157
158 static void
gst_output_selector_init(GstOutputSelector * sel)159 gst_output_selector_init (GstOutputSelector * sel)
160 {
161 sel->sinkpad =
162 gst_pad_new_from_static_template (&gst_output_selector_sink_factory,
163 "sink");
164 gst_pad_set_chain_function (sel->sinkpad,
165 GST_DEBUG_FUNCPTR (gst_output_selector_chain));
166 gst_pad_set_event_function (sel->sinkpad,
167 GST_DEBUG_FUNCPTR (gst_output_selector_event));
168 gst_pad_set_query_function (sel->sinkpad,
169 GST_DEBUG_FUNCPTR (gst_output_selector_query));
170
171 gst_element_add_pad (GST_ELEMENT (sel), sel->sinkpad);
172
173 /* srcpad management */
174 sel->active_srcpad = NULL;
175 sel->nb_srcpads = 0;
176 gst_segment_init (&sel->segment, GST_FORMAT_UNDEFINED);
177 sel->pending_srcpad = NULL;
178
179 sel->resend_latest = FALSE;
180 sel->latest_buffer = NULL;
181 gst_output_selector_switch_pad_negotiation_mode (sel,
182 DEFAULT_PAD_NEGOTIATION_MODE);
183 }
184
185 static void
gst_output_selector_reset(GstOutputSelector * osel)186 gst_output_selector_reset (GstOutputSelector * osel)
187 {
188 GST_OBJECT_LOCK (osel);
189 if (osel->pending_srcpad != NULL) {
190 gst_object_unref (osel->pending_srcpad);
191 osel->pending_srcpad = NULL;
192 }
193
194 if (osel->latest_buffer != NULL) {
195 gst_buffer_unref (osel->latest_buffer);
196 osel->latest_buffer = NULL;
197 }
198 osel->segment_seqnum = GST_SEQNUM_INVALID;
199 GST_OBJECT_UNLOCK (osel);
200 gst_segment_init (&osel->segment, GST_FORMAT_UNDEFINED);
201 }
202
203 static void
gst_output_selector_dispose(GObject * object)204 gst_output_selector_dispose (GObject * object)
205 {
206 GstOutputSelector *osel = GST_OUTPUT_SELECTOR (object);
207
208 gst_output_selector_reset (osel);
209
210 G_OBJECT_CLASS (parent_class)->dispose (object);
211 }
212
213 static void
gst_output_selector_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)214 gst_output_selector_set_property (GObject * object, guint prop_id,
215 const GValue * value, GParamSpec * pspec)
216 {
217 GstOutputSelector *sel = GST_OUTPUT_SELECTOR (object);
218
219 switch (prop_id) {
220 case PROP_ACTIVE_PAD:
221 {
222 GstPad *next_pad;
223
224 next_pad = g_value_get_object (value);
225
226 GST_INFO_OBJECT (sel, "Activating pad %s:%s",
227 GST_DEBUG_PAD_NAME (next_pad));
228
229 /* guard against users setting a sink pad or foreign pad as active pad */
230 if (next_pad != NULL) {
231 g_return_if_fail (GST_PAD_IS_SRC (next_pad));
232 g_return_if_fail (GST_PAD_PARENT (next_pad) == GST_ELEMENT_CAST (sel));
233 }
234
235 GST_OBJECT_LOCK (object);
236 if (next_pad != sel->active_srcpad) {
237 /* switch to new srcpad in next chain run */
238 if (sel->pending_srcpad != NULL) {
239 GST_INFO ("replacing pending switch");
240 gst_object_unref (sel->pending_srcpad);
241 }
242 if (next_pad)
243 gst_object_ref (next_pad);
244 sel->pending_srcpad = next_pad;
245 } else {
246 GST_INFO ("pad already active");
247 if (sel->pending_srcpad != NULL) {
248 gst_object_unref (sel->pending_srcpad);
249 sel->pending_srcpad = NULL;
250 }
251 }
252 GST_OBJECT_UNLOCK (object);
253 break;
254 }
255 case PROP_RESEND_LATEST:{
256 sel->resend_latest = g_value_get_boolean (value);
257 break;
258 }
259 case PROP_PAD_NEGOTIATION_MODE:{
260 gst_output_selector_switch_pad_negotiation_mode (sel,
261 g_value_get_enum (value));
262 break;
263 }
264 default:
265 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
266 break;
267 }
268 }
269
270 static void
gst_output_selector_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)271 gst_output_selector_get_property (GObject * object, guint prop_id,
272 GValue * value, GParamSpec * pspec)
273 {
274 GstOutputSelector *sel = GST_OUTPUT_SELECTOR (object);
275
276 switch (prop_id) {
277 case PROP_ACTIVE_PAD:
278 GST_OBJECT_LOCK (object);
279 g_value_set_object (value,
280 sel->pending_srcpad ? sel->pending_srcpad : sel->active_srcpad);
281 GST_OBJECT_UNLOCK (object);
282 break;
283 case PROP_RESEND_LATEST:{
284 GST_OBJECT_LOCK (object);
285 g_value_set_boolean (value, sel->resend_latest);
286 GST_OBJECT_UNLOCK (object);
287 break;
288 }
289 case PROP_PAD_NEGOTIATION_MODE:
290 g_value_set_enum (value, sel->pad_negotiation_mode);
291 break;
292 default:
293 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
294 break;
295 }
296 }
297
298 static GstPad *
gst_output_selector_get_active(GstOutputSelector * sel)299 gst_output_selector_get_active (GstOutputSelector * sel)
300 {
301 GstPad *active = NULL;
302
303 GST_OBJECT_LOCK (sel);
304 if (sel->pending_srcpad)
305 active = gst_object_ref (sel->pending_srcpad);
306 else if (sel->active_srcpad)
307 active = gst_object_ref (sel->active_srcpad);
308 GST_OBJECT_UNLOCK (sel);
309
310 return active;
311 }
312
313 static void
gst_output_selector_switch_pad_negotiation_mode(GstOutputSelector * sel,gint mode)314 gst_output_selector_switch_pad_negotiation_mode (GstOutputSelector * sel,
315 gint mode)
316 {
317 sel->pad_negotiation_mode = mode;
318 }
319
320 static gboolean
forward_sticky_events(GstPad * pad,GstEvent ** event,gpointer user_data)321 forward_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
322 {
323 GstPad *srcpad = GST_PAD_CAST (user_data);
324
325 gst_pad_push_event (srcpad, gst_event_ref (*event));
326
327 return TRUE;
328 }
329
330 static gboolean
gst_output_selector_srcpad_event_func(GstPad * pad,GstObject * parent,GstEvent * event)331 gst_output_selector_srcpad_event_func (GstPad * pad, GstObject * parent,
332 GstEvent * event)
333 {
334 GstOutputSelector *osel = GST_OUTPUT_SELECTOR (parent);
335
336 switch (GST_EVENT_TYPE (event)) {
337 case GST_EVENT_SEEK:
338 {
339 guint32 seqnum = gst_event_get_seqnum (event);
340
341 GST_OBJECT_LOCK (osel);
342 if (seqnum == osel->segment_seqnum) {
343 GST_OBJECT_UNLOCK (osel);
344
345 GST_DEBUG_OBJECT (pad,
346 "Drop duplicated SEEK event seqnum %" G_GUINT32_FORMAT, seqnum);
347 gst_event_unref (event);
348 return TRUE;
349 }
350
351 osel->segment_seqnum = seqnum;
352 GST_OBJECT_UNLOCK (osel);
353 break;
354 }
355 default:
356 break;
357 }
358
359 return gst_pad_event_default (pad, parent, event);
360 }
361
362 static GstPad *
gst_output_selector_request_new_pad(GstElement * element,GstPadTemplate * templ,const gchar * name,const GstCaps * caps)363 gst_output_selector_request_new_pad (GstElement * element,
364 GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
365 {
366 gchar *padname;
367 GstPad *srcpad;
368 GstOutputSelector *osel;
369
370 osel = GST_OUTPUT_SELECTOR (element);
371
372 GST_DEBUG_OBJECT (osel, "requesting pad");
373
374 GST_OBJECT_LOCK (osel);
375 padname = g_strdup_printf ("src_%u", osel->nb_srcpads++);
376 srcpad = gst_pad_new_from_template (templ, padname);
377 GST_OBJECT_UNLOCK (osel);
378
379 gst_pad_set_event_function (srcpad, gst_output_selector_srcpad_event_func);
380 gst_pad_set_active (srcpad, TRUE);
381
382 /* Forward sticky events to the new srcpad */
383 gst_pad_sticky_events_foreach (osel->sinkpad, forward_sticky_events, srcpad);
384
385 gst_element_add_pad (GST_ELEMENT (osel), srcpad);
386
387 /* Set the first requested src pad as active by default */
388 GST_OBJECT_LOCK (osel);
389 if (osel->active_srcpad == NULL) {
390 osel->active_srcpad = srcpad;
391 GST_OBJECT_UNLOCK (osel);
392 g_object_notify (G_OBJECT (osel), "active-pad");
393 } else {
394 GST_OBJECT_UNLOCK (osel);
395 }
396 g_free (padname);
397
398 return srcpad;
399 }
400
401 static void
gst_output_selector_release_pad(GstElement * element,GstPad * pad)402 gst_output_selector_release_pad (GstElement * element, GstPad * pad)
403 {
404 GstOutputSelector *osel;
405
406 osel = GST_OUTPUT_SELECTOR (element);
407
408 GST_DEBUG_OBJECT (osel, "releasing pad");
409
410 /* Disable active pad if it's the to be removed pad */
411 GST_OBJECT_LOCK (osel);
412 if (osel->active_srcpad == pad) {
413 osel->active_srcpad = NULL;
414 GST_OBJECT_UNLOCK (osel);
415 g_object_notify (G_OBJECT (osel), "active-pad");
416 } else {
417 GST_OBJECT_UNLOCK (osel);
418 }
419
420 gst_pad_set_active (pad, FALSE);
421
422 gst_element_remove_pad (GST_ELEMENT_CAST (osel), pad);
423 }
424
425 static gboolean
gst_output_selector_switch(GstOutputSelector * osel)426 gst_output_selector_switch (GstOutputSelector * osel)
427 {
428 gboolean res = FALSE;
429 GstEvent *ev = NULL;
430 GstSegment *seg = NULL;
431 GstPad *active_srcpad;
432
433 /* Switch */
434 GST_OBJECT_LOCK (osel);
435 GST_INFO_OBJECT (osel, "switching to pad %" GST_PTR_FORMAT,
436 osel->pending_srcpad);
437 if (!osel->pending_srcpad) {
438 GST_OBJECT_UNLOCK (osel);
439 return TRUE;
440 }
441
442 if (gst_pad_is_linked (osel->pending_srcpad)) {
443 osel->active_srcpad = osel->pending_srcpad;
444 res = TRUE;
445 }
446 gst_object_unref (osel->pending_srcpad);
447 osel->pending_srcpad = NULL;
448 active_srcpad = res ? gst_object_ref (osel->active_srcpad) : NULL;
449 GST_OBJECT_UNLOCK (osel);
450
451 /* Send SEGMENT event and latest buffer if switching succeeded
452 * and we already have a valid segment configured */
453 if (res) {
454 GstBuffer *latest_buffer;
455
456 g_object_notify (G_OBJECT (osel), "active-pad");
457
458 GST_OBJECT_LOCK (osel);
459 latest_buffer =
460 osel->latest_buffer ? gst_buffer_ref (osel->latest_buffer) : NULL;
461 GST_OBJECT_UNLOCK (osel);
462
463 gst_pad_sticky_events_foreach (osel->sinkpad, forward_sticky_events,
464 active_srcpad);
465
466 /* update segment if required */
467 if (osel->segment.format != GST_FORMAT_UNDEFINED) {
468 /* Send SEGMENT to the pad we are going to switch to */
469 seg = &osel->segment;
470 /* If resending then mark segment start and position accordingly */
471 if (osel->resend_latest && latest_buffer &&
472 GST_BUFFER_TIMESTAMP_IS_VALID (latest_buffer)) {
473 seg->position = GST_BUFFER_TIMESTAMP (latest_buffer);
474 }
475
476 ev = gst_event_new_segment (seg);
477
478 if (!gst_pad_push_event (active_srcpad, ev)) {
479 GST_WARNING_OBJECT (osel,
480 "newsegment handling failed in %" GST_PTR_FORMAT, active_srcpad);
481 }
482 }
483
484 /* Resend latest buffer to newly switched pad */
485 if (osel->resend_latest && latest_buffer) {
486 GST_INFO ("resending latest buffer");
487 gst_pad_push (active_srcpad, latest_buffer);
488 } else if (latest_buffer) {
489 gst_buffer_unref (latest_buffer);
490 }
491
492 gst_object_unref (active_srcpad);
493 } else {
494 GST_WARNING_OBJECT (osel, "switch failed, pad not linked");
495 }
496
497 return res;
498 }
499
500 static GstFlowReturn
gst_output_selector_chain(GstPad * pad,GstObject * parent,GstBuffer * buf)501 gst_output_selector_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)
502 {
503 GstFlowReturn res;
504 GstOutputSelector *osel;
505 GstClockTime position, duration;
506 GstPad *active_srcpad;
507
508 osel = GST_OUTPUT_SELECTOR (parent);
509
510 /*
511 * The _switch function might push a buffer if 'resend-latest' is true.
512 *
513 * Elements/Applications (e.g. camerabin) might use pad probes to
514 * switch output-selector's active pad. If we simply switch and don't
515 * recheck any pending pad switch the following codepath could end
516 * up pushing a buffer on a non-active pad. This is bad.
517 *
518 * So we always should check the pending_srcpad before going further down
519 * the chain and pushing the new buffer
520 */
521 while (osel->pending_srcpad) {
522 /* Do the switch */
523 gst_output_selector_switch (osel);
524 }
525
526 active_srcpad = gst_output_selector_get_active (osel);
527 if (!active_srcpad) {
528 GST_DEBUG_OBJECT (osel, "No active srcpad");
529 gst_buffer_unref (buf);
530 return GST_FLOW_OK;
531 }
532
533 GST_OBJECT_LOCK (osel);
534 if (osel->latest_buffer) {
535 gst_buffer_unref (osel->latest_buffer);
536 osel->latest_buffer = NULL;
537 }
538
539 if (osel->resend_latest) {
540 /* Keep reference to latest buffer to resend it after switch */
541 osel->latest_buffer = gst_buffer_ref (buf);
542 }
543 GST_OBJECT_UNLOCK (osel);
544
545 /* Keep track of last stop and use it in SEGMENT start after
546 switching to a new src pad */
547 position = GST_BUFFER_TIMESTAMP (buf);
548 if (GST_CLOCK_TIME_IS_VALID (position)) {
549 duration = GST_BUFFER_DURATION (buf);
550 if (GST_CLOCK_TIME_IS_VALID (duration)) {
551 position += duration;
552 }
553 GST_LOG_OBJECT (osel, "setting last stop %" GST_TIME_FORMAT,
554 GST_TIME_ARGS (position));
555 osel->segment.position = position;
556 }
557
558 GST_LOG_OBJECT (osel, "pushing buffer to %" GST_PTR_FORMAT, active_srcpad);
559 res = gst_pad_push (active_srcpad, buf);
560
561 gst_object_unref (active_srcpad);
562
563 return res;
564 }
565
566 static GstStateChangeReturn
gst_output_selector_change_state(GstElement * element,GstStateChange transition)567 gst_output_selector_change_state (GstElement * element,
568 GstStateChange transition)
569 {
570 GstOutputSelector *sel;
571 GstStateChangeReturn result;
572
573 sel = GST_OUTPUT_SELECTOR (element);
574
575 switch (transition) {
576 case GST_STATE_CHANGE_READY_TO_PAUSED:
577 break;
578 default:
579 break;
580 }
581
582 result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
583
584 switch (transition) {
585 case GST_STATE_CHANGE_PAUSED_TO_READY:
586 gst_output_selector_reset (sel);
587 break;
588 default:
589 break;
590 }
591
592 return result;
593 }
594
595 static gboolean
gst_output_selector_forward_event(GstOutputSelector * sel,GstEvent * event)596 gst_output_selector_forward_event (GstOutputSelector * sel, GstEvent * event)
597 {
598 gboolean res = TRUE;
599 GstPad *active;
600
601 switch (sel->pad_negotiation_mode) {
602 case GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ALL:
603 /* Send to all src pads */
604 res = gst_pad_event_default (sel->sinkpad, GST_OBJECT_CAST (sel), event);
605 break;
606 case GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_NONE:
607 gst_event_unref (event);
608 break;
609 default:
610 active = gst_output_selector_get_active (sel);
611 if (active) {
612 res = gst_pad_push_event (active, event);
613 gst_object_unref (active);
614 } else {
615 gst_event_unref (event);
616 }
617 break;
618 }
619
620 return res;
621 }
622
623 static gboolean
gst_output_selector_event(GstPad * pad,GstObject * parent,GstEvent * event)624 gst_output_selector_event (GstPad * pad, GstObject * parent, GstEvent * event)
625 {
626 gboolean res = TRUE;
627 GstOutputSelector *sel;
628 GstPad *active = NULL;
629
630 sel = GST_OUTPUT_SELECTOR (parent);
631
632 switch (GST_EVENT_TYPE (event)) {
633 case GST_EVENT_EOS:
634 {
635 res = gst_output_selector_forward_event (sel, event);
636 break;
637 }
638 case GST_EVENT_SEGMENT:
639 {
640 gst_event_copy_segment (event, &sel->segment);
641 GST_DEBUG_OBJECT (sel, "configured SEGMENT %" GST_SEGMENT_FORMAT,
642 &sel->segment);
643 /* fall through */
644 }
645 default:
646 {
647 active = gst_output_selector_get_active (sel);
648 if (active) {
649 res = gst_pad_push_event (active, event);
650 gst_object_unref (active);
651 } else {
652 gst_event_unref (event);
653 }
654 break;
655 }
656 }
657
658 return res;
659 }
660
661 static gboolean
gst_output_selector_query(GstPad * pad,GstObject * parent,GstQuery * query)662 gst_output_selector_query (GstPad * pad, GstObject * parent, GstQuery * query)
663 {
664 gboolean res = TRUE;
665 GstOutputSelector *sel;
666 GstPad *active = NULL;
667
668 sel = GST_OUTPUT_SELECTOR (parent);
669
670 switch (GST_QUERY_TYPE (query)) {
671 case GST_QUERY_CAPS:
672 {
673 switch (sel->pad_negotiation_mode) {
674 case GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ALL:
675 /* Send caps to all src pads */
676 res = gst_pad_proxy_query_caps (pad, query);
677 break;
678 case GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_NONE:
679 res = FALSE;
680 break;
681 default:
682 active = gst_output_selector_get_active (sel);
683 if (active) {
684 res = gst_pad_peer_query (active, query);
685 gst_object_unref (active);
686 } else {
687 res = FALSE;
688 }
689 break;
690 }
691 break;
692 }
693 case GST_QUERY_DRAIN:
694 if (sel->latest_buffer) {
695 gst_buffer_unref (sel->latest_buffer);
696 sel->latest_buffer = NULL;
697 }
698 /* fall through */
699 default:
700 res = gst_pad_query_default (pad, parent, query);
701 break;
702 }
703
704 return res;
705 }
706