]> git.sesse.net Git - vlc/blob - modules/access/rtp/xiph.c
Modified the way xiph codecs headers are transported in VLC.
[vlc] / modules / access / rtp / xiph.c
1 /**
2  * @file rtpxiph.c
3  * @brief Real-Time Protocol (RTP) Xiph payloads receival
4  */
5 /*****************************************************************************
6  * Copyright © 2008 Rémi Denis-Courmont
7  *
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.
12  *
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.
17  *
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  ****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include <config.h>
25 #endif
26 #include <stdarg.h>
27 #include <assert.h>
28
29 #include <vlc_common.h>
30 #include <vlc_demux.h>
31 #include <vlc_aout.h>
32 #include <vlc_network.h>
33 #ifdef HAVE_POLL
34 # include <poll.h>
35 #endif
36 #include <vlc_plugin.h>
37
38 #include <vlc_codecs.h>
39 #include "../../demux/xiph.h"
40
41 #include "rtp.h"
42
43 /* PT=dynamic
44  * vorbis: Xiph Vorbis audio (draft-ietf-avt-rtp-vorbis-09, RFC FIXME)
45  */
46 typedef struct rtp_vorbis_t
47 {
48     es_out_id_t *id;
49     block_t     *block;
50     uint32_t     ident;
51 } rtp_vorbis_t;
52
53 static void *vorbis_init (demux_t *demux)
54 {
55     rtp_vorbis_t *self = malloc (sizeof (*self));
56
57     if (self == NULL)
58         return NULL;
59
60     self->id = NULL;
61     self->block = NULL;
62     self->ident = 0xffffffff; /* impossible value on the wire */
63     (void)demux;
64     return self;
65 }
66
67 static void vorbis_destroy (demux_t *demux, void *data)
68 {
69     rtp_vorbis_t *self = data;
70
71     if (!data)
72         return;
73     if (self->block)
74     {
75         self->block->i_flags |= BLOCK_FLAG_CORRUPTED;
76         codec_decode (demux, self->id, self->block);
77     }
78     codec_destroy (demux, self->id);
79     free (self);
80 }
81
82 /* Convert configuration from RTP to VLC format */
83 static ssize_t vorbis_header (void **pextra, const uint8_t *buf, size_t len)
84 {
85     /* Headers number */
86     if (len == 0)
87           return -1; /* Invalid */
88     unsigned hcount = 1 + *buf++;
89     len--;
90     if (hcount != 3)
91           return -1; /* Invalid */
92
93     /* Header lengths */
94     uint16_t idlen = 0, cmtlen = 0, setuplen = 0;
95     do
96     {
97         if (len == 0)
98             return -1;
99         idlen = (idlen << 7) | (*buf & 0x7f);
100         len--;
101     }
102     while (*buf++ & 0x80);
103     do
104     {
105         if (len == 0)
106             return -1;
107         cmtlen = (cmtlen << 7) | (*buf & 0x7f);
108         len--;
109     }
110     while (*buf++ & 0x80);
111     if (len < idlen + cmtlen)
112         return -1;
113     setuplen = len - (idlen + cmtlen);
114
115     /* Create the VLC extra format header */
116     unsigned sizes[3] = {
117         idlen, cmtlen, setuplen
118     };
119     void *payloads[3] = {
120         buf + 0,
121         buf + idlen,
122         buf + cmtlen
123     };
124     void *extra;
125     int  extra_size;
126     if (xiph_PackHeaders (&extra_size, &extra, sizes, payloads, 3))
127         return -1;;
128     *pextra = extra;
129     return extra_size;
130 }
131
132
133 static void vorbis_decode (demux_t *demux, void *data, block_t *block)
134 {
135     rtp_vorbis_t *self = data;
136
137     if (!data || block->i_buffer < 4)
138         goto drop;
139
140     /* 32-bits Vorbis RTP header (§2.2) */
141     uint32_t ident = GetDWBE (block->p_buffer);
142     block->i_buffer -= 4;
143     block->p_buffer += 4;
144
145     unsigned fragtype = (ident >> 6) & 3;
146     unsigned datatype = (ident >> 4) & 3;
147     unsigned pkts = (ident) & 15;
148     ident >>= 8;
149
150     /* Vorbis RTP defragmentation */
151     if (self->block && (block->i_flags & BLOCK_FLAG_DISCONTINUITY))
152     {   /* Screwed! discontinuity within a fragmented packet */
153         msg_Warn (demux, "discontinuity in fragmented Vorbis packet");
154         block_Release (self->block);
155         self->block = NULL;
156     }
157
158     if (fragtype <= 1)
159     {
160         if (self->block) /* Invalid first fragment */
161         {
162             block_Release (self->block);
163             self->block = NULL;
164         }
165     }
166     else
167     {
168         if (!self->block)
169             goto drop; /* Invalid non-first fragment */
170     }
171
172     if (fragtype > 0)
173     {   /* Fragment */
174         if (pkts > 0 || block->i_buffer < 2)
175             goto drop;
176
177         size_t fraglen = GetWBE (block->p_buffer);
178         if (block->i_buffer < (fraglen + 2))
179             goto drop; /* Invalid payload length */
180         block->i_buffer = fraglen;
181         if (fragtype == 1)/* Keep first fragment */
182         {
183             block->i_buffer += 2;
184             self->block = block;
185         }
186         else
187         {   /* Append non-first fragment */
188             size_t len = self->block->i_buffer;
189             self->block = block_Realloc (self->block, 0, len + fraglen);
190             if (!self->block)
191             {
192                 block_Release (block);
193                 return;
194             }
195             memcpy (self->block->p_buffer + len, block->p_buffer + 2,
196                     fraglen);
197             block_Release (block);
198         }
199         if (fragtype < 3)
200             return; /* Non-last fragment */
201
202         /* Last fragment reached, process it */
203         block = self->block;
204         self->block = NULL;
205         SetWBE (block->p_buffer, block->i_buffer - 2);
206         pkts = 1;
207     }
208
209     /* Vorbis RTP payload packets processing */
210     while (pkts > 0)
211     {
212         if (block->i_buffer < 2)
213             goto drop;
214
215         size_t len = GetWBE (block->p_buffer);
216         block->i_buffer -= 2;
217         block->p_buffer += 2;
218         if (block->i_buffer < len)
219             goto drop;
220
221         switch (datatype)
222         {
223             case 0: /* Raw audio frame */
224             {
225                 if (self->ident != ident)
226                     break; /* Ignore raw without configuration */
227                 block_t *raw = block_Alloc (len);
228                 memcpy (raw->p_buffer, block->p_buffer, len);
229                 raw->i_pts = block->i_pts; /* FIXME: what about pkts > 1 */
230                 codec_decode (demux, self->id, raw);
231                 break;
232             }
233
234             case 1: /* Packed configuration frame (§3.1.1) */
235             {
236                 if (self->ident == ident)
237                     break; /* Ignore config retransmission */
238
239                 void *extv;
240                 ssize_t extc = vorbis_header (&extv, block->p_buffer, len);
241                 if (extc < 0)
242                     break;
243
244                 es_format_t fmt;
245                 es_format_Init (&fmt, AUDIO_ES, VLC_CODEC_VORBIS);
246                 fmt.p_extra = extv;
247                 fmt.i_extra = extc;
248                 codec_destroy (demux, self->id);
249                 msg_Dbg (demux, "Vorbis packed configuration received "
250                          "(%06"PRIx32")", ident);
251                 self->ident = ident;
252                 self->id = codec_init (demux, &fmt);
253                 break;
254             }
255         }
256
257         block->i_buffer -= len;
258         block->p_buffer += len;
259         pkts--;
260     }
261
262 drop:
263     block_Release (block);
264 }