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