gst/rtp/: Fix the descriptions and fix some email addresses.
[platform/upstream/gstreamer.git] / gst / rtp / gstrtpvorbisdepay.c
1 /* GStreamer
2  * Copyright (C) <2006> Wim Taymans <wim.taymans@gmail.com>
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 #ifdef HAVE_CONFIG_H
21 #  include "config.h"
22 #endif
23
24 #include <gst/tag/tag.h>
25 #include <gst/rtp/gstrtpbuffer.h>
26
27 #include <string.h>
28 #include "gstrtpvorbisdepay.h"
29
30 GST_DEBUG_CATEGORY_STATIC (rtpvorbisdepay_debug);
31 #define GST_CAT_DEFAULT (rtpvorbisdepay_debug)
32
33 /* references:
34  * http://www.rfc-editor.org/rfc/rfc5215.txt
35  */
36
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>");
43
44 static GstStaticPadTemplate gst_rtp_vorbis_depay_sink_template =
45 GST_STATIC_PAD_TEMPLATE ("sink",
46     GST_PAD_SINK,
47     GST_PAD_ALWAYS,
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 
53          *
54          * "encoding-params = (string) <num channels>"
55          * "configuration = (string) ANY" 
56          */
57     )
58     );
59
60 static GstStaticPadTemplate gst_rtp_vorbis_depay_src_template =
61 GST_STATIC_PAD_TEMPLATE ("src",
62     GST_PAD_SRC,
63     GST_PAD_ALWAYS,
64     GST_STATIC_CAPS ("audio/x-vorbis")
65     );
66
67 GST_BOILERPLATE (GstRtpVorbisDepay, gst_rtp_vorbis_depay, GstBaseRTPDepayload,
68     GST_TYPE_BASE_RTP_DEPAYLOAD);
69
70 static gboolean gst_rtp_vorbis_depay_setcaps (GstBaseRTPDepayload * depayload,
71     GstCaps * caps);
72 static GstBuffer *gst_rtp_vorbis_depay_process (GstBaseRTPDepayload * depayload,
73     GstBuffer * buf);
74
75 static void gst_rtp_vorbis_depay_finalize (GObject * object);
76
77 static GstStateChangeReturn gst_rtp_vorbis_depay_change_state (GstElement *
78     element, GstStateChange transition);
79
80
81 static void
82 gst_rtp_vorbis_depay_base_init (gpointer klass)
83 {
84   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
85
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));
90
91   gst_element_class_set_details (element_class, &gst_rtp_vorbis_depay_details);
92 }
93
94 static void
95 gst_rtp_vorbis_depay_class_init (GstRtpVorbisDepayClass * klass)
96 {
97   GObjectClass *gobject_class;
98   GstElementClass *gstelement_class;
99   GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
100
101   gobject_class = (GObjectClass *) klass;
102   gstelement_class = (GstElementClass *) klass;
103   gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
104
105   gobject_class->finalize = gst_rtp_vorbis_depay_finalize;
106
107   gstelement_class->change_state = gst_rtp_vorbis_depay_change_state;
108
109   gstbasertpdepayload_class->process = gst_rtp_vorbis_depay_process;
110   gstbasertpdepayload_class->set_caps = gst_rtp_vorbis_depay_setcaps;
111
112   GST_DEBUG_CATEGORY_INIT (rtpvorbisdepay_debug, "rtpvorbisdepay", 0,
113       "Vorbis RTP Depayloader");
114 }
115
116 static void
117 gst_rtp_vorbis_depay_init (GstRtpVorbisDepay * rtpvorbisdepay,
118     GstRtpVorbisDepayClass * klass)
119 {
120   rtpvorbisdepay->adapter = gst_adapter_new ();
121 }
122 static void
123 gst_rtp_vorbis_depay_finalize (GObject * object)
124 {
125   GstRtpVorbisDepay *rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (object);
126
127   g_object_unref (rtpvorbisdepay->adapter);
128
129   G_OBJECT_CLASS (parent_class)->finalize (object);
130 }
131
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
149 };
150
151 static guint
152 decode_base64 (const gchar * in, guint8 * out)
153 {
154   guint8 v1, v2;
155   guint len = 0;
156
157   v1 = a2bin[(gint) * in];
158   while (v1 <= 63) {
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]);
167     len += 3;
168   }
169   /* move to '\0' */
170   while (*in != '\0')
171     in++;
172
173   /* subtract padding */
174   while (len > 0 && *--in == '=')
175     len--;
176
177   return len;
178 }
179
180 static gboolean
181 gst_rtp_vorbis_depay_parse_configuration (GstRtpVorbisDepay * rtpvorbisdepay,
182     const gchar * configuration)
183 {
184   GstBuffer *buf;
185   guint32 num_headers;
186   guint8 *data;
187   guint size;
188   gint i, j;
189
190   /* deserialize base64 to buffer */
191   size = strlen (configuration);
192   GST_DEBUG_OBJECT (rtpvorbisdepay, "base64 config size %u", size);
193
194   data = g_malloc (size);
195   size = decode_base64 (configuration, data);
196
197   GST_DEBUG_OBJECT (rtpvorbisdepay, "config size %u", size);
198
199   /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
200    * |                     Number of packed headers                  |
201    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
202    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
203    * |                          Packed header                        |
204    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
205    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
206    * |                          Packed header                        |
207    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
208    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
209    * |                          ....                                 |
210    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
211    */
212   if (size < 4)
213     goto too_small;
214
215   num_headers = GST_READ_UINT32_BE (data);
216   size -= 4;
217   data += 4;
218
219   GST_DEBUG_OBJECT (rtpvorbisdepay, "have %u headers", num_headers);
220
221   /*  0                   1                   2                   3
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    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
238    * |                          Setup Header                        ..
239    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
240    * .................................................................
241    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
242    * ..                         Setup Header                         |
243    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
244    */
245   for (i = 0; i < num_headers; i++) {
246     guint32 ident;
247     guint16 length;
248     guint8 n_headers, b;
249     GstRtpVorbisConfig *conf;
250     guint *h_sizes;
251
252     if (size < 6)
253       goto too_small;
254
255     ident = (data[0] << 16) | (data[1] << 8) | data[2];
256     length = (data[3] << 8) | data[4];
257     n_headers = data[5];
258     size -= 6;
259     data += 6;
260
261     GST_DEBUG_OBJECT (rtpvorbisdepay,
262         "header %d, ident 0x%08x, length %u, left %u", i, ident, length, size);
263
264     if (size < length)
265       goto too_small;
266
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++) {
271       guint h_size;
272
273       h_size = 0;
274       do {
275         if (size < 1)
276           goto too_small;
277         b = *data++;
278         size--;
279         h_size = (h_size << 7) | (b & 0x7f);
280       } while (b & 0x80);
281       GST_DEBUG_OBJECT (rtpvorbisdepay, "headers %d: size: %u", j, h_size);
282       h_sizes[j] = h_size;
283       length -= h_size;
284     }
285     /* last header length is the remaining space */
286     GST_DEBUG_OBJECT (rtpvorbisdepay, "last header size: %u", length);
287     h_sizes[j] = length;
288
289     GST_DEBUG_OBJECT (rtpvorbisdepay, "preparing headers");
290     conf = g_new0 (GstRtpVorbisConfig, 1);
291     conf->ident = ident;
292
293     for (j = 0; j <= n_headers; j++) {
294       guint h_size;
295
296       h_size = h_sizes[j];
297       if (size < h_size)
298         goto too_small;
299
300       GST_DEBUG_OBJECT (rtpvorbisdepay, "reading header %d, size %u", j,
301           h_size);
302
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);
306       data += h_size;
307       size -= h_size;
308     }
309     rtpvorbisdepay->configs = g_list_append (rtpvorbisdepay->configs, conf);
310   }
311
312   return TRUE;
313
314   /* ERRORS */
315 too_small:
316   {
317     GST_DEBUG_OBJECT (rtpvorbisdepay, "configuration too small");
318     return FALSE;
319   }
320 }
321
322 static gboolean
323 gst_rtp_vorbis_depay_setcaps (GstBaseRTPDepayload * depayload, GstCaps * caps)
324 {
325   GstStructure *structure;
326   GstRtpVorbisDepay *rtpvorbisdepay;
327   GstCaps *srccaps;
328   const gchar *configuration;
329   gint clock_rate;
330   gboolean res;
331
332   rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (depayload);
333
334   structure = gst_caps_get_structure (caps, 0);
335
336   /* get clockrate */
337   if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
338     goto no_rate;
339
340   /* read and parse configuration string */
341   configuration = gst_structure_get_string (structure, "configuration");
342   if (configuration) {
343     if (!gst_rtp_vorbis_depay_parse_configuration (rtpvorbisdepay,
344             configuration))
345       goto invalid_configuration;
346   } else {
347     GST_WARNING_OBJECT (rtpvorbisdepay, "no configuration specified");
348   }
349
350   /* caps seem good, configure element */
351   depayload->clock_rate = clock_rate;
352
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);
357
358   return res;
359
360   /* ERRORS */
361 invalid_configuration:
362   {
363     GST_ERROR_OBJECT (rtpvorbisdepay, "invalid configuration specified");
364     return FALSE;
365   }
366 no_rate:
367   {
368     GST_ERROR_OBJECT (rtpvorbisdepay, "no clock-rate specified");
369     return FALSE;
370   }
371 }
372
373 static gboolean
374 gst_rtp_vorbis_depay_switch_codebook (GstRtpVorbisDepay * rtpvorbisdepay,
375     guint32 ident)
376 {
377   GList *walk;
378   gboolean res = FALSE;
379
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;
383
384     if (conf->ident == ident) {
385       GList *headers;
386
387       /* FIXME, remove pads, create new pad.. */
388
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);
392
393         gst_buffer_ref (header);
394         gst_base_rtp_depayload_push (GST_BASE_RTP_DEPAYLOAD (rtpvorbisdepay),
395             header);
396       }
397       /* remember the current config */
398       rtpvorbisdepay->config = conf;
399       res = TRUE;
400     }
401   }
402   if (!res) {
403     /* we don't know about the headers, figure out an alternative method for
404      * getting the codebooks. FIXME, fail for now. */
405   }
406   return res;
407 }
408
409 static GstBuffer *
410 gst_rtp_vorbis_depay_process (GstBaseRTPDepayload * depayload, GstBuffer * buf)
411 {
412   GstRtpVorbisDepay *rtpvorbisdepay;
413   GstBuffer *outbuf;
414   GstFlowReturn ret;
415   gint payload_len;
416   guint8 *payload, *to_free = NULL;
417   guint32 timestamp;
418   guint32 header, ident;
419   guint8 F, VDT, packets;
420   gboolean free_payload;
421
422   rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (depayload);
423
424   payload_len = gst_rtp_buffer_get_payload_len (buf);
425
426   GST_DEBUG_OBJECT (depayload, "got RTP packet of size %d", payload_len);
427
428   /* we need at least 4 bytes for the packet header */
429   if (G_UNLIKELY (payload_len < 4))
430     goto packet_short;
431
432   payload = gst_rtp_buffer_get_payload (buf);
433   free_payload = FALSE;
434
435   header = GST_READ_UINT32_BE (payload);
436   /*
437    *  0                   1                   2                   3
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    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
442    *
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.
446    */
447   VDT = (header & 0x30) >> 4;
448   if (G_UNLIKELY (VDT == 3))
449     goto ignore_reserved;
450
451   GST_DEBUG_OBJECT (depayload, "header: 0x%08x", header);
452   ident = (header >> 8) & 0xffffff;
453   F = (header & 0xc0) >> 6;
454   packets = (header & 0xf);
455
456   if (VDT == 0) {
457     gboolean do_switch = FALSE;
458
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
462        * activate it */
463       GST_DEBUG_OBJECT (rtpvorbisdepay, "No active codebook, switching");
464       do_switch = TRUE;
465     } else if (rtpvorbisdepay->config->ident != ident) {
466       /* codebook changed */
467       GST_DEBUG_OBJECT (rtpvorbisdepay, "codebook changed, switching");
468       do_switch = TRUE;
469     }
470     if (do_switch) {
471       if (!gst_rtp_vorbis_depay_switch_codebook (rtpvorbisdepay, ident))
472         goto switch_failed;
473     }
474   }
475
476   /* skip header */
477   payload += 4;
478   payload_len -= 4;
479
480   GST_DEBUG_OBJECT (depayload, "ident: %u, F: %d, VDT: %d, packets: %d", ident,
481       F, VDT, packets);
482
483   /* fragmented packets, assemble */
484   if (F != 0) {
485     GstBuffer *vdata;
486     guint headerskip;
487
488     if (F == 1) {
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;
493     }
494
495     if (!rtpvorbisdepay->assembling)
496       goto no_output;
497
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);
502
503     GST_DEBUG_OBJECT (depayload, "assemble vorbis packet");
504     gst_adapter_push (rtpvorbisdepay->adapter, vdata);
505
506     /* packet is not complete, we are done */
507     if (F != 3)
508       goto no_output;
509
510     /* construct assembled buffer */
511     payload_len = gst_adapter_available (rtpvorbisdepay->adapter);
512     payload = gst_adapter_take (rtpvorbisdepay->adapter, payload_len);
513     /* fix the length */
514     payload[0] = ((payload_len - 2) >> 8) & 0xff;
515     payload[1] = (payload_len - 2) & 0xff;
516     to_free = payload;
517   }
518
519   GST_DEBUG_OBJECT (depayload, "assemble done");
520
521   /* we not assembling anymore now */
522   rtpvorbisdepay->assembling = FALSE;
523   gst_adapter_clear (rtpvorbisdepay->adapter);
524
525   /* payload now points to a length with that many vorbis data bytes.
526    * Iterate over the packets and send them out.
527    *
528    *  0                   1                   2                   3
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    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
533    * ..                        vorbis data                           |
534    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
535    * |            length             |   next vorbis packet data    ..
536    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
537    * ..                        vorbis data                           |
538    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*
539    */
540   timestamp = gst_rtp_buffer_get_timestamp (buf);
541
542   while (payload_len > 2) {
543     guint16 length;
544
545     length = GST_READ_UINT16_BE (payload);
546     payload += 2;
547     payload_len -= 2;
548
549     GST_DEBUG_OBJECT (depayload, "read length %u, avail: %d", length,
550         payload_len);
551
552     /* skip packet if something odd happens */
553     if (G_UNLIKELY (length > payload_len))
554       goto length_short;
555
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;
562       to_free = NULL;
563     } else {
564       outbuf = gst_buffer_new_and_alloc (length);
565       memcpy (GST_BUFFER_DATA (outbuf), payload, length);
566     }
567
568     payload += length;
569     payload_len -= length;
570
571     if (timestamp != -1)
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);
575     else
576       ret = gst_base_rtp_depayload_push (depayload, outbuf);
577
578     if (ret != GST_FLOW_OK)
579       break;
580
581     /* make sure we don't set a timestamp on next buffers */
582     timestamp = -1;
583   }
584
585   g_free (to_free);
586
587   return NULL;
588
589 no_output:
590   {
591     return NULL;
592   }
593   /* ERORRS */
594 switch_failed:
595   {
596     GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
597         (NULL), ("Could not switch codebooks"));
598     return NULL;
599   }
600 packet_short:
601   {
602     GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
603         (NULL), ("Packet was too short (%d < 4)", payload_len));
604     return NULL;
605   }
606 ignore_reserved:
607   {
608     GST_WARNING_OBJECT (rtpvorbisdepay, "reserved VDT ignored");
609     return NULL;
610   }
611 length_short:
612   {
613     GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
614         (NULL), ("Packet contains invalid data"));
615     return NULL;
616   }
617 }
618
619 static GstStateChangeReturn
620 gst_rtp_vorbis_depay_change_state (GstElement * element,
621     GstStateChange transition)
622 {
623   GstRtpVorbisDepay *rtpvorbisdepay;
624   GstStateChangeReturn ret;
625
626   rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (element);
627
628   switch (transition) {
629     case GST_STATE_CHANGE_NULL_TO_READY:
630       break;
631     case GST_STATE_CHANGE_READY_TO_PAUSED:
632       break;
633     default:
634       break;
635   }
636
637   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
638
639   switch (transition) {
640     case GST_STATE_CHANGE_READY_TO_NULL:
641       break;
642     default:
643       break;
644   }
645   return ret;
646 }
647
648 gboolean
649 gst_rtp_vorbis_depay_plugin_init (GstPlugin * plugin)
650 {
651   return gst_element_register (plugin, "rtpvorbisdepay",
652       GST_RANK_MARGINAL, GST_TYPE_RTP_VORBIS_DEPAY);
653 }