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.0
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 Lesser 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 <vlc_codecs.h>
44 * vorbis: Xiph Vorbis audio (draft-ietf-avt-rtp-vorbis-09, RFC FIXME)
46 typedef struct rtp_vorbis_t
53 static void *vorbis_init (demux_t *demux)
55 rtp_vorbis_t *self = malloc (sizeof (*self));
62 self->ident = 0xffffffff; /* impossible value on the wire */
67 static void vorbis_destroy (demux_t *demux, void *data)
69 rtp_vorbis_t *self = data;
75 self->block->i_flags |= BLOCK_FLAG_CORRUPTED;
76 codec_decode (demux, self->id, self->block);
78 codec_destroy (demux, self->id);
82 /* Convert configuration from RTP to VLC format */
83 static ssize_t vorbis_header (void **pextra, const uint8_t *buf, size_t len)
87 return -1; /* Invalid */
88 unsigned hcount = 1 + *buf++;
91 return -1; /* Invalid */
94 uint16_t idlen = 0, cmtlen = 0, setuplen = 0;
99 idlen = (idlen << 7) | (*buf & 0x7f);
102 while (*buf++ & 0x80);
107 cmtlen = (cmtlen << 7) | (*buf & 0x7f);
110 while (*buf++ & 0x80);
111 if (len < idlen + cmtlen)
113 setuplen = len - (idlen + cmtlen);
115 /* Create the VLC extra format header */
116 uint8_t *extra = malloc ((size_t)6 + idlen + cmtlen + setuplen);
119 uint8_t *ptr = *pextra = extra;
120 /* Identification header */
122 *ptr++ = idlen & 0xff;
123 memcpy (ptr, buf, idlen);
126 /* Comments header */
127 *ptr++ = cmtlen >> 8;
128 *ptr++ = cmtlen & 0xff;
129 memcpy (ptr, buf, cmtlen);
133 *ptr++ = setuplen >> 8;
134 *ptr++ = setuplen & 0xff;
135 memcpy (ptr, buf, setuplen);
141 static void vorbis_decode (demux_t *demux, void *data, block_t *block)
143 rtp_vorbis_t *self = data;
145 if (!data || block->i_buffer < 4)
148 /* 32-bits Vorbis RTP header (§2.2) */
149 uint32_t ident = GetDWBE (block->p_buffer);
150 block->i_buffer -= 4;
151 block->p_buffer += 4;
153 unsigned fragtype = (ident >> 6) & 3;
154 unsigned datatype = (ident >> 4) & 3;
155 unsigned pkts = (ident) & 15;
158 /* Vorbis RTP defragmentation */
159 if (self->block && (block->i_flags & BLOCK_FLAG_DISCONTINUITY))
160 { /* Screwed! discontinuity within a fragmented packet */
161 msg_Warn (demux, "discontinuity in fragmented Vorbis packet");
162 block_Release (self->block);
168 if (self->block) /* Invalid first fragment */
170 block_Release (self->block);
177 goto drop; /* Invalid non-first fragment */
182 if (pkts > 0 || block->i_buffer < 2)
185 size_t fraglen = GetWBE (block->p_buffer);
186 if (block->i_buffer < (fraglen + 2))
187 goto drop; /* Invalid payload length */
188 block->i_buffer = fraglen;
189 if (fragtype == 1)/* Keep first fragment */
191 block->i_buffer += 2;
195 { /* Append non-first fragment */
196 size_t len = self->block->i_buffer;
197 self->block = block_Realloc (self->block, 0, len + fraglen);
200 block_Release (block);
203 memcpy (self->block->p_buffer + len, block->p_buffer + 2,
205 block_Release (block);
208 return; /* Non-last fragment */
210 /* Last fragment reached, process it */
213 SetWBE (block->p_buffer, block->i_buffer - 2);
217 /* Vorbis RTP payload packets processing */
220 if (block->i_buffer < 2)
223 size_t len = GetWBE (block->p_buffer);
224 block->i_buffer -= 2;
225 block->p_buffer += 2;
226 if (block->i_buffer < len)
231 case 0: /* Raw audio frame */
233 if (self->ident != ident)
234 break; /* Ignore raw without configuration */
235 block_t *raw = block_Alloc (len);
236 memcpy (raw->p_buffer, block->p_buffer, len);
237 raw->i_pts = block->i_pts; /* FIXME: what about pkts > 1 */
238 codec_decode (demux, self->id, raw);
242 case 1: /* Packed configuration frame (§3.1.1) */
244 if (self->ident == ident)
245 break; /* Ignore config retransmission */
248 ssize_t extc = vorbis_header (&extv, block->p_buffer, len);
253 es_format_Init (&fmt, AUDIO_ES, VLC_FOURCC ('v','o','r','b'));
256 codec_destroy (demux, self->id);
257 msg_Dbg (demux, "Vorbis packed configuration received "
258 "(%06"PRIx32")", ident);
260 self->id = codec_init (demux, &fmt);
265 block->i_buffer -= len;
266 block->p_buffer += len;
271 block_Release (block);