]> git.sesse.net Git - vlc/blob - modules/access/udp.c
Removes trailing spaces. Removes tabs.
[vlc] / modules / access / udp.c
1 /*****************************************************************************
2  * udp.c: raw UDP & RTP input module
3  *****************************************************************************
4  * Copyright (C) 2001-2005 the VideoLAN team
5  * Copyright (C) 2007 Remi Denis-Courmont
6  * $Id$
7  *
8  * Authors: Christophe Massiot <massiot@via.ecp.fr>
9  *          Tristan Leteurtre <tooney@via.ecp.fr>
10  *          Laurent Aimar <fenrir@via.ecp.fr>
11  *          Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
12  *          Remi Denis-Courmont
13  *
14  * Reviewed: 23 October 2003, Jean-Paul Saman <jpsaman _at_ videolan _dot_ org>
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License as published by
18  * the Free Software Foundation; either version 2 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
24  * GNU General Public License for more details.
25  *
26  * You should have received a copy of the GNU General Public License
27  * along with this program; if not, write to the Free Software
28  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
29  *****************************************************************************/
30
31 /*****************************************************************************
32  * Preamble
33  *****************************************************************************/
34
35 #include <vlc/vlc.h>
36 #include <vlc_access.h>
37 #include <vlc_network.h>
38
39 #ifndef SOCK_DCCP /* provisional API */
40 # ifdef __linux__
41 #  define SOCK_DCCP 6
42 # endif
43 #endif
44
45 #ifndef IPPROTO_DCCP
46 # define IPPROTO_DCCP 33 /* IANA */
47 #endif
48
49 #ifndef IPPROTO_UDPLITE
50 # define IPPROTO_UDPLITE 136 /* from IANA */
51 #endif
52 #ifndef SOL_UDPLITE
53 # define SOL_UDPLITE IPPROTO_UDPLITE
54 #endif
55
56 #define MTU 65535
57
58 /*****************************************************************************
59  * Module descriptor
60  *****************************************************************************/
61 #define CACHING_TEXT N_("Caching value in ms")
62 #define CACHING_LONGTEXT N_( \
63     "Caching value for UDP streams. This " \
64     "value should be set in milliseconds." )
65
66 #define RTP_LATE_TEXT N_("RTP reordering timeout in ms")
67 #define RTP_LATE_LONGTEXT N_( \
68     "VLC reorders RTP packets. The input will wait for late packets at most "\
69     "the time specified here (in milliseconds)." )
70
71 static int  Open ( vlc_object_t * );
72 static void Close( vlc_object_t * );
73
74 vlc_module_begin();
75     set_shortname( _("UDP/RTP" ) );
76     set_description( _("UDP/RTP input") );
77     set_category( CAT_INPUT );
78     set_subcategory( SUBCAT_INPUT_ACCESS );
79
80     add_integer( "udp-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT,
81                  CACHING_LONGTEXT, VLC_TRUE );
82     add_integer( "rtp-late", 100, NULL, RTP_LATE_TEXT, RTP_LATE_LONGTEXT, VLC_TRUE );
83     add_obsolete_bool( "udp-auto-mtu" );
84
85     set_capability( "access2", 0 );
86     add_shortcut( "udp" );
87     add_shortcut( "udpstream" );
88     add_shortcut( "udp4" );
89     add_shortcut( "udp6" );
90     add_shortcut( "rtp" );
91     add_shortcut( "rtp4" );
92     add_shortcut( "rtp6" );
93     add_shortcut( "udplite" );
94     add_shortcut( "rtptcp" );
95     add_shortcut( "dccp" );
96
97     set_callbacks( Open, Close );
98 vlc_module_end();
99
100 /*****************************************************************************
101  * Local prototypes
102  *****************************************************************************/
103 #define RTP_HEADER_LEN 12
104
105 static block_t *BlockUDP( access_t * );
106 static block_t *BlockTCP( access_t * );
107 static block_t *BlockRTP( access_t * );
108 static block_t *BlockChoose( access_t * );
109 static int Control( access_t *, int, va_list );
110
111 struct access_sys_t
112 {
113     int fd;
114
115     vlc_bool_t b_framed_rtp;
116
117     /* reorder rtp packets when out-of-sequence */
118     uint16_t i_last_seqno;
119     mtime_t i_rtp_late;
120     block_t *p_list;
121     block_t *p_end;
122     block_t *p_partial_frame; /* Partial Framed RTP packet */
123 };
124
125 /*****************************************************************************
126  * Open: open the socket
127  *****************************************************************************/
128 static int Open( vlc_object_t *p_this )
129 {
130     access_t     *p_access = (access_t*)p_this;
131     access_sys_t *p_sys;
132
133     char *psz_name = strdup( p_access->psz_path );
134     char *psz_parser;
135     const char *psz_server_addr, *psz_bind_addr = "";
136     int  i_bind_port, i_server_port = 0;
137     int fam = AF_UNSPEC, proto = IPPROTO_UDP;
138
139     if (strlen (p_access->psz_access) >= 3)
140     {
141         switch (p_access->psz_access[3])
142         {
143             case '4':
144                 fam = AF_INET;
145                 break;
146
147             case '6':
148                 fam = AF_INET6;
149                 break;
150         }
151         if (strcmp (p_access->psz_access + 3, "lite") == 0)
152             proto = IPPROTO_UDPLITE;
153         else
154         if (strcmp (p_access->psz_access + 3, "tcp") == 0)
155             proto = IPPROTO_TCP;
156         else
157         if (strcmp (p_access->psz_access, "dccp") == 0)
158             proto = IPPROTO_DCCP;
159     }
160
161     i_bind_port = var_CreateGetInteger( p_access, "server-port" );
162
163     /* Parse psz_name syntax :
164      * [serveraddr[:serverport]][@[bindaddr]:[bindport]] */
165     psz_parser = strchr( psz_name, '@' );
166     if( psz_parser != NULL )
167     {
168         /* Found bind address and/or bind port */
169         *psz_parser++ = '\0';
170         psz_bind_addr = psz_parser;
171
172         if( psz_bind_addr[0] == '[' )
173             /* skips bracket'd IPv6 address */
174             psz_parser = strchr( psz_parser, ']' );
175
176         if( psz_parser != NULL )
177         {
178             psz_parser = strchr( psz_parser, ':' );
179             if( psz_parser != NULL )
180             {
181                 *psz_parser++ = '\0';
182                 i_bind_port = atoi( psz_parser );
183             }
184         }
185     }
186
187     psz_server_addr = psz_name;
188     psz_parser = ( psz_server_addr[0] == '[' )
189         ? strchr( psz_name, ']' ) /* skips bracket'd IPv6 address */
190         : psz_name;
191
192     if( psz_parser != NULL )
193     {
194         psz_parser = strchr( psz_parser, ':' );
195         if( psz_parser != NULL )
196         {
197             *psz_parser++ = '\0';
198             i_server_port = atoi( psz_parser );
199         }
200     }
201
202     msg_Dbg( p_access, "opening server=%s:%d local=%s:%d",
203              psz_server_addr, i_server_port, psz_bind_addr, i_bind_port );
204
205     /* Set up p_access */
206     access_InitFields( p_access );
207     ACCESS_SET_CALLBACKS( NULL, BlockChoose, Control, NULL );
208     p_access->info.b_prebuffered = VLC_FALSE;
209     MALLOC_ERR( p_access->p_sys, access_sys_t ); p_sys = p_access->p_sys;
210     memset (p_sys, 0, sizeof (*p_sys));
211
212     switch (proto)
213     {
214         case IPPROTO_UDP:
215         case IPPROTO_UDPLITE:
216             p_sys->fd = net_OpenDgram( p_access, psz_bind_addr, i_bind_port,
217                                        psz_server_addr, i_server_port, fam,
218                                        proto );
219             break;
220
221         case IPPROTO_TCP:
222             p_sys->fd = net_ConnectTCP( p_access, psz_server_addr, i_server_port );
223             p_sys->b_framed_rtp = VLC_TRUE;
224             break;
225
226         case IPPROTO_DCCP:
227 #ifdef SOCK_DCCP
228             p_sys->fd = net_Connect( p_access, psz_server_addr, i_server_port,
229                                      SOCK_DCCP, IPPROTO_DCCP );
230 #else
231             p_sys->fd = -1;
232             msg_Err( p_access, "DCCP support not compiled-in!" );
233 #endif
234             break;
235     }
236     free (psz_name);
237     if( p_sys->fd == -1 )
238     {
239         msg_Err( p_access, "cannot open socket" );
240         free( p_sys );
241         return VLC_EGENERIC;
242     }
243
244     shutdown( p_sys->fd, SHUT_WR );
245
246     net_SetCSCov (p_sys->fd, -1, 12);
247
248     if (p_sys->b_framed_rtp)
249     {
250         /* We don't do autodetection and prebuffering in case of framing */
251         p_access->pf_block = BlockRTP;
252     }
253
254     /* Update default_pts to a suitable value for udp access */
255     var_Create( p_access, "udp-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
256
257     /* RTP reordering for out-of-sequence packets */
258     p_sys->i_rtp_late = var_CreateGetInteger( p_access, "rtp-late" ) * 1000;
259     p_sys->i_last_seqno = 0;
260     p_sys->p_list = NULL;
261     p_sys->p_end = NULL;
262     return VLC_SUCCESS;
263 }
264
265 /*****************************************************************************
266  * Close: free unused data structures
267  *****************************************************************************/
268 static void Close( vlc_object_t *p_this )
269 {
270     access_t     *p_access = (access_t*)p_this;
271     access_sys_t *p_sys = p_access->p_sys;
272
273     block_ChainRelease( p_sys->p_list );
274     net_Close( p_sys->fd );
275     free( p_sys );
276 }
277
278 /*****************************************************************************
279  * Control:
280  *****************************************************************************/
281 static int Control( access_t *p_access, int i_query, va_list args )
282 {
283     vlc_bool_t   *pb_bool;
284     int          *pi_int;
285     int64_t      *pi_64;
286
287     switch( i_query )
288     {
289         /* */
290         case ACCESS_CAN_SEEK:
291         case ACCESS_CAN_FASTSEEK:
292         case ACCESS_CAN_PAUSE:
293         case ACCESS_CAN_CONTROL_PACE:
294             pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
295             *pb_bool = VLC_FALSE;
296             break;
297         /* */
298         case ACCESS_GET_MTU:
299             pi_int = (int*)va_arg( args, int * );
300             *pi_int = MTU;
301             break;
302
303         case ACCESS_GET_PTS_DELAY:
304             pi_64 = (int64_t*)va_arg( args, int64_t * );
305             *pi_64 = var_GetInteger( p_access, "udp-caching" ) * 1000;
306             break;
307
308         /* */
309         case ACCESS_SET_PAUSE_STATE:
310         case ACCESS_GET_TITLE_INFO:
311         case ACCESS_SET_TITLE:
312         case ACCESS_SET_SEEKPOINT:
313         case ACCESS_SET_PRIVATE_ID_STATE:
314             return VLC_EGENERIC;
315
316         default:
317             msg_Warn( p_access, "unimplemented query in control" );
318             return VLC_EGENERIC;
319
320     }
321     return VLC_SUCCESS;
322 }
323
324 /*****************************************************************************
325  * BlockUDP:
326  *****************************************************************************/
327 static block_t *BlockUDP( access_t *p_access )
328 {
329     access_sys_t *p_sys = p_access->p_sys;
330     block_t      *p_block;
331
332     /* Read data */
333     p_block = block_New( p_access, MTU );
334     p_block->i_buffer = net_Read( p_access, p_sys->fd, NULL,
335                                   p_block->p_buffer, MTU, VLC_FALSE );
336     if( p_block->i_buffer < 0 )
337     {
338         block_Release( p_block );
339         return NULL;
340     }
341
342     return block_Realloc( p_block, 0, p_block->i_buffer );
343 }
344
345 /*****************************************************************************
346  * BlockTCP: Framed RTP/AVP packet reception for COMEDIA (see RFC4571)
347  *****************************************************************************/
348 static block_t *BlockTCP( access_t *p_access )
349 {
350     access_sys_t *p_sys = p_access->p_sys;
351     block_t      *p_block = p_sys->p_partial_frame;
352
353     if( p_access->info.b_eof )
354         return NULL;
355
356     if( p_block == NULL )
357     {
358         /* MTU should always be 65535 in this case */
359         p_sys->p_partial_frame = p_block = block_New( p_access, 2 + MTU );
360         if (p_block == NULL)
361             return NULL;
362     }
363
364     /* Read RTP framing */
365     if (p_block->i_buffer < 2)
366     {
367         /* FIXME: not very efficient */
368         int i_read = net_Read( p_access, p_sys->fd, NULL,
369                                p_block->p_buffer + p_block->i_buffer,
370                                2 - p_block->i_buffer, VLC_FALSE );
371         if( i_read <= 0 )
372             goto error;
373
374         p_block->i_buffer += i_read;
375         if (p_block->i_buffer < 2)
376             return NULL;
377     }
378
379     uint16_t framelen = GetWLE( p_block->p_buffer );
380     /* Read RTP frame */
381     if( framelen > 0 )
382     {
383         int i_read = net_Read( p_access, p_sys->fd, NULL,
384                                p_block->p_buffer + p_block->i_buffer,
385                                2 + framelen - p_block->i_buffer, VLC_FALSE );
386         if( i_read <= 0 )
387             goto error;
388
389         p_block->i_buffer += i_read;
390     }
391
392     if( p_block->i_buffer < (2 + framelen) )
393         return NULL; // incomplete frame
394
395     /* Hide framing from RTP layer */
396     p_block->p_buffer += 2;
397     p_block->i_buffer -= 2;
398     p_sys->p_partial_frame = NULL;
399     return p_block;
400
401 error:
402     p_access->info.b_eof = VLC_TRUE;
403     block_Release( p_block );
404     p_sys->p_partial_frame = NULL;
405     return NULL;
406 }
407
408
409 /*
410  * rtp_ChainInsert - insert a p_block in the chain and
411  * look at the sequence numbers.
412  */
413 static inline vlc_bool_t rtp_ChainInsert( access_t *p_access, block_t *p_block )
414 {
415     access_sys_t *p_sys = (access_sys_t *) p_access->p_sys;
416     block_t *p_prev = NULL;
417     block_t *p = p_sys->p_end;
418     uint16_t i_new = (uint16_t) p_block->i_dts;
419     uint16_t i_tmp = 0;
420
421     if( !p_sys->p_list )
422     {
423         p_sys->p_list = p_block;
424         p_sys->p_end = p_block;
425         return VLC_TRUE;
426     }
427     /* walk through the queue from top down since the new packet is in
428     most cases just appended to the end */
429
430     for( ;; )
431     {
432         i_tmp = i_new - (uint16_t) p->i_dts;
433
434         if( !i_tmp )   /* trash duplicate */
435             break;
436
437         if ( i_tmp < 32768 )
438         {   /* insert after this block ( i_new > p->i_dts ) */
439             p_block->p_next = p->p_next;
440             p->p_next = p_block;
441             p_block->p_prev = p;
442             if (p_prev)
443             {
444                 p_prev->p_prev = p_block;
445                 msg_Dbg(p_access, "RTP reordering: insert after %d, new %d",
446                         (uint16_t) p->i_dts, i_new );
447             }
448             else
449             {
450                 p_sys->p_end = p_block;
451             }
452             return VLC_TRUE;
453         }
454         if( p == p_sys->p_list )
455         {   /* we've reached bottom of chain */
456             i_tmp = p_sys->i_last_seqno - i_new;
457             if( !p_access->info.b_prebuffered || (i_tmp > 32767) )
458             {
459                 msg_Dbg(p_access, "RTP reordering: prepend %d before %d",
460                         i_new, (uint16_t) p->i_dts );
461                 p_block->p_next = p;
462                 p->p_prev = p_block;
463                 p_sys->p_list = p_block;
464                 return VLC_TRUE;
465             }
466
467             if( !i_tmp )   /* trash duplicate */
468                 break;
469
470             /* reordering failed - append the packet to the end of queue */
471             msg_Dbg(p_access, "RTP: sequence changed (or buffer too small) "
472                     "new: %d, buffer %d...%d", i_new, (uint16_t) p->i_dts,
473                 (uint16_t) p_sys->p_end->i_dts);
474             p_sys->p_end->p_next = p_block;
475             p_block->p_prev = p_sys->p_end;
476             p_sys->p_end = p_block;
477             return VLC_TRUE;
478         }
479         p_prev = p;
480         p = p->p_prev;
481     }
482     block_Release( p_block );
483     return VLC_FALSE;
484 }
485
486 /*****************************************************************************
487  * BlockParseRTP/BlockRTP:
488  *****************************************************************************/
489 static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
490 {
491     int      i_payload_type;
492     size_t   i_skip = RTP_HEADER_LEN;
493
494     if( p_block == NULL )
495         return NULL;
496
497     if( p_block->i_buffer < RTP_HEADER_LEN )
498     {
499         msg_Dbg( p_access, "short RTP packet received" );
500         goto trash;
501     }
502
503     /* Parse the header and make some verifications.
504      * See RFC 3550. */
505     // Version number:
506     if( ( p_block->p_buffer[0] >> 6 ) != 2)
507     {
508         msg_Dbg( p_access, "RTP version is %u instead of 2",
509                  p_block->p_buffer[0] >> 6 );
510         goto trash;
511     }
512     // Padding bit:
513     uint8_t pad = (p_block->p_buffer[0] & 0x20)
514                     ? p_block->p_buffer[p_block->i_buffer - 1] : 0;
515     // CSRC count:
516     i_skip += (p_block->p_buffer[0] & 0x0F) * 4;
517     // Extension header:
518     if (p_block->p_buffer[0] & 0x10) /* Extension header */
519     {
520         i_skip += 4;
521         if ((size_t)p_block->i_buffer < i_skip)
522             goto trash;
523
524         i_skip += 4 * GetWBE( p_block->p_buffer + i_skip - 2 );
525     }
526
527     i_payload_type    = p_block->p_buffer[1] & 0x7F;
528
529     /* Remember sequence number in i_dts */
530     p_block->i_pts = mdate();
531     p_block->i_dts = (mtime_t) GetWBE( p_block->p_buffer + 2 );
532
533     /* FIXME: use rtpmap */
534     switch( i_payload_type )
535     {
536         case 14: // MPA: MPEG Audio (RFC2250, §3.4)
537             i_skip += 4; // 32 bits RTP/MPA header
538             break;
539
540         case 32: // MPV: MPEG Video (RFC2250, §3.5)
541             i_skip += 4; // 32 bits RTP/MPV header
542             if( (size_t)p_block->i_buffer < i_skip )
543                 goto trash;
544             if( p_block->p_buffer[i_skip - 3] & 0x4 )
545             {
546                 /* MPEG2 Video extension header */
547                 /* TODO: shouldn't we skip this too ? */
548             }
549             break;
550
551         case 33: // MP2: MPEG TS (RFC2250, §2)
552             /* plain TS over RTP */
553             break;
554
555         default:
556             msg_Dbg( p_access, "unsupported RTP payload type: %u", i_payload_type );
557             goto trash;
558     }
559
560     if( (size_t)p_block->i_buffer < (i_skip + pad) )
561         goto trash;
562
563     /* Remove the RTP header */
564     p_block->i_buffer -= i_skip;
565     p_block->p_buffer += i_skip;
566
567     /* This is the place for deciphering and authentication */
568
569     /* Remove padding (at the end) */
570     p_block->i_buffer -= pad;
571
572 #if 0
573     /* Emulate packet loss */
574     if ( (i_sequence_number % 4000) == 0)
575     {
576         msg_Warn( p_access, "Emulating packet drop" );
577         block_Release( p_block );
578         return NULL;
579     }
580 #endif
581
582     return p_block;
583
584 trash:
585     block_Release( p_block );
586     return NULL;
587 }
588
589 static block_t *BlockPrebufferRTP( access_t *p_access, block_t *p_block )
590 {
591     access_sys_t *p_sys = p_access->p_sys;
592     mtime_t   i_first = mdate();
593     int       i_count = 0;
594     block_t   *p = p_block;
595
596     for( ;; )
597     {
598         mtime_t i_date = mdate();
599
600         if( p && rtp_ChainInsert( p_access, p ))
601             i_count++;
602
603         /* Require at least 2 packets in the buffer */
604         if( i_count > 2 && (i_date - i_first) > p_sys->i_rtp_late )
605             break;
606
607         p = BlockParseRTP( p_access, BlockUDP( p_access ) );
608         if( !p && (i_date - i_first) > p_sys->i_rtp_late )
609         {
610             msg_Err( p_access, "error in RTP prebuffering!" );
611             break;
612         }
613     }
614
615     msg_Dbg( p_access, "RTP: prebuffered %d packets", i_count - 1 );
616     p_access->info.b_prebuffered = VLC_TRUE;
617     p = p_sys->p_list;
618     p_sys->p_list = p_sys->p_list->p_next;
619     p_sys->i_last_seqno = (uint16_t) p->i_dts;
620     p->p_next = NULL;
621     return p;
622 }
623
624 static block_t *BlockRTP( access_t *p_access )
625 {
626     access_sys_t *p_sys = p_access->p_sys;
627     block_t *p;
628
629     while ( !p_sys->p_list ||
630              ( mdate() - p_sys->p_list->i_pts ) < p_sys->i_rtp_late )
631     {
632         p = BlockParseRTP( p_access,
633                            p_sys->b_framed_rtp ? BlockTCP( p_access )
634                                                : BlockUDP( p_access ) );
635         if ( !p )
636             return NULL;
637
638         rtp_ChainInsert( p_access, p );
639     }
640
641     p = p_sys->p_list;
642     p_sys->p_list = p_sys->p_list->p_next;
643     p_sys->i_last_seqno++;
644     if( p_sys->i_last_seqno != (uint16_t) p->i_dts )
645     {
646         msg_Dbg( p_access, "RTP: packet(s) lost, expected %d, got %d",
647                  p_sys->i_last_seqno, (uint16_t) p->i_dts );
648         p_sys->i_last_seqno = (uint16_t) p->i_dts;
649     }
650     p->p_next = NULL;
651     return p;
652 }
653
654 /*****************************************************************************
655  * BlockChoose: decide between RTP and UDP
656  *****************************************************************************/
657 static block_t *BlockChoose( access_t *p_access )
658 {
659     block_t *p_block;
660     int     i_rtp_version;
661     int     i_payload_type;
662
663     if( ( p_block = BlockUDP( p_access ) ) == NULL )
664         return NULL;
665
666     if( p_block->p_buffer[0] == 0x47 )
667     {
668         msg_Dbg( p_access, "detected TS over raw UDP" );
669         p_access->pf_block = BlockUDP;
670         p_access->info.b_prebuffered = VLC_TRUE;
671         return p_block;
672     }
673
674     if( p_block->i_buffer < RTP_HEADER_LEN )
675         return p_block;
676
677     /* Parse the header and make some verifications.
678      * See RFC 3550. */
679
680     i_rtp_version  = p_block->p_buffer[0] >> 6;
681     i_payload_type = ( p_block->p_buffer[1] & 0x7F );
682
683     if( i_rtp_version != 2 )
684     {
685         msg_Dbg( p_access, "no supported RTP header detected" );
686         p_access->pf_block = BlockUDP;
687         p_access->info.b_prebuffered = VLC_TRUE;
688         return p_block;
689     }
690
691     switch( i_payload_type )
692     {
693         case 33:
694             msg_Dbg( p_access, "detected MPEG2 TS over RTP" );
695             p_access->psz_demux = strdup( "ts" );
696             break;
697
698         case 14:
699             msg_Dbg( p_access, "detected MPEG Audio over RTP" );
700             p_access->psz_demux = strdup( "mpga" );
701             break;
702
703         case 32:
704             msg_Dbg( p_access, "detected MPEG Video over RTP" );
705             p_access->psz_demux = strdup( "mpgv" );
706             break;
707
708         default:
709             msg_Dbg( p_access, "no RTP header detected" );
710             p_access->pf_block = BlockUDP;
711             p_access->info.b_prebuffered = VLC_TRUE;
712             return p_block;
713     }
714
715     if( !BlockParseRTP( p_access, p_block )) return NULL;
716
717     p_access->pf_block = BlockRTP;
718
719     return BlockPrebufferRTP( p_access, p_block );
720 }