3 * @brief Real-Time Protocol (RTP) Xiph payloads receival
5 /*****************************************************************************
6 * Copyright © 2008 Rémi Denis-Courmont
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 ****************************************************************************/
29 #include <vlc_common.h>
30 #include <vlc_demux.h>
32 #include <vlc_network.h>
36 #include <vlc_plugin.h>
38 #include "../../demux/xiph.h"
43 * vorbis: Xiph Vorbis audio (RFC 5215)
45 typedef struct rtp_vorbis_t
52 static void *vorbis_init (demux_t *demux)
54 rtp_vorbis_t *self = malloc (sizeof (*self));
61 self->ident = 0xffffffff; /* impossible value on the wire */
66 static void vorbis_destroy (demux_t *demux, void *data)
68 rtp_vorbis_t *self = data;
74 self->block->i_flags |= BLOCK_FLAG_CORRUPTED;
75 codec_decode (demux, self->id, self->block);
77 codec_destroy (demux, self->id);
81 /* Convert configuration from RTP to VLC format */
82 static ssize_t vorbis_header (void **pextra, const uint8_t *buf, size_t len)
86 return -1; /* Invalid */
87 unsigned hcount = 1 + *buf++;
90 return -1; /* Invalid */
93 uint16_t idlen = 0, cmtlen = 0, setuplen = 0;
98 idlen = (idlen << 7) | (*buf & 0x7f);
101 while (*buf++ & 0x80);
106 cmtlen = (cmtlen << 7) | (*buf & 0x7f);
109 while (*buf++ & 0x80);
110 if (len < idlen + cmtlen)
112 setuplen = len - (idlen + cmtlen);
114 /* Create the VLC extra format header */
115 unsigned sizes[3] = {
116 idlen, cmtlen, setuplen
118 const void *payloads[3] = {
125 if (xiph_PackHeaders (&extra_size, &extra, sizes, payloads, 3))
132 static void vorbis_decode (demux_t *demux, void *data, block_t *block)
134 rtp_vorbis_t *self = data;
136 if (!data || block->i_buffer < 4)
139 /* 32-bits Vorbis RTP header (§2.2) */
140 uint32_t ident = GetDWBE (block->p_buffer);
141 block->i_buffer -= 4;
142 block->p_buffer += 4;
144 unsigned fragtype = (ident >> 6) & 3;
145 unsigned datatype = (ident >> 4) & 3;
146 unsigned pkts = (ident) & 15;
149 /* Vorbis RTP defragmentation */
150 if (self->block && (block->i_flags & BLOCK_FLAG_DISCONTINUITY))
151 { /* Screwed! discontinuity within a fragmented packet */
152 msg_Warn (demux, "discontinuity in fragmented Vorbis packet");
153 block_Release (self->block);
159 if (self->block) /* Invalid first fragment */
161 block_Release (self->block);
168 goto drop; /* Invalid non-first fragment */
173 if (pkts > 0 || block->i_buffer < 2)
176 size_t fraglen = GetWBE (block->p_buffer);
177 if (block->i_buffer < (fraglen + 2))
178 goto drop; /* Invalid payload length */
179 block->i_buffer = fraglen;
180 if (fragtype == 1)/* Keep first fragment */
182 block->i_buffer += 2;
186 { /* Append non-first fragment */
187 size_t len = self->block->i_buffer;
188 self->block = block_Realloc (self->block, 0, len + fraglen);
191 block_Release (block);
194 memcpy (self->block->p_buffer + len, block->p_buffer + 2,
196 block_Release (block);
199 return; /* Non-last fragment */
201 /* Last fragment reached, process it */
204 SetWBE (block->p_buffer, block->i_buffer - 2);
208 /* Vorbis RTP payload packets processing */
211 if (block->i_buffer < 2)
214 size_t len = GetWBE (block->p_buffer);
215 block->i_buffer -= 2;
216 block->p_buffer += 2;
217 if (block->i_buffer < len)
222 case 0: /* Raw audio frame */
224 if (self->ident != ident)
225 break; /* Ignore raw without configuration */
226 block_t *raw = block_Alloc (len);
227 memcpy (raw->p_buffer, block->p_buffer, len);
228 raw->i_pts = block->i_pts; /* FIXME: what about pkts > 1 */
229 codec_decode (demux, self->id, raw);
233 case 1: /* Packed configuration frame (§3.1.1) */
235 if (self->ident == ident)
236 break; /* Ignore config retransmission */
239 ssize_t extc = vorbis_header (&extv, block->p_buffer, len);
244 es_format_Init (&fmt, AUDIO_ES, VLC_CODEC_VORBIS);
247 codec_destroy (demux, self->id);
248 msg_Dbg (demux, "Vorbis packed configuration received "
249 "(%06"PRIx32")", ident);
251 self->id = codec_init (demux, &fmt);
256 block->i_buffer -= len;
257 block->p_buffer += len;
262 block_Release (block);