Tizen 2.0 Release
[framework/multimedia/gst-plugins-good0.10.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 GST_BOILERPLATE (GstRtpVorbisDepay, gst_rtp_vorbis_depay, GstBaseRTPDepayload,
61     GST_TYPE_BASE_RTP_DEPAYLOAD);
62
63 static gboolean gst_rtp_vorbis_depay_setcaps (GstBaseRTPDepayload * depayload,
64     GstCaps * caps);
65 static GstBuffer *gst_rtp_vorbis_depay_process (GstBaseRTPDepayload * 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
74 static void
75 gst_rtp_vorbis_depay_base_init (gpointer klass)
76 {
77   GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
78
79   gst_element_class_add_static_pad_template (element_class,
80       &gst_rtp_vorbis_depay_sink_template);
81   gst_element_class_add_static_pad_template (element_class,
82       &gst_rtp_vorbis_depay_src_template);
83
84   gst_element_class_set_details_simple (element_class, "RTP Vorbis depayloader",
85       "Codec/Depayloader/Network/RTP",
86       "Extracts Vorbis Audio from RTP packets (RFC 5215)",
87       "Wim Taymans <wim.taymans@gmail.com>");
88 }
89
90 static void
91 gst_rtp_vorbis_depay_class_init (GstRtpVorbisDepayClass * klass)
92 {
93   GObjectClass *gobject_class;
94   GstElementClass *gstelement_class;
95   GstBaseRTPDepayloadClass *gstbasertpdepayload_class;
96
97   gobject_class = (GObjectClass *) klass;
98   gstelement_class = (GstElementClass *) klass;
99   gstbasertpdepayload_class = (GstBaseRTPDepayloadClass *) klass;
100
101   gobject_class->finalize = gst_rtp_vorbis_depay_finalize;
102
103   gstelement_class->change_state = gst_rtp_vorbis_depay_change_state;
104
105   gstbasertpdepayload_class->process = gst_rtp_vorbis_depay_process;
106   gstbasertpdepayload_class->set_caps = gst_rtp_vorbis_depay_setcaps;
107
108   GST_DEBUG_CATEGORY_INIT (rtpvorbisdepay_debug, "rtpvorbisdepay", 0,
109       "Vorbis RTP Depayloader");
110 }
111
112 static void
113 gst_rtp_vorbis_depay_init (GstRtpVorbisDepay * rtpvorbisdepay,
114     GstRtpVorbisDepayClass * klass)
115 {
116   rtpvorbisdepay->adapter = gst_adapter_new ();
117 }
118
119 static void
120 free_config (GstRtpVorbisConfig * conf)
121 {
122   GList *headers;
123
124   for (headers = conf->headers; headers; headers = g_list_next (headers)) {
125     GstBuffer *header = GST_BUFFER_CAST (headers->data);
126
127     gst_buffer_unref (header);
128   }
129   g_list_free (conf->headers);
130   g_free (conf);
131 }
132
133 static void
134 free_indents (GstRtpVorbisDepay * rtpvorbisdepay)
135 {
136   GList *walk;
137
138   for (walk = rtpvorbisdepay->configs; walk; walk = g_list_next (walk)) {
139     free_config ((GstRtpVorbisConfig *) walk->data);
140   }
141   g_list_free (rtpvorbisdepay->configs);
142   rtpvorbisdepay->configs = NULL;
143 }
144
145 static void
146 gst_rtp_vorbis_depay_finalize (GObject * object)
147 {
148   GstRtpVorbisDepay *rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (object);
149
150   g_object_unref (rtpvorbisdepay->adapter);
151
152   G_OBJECT_CLASS (parent_class)->finalize (object);
153 }
154
155 /* takes ownership of confbuf */
156 static gboolean
157 gst_rtp_vorbis_depay_parse_configuration (GstRtpVorbisDepay * rtpvorbisdepay,
158     GstBuffer * confbuf)
159 {
160   GstBuffer *buf;
161   guint32 num_headers;
162   guint8 *data;
163   guint size;
164   guint offset;
165   gint i, j;
166
167   data = GST_BUFFER_DATA (confbuf);
168   size = GST_BUFFER_SIZE (confbuf);
169
170   GST_DEBUG_OBJECT (rtpvorbisdepay, "config size %u", size);
171
172   /* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
173    * |                     Number of packed headers                  |
174    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
175    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
176    * |                          Packed header                        |
177    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
178    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
179    * |                          Packed header                        |
180    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
181    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
182    * |                          ....                                 |
183    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
184    */
185   if (size < 4)
186     goto too_small;
187
188   num_headers = GST_READ_UINT32_BE (data);
189   size -= 4;
190   data += 4;
191   offset = 4;
192
193   GST_DEBUG_OBJECT (rtpvorbisdepay, "have %u headers", num_headers);
194
195   /*  0                   1                   2                   3
196    *  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
197    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
198    * |                   Ident                       | length       ..
199    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
200    * ..              | n. of headers |    length1    |    length2   ..
201    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
202    * ..              |             Identification Header            ..
203    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
204    * .................................................................
205    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
206    * ..              |         Comment Header                       ..
207    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
208    * .................................................................
209    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
210    * ..                        Comment Header                        |
211    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
212    * |                          Setup Header                        ..
213    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
214    * .................................................................
215    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
216    * ..                         Setup Header                         |
217    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
218    */
219   for (i = 0; i < num_headers; i++) {
220     guint32 ident;
221     guint16 length;
222     guint8 n_headers, b;
223     GstRtpVorbisConfig *conf;
224     guint *h_sizes;
225     guint extra = 1;
226
227     if (size < 6)
228       goto too_small;
229
230     ident = (data[0] << 16) | (data[1] << 8) | data[2];
231     length = (data[3] << 8) | data[4];
232     n_headers = data[5];
233     size -= 6;
234     data += 6;
235     offset += 6;
236
237     GST_DEBUG_OBJECT (rtpvorbisdepay,
238         "header %d, ident 0x%08x, length %u, left %u", i, ident, length, size);
239
240     /* FIXME check if we already got this ident */
241
242     /* length might also include count of following size fields */
243     if (size < length && size + 1 != length)
244       goto too_small;
245
246     /* read header sizes we read 2 sizes, the third size (for which we allocate
247      * space) must be derived from the total packed header length. */
248     h_sizes = g_newa (guint, n_headers + 1);
249     for (j = 0; j < n_headers; j++) {
250       guint h_size;
251
252       h_size = 0;
253       do {
254         if (size < 1)
255           goto too_small;
256         b = *data++;
257         offset++;
258         extra++;
259         size--;
260         h_size = (h_size << 7) | (b & 0x7f);
261       } while (b & 0x80);
262       GST_DEBUG_OBJECT (rtpvorbisdepay, "headers %d: size: %u", j, h_size);
263
264       if (length < h_size)
265         goto too_small;
266
267       h_sizes[j] = h_size;
268       length -= h_size;
269     }
270     /* last header length is the remaining space */
271     GST_DEBUG_OBJECT (rtpvorbisdepay, "last header size: %u", length);
272     h_sizes[j] = length;
273
274     GST_DEBUG_OBJECT (rtpvorbisdepay, "preparing headers");
275     conf = g_new0 (GstRtpVorbisConfig, 1);
276     conf->ident = ident;
277
278     for (j = 0; j <= n_headers; j++) {
279       guint h_size;
280
281       h_size = h_sizes[j];
282       if (size < h_size) {
283         if (j != n_headers || size + extra != h_size) {
284           free_config (conf);
285           goto too_small;
286         } else {
287           /* otherwise means that overall length field contained total length,
288            * including extra fields */
289           h_size -= extra;
290         }
291       }
292
293       GST_DEBUG_OBJECT (rtpvorbisdepay, "reading header %d, size %u", j,
294           h_size);
295
296       buf = gst_buffer_create_sub (confbuf, offset, h_size);
297       conf->headers = g_list_append (conf->headers, buf);
298       offset += h_size;
299       size -= h_size;
300     }
301     rtpvorbisdepay->configs = g_list_append (rtpvorbisdepay->configs, conf);
302   }
303   gst_buffer_unref (confbuf);
304
305   return TRUE;
306
307   /* ERRORS */
308 too_small:
309   {
310     GST_DEBUG_OBJECT (rtpvorbisdepay, "configuration too small");
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   guint8 *conf;
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   conf = GST_BUFFER_DATA (confbuf);
330   /* 1 header */
331   GST_WRITE_UINT32_BE (conf, 1);
332   /* write Ident */
333   GST_WRITE_UINT24_BE (conf + 4, ident);
334   /* write sort-of-length */
335   GST_WRITE_UINT16_BE (conf + 7, length);
336   /* copy remainder */
337   memcpy (conf + 9, configuration, size);
338
339   return gst_rtp_vorbis_depay_parse_configuration (rtpvorbisdepay, confbuf);
340 }
341
342 static gboolean
343 gst_rtp_vorbis_depay_setcaps (GstBaseRTPDepayload * 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_DATA (confbuf) = data;
372     GST_BUFFER_MALLOCDATA (confbuf) = data;
373     GST_BUFFER_SIZE (confbuf) = 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_simple ("audio/x-vorbis", NULL);
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_base_rtp_depayload_push (GST_BASE_RTP_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 (GstBaseRTPDepayload * 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 timestamp;
448   guint32 header, ident;
449   guint8 F, VDT, packets;
450
451   rtpvorbisdepay = GST_RTP_VORBIS_DEPAY (depayload);
452
453   payload_len = gst_rtp_buffer_get_payload_len (buf);
454
455   GST_DEBUG_OBJECT (depayload, "got RTP packet of size %d", payload_len);
456
457   /* we need at least 4 bytes for the packet header */
458   if (G_UNLIKELY (payload_len < 4))
459     goto packet_short;
460
461   payload = gst_rtp_buffer_get_payload (buf);
462
463   header = GST_READ_UINT32_BE (payload);
464   /*
465    *  0                   1                   2                   3
466    *  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
467    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
468    * |                     Ident                     | F |VDT|# pkts.|
469    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
470    *
471    * F: Fragment type (0=none, 1=start, 2=cont, 3=end)
472    * VDT: Vorbis data type (0=vorbis, 1=config, 2=comment, 3=reserved)
473    * pkts: number of packets.
474    */
475   VDT = (header & 0x30) >> 4;
476   if (G_UNLIKELY (VDT == 3))
477     goto ignore_reserved;
478
479   GST_DEBUG_OBJECT (depayload, "header: 0x%08x", header);
480   ident = (header >> 8) & 0xffffff;
481   F = (header & 0xc0) >> 6;
482   packets = (header & 0xf);
483
484   if (VDT == 0) {
485     gboolean do_switch = FALSE;
486
487     /* we have a raw payload, find the codebook for the ident */
488     if (!rtpvorbisdepay->config) {
489       /* we don't have an active codebook, find the codebook and
490        * activate it */
491       GST_DEBUG_OBJECT (rtpvorbisdepay, "No active codebook, switching");
492       do_switch = TRUE;
493     } else if (rtpvorbisdepay->config->ident != ident) {
494       /* codebook changed */
495       GST_DEBUG_OBJECT (rtpvorbisdepay, "codebook changed, switching");
496       do_switch = TRUE;
497     }
498     if (do_switch) {
499       if (!gst_rtp_vorbis_depay_switch_codebook (rtpvorbisdepay, ident))
500         goto switch_failed;
501     }
502   }
503
504   /* skip header */
505   payload += 4;
506   payload_len -= 4;
507
508   GST_DEBUG_OBJECT (depayload, "ident: %u, F: %d, VDT: %d, packets: %d", ident,
509       F, VDT, packets);
510
511   /* fragmented packets, assemble */
512   if (F != 0) {
513     GstBuffer *vdata;
514     guint headerskip;
515
516     if (F == 1) {
517       /* if we start a packet, clear adapter and start assembling. */
518       gst_adapter_clear (rtpvorbisdepay->adapter);
519       GST_DEBUG_OBJECT (depayload, "start assemble");
520       rtpvorbisdepay->assembling = TRUE;
521     }
522
523     if (!rtpvorbisdepay->assembling)
524       goto no_output;
525
526     /* first assembled packet, reuse 2 bytes to store the length */
527     headerskip = (F == 1 ? 4 : 6);
528     /* skip header and length. */
529     vdata = gst_rtp_buffer_get_payload_subbuffer (buf, headerskip, -1);
530
531     GST_DEBUG_OBJECT (depayload, "assemble vorbis packet");
532     gst_adapter_push (rtpvorbisdepay->adapter, vdata);
533
534     /* packet is not complete, we are done */
535     if (F != 3)
536       goto no_output;
537
538     /* construct assembled buffer */
539     payload_len = gst_adapter_available (rtpvorbisdepay->adapter);
540     payload = gst_adapter_take (rtpvorbisdepay->adapter, payload_len);
541     /* fix the length */
542     payload[0] = ((payload_len - 2) >> 8) & 0xff;
543     payload[1] = (payload_len - 2) & 0xff;
544     to_free = payload;
545   }
546
547   GST_DEBUG_OBJECT (depayload, "assemble done");
548
549   /* we not assembling anymore now */
550   rtpvorbisdepay->assembling = FALSE;
551   gst_adapter_clear (rtpvorbisdepay->adapter);
552
553   /* payload now points to a length with that many vorbis data bytes.
554    * Iterate over the packets and send them out.
555    *
556    *  0                   1                   2                   3
557    *  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
558    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
559    * |             length            |          vorbis data         ..
560    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
561    * ..                        vorbis data                           |
562    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
563    * |            length             |   next vorbis packet data    ..
564    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
565    * ..                        vorbis data                           |
566    * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+*
567    */
568   timestamp = gst_rtp_buffer_get_timestamp (buf);
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_DATA (outbuf) = payload;
597       GST_BUFFER_MALLOCDATA (outbuf) = to_free;
598       GST_BUFFER_SIZE (outbuf) = length;
599       to_free = NULL;
600     } else {
601       outbuf = gst_buffer_new_and_alloc (length);
602       memcpy (GST_BUFFER_DATA (outbuf), payload, length);
603     }
604
605     payload += length;
606     payload_len -= length;
607
608     if (timestamp != -1)
609       /* push with timestamp of the last packet, which is the same timestamp that
610        * should apply to the first assembled packet. */
611       ret = gst_base_rtp_depayload_push_ts (depayload, timestamp, outbuf);
612     else
613       ret = gst_base_rtp_depayload_push (depayload, outbuf);
614
615     if (ret != GST_FLOW_OK)
616       break;
617
618     /* make sure we don't set a timestamp on next buffers */
619     timestamp = -1;
620   }
621
622   g_free (to_free);
623
624   return NULL;
625
626 no_output:
627   {
628     return NULL;
629   }
630   /* ERORRS */
631 switch_failed:
632   {
633     GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
634         (NULL), ("Could not switch codebooks"));
635     return NULL;
636   }
637 packet_short:
638   {
639     GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
640         (NULL), ("Packet was too short (%d < 4)", payload_len));
641     return NULL;
642   }
643 ignore_reserved:
644   {
645     GST_WARNING_OBJECT (rtpvorbisdepay, "reserved VDT ignored");
646     return NULL;
647   }
648 length_short:
649   {
650     GST_ELEMENT_WARNING (rtpvorbisdepay, STREAM, DECODE,
651         (NULL), ("Packet contains invalid data"));
652     return NULL;
653   }
654 invalid_configuration:
655   {
656     /* fatal, as we otherwise risk carrying on without output */
657     GST_ELEMENT_ERROR (rtpvorbisdepay, STREAM, DECODE,
658         (NULL), ("Packet contains invalid configuration"));
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 }