]> git.sesse.net Git - vlc/blob - modules/access/rtp/xiph.c
stream_filter/httplive.c: Append new segment any (HLS Live playback) when gap in...
[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 "../../demux/xiph.h"
39
40 #include "rtp.h"
41
42 typedef struct rtp_xiph_t
43 {
44     es_out_id_t *id;
45     block_t     *block;
46     uint32_t     ident;
47     bool         vorbis;
48 } rtp_xiph_t;
49
50 static void *xiph_init (bool vorbis)
51 {
52     rtp_xiph_t *self = malloc (sizeof (*self));
53
54     if (self == NULL)
55         return NULL;
56
57     self->id = NULL;
58     self->block = NULL;
59     self->ident = 0xffffffff; /* impossible value on the wire */
60     self->vorbis = vorbis;
61     return self;
62 }
63
64 #if 0
65 /* PT=dynamic
66  * vorbis: Xiph Vorbis audio (RFC 5215)
67  */
68 static void *vorbis_init (demux_t *demux)
69 {
70     (void)demux;
71     return xiph_init (true);
72 }
73 #endif
74
75 /* PT=dynamic
76  * vorbis: Xiph Theora video
77  */
78 void *theora_init (demux_t *demux)
79 {
80     (void)demux;
81     return xiph_init (false);
82 }
83
84 void xiph_destroy (demux_t *demux, void *data)
85 {
86     rtp_xiph_t *self = data;
87
88     if (!data)
89         return;
90     if (self->block)
91     {
92         self->block->i_flags |= BLOCK_FLAG_CORRUPTED;
93         codec_decode (demux, self->id, self->block);
94     }
95     codec_destroy (demux, self->id);
96     free (self);
97 }
98
99 /* Convert configuration from RTP to VLC format */
100 static ssize_t xiph_header (void **pextra, const uint8_t *buf, size_t len)
101 {
102     /* Headers number */
103     if (len == 0)
104           return -1; /* Invalid */
105     unsigned hcount = 1 + *buf++;
106     len--;
107     if (hcount != 3)
108           return -1; /* Invalid */
109
110     /* Header lengths */
111     uint16_t idlen = 0, cmtlen = 0, setuplen = 0;
112     do
113     {
114         if (len == 0)
115             return -1;
116         idlen = (idlen << 7) | (*buf & 0x7f);
117         len--;
118     }
119     while (*buf++ & 0x80);
120     do
121     {
122         if (len == 0)
123             return -1;
124         cmtlen = (cmtlen << 7) | (*buf & 0x7f);
125         len--;
126     }
127     while (*buf++ & 0x80);
128     if (len < idlen + cmtlen)
129         return -1;
130     setuplen = len - (idlen + cmtlen);
131
132     /* Create the VLC extra format header */
133     unsigned sizes[3] = {
134         idlen, cmtlen, setuplen
135     };
136     const void *payloads[3] = {
137         buf + 0,
138         buf + idlen,
139         buf + idlen + cmtlen
140     };
141     void *extra;
142     int  extra_size;
143     if (xiph_PackHeaders (&extra_size, &extra, sizes, payloads, 3))
144         return -1;;
145     *pextra = extra;
146     return extra_size;
147 }
148
149
150 void xiph_decode (demux_t *demux, void *data, block_t *block)
151 {
152     rtp_xiph_t *self = data;
153
154     if (!data || block->i_buffer < 4)
155         goto drop;
156
157     /* 32-bits RTP header (§2.2) */
158     uint32_t ident = GetDWBE (block->p_buffer);
159     block->i_buffer -= 4;
160     block->p_buffer += 4;
161
162     unsigned fragtype = (ident >> 6) & 3;
163     unsigned datatype = (ident >> 4) & 3;
164     unsigned pkts = (ident) & 15;
165     ident >>= 8;
166
167     /* RTP defragmentation */
168     if (self->block && (block->i_flags & BLOCK_FLAG_DISCONTINUITY))
169     {   /* Screwed! discontinuity within a fragmented packet */
170         msg_Warn (demux, self->vorbis ?
171                   "discontinuity in fragmented Vorbis packet" :
172                   "discontinuity in fragmented Theora packet");
173         block_Release (self->block);
174         self->block = NULL;
175     }
176
177     if (fragtype <= 1)
178     {
179         if (self->block) /* Invalid first fragment */
180         {
181             block_Release (self->block);
182             self->block = NULL;
183         }
184     }
185     else
186     {
187         if (!self->block)
188             goto drop; /* Invalid non-first fragment */
189     }
190
191     if (fragtype > 0)
192     {   /* Fragment */
193         if (pkts > 0 || block->i_buffer < 2)
194             goto drop;
195
196         size_t fraglen = GetWBE (block->p_buffer);
197         if (block->i_buffer < (fraglen + 2))
198             goto drop; /* Invalid payload length */
199         block->i_buffer = fraglen;
200         if (fragtype == 1)/* Keep first fragment */
201         {
202             block->i_buffer += 2;
203             self->block = block;
204         }
205         else
206         {   /* Append non-first fragment */
207             size_t len = self->block->i_buffer;
208             self->block = block_Realloc (self->block, 0, len + fraglen);
209             if (!self->block)
210             {
211                 block_Release (block);
212                 return;
213             }
214             memcpy (self->block->p_buffer + len, block->p_buffer + 2,
215                     fraglen);
216             block_Release (block);
217         }
218         if (fragtype < 3)
219             return; /* Non-last fragment */
220
221         /* Last fragment reached, process it */
222         block = self->block;
223         self->block = NULL;
224         SetWBE (block->p_buffer, block->i_buffer - 2);
225         pkts = 1;
226     }
227
228     /* RTP payload packets processing */
229     while (pkts > 0)
230     {
231         if (block->i_buffer < 2)
232             goto drop;
233
234         size_t len = GetWBE (block->p_buffer);
235         block->i_buffer -= 2;
236         block->p_buffer += 2;
237         if (block->i_buffer < len)
238             goto drop;
239
240         switch (datatype)
241         {
242             case 0: /* Raw payload */
243             {
244                 if (self->ident != ident)
245                 {
246                     msg_Warn (demux, self->vorbis ?
247                         "ignoring raw Vorbis payload without configuration" :
248                         "ignoring raw Theora payload without configuration");
249                     break;
250                 }
251                 block_t *raw = block_Alloc (len);
252                 memcpy (raw->p_buffer, block->p_buffer, len);
253                 raw->i_pts = block->i_pts; /* FIXME: what about pkts > 1 */
254                 codec_decode (demux, self->id, raw);
255                 break;
256             }
257
258             case 1: /* Packed configuration frame (§3.1.1) */
259             {
260                 if (self->ident == ident)
261                     break; /* Ignore config retransmission */
262
263                 void *extv;
264                 ssize_t extc = xiph_header (&extv, block->p_buffer, len);
265                 if (extc < 0)
266                     break;
267
268                 es_format_t fmt;
269                 es_format_Init (&fmt, self->vorbis ? AUDIO_ES : VIDEO_ES,
270                                 self->vorbis ? VLC_CODEC_VORBIS
271                                              : VLC_CODEC_THEORA);
272                 fmt.p_extra = extv;
273                 fmt.i_extra = extc;
274                 codec_destroy (demux, self->id);
275                 msg_Dbg (demux, self->vorbis ?
276                          "Vorbis packed configuration received (%06"PRIx32")" :
277                          "Theora packed configuration received (%06"PRIx32")",
278                          ident);
279                 self->ident = ident;
280                 self->id = codec_init (demux, &fmt);
281                 break;
282             }
283         }
284
285         block->i_buffer -= len;
286         block->p_buffer += len;
287         pkts--;
288     }
289
290 drop:
291     block_Release (block);
292 }