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