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