Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / gst-libs / gst / rtp / gstbasertpdepayload.c
1 /* GStreamer
2  * Copyright (C) <2005> Philippe Khalaf <burger@speedy.org> 
3  * Copyright (C) <2005> Nokia Corporation <kai.vehmanen@nokia.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /**
22  * SECTION:gstbasertpdepayload
23  * @short_description: Base class for RTP depayloader
24  *
25  * <refsect2>
26  * <para>
27  * Provides a base class for RTP depayloaders
28  * </para>
29  * </refsect2>
30  */
31
32 #include "gstbasertpdepayload.h"
33
34 #ifdef GST_DISABLE_DEPRECATED
35 #define QUEUE_LOCK_INIT(base)   (g_static_rec_mutex_init(&base->queuelock))
36 #define QUEUE_LOCK_FREE(base)   (g_static_rec_mutex_free(&base->queuelock))
37 #define QUEUE_LOCK(base)        (g_static_rec_mutex_lock(&base->queuelock))
38 #define QUEUE_UNLOCK(base)      (g_static_rec_mutex_unlock(&base->queuelock))
39 #else
40 /* otherwise it's already been defined in the header (FIXME 0.11)*/
41 #endif
42
43 GST_DEBUG_CATEGORY_STATIC (basertpdepayload_debug);
44 #define GST_CAT_DEFAULT (basertpdepayload_debug)
45
46 #define GST_BASE_RTP_DEPAYLOAD_GET_PRIVATE(obj)  \
47    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_BASE_RTP_DEPAYLOAD, GstBaseRTPDepayloadPrivate))
48
49 struct _GstBaseRTPDepayloadPrivate
50 {
51   GstClockTime npt_start;
52   GstClockTime npt_stop;
53   gdouble play_speed;
54   gdouble play_scale;
55
56   gboolean discont;
57   GstClockTime timestamp;
58   GstClockTime duration;
59
60   guint32 next_seqnum;
61
62   gboolean negotiated;
63 };
64
65 /* Filter signals and args */
66 enum
67 {
68   /* FILL ME */
69   LAST_SIGNAL
70 };
71
72 #define DEFAULT_QUEUE_DELAY     0
73
74 enum
75 {
76   PROP_0,
77   PROP_QUEUE_DELAY,
78   PROP_LAST
79 };
80
81 static void gst_base_rtp_depayload_finalize (GObject * object);
82 static void gst_base_rtp_depayload_set_property (GObject * object,
83     guint prop_id, const GValue * value, GParamSpec * pspec);
84 static void gst_base_rtp_depayload_get_property (GObject * object,
85     guint prop_id, GValue * value, GParamSpec * pspec);
86
87 static gboolean gst_base_rtp_depayload_setcaps (GstPad * pad, GstCaps * caps);
88 static GstFlowReturn gst_base_rtp_depayload_chain (GstPad * pad,
89     GstBuffer * in);
90 static gboolean gst_base_rtp_depayload_handle_sink_event (GstPad * pad,
91     GstEvent * event);
92
93 static GstStateChangeReturn gst_base_rtp_depayload_change_state (GstElement *
94     element, GstStateChange transition);
95
96 static void gst_base_rtp_depayload_set_gst_timestamp
97     (GstBaseRTPDepayload * filter, guint32 rtptime, GstBuffer * buf);
98 static gboolean gst_base_rtp_depayload_packet_lost (GstBaseRTPDepayload *
99     filter, GstEvent * event);
100 static gboolean gst_base_rtp_depayload_handle_event (GstBaseRTPDepayload *
101     filter, GstEvent * event);
102
103 GST_BOILERPLATE (GstBaseRTPDepayload, gst_base_rtp_depayload, GstElement,
104     GST_TYPE_ELEMENT);
105
106 static void
107 gst_base_rtp_depayload_base_init (gpointer klass)
108 {
109   /*GstElementClass *element_class = GST_ELEMENT_CLASS (klass); */
110 }
111
112 static void
113 gst_base_rtp_depayload_class_init (GstBaseRTPDepayloadClass * klass)
114 {
115   GObjectClass *gobject_class;
116   GstElementClass *gstelement_class;
117
118   gobject_class = G_OBJECT_CLASS (klass);
119   gstelement_class = (GstElementClass *) klass;
120   parent_class = g_type_class_peek_parent (klass);
121
122   g_type_class_add_private (klass, sizeof (GstBaseRTPDepayloadPrivate));
123
124   gobject_class->finalize = gst_base_rtp_depayload_finalize;
125   gobject_class->set_property = gst_base_rtp_depayload_set_property;
126   gobject_class->get_property = gst_base_rtp_depayload_get_property;
127
128   /**
129    * GstBaseRTPDepayload::queue-delay
130    *
131    * Control the amount of packets to buffer.
132    *
133    * Deprecated: Use a jitterbuffer or RTP session manager to delay packet
134    * playback. This property has no effect anymore since 0.10.15.
135    */
136 #ifndef GST_REMOVE_DEPRECATED
137   g_object_class_install_property (gobject_class, PROP_QUEUE_DELAY,
138       g_param_spec_uint ("queue-delay", "Queue Delay",
139           "Amount of ms to queue/buffer, deprecated", 0, G_MAXUINT,
140           DEFAULT_QUEUE_DELAY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
141 #endif
142
143   gstelement_class->change_state = gst_base_rtp_depayload_change_state;
144
145   klass->set_gst_timestamp = gst_base_rtp_depayload_set_gst_timestamp;
146   klass->packet_lost = gst_base_rtp_depayload_packet_lost;
147   klass->handle_event = gst_base_rtp_depayload_handle_event;
148
149   GST_DEBUG_CATEGORY_INIT (basertpdepayload_debug, "basertpdepayload", 0,
150       "Base class for RTP Depayloaders");
151 }
152
153 static void
154 gst_base_rtp_depayload_init (GstBaseRTPDepayload * filter,
155     GstBaseRTPDepayloadClass * klass)
156 {
157   GstPadTemplate *pad_template;
158   GstBaseRTPDepayloadPrivate *priv;
159
160   priv = GST_BASE_RTP_DEPAYLOAD_GET_PRIVATE (filter);
161   filter->priv = priv;
162
163   GST_DEBUG_OBJECT (filter, "init");
164
165   pad_template =
166       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "sink");
167   g_return_if_fail (pad_template != NULL);
168   filter->sinkpad = gst_pad_new_from_template (pad_template, "sink");
169   gst_pad_set_setcaps_function (filter->sinkpad,
170       gst_base_rtp_depayload_setcaps);
171   gst_pad_set_chain_function (filter->sinkpad, gst_base_rtp_depayload_chain);
172   gst_pad_set_event_function (filter->sinkpad,
173       gst_base_rtp_depayload_handle_sink_event);
174   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
175
176   pad_template =
177       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "src");
178   g_return_if_fail (pad_template != NULL);
179   filter->srcpad = gst_pad_new_from_template (pad_template, "src");
180   gst_pad_use_fixed_caps (filter->srcpad);
181   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
182
183   filter->queue = g_queue_new ();
184   filter->queue_delay = DEFAULT_QUEUE_DELAY;
185
186   gst_segment_init (&filter->segment, GST_FORMAT_UNDEFINED);
187 }
188
189 static void
190 gst_base_rtp_depayload_finalize (GObject * object)
191 {
192   GstBaseRTPDepayload *filter = GST_BASE_RTP_DEPAYLOAD (object);
193
194   g_queue_free (filter->queue);
195
196   G_OBJECT_CLASS (parent_class)->finalize (object);
197 }
198
199 static gboolean
200 gst_base_rtp_depayload_setcaps (GstPad * pad, GstCaps * caps)
201 {
202   GstBaseRTPDepayload *filter;
203   GstBaseRTPDepayloadClass *bclass;
204   GstBaseRTPDepayloadPrivate *priv;
205   gboolean res;
206   GstStructure *caps_struct;
207   const GValue *value;
208
209   filter = GST_BASE_RTP_DEPAYLOAD (gst_pad_get_parent (pad));
210   priv = filter->priv;
211
212   bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter);
213
214   GST_DEBUG_OBJECT (filter, "Set caps");
215
216   caps_struct = gst_caps_get_structure (caps, 0);
217
218   /* get other values for newsegment */
219   value = gst_structure_get_value (caps_struct, "npt-start");
220   if (value && G_VALUE_HOLDS_UINT64 (value))
221     priv->npt_start = g_value_get_uint64 (value);
222   else
223     priv->npt_start = 0;
224   GST_DEBUG_OBJECT (filter, "NPT start %" G_GUINT64_FORMAT, priv->npt_start);
225
226   value = gst_structure_get_value (caps_struct, "npt-stop");
227   if (value && G_VALUE_HOLDS_UINT64 (value))
228     priv->npt_stop = g_value_get_uint64 (value);
229   else
230     priv->npt_stop = -1;
231
232   GST_DEBUG_OBJECT (filter, "NPT stop %" G_GUINT64_FORMAT, priv->npt_stop);
233
234   value = gst_structure_get_value (caps_struct, "play-speed");
235   if (value && G_VALUE_HOLDS_DOUBLE (value))
236     priv->play_speed = g_value_get_double (value);
237   else
238     priv->play_speed = 1.0;
239
240   value = gst_structure_get_value (caps_struct, "play-scale");
241   if (value && G_VALUE_HOLDS_DOUBLE (value))
242     priv->play_scale = g_value_get_double (value);
243   else
244     priv->play_scale = 1.0;
245
246   if (bclass->set_caps) {
247     res = bclass->set_caps (filter, caps);
248     if (!res) {
249       GST_WARNING_OBJECT (filter, "Subclass rejected caps %" GST_PTR_FORMAT,
250           caps);
251     }
252   } else {
253     res = TRUE;
254   }
255
256   priv->negotiated = res;
257
258   gst_object_unref (filter);
259
260   return res;
261 }
262
263 static GstFlowReturn
264 gst_base_rtp_depayload_chain (GstPad * pad, GstBuffer * in)
265 {
266   GstBaseRTPDepayload *filter;
267   GstBaseRTPDepayloadPrivate *priv;
268   GstBaseRTPDepayloadClass *bclass;
269   GstFlowReturn ret = GST_FLOW_OK;
270   GstBuffer *out_buf;
271   GstClockTime timestamp;
272   guint16 seqnum;
273   guint32 rtptime;
274   gboolean discont;
275   gint gap;
276
277   filter = GST_BASE_RTP_DEPAYLOAD (GST_OBJECT_PARENT (pad));
278   priv = filter->priv;
279
280   /* we must have a setcaps first */
281   if (G_UNLIKELY (!priv->negotiated))
282     goto not_negotiated;
283
284   /* we must validate, it's possible that this element is plugged right after a
285    * network receiver and we don't want to operate on invalid data */
286   if (G_UNLIKELY (!gst_rtp_buffer_validate (in)))
287     goto invalid_buffer;
288
289   if (!priv->discont)
290     priv->discont = GST_BUFFER_IS_DISCONT (in);
291
292   timestamp = GST_BUFFER_TIMESTAMP (in);
293   /* convert to running_time and save the timestamp, this is the timestamp
294    * we put on outgoing buffers. */
295   timestamp = gst_segment_to_running_time (&filter->segment, GST_FORMAT_TIME,
296       timestamp);
297   priv->timestamp = timestamp;
298   priv->duration = GST_BUFFER_DURATION (in);
299
300   seqnum = gst_rtp_buffer_get_seq (in);
301   rtptime = gst_rtp_buffer_get_timestamp (in);
302   discont = FALSE;
303
304   GST_LOG_OBJECT (filter, "discont %d, seqnum %u, rtptime %u, timestamp %"
305       GST_TIME_FORMAT, priv->discont, seqnum, rtptime,
306       GST_TIME_ARGS (timestamp));
307
308   /* Check seqnum. This is a very simple check that makes sure that the seqnums
309    * are striclty increasing, dropping anything that is out of the ordinary. We
310    * can only do this when the next_seqnum is known. */
311   if (G_LIKELY (priv->next_seqnum != -1)) {
312     gap = gst_rtp_buffer_compare_seqnum (seqnum, priv->next_seqnum);
313
314     /* if we have no gap, all is fine */
315     if (G_UNLIKELY (gap != 0)) {
316       GST_LOG_OBJECT (filter, "got packet %u, expected %u, gap %d", seqnum,
317           priv->next_seqnum, gap);
318       if (gap < 0) {
319         /* seqnum > next_seqnum, we are missing some packets, this is always a
320          * DISCONT. */
321         GST_LOG_OBJECT (filter, "%d missing packets", gap);
322         discont = TRUE;
323       } else {
324         /* seqnum < next_seqnum, we have seen this packet before or the sender
325          * could be restarted. If the packet is not too old, we throw it away as
326          * a duplicate, otherwise we mark discont and continue. 100 misordered
327          * packets is a good threshold. See also RFC 4737. */
328         if (gap < 100)
329           goto dropping;
330
331         GST_LOG_OBJECT (filter,
332             "%d > 100, packet too old, sender likely restarted", gap);
333         discont = TRUE;
334       }
335     }
336   }
337   priv->next_seqnum = (seqnum + 1) & 0xffff;
338
339   if (G_UNLIKELY (discont && !priv->discont)) {
340     GST_LOG_OBJECT (filter, "mark DISCONT on input buffer");
341     /* we detected a seqnum discont but the buffer was not flagged with a discont,
342      * set the discont flag so that the subclass can throw away old data. */
343     priv->discont = TRUE;
344     in = gst_buffer_make_metadata_writable (in);
345     GST_BUFFER_FLAG_SET (in, GST_BUFFER_FLAG_DISCONT);
346   }
347
348   bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter);
349
350   if (G_UNLIKELY (bclass->process == NULL))
351     goto no_process;
352
353   /* let's send it out to processing */
354   out_buf = bclass->process (filter, in);
355   if (out_buf) {
356     /* we pass rtptime as backward compatibility, in reality, the incomming
357      * buffer timestamp is always applied to the outgoing packet. */
358     ret = gst_base_rtp_depayload_push_ts (filter, rtptime, out_buf);
359   }
360   gst_buffer_unref (in);
361
362   return ret;
363
364   /* ERRORS */
365 not_negotiated:
366   {
367     /* this is not fatal but should be filtered earlier */
368     if (GST_BUFFER_CAPS (in) == NULL) {
369       GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION,
370           ("No RTP format was negotiated."),
371           ("Input buffers need to have RTP caps set on them. This is usually "
372               "achieved by setting the 'caps' property of the upstream source "
373               "element (often udpsrc or appsrc), or by putting a capsfilter "
374               "element before the depayloader and setting the 'caps' property "
375               "on that. Also see http://cgit.freedesktop.org/gstreamer/"
376               "gst-plugins-good/tree/gst/rtp/README"));
377     } else {
378       GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION,
379           ("No RTP format was negotiated."),
380           ("RTP caps on input buffer were rejected, most likely because they "
381               "were incomplete or contained wrong values. Check the debug log "
382               "for more information."));
383     }
384     gst_buffer_unref (in);
385     return GST_FLOW_NOT_NEGOTIATED;
386   }
387 invalid_buffer:
388   {
389     /* this is not fatal but should be filtered earlier */
390     GST_ELEMENT_WARNING (filter, STREAM, DECODE, (NULL),
391         ("Received invalid RTP payload, dropping"));
392     gst_buffer_unref (in);
393     return GST_FLOW_OK;
394   }
395 dropping:
396   {
397     GST_WARNING_OBJECT (filter, "%d <= 100, dropping old packet", gap);
398     gst_buffer_unref (in);
399     return GST_FLOW_OK;
400   }
401 no_process:
402   {
403     /* this is not fatal but should be filtered earlier */
404     GST_ELEMENT_ERROR (filter, STREAM, NOT_IMPLEMENTED, (NULL),
405         ("The subclass does not have a process method"));
406     gst_buffer_unref (in);
407     return GST_FLOW_ERROR;
408   }
409 }
410
411 static gboolean
412 gst_base_rtp_depayload_handle_event (GstBaseRTPDepayload * filter,
413     GstEvent * event)
414 {
415   gboolean res = TRUE;
416   gboolean forward = TRUE;
417
418   switch (GST_EVENT_TYPE (event)) {
419     case GST_EVENT_FLUSH_STOP:
420       gst_segment_init (&filter->segment, GST_FORMAT_UNDEFINED);
421       filter->need_newsegment = TRUE;
422       filter->priv->next_seqnum = -1;
423       break;
424     case GST_EVENT_NEWSEGMENT:
425     {
426       gboolean update;
427       gdouble rate;
428       GstFormat fmt;
429       gint64 start, stop, position;
430
431       gst_event_parse_new_segment (event, &update, &rate, &fmt, &start, &stop,
432           &position);
433
434       gst_segment_set_newsegment (&filter->segment, update, rate, fmt,
435           start, stop, position);
436
437       /* don't pass the event downstream, we generate our own segment including
438        * the NTP time and other things we receive in caps */
439       forward = FALSE;
440       break;
441     }
442     case GST_EVENT_CUSTOM_DOWNSTREAM:
443     {
444       GstBaseRTPDepayloadClass *bclass;
445
446       bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter);
447
448       if (gst_event_has_name (event, "GstRTPPacketLost")) {
449         /* we get this event from the jitterbuffer when it considers a packet as
450          * being lost. We send it to our packet_lost vmethod. The default
451          * implementation will make time progress by pushing out a NEWSEGMENT
452          * update event. Subclasses can override and to one of the following:
453          *  - Adjust timestamp/duration to something more accurate before
454          *    calling the parent (default) packet_lost method.
455          *  - do some more advanced error concealing on the already received
456          *    (fragmented) packets.
457          *  - ignore the packet lost.
458          */
459         if (bclass->packet_lost)
460           res = bclass->packet_lost (filter, event);
461         forward = FALSE;
462       }
463       break;
464     }
465     default:
466       break;
467   }
468
469   if (forward)
470     res = gst_pad_push_event (filter->srcpad, event);
471   else
472     gst_event_unref (event);
473
474   return res;
475 }
476
477 static gboolean
478 gst_base_rtp_depayload_handle_sink_event (GstPad * pad, GstEvent * event)
479 {
480   gboolean res = FALSE;
481   GstBaseRTPDepayload *filter;
482   GstBaseRTPDepayloadClass *bclass;
483
484   filter = GST_BASE_RTP_DEPAYLOAD (gst_pad_get_parent (pad));
485   if (G_UNLIKELY (filter == NULL)) {
486     gst_event_unref (event);
487     return FALSE;
488   }
489
490   bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter);
491   if (bclass->handle_event)
492     res = bclass->handle_event (filter, event);
493   else
494     gst_event_unref (event);
495
496   gst_object_unref (filter);
497   return res;
498 }
499
500 static GstEvent *
501 create_segment_event (GstBaseRTPDepayload * filter, gboolean update,
502     GstClockTime position)
503 {
504   GstEvent *event;
505   GstClockTime stop;
506   GstBaseRTPDepayloadPrivate *priv;
507
508   priv = filter->priv;
509
510   if (priv->npt_stop != -1)
511     stop = priv->npt_stop - priv->npt_start;
512   else
513     stop = -1;
514
515   event = gst_event_new_new_segment_full (update, priv->play_speed,
516       priv->play_scale, GST_FORMAT_TIME, position, stop,
517       position + priv->npt_start);
518
519   return event;
520 }
521
522 typedef struct
523 {
524   GstBaseRTPDepayload *depayload;
525   GstBaseRTPDepayloadClass *bclass;
526   GstCaps *caps;
527   gboolean do_ts;
528   gboolean rtptime;
529 } HeaderData;
530
531 static GstBufferListItem
532 set_headers (GstBuffer ** buffer, guint group, guint idx, HeaderData * data)
533 {
534   GstBaseRTPDepayload *depayload = data->depayload;
535
536   *buffer = gst_buffer_make_metadata_writable (*buffer);
537   gst_buffer_set_caps (*buffer, data->caps);
538
539   /* set the timestamp if we must and can */
540   if (data->bclass->set_gst_timestamp && data->do_ts)
541     data->bclass->set_gst_timestamp (depayload, data->rtptime, *buffer);
542
543   if (G_UNLIKELY (depayload->priv->discont)) {
544     GST_LOG_OBJECT (depayload, "Marking DISCONT on output buffer");
545     GST_BUFFER_FLAG_SET (*buffer, GST_BUFFER_FLAG_DISCONT);
546     depayload->priv->discont = FALSE;
547   }
548
549   return GST_BUFFER_LIST_SKIP_GROUP;
550 }
551
552 static GstFlowReturn
553 gst_base_rtp_depayload_prepare_push (GstBaseRTPDepayload * filter,
554     gboolean do_ts, guint32 rtptime, gboolean is_list, gpointer obj)
555 {
556   HeaderData data;
557
558   data.depayload = filter;
559   data.caps = GST_PAD_CAPS (filter->srcpad);
560   data.rtptime = rtptime;
561   data.do_ts = do_ts;
562   data.bclass = GST_BASE_RTP_DEPAYLOAD_GET_CLASS (filter);
563
564   if (is_list) {
565     GstBufferList **blist = obj;
566     gst_buffer_list_foreach (*blist, (GstBufferListFunc) set_headers, &data);
567   } else {
568     GstBuffer **buf = obj;
569     set_headers (buf, 0, 0, &data);
570   }
571
572   /* if this is the first buffer send a NEWSEGMENT */
573   if (G_UNLIKELY (filter->need_newsegment)) {
574     GstEvent *event;
575
576     event = create_segment_event (filter, FALSE, 0);
577
578     gst_pad_push_event (filter->srcpad, event);
579
580     filter->need_newsegment = FALSE;
581     GST_DEBUG_OBJECT (filter, "Pushed newsegment event on this first buffer");
582   }
583
584   return GST_FLOW_OK;
585 }
586
587 /**
588  * gst_base_rtp_depayload_push_ts:
589  * @filter: a #GstBaseRTPDepayload
590  * @timestamp: an RTP timestamp to apply
591  * @out_buf: a #GstBuffer
592  *
593  * Push @out_buf to the peer of @filter. This function takes ownership of
594  * @out_buf.
595  *
596  * Unlike gst_base_rtp_depayload_push(), this function will by default apply
597  * the last incomming timestamp on the outgoing buffer when it didn't have a
598  * timestamp already. The set_get_timestamp vmethod can be overwritten to change
599  * this behaviour (and take, for example, @timestamp into account).
600  *
601  * Returns: a #GstFlowReturn.
602  */
603 GstFlowReturn
604 gst_base_rtp_depayload_push_ts (GstBaseRTPDepayload * filter, guint32 timestamp,
605     GstBuffer * out_buf)
606 {
607   GstFlowReturn res;
608
609   res =
610       gst_base_rtp_depayload_prepare_push (filter, TRUE, timestamp, FALSE,
611       &out_buf);
612
613   if (G_LIKELY (res == GST_FLOW_OK))
614     res = gst_pad_push (filter->srcpad, out_buf);
615   else
616     gst_buffer_unref (out_buf);
617
618   return res;
619 }
620
621 /**
622  * gst_base_rtp_depayload_push:
623  * @filter: a #GstBaseRTPDepayload
624  * @out_buf: a #GstBuffer
625  *
626  * Push @out_buf to the peer of @filter. This function takes ownership of
627  * @out_buf.
628  *
629  * Unlike gst_base_rtp_depayload_push_ts(), this function will not apply
630  * any timestamp on the outgoing buffer. Subclasses should therefore timestamp
631  * outgoing buffers themselves.
632  *
633  * Returns: a #GstFlowReturn.
634  */
635 GstFlowReturn
636 gst_base_rtp_depayload_push (GstBaseRTPDepayload * filter, GstBuffer * out_buf)
637 {
638   GstFlowReturn res;
639
640   res = gst_base_rtp_depayload_prepare_push (filter, FALSE, 0, FALSE, &out_buf);
641
642   if (G_LIKELY (res == GST_FLOW_OK))
643     res = gst_pad_push (filter->srcpad, out_buf);
644   else
645     gst_buffer_unref (out_buf);
646
647   return res;
648 }
649
650 /**
651  * gst_base_rtp_depayload_push_list:
652  * @filter: a #GstBaseRTPDepayload
653  * @out_list: a #GstBufferList
654  *
655  * Push @out_list to the peer of @filter. This function takes ownership of
656  * @out_list.
657  *
658  * Returns: a #GstFlowReturn.
659  *
660  * Since: 0.10.32
661  */
662 GstFlowReturn
663 gst_base_rtp_depayload_push_list (GstBaseRTPDepayload * filter,
664     GstBufferList * out_list)
665 {
666   GstFlowReturn res;
667
668   res = gst_base_rtp_depayload_prepare_push (filter, TRUE, 0, TRUE, &out_list);
669
670   if (G_LIKELY (res == GST_FLOW_OK))
671     res = gst_pad_push_list (filter->srcpad, out_list);
672   else
673     gst_buffer_list_unref (out_list);
674
675   return res;
676 }
677
678 /* convert the PacketLost event form a jitterbuffer to a segment update.
679  * subclasses can override this.  */
680 static gboolean
681 gst_base_rtp_depayload_packet_lost (GstBaseRTPDepayload * filter,
682     GstEvent * event)
683 {
684   GstClockTime timestamp, duration, position;
685   GstEvent *sevent;
686   const GstStructure *s;
687
688   s = gst_event_get_structure (event);
689
690   /* first start by parsing the timestamp and duration */
691   timestamp = -1;
692   duration = -1;
693
694   gst_structure_get_clock_time (s, "timestamp", &timestamp);
695   gst_structure_get_clock_time (s, "duration", &duration);
696
697   position = timestamp;
698   if (duration != -1)
699     position += duration;
700
701   /* update the current segment with the elapsed time */
702   sevent = create_segment_event (filter, TRUE, position);
703
704   return gst_pad_push_event (filter->srcpad, sevent);
705 }
706
707 static void
708 gst_base_rtp_depayload_set_gst_timestamp (GstBaseRTPDepayload * filter,
709     guint32 rtptime, GstBuffer * buf)
710 {
711   GstBaseRTPDepayloadPrivate *priv;
712   GstClockTime timestamp, duration;
713
714   priv = filter->priv;
715
716   timestamp = GST_BUFFER_TIMESTAMP (buf);
717   duration = GST_BUFFER_DURATION (buf);
718
719   /* apply last incomming timestamp and duration to outgoing buffer if
720    * not otherwise set. */
721   if (!GST_CLOCK_TIME_IS_VALID (timestamp))
722     GST_BUFFER_TIMESTAMP (buf) = priv->timestamp;
723   if (!GST_CLOCK_TIME_IS_VALID (duration))
724     GST_BUFFER_DURATION (buf) = priv->duration;
725 }
726
727 static GstStateChangeReturn
728 gst_base_rtp_depayload_change_state (GstElement * element,
729     GstStateChange transition)
730 {
731   GstBaseRTPDepayload *filter;
732   GstBaseRTPDepayloadPrivate *priv;
733   GstStateChangeReturn ret;
734
735   filter = GST_BASE_RTP_DEPAYLOAD (element);
736   priv = filter->priv;
737
738   switch (transition) {
739     case GST_STATE_CHANGE_NULL_TO_READY:
740       break;
741     case GST_STATE_CHANGE_READY_TO_PAUSED:
742       filter->need_newsegment = TRUE;
743       priv->npt_start = 0;
744       priv->npt_stop = -1;
745       priv->play_speed = 1.0;
746       priv->play_scale = 1.0;
747       priv->next_seqnum = -1;
748       priv->negotiated = FALSE;
749       priv->discont = FALSE;
750       break;
751     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
752       break;
753     default:
754       break;
755   }
756
757   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
758
759   switch (transition) {
760     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
761       break;
762     case GST_STATE_CHANGE_PAUSED_TO_READY:
763       break;
764     case GST_STATE_CHANGE_READY_TO_NULL:
765       break;
766     default:
767       break;
768   }
769   return ret;
770 }
771
772 static void
773 gst_base_rtp_depayload_set_property (GObject * object, guint prop_id,
774     const GValue * value, GParamSpec * pspec)
775 {
776   GstBaseRTPDepayload *filter;
777
778   filter = GST_BASE_RTP_DEPAYLOAD (object);
779
780   switch (prop_id) {
781     case PROP_QUEUE_DELAY:
782       filter->queue_delay = g_value_get_uint (value);
783       break;
784     default:
785       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
786       break;
787   }
788 }
789
790 static void
791 gst_base_rtp_depayload_get_property (GObject * object, guint prop_id,
792     GValue * value, GParamSpec * pspec)
793 {
794   GstBaseRTPDepayload *filter;
795
796   filter = GST_BASE_RTP_DEPAYLOAD (object);
797
798   switch (prop_id) {
799     case PROP_QUEUE_DELAY:
800       g_value_set_uint (value, filter->queue_delay);
801       break;
802     default:
803       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
804       break;
805   }
806 }