Merge branch 'master' into 0.11
[platform/upstream/gst-plugins-good.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 static GstStaticPadTemplate gst_rtp_vorbis_depay_sink_template =
38 GST_STATIC_PAD_TEMPLATE ("sink",
39     GST_PAD_SINK,
40     GST_PAD_ALWAYS,
41     GST_STATIC_CAPS ("application/x-rtp, "
42         "media = (string) \"audio\", "
43         "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
44         "clock-rate = (int) [1, MAX ], " "encoding-name = (string) \"VORBIS\""
45         /* All required parameters 
46          *
47          * "encoding-params = (string) <num channels>"
48          * "configuration = (string) ANY" 
49          */
50     )
51     );
52
53 static GstStaticPadTemplate gst_rtp_vorbis_depay_src_template =
54 GST_STATIC_PAD_TEMPLATE ("src",
55     GST_PAD_SRC,
56     GST_PAD_ALWAYS,
57     GST_STATIC_CAPS ("audio/x-vorbis")
58     );
59
60 #define gst_rtp_vorbis_depay_parent_class parent_class
61 G_DEFINE_TYPE (GstRtpVorbisDepay, gst_rtp_vorbis_depay,
62     GST_TYPE_RTP_BASE_DEPAYLOAD);
63
64 static gboolean gst_rtp_vorbis_depay_setcaps (GstRTPBaseDepayload * depayload,
65     GstCaps * caps);
66 static GstBuffer *gst_rtp_vorbis_depay_process (GstRTPBaseDepayload * depayload,
67     GstBuffer * buf);
68
69 static void gst_rtp_vorbis_depay_finalize (GObject * object);
70
71 static GstStateChangeReturn gst_rtp_vorbis_depay_change_state (GstElement *
72     element, GstStateChange transition);
73
74 static void
75 gst_rtp_vorbis_depay_class_init (GstRtpVorbisDepayClass * klass)
76 {
77   GObjectClass *gobject_class;
78   GstElementClass *gstelement_class;
79   GstRTPBaseDepayloadClass *gstrtpbasedepayload_class;
80
81   gobject_class = (GObjectClass *) klass;
82   gstelement_class = (GstElementClass *) klass;
83   gstrtpbasedepayload_class = (GstRTPBaseDepayloadClass *) klass;
84
85   gobject_class->finalize = gst_rtp_vorbis_depay_finalize;
86
87   gstelement_class->change_state = gst_rtp_vorbis_depay_change_state;
88
89   gstrtpbasedepayload_class->process = gst_rtp_vorbis_depay_process;
90   gstrtpbasedepayload_class->set_caps = gst_rtp_vorbis_depay_setcaps;
91
92   gst_element_class_add_pad_template (gstelement_class,
93       gst_static_pad_template_get (&gst_rtp_vorbis_depay_sink_template));
94   gst_element_class_add_pad_template (gstelement_class,
95       gst_static_pad_template_get (&gst_rtp_vorbis_depay_src_template));
96
97   gst_element_class_set_details_simple (gstelement_class,
98       "RTP Vorbis depayloader", "Codec/Depayloader/Network/RTP",
99       "Extracts Vorbis Audio from RTP packets (RFC 5215)",
100       "Wim Taymans <wim.taymans@gmail.com>");
101
102   GST_DEBUG_CATEGORY_INIT (rtpvorbisdepay_debug, "rtpvorbisdepay", 0,
103       "Vorbis RTP Depayloader");
104 }
105
106 static void
107 gst_rtp_vorbis_depay_init (GstRtpVorbisDepay * rtpvorbisdepay)
108 {
109   rtpvorbisdepay->adapter = gst_adapter_new ();
110 }
111
112 static void
113 free_config (GstRtpVorbisConfig * conf)
114 {
115   GList *headers;
116
117   for (headers = conf->headers; headers; headers = g_list_next (headers)) {
118     GstBuffer *header = GST_BUFFER_CAST (headers->data);
119
120     gst_buffer_unref (header);
121   }
122   g_list_free (conf->headers);
123   g_free (conf);
124 }
125
126 static void
127 free_indents (GstRtpVorbisDepay * rtpvorbisdepay)
128 {
129   GList *walk;
130
131   for (walk = rtpvorbisdepay->configs; walk; walk = g_list_next (walk)) {
132     free_config ((GstRtpVorbisConfig *) walk->data);
133   }
134   g_list_free (rtpvorbisdepay->configs);
135   rtpvorbisdepay->configs = NULL;
136 }
137
138 static void
139 gst_rtp_vorbis_depay_finalize (GObject * object)
140 {
141   GstRtpVorbisDepay *rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (object);
142
143   g_object_unref (rtpvorbisdepay->adapter);
144
145   G_OBJECT_CLASS (parent_class)->finalize (object);
146 }
147
148 /* takes ownership of confbuf */
149 static gboolean
150 gst_rtp_vorbis_depay_parse_configuration (GstRtpVorbisDepay * rtpvorbisdepay,
151     GstBuffer * confbuf)
152 {
153   GstBuffer *buf;
154   guint32 num_headers;
155   guint8 *data, *bdata;
156   gsize size;
157   guint offset;
158   gint i, j;
159
160   bdata = data = gst_buffer_map (confbuf, &size, NULL, GST_MAP_READ);
161
162   GST_DEBUG_OBJECT (rtpvorbisdepay, "config size %" G_GSIZE_FORMAT, size);
163
164   /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
165    * |                     Number of packed headers                  |
166    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
167    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
168    * |                          Packed header                        |
169    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
170    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
171    * |                          Packed header                        |
172    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
173    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
174    * |                          ....                                 |
175    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
176    */
177   if (size < 4)
178     goto too_small;
179
180   num_headers = GST_READ_UINT32_BE (data);
181   size -= 4;
182   data += 4;
183   offset = 4;
184
185   GST_DEBUG_OBJECT (rtpvorbisdepay, "have %u headers", num_headers);
186
187   /*  0                   1                   2                   3
188    *  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
189    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
190    * |                   Ident                       | length       ..
191    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
192    * ..              | n. of headers |    length1    |    length2   ..
193    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
194    * ..              |             Identification Header            ..
195    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
196    * .................................................................
197    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
198    * ..              |         Comment Header                       ..
199    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
200    * .................................................................
201    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
202    * ..                        Comment Header                        |
203    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
204    * |                          Setup Header                        ..
205    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
206    * .................................................................
207    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
208    * ..                         Setup Header                         |
209    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
210    */
211   for (i = 0; i < num_headers; i++) {
212     guint32 ident;
213     guint16 length;
214     guint8 n_headers, b;
215     GstRtpVorbisConfig *conf;
216     guint *h_sizes;
217     guint extra = 1;
218
219     if (size < 6)
220       goto too_small;
221
222     ident = (data[0] << 16) | (data[1] << 8) | data[2];
223     length = (data[3] << 8) | data[4];
224     n_headers = data[5];
225     size -= 6;
226     data += 6;
227     offset += 6;
228
229     GST_DEBUG_OBJECT (rtpvorbisdepay,
230         "header %d, ident 0x%08x, length %u, left %" G_GSIZE_FORMAT, i, ident,
231         length, size);
232
233     /* FIXME check if we already got this ident */
234
235     /* length might also include count of following size fields */
236     if (size < length && size + 1 != length)
237       goto too_small;
238
239     /* read header sizes we read 2 sizes, the third size (for which we allocate
240      * space) must be derived from the total packed header length. */
241     h_sizes = g_newa (guint, n_headers + 1);
242     for (j = 0; j < n_headers; j++) {
243       guint h_size;
244
245       h_size = 0;
246       do {
247         if (size < 1)
248           goto too_small;
249         b = *data++;
250         offset++;
251         extra++;
252         size--;
253         h_size = (h_size << 7) | (b & 0x7f);
254       } while (b & 0x80);
255       GST_DEBUG_OBJECT (rtpvorbisdepay, "headers %d: size: %u", j, h_size);
256
257       if (length < h_size)
258         goto too_small;
259
260       h_sizes[j] = h_size;
261       length -= h_size;
262     }
263     /* last header length is the remaining space */
264     GST_DEBUG_OBJECT (rtpvorbisdepay, "last header size: %u", length);
265     h_sizes[j] = length;
266
267     GST_DEBUG_OBJECT (rtpvorbisdepay, "preparing headers");
268     conf = g_new0 (GstRtpVorbisConfig, 1);
269     conf->ident = ident;
270
271     for (j = 0; j <= n_headers; j++) {
272       guint h_size;
273
274       h_size = h_sizes[j];
275       if (size < h_size) {
276         if (j != n_headers || size + extra != h_size) {
277           free_config (conf);
278           goto too_small;
279         } else {
280           /* otherwise means that overall length field contained total length,
281            * including extra fields */
282           h_size -= extra;
283         }
284       }
285
286       GST_DEBUG_OBJECT (rtpvorbisdepay, "reading header %d, size %u", j,
287           h_size);
288
289       buf = gst_buffer_copy_region (confbuf, GST_BUFFER_COPY_MEMORY, offset,
290           h_size);
291       conf->headers = g_list_append (conf->headers, buf);
292       offset += h_size;
293       size -= h_size;
294     }
295     rtpvorbisdepay->configs = g_list_append (rtpvorbisdepay->configs, conf);
296   }
297
298   gst_buffer_unmap (confbuf, bdata, -1);
299   gst_buffer_unref (confbuf);
300
301   return TRUE;
302
303   /* ERRORS */
304 too_small:
305   {
306     GST_DEBUG_OBJECT (rtpvorbisdepay, "configuration too small");
307     gst_buffer_unmap (confbuf, bdata, -1);
308     gst_buffer_unref (confbuf);
309     return FALSE;
310   }
311 }
312
313 static gboolean
314 gst_rtp_vorbis_depay_parse_inband_configuration (GstRtpVorbisDepay *
315     rtpvorbisdepay, guint ident, guint8 * configuration, guint size,
316     guint length)
317 {
318   GstBuffer *confbuf;
319   guint8 *conf;
320
321   if (G_UNLIKELY (size < 4))
322     return FALSE;
323
324   /* transform inline to out-of-band and parse that one */
325   confbuf = gst_buffer_new_and_alloc (size + 9);
326   conf = gst_buffer_map (confbuf, NULL, NULL, -1);
327   /* 1 header */
328   GST_WRITE_UINT32_BE (conf, 1);
329   /* write Ident */
330   GST_WRITE_UINT24_BE (conf + 4, ident);
331   /* write sort-of-length */
332   GST_WRITE_UINT16_BE (conf + 7, length);
333   /* copy remainder */
334   memcpy (conf + 9, configuration, size);
335   gst_buffer_unmap (confbuf, conf, -1);
336
337   return gst_rtp_vorbis_depay_parse_configuration (rtpvorbisdepay, confbuf);
338 }
339
340 static gboolean
341 gst_rtp_vorbis_depay_setcaps (GstRTPBaseDepayload * depayload, GstCaps * caps)
342 {
343   GstStructure *structure;
344   GstRtpVorbisDepay *rtpvorbisdepay;
345   GstCaps *srccaps;
346   const gchar *configuration;
347   gint clock_rate;
348   gboolean res;
349
350   rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (depayload);
351
352   structure = gst_caps_get_structure (caps, 0);
353
354   /* get clockrate */
355   if (!gst_structure_get_int (structure, "clock-rate", &clock_rate))
356     goto no_rate;
357
358   /* read and parse configuration string */
359   configuration = gst_structure_get_string (structure, "configuration");
360   if (configuration) {
361     GstBuffer *confbuf;
362     guint8 *data;
363     gsize size;
364
365     /* deserialize base64 to buffer */
366     data = g_base64_decode (configuration, &size);
367
368     confbuf = gst_buffer_new ();
369     gst_buffer_take_memory (confbuf, -1,
370         gst_memory_new_wrapped (0, data, g_free, size, 0, size));
371     if (!gst_rtp_vorbis_depay_parse_configuration (rtpvorbisdepay, confbuf))
372       goto invalid_configuration;
373   } else {
374     GST_WARNING_OBJECT (rtpvorbisdepay, "no configuration specified");
375   }
376
377   /* caps seem good, configure element */
378   depayload->clock_rate = clock_rate;
379
380   /* set caps on pad and on header */
381   srccaps = gst_caps_new_empty_simple ("audio/x-vorbis");
382   res = gst_pad_set_caps (depayload->srcpad, srccaps);
383   gst_caps_unref (srccaps);
384
385   return res;
386
387   /* ERRORS */
388 invalid_configuration:
389   {
390     GST_ERROR_OBJECT (rtpvorbisdepay, "invalid configuration specified");
391     return FALSE;
392   }
393 no_rate:
394   {
395     GST_ERROR_OBJECT (rtpvorbisdepay, "no clock-rate specified");
396     return FALSE;
397   }
398 }
399
400 static gboolean
401 gst_rtp_vorbis_depay_switch_codebook (GstRtpVorbisDepay * rtpvorbisdepay,
402     guint32 ident)
403 {
404   GList *walk;
405   gboolean res = FALSE;
406
407   GST_DEBUG_OBJECT (rtpvorbisdepay, "Looking up code book ident 0x%08x", ident);
408   for (walk = rtpvorbisdepay->configs; walk; walk = g_list_next (walk)) {
409     GstRtpVorbisConfig *conf = (GstRtpVorbisConfig *) walk->data;
410
411     if (conf->ident == ident) {
412       GList *headers;
413
414       /* FIXME, remove pads, create new pad.. */
415
416       /* push out all the headers */
417       for (headers = conf->headers; headers; headers = g_list_next (headers)) {
418         GstBuffer *header = GST_BUFFER_CAST (headers->data);
419
420         gst_buffer_ref (header);
421         gst_rtp_base_depayload_push (GST_RTP_BASE_DEPAYLOAD (rtpvorbisdepay),
422             header);
423       }
424       /* remember the current config */
425       rtpvorbisdepay->config = conf;
426       res = TRUE;
427     }
428   }
429   if (!res) {
430     /* we don't know about the headers, figure out an alternative method for
431      * getting the codebooks. FIXME, fail for now. */
432   }
433   return res;
434 }
435
436 static GstBuffer *
437 gst_rtp_vorbis_depay_process (GstRTPBaseDepayload * depayload, GstBuffer * buf)
438 {
439   GstRtpVorbisDepay *rtpvorbisdepay;
440   GstBuffer *outbuf;
441   GstFlowReturn ret;
442   gint payload_len;
443   guint8 *payload, *to_free = NULL;
444   guint32 header, ident;
445   guint8 F, VDT, packets;
446   GstRTPBuffer rtp;
447
448   rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (depayload);
449
450   gst_rtp_buffer_map (buf, GST_MAP_READ, &rtp);
451
452   payload_len = gst_rtp_buffer_get_payload_len (&rtp);
453
454   GST_DEBUG_OBJECT (depayload, "got RTP packet of size %d", payload_len);
455
456   /* we need at least 4 bytes for the packet header */
457   if (G_UNLIKELY (payload_len < 4))
458     goto packet_short;
459
460   payload = gst_rtp_buffer_get_payload (&rtp);
461
462   header = GST_READ_UINT32_BE (payload);
463   /*
464    *  0                   1                   2                   3
465    *  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
466    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
467    * |                     Ident                     | F |VDT|# pkts.|
468    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
469    *
470    * F: Fragment type (0=none, 1=start, 2=cont, 3=end)
471    * VDT: Vorbis data type (0=vorbis, 1=config, 2=comment, 3=reserved)
472    * pkts: number of packets.
473    */
474   VDT = (header & 0x30) >> 4;
475   if (G_UNLIKELY (VDT == 3))
476     goto ignore_reserved;
477
478   GST_DEBUG_OBJECT (depayload, "header: 0x%08x", header);
479   ident = (header >> 8) & 0xffffff;
480   F = (header & 0xc0) >> 6;
481   packets = (header & 0xf);
482
483   if (VDT == 0) {
484     gboolean do_switch = FALSE;
485
486     /* we have a raw payload, find the codebook for the ident */
487     if (!rtpvorbisdepay->config) {
488       /* we don't have an active codebook, find the codebook and
489        * activate it */
490       GST_DEBUG_OBJECT (rtpvorbisdepay, "No active codebook, switching");
491       do_switch = TRUE;
492     } else if (rtpvorbisdepay->config->ident != ident) {
493       /* codebook changed */
494       GST_DEBUG_OBJECT (rtpvorbisdepay, "codebook changed, switching");
495       do_switch = TRUE;
496     }
497     if (do_switch) {
498       if (!gst_rtp_vorbis_depay_switch_codebook (rtpvorbisdepay, ident))
499         goto switch_failed;
500     }
501   }
502
503   /* skip header */
504   payload += 4;
505   payload_len -= 4;
506
507   GST_DEBUG_OBJECT (depayload, "ident: %u, F: %d, VDT: %d, packets: %d", ident,
508       F, VDT, packets);
509
510   /* fragmented packets, assemble */
511   if (F != 0) {
512     GstBuffer *vdata;
513     guint headerskip;
514
515     if (F == 1) {
516       /* if we start a packet, clear adapter and start assembling. */
517       gst_adapter_clear (rtpvorbisdepay->adapter);
518       GST_DEBUG_OBJECT (depayload, "start assemble");
519       rtpvorbisdepay->assembling = TRUE;
520     }
521
522     if (!rtpvorbisdepay->assembling)
523       goto no_output;
524
525     /* first assembled packet, reuse 2 bytes to store the length */
526     headerskip = (F == 1 ? 4 : 6);
527     /* skip header and length. */
528     vdata = gst_rtp_buffer_get_payload_subbuffer (&rtp, headerskip, -1);
529
530     GST_DEBUG_OBJECT (depayload, "assemble vorbis packet");
531     gst_adapter_push (rtpvorbisdepay->adapter, vdata);
532
533     /* packet is not complete, we are done */
534     if (F != 3)
535       goto no_output;
536
537     /* construct assembled buffer */
538     payload_len = gst_adapter_available (rtpvorbisdepay->adapter);
539     payload = gst_adapter_take (rtpvorbisdepay->adapter, payload_len);
540     /* fix the length */
541     payload[0] = ((payload_len - 2) >> 8) & 0xff;
542     payload[1] = (payload_len - 2) & 0xff;
543     to_free = payload;
544   }
545
546   GST_DEBUG_OBJECT (depayload, "assemble done");
547
548   /* we not assembling anymore now */
549   rtpvorbisdepay->assembling = FALSE;
550   gst_adapter_clear (rtpvorbisdepay->adapter);
551
552   /* payload now points to a length with that many vorbis data bytes.
553    * Iterate over the packets and send them out.
554    *
555    *  0                   1                   2                   3
556    *  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
557    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
558    * |             length            |          vorbis data         ..
559    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
560    * ..                        vorbis data                           |
561    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
562    * |            length             |   next vorbis packet data    ..
563    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
564    * ..                        vorbis data                           |
565    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*
566    */
567   while (payload_len > 2) {
568     guint16 length;
569
570     length = GST_READ_UINT16_BE (payload);
571     payload += 2;
572     payload_len -= 2;
573
574     GST_DEBUG_OBJECT (depayload, "read length %u, avail: %d", length,
575         payload_len);
576
577     /* skip packet if something odd happens */
578     if (G_UNLIKELY (length > payload_len))
579       goto length_short;
580
581     /* handle in-band configuration */
582     if (G_UNLIKELY (VDT == 1)) {
583       GST_DEBUG_OBJECT (rtpvorbisdepay, "in-band configuration");
584       if (!gst_rtp_vorbis_depay_parse_inband_configuration (rtpvorbisdepay,
585               ident, payload, payload_len, length))
586         goto invalid_configuration;
587       goto no_output;
588     }
589
590     /* create buffer for packet */
591     if (G_UNLIKELY (to_free)) {
592       outbuf = gst_buffer_new ();
593       gst_buffer_take_memory (outbuf, -1,
594           gst_memory_new_wrapped (0, to_free, g_free,
595               (payload - to_free) + length, payload - to_free, length));
596       to_free = NULL;
597     } else {
598       guint8 *data;
599
600       outbuf = gst_buffer_new_and_alloc (length);
601       data = gst_buffer_map (outbuf, NULL, NULL, GST_MAP_WRITE);
602       memcpy (data, payload, length);
603       gst_buffer_unmap (outbuf, data, -1);
604     }
605
606     payload += length;
607     payload_len -= length;
608
609     ret = gst_rtp_base_depayload_push (depayload, outbuf);
610     if (ret != GST_FLOW_OK)
611       break;
612   }
613
614   g_free (to_free);
615
616   gst_rtp_buffer_unmap (&rtp);
617
618   return NULL;
619
620 no_output:
621   {
622     gst_rtp_buffer_unmap (&rtp);
623     return NULL;
624   }
625   /* ERORRS */
626 switch_failed:
627   {
628     GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
629         (NULL), ("Could not switch codebooks"));
630     gst_rtp_buffer_unmap (&rtp);
631     return NULL;
632   }
633 packet_short:
634   {
635     GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
636         (NULL), ("Packet was too short (%d < 4)", payload_len));
637     gst_rtp_buffer_unmap (&rtp);
638     return NULL;
639   }
640 ignore_reserved:
641   {
642     GST_WARNING_OBJECT (rtpvorbisdepay, "reserved VDT ignored");
643     gst_rtp_buffer_unmap (&rtp);
644     return NULL;
645   }
646 length_short:
647   {
648     GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
649         (NULL), ("Packet contains invalid data"));
650     gst_rtp_buffer_unmap (&rtp);
651     return NULL;
652   }
653 invalid_configuration:
654   {
655     /* fatal, as we otherwise risk carrying on without output */
656     GST_ELEMENT_ERROR (rtpvorbisdepay, STREAM, DECODE,
657         (NULL), ("Packet contains invalid configuration"));
658     gst_rtp_buffer_unmap (&rtp);
659     return NULL;
660   }
661 }
662
663 static GstStateChangeReturn
664 gst_rtp_vorbis_depay_change_state (GstElement * element,
665     GstStateChange transition)
666 {
667   GstRtpVorbisDepay *rtpvorbisdepay;
668   GstStateChangeReturn ret;
669
670   rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (element);
671
672   switch (transition) {
673     case GST_STATE_CHANGE_NULL_TO_READY:
674       break;
675     case GST_STATE_CHANGE_READY_TO_PAUSED:
676       break;
677     default:
678       break;
679   }
680
681   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
682
683   switch (transition) {
684     case GST_STATE_CHANGE_PAUSED_TO_READY:
685       free_indents (rtpvorbisdepay);
686       break;
687     case GST_STATE_CHANGE_READY_TO_NULL:
688       break;
689     default:
690       break;
691   }
692   return ret;
693 }
694
695 gboolean
696 gst_rtp_vorbis_depay_plugin_init (GstPlugin * plugin)
697 {
698   return gst_element_register (plugin, "rtpvorbisdepay",
699       GST_RANK_SECONDARY, GST_TYPE_RTP_VORBIS_DEPAY);
700 }