libs: Remove "Since" markers and minor doc fixups
[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., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, 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
43   gboolean discont;
44   GstClockTime pts;
45   GstClockTime dts;
46   GstClockTime duration;
47
48   guint32 next_seqnum;
49
50   gboolean negotiated;
51 };
52
53 /* Filter signals and args */
54 enum
55 {
56   /* FILL ME */
57   LAST_SIGNAL
58 };
59
60 enum
61 {
62   PROP_0,
63   PROP_LAST
64 };
65
66 static void gst_rtp_base_depayload_finalize (GObject * object);
67 static void gst_rtp_base_depayload_set_property (GObject * object,
68     guint prop_id, const GValue * value, GParamSpec * pspec);
69 static void gst_rtp_base_depayload_get_property (GObject * object,
70     guint prop_id, GValue * value, GParamSpec * pspec);
71
72 static GstFlowReturn gst_rtp_base_depayload_chain (GstPad * pad,
73     GstObject * parent, GstBuffer * in);
74 static gboolean gst_rtp_base_depayload_handle_sink_event (GstPad * pad,
75     GstObject * parent, GstEvent * event);
76
77 static GstStateChangeReturn gst_rtp_base_depayload_change_state (GstElement *
78     element, GstStateChange transition);
79
80 static gboolean gst_rtp_base_depayload_packet_lost (GstRTPBaseDepayload *
81     filter, GstEvent * event);
82 static gboolean gst_rtp_base_depayload_handle_event (GstRTPBaseDepayload *
83     filter, GstEvent * event);
84
85 static GstElementClass *parent_class = NULL;
86 static void gst_rtp_base_depayload_class_init (GstRTPBaseDepayloadClass *
87     klass);
88 static void gst_rtp_base_depayload_init (GstRTPBaseDepayload * rtpbasepayload,
89     GstRTPBaseDepayloadClass * klass);
90
91 GType
92 gst_rtp_base_depayload_get_type (void)
93 {
94   static GType rtp_base_depayload_type = 0;
95
96   if (g_once_init_enter ((gsize *) & rtp_base_depayload_type)) {
97     static const GTypeInfo rtp_base_depayload_info = {
98       sizeof (GstRTPBaseDepayloadClass),
99       NULL,
100       NULL,
101       (GClassInitFunc) gst_rtp_base_depayload_class_init,
102       NULL,
103       NULL,
104       sizeof (GstRTPBaseDepayload),
105       0,
106       (GInstanceInitFunc) gst_rtp_base_depayload_init,
107     };
108
109     g_once_init_leave ((gsize *) & rtp_base_depayload_type,
110         g_type_register_static (GST_TYPE_ELEMENT, "GstRTPBaseDepayload",
111             &rtp_base_depayload_info, G_TYPE_FLAG_ABSTRACT));
112   }
113   return rtp_base_depayload_type;
114 }
115
116 static void
117 gst_rtp_base_depayload_class_init (GstRTPBaseDepayloadClass * klass)
118 {
119   GObjectClass *gobject_class;
120   GstElementClass *gstelement_class;
121
122   gobject_class = G_OBJECT_CLASS (klass);
123   gstelement_class = (GstElementClass *) klass;
124   parent_class = g_type_class_peek_parent (klass);
125
126   g_type_class_add_private (klass, sizeof (GstRTPBaseDepayloadPrivate));
127
128   gobject_class->finalize = gst_rtp_base_depayload_finalize;
129   gobject_class->set_property = gst_rtp_base_depayload_set_property;
130   gobject_class->get_property = gst_rtp_base_depayload_get_property;
131
132   gstelement_class->change_state = gst_rtp_base_depayload_change_state;
133
134   klass->packet_lost = gst_rtp_base_depayload_packet_lost;
135   klass->handle_event = gst_rtp_base_depayload_handle_event;
136
137   GST_DEBUG_CATEGORY_INIT (rtpbasedepayload_debug, "rtpbasedepayload", 0,
138       "Base class for RTP Depayloaders");
139 }
140
141 static void
142 gst_rtp_base_depayload_init (GstRTPBaseDepayload * filter,
143     GstRTPBaseDepayloadClass * klass)
144 {
145   GstPadTemplate *pad_template;
146   GstRTPBaseDepayloadPrivate *priv;
147
148   priv = GST_RTP_BASE_DEPAYLOAD_GET_PRIVATE (filter);
149   filter->priv = priv;
150
151   GST_DEBUG_OBJECT (filter, "init");
152
153   pad_template =
154       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "sink");
155   g_return_if_fail (pad_template != NULL);
156   filter->sinkpad = gst_pad_new_from_template (pad_template, "sink");
157   gst_pad_set_chain_function (filter->sinkpad, gst_rtp_base_depayload_chain);
158   gst_pad_set_event_function (filter->sinkpad,
159       gst_rtp_base_depayload_handle_sink_event);
160   gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad);
161
162   pad_template =
163       gst_element_class_get_pad_template (GST_ELEMENT_CLASS (klass), "src");
164   g_return_if_fail (pad_template != NULL);
165   filter->srcpad = gst_pad_new_from_template (pad_template, "src");
166   gst_pad_use_fixed_caps (filter->srcpad);
167   gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad);
168
169   gst_segment_init (&filter->segment, GST_FORMAT_UNDEFINED);
170 }
171
172 static void
173 gst_rtp_base_depayload_finalize (GObject * object)
174 {
175   G_OBJECT_CLASS (parent_class)->finalize (object);
176 }
177
178 static gboolean
179 gst_rtp_base_depayload_setcaps (GstRTPBaseDepayload * filter, GstCaps * caps)
180 {
181   GstRTPBaseDepayloadClass *bclass;
182   GstRTPBaseDepayloadPrivate *priv;
183   gboolean res;
184   GstStructure *caps_struct;
185   const GValue *value;
186
187   priv = filter->priv;
188
189   bclass = GST_RTP_BASE_DEPAYLOAD_GET_CLASS (filter);
190
191   GST_DEBUG_OBJECT (filter, "Set caps");
192
193   caps_struct = gst_caps_get_structure (caps, 0);
194
195   /* get other values for newsegment */
196   value = gst_structure_get_value (caps_struct, "npt-start");
197   if (value && G_VALUE_HOLDS_UINT64 (value))
198     priv->npt_start = g_value_get_uint64 (value);
199   else
200     priv->npt_start = 0;
201   GST_DEBUG_OBJECT (filter, "NPT start %" G_GUINT64_FORMAT, priv->npt_start);
202
203   value = gst_structure_get_value (caps_struct, "npt-stop");
204   if (value && G_VALUE_HOLDS_UINT64 (value))
205     priv->npt_stop = g_value_get_uint64 (value);
206   else
207     priv->npt_stop = -1;
208
209   GST_DEBUG_OBJECT (filter, "NPT stop %" G_GUINT64_FORMAT, priv->npt_stop);
210
211   value = gst_structure_get_value (caps_struct, "play-speed");
212   if (value && G_VALUE_HOLDS_DOUBLE (value))
213     priv->play_speed = g_value_get_double (value);
214   else
215     priv->play_speed = 1.0;
216
217   value = gst_structure_get_value (caps_struct, "play-scale");
218   if (value && G_VALUE_HOLDS_DOUBLE (value))
219     priv->play_scale = g_value_get_double (value);
220   else
221     priv->play_scale = 1.0;
222
223   if (bclass->set_caps) {
224     res = bclass->set_caps (filter, caps);
225     if (!res) {
226       GST_WARNING_OBJECT (filter, "Subclass rejected caps %" GST_PTR_FORMAT,
227           caps);
228     }
229   } else {
230     res = TRUE;
231   }
232
233   priv->negotiated = res;
234
235   return res;
236 }
237
238 static GstFlowReturn
239 gst_rtp_base_depayload_chain (GstPad * pad, GstObject * parent, GstBuffer * in)
240 {
241   GstRTPBaseDepayload *filter;
242   GstRTPBaseDepayloadPrivate *priv;
243   GstRTPBaseDepayloadClass *bclass;
244   GstFlowReturn ret = GST_FLOW_OK;
245   GstBuffer *out_buf;
246   GstClockTime pts, dts;
247   guint16 seqnum;
248   guint32 rtptime;
249   gboolean discont;
250   gint gap;
251   GstRTPBuffer rtp = { NULL };
252
253   filter = GST_RTP_BASE_DEPAYLOAD (parent);
254   priv = filter->priv;
255
256   /* we must have a setcaps first */
257   if (G_UNLIKELY (!priv->negotiated))
258     goto not_negotiated;
259
260   /* we must validate, it's possible that this element is plugged right after a
261    * network receiver and we don't want to operate on invalid data */
262   if (G_UNLIKELY (!gst_rtp_buffer_validate (in)))
263     goto invalid_buffer;
264
265   if (!priv->discont)
266     priv->discont = GST_BUFFER_IS_DISCONT (in);
267
268   pts = GST_BUFFER_PTS (in);
269   dts = GST_BUFFER_DTS (in);
270   /* convert to running_time and save the timestamp, this is the timestamp
271    * we put on outgoing buffers. */
272   pts = gst_segment_to_running_time (&filter->segment, GST_FORMAT_TIME, pts);
273   dts = gst_segment_to_running_time (&filter->segment, GST_FORMAT_TIME, dts);
274   priv->pts = pts;
275   priv->dts = dts;
276   priv->duration = GST_BUFFER_DURATION (in);
277
278   gst_rtp_buffer_map (in, GST_MAP_READ, &rtp);
279   seqnum = gst_rtp_buffer_get_seq (&rtp);
280   rtptime = gst_rtp_buffer_get_timestamp (&rtp);
281   gst_rtp_buffer_unmap (&rtp);
282
283   discont = FALSE;
284
285   GST_LOG_OBJECT (filter, "discont %d, seqnum %u, rtptime %u, pts %"
286       GST_TIME_FORMAT ", dts %" GST_TIME_FORMAT, priv->discont, seqnum, rtptime,
287       GST_TIME_ARGS (pts), GST_TIME_ARGS (dts));
288
289   /* Check seqnum. This is a very simple check that makes sure that the seqnums
290    * are striclty increasing, dropping anything that is out of the ordinary. We
291    * can only do this when the next_seqnum is known. */
292   if (G_LIKELY (priv->next_seqnum != -1)) {
293     gap = gst_rtp_buffer_compare_seqnum (seqnum, priv->next_seqnum);
294
295     /* if we have no gap, all is fine */
296     if (G_UNLIKELY (gap != 0)) {
297       GST_LOG_OBJECT (filter, "got packet %u, expected %u, gap %d", seqnum,
298           priv->next_seqnum, gap);
299       if (gap < 0) {
300         /* seqnum > next_seqnum, we are missing some packets, this is always a
301          * DISCONT. */
302         GST_LOG_OBJECT (filter, "%d missing packets", gap);
303         discont = TRUE;
304       } else {
305         /* seqnum < next_seqnum, we have seen this packet before or the sender
306          * could be restarted. If the packet is not too old, we throw it away as
307          * a duplicate, otherwise we mark discont and continue. 100 misordered
308          * packets is a good threshold. See also RFC 4737. */
309         if (gap < 100)
310           goto dropping;
311
312         GST_LOG_OBJECT (filter,
313             "%d > 100, packet too old, sender likely restarted", gap);
314         discont = TRUE;
315       }
316     }
317   }
318   priv->next_seqnum = (seqnum + 1) & 0xffff;
319
320   if (G_UNLIKELY (discont && !priv->discont)) {
321     GST_LOG_OBJECT (filter, "mark DISCONT on input buffer");
322     /* we detected a seqnum discont but the buffer was not flagged with a discont,
323      * set the discont flag so that the subclass can throw away old data. */
324     priv->discont = TRUE;
325     in = gst_buffer_make_writable (in);
326     GST_BUFFER_FLAG_SET (in, GST_BUFFER_FLAG_DISCONT);
327   }
328
329   bclass = GST_RTP_BASE_DEPAYLOAD_GET_CLASS (filter);
330
331   if (G_UNLIKELY (bclass->process == NULL))
332     goto no_process;
333
334   /* let's send it out to processing */
335   out_buf = bclass->process (filter, in);
336   if (out_buf) {
337     ret = gst_rtp_base_depayload_push (filter, out_buf);
338   }
339   gst_buffer_unref (in);
340
341   return ret;
342
343   /* ERRORS */
344 not_negotiated:
345   {
346     /* this is not fatal but should be filtered earlier */
347     GST_ELEMENT_ERROR (filter, CORE, NEGOTIATION,
348         ("No RTP format was negotiated."),
349         ("Input buffers need to have RTP caps set on them. This is usually "
350             "achieved by setting the 'caps' property of the upstream source "
351             "element (often udpsrc or appsrc), or by putting a capsfilter "
352             "element before the depayloader and setting the 'caps' property "
353             "on that. Also see http://cgit.freedesktop.org/gstreamer/"
354             "gst-plugins-good/tree/gst/rtp/README"));
355     gst_buffer_unref (in);
356     return GST_FLOW_NOT_NEGOTIATED;
357   }
358 invalid_buffer:
359   {
360     /* this is not fatal but should be filtered earlier */
361     GST_ELEMENT_WARNING (filter, STREAM, DECODE, (NULL),
362         ("Received invalid RTP payload, dropping"));
363     gst_buffer_unref (in);
364     return GST_FLOW_OK;
365   }
366 dropping:
367   {
368     GST_WARNING_OBJECT (filter, "%d <= 100, dropping old packet", gap);
369     gst_buffer_unref (in);
370     return GST_FLOW_OK;
371   }
372 no_process:
373   {
374     /* this is not fatal but should be filtered earlier */
375     GST_ELEMENT_ERROR (filter, STREAM, NOT_IMPLEMENTED, (NULL),
376         ("The subclass does not have a process method"));
377     gst_buffer_unref (in);
378     return GST_FLOW_ERROR;
379   }
380 }
381
382 static gboolean
383 gst_rtp_base_depayload_handle_event (GstRTPBaseDepayload * filter,
384     GstEvent * event)
385 {
386   gboolean res = TRUE;
387   gboolean forward = TRUE;
388
389   switch (GST_EVENT_TYPE (event)) {
390     case GST_EVENT_FLUSH_STOP:
391       gst_segment_init (&filter->segment, GST_FORMAT_UNDEFINED);
392       filter->need_newsegment = TRUE;
393       filter->priv->next_seqnum = -1;
394       break;
395     case GST_EVENT_CAPS:
396     {
397       GstCaps *caps;
398
399       gst_event_parse_caps (event, &caps);
400
401       res = gst_rtp_base_depayload_setcaps (filter, caps);
402       forward = FALSE;
403       break;
404     }
405     case GST_EVENT_SEGMENT:
406     {
407       gst_event_copy_segment (event, &filter->segment);
408       /* don't pass the event downstream, we generate our own segment including
409        * the NTP time and other things we receive in caps */
410       forward = FALSE;
411       break;
412     }
413     case GST_EVENT_CUSTOM_DOWNSTREAM:
414     {
415       GstRTPBaseDepayloadClass *bclass;
416
417       bclass = GST_RTP_BASE_DEPAYLOAD_GET_CLASS (filter);
418
419       if (gst_event_has_name (event, "GstRTPPacketLost")) {
420         /* we get this event from the jitterbuffer when it considers a packet as
421          * being lost. We send it to our packet_lost vmethod. The default
422          * implementation will make time progress by pushing out a NEWSEGMENT
423          * update event. Subclasses can override and to one of the following:
424          *  - Adjust timestamp/duration to something more accurate before
425          *    calling the parent (default) packet_lost method.
426          *  - do some more advanced error concealing on the already received
427          *    (fragmented) packets.
428          *  - ignore the packet lost.
429          */
430         if (bclass->packet_lost)
431           res = bclass->packet_lost (filter, event);
432         forward = FALSE;
433       }
434       break;
435     }
436     default:
437       break;
438   }
439
440   if (forward)
441     res = gst_pad_push_event (filter->srcpad, event);
442   else
443     gst_event_unref (event);
444
445   return res;
446 }
447
448 static gboolean
449 gst_rtp_base_depayload_handle_sink_event (GstPad * pad, GstObject * parent,
450     GstEvent * event)
451 {
452   gboolean res = FALSE;
453   GstRTPBaseDepayload *filter;
454   GstRTPBaseDepayloadClass *bclass;
455
456   filter = GST_RTP_BASE_DEPAYLOAD (parent);
457   bclass = GST_RTP_BASE_DEPAYLOAD_GET_CLASS (filter);
458   if (bclass->handle_event)
459     res = bclass->handle_event (filter, event);
460   else
461     gst_event_unref (event);
462
463   return res;
464 }
465
466 static GstEvent *
467 create_segment_event (GstRTPBaseDepayload * filter, gboolean update,
468     GstClockTime position)
469 {
470   GstEvent *event;
471   GstClockTime stop;
472   GstRTPBaseDepayloadPrivate *priv;
473   GstSegment segment;
474
475   priv = filter->priv;
476
477   if (priv->npt_stop != -1)
478     stop = priv->npt_stop - priv->npt_start;
479   else
480     stop = -1;
481
482   gst_segment_init (&segment, GST_FORMAT_TIME);
483   segment.rate = priv->play_speed;
484   segment.applied_rate = priv->play_scale;
485   segment.start = 0;
486   segment.stop = stop;
487   segment.time = priv->npt_start;
488   segment.position = position;
489
490   event = gst_event_new_segment (&segment);
491
492   return event;
493 }
494
495 typedef struct
496 {
497   GstRTPBaseDepayload *depayload;
498   GstRTPBaseDepayloadClass *bclass;
499 } HeaderData;
500
501 static gboolean
502 set_headers (GstBuffer ** buffer, guint idx, HeaderData * data)
503 {
504   GstRTPBaseDepayload *depayload = data->depayload;
505   GstRTPBaseDepayloadPrivate *priv = depayload->priv;
506   GstClockTime pts, dts, duration;
507
508   *buffer = gst_buffer_make_writable (*buffer);
509
510   pts = GST_BUFFER_PTS (*buffer);
511   dts = GST_BUFFER_DTS (*buffer);
512   duration = GST_BUFFER_DURATION (*buffer);
513
514   /* apply last incomming timestamp and duration to outgoing buffer if
515    * not otherwise set. */
516   if (!GST_CLOCK_TIME_IS_VALID (pts))
517     GST_BUFFER_PTS (*buffer) = priv->pts;
518   if (!GST_CLOCK_TIME_IS_VALID (dts))
519     GST_BUFFER_DTS (*buffer) = priv->dts;
520   if (!GST_CLOCK_TIME_IS_VALID (duration))
521     GST_BUFFER_DURATION (*buffer) = priv->duration;
522
523   if (G_UNLIKELY (depayload->priv->discont)) {
524     GST_LOG_OBJECT (depayload, "Marking DISCONT on output buffer");
525     GST_BUFFER_FLAG_SET (*buffer, GST_BUFFER_FLAG_DISCONT);
526     depayload->priv->discont = FALSE;
527   }
528
529   /* make sure we only set the timestamp on the first packet */
530   priv->pts = GST_CLOCK_TIME_NONE;
531   priv->dts = GST_CLOCK_TIME_NONE;
532   priv->duration = GST_CLOCK_TIME_NONE;
533
534   return TRUE;
535 }
536
537 static GstFlowReturn
538 gst_rtp_base_depayload_prepare_push (GstRTPBaseDepayload * filter,
539     gboolean is_list, gpointer obj)
540 {
541   HeaderData data;
542
543   data.depayload = filter;
544   data.bclass = GST_RTP_BASE_DEPAYLOAD_GET_CLASS (filter);
545
546   if (is_list) {
547     GstBufferList **blist = obj;
548     gst_buffer_list_foreach (*blist, (GstBufferListFunc) set_headers, &data);
549   } else {
550     GstBuffer **buf = obj;
551     set_headers (buf, 0, &data);
552   }
553
554   /* if this is the first buffer send a NEWSEGMENT */
555   if (G_UNLIKELY (filter->need_newsegment)) {
556     GstEvent *event;
557
558     event = create_segment_event (filter, FALSE, 0);
559
560     gst_pad_push_event (filter->srcpad, event);
561
562     filter->need_newsegment = FALSE;
563     GST_DEBUG_OBJECT (filter, "Pushed newsegment event on this first buffer");
564   }
565
566   return GST_FLOW_OK;
567 }
568
569 /**
570  * gst_rtp_base_depayload_push:
571  * @filter: a #GstRTPBaseDepayload
572  * @out_buf: a #GstBuffer
573  *
574  * Push @out_buf to the peer of @filter. This function takes ownership of
575  * @out_buf.
576  *
577  * This function will by default apply the last incomming timestamp on
578  * the outgoing buffer when it didn't have a timestamp already.
579  *
580  * Returns: a #GstFlowReturn.
581  */
582 GstFlowReturn
583 gst_rtp_base_depayload_push (GstRTPBaseDepayload * filter, GstBuffer * out_buf)
584 {
585   GstFlowReturn res;
586
587   res = gst_rtp_base_depayload_prepare_push (filter, FALSE, &out_buf);
588
589   if (G_LIKELY (res == GST_FLOW_OK))
590     res = gst_pad_push (filter->srcpad, out_buf);
591   else
592     gst_buffer_unref (out_buf);
593
594   return res;
595 }
596
597 /**
598  * gst_rtp_base_depayload_push_list:
599  * @filter: a #GstRTPBaseDepayload
600  * @out_list: a #GstBufferList
601  *
602  * Push @out_list to the peer of @filter. This function takes ownership of
603  * @out_list.
604  *
605  * Returns: a #GstFlowReturn.
606  */
607 GstFlowReturn
608 gst_rtp_base_depayload_push_list (GstRTPBaseDepayload * filter,
609     GstBufferList * out_list)
610 {
611   GstFlowReturn res;
612
613   res = gst_rtp_base_depayload_prepare_push (filter, TRUE, &out_list);
614
615   if (G_LIKELY (res == GST_FLOW_OK))
616     res = gst_pad_push_list (filter->srcpad, out_list);
617   else
618     gst_buffer_list_unref (out_list);
619
620   return res;
621 }
622
623 /* convert the PacketLost event form a jitterbuffer to a segment update.
624  * subclasses can override this.  */
625 static gboolean
626 gst_rtp_base_depayload_packet_lost (GstRTPBaseDepayload * filter,
627     GstEvent * event)
628 {
629   GstClockTime timestamp, duration, position;
630   GstEvent *sevent;
631   const GstStructure *s;
632
633   s = gst_event_get_structure (event);
634
635   /* first start by parsing the timestamp and duration */
636   timestamp = -1;
637   duration = -1;
638
639   gst_structure_get_clock_time (s, "timestamp", &timestamp);
640   gst_structure_get_clock_time (s, "duration", &duration);
641
642   position = timestamp;
643   if (duration != -1)
644     position += duration;
645
646   /* update the current segment with the elapsed time */
647   sevent = create_segment_event (filter, TRUE, position);
648
649   return gst_pad_push_event (filter->srcpad, sevent);
650 }
651
652 static GstStateChangeReturn
653 gst_rtp_base_depayload_change_state (GstElement * element,
654     GstStateChange transition)
655 {
656   GstRTPBaseDepayload *filter;
657   GstRTPBaseDepayloadPrivate *priv;
658   GstStateChangeReturn ret;
659
660   filter = GST_RTP_BASE_DEPAYLOAD (element);
661   priv = filter->priv;
662
663   switch (transition) {
664     case GST_STATE_CHANGE_NULL_TO_READY:
665       break;
666     case GST_STATE_CHANGE_READY_TO_PAUSED:
667       filter->need_newsegment = TRUE;
668       priv->npt_start = 0;
669       priv->npt_stop = -1;
670       priv->play_speed = 1.0;
671       priv->play_scale = 1.0;
672       priv->next_seqnum = -1;
673       priv->negotiated = FALSE;
674       priv->discont = FALSE;
675       break;
676     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
677       break;
678     default:
679       break;
680   }
681
682   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
683
684   switch (transition) {
685     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
686       break;
687     case GST_STATE_CHANGE_PAUSED_TO_READY:
688       break;
689     case GST_STATE_CHANGE_READY_TO_NULL:
690       break;
691     default:
692       break;
693   }
694   return ret;
695 }
696
697 static void
698 gst_rtp_base_depayload_set_property (GObject * object, guint prop_id,
699     const GValue * value, GParamSpec * pspec)
700 {
701   switch (prop_id) {
702     default:
703       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
704       break;
705   }
706 }
707
708 static void
709 gst_rtp_base_depayload_get_property (GObject * object, guint prop_id,
710     GValue * value, GParamSpec * pspec)
711 {
712   switch (prop_id) {
713     default:
714       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
715       break;
716   }
717 }