]> git.sesse.net Git - vlc/blob - modules/access/rtp/xiph.c
macosx: fixed menubar appearance in fullscreen mode by partially reverting [46c93c9cc...
[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.0
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 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  ****************************************************************************/
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
40 #include "rtp.h"
41 #include <srtp.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     uint8_t *extra = malloc ((size_t)6 + idlen + cmtlen + setuplen);
117     if (extra == NULL)
118         return -1;
119     uint8_t *ptr = *pextra = extra;
120     /* Identification header */
121     *ptr++ = idlen >> 8;
122     *ptr++ = idlen & 0xff;
123     memcpy (ptr, buf, idlen);
124     buf += idlen;
125     ptr += idlen;
126     /* Comments header */
127     *ptr++ = cmtlen >> 8;
128     *ptr++ = cmtlen & 0xff;
129     memcpy (ptr, buf, cmtlen);
130     buf += cmtlen;
131     ptr += cmtlen;
132     /* Setup header */
133     *ptr++ = setuplen >> 8;
134     *ptr++ = setuplen & 0xff;
135     memcpy (ptr, buf, setuplen);
136     ptr += setuplen;
137     return ptr - extra;
138 }
139
140
141 static void vorbis_decode (demux_t *demux, void *data, block_t *block)
142 {
143     rtp_vorbis_t *self = data;
144
145     if (!data || block->i_buffer < 4)
146         goto drop;
147
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;
152
153     unsigned fragtype = (ident >> 6) & 3;
154     unsigned datatype = (ident >> 4) & 3;
155     unsigned pkts = (ident) & 15;
156     ident >>= 8;
157
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);
163         self->block = NULL;
164     }
165
166     if (fragtype <= 1)
167     {
168         if (self->block) /* Invalid first fragment */
169         {
170             block_Release (self->block);
171             self->block = NULL;
172         }
173     }
174     else
175     {
176         if (!self->block)
177             goto drop; /* Invalid non-first fragment */
178     }
179
180     if (fragtype > 0)
181     {   /* Fragment */
182         if (pkts > 0 || block->i_buffer < 2)
183             goto drop;
184
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 */
190         {
191             block->i_buffer += 2;
192             self->block = block;
193         }
194         else
195         {   /* Append non-first fragment */
196             size_t len = self->block->i_buffer;
197             self->block = block_Realloc (self->block, 0, len + fraglen);
198             if (!self->block)
199             {
200                 block_Release (block);
201                 return;
202             }
203             memcpy (self->block->p_buffer + len, block->p_buffer + 2,
204                     fraglen);
205             block_Release (block);
206         }
207         if (fragtype < 3)
208             return; /* Non-last fragment */
209
210         /* Last fragment reached, process it */
211         block = self->block;
212         self->block = NULL;
213         SetWBE (block->p_buffer, block->i_buffer - 2);
214         pkts = 1;
215     }
216
217     /* Vorbis RTP payload packets processing */
218     while (pkts > 0)
219     {
220         if (block->i_buffer < 2)
221             goto drop;
222
223         size_t len = GetWBE (block->p_buffer);
224         block->i_buffer -= 2;
225         block->p_buffer += 2;
226         if (block->i_buffer < len)
227             goto drop;
228
229         switch (datatype)
230         {
231             case 0: /* Raw audio frame */
232             {
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);
239                 break;
240             }
241
242             case 1: /* Packed configuration frame (§3.1.1) */
243             {
244                 if (self->ident == ident)
245                     break; /* Ignore config retransmission */
246
247                 void *extv;
248                 ssize_t extc = vorbis_header (&extv, block->p_buffer, len);
249                 if (extc < 0)
250                     break;
251
252                 es_format_t fmt;
253                 es_format_Init (&fmt, AUDIO_ES, VLC_FOURCC ('v','o','r','b'));
254                 fmt.p_extra = extv;
255                 fmt.i_extra = extc;
256                 codec_destroy (demux, self->id);
257                 msg_Dbg (demux, "Vorbis packed configuration received "
258                          "(%06"PRIx32")", ident);
259                 self->ident = ident;
260                 self->id = codec_init (demux, &fmt);
261                 break;
262             }
263         }
264
265         block->i_buffer -= len;
266         block->p_buffer += len;
267         pkts--;
268     }
269
270 drop:
271     block_Release (block);
272 }