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