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