rtpbasedepayload: fix leaks in error code paths
[platform/upstream/gst-plugins-base.git] / gst-libs / gst / rtp / gstrtpbasedepayload.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., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 /**
22  * SECTION:gstrtpbasedepayload
23  * @short_description: Base class for RTP depayloader
24  *
25  * Provides a base class for RTP depayloaders
26  */
27
28 #include "gstrtpbasedepayload.h"
29
30 GST_DEBUG_CATEGORY_STATIC (rtpbasedepayload_debug);
31 #define GST_CAT_DEFAULT (rtpbasedepayload_debug)
32
33 #define GST_RTP_BASE_DEPAYLOAD_GET_PRIVATE(obj)  \
34    (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_RTP_BASE_DEPAYLOAD, GstRTPBaseDepayloadPrivate))
35
36 struct _GstRTPBaseDepayloadPrivate
37 {
38   GstClockTime npt_start;
39   GstClockTime npt_stop;
40   gdouble play_speed;
41   gdouble play_scale;
42   guint clock_base;
43
44   gboolean discont;
45   GstClockTime pts;
46   GstClockTime dts;
47   GstClockTime duration;
48
49   guint32 last_seqnum;
50   guint32 last_rtptime;
51   guint32 next_seqnum;
52
53   gboolean negotiated;
54
55   GstCaps *last_caps;
56   GstEvent *segment_event;
57 };
58
59 /* Filter signals and args */
60 enum
61 {
62   /* FILL ME */
63   LAST_SIGNAL
64 };
65
66 enum
67 {
68   PROP_0,
69   PROP_STATS,
70   PROP_LAST
71 };
72
73 static void gst_rtp_base_depayload_finalize (GObject * object);
74 static void gst_rtp_base_depayload_set_property (GObject * object,
75     guint prop_id, const GValue * value, GParamSpec * pspec);
76 static void gst_rtp_base_depayload_get_property (GObject * object,
77     guint prop_id, GValue * value, GParamSpec * pspec);
78
79 static GstFlowReturn gst_rtp_base_depayload_chain (GstPad * pad,
80     GstObject * parent, GstBuffer * in);
81 static GstFlowReturn gst_rtp_base_depayload_chain_list (GstPad * pad,
82     GstObject * parent, GstBufferList * list);
83 static gboolean gst_rtp_base_depayload_handle_sink_event (GstPad * pad,
84     GstObject * parent, GstEvent * event);
85
86 static GstStateChangeReturn gst_rtp_base_depayload_change_state (GstElement *
87     element, GstStateChange transition);
88
89 static gboolean gst_rtp_base_depayload_packet_lost (GstRTPBaseDepayload *
90     filter, GstEvent * event);
91 static gboolean gst_rtp_base_depayload_handle_event (GstRTPBaseDepayload *
92     filter, GstEvent * event);
93
94 static GstElementClass *parent_class = NULL;
95 static void gst_rtp_base_depayload_class_init (GstRTPBaseDepayloadClass *
96     klass);
97 static void gst_rtp_base_depayload_init (GstRTPBaseDepayload * rtpbasepayload,
98     GstRTPBaseDepayloadClass * klass);
99 static GstEvent *create_segment_event (GstRTPBaseDepayload * filter,
100     guint rtptime, GstClockTime position);
101
102 GType
103 gst_rtp_base_depayload_get_type (void)
104 {
105   static GType rtp_base_depayload_type = 0;
106
107   if (g_once_init_enter ((gsize *) & rtp_base_depayload_type)) {
108     static const GTypeInfo rtp_base_depayload_info = {
109       sizeof (GstRTPBaseDepayloadClass),
110       NULL,
111       NULL,
112       (GClassInitFunc) gst_rtp_base_depayload_class_init,
113       NULL,
114       NULL,
115       sizeof (GstRTPBaseDepayload),
116       0,
117       (GInstanceInitFunc) gst_rtp_base_depayload_init,
118     };
119
120     g_once_init_leave ((gsize *) & rtp_base_depayload_type,
121         g_type_register_static (GST_TYPE_ELEMENT, "GstRTPBaseDepayload",
122             &rtp_base_depayload_info, G_TYPE_FLAG_ABSTRACT));
123   }
124   return rtp_base_depayload_type;
125 }
126
127 static void
128 gst_rtp_base_depayload_class_init (GstRTPBaseDepayloadClass * klass)
129 {
130   GObjectClass *gobject_class;
131   GstElementClass *gstelement_class;
132
133   gobject_class = G_OBJECT_CLASS (klass);
134   gstelement_class = (GstElementClass *) klass;
135   parent_class = g_type_class_peek_parent (klass);
136
137   g_type_class_add_private (klass, sizeof (GstRTPBaseDepayloadPrivate));
138
139   gobject_class->finalize = gst_rtp_base_depayload_finalize;
140   gobject_class->set_property = gst_rtp_base_depayload_set_property;
141   gobject_class->get_property = gst_rtp_base_depayload_get_property;
142
143
144   /**
145    * GstRTPBaseDepayload:stats:
146    *
147    * Various depayloader statistics retrieved atomically (and are therefore
148    * synchroized with each other). This property return a GstStructure named
149    * application/x-rtp-depayload-stats containing the following fields relating to
150    * the last processed buffer and current state of the stream being depayloaded:
151    *
152    * <variablelist>
153    *   <varlistentry>
154    *     <term>clock-rate</term>
155    *     <listitem><para>#G_TYPE_UINT, clock-rate of the
156    *     stream</para></listitem>
157    *   </varlistentry>
158    *   <varlistentry>
159    *     <term>npt-start</term>
160    *     <listitem><para>#G_TYPE_UINT64, time of playback start
161    *     </para></listitem>
162    *   </varlistentry>
163    *   <varlistentry>
164    *     <term>npt-stop</term>
165    *     <listitem><para>#G_TYPE_UINT64, time of playback stop
166    *     </para></listitem>
167    *   </varlistentry>
168    *   <varlistentry>
169    *     <term>play-speed</term>
170    *     <listitem><para>#G_TYPE_DOUBLE, the playback speed
171    *     </para></listitem>
172    *   </varlistentry>
173    *   <varlistentry>
174    *     <term>play-scale</term>
175    *     <listitem><para>#G_TYPE_DOUBLE, the playback scale
176    *     </para></listitem>
177    *   </varlistentry>
178    *   <varlistentry>
179    *     <term>running-time-dts</term>
180    *     <listitem><para>#G_TYPE_UINT64, the last running-time of the
181    *      last DTS
182    *     </para></listitem>
183    *   </varlistentry>
184    *   <varlistentry>
185    *     <term>running-time-pts</term>
186    *     <listitem><para>#G_TYPE_UINT64, the last running-time of the
187    *      last PTS
188    *     </para></listitem>
189    *   </varlistentry>
190    *   <varlistentry>
191    *     <term>seqnum</term>
192    *     <listitem><para>#G_TYPE_UINT, the last seen seqnum
193    *     </para></listitem>
194    *   </varlistentry>
195    *   <varlistentry>
196    *     <term>timestamp</term>
197    *     <listitem><para>#G_TYPE_UINT, the last seen RTP timestamp
198    *     </para></listitem>
199    *   </varlistentry>
200    * </variablelist>
201    **/
202   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_STATS,
203       g_param_spec_boxed ("stats", "Statistics", "Various statistics",
204           GST_TYPE_STRUCTURE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
205
206   gstelement_class->change_state = gst_rtp_base_depayload_change_state;
207
208   klass->packet_lost = gst_rtp_base_depayload_packet_lost;
209   klass->handle_event = gst_rtp_base_depayload_handle_event;
210
211   GST_DEBUG_CATEGORY_INIT (rtpbasedepayload_debug, "rtpbasedepayload", 0,
212       "Base class for RTP Depayloaders");
213 }
214
215 static void
216 gst_rtp_base_depayload_init (GstRTPBaseDepayload * filter,
217     GstRTPBaseDepayloadClass * klass)
218 {
219   GstPadTemplate *pad_template;
220   GstRTPBaseDepayloadPrivate *priv;
221
222   priv = GST_RTP_BASE_DEPAYLOAD_GET_PRIVATE (filter);
223   filter->priv = priv;
224
225   GST_DEBUG_OBJECT (filter, "init");
226
227   pad_template =
228       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "sink");
229   g_return_if_fail (pad_template != NULL);
230   filter->sinkpad = gst_pad_new_from_template (pad_template, "sink");
231   gst_pad_set_chain_function (filter->sinkpad, gst_rtp_base_depayload_chain);
232   gst_pad_set_chain_list_function (filter->sinkpad,
233       gst_rtp_base_depayload_chain_list);
234   gst_pad_set_event_function (filter->sinkpad,
235       gst_rtp_base_depayload_handle_sink_event);
236   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
237
238   pad_template =
239       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "src");
240   g_return_if_fail (pad_template != NULL);
241   filter->srcpad = gst_pad_new_from_template (pad_template, "src");
242   gst_pad_use_fixed_caps (filter->srcpad);
243   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
244
245   priv->npt_start = 0;
246   priv->npt_stop = -1;
247   priv->play_speed = 1.0;
248   priv->play_scale = 1.0;
249   priv->clock_base = -1;
250   priv->dts = -1;
251   priv->pts = -1;
252   priv->duration = -1;
253
254   gst_segment_init (&filter->segment, GST_FORMAT_UNDEFINED);
255 }
256
257 static void
258 gst_rtp_base_depayload_finalize (GObject * object)
259 {
260   G_OBJECT_CLASS (parent_class)->finalize (object);
261 }
262
263 static gboolean
264 gst_rtp_base_depayload_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps)
265 {
266   GstRTPBaseDepayloadClass *bclass;
267   GstRTPBaseDepayloadPrivate *priv;
268   gboolean res;
269   GstStructure *caps_struct;
270   const GValue *value;
271
272   priv = filter->priv;
273
274   bclass = GST_RTP_BASE_DEPAYLOAD_GET_CLASS (filter);
275
276   GST_DEBUG_OBJECT (filter, "Set caps %" GST_PTR_FORMAT, caps);
277
278   if (priv->last_caps) {
279     if (gst_caps_is_equal (priv->last_caps, caps)) {
280       res = TRUE;
281       goto caps_not_changed;
282     } else {
283       gst_caps_unref (priv->last_caps);
284       priv->last_caps = NULL;
285     }
286   }
287
288   caps_struct = gst_caps_get_structure (caps, 0);
289
290   /* get other values for newsegment */
291   value = gst_structure_get_value (caps_struct, "npt-start");
292   if (value && G_VALUE_HOLDS_UINT64 (value))
293     priv->npt_start = g_value_get_uint64 (value);
294   else
295     priv->npt_start = 0;
296   GST_DEBUG_OBJECT (filter, "NPT start %" G_GUINT64_FORMAT, priv->npt_start);
297
298   value = gst_structure_get_value (caps_struct, "npt-stop");
299   if (value && G_VALUE_HOLDS_UINT64 (value))
300     priv->npt_stop = g_value_get_uint64 (value);
301   else
302     priv->npt_stop = -1;
303
304   GST_DEBUG_OBJECT (filter, "NPT stop %" G_GUINT64_FORMAT, priv->npt_stop);
305
306   value = gst_structure_get_value (caps_struct, "play-speed");
307   if (value && G_VALUE_HOLDS_DOUBLE (value))
308     priv->play_speed = g_value_get_double (value);
309   else
310     priv->play_speed = 1.0;
311
312   value = gst_structure_get_value (caps_struct, "play-scale");
313   if (value && G_VALUE_HOLDS_DOUBLE (value))
314     priv->play_scale = g_value_get_double (value);
315   else
316     priv->play_scale = 1.0;
317
318   value = gst_structure_get_value (caps_struct, "clock-base");
319   if (value && G_VALUE_HOLDS_UINT (value))
320     priv->clock_base = g_value_get_uint (value);
321   else
322     priv->clock_base = -1;
323
324   if (bclass->set_caps) {
325     res = bclass->set_caps (filter, caps);
326     if (!res) {
327       GST_WARNING_OBJECT (filter, "Subclass rejected caps %" GST_PTR_FORMAT,
328           caps);
329     }
330   } else {
331     res = TRUE;
332   }
333
334   priv->negotiated = res;
335
336   if (priv->negotiated)
337     priv->last_caps = gst_caps_ref (caps);
338
339   return res;
340
341 caps_not_changed:
342   {
343     GST_DEBUG_OBJECT (filter, "Caps did not change");
344     return res;
345   }
346 }
347
348 static GstFlowReturn
349 gst_rtp_base_depayload_handle_buffer (GstRTPBaseDepayload * filter,
350     GstRTPBaseDepayloadClass * bclass, GstBuffer * in)
351 {
352   GstBuffer *(*process_rtp_packet_func) (GstRTPBaseDepayload * base,
353       GstRTPBuffer * rtp_buffer);
354   GstBuffer *(*process_func) (GstRTPBaseDepayload * base, GstBuffer * in);
355   GstRTPBaseDepayloadPrivate *priv;
356   GstFlowReturn ret = GST_FLOW_OK;
357   GstBuffer *out_buf;
358   GstClockTime pts, dts;
359   guint16 seqnum;
360   guint32 rtptime;
361   gboolean discont, buf_discont;
362   gint gap;
363   GstRTPBuffer rtp = { NULL };
364
365   priv = filter->priv;
366
367   process_func = bclass->process;
368   process_rtp_packet_func = bclass->process_rtp_packet;
369
370   /* we must have a setcaps first */
371   if (G_UNLIKELY (!priv->negotiated))
372     goto not_negotiated;
373
374   if (G_UNLIKELY (!gst_rtp_buffer_map (in, GST_MAP_READ, &rtp)))
375     goto invalid_buffer;
376
377   buf_discont = GST_BUFFER_IS_DISCONT (in);
378
379   pts = GST_BUFFER_PTS (in);
380   dts = GST_BUFFER_DTS (in);
381   /* convert to running_time and save the timestamp, this is the timestamp
382    * we put on outgoing buffers. */
383   pts = gst_segment_to_running_time (&filter->segment, GST_FORMAT_TIME, pts);
384   dts = gst_segment_to_running_time (&filter->segment, GST_FORMAT_TIME, dts);
385   priv->pts = pts;
386   priv->dts = dts;
387   priv->duration = GST_BUFFER_DURATION (in);
388
389   seqnum = gst_rtp_buffer_get_seq (&rtp);
390   rtptime = gst_rtp_buffer_get_timestamp (&rtp);
391
392   priv->last_seqnum = seqnum;
393   priv->last_rtptime = rtptime;
394
395   discont = buf_discont;
396
397   GST_LOG_OBJECT (filter, "discont %d, seqnum %u, rtptime %u, pts %"
398       GST_TIME_FORMAT ", dts %" GST_TIME_FORMAT, buf_discont, seqnum, rtptime,
399       GST_TIME_ARGS (pts), GST_TIME_ARGS (dts));
400
401   /* Check seqnum. This is a very simple check that makes sure that the seqnums
402    * are strictly increasing, dropping anything that is out of the ordinary. We
403    * can only do this when the next_seqnum is known. */
404   if (G_LIKELY (priv->next_seqnum != -1)) {
405     gap = gst_rtp_buffer_compare_seqnum (seqnum, priv->next_seqnum);
406
407     /* if we have no gap, all is fine */
408     if (G_UNLIKELY (gap != 0)) {
409       GST_LOG_OBJECT (filter, "got packet %u, expected %u, gap %d", seqnum,
410           priv->next_seqnum, gap);
411       if (gap < 0) {
412         /* seqnum > next_seqnum, we are missing some packets, this is always a
413          * DISCONT. */
414         GST_LOG_OBJECT (filter, "%d missing packets", gap);
415         discont = TRUE;
416       } else {
417         /* seqnum < next_seqnum, we have seen this packet before or the sender
418          * could be restarted. If the packet is not too old, we throw it away as
419          * a duplicate, otherwise we mark discont and continue. 100 misordered
420          * packets is a good threshold. See also RFC 4737. */
421         if (gap < 100)
422           goto dropping;
423
424         GST_LOG_OBJECT (filter,
425             "%d > 100, packet too old, sender likely restarted", gap);
426         discont = TRUE;
427       }
428     }
429   }
430   priv->next_seqnum = (seqnum + 1) & 0xffff;
431
432   if (G_UNLIKELY (discont)) {
433     priv->discont = TRUE;
434     if (!buf_discont) {
435       /* we detected a seqnum discont but the buffer was not flagged with a discont,
436        * set the discont flag so that the subclass can throw away old data. */
437       GST_LOG_OBJECT (filter, "mark DISCONT on input buffer");
438       in = gst_buffer_make_writable (in);
439       GST_BUFFER_FLAG_SET (in, GST_BUFFER_FLAG_DISCONT);
440     }
441   }
442
443   /* prepare segment event if needed */
444   if (filter->need_newsegment) {
445     priv->segment_event = create_segment_event (filter, rtptime,
446         GST_BUFFER_PTS (in));
447     filter->need_newsegment = FALSE;
448   }
449
450   if (process_rtp_packet_func != NULL) {
451     out_buf = process_rtp_packet_func (filter, &rtp);
452     gst_rtp_buffer_unmap (&rtp);
453   } else if (process_func != NULL) {
454     gst_rtp_buffer_unmap (&rtp);
455     out_buf = process_func (filter, in);
456   } else {
457     goto no_process;
458   }
459
460   /* let's send it out to processing */
461   if (out_buf) {
462     ret = gst_rtp_base_depayload_push (filter, out_buf);
463   }
464
465   return ret;
466
467   /* ERRORS */
468 not_negotiated:
469   {
470     /* this is not fatal but should be filtered earlier */
471     GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION,
472         ("No RTP format was negotiated."),
473         ("Input buffers need to have RTP caps set on them. This is usually "
474             "achieved by setting the 'caps' property of the upstream source "
475             "element (often udpsrc or appsrc), or by putting a capsfilter "
476             "element before the depayloader and setting the 'caps' property "
477             "on that. Also see http://cgit.freedesktop.org/gstreamer/"
478             "gst-plugins-good/tree/gst/rtp/README"));
479     return GST_FLOW_NOT_NEGOTIATED;
480   }
481 invalid_buffer:
482   {
483     /* this is not fatal but should be filtered earlier */
484     GST_ELEMENT_WARNING (filter, STREAM, DECODE, (NULL),
485         ("Received invalid RTP payload, dropping"));
486     return GST_FLOW_OK;
487   }
488 dropping:
489   {
490     gst_rtp_buffer_unmap (&rtp);
491     GST_WARNING_OBJECT (filter, "%d <= 100, dropping old packet", gap);
492     return GST_FLOW_OK;
493   }
494 no_process:
495   {
496     gst_rtp_buffer_unmap (&rtp);
497     /* this is not fatal but should be filtered earlier */
498     GST_ELEMENT_ERROR (filter, STREAM, NOT_IMPLEMENTED, (NULL),
499         ("The subclass does not have a process or process_rtp_packet method"));
500     return GST_FLOW_ERROR;
501   }
502 }
503
504 static GstFlowReturn
505 gst_rtp_base_depayload_chain (GstPad * pad, GstObject * parent, GstBuffer * in)
506 {
507   GstRTPBaseDepayloadClass *bclass;
508   GstRTPBaseDepayload *basedepay;
509   GstFlowReturn flow_ret;
510
511   basedepay = GST_RTP_BASE_DEPAYLOAD_CAST (parent);
512
513   bclass = GST_RTP_BASE_DEPAYLOAD_GET_CLASS (basedepay);
514
515   flow_ret = gst_rtp_base_depayload_handle_buffer (basedepay, bclass, in);
516
517   gst_buffer_unref (in);
518
519   return flow_ret;
520 }
521
522 static GstFlowReturn
523 gst_rtp_base_depayload_chain_list (GstPad * pad, GstObject * parent,
524     GstBufferList * list)
525 {
526   GstRTPBaseDepayloadClass *bclass;
527   GstRTPBaseDepayload *basedepay;
528   GstFlowReturn flow_ret;
529   GstBuffer *buffer;
530   guint i, len;
531
532   basedepay = GST_RTP_BASE_DEPAYLOAD_CAST (parent);
533
534   bclass = GST_RTP_BASE_DEPAYLOAD_GET_CLASS (basedepay);
535
536   flow_ret = GST_FLOW_OK;
537
538   /* chain each buffer in list individually */
539   len = gst_buffer_list_length (list);
540
541   if (len == 0)
542     goto done;
543
544   for (i = 0; i < len; i++) {
545     buffer = gst_buffer_list_get (list, i);
546
547     /* Should we fix up any missing timestamps for list buffers here
548      * (e.g. set to first or previous timestamp in list) or just assume
549      * the's a jitterbuffer that will have done that for us? */
550     flow_ret = gst_rtp_base_depayload_handle_buffer (basedepay, bclass, buffer);
551     if (flow_ret != GST_FLOW_OK)
552       break;
553   }
554
555 done:
556
557   gst_buffer_list_unref (list);
558
559   return flow_ret;
560 }
561
562 static gboolean
563 gst_rtp_base_depayload_handle_event (GstRTPBaseDepayload * filter,
564     GstEvent * event)
565 {
566   gboolean res = TRUE;
567   gboolean forward = TRUE;
568
569   switch (GST_EVENT_TYPE (event)) {
570     case GST_EVENT_FLUSH_STOP:
571       gst_segment_init (&filter->segment, GST_FORMAT_UNDEFINED);
572       filter->need_newsegment = TRUE;
573       filter->priv->next_seqnum = -1;
574       gst_event_replace (&filter->priv->segment_event, NULL);
575       break;
576     case GST_EVENT_CAPS:
577     {
578       GstCaps *caps;
579
580       gst_event_parse_caps (event, &caps);
581
582       res = gst_rtp_base_depayload_setcaps (filter, caps);
583       forward = FALSE;
584       break;
585     }
586     case GST_EVENT_SEGMENT:
587     {
588       gst_event_copy_segment (event, &filter->segment);
589       /* don't pass the event downstream, we generate our own segment including
590        * the NTP time and other things we receive in caps */
591       forward = FALSE;
592       break;
593     }
594     case GST_EVENT_CUSTOM_DOWNSTREAM:
595     {
596       GstRTPBaseDepayloadClass *bclass;
597
598       bclass = GST_RTP_BASE_DEPAYLOAD_GET_CLASS (filter);
599
600       if (gst_event_has_name (event, "GstRTPPacketLost")) {
601         /* we get this event from the jitterbuffer when it considers a packet as
602          * being lost. We send it to our packet_lost vmethod. The default
603          * implementation will make time progress by pushing out a GAP event.
604          * Subclasses can override and do one of the following:
605          *  - Adjust timestamp/duration to something more accurate before
606          *    calling the parent (default) packet_lost method.
607          *  - do some more advanced error concealing on the already received
608          *    (fragmented) packets.
609          *  - ignore the packet lost.
610          */
611         if (bclass->packet_lost)
612           res = bclass->packet_lost (filter, event);
613         forward = FALSE;
614       }
615       break;
616     }
617     default:
618       break;
619   }
620
621   if (forward)
622     res = gst_pad_push_event (filter->srcpad, event);
623   else
624     gst_event_unref (event);
625
626   return res;
627 }
628
629 static gboolean
630 gst_rtp_base_depayload_handle_sink_event (GstPad * pad, GstObject * parent,
631     GstEvent * event)
632 {
633   gboolean res = FALSE;
634   GstRTPBaseDepayload *filter;
635   GstRTPBaseDepayloadClass *bclass;
636
637   filter = GST_RTP_BASE_DEPAYLOAD (parent);
638   bclass = GST_RTP_BASE_DEPAYLOAD_GET_CLASS (filter);
639   if (bclass->handle_event)
640     res = bclass->handle_event (filter, event);
641   else
642     gst_event_unref (event);
643
644   return res;
645 }
646
647 static GstEvent *
648 create_segment_event (GstRTPBaseDepayload * filter, guint rtptime,
649     GstClockTime position)
650 {
651   GstEvent *event;
652   GstClockTime start, stop, running_time;
653   GstRTPBaseDepayloadPrivate *priv;
654   GstSegment segment;
655
656   priv = filter->priv;
657
658   /* determining the start of the segment */
659   start = filter->segment.start;
660   if (priv->clock_base != -1 && position != -1) {
661     GstClockTime exttime, gap;
662
663     exttime = priv->clock_base;
664     gst_rtp_buffer_ext_timestamp (&exttime, rtptime);
665     gap = gst_util_uint64_scale_int (exttime - priv->clock_base,
666         filter->clock_rate, GST_SECOND);
667
668     /* account for lost packets */
669     if (position > gap) {
670       GST_DEBUG_OBJECT (filter,
671           "Found gap of %" GST_TIME_FORMAT ", adjusting start: %"
672           GST_TIME_FORMAT " = %" GST_TIME_FORMAT " - %" GST_TIME_FORMAT,
673           GST_TIME_ARGS (gap), GST_TIME_ARGS (position - gap),
674           GST_TIME_ARGS (position), GST_TIME_ARGS (gap));
675       start = position - gap;
676     }
677   }
678
679   /* determining the stop of the segment */
680   stop = filter->segment.stop;
681   if (priv->npt_stop != -1)
682     stop = start + (priv->npt_stop - priv->npt_start);
683
684   if (position == -1)
685     position = start;
686
687   running_time = gst_segment_to_running_time (&filter->segment,
688       GST_FORMAT_TIME, start);
689
690   gst_segment_init (&segment, GST_FORMAT_TIME);
691   segment.rate = priv->play_speed;
692   segment.applied_rate = priv->play_scale;
693   segment.start = start;
694   segment.stop = stop;
695   segment.time = priv->npt_start;
696   segment.position = position;
697   segment.base = running_time;
698
699   GST_DEBUG_OBJECT (filter, "Creating segment event %" GST_SEGMENT_FORMAT,
700       &segment);
701   event = gst_event_new_segment (&segment);
702
703   return event;
704 }
705
706 typedef struct
707 {
708   GstRTPBaseDepayload *depayload;
709   GstRTPBaseDepayloadClass *bclass;
710 } HeaderData;
711
712 static gboolean
713 set_headers (GstBuffer ** buffer, guint idx, HeaderData * data)
714 {
715   GstRTPBaseDepayload *depayload = data->depayload;
716   GstRTPBaseDepayloadPrivate *priv = depayload->priv;
717   GstClockTime pts, dts, duration;
718
719   *buffer = gst_buffer_make_writable (*buffer);
720
721   pts = GST_BUFFER_PTS (*buffer);
722   dts = GST_BUFFER_DTS (*buffer);
723   duration = GST_BUFFER_DURATION (*buffer);
724
725   /* apply last incomming timestamp and duration to outgoing buffer if
726    * not otherwise set. */
727   if (!GST_CLOCK_TIME_IS_VALID (pts))
728     GST_BUFFER_PTS (*buffer) = priv->pts;
729   if (!GST_CLOCK_TIME_IS_VALID (dts))
730     GST_BUFFER_DTS (*buffer) = priv->dts;
731   if (!GST_CLOCK_TIME_IS_VALID (duration))
732     GST_BUFFER_DURATION (*buffer) = priv->duration;
733
734   if (G_UNLIKELY (depayload->priv->discont)) {
735     GST_LOG_OBJECT (depayload, "Marking DISCONT on output buffer");
736     GST_BUFFER_FLAG_SET (*buffer, GST_BUFFER_FLAG_DISCONT);
737     depayload->priv->discont = FALSE;
738   }
739
740   /* make sure we only set the timestamp on the first packet */
741   priv->pts = GST_CLOCK_TIME_NONE;
742   priv->dts = GST_CLOCK_TIME_NONE;
743   priv->duration = GST_CLOCK_TIME_NONE;
744
745   return TRUE;
746 }
747
748 static GstFlowReturn
749 gst_rtp_base_depayload_prepare_push (GstRTPBaseDepayload * filter,
750     gboolean is_list, gpointer obj)
751 {
752   HeaderData data;
753
754   data.depayload = filter;
755   data.bclass = GST_RTP_BASE_DEPAYLOAD_GET_CLASS (filter);
756
757   if (is_list) {
758     GstBufferList **blist = obj;
759     gst_buffer_list_foreach (*blist, (GstBufferListFunc) set_headers, &data);
760   } else {
761     GstBuffer **buf = obj;
762     set_headers (buf, 0, &data);
763   }
764
765   /* if this is the first buffer send a NEWSEGMENT */
766   if (G_UNLIKELY (filter->priv->segment_event)) {
767     gst_pad_push_event (filter->srcpad, filter->priv->segment_event);
768     filter->priv->segment_event = NULL;
769     GST_DEBUG_OBJECT (filter, "Pushed newsegment event on this first buffer");
770   }
771
772   return GST_FLOW_OK;
773 }
774
775 /**
776  * gst_rtp_base_depayload_push:
777  * @filter: a #GstRTPBaseDepayload
778  * @out_buf: a #GstBuffer
779  *
780  * Push @out_buf to the peer of @filter. This function takes ownership of
781  * @out_buf.
782  *
783  * This function will by default apply the last incomming timestamp on
784  * the outgoing buffer when it didn't have a timestamp already.
785  *
786  * Returns: a #GstFlowReturn.
787  */
788 GstFlowReturn
789 gst_rtp_base_depayload_push (GstRTPBaseDepayload * filter, GstBuffer * out_buf)
790 {
791   GstFlowReturn res;
792
793   res = gst_rtp_base_depayload_prepare_push (filter, FALSE, &out_buf);
794
795   if (G_LIKELY (res == GST_FLOW_OK))
796     res = gst_pad_push (filter->srcpad, out_buf);
797   else
798     gst_buffer_unref (out_buf);
799
800   return res;
801 }
802
803 /**
804  * gst_rtp_base_depayload_push_list:
805  * @filter: a #GstRTPBaseDepayload
806  * @out_list: a #GstBufferList
807  *
808  * Push @out_list to the peer of @filter. This function takes ownership of
809  * @out_list.
810  *
811  * Returns: a #GstFlowReturn.
812  */
813 GstFlowReturn
814 gst_rtp_base_depayload_push_list (GstRTPBaseDepayload * filter,
815     GstBufferList * out_list)
816 {
817   GstFlowReturn res;
818
819   res = gst_rtp_base_depayload_prepare_push (filter, TRUE, &out_list);
820
821   if (G_LIKELY (res == GST_FLOW_OK))
822     res = gst_pad_push_list (filter->srcpad, out_list);
823   else
824     gst_buffer_list_unref (out_list);
825
826   return res;
827 }
828
829 /* convert the PacketLost event from a jitterbuffer to a GAP event.
830  * subclasses can override this.  */
831 static gboolean
832 gst_rtp_base_depayload_packet_lost (GstRTPBaseDepayload * filter,
833     GstEvent * event)
834 {
835   GstClockTime timestamp, duration;
836   GstEvent *sevent;
837   const GstStructure *s;
838
839   s = gst_event_get_structure (event);
840
841   /* first start by parsing the timestamp and duration */
842   timestamp = -1;
843   duration = -1;
844
845   gst_structure_get_clock_time (s, "timestamp", &timestamp);
846   gst_structure_get_clock_time (s, "duration", &duration);
847
848   /* send GAP event */
849   sevent = gst_event_new_gap (timestamp, duration);
850
851   return gst_pad_push_event (filter->srcpad, sevent);
852 }
853
854 static GstStateChangeReturn
855 gst_rtp_base_depayload_change_state (GstElement * element,
856     GstStateChange transition)
857 {
858   GstRTPBaseDepayload *filter;
859   GstRTPBaseDepayloadPrivate *priv;
860   GstStateChangeReturn ret;
861
862   filter = GST_RTP_BASE_DEPAYLOAD (element);
863   priv = filter->priv;
864
865   switch (transition) {
866     case GST_STATE_CHANGE_NULL_TO_READY:
867       break;
868     case GST_STATE_CHANGE_READY_TO_PAUSED:
869       filter->need_newsegment = TRUE;
870       priv->npt_start = 0;
871       priv->npt_stop = -1;
872       priv->play_speed = 1.0;
873       priv->play_scale = 1.0;
874       priv->clock_base = -1;
875       priv->next_seqnum = -1;
876       priv->negotiated = FALSE;
877       priv->discont = FALSE;
878       break;
879     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
880       break;
881     default:
882       break;
883   }
884
885   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
886
887   switch (transition) {
888     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
889       break;
890     case GST_STATE_CHANGE_PAUSED_TO_READY:
891       gst_caps_replace (&priv->last_caps, NULL);
892       gst_event_replace (&priv->segment_event, NULL);
893       break;
894     case GST_STATE_CHANGE_READY_TO_NULL:
895       break;
896     default:
897       break;
898   }
899   return ret;
900 }
901
902 static GstStructure *
903 gst_rtp_base_depayload_create_stats (GstRTPBaseDepayload * depayload)
904 {
905   GstRTPBaseDepayloadPrivate *priv;
906   GstStructure *s;
907
908   priv = depayload->priv;
909
910   s = gst_structure_new ("application/x-rtp-depayload-stats",
911       "clock_rate", G_TYPE_UINT, depayload->clock_rate,
912       "npt-start", G_TYPE_UINT64, priv->npt_start,
913       "npt-stop", G_TYPE_UINT64, priv->npt_stop,
914       "play-speed", G_TYPE_DOUBLE, priv->play_speed,
915       "play-scale", G_TYPE_DOUBLE, priv->play_scale,
916       "running-time-dts", G_TYPE_UINT64, priv->dts,
917       "running-time-pts", G_TYPE_UINT64, priv->pts,
918       "seqnum", G_TYPE_UINT, (guint) priv->last_seqnum,
919       "timestamp", G_TYPE_UINT, (guint) priv->last_rtptime, NULL);
920
921   return s;
922 }
923
924
925 static void
926 gst_rtp_base_depayload_set_property (GObject * object, guint prop_id,
927     const GValue * value, GParamSpec * pspec)
928 {
929   switch (prop_id) {
930     default:
931       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
932       break;
933   }
934 }
935
936 static void
937 gst_rtp_base_depayload_get_property (GObject * object, guint prop_id,
938     GValue * value, GParamSpec * pspec)
939 {
940   GstRTPBaseDepayload *depayload;
941
942   depayload = GST_RTP_BASE_DEPAYLOAD (object);
943
944   switch (prop_id) {
945     case PROP_STATS:
946       g_value_take_boxed (value,
947           gst_rtp_base_depayload_create_stats (depayload));
948       break;
949     default:
950       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
951       break;
952   }
953 }