]> git.sesse.net Git - vlc/blob - modules/demux/rtp.c
Update the symbol list
[vlc] / modules / demux / rtp.c
1 /*****************************************************************************
2  * rtp.c : Real-Time Protocol (RTP) demux module for VLC media player
3  *****************************************************************************
4  * Copyright (C) 2001-2005 the VideoLAN team
5  * Copyright © 2007 Rémi Denis-Courmont
6  * $Id$
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 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #include <vlc/vlc.h>
27 #include <stdarg.h>
28 #include <assert.h>
29
30 #include <vlc_demux.h>
31 #include <vlc_aout.h>
32
33 #include <vlc_codecs.h>
34
35 /*****************************************************************************
36  * Module descriptor
37  *****************************************************************************/
38
39 #define RTP_MAX_DROPOUT_TEXT N_("RTP maximum sequence number dropout")
40 #define RTP_MAX_DROPOUT_LONGTEXT N_( \
41     "RTP packets will be discarded if they are too much ahead (i.e. in the " \
42     "future) by this many packets from the last received packet." )
43
44 #define RTP_MAX_MISORDER_TEXT N_("RTP maximum sequence number misordering")
45 #define RTP_MAX_MISORDER_LONGTEXT N_( \
46     "RTP packets will be discarded if they are too far behind (i.e. in the " \
47     "past) by this many packets from the last received packet." )
48
49 #define RTP_MIN_SEQUENTIAL_TEXT N_("RTP minimum sequential packets count")
50 #define RTP_MIN_SEQUENTIAL_LONGTEXT N_( \
51     "VLC will wait until it has received this many sequential RTP packets " \
52     "before it considers the RTP stream synchronized." )
53
54
55 static int  Open (vlc_object_t *);
56 static void Close (vlc_object_t *);
57
58 vlc_module_begin ();
59     set_shortname (_("RTP"));
60     set_description (_("(Experimental) Real-Time Protocol demuxer"));
61     set_category (CAT_INPUT);
62     set_subcategory (SUBCAT_INPUT_DEMUX);
63     set_capability ("access_demux", 10);
64     set_callbacks (Open, Close);
65
66     add_integer( "rtp-max-dropout", 3000, NULL, RTP_MAX_DROPOUT_TEXT,
67                  RTP_MAX_DROPOUT_LONGTEXT, VLC_TRUE );
68     add_integer( "rtp-max-misorder", 100, NULL, RTP_MAX_MISORDER_TEXT,
69                  RTP_MAX_MISORDER_LONGTEXT, VLC_TRUE );
70     add_integer( "rtp-min-seq", 2, NULL, RTP_MIN_SEQUENTIAL_TEXT,
71                  RTP_MIN_SEQUENTIAL_LONGTEXT, VLC_TRUE );
72
73     add_shortcut ("rtp");
74 vlc_module_end ();
75
76 /*****************************************************************************
77  * Local prototypes
78  *****************************************************************************/
79 static int Demux (demux_t *);
80 static int Control (demux_t *, int i_query, va_list args);
81 static block_t *ParseRTP (demux_t *obj, block_t *p_block, int8_t *pt,
82                           uint16_t *seq);
83
84 #define RTP_PACKET_SIZE 0xffff
85
86 typedef int (*rtp_pt_cb) (demux_t *, block_t *, void *);
87
88 /* State for a RTP source */
89 typedef struct rtp_source_t
90 {
91     uint32_t ssrc; /* current synchronization source */
92     int8_t   pt;   /* current payload type, -1 if none */
93
94     uint8_t  probation; /* how many packets left before resync */
95     uint16_t max_seq; /* next expected sequence */
96     uint16_t bad_seq; /* tentatively next expected sequence for resync */
97 } rtp_source_t;
98
99 /* State for a RTP session */
100 typedef struct rtp_session_t
101 {
102     /*stream_t *feed;*/ /* where data comes from */
103     /* TODO: keep values to sync multiple sessions. */
104     /* We'd need to parse RTCP SR to do that though... */
105     rtp_source_t src[1];
106 } rtp_session_t;
107
108
109 struct demux_sys_t
110 {
111     uint16_t max_dropout;
112     uint16_t max_misorder;
113     uint16_t min_sequential;
114
115     rtp_session_t session;
116 };
117
118
119 /*****************************************************************************
120  * Open: check stream and initializes structures
121  *****************************************************************************/
122 static int Open (vlc_object_t *obj)
123 {
124     demux_t *demux = (demux_t *)obj;
125     demux_sys_t *p_sys;
126
127     assert (demux->s == NULL);
128     msg_Dbg (pbj, "access = %s", obj->psz_access);
129
130     /* Initializes demux */
131     p_sys = calloc (1, sizeof (*p_sys));
132     if (p_sys == NULL)
133         return VLC_ENOMEM;
134
135     p_sys->max_dropout = var_CreateGetInteger (obj, "rtp-max-dropout");
136     p_sys->max_misorder = var_CreateGetInteger (obj, "rtp-max-misorder");
137     p_sys->min_sequential = var_CreateGetInteger (obj, "rtp-min-seq");
138
139     demux->pf_demux   = Demux;
140     demux->pf_control = Control;
141     demux->p_sys      = p_sys;
142
143     return VLC_SUCCESS;
144 }
145
146
147 /*****************************************************************************
148  * Close: frees unused data
149  *****************************************************************************/
150 static void Close (vlc_object_t *obj)
151 {
152     demux_sys_t *p_sys = ((demux_t *)obj)->p_sys;
153     free (p_sys);
154 }
155
156 /*****************************************************************************
157  * Control:
158  *****************************************************************************/
159 static int Control (demux_t *p_demux, int i_query, va_list args)
160 {
161     /*demux_sys_t *p_sys  = p_demux->p_sys;*/
162
163     switch (i_query)
164     {
165         case DEMUX_GET_POSITION:
166             return VLC_EGENERIC;
167
168         case DEMUX_GET_TIME:
169         case DEMUX_GET_LENGTH:
170         {
171             int64_t *v = va_arg (args, int64_t *);
172             *v = 0;
173             return 0;
174         }
175     }
176
177     return VLC_EGENERIC;
178 }
179
180
181 static int Demux (demux_t *demux)
182 {
183     //demux_sys_t *p_sys = demux->p_sys;
184     block_t *block = stream_Block (demux->s, RTP_PACKET_SIZE);
185     uint16_t seq;
186     int8_t pt;
187
188     if (block == NULL)
189         return 0;
190
191     block = ParseRTP (demux, block, &pt, &seq);
192     if (block == NULL)
193         return 1;
194
195     msg_Dbg (demux, "got len = %5u; PT = %3d, seq = %5u", block->i_buffer, pt, seq);
196
197     return 1;
198 }
199
200
201 static block_t *ParseRTP (demux_t *obj, block_t *p_block, int8_t *pt,
202                           uint16_t *seq)
203 {
204     size_t i_skip = 12;
205
206     /* RTP header sanity checks (see RFC 3550) */
207     if (p_block->i_buffer < 12)
208         goto trash;
209
210     if (p_block->i_buffer > RTP_PACKET_SIZE)
211     {
212         msg_Err (obj, "RTP packet too big! wrong demux?");
213         goto trash;
214     }
215
216     // Version number:
217     if ((p_block->p_buffer[0] >> 6 ) != 2)
218     {
219         // STUN/ICE anyone ?
220         msg_Dbg (obj, "RTP version is %u instead of 2", p_block->p_buffer[0] >> 6);
221         goto trash;
222     }
223
224     // Padding bit:
225     uint8_t pad = (p_block->p_buffer[0] & 0x20)
226                  ? p_block->p_buffer[p_block->i_buffer - 1] : 0;
227
228     // CSRC count:
229     i_skip += (p_block->p_buffer[0] & 0x0F) * 4;
230
231     // Extension header:
232     if (p_block->p_buffer[0] & 0x10) /* Extension header */
233     {
234         i_skip += 4;
235         if ((size_t)p_block->i_buffer < i_skip)
236             goto trash;
237
238         i_skip += 4 * GetWBE (p_block->p_buffer + i_skip - 2);
239     }
240
241     if ((size_t)p_block->i_buffer < (i_skip + pad))
242         goto trash;
243
244     *pt = p_block->p_buffer[1] & 0x7F;
245     *seq = GetWBE (p_block->p_buffer + 2);
246
247     /* This is the place for deciphering and authentication */
248
249     /* Remove the RTP header */
250     p_block->i_buffer -= i_skip;
251     p_block->p_buffer += i_skip;
252
253     /* Remove padding (at the end) */
254     p_block->i_buffer -= pad;
255
256     return p_block;
257
258 trash:
259     block_Release (p_block);
260     msg_Dbg (obj, "ignored non-RTP packet");
261     return NULL;
262 }
263
264
265 /**
266  * Initializes a source before any packet has been received
267  */
268 static
269 void PreinitSource (const demux_sys_t *p_sys, rtp_source_t *src)
270 {
271     src->pt = -1;
272     src->probation = p_sys->min_sequential;
273 }
274
275
276 /**
277  * Reinitializes a source (resynchronization)
278  */
279 static
280 void InitSource (const demux_sys_t *p_sys, rtp_source_t *src, uint32_t ssrc,
281                  uint16_t seq)
282 {
283     src->ssrc = ssrc;
284     (void)src->pt;
285
286     src->probation = p_sys->min_sequential - 1;
287     src->bad_seq = src->max_seq = seq;
288 }
289
290
291 #if 0
292 /*
293  * Generic packet handlers
294  */
295
296 /* Ignore a packet */
297 static int pt_ignore (demux_t *obj, block_t *block, rtp_pt_t *self)
298 {
299     (void)self;
300     msg_Dbg (obj, "ignoring unknown payload type");
301     block_Release (block);
302     return 0;
303 }
304
305
306 /* Send a packet to decoder */
307 #if 0
308 static void pt_decode (demux_t *obj, block_t *block, rtp_pt_t *self)
309 {
310     p_block->i_pts = p_block->i_dts = date_... (...);
311     es_out_Control (obj->out, ES_OUT_SET_PCR, p_block->i_pts);
312     es_out_Send (obj->out, (es_out_id_t *)*p_id, block);
313     return 0;
314 }
315 #endif
316
317
318 /* Send a packet to a chained demuxer */
319 static
320 int pt_demux (demux_t *obj, block_t *block, rtp_pt_t *self, const char *demux)
321 {
322     stream_t *stream = self->data.demux.stream;
323
324     if (stream == NULL)
325     {
326         stream = stream_DemuxNew (obj, demux, obj->out);
327         if (stream == NULL)
328             return VLC_EGENERIC;
329         self->data.demux.stream = stream;
330     }
331
332     stream_DemuxSend (stream, block);
333     return 0;
334 }
335
336
337 /*
338  * Static payload types handler
339  */
340
341 /* PT=14
342  * MPA: MPEG Audio (RFC2250, §3.4)
343  */
344 static int pt_mpa (demux_t *obj, block_t *block, rtp_pt_t *self)
345 {
346     if (block->i_buffer < 4)
347         return VLC_EGENERIC;
348
349     block->i_buffer -= 4; // 32 bits RTP/MPA header
350     block->p_buffer += 4;
351
352     return pt_demux (obj, block, self, "mpga");
353 }
354
355
356 /* PT=32
357  * MPV: MPEG Video (RFC2250, §3.5)
358  */
359 static int pt_mpv (demux_t *obj, block_t *block, rtp_pt_t *self)
360 {
361     if (block->i_buffer < 4)
362         return VLC_EGENERIC;
363
364     block->i_buffer -= 4; // 32 bits RTP/MPV header
365     block->p_buffer += 4;
366
367     if (block->p_buffer[-3] & 0x4)
368     {
369         /* MPEG2 Video extension header */
370         /* TODO: shouldn't we skip this too ? */
371     }
372
373     return pt_demux (obj, block, self, "mpgv");
374 }
375
376
377 /* PT=33
378  * MP2: MPEG TS (RFC2250, §2)
379  */
380 static int pt_ts (demux_t *obj, block_t *block, rtp_pt_t *self)
381 {
382     return pt_demux (obj, block, self, "ts");
383 }
384
385
386 /*
387  * Dynamic payload type handlers
388  * Hmm, none implemented yet.
389  */
390 #endif