Added gst-plugins-base-subtitles0.10-0.10.34 for Meego Harmattan 1.2
[mafwsubrenderer] / gst-plugins-base-subtitles0.10 / gst-libs / gst / rtp / gstbasertpaudiopayload.c
1 /* GStreamer
2  * Copyright (C) <2006> Philippe Khalaf <philippe.kalaf@collabora.co.uk>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:gstbasertpaudiopayload
22  * @short_description: Base class for audio RTP payloader
23  *
24  * <refsect2>
25  * <para>
26  * Provides a base class for audio RTP payloaders for frame or sample based
27  * audio codecs (constant bitrate)
28  * </para>
29  * <para>
30  * This class derives from GstBaseRTPPayload. It can be used for payloading
31  * audio codecs. It will only work with constant bitrate codecs. It supports
32  * both frame based and sample based codecs. It takes care of packing up the
33  * audio data into RTP packets and filling up the headers accordingly. The
34  * payloading is done based on the maximum MTU (mtu) and the maximum time per
35  * packet (max-ptime). The general idea is to divide large data buffers into
36  * smaller RTP packets. The RTP packet size is the minimum of either the MTU,
37  * max-ptime (if set) or available data. The RTP packet size is always larger or
38  * equal to min-ptime (if set). If min-ptime is not set, any residual data is
39  * sent in a last RTP packet. In the case of frame based codecs, the resulting
40  * RTP packets always contain full frames.
41  * </para>
42  * <title>Usage</title>
43  * <para>
44  * To use this base class, your child element needs to call either
45  * gst_base_rtp_audio_payload_set_frame_based() or
46  * gst_base_rtp_audio_payload_set_sample_based(). This is usually done in the
47  * element's _init() function. Then, the child element must call either
48  * gst_base_rtp_audio_payload_set_frame_options(),
49  * gst_base_rtp_audio_payload_set_sample_options() or
50  * gst_base_rtp_audio_payload_set_samplebits_options. Since
51  * GstBaseRTPAudioPayload derives from GstBaseRTPPayload, the child element
52  * must set any variables or call/override any functions required by that base
53  * class. The child element does not need to override any other functions
54  * specific to GstBaseRTPAudioPayload.
55  * </para>
56  * </refsect2>
57  */
58
59 #ifdef HAVE_CONFIG_H
60 #include "config.h"
61 #endif
62
63 #include <stdlib.h>
64 #include <string.h>
65 #include <gst/rtp/gstrtpbuffer.h>
66 #include <gst/base/gstadapter.h>
67
68 #include "gstbasertpaudiopayload.h"
69
70 GST_DEBUG_CATEGORY_STATIC (basertpaudiopayload_debug);
71 #define GST_CAT_DEFAULT (basertpaudiopayload_debug)
72
73 #define DEFAULT_BUFFER_LIST             FALSE
74
75 enum
76 {
77   PROP_0,
78   PROP_BUFFER_LIST,
79   PROP_LAST
80 };
81
82 /* function to convert bytes to a time */
83 typedef GstClockTime (*GetBytesToTimeFunc) (GstBaseRTPAudioPayload * payload,
84     guint64 bytes);
85 /* function to convert bytes to a RTP time */
86 typedef guint32 (*GetBytesToRTPTimeFunc) (GstBaseRTPAudioPayload * payload,
87     guint64 bytes);
88 /* function to convert time to bytes */
89 typedef guint64 (*GetTimeToBytesFunc) (GstBaseRTPAudioPayload * payload,
90     GstClockTime time);
91
92 struct _GstBaseRTPAudioPayloadPrivate
93 {
94   GetBytesToTimeFunc bytes_to_time;
95   GetBytesToRTPTimeFunc bytes_to_rtptime;
96   GetTimeToBytesFunc time_to_bytes;
97
98   GstAdapter *adapter;
99   guint fragment_size;
100   GstClockTime frame_duration_ns;
101   gboolean discont;
102   guint64 offset;
103   GstClockTime last_timestamp;
104   guint32 last_rtptime;
105   guint align;
106
107   guint cached_mtu;
108   guint cached_min_ptime;
109   guint cached_max_ptime;
110   guint cached_ptime;
111   guint cached_min_length;
112   guint cached_max_length;
113   guint cached_ptime_multiple;
114   guint cached_align;
115
116   gboolean buffer_list;
117 };
118
119
120 #define GST_BASE_RTP_AUDIO_PAYLOAD_GET_PRIVATE(o) \
121   (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_BASE_RTP_AUDIO_PAYLOAD, \
122                                 GstBaseRTPAudioPayloadPrivate))
123
124 static void gst_base_rtp_audio_payload_finalize (GObject * object);
125
126 static void gst_base_rtp_audio_payload_set_property (GObject * object,
127     guint prop_id, const GValue * value, GParamSpec * pspec);
128 static void gst_base_rtp_audio_payload_get_property (GObject * object,
129     guint prop_id, GValue * value, GParamSpec * pspec);
130
131 /* bytes to time functions */
132 static GstClockTime
133 gst_base_rtp_audio_payload_frame_bytes_to_time (GstBaseRTPAudioPayload *
134     payload, guint64 bytes);
135 static GstClockTime
136 gst_base_rtp_audio_payload_sample_bytes_to_time (GstBaseRTPAudioPayload *
137     payload, guint64 bytes);
138
139 /* bytes to RTP time functions */
140 static guint32
141 gst_base_rtp_audio_payload_frame_bytes_to_rtptime (GstBaseRTPAudioPayload *
142     payload, guint64 bytes);
143 static guint32
144 gst_base_rtp_audio_payload_sample_bytes_to_rtptime (GstBaseRTPAudioPayload *
145     payload, guint64 bytes);
146
147 /* time to bytes functions */
148 static guint64
149 gst_base_rtp_audio_payload_frame_time_to_bytes (GstBaseRTPAudioPayload *
150     payload, GstClockTime time);
151 static guint64
152 gst_base_rtp_audio_payload_sample_time_to_bytes (GstBaseRTPAudioPayload *
153     payload, GstClockTime time);
154
155 static GstFlowReturn gst_base_rtp_audio_payload_handle_buffer (GstBaseRTPPayload
156     * payload, GstBuffer * buffer);
157
158 static GstStateChangeReturn gst_base_rtp_payload_audio_change_state (GstElement
159     * element, GstStateChange transition);
160
161 static gboolean gst_base_rtp_payload_audio_handle_event (GstPad * pad,
162     GstEvent * event);
163
164 GST_BOILERPLATE (GstBaseRTPAudioPayload, gst_base_rtp_audio_payload,
165     GstBaseRTPPayload, GST_TYPE_BASE_RTP_PAYLOAD);
166
167 static void
168 gst_base_rtp_audio_payload_base_init (gpointer klass)
169 {
170 }
171
172 static void
173 gst_base_rtp_audio_payload_class_init (GstBaseRTPAudioPayloadClass * klass)
174 {
175   GObjectClass *gobject_class;
176   GstElementClass *gstelement_class;
177   GstBaseRTPPayloadClass *gstbasertppayload_class;
178
179   g_type_class_add_private (klass, sizeof (GstBaseRTPAudioPayloadPrivate));
180
181   gobject_class = (GObjectClass *) klass;
182   gstelement_class = (GstElementClass *) klass;
183   gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
184
185   gobject_class->finalize = gst_base_rtp_audio_payload_finalize;
186   gobject_class->set_property = gst_base_rtp_audio_payload_set_property;
187   gobject_class->get_property = gst_base_rtp_audio_payload_get_property;
188
189   g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_BUFFER_LIST,
190       g_param_spec_boolean ("buffer-list", "Buffer List",
191           "Use Buffer Lists",
192           DEFAULT_BUFFER_LIST, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
193
194   gstelement_class->change_state =
195       GST_DEBUG_FUNCPTR (gst_base_rtp_payload_audio_change_state);
196
197   gstbasertppayload_class->handle_buffer =
198       GST_DEBUG_FUNCPTR (gst_base_rtp_audio_payload_handle_buffer);
199   gstbasertppayload_class->handle_event =
200       GST_DEBUG_FUNCPTR (gst_base_rtp_payload_audio_handle_event);
201
202   GST_DEBUG_CATEGORY_INIT (basertpaudiopayload_debug, "basertpaudiopayload", 0,
203       "base audio RTP payloader");
204 }
205
206 static void
207 gst_base_rtp_audio_payload_init (GstBaseRTPAudioPayload * payload,
208     GstBaseRTPAudioPayloadClass * klass)
209 {
210   payload->priv = GST_BASE_RTP_AUDIO_PAYLOAD_GET_PRIVATE (payload);
211
212   /* these need to be set by child object if frame based */
213   payload->frame_size = 0;
214   payload->frame_duration = 0;
215
216   /* these need to be set by child object if sample based */
217   payload->sample_size = 0;
218
219   payload->priv->adapter = gst_adapter_new ();
220
221   payload->priv->buffer_list = DEFAULT_BUFFER_LIST;
222 }
223
224 static void
225 gst_base_rtp_audio_payload_finalize (GObject * object)
226 {
227   GstBaseRTPAudioPayload *payload;
228
229   payload = GST_BASE_RTP_AUDIO_PAYLOAD (object);
230
231   g_object_unref (payload->priv->adapter);
232
233   GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
234 }
235
236 static void
237 gst_base_rtp_audio_payload_set_property (GObject * object,
238     guint prop_id, const GValue * value, GParamSpec * pspec)
239 {
240   GstBaseRTPAudioPayload *payload;
241
242   payload = GST_BASE_RTP_AUDIO_PAYLOAD (object);
243
244   switch (prop_id) {
245     case PROP_BUFFER_LIST:
246       payload->priv->buffer_list = g_value_get_boolean (value);
247       break;
248     default:
249       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
250       break;
251   }
252 }
253
254 static void
255 gst_base_rtp_audio_payload_get_property (GObject * object,
256     guint prop_id, GValue * value, GParamSpec * pspec)
257 {
258   GstBaseRTPAudioPayload *payload;
259
260   payload = GST_BASE_RTP_AUDIO_PAYLOAD (object);
261
262   switch (prop_id) {
263     case PROP_BUFFER_LIST:
264       g_value_set_boolean (value, payload->priv->buffer_list);
265       break;
266     default:
267       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
268       break;
269   }
270 }
271
272 /**
273  * gst_base_rtp_audio_payload_set_frame_based:
274  * @basertpaudiopayload: a pointer to the element.
275  *
276  * Tells #GstBaseRTPAudioPayload that the child element is for a frame based
277  * audio codec
278  */
279 void
280 gst_base_rtp_audio_payload_set_frame_based (GstBaseRTPAudioPayload *
281     basertpaudiopayload)
282 {
283   g_return_if_fail (basertpaudiopayload != NULL);
284   g_return_if_fail (basertpaudiopayload->priv->time_to_bytes == NULL);
285   g_return_if_fail (basertpaudiopayload->priv->bytes_to_time == NULL);
286   g_return_if_fail (basertpaudiopayload->priv->bytes_to_rtptime == NULL);
287
288   basertpaudiopayload->priv->bytes_to_time =
289       gst_base_rtp_audio_payload_frame_bytes_to_time;
290   basertpaudiopayload->priv->bytes_to_rtptime =
291       gst_base_rtp_audio_payload_frame_bytes_to_rtptime;
292   basertpaudiopayload->priv->time_to_bytes =
293       gst_base_rtp_audio_payload_frame_time_to_bytes;
294 }
295
296 /**
297  * gst_base_rtp_audio_payload_set_sample_based:
298  * @basertpaudiopayload: a pointer to the element.
299  *
300  * Tells #GstBaseRTPAudioPayload that the child element is for a sample based
301  * audio codec
302  */
303 void
304 gst_base_rtp_audio_payload_set_sample_based (GstBaseRTPAudioPayload *
305     basertpaudiopayload)
306 {
307   g_return_if_fail (basertpaudiopayload != NULL);
308   g_return_if_fail (basertpaudiopayload->priv->time_to_bytes == NULL);
309   g_return_if_fail (basertpaudiopayload->priv->bytes_to_time == NULL);
310   g_return_if_fail (basertpaudiopayload->priv->bytes_to_rtptime == NULL);
311
312   basertpaudiopayload->priv->bytes_to_time =
313       gst_base_rtp_audio_payload_sample_bytes_to_time;
314   basertpaudiopayload->priv->bytes_to_rtptime =
315       gst_base_rtp_audio_payload_sample_bytes_to_rtptime;
316   basertpaudiopayload->priv->time_to_bytes =
317       gst_base_rtp_audio_payload_sample_time_to_bytes;
318 }
319
320 /**
321  * gst_base_rtp_audio_payload_set_frame_options:
322  * @basertpaudiopayload: a pointer to the element.
323  * @frame_duration: The duraction of an audio frame in milliseconds.
324  * @frame_size: The size of an audio frame in bytes.
325  *
326  * Sets the options for frame based audio codecs.
327  *
328  */
329 void
330 gst_base_rtp_audio_payload_set_frame_options (GstBaseRTPAudioPayload
331     * basertpaudiopayload, gint frame_duration, gint frame_size)
332 {
333   GstBaseRTPAudioPayloadPrivate *priv;
334
335   g_return_if_fail (basertpaudiopayload != NULL);
336
337   priv = basertpaudiopayload->priv;
338
339   basertpaudiopayload->frame_duration = frame_duration;
340   priv->frame_duration_ns = frame_duration * GST_MSECOND;
341   basertpaudiopayload->frame_size = frame_size;
342   priv->align = frame_size;
343
344   gst_adapter_clear (priv->adapter);
345
346   GST_DEBUG_OBJECT (basertpaudiopayload, "frame set to %d ms and size %d",
347       frame_duration, frame_size);
348 }
349
350 /**
351  * gst_base_rtp_audio_payload_set_sample_options:
352  * @basertpaudiopayload: a pointer to the element.
353  * @sample_size: Size per sample in bytes.
354  *
355  * Sets the options for sample based audio codecs.
356  */
357 void
358 gst_base_rtp_audio_payload_set_sample_options (GstBaseRTPAudioPayload
359     * basertpaudiopayload, gint sample_size)
360 {
361   g_return_if_fail (basertpaudiopayload != NULL);
362
363   /* sample_size is in bits internally */
364   gst_base_rtp_audio_payload_set_samplebits_options (basertpaudiopayload,
365       sample_size * 8);
366 }
367
368 /**
369  * gst_base_rtp_audio_payload_set_samplebits_options:
370  * @basertpaudiopayload: a pointer to the element.
371  * @sample_size: Size per sample in bits.
372  *
373  * Sets the options for sample based audio codecs.
374  *
375  * Since: 0.10.18
376  */
377 void
378 gst_base_rtp_audio_payload_set_samplebits_options (GstBaseRTPAudioPayload
379     * basertpaudiopayload, gint sample_size)
380 {
381   guint fragment_size;
382   GstBaseRTPAudioPayloadPrivate *priv;
383
384   g_return_if_fail (basertpaudiopayload != NULL);
385
386   priv = basertpaudiopayload->priv;
387
388   basertpaudiopayload->sample_size = sample_size;
389
390   /* sample_size is in bits and is converted into multiple bytes */
391   fragment_size = sample_size;
392   while ((fragment_size % 8) != 0)
393     fragment_size += fragment_size;
394   priv->fragment_size = fragment_size / 8;
395   priv->align = priv->fragment_size;
396
397   gst_adapter_clear (priv->adapter);
398
399   GST_DEBUG_OBJECT (basertpaudiopayload,
400       "Samplebits set to sample size %d bits", sample_size);
401 }
402
403 static void
404 gst_base_rtp_audio_payload_set_meta (GstBaseRTPAudioPayload * payload,
405     GstBuffer * buffer, guint payload_len, GstClockTime timestamp)
406 {
407   GstBaseRTPPayload *basepayload;
408   GstBaseRTPAudioPayloadPrivate *priv;
409
410   basepayload = GST_BASE_RTP_PAYLOAD_CAST (payload);
411   priv = payload->priv;
412
413   /* set payload type */
414   gst_rtp_buffer_set_payload_type (buffer, basepayload->pt);
415   /* set marker bit for disconts */
416   if (priv->discont) {
417     GST_DEBUG_OBJECT (payload, "Setting marker and DISCONT");
418     gst_rtp_buffer_set_marker (buffer, TRUE);
419     GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_DISCONT);
420     priv->discont = FALSE;
421   }
422   GST_BUFFER_TIMESTAMP (buffer) = timestamp;
423
424   /* get the offset in RTP time */
425   GST_BUFFER_OFFSET (buffer) = priv->bytes_to_rtptime (payload, priv->offset);
426
427   priv->offset += payload_len;
428
429   /* Set the duration from the size */
430   GST_BUFFER_DURATION (buffer) = priv->bytes_to_time (payload, payload_len);
431
432   /* remember the last rtptime/timestamp pair. We will use this to realign our
433    * RTP timestamp after a buffer discont */
434   priv->last_rtptime = GST_BUFFER_OFFSET (buffer);
435   priv->last_timestamp = timestamp;
436 }
437
438 /**
439  * gst_base_rtp_audio_payload_push:
440  * @baseaudiopayload: a #GstBaseRTPPayload
441  * @data: data to set as payload
442  * @payload_len: length of payload
443  * @timestamp: a #GstClockTime
444  *
445  * Create an RTP buffer and store @payload_len bytes of @data as the
446  * payload. Set the timestamp on the new buffer to @timestamp before pushing
447  * the buffer downstream.
448  *
449  * Returns: a #GstFlowReturn
450  *
451  * Since: 0.10.13
452  */
453 GstFlowReturn
454 gst_base_rtp_audio_payload_push (GstBaseRTPAudioPayload * baseaudiopayload,
455     const guint8 * data, guint payload_len, GstClockTime timestamp)
456 {
457   GstBaseRTPPayload *basepayload;
458   GstBuffer *outbuf;
459   guint8 *payload;
460   GstFlowReturn ret;
461
462   basepayload = GST_BASE_RTP_PAYLOAD (baseaudiopayload);
463
464   GST_DEBUG_OBJECT (baseaudiopayload, "Pushing %d bytes ts %" GST_TIME_FORMAT,
465       payload_len, GST_TIME_ARGS (timestamp));
466
467   /* create buffer to hold the payload */
468   outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
469
470   /* copy payload */
471   payload = gst_rtp_buffer_get_payload (outbuf);
472   memcpy (payload, data, payload_len);
473
474   /* set metadata */
475   gst_base_rtp_audio_payload_set_meta (baseaudiopayload, outbuf, payload_len,
476       timestamp);
477
478   ret = gst_basertppayload_push (basepayload, outbuf);
479
480   return ret;
481 }
482
483 static GstFlowReturn
484 gst_base_rtp_audio_payload_push_buffer (GstBaseRTPAudioPayload *
485     baseaudiopayload, GstBuffer * buffer, GstClockTime timestamp)
486 {
487   GstBaseRTPPayload *basepayload;
488   GstBaseRTPAudioPayloadPrivate *priv;
489   GstBuffer *outbuf;
490   guint8 *payload;
491   guint payload_len;
492   GstFlowReturn ret;
493
494   priv = baseaudiopayload->priv;
495   basepayload = GST_BASE_RTP_PAYLOAD (baseaudiopayload);
496
497   payload_len = GST_BUFFER_SIZE (buffer);
498
499   GST_DEBUG_OBJECT (baseaudiopayload, "Pushing %d bytes ts %" GST_TIME_FORMAT,
500       payload_len, GST_TIME_ARGS (timestamp));
501
502   if (priv->buffer_list) {
503     /* create just the RTP header buffer */
504     outbuf = gst_rtp_buffer_new_allocate (0, 0, 0);
505   } else {
506     /* create buffer to hold the payload */
507     outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
508   }
509
510   /* set metadata */
511   gst_base_rtp_audio_payload_set_meta (baseaudiopayload, outbuf, payload_len,
512       timestamp);
513
514   if (priv->buffer_list) {
515     GstBufferList *list;
516     GstBufferListIterator *it;
517
518     list = gst_buffer_list_new ();
519     it = gst_buffer_list_iterate (list);
520
521     /* add both buffers to the buffer list */
522     gst_buffer_list_iterator_add_group (it);
523     gst_buffer_list_iterator_add (it, outbuf);
524     gst_buffer_list_iterator_add (it, buffer);
525
526     gst_buffer_list_iterator_free (it);
527
528     GST_DEBUG_OBJECT (baseaudiopayload, "Pushing list %p", list);
529     ret = gst_basertppayload_push_list (basepayload, list);
530   } else {
531     /* copy payload */
532     payload = gst_rtp_buffer_get_payload (outbuf);
533     memcpy (payload, GST_BUFFER_DATA (buffer), payload_len);
534     gst_buffer_unref (buffer);
535
536     GST_DEBUG_OBJECT (baseaudiopayload, "Pushing buffer %p", outbuf);
537     ret = gst_basertppayload_push (basepayload, outbuf);
538   }
539
540   return ret;
541 }
542
543 /**
544  * gst_base_rtp_audio_payload_flush:
545  * @baseaudiopayload: a #GstBaseRTPPayload
546  * @payload_len: length of payload
547  * @timestamp: a #GstClockTime
548  *
549  * Create an RTP buffer and store @payload_len bytes of the adapter as the
550  * payload. Set the timestamp on the new buffer to @timestamp before pushing
551  * the buffer downstream.
552  *
553  * If @payload_len is -1, all pending bytes will be flushed. If @timestamp is
554  * -1, the timestamp will be calculated automatically.
555  *
556  * Returns: a #GstFlowReturn
557  *
558  * Since: 0.10.25
559  */
560 GstFlowReturn
561 gst_base_rtp_audio_payload_flush (GstBaseRTPAudioPayload * baseaudiopayload,
562     guint payload_len, GstClockTime timestamp)
563 {
564   GstBaseRTPPayload *basepayload;
565   GstBaseRTPAudioPayloadPrivate *priv;
566   GstBuffer *outbuf;
567   guint8 *payload;
568   GstFlowReturn ret;
569   GstAdapter *adapter;
570   guint64 distance;
571
572   priv = baseaudiopayload->priv;
573   adapter = priv->adapter;
574
575   basepayload = GST_BASE_RTP_PAYLOAD (baseaudiopayload);
576
577   if (payload_len == -1)
578     payload_len = gst_adapter_available (adapter);
579
580   /* nothing to do, just return */
581   if (payload_len == 0)
582     return GST_FLOW_OK;
583
584   if (timestamp == -1) {
585     /* calculate the timestamp */
586     timestamp = gst_adapter_prev_timestamp (adapter, &distance);
587
588     GST_LOG_OBJECT (baseaudiopayload,
589         "last timestamp %" GST_TIME_FORMAT ", distance %" G_GUINT64_FORMAT,
590         GST_TIME_ARGS (timestamp), distance);
591
592     if (GST_CLOCK_TIME_IS_VALID (timestamp) && distance > 0) {
593       /* convert the number of bytes since the last timestamp to time and add to
594        * the last seen timestamp */
595       timestamp += priv->bytes_to_time (baseaudiopayload, distance);
596     }
597   }
598
599   GST_DEBUG_OBJECT (baseaudiopayload, "Pushing %d bytes ts %" GST_TIME_FORMAT,
600       payload_len, GST_TIME_ARGS (timestamp));
601
602   if (priv->buffer_list && gst_adapter_available_fast (adapter) >= payload_len) {
603     GstBuffer *buffer;
604     /* we can quickly take a buffer out of the adapter without having to copy
605      * anything. */
606     buffer = gst_adapter_take_buffer (adapter, payload_len);
607
608     ret =
609         gst_base_rtp_audio_payload_push_buffer (baseaudiopayload, buffer,
610         timestamp);
611   } else {
612     /* create buffer to hold the payload */
613     outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
614
615     /* copy payload */
616     payload = gst_rtp_buffer_get_payload (outbuf);
617     gst_adapter_copy (adapter, payload, 0, payload_len);
618     gst_adapter_flush (adapter, payload_len);
619
620     /* set metadata */
621     gst_base_rtp_audio_payload_set_meta (baseaudiopayload, outbuf, payload_len,
622         timestamp);
623
624     ret = gst_basertppayload_push (basepayload, outbuf);
625   }
626
627   return ret;
628 }
629
630 #define ALIGN_DOWN(val,len) ((val) - ((val) % (len)))
631
632 /* calculate the min and max length of a packet. This depends on the configured
633  * mtu and min/max_ptime values. We cache those so that we don't have to redo
634  * all the calculations */
635 static gboolean
636 gst_base_rtp_audio_payload_get_lengths (GstBaseRTPPayload *
637     basepayload, guint * min_payload_len, guint * max_payload_len,
638     guint * align)
639 {
640   GstBaseRTPAudioPayload *payload;
641   GstBaseRTPAudioPayloadPrivate *priv;
642   guint max_mtu, mtu;
643   guint maxptime_octets;
644   guint minptime_octets;
645   guint ptime_mult_octets;
646
647   payload = GST_BASE_RTP_AUDIO_PAYLOAD_CAST (basepayload);
648   priv = payload->priv;
649
650   if (priv->align == 0)
651     return FALSE;
652
653   mtu = GST_BASE_RTP_PAYLOAD_MTU (payload);
654
655   /* check cached values */
656   if (G_LIKELY (priv->cached_mtu == mtu
657           && priv->cached_ptime_multiple ==
658           basepayload->abidata.ABI.ptime_multiple
659           && priv->cached_ptime == basepayload->abidata.ABI.ptime
660           && priv->cached_max_ptime == basepayload->max_ptime
661           && priv->cached_min_ptime == basepayload->min_ptime)) {
662     /* if nothing changed, return cached values */
663     *min_payload_len = priv->cached_min_length;
664     *max_payload_len = priv->cached_max_length;
665     *align = priv->cached_align;
666     return TRUE;
667   }
668
669   ptime_mult_octets = priv->time_to_bytes (payload,
670       basepayload->abidata.ABI.ptime_multiple);
671   *align = ALIGN_DOWN (MAX (priv->align, ptime_mult_octets), priv->align);
672
673   /* ptime max */
674   if (basepayload->max_ptime != -1) {
675     maxptime_octets = priv->time_to_bytes (payload, basepayload->max_ptime);
676   } else {
677     maxptime_octets = G_MAXUINT;
678   }
679   /* MTU max */
680   max_mtu = gst_rtp_buffer_calc_payload_len (mtu, 0, 0);
681   /* round down to alignment */
682   max_mtu = ALIGN_DOWN (max_mtu, *align);
683
684   /* combine max ptime and max payload length */
685   *max_payload_len = MIN (max_mtu, maxptime_octets);
686
687   /* min number of bytes based on a given ptime */
688   minptime_octets = priv->time_to_bytes (payload, basepayload->min_ptime);
689   /* must be at least one frame size */
690   *min_payload_len = MAX (minptime_octets, *align);
691
692   if (*min_payload_len > *max_payload_len)
693     *min_payload_len = *max_payload_len;
694
695   /* If the ptime is specified in the caps, tried to adhere to it exactly */
696   if (basepayload->abidata.ABI.ptime) {
697     guint ptime_in_bytes = priv->time_to_bytes (payload,
698         basepayload->abidata.ABI.ptime);
699
700     /* clip to computed min and max lengths */
701     ptime_in_bytes = MAX (*min_payload_len, ptime_in_bytes);
702     ptime_in_bytes = MIN (*max_payload_len, ptime_in_bytes);
703
704     *min_payload_len = *max_payload_len = ptime_in_bytes;
705   }
706
707   /* cache values */
708   priv->cached_mtu = mtu;
709   priv->cached_ptime = basepayload->abidata.ABI.ptime;
710   priv->cached_min_ptime = basepayload->min_ptime;
711   priv->cached_max_ptime = basepayload->max_ptime;
712   priv->cached_ptime_multiple = basepayload->abidata.ABI.ptime_multiple;
713   priv->cached_min_length = *min_payload_len;
714   priv->cached_max_length = *max_payload_len;
715   priv->cached_align = *align;
716
717   return TRUE;
718 }
719
720 /* frame conversions functions */
721 static GstClockTime
722 gst_base_rtp_audio_payload_frame_bytes_to_time (GstBaseRTPAudioPayload *
723     payload, guint64 bytes)
724 {
725   guint64 framecount;
726
727   framecount = bytes / payload->frame_size;
728   if (G_UNLIKELY (bytes % payload->frame_size))
729     framecount++;
730
731   return framecount * payload->priv->frame_duration_ns;
732 }
733
734 static guint32
735 gst_base_rtp_audio_payload_frame_bytes_to_rtptime (GstBaseRTPAudioPayload *
736     payload, guint64 bytes)
737 {
738   guint64 framecount;
739   guint64 time;
740
741   framecount = bytes / payload->frame_size;
742   if (G_UNLIKELY (bytes % payload->frame_size))
743     framecount++;
744
745   time = framecount * payload->priv->frame_duration_ns;
746
747   return gst_util_uint64_scale_int (time,
748       GST_BASE_RTP_PAYLOAD (payload)->clock_rate, GST_SECOND);
749 }
750
751 static guint64
752 gst_base_rtp_audio_payload_frame_time_to_bytes (GstBaseRTPAudioPayload *
753     payload, GstClockTime time)
754 {
755   return gst_util_uint64_scale (time, payload->frame_size,
756       payload->priv->frame_duration_ns);
757 }
758
759 /* sample conversion functions */
760 static GstClockTime
761 gst_base_rtp_audio_payload_sample_bytes_to_time (GstBaseRTPAudioPayload *
762     payload, guint64 bytes)
763 {
764   guint64 rtptime;
765
766   /* avoid division when we can */
767   if (G_LIKELY (payload->sample_size != 8))
768     rtptime = gst_util_uint64_scale_int (bytes, 8, payload->sample_size);
769   else
770     rtptime = bytes;
771
772   return gst_util_uint64_scale_int (rtptime, GST_SECOND,
773       GST_BASE_RTP_PAYLOAD (payload)->clock_rate);
774 }
775
776 static guint32
777 gst_base_rtp_audio_payload_sample_bytes_to_rtptime (GstBaseRTPAudioPayload *
778     payload, guint64 bytes)
779 {
780   /* avoid division when we can */
781   if (G_LIKELY (payload->sample_size != 8))
782     return gst_util_uint64_scale_int (bytes, 8, payload->sample_size);
783   else
784     return bytes;
785 }
786
787 static guint64
788 gst_base_rtp_audio_payload_sample_time_to_bytes (GstBaseRTPAudioPayload *
789     payload, guint64 time)
790 {
791   guint64 samples;
792
793   samples = gst_util_uint64_scale_int (time,
794       GST_BASE_RTP_PAYLOAD (payload)->clock_rate, GST_SECOND);
795
796   /* avoid multiplication when we can */
797   if (G_LIKELY (payload->sample_size != 8))
798     return gst_util_uint64_scale_int (samples, payload->sample_size, 8);
799   else
800     return samples;
801 }
802
803 static GstFlowReturn
804 gst_base_rtp_audio_payload_handle_buffer (GstBaseRTPPayload *
805     basepayload, GstBuffer * buffer)
806 {
807   GstBaseRTPAudioPayload *payload;
808   GstBaseRTPAudioPayloadPrivate *priv;
809   guint payload_len;
810   GstFlowReturn ret;
811   guint available;
812   guint min_payload_len;
813   guint max_payload_len;
814   guint align;
815   guint size;
816   gboolean discont;
817   GstClockTime timestamp;
818
819   ret = GST_FLOW_OK;
820
821   payload = GST_BASE_RTP_AUDIO_PAYLOAD_CAST (basepayload);
822   priv = payload->priv;
823
824   timestamp = GST_BUFFER_TIMESTAMP (buffer);
825   discont = GST_BUFFER_IS_DISCONT (buffer);
826   if (discont) {
827
828     GST_DEBUG_OBJECT (payload, "Got DISCONT");
829     /* flush everything out of the adapter, mark DISCONT */
830     ret = gst_base_rtp_audio_payload_flush (payload, -1, -1);
831     priv->discont = TRUE;
832
833     /* get the distance between the timestamp gap and produce the same gap in
834      * the RTP timestamps */
835     if (priv->last_timestamp != -1 && timestamp != -1) {
836       /* we had a last timestamp, compare it to the new timestamp and update the
837        * offset counter for RTP timestamps. The effect is that we will produce
838        * output buffers containing the same RTP timestamp gap as the gap
839        * between the GST timestamps. */
840       if (timestamp > priv->last_timestamp) {
841         GstClockTime diff;
842         guint64 bytes;
843         /* we're only going to apply a positive gap, otherwise we let the marker
844          * bit do its thing. simply convert to bytes and add the the current
845          * offset */
846         diff = timestamp - priv->last_timestamp;
847         bytes = priv->time_to_bytes (payload, diff);
848         priv->offset += bytes;
849
850         GST_DEBUG_OBJECT (payload,
851             "elapsed time %" GST_TIME_FORMAT ", bytes %" G_GUINT64_FORMAT
852             ", new offset %" G_GUINT64_FORMAT, GST_TIME_ARGS (diff), bytes,
853             priv->offset);
854       }
855     }
856   }
857
858   if (!gst_base_rtp_audio_payload_get_lengths (basepayload, &min_payload_len,
859           &max_payload_len, &align))
860     goto config_error;
861
862   GST_DEBUG_OBJECT (payload,
863       "Calculated min_payload_len %u and max_payload_len %u",
864       min_payload_len, max_payload_len);
865
866   size = GST_BUFFER_SIZE (buffer);
867
868   /* shortcut, we don't need to use the adapter when the packet can be pushed
869    * through directly. */
870   available = gst_adapter_available (priv->adapter);
871
872   GST_DEBUG_OBJECT (payload, "got buffer size %u, available %u",
873       size, available);
874
875   if (available == 0 && (size >= min_payload_len && size <= max_payload_len) &&
876       (size % align == 0)) {
877     /* If buffer fits on an RTP packet, let's just push it through
878      * this will check against max_ptime and max_mtu */
879     GST_DEBUG_OBJECT (payload, "Fast packet push");
880     ret = gst_base_rtp_audio_payload_push_buffer (payload, buffer, timestamp);
881   } else {
882     /* push the buffer in the adapter */
883     gst_adapter_push (priv->adapter, buffer);
884     available += size;
885
886     GST_DEBUG_OBJECT (payload, "available now %u", available);
887
888     /* as long as we have full frames */
889     while (available >= min_payload_len) {
890       /* get multiple of alignment */
891       payload_len = MIN (max_payload_len, available);
892       payload_len = ALIGN_DOWN (payload_len, align);
893
894       /* and flush out the bytes from the adapter, automatically set the
895        * timestamp. */
896       ret = gst_base_rtp_audio_payload_flush (payload, payload_len, -1);
897
898       available -= payload_len;
899       GST_DEBUG_OBJECT (payload, "available after push %u", available);
900     }
901   }
902   return ret;
903
904   /* ERRORS */
905 config_error:
906   {
907     GST_ELEMENT_ERROR (payload, STREAM, NOT_IMPLEMENTED, (NULL),
908         ("subclass did not configure us properly"));
909     gst_buffer_unref (buffer);
910     return GST_FLOW_ERROR;
911   }
912 }
913
914 static GstStateChangeReturn
915 gst_base_rtp_payload_audio_change_state (GstElement * element,
916     GstStateChange transition)
917 {
918   GstBaseRTPAudioPayload *basertppayload;
919   GstStateChangeReturn ret;
920
921   basertppayload = GST_BASE_RTP_AUDIO_PAYLOAD (element);
922
923   switch (transition) {
924     case GST_STATE_CHANGE_READY_TO_PAUSED:
925       basertppayload->priv->cached_mtu = -1;
926       basertppayload->priv->last_rtptime = -1;
927       basertppayload->priv->last_timestamp = -1;
928       break;
929     default:
930       break;
931   }
932
933   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
934
935   switch (transition) {
936     case GST_STATE_CHANGE_PAUSED_TO_READY:
937       gst_adapter_clear (basertppayload->priv->adapter);
938       break;
939     default:
940       break;
941   }
942
943   return ret;
944 }
945
946 static gboolean
947 gst_base_rtp_payload_audio_handle_event (GstPad * pad, GstEvent * event)
948 {
949   GstBaseRTPAudioPayload *payload;
950   gboolean res = FALSE;
951
952   payload = GST_BASE_RTP_AUDIO_PAYLOAD (gst_pad_get_parent (pad));
953
954   switch (GST_EVENT_TYPE (event)) {
955     case GST_EVENT_EOS:
956       /* flush remaining bytes in the adapter */
957       gst_base_rtp_audio_payload_flush (payload, -1, -1);
958       break;
959     case GST_EVENT_FLUSH_STOP:
960       gst_adapter_clear (payload->priv->adapter);
961       break;
962     default:
963       break;
964   }
965
966   gst_object_unref (payload);
967
968   /* return FALSE to let parent handle the remainder of the event */
969   return res;
970 }
971
972 /**
973  * gst_base_rtp_audio_payload_get_adapter:
974  * @basertpaudiopayload: a #GstBaseRTPAudioPayload
975  *
976  * Gets the internal adapter used by the depayloader.
977  *
978  * Returns: a #GstAdapter.
979  *
980  * Since: 0.10.13
981  */
982 GstAdapter *
983 gst_base_rtp_audio_payload_get_adapter (GstBaseRTPAudioPayload
984     * basertpaudiopayload)
985 {
986   GstAdapter *adapter;
987
988   if ((adapter = basertpaudiopayload->priv->adapter))
989     g_object_ref (adapter);
990
991   return adapter;
992 }