114 const GValue * value, GParamSpec * pspec); |
117 const GValue * value, GParamSpec * pspec); |
115 static void gst_tee_get_property (GObject * object, guint prop_id, |
118 static void gst_tee_get_property (GObject * object, guint prop_id, |
116 GValue * value, GParamSpec * pspec); |
119 GValue * value, GParamSpec * pspec); |
117 |
120 |
118 static GstFlowReturn gst_tee_chain (GstPad * pad, GstBuffer * buffer); |
121 static GstFlowReturn gst_tee_chain (GstPad * pad, GstBuffer * buffer); |
119 static GstFlowReturn gst_tee_chain_list (GstPad * pad, GstBufferList * list); |
|
120 static GstFlowReturn gst_tee_buffer_alloc (GstPad * pad, guint64 offset, |
122 static GstFlowReturn gst_tee_buffer_alloc (GstPad * pad, guint64 offset, |
121 guint size, GstCaps * caps, GstBuffer ** buf); |
123 guint size, GstCaps * caps, GstBuffer ** buf); |
122 static gboolean gst_tee_sink_activate_push (GstPad * pad, gboolean active); |
124 static gboolean gst_tee_sink_activate_push (GstPad * pad, gboolean active); |
123 static gboolean gst_tee_src_check_get_range (GstPad * pad); |
125 static gboolean gst_tee_src_check_get_range (GstPad * pad); |
124 static gboolean gst_tee_src_activate_pull (GstPad * pad, gboolean active); |
126 static gboolean gst_tee_src_activate_pull (GstPad * pad, gboolean active); |
172 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_tee_get_property); |
172 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_tee_get_property); |
173 |
173 |
174 g_object_class_install_property (gobject_class, PROP_NUM_SRC_PADS, |
174 g_object_class_install_property (gobject_class, PROP_NUM_SRC_PADS, |
175 g_param_spec_int ("num-src-pads", "Num Src Pads", |
175 g_param_spec_int ("num-src-pads", "Num Src Pads", |
176 "The number of source pads", 0, G_MAXINT, DEFAULT_PROP_NUM_SRC_PADS, |
176 "The number of source pads", 0, G_MAXINT, DEFAULT_PROP_NUM_SRC_PADS, |
177 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); |
177 G_PARAM_READABLE)); |
178 g_object_class_install_property (gobject_class, PROP_HAS_SINK_LOOP, |
178 g_object_class_install_property (gobject_class, PROP_HAS_SINK_LOOP, |
179 g_param_spec_boolean ("has-sink-loop", "Has Sink Loop", |
179 g_param_spec_boolean ("has-sink-loop", "Has Sink Loop", |
180 "If the element should spawn a thread (unimplemented and deprecated)", |
180 "If the element should spawn a thread (unimplemented and deprecated)", |
181 DEFAULT_PROP_HAS_SINK_LOOP, |
181 DEFAULT_PROP_HAS_SINK_LOOP, G_PARAM_CONSTRUCT | G_PARAM_READWRITE)); |
182 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
183 g_object_class_install_property (gobject_class, PROP_HAS_CHAIN, |
182 g_object_class_install_property (gobject_class, PROP_HAS_CHAIN, |
184 g_param_spec_boolean ("has-chain", "Has Chain", |
183 g_param_spec_boolean ("has-chain", "Has Chain", |
185 "If the element can operate in push mode", DEFAULT_PROP_HAS_CHAIN, |
184 "If the element can operate in push mode", |
186 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
185 DEFAULT_PROP_HAS_CHAIN, G_PARAM_CONSTRUCT | G_PARAM_READWRITE)); |
187 g_object_class_install_property (gobject_class, PROP_SILENT, |
186 g_object_class_install_property (gobject_class, PROP_SILENT, |
188 g_param_spec_boolean ("silent", "Silent", |
187 g_param_spec_boolean ("silent", "Silent", |
189 "Don't produce last_message events", DEFAULT_PROP_SILENT, |
188 "Don't produce last_message events", DEFAULT_PROP_SILENT, |
190 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
189 G_PARAM_CONSTRUCT | G_PARAM_READWRITE)); |
191 g_object_class_install_property (gobject_class, PROP_LAST_MESSAGE, |
190 g_object_class_install_property (gobject_class, PROP_LAST_MESSAGE, |
192 g_param_spec_string ("last-message", "Last Message", |
191 g_param_spec_string ("last_message", "Last Message", |
193 "The message describing current status", DEFAULT_PROP_LAST_MESSAGE, |
192 "The message describing current status", DEFAULT_PROP_LAST_MESSAGE, |
194 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); |
193 G_PARAM_READABLE)); |
195 g_object_class_install_property (gobject_class, PROP_PULL_MODE, |
194 g_object_class_install_property (gobject_class, PROP_PULL_MODE, |
196 g_param_spec_enum ("pull-mode", "Pull mode", |
195 g_param_spec_enum ("pull-mode", "Pull mode", |
197 "Behavior of tee in pull mode", GST_TYPE_TEE_PULL_MODE, |
196 "Behavior of tee in pull mode", GST_TYPE_TEE_PULL_MODE, |
198 DEFAULT_PULL_MODE, |
197 DEFAULT_PULL_MODE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE)); |
199 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
200 g_object_class_install_property (gobject_class, PROP_ALLOC_PAD, |
|
201 g_param_spec_object ("alloc-pad", "Allocation Src Pad", |
|
202 "The pad used for gst_pad_alloc_buffer", GST_TYPE_PAD, |
|
203 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
|
204 |
198 |
205 gstelement_class->request_new_pad = |
199 gstelement_class->request_new_pad = |
206 GST_DEBUG_FUNCPTR (gst_tee_request_new_pad); |
200 GST_DEBUG_FUNCPTR (gst_tee_request_new_pad); |
207 gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_tee_release_pad); |
201 gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_tee_release_pad); |
208 } |
202 } |
209 |
203 |
210 static void |
204 static void |
211 gst_tee_init (GstTee * tee, GstTeeClass * g_class) |
205 gst_tee_init (GstTee * tee, GstTeeClass * g_class) |
212 { |
206 { |
213 tee->dyn_lock = g_mutex_new (); |
|
214 |
|
215 tee->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink"); |
207 tee->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink"); |
216 tee->sink_mode = GST_ACTIVATE_NONE; |
208 tee->sink_mode = GST_ACTIVATE_NONE; |
217 |
209 |
218 gst_pad_set_setcaps_function (tee->sinkpad, |
210 gst_pad_set_setcaps_function (tee->sinkpad, |
219 GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps)); |
211 GST_DEBUG_FUNCPTR (gst_pad_proxy_setcaps)); |
299 GST_OBJECT_LOCK (tee); |
288 GST_OBJECT_LOCK (tee); |
300 GST_DEBUG_OBJECT (tee, "warning failed to activate request pad"); |
289 GST_DEBUG_OBJECT (tee, "warning failed to activate request pad"); |
301 if (tee->allocpad == srcpad) |
290 if (tee->allocpad == srcpad) |
302 tee->allocpad = NULL; |
291 tee->allocpad = NULL; |
303 gst_object_unref (srcpad); |
292 gst_object_unref (srcpad); |
304 GST_OBJECT_UNLOCK (tee); |
293 GST_OBJECT_LOCK (tee); |
305 g_object_notify (G_OBJECT (tee), "alloc-pad"); |
|
306 return NULL; |
294 return NULL; |
307 } |
295 } |
308 } |
296 } |
309 |
297 |
310 static void |
298 static void |
311 gst_tee_release_pad (GstElement * element, GstPad * pad) |
299 gst_tee_release_pad (GstElement * element, GstPad * pad) |
312 { |
300 { |
313 GstTee *tee; |
301 GstTee *tee; |
314 PushData *data; |
|
315 |
302 |
316 tee = GST_TEE (element); |
303 tee = GST_TEE (element); |
317 |
304 |
318 GST_DEBUG_OBJECT (tee, "releasing pad"); |
305 GST_DEBUG_OBJECT (tee, "releasing pad"); |
319 |
306 |
320 GST_OBJECT_LOCK (tee); |
307 GST_OBJECT_LOCK (tee); |
321 if (tee->allocpad == pad) |
308 if (tee->allocpad == pad) |
322 tee->allocpad = NULL; |
309 tee->allocpad = NULL; |
323 GST_OBJECT_UNLOCK (tee); |
310 GST_OBJECT_UNLOCK (tee); |
324 g_object_notify (G_OBJECT (tee), "alloc-pad"); |
|
325 |
|
326 /* wait for pending pad_alloc to finish */ |
|
327 GST_TEE_DYN_LOCK (tee); |
|
328 /* mark the pad as removed so that future pad_alloc fails with NOT_LINKED. */ |
|
329 data = g_object_get_qdata (G_OBJECT (pad), push_data); |
|
330 data->removed = TRUE; |
|
331 |
311 |
332 gst_pad_set_active (pad, FALSE); |
312 gst_pad_set_active (pad, FALSE); |
333 |
313 |
334 gst_element_remove_pad (GST_ELEMENT_CAST (tee), pad); |
314 gst_element_remove_pad (GST_ELEMENT_CAST (tee), pad); |
335 GST_TEE_DYN_UNLOCK (tee); |
|
336 } |
315 } |
337 |
316 |
338 static void |
317 static void |
339 gst_tee_set_property (GObject * object, guint prop_id, const GValue * value, |
318 gst_tee_set_property (GObject * object, guint prop_id, const GValue * value, |
340 GParamSpec * pspec) |
319 GParamSpec * pspec) |
401 g_value_set_string (value, tee->last_message); |
368 g_value_set_string (value, tee->last_message); |
402 break; |
369 break; |
403 case PROP_PULL_MODE: |
370 case PROP_PULL_MODE: |
404 g_value_set_enum (value, tee->pull_mode); |
371 g_value_set_enum (value, tee->pull_mode); |
405 break; |
372 break; |
406 case PROP_ALLOC_PAD: |
|
407 g_value_set_object (value, tee->allocpad); |
|
408 break; |
|
409 default: |
373 default: |
410 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
374 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
411 break; |
375 break; |
412 } |
376 } |
413 GST_OBJECT_UNLOCK (tee); |
377 GST_OBJECT_UNLOCK (tee); |
414 } |
378 } |
415 |
379 |
416 /* we have no previous source pad we can use to proxy the pad alloc. Loop over |
380 /* we have no previous source pad we can use to proxy the pad alloc. Loop over |
417 * the source pads, try to alloc a buffer on each one of them. Keep a reference |
381 * the source pads, try to alloc a buffer on each one of them. Keep a reference |
418 * to the first pad that succeeds, we will be using it to alloc more buffers |
382 * to the first pad that succeeds, we will be using it to alloc more buffers |
419 * later. must be called with the OBJECT_LOCK on tee. */ |
383 * later. */ |
420 static GstFlowReturn |
384 static GstFlowReturn |
421 gst_tee_find_buffer_alloc (GstTee * tee, guint64 offset, guint size, |
385 gst_tee_find_buffer_alloc (GstTee * tee, guint64 offset, guint size, |
422 GstCaps * caps, GstBuffer ** buf) |
386 GstCaps * caps, GstBuffer ** buf) |
423 { |
387 { |
424 GstFlowReturn res; |
388 GstFlowReturn res; |
431 pads = GST_ELEMENT_CAST (tee)->srcpads; |
395 pads = GST_ELEMENT_CAST (tee)->srcpads; |
432 cookie = GST_ELEMENT_CAST (tee)->pads_cookie; |
396 cookie = GST_ELEMENT_CAST (tee)->pads_cookie; |
433 |
397 |
434 while (pads) { |
398 while (pads) { |
435 GstPad *pad; |
399 GstPad *pad; |
436 PushData *data; |
|
437 |
400 |
438 pad = GST_PAD_CAST (pads->data); |
401 pad = GST_PAD_CAST (pads->data); |
439 gst_object_ref (pad); |
402 gst_object_ref (pad); |
440 GST_DEBUG_OBJECT (tee, "try alloc on pad %s:%s", GST_DEBUG_PAD_NAME (pad)); |
403 GST_DEBUG_OBJECT (tee, "try alloc on pad %s:%s", GST_DEBUG_PAD_NAME (pad)); |
441 GST_OBJECT_UNLOCK (tee); |
404 GST_OBJECT_UNLOCK (tee); |
442 |
405 |
443 GST_TEE_DYN_LOCK (tee); |
406 res = gst_pad_alloc_buffer (pad, offset, size, caps, buf); |
444 data = g_object_get_qdata (G_OBJECT (pad), push_data); |
|
445 if (!data->removed) |
|
446 res = gst_pad_alloc_buffer (pad, offset, size, caps, buf); |
|
447 else |
|
448 res = GST_FLOW_NOT_LINKED; |
|
449 GST_TEE_DYN_UNLOCK (tee); |
|
450 |
407 |
451 GST_DEBUG_OBJECT (tee, "got return value %d", res); |
408 GST_DEBUG_OBJECT (tee, "got return value %d", res); |
452 |
409 |
453 gst_object_unref (pad); |
410 gst_object_unref (pad); |
454 |
411 |
457 GST_DEBUG_OBJECT (tee, "pad list changed, restart"); |
414 GST_DEBUG_OBJECT (tee, "pad list changed, restart"); |
458 /* pad list changed, restart. If the pad alloc function returned OK we |
415 /* pad list changed, restart. If the pad alloc function returned OK we |
459 * need to unref the buffer */ |
416 * need to unref the buffer */ |
460 if (res == GST_FLOW_OK) |
417 if (res == GST_FLOW_OK) |
461 gst_buffer_unref (*buf); |
418 gst_buffer_unref (*buf); |
462 *buf = NULL; |
|
463 goto retry; |
419 goto retry; |
464 } |
420 } |
465 if (res == GST_FLOW_OK) { |
421 if (res == GST_FLOW_OK) { |
466 GST_DEBUG_OBJECT (tee, "we have a buffer on pad %s:%s", |
422 GST_DEBUG_OBJECT (tee, "we have a buffer on pad %s:%s", |
467 GST_DEBUG_PAD_NAME (pad)); |
423 GST_DEBUG_PAD_NAME (pad)); |
468 /* we have a buffer, keep the pad for later and exit the loop. */ |
424 /* we have a buffer, keep the pad for later and exit the loop. */ |
469 tee->allocpad = pad; |
425 tee->allocpad = pad; |
470 GST_OBJECT_UNLOCK (tee); |
|
471 g_object_notify (G_OBJECT (tee), "alloc-pad"); |
|
472 GST_OBJECT_LOCK (tee); |
|
473 break; |
426 break; |
474 } |
427 } |
475 /* no valid buffer, try another pad */ |
428 /* no valid buffer, try another pad */ |
476 pads = g_list_next (pads); |
429 pads = g_list_next (pads); |
477 } |
430 } |
491 |
444 |
492 res = GST_FLOW_NOT_LINKED; |
445 res = GST_FLOW_NOT_LINKED; |
493 |
446 |
494 GST_OBJECT_LOCK (tee); |
447 GST_OBJECT_LOCK (tee); |
495 if ((allocpad = tee->allocpad)) { |
448 if ((allocpad = tee->allocpad)) { |
496 PushData *data; |
|
497 |
|
498 /* if we had a previous pad we used for allocating a buffer, continue using |
449 /* if we had a previous pad we used for allocating a buffer, continue using |
499 * it. */ |
450 * it. */ |
500 GST_DEBUG_OBJECT (tee, "using pad %s:%s for alloc", |
451 GST_DEBUG_OBJECT (tee, "using pad %s:%s for alloc", |
501 GST_DEBUG_PAD_NAME (allocpad)); |
452 GST_DEBUG_PAD_NAME (allocpad)); |
502 gst_object_ref (allocpad); |
453 gst_object_ref (allocpad); |
503 GST_OBJECT_UNLOCK (tee); |
454 GST_OBJECT_UNLOCK (tee); |
504 |
455 |
505 GST_TEE_DYN_LOCK (tee); |
456 res = gst_pad_alloc_buffer (allocpad, offset, size, caps, buf); |
506 data = g_object_get_qdata (G_OBJECT (allocpad), push_data); |
|
507 if (!data->removed) |
|
508 res = gst_pad_alloc_buffer (allocpad, offset, size, caps, buf); |
|
509 else |
|
510 res = GST_FLOW_NOT_LINKED; |
|
511 GST_TEE_DYN_UNLOCK (tee); |
|
512 |
|
513 gst_object_unref (allocpad); |
457 gst_object_unref (allocpad); |
514 |
458 |
515 GST_OBJECT_LOCK (tee); |
459 GST_OBJECT_LOCK (tee); |
516 } |
460 } |
517 /* either we failed to alloc on the the previous pad or we did not have a |
461 /* either we failed to alloc on the the previous pad or we did not have a |
525 |
469 |
526 return res; |
470 return res; |
527 } |
471 } |
528 |
472 |
529 static GstFlowReturn |
473 static GstFlowReturn |
530 gst_tee_do_push (GstTee * tee, GstPad * pad, gpointer data, gboolean is_list) |
474 gst_tee_do_push (GstTee * tee, GstPad * pad, GstBuffer * buffer) |
531 { |
475 { |
532 GstFlowReturn res; |
476 GstFlowReturn res; |
533 |
477 |
534 if (G_UNLIKELY (!tee->silent)) { |
478 if (G_UNLIKELY (!tee->silent)) { |
535 GST_OBJECT_LOCK (tee); |
479 GST_OBJECT_LOCK (tee); |
536 g_free (tee->last_message); |
480 g_free (tee->last_message); |
537 if (is_list) { |
481 tee->last_message = |
538 tee->last_message = |
482 g_strdup_printf ("chain ******* (%s:%s)t (%d bytes, %" |
539 g_strdup_printf ("chain-list ******* (%s:%s)t %p", |
483 G_GUINT64_FORMAT ") %p", GST_DEBUG_PAD_NAME (pad), |
540 GST_DEBUG_PAD_NAME (pad), data); |
484 GST_BUFFER_SIZE (buffer), GST_BUFFER_TIMESTAMP (buffer), buffer); |
541 } else { |
|
542 tee->last_message = |
|
543 g_strdup_printf ("chain ******* (%s:%s)t (%d bytes, %" |
|
544 G_GUINT64_FORMAT ") %p", GST_DEBUG_PAD_NAME (pad), |
|
545 GST_BUFFER_SIZE (data), GST_BUFFER_TIMESTAMP (data), data); |
|
546 } |
|
547 GST_OBJECT_UNLOCK (tee); |
485 GST_OBJECT_UNLOCK (tee); |
548 g_object_notify (G_OBJECT (tee), "last_message"); |
486 g_object_notify (G_OBJECT (tee), "last_message"); |
549 } |
487 } |
550 |
488 |
551 /* Push */ |
489 /* Push */ |
552 if (pad == tee->pull_pad) { |
490 if (pad == tee->pull_pad) { |
553 /* don't push on the pad we're pulling from */ |
491 /* don't push on the pad we're pulling from */ |
554 res = GST_FLOW_OK; |
492 res = GST_FLOW_OK; |
555 } else if (is_list) { |
|
556 res = |
|
557 gst_pad_push_list (pad, |
|
558 gst_buffer_list_ref (GST_BUFFER_LIST_CAST (data))); |
|
559 } else { |
493 } else { |
560 res = gst_pad_push (pad, gst_buffer_ref (GST_BUFFER_CAST (data))); |
494 res = gst_pad_push (pad, gst_buffer_ref (buffer)); |
561 } |
495 } |
562 return res; |
496 return res; |
563 } |
497 } |
564 |
498 |
565 static void |
499 static void |
596 pads = GST_ELEMENT_CAST (tee)->srcpads; |
528 pads = GST_ELEMENT_CAST (tee)->srcpads; |
597 cookie = GST_ELEMENT_CAST (tee)->pads_cookie; |
529 cookie = GST_ELEMENT_CAST (tee)->pads_cookie; |
598 |
530 |
599 while (pads) { |
531 while (pads) { |
600 GstPad *pad; |
532 GstPad *pad; |
601 PushData *pdata; |
533 PushData *data; |
602 |
534 |
603 pad = GST_PAD_CAST (pads->data); |
535 pad = GST_PAD_CAST (pads->data); |
604 |
536 |
605 /* get the private data, something is really wrong with the internal state |
537 /* get the private data, something is really wrong with the internal state |
606 * when it is not there */ |
538 * when it is not there */ |
607 pdata = g_object_get_qdata (G_OBJECT (pad), push_data); |
539 data = g_object_get_qdata (G_OBJECT (pad), push_data); |
608 g_assert (pdata != NULL); |
540 |
609 |
541 g_assert (data != NULL); |
610 if (!pdata->pushed) { |
542 |
|
543 if (!data->pushed) { |
611 /* not yet pushed, release lock and start pushing */ |
544 /* not yet pushed, release lock and start pushing */ |
612 gst_object_ref (pad); |
545 gst_object_ref (pad); |
613 GST_OBJECT_UNLOCK (tee); |
546 GST_OBJECT_UNLOCK (tee); |
614 |
547 |
615 GST_LOG_OBJECT (tee, "Starting to push %s %p", |
548 GST_LOG_OBJECT (tee, "Starting to push buffer %p", buffer); |
616 is_list ? "list" : "buffer", data); |
549 |
617 |
550 ret = gst_tee_do_push (tee, pad, buffer); |
618 ret = gst_tee_do_push (tee, pad, data, is_list); |
551 |
619 |
552 GST_LOG_OBJECT (tee, "Pushing buffer %p yielded result %s", buffer, |
620 GST_LOG_OBJECT (tee, "Pushing item %p yielded result %s", data, |
|
621 gst_flow_get_name (ret)); |
553 gst_flow_get_name (ret)); |
622 |
554 |
623 GST_OBJECT_LOCK (tee); |
555 GST_OBJECT_LOCK (tee); |
624 /* keep track of which pad we pushed and the result value. We need to do |
556 /* keep track of which pad we pushed and the result value. We need to do |
625 * this before we release the refcount on the pad, the PushData is |
557 * this before we release the refcount on the pad, the PushData is |
626 * destroyed when the last ref of the pad goes away. */ |
558 * destroyed when the last ref of the pad goes away. */ |
627 pdata->pushed = TRUE; |
559 data->pushed = TRUE; |
628 pdata->result = ret; |
560 data->result = ret; |
629 gst_object_unref (pad); |
561 gst_object_unref (pad); |
630 } else { |
562 } else { |
631 /* already pushed, use previous return value */ |
563 /* already pushed, use previous return value */ |
632 ret = pdata->result; |
564 ret = data->result; |
633 GST_LOG_OBJECT (tee, "pad already pushed with %s", |
565 GST_LOG_OBJECT (tee, "pad already pushed with %s", |
634 gst_flow_get_name (ret)); |
566 gst_flow_get_name (ret)); |
635 } |
567 } |
636 |
568 /* stop pushing more buffers when we have a fatal error */ |
637 /* before we go combining the return value, check if the pad list is still |
569 if (GST_FLOW_IS_FATAL (ret)) |
638 * the same. It could be possible that the pad we just pushed was removed |
570 goto error; |
639 * and the return value it not valid anymore */ |
571 |
|
572 /* keep all other return values, overwriting the previous one */ |
|
573 GST_LOG_OBJECT (tee, "Replacing ret val %d with %d", cret, ret); |
|
574 if (cret == GST_FLOW_NOT_LINKED) |
|
575 cret = ret; |
|
576 |
640 if (GST_ELEMENT_CAST (tee)->pads_cookie != cookie) { |
577 if (GST_ELEMENT_CAST (tee)->pads_cookie != cookie) { |
641 GST_LOG_OBJECT (tee, "pad list changed"); |
578 GST_LOG_OBJECT (tee, "pad list changed"); |
642 /* the list of pads changed, restart iteration. Pads that we already |
579 /* the list of pads changed, restart iteration. Pads that we already |
643 * pushed on and are still in the new list, will not be pushed on |
580 * pushed on and are still in the new list, will not be pushed on |
644 * again. */ |
581 * again. */ |
645 goto restart; |
582 goto restart; |
646 } |
583 } |
647 |
|
648 /* stop pushing more buffers when we have a fatal error */ |
|
649 if (ret != GST_FLOW_OK && ret != GST_FLOW_NOT_LINKED) |
|
650 goto error; |
|
651 |
|
652 /* keep all other return values, overwriting the previous one. */ |
|
653 if (ret != GST_FLOW_NOT_LINKED) { |
|
654 GST_LOG_OBJECT (tee, "Replacing ret val %d with %d", cret, ret); |
|
655 cret = ret; |
|
656 } |
|
657 pads = g_list_next (pads); |
584 pads = g_list_next (pads); |
658 } |
585 } |
659 GST_OBJECT_UNLOCK (tee); |
586 GST_OBJECT_UNLOCK (tee); |
660 |
587 |
661 gst_mini_object_unref (GST_MINI_OBJECT_CAST (data)); |
588 gst_buffer_unref (buffer); |
662 |
589 |
663 /* no need to unset gvalue */ |
590 /* no need to unset gvalue */ |
664 return cret; |
591 return cret; |
665 |
592 |
666 /* ERRORS */ |
593 /* ERRORS */ |
667 error: |
594 error: |
668 { |
595 { |
669 GST_DEBUG_OBJECT (tee, "received error %s", gst_flow_get_name (ret)); |
596 GST_DEBUG_OBJECT (tee, "received error %s", gst_flow_get_name (ret)); |
670 gst_mini_object_unref (GST_MINI_OBJECT_CAST (data)); |
597 gst_buffer_unref (buffer); |
671 GST_OBJECT_UNLOCK (tee); |
598 GST_OBJECT_UNLOCK (tee); |
672 return ret; |
599 return ret; |
673 } |
600 } |
674 } |
601 } |
675 |
602 |