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