Branch data Line data Source code
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., 59 Temple Place - Suite 330,
17 : : * Boston, MA 02111-1307, USA.
18 : : */
19 : :
20 : : /**
21 : : * SECTION:element-output-selector
22 : : * @see_also: #GstOutputSelector, #GstInputSelector
23 : : *
24 : : * Direct input stream to one out of N output pads.
25 : : *
26 : : * Since: 0.10.32
27 : : */
28 : :
29 : : #ifdef HAVE_CONFIG_H
30 : : #include "config.h"
31 : : #endif
32 : :
33 : : #include <string.h>
34 : :
35 : : #include "gstoutputselector.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%d",
48 : : GST_PAD_SRC,
49 : : GST_PAD_REQUEST,
50 : : GST_STATIC_CAPS_ANY);
51 : :
52 : : enum GstOutputSelectorPadNegotiationMode
53 : : {
54 : : GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_NONE,
55 : : GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ALL,
56 : : GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ACTIVE
57 : : };
58 : : #define GST_TYPE_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE (gst_output_selector_pad_negotiation_mode_get_type())
59 : : static GType
60 : 13 : gst_output_selector_pad_negotiation_mode_get_type (void)
61 : : {
62 : : static GType pad_negotiation_mode_type = 0;
63 : : static GEnumValue pad_negotiation_modes[] = {
64 : : {GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_NONE, "None", "none"},
65 : : {GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ALL, "All", "all"},
66 : : {GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ACTIVE, "Active", "active"},
67 : : {0, NULL, NULL}
68 : : };
69 : :
70 [ + - ]: 13 : if (!pad_negotiation_mode_type) {
71 : 13 : pad_negotiation_mode_type =
72 : 13 : g_enum_register_static ("GstOutputSelectorPadNegotiationMode",
73 : : pad_negotiation_modes);
74 : : }
75 : 13 : return pad_negotiation_mode_type;
76 : : }
77 : :
78 : :
79 : : enum
80 : : {
81 : : PROP_0,
82 : : PROP_ACTIVE_PAD,
83 : : PROP_RESEND_LATEST,
84 : : PROP_PAD_NEGOTIATION_MODE
85 : : };
86 : :
87 : : #define DEFAULT_PAD_NEGOTIATION_MODE GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ALL
88 : :
89 : : #define _do_init(bla) \
90 : : GST_DEBUG_CATEGORY_INIT (output_selector_debug, \
91 : : "output-selector", 0, "Output stream selector");
92 : :
93 [ + + ][ + - ]: 497 : GST_BOILERPLATE_FULL (GstOutputSelector, gst_output_selector, GstElement,
94 : 497 : GST_TYPE_ELEMENT, _do_init);
95 : :
96 : : static void gst_output_selector_dispose (GObject * object);
97 : : static void gst_output_selector_set_property (GObject * object,
98 : : guint prop_id, const GValue * value, GParamSpec * pspec);
99 : : static void gst_output_selector_get_property (GObject * object,
100 : : guint prop_id, GValue * value, GParamSpec * pspec);
101 : : static GstPad *gst_output_selector_request_new_pad (GstElement * element,
102 : : GstPadTemplate * templ, const gchar * unused);
103 : : static void gst_output_selector_release_pad (GstElement * element,
104 : : GstPad * pad);
105 : : static GstFlowReturn gst_output_selector_chain (GstPad * pad, GstBuffer * buf);
106 : : static GstFlowReturn gst_output_selector_buffer_alloc (GstPad * pad,
107 : : guint64 offset, guint size, GstCaps * caps, GstBuffer ** buf);
108 : : static GstStateChangeReturn gst_output_selector_change_state (GstElement *
109 : : element, GstStateChange transition);
110 : : static gboolean gst_output_selector_handle_sink_event (GstPad * pad,
111 : : GstEvent * event);
112 : : static void gst_output_selector_switch_pad_negotiation_mode (GstOutputSelector *
113 : : sel, gint mode);
114 : :
115 : : static void
116 : 13 : gst_output_selector_base_init (gpointer g_class)
117 : : {
118 : 13 : GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
119 : :
120 : 13 : gst_element_class_set_details_simple (element_class, "Output selector",
121 : : "Generic", "1-to-N output stream selector",
122 : : "Stefan Kost <stefan.kost@nokia.com>");
123 : 13 : gst_element_class_add_pad_template (element_class,
124 : : gst_static_pad_template_get (&gst_output_selector_sink_factory));
125 : 13 : gst_element_class_add_pad_template (element_class,
126 : : gst_static_pad_template_get (&gst_output_selector_src_factory));
127 : 13 : }
128 : :
129 : : static void
130 : 13 : gst_output_selector_class_init (GstOutputSelectorClass * klass)
131 : : {
132 : 13 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
133 : 13 : GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
134 : :
135 : 13 : gobject_class->dispose = gst_output_selector_dispose;
136 : :
137 : 13 : gobject_class->set_property = gst_output_selector_set_property;
138 : 13 : gobject_class->get_property = gst_output_selector_get_property;
139 : :
140 : 13 : g_object_class_install_property (gobject_class, PROP_ACTIVE_PAD,
141 : : g_param_spec_object ("active-pad", "Active pad",
142 : : "Currently active src pad", GST_TYPE_PAD,
143 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
144 : 13 : g_object_class_install_property (gobject_class, PROP_RESEND_LATEST,
145 : : g_param_spec_boolean ("resend-latest", "Resend latest buffer",
146 : : "Resend latest buffer after a switch to a new pad", FALSE,
147 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
148 : 13 : g_object_class_install_property (gobject_class, PROP_PAD_NEGOTIATION_MODE,
149 : : g_param_spec_enum ("pad-negotiation-mode", "Pad negotiation mode",
150 : : "The mode to be used for pad negotiation",
151 : : GST_TYPE_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE,
152 : : DEFAULT_PAD_NEGOTIATION_MODE,
153 : : G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
154 : :
155 : 13 : gstelement_class->request_new_pad =
156 : 13 : GST_DEBUG_FUNCPTR (gst_output_selector_request_new_pad);
157 : 13 : gstelement_class->release_pad =
158 : 13 : GST_DEBUG_FUNCPTR (gst_output_selector_release_pad);
159 : :
160 : 13 : gstelement_class->change_state = gst_output_selector_change_state;
161 : 13 : }
162 : :
163 : : static void
164 : 23 : gst_output_selector_init (GstOutputSelector * sel,
165 : : GstOutputSelectorClass * g_class)
166 : : {
167 : 23 : sel->sinkpad =
168 : 23 : gst_pad_new_from_static_template (&gst_output_selector_sink_factory,
169 : : "sink");
170 : 23 : gst_pad_set_chain_function (sel->sinkpad,
171 : 23 : GST_DEBUG_FUNCPTR (gst_output_selector_chain));
172 : 23 : gst_pad_set_event_function (sel->sinkpad,
173 : 23 : GST_DEBUG_FUNCPTR (gst_output_selector_handle_sink_event));
174 : 23 : gst_pad_set_bufferalloc_function (sel->sinkpad,
175 : 23 : GST_DEBUG_FUNCPTR (gst_output_selector_buffer_alloc));
176 : :
177 : 23 : gst_element_add_pad (GST_ELEMENT (sel), sel->sinkpad);
178 : :
179 : : /* srcpad management */
180 : 23 : sel->active_srcpad = NULL;
181 : 23 : sel->nb_srcpads = 0;
182 : 23 : gst_segment_init (&sel->segment, GST_FORMAT_TIME);
183 : 23 : sel->pending_srcpad = NULL;
184 : :
185 : 23 : sel->resend_latest = FALSE;
186 : 23 : sel->latest_buffer = NULL;
187 : 23 : gst_output_selector_switch_pad_negotiation_mode (sel,
188 : : DEFAULT_PAD_NEGOTIATION_MODE);
189 : 23 : }
190 : :
191 : : static void
192 : 50 : gst_output_selector_reset (GstOutputSelector * osel)
193 : : {
194 [ + + ]: 50 : if (osel->pending_srcpad != NULL) {
195 : 5 : gst_object_unref (osel->pending_srcpad);
196 : 5 : osel->pending_srcpad = NULL;
197 : : }
198 [ - + ]: 50 : if (osel->latest_buffer != NULL) {
199 : 0 : gst_buffer_unref (osel->latest_buffer);
200 : 0 : osel->latest_buffer = NULL;
201 : : }
202 : 50 : gst_segment_init (&osel->segment, GST_FORMAT_UNDEFINED);
203 : 50 : }
204 : :
205 : : static void
206 : 23 : gst_output_selector_dispose (GObject * object)
207 : : {
208 : 23 : GstOutputSelector *osel = GST_OUTPUT_SELECTOR (object);
209 : :
210 : 23 : gst_output_selector_reset (osel);
211 : :
212 : 23 : G_OBJECT_CLASS (parent_class)->dispose (object);
213 : 23 : }
214 : :
215 : : static void
216 : 36 : gst_output_selector_set_property (GObject * object, guint prop_id,
217 : : const GValue * value, GParamSpec * pspec)
218 : : {
219 : 36 : GstOutputSelector *sel = GST_OUTPUT_SELECTOR (object);
220 : :
221 [ + - + - ]: 36 : switch (prop_id) {
222 : : case PROP_ACTIVE_PAD:
223 : : {
224 : : GstPad *next_pad;
225 : :
226 : 30 : next_pad = g_value_get_object (value);
227 : :
228 [ - + ][ # # ]: 30 : GST_INFO_OBJECT (sel, "Activating pad %s:%s",
[ # # ][ # # ]
[ # # ][ # # ]
229 : : GST_DEBUG_PAD_NAME (next_pad));
230 : :
231 : 30 : GST_OBJECT_LOCK (object);
232 [ + + ]: 30 : if (next_pad != sel->active_srcpad) {
233 : : /* switch to new srcpad in next chain run */
234 [ + + ]: 15 : if (sel->pending_srcpad != NULL) {
235 [ - + ]: 1 : GST_INFO ("replacing pending switch");
236 : 1 : gst_object_unref (sel->pending_srcpad);
237 : : }
238 [ + - ]: 15 : if (next_pad)
239 : 15 : gst_object_ref (next_pad);
240 : 15 : sel->pending_srcpad = next_pad;
241 : : } else {
242 [ - + ]: 15 : GST_INFO ("pad already active");
243 [ - + ]: 15 : if (sel->pending_srcpad != NULL) {
244 : 0 : gst_object_unref (sel->pending_srcpad);
245 : 0 : sel->pending_srcpad = NULL;
246 : : }
247 : : }
248 : 30 : GST_OBJECT_UNLOCK (object);
249 : 30 : break;
250 : : }
251 : : case PROP_RESEND_LATEST:{
252 : 0 : sel->resend_latest = g_value_get_boolean (value);
253 : 0 : break;
254 : : }
255 : : case PROP_PAD_NEGOTIATION_MODE:{
256 : 6 : gst_output_selector_switch_pad_negotiation_mode (sel,
257 : : g_value_get_enum (value));
258 : 6 : break;
259 : : }
260 : : default:
261 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
262 : 0 : break;
263 : : }
264 : 36 : }
265 : :
266 : : static void
267 : 0 : gst_output_selector_get_property (GObject * object, guint prop_id,
268 : : GValue * value, GParamSpec * pspec)
269 : : {
270 : 0 : GstOutputSelector *sel = GST_OUTPUT_SELECTOR (object);
271 : :
272 [ # # # # ]: 0 : switch (prop_id) {
273 : : case PROP_ACTIVE_PAD:
274 : 0 : GST_OBJECT_LOCK (object);
275 [ # # ]: 0 : g_value_set_object (value,
276 : 0 : sel->pending_srcpad ? sel->pending_srcpad : sel->active_srcpad);
277 : 0 : GST_OBJECT_UNLOCK (object);
278 : 0 : break;
279 : : case PROP_RESEND_LATEST:{
280 : 0 : GST_OBJECT_LOCK (object);
281 : 0 : g_value_set_boolean (value, sel->resend_latest);
282 : 0 : GST_OBJECT_UNLOCK (object);
283 : 0 : break;
284 : : }
285 : : case PROP_PAD_NEGOTIATION_MODE:
286 : 0 : g_value_set_enum (value, sel->pad_negotiation_mode);
287 : 0 : break;
288 : : default:
289 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
290 : 0 : break;
291 : : }
292 : 0 : }
293 : :
294 : : static GstCaps *
295 : 3 : gst_output_selector_sink_getcaps (GstPad * pad)
296 : : {
297 : 3 : GstOutputSelector *sel = GST_OUTPUT_SELECTOR (GST_PAD_PARENT (pad));
298 : 3 : GstPad *active = NULL;
299 : 3 : GstCaps *caps = NULL;
300 : :
301 : 3 : GST_OBJECT_LOCK (sel);
302 [ + + ]: 3 : if (sel->pending_srcpad)
303 : 1 : active = gst_object_ref (sel->pending_srcpad);
304 [ + + ]: 2 : else if (sel->active_srcpad)
305 : 1 : active = gst_object_ref (sel->active_srcpad);
306 : 3 : GST_OBJECT_UNLOCK (sel);
307 : :
308 [ + + ]: 3 : if (active) {
309 : 2 : caps = gst_pad_peer_get_caps_reffed (active);
310 : 2 : gst_object_unref (active);
311 : : }
312 [ + + ]: 3 : if (caps == NULL) {
313 : 1 : caps = gst_caps_new_any ();
314 : : }
315 : 3 : return caps;
316 : : }
317 : :
318 : : static gboolean
319 : 0 : gst_output_selector_sink_setcaps (GstPad * pad, GstCaps * caps)
320 : : {
321 : 0 : GstOutputSelector *sel = GST_OUTPUT_SELECTOR (GST_PAD_PARENT (pad));
322 : 0 : GstPad *active = NULL;
323 : 0 : gboolean ret = TRUE;
324 : :
325 : 0 : GST_OBJECT_LOCK (sel);
326 [ # # ]: 0 : if (sel->pending_srcpad)
327 : 0 : active = gst_object_ref (sel->pending_srcpad);
328 [ # # ]: 0 : else if (sel->active_srcpad)
329 : 0 : active = gst_object_ref (sel->active_srcpad);
330 : 0 : GST_OBJECT_UNLOCK (sel);
331 : :
332 [ # # ]: 0 : if (active) {
333 : 0 : ret = gst_pad_set_caps (active, caps);
334 : 0 : gst_object_unref (active);
335 : : }
336 : 0 : return ret;
337 : : }
338 : :
339 : : static void
340 : 29 : gst_output_selector_switch_pad_negotiation_mode (GstOutputSelector * sel,
341 : : gint mode)
342 : : {
343 : 29 : sel->pad_negotiation_mode = mode;
344 [ + + ]: 29 : if (mode == GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_ALL) {
345 : 25 : gst_pad_set_getcaps_function (sel->sinkpad, gst_pad_proxy_getcaps);
346 : 25 : gst_pad_set_setcaps_function (sel->sinkpad, gst_pad_proxy_setcaps);
347 [ + + ]: 4 : } else if (mode == GST_OUTPUT_SELECTOR_PAD_NEGOTIATION_MODE_NONE) {
348 : 2 : gst_pad_set_getcaps_function (sel->sinkpad, NULL);
349 : 2 : gst_pad_set_setcaps_function (sel->sinkpad, NULL);
350 : : } else { /* active */
351 : 2 : gst_pad_set_getcaps_function (sel->sinkpad,
352 : : gst_output_selector_sink_getcaps);
353 : 2 : gst_pad_set_setcaps_function (sel->sinkpad,
354 : : gst_output_selector_sink_setcaps);
355 : : }
356 : 29 : }
357 : :
358 : : static GstFlowReturn
359 : 0 : gst_output_selector_buffer_alloc (GstPad * pad, guint64 offset, guint size,
360 : : GstCaps * caps, GstBuffer ** buf)
361 : : {
362 : : GstOutputSelector *sel;
363 : : GstFlowReturn res;
364 : : GstPad *allocpad;
365 : :
366 : 0 : sel = GST_OUTPUT_SELECTOR (GST_PAD_PARENT (pad));
367 : 0 : res = GST_FLOW_NOT_LINKED;
368 : :
369 : 0 : GST_OBJECT_LOCK (sel);
370 [ # # ]: 0 : allocpad = sel->pending_srcpad ? sel->pending_srcpad : sel->active_srcpad;
371 [ # # ]: 0 : if (allocpad) {
372 : : /* if we had a previous pad we used for allocating a buffer, continue using
373 : : * it. */
374 [ # # ][ # # ]: 0 : GST_DEBUG_OBJECT (sel, "using pad %s:%s for alloc",
[ # # ][ # # ]
[ # # ][ # # ]
375 : : GST_DEBUG_PAD_NAME (allocpad));
376 : 0 : gst_object_ref (allocpad);
377 : 0 : GST_OBJECT_UNLOCK (sel);
378 : :
379 : 0 : res = gst_pad_alloc_buffer (allocpad, offset, size, caps, buf);
380 : 0 : gst_object_unref (allocpad);
381 : :
382 : 0 : GST_OBJECT_LOCK (sel);
383 : : } else {
384 : : /* fallback case, allocate a buffer of our own, add pad caps. */
385 [ # # ]: 0 : GST_DEBUG_OBJECT (pad, "fallback buffer alloc");
386 : 0 : *buf = NULL;
387 : 0 : res = GST_FLOW_OK;
388 : : }
389 : 0 : GST_OBJECT_UNLOCK (sel);
390 : :
391 [ # # ]: 0 : GST_DEBUG_OBJECT (sel, "buffer alloc finished: %s", gst_flow_get_name (res));
392 : :
393 : 0 : return res;
394 : : }
395 : :
396 : : static GstPad *
397 : 30 : gst_output_selector_request_new_pad (GstElement * element,
398 : : GstPadTemplate * templ, const gchar * name)
399 : : {
400 : : gchar *padname;
401 : : GstPad *srcpad;
402 : : GstOutputSelector *osel;
403 : :
404 : 30 : osel = GST_OUTPUT_SELECTOR (element);
405 : :
406 [ - + ]: 30 : GST_DEBUG_OBJECT (osel, "requesting pad");
407 : :
408 : 30 : GST_OBJECT_LOCK (osel);
409 : 30 : padname = g_strdup_printf ("src%d", osel->nb_srcpads++);
410 : 30 : srcpad = gst_pad_new_from_template (templ, padname);
411 : 30 : GST_OBJECT_UNLOCK (osel);
412 : :
413 : 30 : gst_pad_set_active (srcpad, TRUE);
414 : 30 : gst_element_add_pad (GST_ELEMENT (osel), srcpad);
415 : :
416 : : /* Set the first requested src pad as active by default */
417 [ + + ]: 30 : if (osel->active_srcpad == NULL) {
418 : 15 : osel->active_srcpad = srcpad;
419 : : }
420 : 30 : g_free (padname);
421 : :
422 : 30 : return srcpad;
423 : : }
424 : :
425 : : static void
426 : 30 : gst_output_selector_release_pad (GstElement * element, GstPad * pad)
427 : : {
428 : : GstOutputSelector *osel;
429 : :
430 : 30 : osel = GST_OUTPUT_SELECTOR (element);
431 : :
432 [ - + ]: 30 : GST_DEBUG_OBJECT (osel, "releasing pad");
433 : :
434 : 30 : gst_pad_set_active (pad, FALSE);
435 : :
436 : 30 : gst_element_remove_pad (GST_ELEMENT_CAST (osel), pad);
437 : 30 : }
438 : :
439 : : static gboolean
440 : 9 : gst_output_selector_switch (GstOutputSelector * osel)
441 : : {
442 : 9 : gboolean res = FALSE;
443 : 9 : GstEvent *ev = NULL;
444 : 9 : GstSegment *seg = NULL;
445 : 9 : gint64 start = 0, position = 0;
446 : :
447 : : /* Switch */
448 : 9 : GST_OBJECT_LOCK (GST_OBJECT (osel));
449 [ - + ]: 9 : GST_INFO ("switching to pad %" GST_PTR_FORMAT, osel->pending_srcpad);
450 [ + - ]: 9 : if (gst_pad_is_linked (osel->pending_srcpad)) {
451 : 9 : osel->active_srcpad = osel->pending_srcpad;
452 : 9 : res = TRUE;
453 : : }
454 : 9 : gst_object_unref (osel->pending_srcpad);
455 : 9 : osel->pending_srcpad = NULL;
456 : 9 : GST_OBJECT_UNLOCK (GST_OBJECT (osel));
457 : :
458 : : /* Send NEWSEGMENT event and latest buffer if switching succeeded */
459 [ + - ]: 9 : if (res) {
460 : : /* Send NEWSEGMENT to the pad we are going to switch to */
461 : 9 : seg = &osel->segment;
462 : : /* If resending then mark newsegment start and position accordingly */
463 [ - + ][ # # ]: 9 : if (osel->resend_latest && osel->latest_buffer &&
[ # # ]
464 : 0 : GST_BUFFER_TIMESTAMP_IS_VALID (osel->latest_buffer)) {
465 : 0 : start = position = GST_BUFFER_TIMESTAMP (osel->latest_buffer);
466 : : } else {
467 : 9 : start = position = seg->last_stop;
468 : : }
469 : 9 : ev = gst_event_new_new_segment (TRUE, seg->rate,
470 : : seg->format, start, seg->stop, position);
471 [ + - ]: 9 : if (!gst_pad_push_event (osel->active_srcpad, ev)) {
472 [ - + ]: 9 : GST_WARNING_OBJECT (osel,
473 : : "newsegment handling failed in %" GST_PTR_FORMAT,
474 : : osel->active_srcpad);
475 : : }
476 : :
477 : : /* Resend latest buffer to newly switched pad */
478 [ - + ][ # # ]: 9 : if (osel->resend_latest && osel->latest_buffer) {
479 [ # # ]: 0 : GST_INFO ("resending latest buffer");
480 : 0 : gst_pad_push (osel->active_srcpad, gst_buffer_ref (osel->latest_buffer));
481 : : }
482 : : } else {
483 [ # # ]: 0 : GST_WARNING_OBJECT (osel, "switch failed, pad not linked");
484 : : }
485 : :
486 : 9 : return res;
487 : : }
488 : :
489 : : static GstFlowReturn
490 : 36 : gst_output_selector_chain (GstPad * pad, GstBuffer * buf)
491 : : {
492 : : GstFlowReturn res;
493 : : GstOutputSelector *osel;
494 : : GstClockTime last_stop, duration;
495 : :
496 : 36 : osel = GST_OUTPUT_SELECTOR (gst_pad_get_parent (pad));
497 : :
498 : : /*
499 : : * The _switch function might push a buffer if 'resend-latest' is true.
500 : : *
501 : : * Elements/Applications (e.g. camerabin) might use pad probes to
502 : : * switch output-selector's active pad. If we simply switch and don't
503 : : * recheck any pending pad switch the following codepath could end
504 : : * up pushing a buffer on a non-active pad. This is bad.
505 : : *
506 : : * So we always should check the pending_srcpad before going further down
507 : : * the chain and pushing the new buffer
508 : : */
509 [ + + ]: 45 : while (osel->pending_srcpad) {
510 : : /* Do the switch */
511 : 9 : gst_output_selector_switch (osel);
512 : : }
513 : :
514 [ - + ]: 36 : if (osel->latest_buffer) {
515 : 0 : gst_buffer_unref (osel->latest_buffer);
516 : 0 : osel->latest_buffer = NULL;
517 : : }
518 : :
519 [ - + ]: 36 : if (osel->resend_latest) {
520 : : /* Keep reference to latest buffer to resend it after switch */
521 : 0 : osel->latest_buffer = gst_buffer_ref (buf);
522 : : }
523 : :
524 : : /* Keep track of last stop and use it in NEWSEGMENT start after
525 : : switching to a new src pad */
526 : 36 : last_stop = GST_BUFFER_TIMESTAMP (buf);
527 [ - + ]: 36 : if (GST_CLOCK_TIME_IS_VALID (last_stop)) {
528 : 0 : duration = GST_BUFFER_DURATION (buf);
529 [ # # ]: 0 : if (GST_CLOCK_TIME_IS_VALID (duration)) {
530 : 0 : last_stop += duration;
531 : : }
532 [ # # ][ # # ]: 0 : GST_LOG_OBJECT (osel, "setting last stop %" GST_TIME_FORMAT,
[ # # ][ # # ]
[ # # ]
533 : : GST_TIME_ARGS (last_stop));
534 : 0 : gst_segment_set_last_stop (&osel->segment, osel->segment.format, last_stop);
535 : : }
536 : :
537 [ - + ]: 36 : GST_LOG_OBJECT (osel, "pushing buffer to %" GST_PTR_FORMAT,
538 : : osel->active_srcpad);
539 : 36 : res = gst_pad_push (osel->active_srcpad, buf);
540 : 36 : gst_object_unref (osel);
541 : :
542 : 36 : return res;
543 : : }
544 : :
545 : : static GstStateChangeReturn
546 : 173 : gst_output_selector_change_state (GstElement * element,
547 : : GstStateChange transition)
548 : : {
549 : : GstOutputSelector *sel;
550 : : GstStateChangeReturn result;
551 : :
552 : 173 : sel = GST_OUTPUT_SELECTOR (element);
553 : :
554 [ + + ]: 173 : switch (transition) {
555 : : case GST_STATE_CHANGE_READY_TO_PAUSED:
556 : 27 : break;
557 : : default:
558 : 146 : break;
559 : : }
560 : :
561 : 173 : result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
562 : :
563 [ + + ]: 173 : switch (transition) {
564 : : case GST_STATE_CHANGE_PAUSED_TO_READY:
565 : 27 : gst_output_selector_reset (sel);
566 : 27 : break;
567 : : default:
568 : 146 : break;
569 : : }
570 : :
571 : 173 : return result;
572 : : }
573 : :
574 : : static gboolean
575 : 0 : gst_output_selector_handle_sink_event (GstPad * pad, GstEvent * event)
576 : : {
577 : 0 : gboolean res = TRUE;
578 : : GstOutputSelector *sel;
579 : 0 : GstPad *output_pad = NULL;
580 : :
581 : 0 : sel = GST_OUTPUT_SELECTOR (gst_pad_get_parent (pad));
582 : :
583 [ # # # ]: 0 : switch (GST_EVENT_TYPE (event)) {
584 : : case GST_EVENT_NEWSEGMENT:
585 : : {
586 : : gboolean update;
587 : : GstFormat format;
588 : : gdouble rate, arate;
589 : : gint64 start, stop, time;
590 : :
591 : 0 : gst_event_parse_new_segment_full (event, &update, &rate, &arate, &format,
592 : : &start, &stop, &time);
593 : :
594 [ # # ]: 0 : GST_DEBUG_OBJECT (sel,
595 : : "configured NEWSEGMENT update %d, rate %lf, applied rate %lf, "
596 : : "format %d, " "%" G_GINT64_FORMAT " -- %" G_GINT64_FORMAT ", time %"
597 : : G_GINT64_FORMAT, update, rate, arate, format, start, stop, time);
598 : :
599 : 0 : gst_segment_set_newsegment_full (&sel->segment, update,
600 : : rate, arate, format, start, stop, time);
601 : :
602 : : /* Send newsegment to all src pads */
603 : 0 : gst_pad_event_default (pad, event);
604 : 0 : break;
605 : : }
606 : : case GST_EVENT_EOS:
607 : : /* Send eos to all src pads */
608 : 0 : gst_pad_event_default (pad, event);
609 : 0 : break;
610 : : default:
611 : : /* Send other events to pending or active src pad */
612 : 0 : output_pad =
613 [ # # ]: 0 : sel->pending_srcpad ? sel->pending_srcpad : sel->active_srcpad;
614 : 0 : res = gst_pad_push_event (output_pad, event);
615 : 0 : break;
616 : : }
617 : :
618 : 0 : gst_object_unref (sel);
619 : :
620 : 0 : return res;
621 : : }
|