2 * Copyright (C) <2006> Philippe Khalaf <philippe.kalaf@collabora.co.uk>
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.
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.
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.
21 * SECTION:gstbasertpaudiopayload
22 * @short_description: Base class for audio RTP payloader
26 * Provides a base class for audio RTP payloaders for frame or sample based
27 * audio codecs (constant bitrate)
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.
42 * <title>Usage</title>
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.
65 #include <gst/rtp/gstrtpbuffer.h>
66 #include <gst/base/gstadapter.h>
68 #include "gstbasertpaudiopayload.h"
70 GST_DEBUG_CATEGORY_STATIC (basertpaudiopayload_debug);
71 #define GST_CAT_DEFAULT (basertpaudiopayload_debug)
73 /* function to calculate the min/max length and alignment of a packet */
74 typedef gboolean (*GetLengthsFunc) (GstBaseRTPPayload * basepayload,
75 guint * min_payload_len, guint * max_payload_len, guint * align);
76 /* function to convert bytes to a duration */
77 typedef GstClockTime (*GetDurationFunc) (GstBaseRTPAudioPayload * payload,
80 struct _GstBaseRTPAudioPayloadPrivate
82 GetLengthsFunc get_lengths;
83 GetDurationFunc get_duration;
90 #define GST_BASE_RTP_AUDIO_PAYLOAD_GET_PRIVATE(o) \
91 (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_BASE_RTP_AUDIO_PAYLOAD, \
92 GstBaseRTPAudioPayloadPrivate))
94 static void gst_base_rtp_audio_payload_finalize (GObject * object);
96 /* length functions */
97 static gboolean gst_base_rtp_audio_payload_get_frame_lengths (GstBaseRTPPayload
98 * basepayload, guint * min_payload_len, guint * max_payload_len,
100 static gboolean gst_base_rtp_audio_payload_get_sample_lengths (GstBaseRTPPayload
101 * basepayload, guint * min_payload_len, guint * max_payload_len,
104 /* duration functions */
106 gst_base_rtp_audio_payload_get_frame_duration (GstBaseRTPAudioPayload * payload,
109 gst_base_rtp_audio_payload_get_sample_duration (GstBaseRTPAudioPayload *
110 payload, guint64 bytes);
112 static GstFlowReturn gst_base_rtp_audio_payload_handle_buffer (GstBaseRTPPayload
113 * payload, GstBuffer * buffer);
115 static GstStateChangeReturn gst_base_rtp_payload_audio_change_state (GstElement
116 * element, GstStateChange transition);
118 static gboolean gst_base_rtp_payload_audio_handle_event (GstPad * pad,
121 GST_BOILERPLATE (GstBaseRTPAudioPayload, gst_base_rtp_audio_payload,
122 GstBaseRTPPayload, GST_TYPE_BASE_RTP_PAYLOAD);
125 gst_base_rtp_audio_payload_base_init (gpointer klass)
130 gst_base_rtp_audio_payload_class_init (GstBaseRTPAudioPayloadClass * klass)
132 GObjectClass *gobject_class;
133 GstElementClass *gstelement_class;
134 GstBaseRTPPayloadClass *gstbasertppayload_class;
136 g_type_class_add_private (klass, sizeof (GstBaseRTPAudioPayloadPrivate));
138 gobject_class = (GObjectClass *) klass;
139 gstelement_class = (GstElementClass *) klass;
140 gstbasertppayload_class = (GstBaseRTPPayloadClass *) klass;
142 gobject_class->finalize =
143 GST_DEBUG_FUNCPTR (gst_base_rtp_audio_payload_finalize);
145 gstelement_class->change_state =
146 GST_DEBUG_FUNCPTR (gst_base_rtp_payload_audio_change_state);
148 gstbasertppayload_class->handle_buffer =
149 GST_DEBUG_FUNCPTR (gst_base_rtp_audio_payload_handle_buffer);
150 gstbasertppayload_class->handle_event =
151 GST_DEBUG_FUNCPTR (gst_base_rtp_payload_audio_handle_event);
153 GST_DEBUG_CATEGORY_INIT (basertpaudiopayload_debug, "basertpaudiopayload", 0,
154 "base audio RTP payloader");
158 gst_base_rtp_audio_payload_init (GstBaseRTPAudioPayload * basertpaudiopayload,
159 GstBaseRTPAudioPayloadClass * klass)
161 basertpaudiopayload->priv =
162 GST_BASE_RTP_AUDIO_PAYLOAD_GET_PRIVATE (basertpaudiopayload);
164 /* these need to be set by child object if frame based */
165 basertpaudiopayload->frame_size = 0;
166 basertpaudiopayload->frame_duration = 0;
168 /* these need to be set by child object if sample based */
169 basertpaudiopayload->sample_size = 0;
171 basertpaudiopayload->priv->adapter = gst_adapter_new ();
175 gst_base_rtp_audio_payload_finalize (GObject * object)
177 GstBaseRTPAudioPayload *basertpaudiopayload;
179 basertpaudiopayload = GST_BASE_RTP_AUDIO_PAYLOAD (object);
181 g_object_unref (basertpaudiopayload->priv->adapter);
183 GST_CALL_PARENT (G_OBJECT_CLASS, finalize, (object));
187 * gst_base_rtp_audio_payload_set_frame_based:
188 * @basertpaudiopayload: a pointer to the element.
190 * Tells #GstBaseRTPAudioPayload that the child element is for a frame based
194 gst_base_rtp_audio_payload_set_frame_based (GstBaseRTPAudioPayload *
197 g_return_if_fail (basertpaudiopayload != NULL);
198 g_return_if_fail (basertpaudiopayload->priv->get_lengths == NULL);
199 g_return_if_fail (basertpaudiopayload->priv->get_duration == NULL);
201 basertpaudiopayload->priv->get_lengths =
202 gst_base_rtp_audio_payload_get_frame_lengths;
203 basertpaudiopayload->priv->get_duration =
204 gst_base_rtp_audio_payload_get_frame_duration;
208 * gst_base_rtp_audio_payload_set_sample_based:
209 * @basertpaudiopayload: a pointer to the element.
211 * Tells #GstBaseRTPAudioPayload that the child element is for a sample based
215 gst_base_rtp_audio_payload_set_sample_based (GstBaseRTPAudioPayload *
218 g_return_if_fail (basertpaudiopayload != NULL);
219 g_return_if_fail (basertpaudiopayload->priv->get_lengths == NULL);
220 g_return_if_fail (basertpaudiopayload->priv->get_duration == NULL);
222 basertpaudiopayload->priv->get_lengths =
223 gst_base_rtp_audio_payload_get_sample_lengths;
224 basertpaudiopayload->priv->get_duration =
225 gst_base_rtp_audio_payload_get_sample_duration;
229 * gst_base_rtp_audio_payload_set_frame_options:
230 * @basertpaudiopayload: a pointer to the element.
231 * @frame_duration: The duraction of an audio frame in milliseconds.
232 * @frame_size: The size of an audio frame in bytes.
234 * Sets the options for frame based audio codecs.
238 gst_base_rtp_audio_payload_set_frame_options (GstBaseRTPAudioPayload
239 * basertpaudiopayload, gint frame_duration, gint frame_size)
241 g_return_if_fail (basertpaudiopayload != NULL);
243 basertpaudiopayload->frame_size = frame_size;
244 basertpaudiopayload->frame_duration = frame_duration;
246 gst_adapter_clear (basertpaudiopayload->priv->adapter);
250 * gst_base_rtp_audio_payload_set_sample_options:
251 * @basertpaudiopayload: a pointer to the element.
252 * @sample_size: Size per sample in bytes.
254 * Sets the options for sample based audio codecs.
257 gst_base_rtp_audio_payload_set_sample_options (GstBaseRTPAudioPayload
258 * basertpaudiopayload, gint sample_size)
260 g_return_if_fail (basertpaudiopayload != NULL);
262 /* sample_size is in bits internally */
263 gst_base_rtp_audio_payload_set_samplebits_options (basertpaudiopayload,
268 * gst_base_rtp_audio_payload_set_samplebits_options:
269 * @basertpaudiopayload: a pointer to the element.
270 * @sample_size: Size per sample in bits.
272 * Sets the options for sample based audio codecs.
277 gst_base_rtp_audio_payload_set_samplebits_options (GstBaseRTPAudioPayload
278 * basertpaudiopayload, gint sample_size)
282 g_return_if_fail (basertpaudiopayload != NULL);
284 basertpaudiopayload->sample_size = sample_size;
286 /* sample_size is in bits and is converted into multiple bytes */
287 fragment_size = sample_size;
288 while ((fragment_size % 8) != 0)
289 fragment_size += fragment_size;
290 basertpaudiopayload->priv->fragment_size = fragment_size / 8;
292 gst_adapter_clear (basertpaudiopayload->priv->adapter);
296 * gst_base_rtp_audio_payload_push:
297 * @baseaudiopayload: a #GstBaseRTPPayload
298 * @data: data to set as payload
299 * @payload_len: length of payload
300 * @timestamp: a #GstClockTime
302 * Create an RTP buffer and store @payload_len bytes of @data as the
303 * payload. Set the timestamp on the new buffer to @timestamp before pushing
304 * the buffer downstream.
306 * Returns: a #GstFlowReturn
311 gst_base_rtp_audio_payload_push (GstBaseRTPAudioPayload * baseaudiopayload,
312 const guint8 * data, guint payload_len, GstClockTime timestamp)
314 GstBaseRTPPayload *basepayload;
319 basepayload = GST_BASE_RTP_PAYLOAD (baseaudiopayload);
321 GST_DEBUG_OBJECT (baseaudiopayload, "Pushing %d bytes ts %" GST_TIME_FORMAT,
322 payload_len, GST_TIME_ARGS (timestamp));
324 /* create buffer to hold the payload */
325 outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
328 gst_rtp_buffer_set_payload_type (outbuf, basepayload->pt);
329 payload = gst_rtp_buffer_get_payload (outbuf);
330 memcpy (payload, data, payload_len);
332 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
333 ret = gst_basertppayload_push (basepayload, outbuf);
339 * gst_base_rtp_audio_payload_flush:
340 * @baseaudiopayload: a #GstBaseRTPPayload
341 * @payload_len: length of payload
342 * @timestamp: a #GstClockTime
344 * Create an RTP buffer and store @payload_len bytes of the adapter as the
345 * payload. Set the timestamp on the new buffer to @timestamp before pushing
346 * the buffer downstream.
348 * Returns: a #GstFlowReturn
353 gst_base_rtp_audio_payload_flush (GstBaseRTPAudioPayload * baseaudiopayload,
354 guint payload_len, GstClockTime timestamp)
356 GstBaseRTPPayload *basepayload;
361 basepayload = GST_BASE_RTP_PAYLOAD (baseaudiopayload);
363 GST_DEBUG_OBJECT (baseaudiopayload, "Pushing %d bytes ts %" GST_TIME_FORMAT,
364 payload_len, GST_TIME_ARGS (timestamp));
366 /* create buffer to hold the payload */
367 outbuf = gst_rtp_buffer_new_allocate (payload_len, 0, 0);
370 gst_rtp_buffer_set_payload_type (outbuf, basepayload->pt);
371 payload = gst_rtp_buffer_get_payload (outbuf);
372 gst_adapter_copy (baseaudiopayload->priv->adapter, payload, 0, payload_len);
373 gst_adapter_flush (baseaudiopayload->priv->adapter, payload_len);
375 GST_BUFFER_TIMESTAMP (outbuf) = timestamp;
376 ret = gst_basertppayload_push (basepayload, outbuf);
381 #define ALIGN_DOWN(val,len) ((val) - ((val) % (len)))
383 /* this assumes all frames have a constant duration and a constant size */
385 gst_base_rtp_audio_payload_get_frame_lengths (GstBaseRTPPayload *
386 basepayload, guint * min_payload_len, guint * max_payload_len,
389 GstBaseRTPAudioPayload *payload;
391 guint frame_duration;
393 guint maxptime_octets;
394 guint minptime_octets;
396 payload = GST_BASE_RTP_AUDIO_PAYLOAD_CAST (basepayload);
398 if (payload->frame_size == 0 || payload->frame_duration == 0)
401 *align = frame_size = payload->frame_size;
402 frame_duration = payload->frame_duration * GST_MSECOND;
404 if (basepayload->max_ptime != -1) {
406 gst_util_uint64_scale (frame_size, basepayload->max_ptime,
408 /* must be a multiple of the frame_size */
409 maxptime_octets = MAX (frame_size, maxptime_octets);
411 maxptime_octets = G_MAXUINT;
416 gst_rtp_buffer_calc_payload_len (GST_BASE_RTP_PAYLOAD_MTU (payload), 0,
418 /* round down to frame_size */
419 max_frames = ALIGN_DOWN (max_frames, frame_size);
420 /* max payload length */
421 *max_payload_len = MIN (max_frames, maxptime_octets);
423 /* min number of bytes based on a given ptime, has to be a multiple
426 gst_util_uint64_scale (frame_size, basepayload->min_ptime,
428 *min_payload_len = MAX (minptime_octets, frame_size);
430 if (*min_payload_len > *max_payload_len)
431 *min_payload_len = *max_payload_len;
437 gst_base_rtp_audio_payload_get_frame_duration (GstBaseRTPAudioPayload *
438 payload, guint64 bytes)
440 return gst_util_uint64_scale (bytes, payload->frame_duration * GST_MSECOND,
441 payload->frame_size);
445 gst_base_rtp_audio_payload_get_sample_lengths (GstBaseRTPPayload *
446 basepayload, guint * min_payload_len, guint * max_payload_len,
449 GstBaseRTPAudioPayload *payload;
450 guint maxptime_octets;
451 guint minptime_octets;
453 payload = GST_BASE_RTP_AUDIO_PAYLOAD_CAST (basepayload);
455 if (payload->sample_size == 0)
458 /* sample_size is in bits and is converted into multiple bytes */
459 *align = payload->priv->fragment_size;
461 /* max number of bytes based on given ptime */
462 if (basepayload->max_ptime != -1) {
463 maxptime_octets = gst_util_uint64_scale (basepayload->max_ptime * 8,
464 basepayload->clock_rate, payload->sample_size * GST_SECOND);
466 maxptime_octets = G_MAXUINT;
469 *max_payload_len = MIN (
471 gst_rtp_buffer_calc_payload_len (GST_BASE_RTP_PAYLOAD_MTU
476 /* min number of bytes based on a given ptime, has to be a multiple
478 minptime_octets = gst_util_uint64_scale (basepayload->min_ptime * 8,
479 basepayload->clock_rate, payload->sample_size * GST_SECOND);
481 *min_payload_len = MAX (minptime_octets, *align);
483 if (*min_payload_len > *max_payload_len)
484 *min_payload_len = *max_payload_len;
490 gst_base_rtp_audio_payload_get_sample_duration (GstBaseRTPAudioPayload *
491 payload, guint64 bytes)
493 return (bytes * 8 * GST_SECOND) /
494 (GST_BASE_RTP_PAYLOAD (payload)->clock_rate * payload->sample_size);
498 gst_base_rtp_audio_payload_handle_buffer (GstBaseRTPPayload *
499 basepayload, GstBuffer * buffer)
501 GstBaseRTPAudioPayload *payload;
505 guint min_payload_len;
506 guint max_payload_len;
512 payload = GST_BASE_RTP_AUDIO_PAYLOAD_CAST (basepayload);
514 if (payload->priv->get_lengths == NULL || payload->priv->get_duration == NULL)
517 if (!payload->priv->get_lengths (basepayload, &min_payload_len,
518 &max_payload_len, &align))
521 GST_DEBUG_OBJECT (payload,
522 "Calculated min_payload_len %u and max_payload_len %u",
523 min_payload_len, max_payload_len);
525 size = GST_BUFFER_SIZE (buffer);
527 /* shortcut, we don't need to use the adapter when the packet can be pushed
528 * through directly. */
529 available = gst_adapter_available (payload->priv->adapter);
531 GST_DEBUG_OBJECT (payload, "got buffer size %u, available %u",
534 if (available == 0 && (size >= min_payload_len && size <= max_payload_len)) {
535 /* If buffer fits on an RTP packet, let's just push it through
536 * this will check against max_ptime and max_mtu */
537 GST_DEBUG_OBJECT (payload, "Fast packet push");
538 ret = gst_base_rtp_audio_payload_push (payload,
539 GST_BUFFER_DATA (buffer), size, GST_BUFFER_TIMESTAMP (buffer));
540 gst_buffer_unref (buffer);
542 /* push the buffer in the adapter */
543 gst_adapter_push (payload->priv->adapter, buffer);
546 GST_DEBUG_OBJECT (payload, "available now %u", available);
548 /* as long as we have full frames */
549 while (available >= min_payload_len) {
551 GstClockTime timestamp;
553 payload_len = ALIGN_DOWN (available, align);
554 payload_len = MIN (max_payload_len, payload_len);
556 /* calculate the timestamp */
558 gst_adapter_prev_timestamp (payload->priv->adapter, &distance);
560 GST_LOG_OBJECT (payload,
561 "last timestamp %" GST_TIME_FORMAT ", distance %" G_GUINT64_FORMAT,
562 GST_TIME_ARGS (timestamp), distance);
564 if (GST_CLOCK_TIME_IS_VALID (timestamp) && distance > 0) {
565 /* convert the number of bytes since the last timestamp to time and add to
566 * the last seen timestamp */
567 timestamp += payload->priv->get_duration (payload, distance);
570 /* and flush out the bytes from the adapter */
571 ret = gst_base_rtp_audio_payload_flush (payload, payload_len, timestamp);
573 available -= payload_len;
574 GST_DEBUG_OBJECT (payload, "available after push %u", available);
582 GST_DEBUG_OBJECT (payload, "Required options not set");
583 gst_buffer_unref (buffer);
584 return GST_FLOW_ERROR;
588 static GstStateChangeReturn
589 gst_base_rtp_payload_audio_change_state (GstElement * element,
590 GstStateChange transition)
592 GstBaseRTPAudioPayload *basertppayload;
593 GstStateChangeReturn ret;
595 basertppayload = GST_BASE_RTP_AUDIO_PAYLOAD (element);
597 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
599 switch (transition) {
600 case GST_STATE_CHANGE_PAUSED_TO_READY:
601 gst_adapter_clear (basertppayload->priv->adapter);
611 gst_base_rtp_payload_audio_handle_event (GstPad * pad, GstEvent * event)
613 GstBaseRTPAudioPayload *payload;
614 gboolean res = FALSE;
616 payload = GST_BASE_RTP_AUDIO_PAYLOAD (gst_pad_get_parent (pad));
618 switch (GST_EVENT_TYPE (event)) {
620 /* FIXME. push remaining bytes? maybe not because it would violate the
622 gst_adapter_clear (payload->priv->adapter);
624 case GST_EVENT_FLUSH_STOP:
625 gst_adapter_clear (payload->priv->adapter);
631 gst_object_unref (payload);
633 /* return FALSE to let parent handle the remainder of the event */
638 * gst_base_rtp_audio_payload_get_adapter:
639 * @basertpaudiopayload: a #GstBaseRTPAudioPayload
641 * Gets the internal adapter used by the depayloader.
643 * Returns: a #GstAdapter.
648 gst_base_rtp_audio_payload_get_adapter (GstBaseRTPAudioPayload
649 * basertpaudiopayload)
653 if ((adapter = basertpaudiopayload->priv->adapter))
654 g_object_ref (adapter);