2 * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
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.
24 #include <gst/tag/tag.h>
25 #include <gst/rtp/gstrtpbuffer.h>
28 #include "gstrtpvorbisdepay.h"
30 GST_DEBUG_CATEGORY_STATIC (rtpvorbisdepay_debug);
31 #define GST_CAT_DEFAULT (rtpvorbisdepay_debug)
34 * http://www.rfc-editor.org/rfc/rfc5215.txt
37 /* elementfactory information */
38 static const GstElementDetails gst_rtp_vorbis_depay_details =
39 GST_ELEMENT_DETAILS ("RTP Vorbis depayloader",
40 "Codec/Depayloader/Network",
41 "Extracts Vorbis Audio from RTP packets (RFC 5215)",
42 "Wim Taymans <wim.taymans@gmail.com>");
44 static GstStaticPadTemplate gst_rtp_vorbis_depay_sink_template =
45 GST_STATIC_PAD_TEMPLATE ("sink",
48 GST_STATIC_CAPS ("application/x-rtp, "
49 "media = (string) \"audio\", "
50 "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
51 "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"VORBIS\""
52 /* All required parameters
54 * "encoding-params = (string) <num channels>"
55 * "configuration = (string) ANY"
60 static GstStaticPadTemplate gst_rtp_vorbis_depay_src_template =
61 GST_STATIC_PAD_TEMPLATE ("src",
64 GST_STATIC_CAPS ("audio/x-vorbis")
67 GST_BOILERPLATE (GstRtpVorbisDepay, gst_rtp_vorbis_depay, GstBaseRTPDepayload,
68 GST_TYPE_BASE_RTP_DEPAYLOAD);
70 static gboolean gst_rtp_vorbis_depay_setcaps (GstBaseRTPDepayload * depayload,
72 static GstBuffer *gst_rtp_vorbis_depay_process (GstBaseRTPDepayload * depayload,
75 static void gst_rtp_vorbis_depay_finalize (GObject * object);
77 static GstStateChangeReturn gst_rtp_vorbis_depay_change_state (GstElement *
78 element, GstStateChange transition);
82 gst_rtp_vorbis_depay_base_init (gpointer klass)
84 GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
86 gst_element_class_add_pad_template (element_class,
87 gst_static_pad_template_get (&gst_rtp_vorbis_depay_sink_template));
88 gst_element_class_add_pad_template (element_class,
89 gst_static_pad_template_get (&gst_rtp_vorbis_depay_src_template));
91 gst_element_class_set_details (element_class, &gst_rtp_vorbis_depay_details);
95 gst_rtp_vorbis_depay_class_init (GstRtpVorbisDepayClass * klass)
97 GObjectClass *gobject_class;
98 GstElementClass *gstelement_class;
99 GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
101 gobject_class = (GObjectClass *) klass;
102 gstelement_class = (GstElementClass *) klass;
103 gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
105 gobject_class->finalize = gst_rtp_vorbis_depay_finalize;
107 gstelement_class->change_state = gst_rtp_vorbis_depay_change_state;
109 gstbasertpdepayload_class->process = gst_rtp_vorbis_depay_process;
110 gstbasertpdepayload_class->set_caps = gst_rtp_vorbis_depay_setcaps;
112 GST_DEBUG_CATEGORY_INIT (rtpvorbisdepay_debug, "rtpvorbisdepay", 0,
113 "Vorbis RTP Depayloader");
117 gst_rtp_vorbis_depay_init (GstRtpVorbisDepay * rtpvorbisdepay,
118 GstRtpVorbisDepayClass * klass)
120 rtpvorbisdepay->adapter = gst_adapter_new ();
123 gst_rtp_vorbis_depay_finalize (GObject * object)
125 GstRtpVorbisDepay *rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (object);
127 g_object_unref (rtpvorbisdepay->adapter);
129 G_OBJECT_CLASS (parent_class)->finalize (object);
132 static const guint8 a2bin[256] = {
133 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
134 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
135 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 64, 64, 63,
136 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64,
137 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
138 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 64,
139 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
140 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64,
141 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
142 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
143 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
144 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
145 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
146 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
147 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
148 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
152 decode_base64 (const gchar * in, guint8 * out)
157 v1 = a2bin[(gint) * in];
159 /* read 4 bytes, write 3 bytes, invalid base64 are zeroes */
160 v2 = a2bin[(gint) * ++in];
161 *out++ = (v1 << 2) | ((v2 & 0x3f) >> 4);
162 v1 = (v2 > 63 ? 64 : a2bin[(gint) * ++in]);
163 *out++ = (v2 << 4) | ((v1 & 0x3f) >> 2);
164 v2 = (v1 > 63 ? 64 : a2bin[(gint) * ++in]);
165 *out++ = (v1 << 6) | (v2 & 0x3f);
166 v1 = (v2 > 63 ? 64 : a2bin[(gint) * ++in]);
173 /* subtract padding */
174 while (len > 0 && *--in == '=')
181 gst_rtp_vorbis_depay_parse_configuration (GstRtpVorbisDepay * rtpvorbisdepay,
182 const gchar * configuration)
190 /* deserialize base64 to buffer */
191 size = strlen (configuration);
192 GST_DEBUG_OBJECT (rtpvorbisdepay, "base64 config size %u", size);
194 data = g_malloc (size);
195 size = decode_base64 (configuration, data);
197 GST_DEBUG_OBJECT (rtpvorbisdepay, "config size %u", size);
199 /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
200 * | Number of packed headers |
201 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
202 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
204 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
205 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
207 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
208 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
210 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
215 num_headers = GST_READ_UINT32_BE (data);
219 GST_DEBUG_OBJECT (rtpvorbisdepay, "have %u headers", num_headers);
222 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
223 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
224 * | Ident | length ..
225 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
226 * .. | n. of headers | length1 | length2 ..
227 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
228 * .. | Identification Header ..
229 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
230 * .................................................................
231 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
232 * .. | Comment Header ..
233 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
234 * .................................................................
235 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
236 * .. Comment Header |
237 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
239 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
240 * .................................................................
241 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
243 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
245 for (i = 0; i < num_headers; i++) {
249 GstRtpVorbisConfig *conf;
255 ident = (data[0] << 16) | (data[1] << 8) | data[2];
256 length = (data[3] << 8) | data[4];
261 GST_DEBUG_OBJECT (rtpvorbisdepay,
262 "header %d, ident 0x%08x, length %u, left %u", i, ident, length, size);
267 /* read header sizes we read 2 sizes, the third size (for which we allocate
268 * space) must be derived from the total packed header length. */
269 h_sizes = g_newa (guint, n_headers + 1);
270 for (j = 0; j < n_headers; j++) {
279 h_size = (h_size << 7) | (b & 0x7f);
281 GST_DEBUG_OBJECT (rtpvorbisdepay, "headers %d: size: %u", j, h_size);
285 /* last header length is the remaining space */
286 GST_DEBUG_OBJECT (rtpvorbisdepay, "last header size: %u", length);
289 GST_DEBUG_OBJECT (rtpvorbisdepay, "preparing headers");
290 conf = g_new0 (GstRtpVorbisConfig, 1);
293 for (j = 0; j <= n_headers; j++) {
300 GST_DEBUG_OBJECT (rtpvorbisdepay, "reading header %d, size %u", j,
303 buf = gst_buffer_new_and_alloc (h_size);
304 memcpy (GST_BUFFER_DATA (buf), data, h_size);
305 conf->headers = g_list_append (conf->headers, buf);
309 rtpvorbisdepay->configs = g_list_append (rtpvorbisdepay->configs, conf);
317 GST_DEBUG_OBJECT (rtpvorbisdepay, "configuration too small");
323 gst_rtp_vorbis_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
325 GstStructure *structure;
326 GstRtpVorbisDepay *rtpvorbisdepay;
328 const gchar *configuration;
332 rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (depayload);
334 structure = gst_caps_get_structure (caps, 0);
337 if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
340 /* read and parse configuration string */
341 configuration = gst_structure_get_string (structure, "configuration");
343 if (!gst_rtp_vorbis_depay_parse_configuration (rtpvorbisdepay,
345 goto invalid_configuration;
347 GST_WARNING_OBJECT (rtpvorbisdepay, "no configuration specified");
350 /* caps seem good, configure element */
351 depayload->clock_rate = clock_rate;
353 /* set caps on pad and on header */
354 srccaps = gst_caps_new_simple ("audio/x-vorbis", NULL);
355 res = gst_pad_set_caps (depayload->srcpad, srccaps);
356 gst_caps_unref (srccaps);
361 invalid_configuration:
363 GST_ERROR_OBJECT (rtpvorbisdepay, "invalid configuration specified");
368 GST_ERROR_OBJECT (rtpvorbisdepay, "no clock-rate specified");
374 gst_rtp_vorbis_depay_switch_codebook (GstRtpVorbisDepay * rtpvorbisdepay,
378 gboolean res = FALSE;
380 GST_DEBUG_OBJECT (rtpvorbisdepay, "Looking up code book ident 0x%08x", ident);
381 for (walk = rtpvorbisdepay->configs; walk; walk = g_list_next (walk)) {
382 GstRtpVorbisConfig *conf = (GstRtpVorbisConfig *) walk->data;
384 if (conf->ident == ident) {
387 /* FIXME, remove pads, create new pad.. */
389 /* push out all the headers */
390 for (headers = conf->headers; headers; headers = g_list_next (headers)) {
391 GstBuffer *header = GST_BUFFER_CAST (headers->data);
393 gst_buffer_ref (header);
394 gst_base_rtp_depayload_push (GST_BASE_RTP_DEPAYLOAD (rtpvorbisdepay),
397 /* remember the current config */
398 rtpvorbisdepay->config = conf;
403 /* we don't know about the headers, figure out an alternative method for
404 * getting the codebooks. FIXME, fail for now. */
410 gst_rtp_vorbis_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
412 GstRtpVorbisDepay *rtpvorbisdepay;
416 guint8 *payload, *to_free = NULL;
418 guint32 header, ident;
419 guint8 F, VDT, packets;
420 gboolean free_payload;
422 rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (depayload);
424 payload_len = gst_rtp_buffer_get_payload_len (buf);
426 GST_DEBUG_OBJECT (depayload, "got RTP packet of size %d", payload_len);
428 /* we need at least 4 bytes for the packet header */
429 if (G_UNLIKELY (payload_len < 4))
432 payload = gst_rtp_buffer_get_payload (buf);
433 free_payload = FALSE;
435 header = GST_READ_UINT32_BE (payload);
438 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
439 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
440 * | Ident | F |VDT|# pkts.|
441 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
443 * F: Fragment type (0=none, 1=start, 2=cont, 3=end)
444 * VDT: Vorbis data type (0=vorbis, 1=config, 2=comment, 3=reserved)
445 * pkts: number of packets.
447 VDT = (header & 0x30) >> 4;
448 if (G_UNLIKELY (VDT == 3))
449 goto ignore_reserved;
451 GST_DEBUG_OBJECT (depayload, "header: 0x%08x", header);
452 ident = (header >> 8) & 0xffffff;
453 F = (header & 0xc0) >> 6;
454 packets = (header & 0xf);
457 gboolean do_switch = FALSE;
459 /* we have a raw payload, find the codebook for the ident */
460 if (!rtpvorbisdepay->config) {
461 /* we don't have an active codebook, find the codebook and
463 GST_DEBUG_OBJECT (rtpvorbisdepay, "No active codebook, switching");
465 } else if (rtpvorbisdepay->config->ident != ident) {
466 /* codebook changed */
467 GST_DEBUG_OBJECT (rtpvorbisdepay, "codebook changed, switching");
471 if (!gst_rtp_vorbis_depay_switch_codebook (rtpvorbisdepay, ident))
480 GST_DEBUG_OBJECT (depayload, "ident: %u, F: %d, VDT: %d, packets: %d", ident,
483 /* fragmented packets, assemble */
489 /* if we start a packet, clear adapter and start assembling. */
490 gst_adapter_clear (rtpvorbisdepay->adapter);
491 GST_DEBUG_OBJECT (depayload, "start assemble");
492 rtpvorbisdepay->assembling = TRUE;
495 if (!rtpvorbisdepay->assembling)
498 /* first assembled packet, reuse 2 bytes to store the length */
499 headerskip = (F == 1 ? 4 : 6);
500 /* skip header and length. */
501 vdata = gst_rtp_buffer_get_payload_subbuffer (buf, headerskip, -1);
503 GST_DEBUG_OBJECT (depayload, "assemble vorbis packet");
504 gst_adapter_push (rtpvorbisdepay->adapter, vdata);
506 /* packet is not complete, we are done */
510 /* construct assembled buffer */
511 payload_len = gst_adapter_available (rtpvorbisdepay->adapter);
512 payload = gst_adapter_take (rtpvorbisdepay->adapter, payload_len);
514 payload[0] = ((payload_len - 2) >> 8) & 0xff;
515 payload[1] = (payload_len - 2) & 0xff;
519 GST_DEBUG_OBJECT (depayload, "assemble done");
521 /* we not assembling anymore now */
522 rtpvorbisdepay->assembling = FALSE;
523 gst_adapter_clear (rtpvorbisdepay->adapter);
525 /* payload now points to a length with that many vorbis data bytes.
526 * Iterate over the packets and send them out.
529 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
530 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
531 * | length | vorbis data ..
532 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
534 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
535 * | length | next vorbis packet data ..
536 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
538 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*
540 timestamp = gst_rtp_buffer_get_timestamp (buf);
542 while (payload_len > 2) {
545 length = GST_READ_UINT16_BE (payload);
549 GST_DEBUG_OBJECT (depayload, "read length %u, avail: %d", length,
552 /* skip packet if something odd happens */
553 if (G_UNLIKELY (length > payload_len))
556 /* create buffer for packet */
557 if (G_UNLIKELY (to_free)) {
558 outbuf = gst_buffer_new ();
559 GST_BUFFER_DATA (outbuf) = payload;
560 GST_BUFFER_MALLOCDATA (outbuf) = to_free;
561 GST_BUFFER_SIZE (outbuf) = length;
564 outbuf = gst_buffer_new_and_alloc (length);
565 memcpy (GST_BUFFER_DATA (outbuf), payload, length);
569 payload_len -= length;
572 /* push with timestamp of the last packet, which is the same timestamp that
573 * should apply to the first assembled packet. */
574 ret = gst_base_rtp_depayload_push_ts (depayload, timestamp, outbuf);
576 ret = gst_base_rtp_depayload_push (depayload, outbuf);
578 if (ret != GST_FLOW_OK)
581 /* make sure we don't set a timestamp on next buffers */
596 GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
597 (NULL), ("Could not switch codebooks"));
602 GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
603 (NULL), ("Packet was too short (%d < 4)", payload_len));
608 GST_WARNING_OBJECT (rtpvorbisdepay, "reserved VDT ignored");
613 GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
614 (NULL), ("Packet contains invalid data"));
619 static GstStateChangeReturn
620 gst_rtp_vorbis_depay_change_state (GstElement * element,
621 GstStateChange transition)
623 GstRtpVorbisDepay *rtpvorbisdepay;
624 GstStateChangeReturn ret;
626 rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (element);
628 switch (transition) {
629 case GST_STATE_CHANGE_NULL_TO_READY:
631 case GST_STATE_CHANGE_READY_TO_PAUSED:
637 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
639 switch (transition) {
640 case GST_STATE_CHANGE_READY_TO_NULL:
649 gst_rtp_vorbis_depay_plugin_init (GstPlugin * plugin)
651 return gst_element_register (plugin, "rtpvorbisdepay",
652 GST_RANK_MARGINAL, GST_TYPE_RTP_VORBIS_DEPAY);