1 /*****************************************************************************
2 * udp.c: raw UDP & RTP input module
3 *****************************************************************************
4 * Copyright (C) 2001-2005 the VideoLAN team
7 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8 * Tristan Leteurtre <tooney@via.ecp.fr>
9 * Laurent Aimar <fenrir@via.ecp.fr>
10 * Jean-Paul Saman <jpsaman #_at_# m2x dot nl>
12 * Reviewed: 23 October 2003, Jean-Paul Saman <jpsaman@wxs.nl>
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
19 * This program is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with this program; if not, write to the Free Software
26 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
27 *****************************************************************************/
29 /*****************************************************************************
31 *****************************************************************************/
35 #include <vlc/input.h>
39 /*****************************************************************************
41 *****************************************************************************/
42 #define CACHING_TEXT N_("Caching value in ms")
43 #define CACHING_LONGTEXT N_( \
44 "Allows you to modify the default caching value for UDP streams. This " \
45 "value should be set in millisecond units." )
47 #define AUTO_MTU_TEXT N_("Autodetection of MTU")
48 #define AUTO_MTU_LONGTEXT N_( \
49 "Allows growing the MTU if truncated packets are found" )
51 #define RTP_LATE_TEXT N_("Reorder timeout in ms for late RTP packets")
52 #define RTP_LATE_LONGTEXT N_( \
53 "Allows you to modify the RTP packets reorder and late behaviour. " \
54 "If enabled (value>0) then out-of-order packets will be held for the " \
55 "specified timeout in ms. " \
56 "The default behaviour is not to reorder." )
58 static int Open ( vlc_object_t * );
59 static void Close( vlc_object_t * );
62 set_shortname( _("UDP/RTP" ) );
63 set_description( _("UDP/RTP input") );
64 set_category( CAT_INPUT );
65 set_subcategory( SUBCAT_INPUT_ACCESS );
67 add_integer( "udp-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT,
68 CACHING_LONGTEXT, VLC_TRUE );
69 add_bool( "udp-auto-mtu", 1, NULL,
70 AUTO_MTU_TEXT, AUTO_MTU_LONGTEXT, VLC_TRUE );
72 add_integer( "rtp-late", 0, NULL, RTP_LATE_TEXT, RTP_LATE_LONGTEXT, VLC_TRUE );
74 set_capability( "access2", 0 );
75 add_shortcut( "udp" );
76 add_shortcut( "udpstream" );
77 add_shortcut( "udp4" );
78 add_shortcut( "udp6" );
79 add_shortcut( "rtp" );
80 add_shortcut( "rtp4" );
81 add_shortcut( "rtp6" );
82 set_callbacks( Open, Close );
85 /*****************************************************************************
87 *****************************************************************************/
88 #define RTP_HEADER_LEN 12
89 #define RTP_SEQ_NUM_SIZE 65536
91 static block_t *BlockUDP( access_t * );
92 static block_t *BlockRTP( access_t * );
93 static block_t *BlockChoose( access_t * );
94 static int Control( access_t *, int, va_list );
101 vlc_bool_t b_auto_mtu;
104 uint16_t i_sequence_number;
105 vlc_bool_t b_first_seqno;
107 /* reorder rtp packets when out-of-bounds
108 * the packets hold queue is one level deep
110 uint32_t i_rtp_late; /* number of ms an RTP packet may be too late*/
111 uint32_t i_last_pcr; /* last known good PCR */
112 block_t *p_list; /* list of packets to rearrange */
113 block_t *p_end; /* last packet in p_list */
116 /*****************************************************************************
117 * Open: open the socket
118 *****************************************************************************/
119 static int Open( vlc_object_t *p_this )
121 access_t *p_access = (access_t*)p_this;
124 char *psz_name = strdup( p_access->psz_path );
125 char *psz_parser, *psz_server_addr, *psz_bind_addr = "";
126 int i_bind_port, i_server_port = 0;
128 /* First set ipv4/ipv6 */
129 var_Create( p_access, "ipv4", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
130 var_Create( p_access, "ipv6", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
132 if( *p_access->psz_access )
135 /* Find out which shortcut was used */
136 if( !strncmp( p_access->psz_access, "udp4", 6 ) ||
137 !strncmp( p_access->psz_access, "rtp4", 6 ))
139 val.b_bool = VLC_TRUE;
140 var_Set( p_access, "ipv4", val );
142 val.b_bool = VLC_FALSE;
143 var_Set( p_access, "ipv6", val );
145 else if( !strncmp( p_access->psz_access, "udp6", 6 ) ||
146 !strncmp( p_access->psz_access, "rtp6", 6 ) )
148 val.b_bool = VLC_TRUE;
149 var_Set( p_access, "ipv6", val );
151 val.b_bool = VLC_FALSE;
152 var_Set( p_access, "ipv4", val );
156 i_bind_port = var_CreateGetInteger( p_access, "server-port" );
158 /* Parse psz_name syntax :
159 * [serveraddr[:serverport]][@[bindaddr]:[bindport]] */
160 psz_parser = strchr( psz_name, '@' );
161 if( psz_parser != NULL )
163 /* Found bind address and/or bind port */
164 *psz_parser++ = '\0';
165 psz_bind_addr = psz_parser;
167 if( *psz_parser == '[' )
168 /* skips bracket'd IPv6 address */
169 psz_parser = strchr( psz_parser, ']' );
171 if( psz_parser != NULL )
173 psz_parser = strchr( psz_parser, ':' );
174 if( psz_parser != NULL )
176 *psz_parser++ = '\0';
177 i_bind_port = atoi( psz_parser );
182 psz_server_addr = psz_name;
183 if( *psz_server_addr == '[' )
184 /* skips bracket'd IPv6 address */
185 psz_parser = strchr( psz_name, ']' );
187 if( psz_parser != NULL )
189 psz_parser = strchr( psz_parser, ':' );
190 if( psz_parser != NULL )
192 *psz_parser++ = '\0';
193 i_server_port = atoi( psz_parser );
197 msg_Dbg( p_access, "opening server=%s:%d local=%s:%d",
198 psz_server_addr, i_server_port, psz_bind_addr, i_bind_port );
200 /* Set up p_access */
201 p_access->pf_read = NULL;
202 if( !strcasecmp( p_access->psz_access, "rtp" )
203 || !strcasecmp( p_access->psz_access, "rtp4" )
204 || !strcasecmp( p_access->psz_access, "rtp6" ) )
206 p_access->pf_block = BlockRTP;
210 p_access->pf_block = BlockChoose;
212 p_access->pf_control = Control;
213 p_access->pf_seek = NULL;
214 p_access->info.i_update = 0;
215 p_access->info.i_size = 0;
216 p_access->info.i_pos = 0;
217 p_access->info.b_eof = VLC_FALSE;
218 p_access->info.i_title = 0;
219 p_access->info.i_seekpoint = 0;
221 p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) );
222 p_sys->fd = net_OpenUDP( p_access, psz_bind_addr, i_bind_port,
223 psz_server_addr, i_server_port );
226 msg_Err( p_access, "cannot open socket" );
233 net_StopSend( p_sys->fd );
236 p_sys->i_mtu = var_CreateGetInteger( p_access, "mtu" );
237 if( p_sys->i_mtu <= 1 )
238 p_sys->i_mtu = 1500; /* Avoid problem */
240 p_sys->b_auto_mtu = var_CreateGetBool( p_access, "udp-auto-mtu" );;
242 /* Update default_pts to a suitable value for udp access */
243 var_Create( p_access, "udp-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
245 /* Keep track of RTP sequence number */
246 p_sys->i_sequence_number = 0;
247 p_sys->b_first_seqno = VLC_TRUE;
249 /* RTP reordering out-of-bound packets */
250 p_sys->i_last_pcr = 0;
251 p_sys->i_rtp_late = var_CreateGetInteger( p_access, "rtp-late" );
252 p_sys->p_list = NULL;
258 /*****************************************************************************
259 * Close: free unused data structures
260 *****************************************************************************/
261 static void Close( vlc_object_t *p_this )
263 access_t *p_access = (access_t*)p_this;
264 access_sys_t *p_sys = p_access->p_sys;
266 block_ChainRelease( p_sys->p_list );
267 net_Close( p_sys->fd );
271 /*****************************************************************************
273 *****************************************************************************/
274 static int Control( access_t *p_access, int i_query, va_list args )
276 access_sys_t *p_sys = p_access->p_sys;
284 case ACCESS_CAN_SEEK:
285 case ACCESS_CAN_FASTSEEK:
286 case ACCESS_CAN_PAUSE:
287 case ACCESS_CAN_CONTROL_PACE:
288 pb_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t* );
289 *pb_bool = VLC_FALSE;
293 pi_int = (int*)va_arg( args, int * );
294 *pi_int = p_sys->i_mtu;
297 case ACCESS_GET_PTS_DELAY:
298 pi_64 = (int64_t*)va_arg( args, int64_t * );
299 *pi_64 = var_GetInteger( p_access, "udp-caching" ) * 1000;
303 case ACCESS_SET_PAUSE_STATE:
304 case ACCESS_GET_TITLE_INFO:
305 case ACCESS_SET_TITLE:
306 case ACCESS_SET_SEEKPOINT:
307 case ACCESS_SET_PRIVATE_ID_STATE:
311 msg_Warn( p_access, "unimplemented query in control" );
318 /*****************************************************************************
320 *****************************************************************************/
321 static block_t *BlockUDP( access_t *p_access )
323 access_sys_t *p_sys = p_access->p_sys;
327 p_block = block_New( p_access, p_sys->i_mtu );
328 p_block->i_buffer = net_Read( p_access, p_sys->fd, NULL,
329 p_block->p_buffer, p_sys->i_mtu,
331 if( p_block->i_buffer <= 0 )
333 block_Release( p_block );
337 if( (p_block->i_buffer >= p_sys->i_mtu) && p_sys->b_auto_mtu &&
338 p_sys->i_mtu < 32767 )
340 /* Increase by 100% */
342 msg_Dbg( p_access, "increasing MTU to %d", p_sys->i_mtu );
349 * rtp_ChainInsert - insert a p_block in the chain and
350 * look at the sequence numbers.
352 static inline void rtp_ChainInsert( access_t *p_access, block_t *p_block )
354 access_sys_t *p_sys = (access_sys_t *) p_access->p_sys;
355 block_t *p_list = p_sys->p_list;
356 block_t *p_end = p_sys->p_end;
360 uint16_t i_expected = 0;
361 uint32_t i_pcr_new = 0;
363 if( !p_block ) return;
366 p_sys->p_list = p_block;
367 p_sys->p_end = p_block;
371 /* Appending packets at the end of the chain is the normal case */
372 i_pcr_new = ( (p_block->p_buffer[4] << 24) +
373 (p_block->p_buffer[5] << 16) +
374 (p_block->p_buffer[6] << 8) +
375 p_block->p_buffer[7] );
376 i_new = ( (p_block->p_buffer[2] << 8 ) + p_block->p_buffer[3] );
377 i_cur = ( (p_end->p_buffer[2] << 8 ) + p_end->p_buffer[3] );
379 i_expected = i_cur + 1;
380 if( (i_new - i_expected) >= 0 ) /* Append at the end? */
382 msg_Dbg( p_access, "RTP: append %u after %u", i_new, i_cur );
383 p_end->p_next = p_block;
384 p_sys->p_end = p_end->p_next;
387 /* Add to the front fo the chain? */
389 i_cur = ( (p->p_buffer[2] << 8 ) + p->p_buffer[3] );
390 if( (i_expected - i_new) > 0 )
392 msg_Dbg( p_access, "RTP: prepend %u before %u", i_cur, i_new );
394 p_sys->p_list = p_block;
397 /* The packet can't be added to the front or the end of the chain,
398 * thus walk the chain from the start.
402 i_cur = (p->p_buffer[2] << 8 ) + p->p_buffer[3];
403 i_expected = i_cur+1;
405 if( (i_cur - i_new) == 0 )
407 uint32_t i_pcr_cur = ( (p->p_buffer[4] << 24) +
408 (p->p_buffer[5] << 16) +
409 (p->p_buffer[6] << 8) +
411 /* This packet might be a duplicate, so check PCR's */
412 if( i_pcr_cur >= i_pcr_new )
414 /* packet way too late drop it. */
415 block_Release( p_block );
418 /* Add it to list later on
419 * else if( i_pcr_cur < i_pcr_new ) */
422 else if( (i_expected - i_new) >= 0 ) /* insert in chain */
424 block_t *p_tmp = NULL;
427 msg_Dbg( p_access, "RTP: insert %u after %u", i_new, i_cur );
429 p_block->p_next = p_tmp;
432 if( !p->p_next ) break;
435 msg_Dbg(p_access, "RTP: trashing duplicate %d", i_new );
436 block_Release( p_block );
440 * rtp_ChainSend - look which packets are ready for sending.
442 static inline block_t *rtp_ChainSend( access_t *p_access, block_t **pp_list, uint16_t i_seq )
444 access_sys_t *p_sys = (access_sys_t *) p_access->p_sys;
449 /* Parse RTP header */
451 int i_extension_bit = 0;
452 int i_extension_length = 0;
453 int i_CSRC_count = 0;
454 int i_payload_type = 0;
455 uint32_t i_pcr_prev = 0;
456 uint16_t i_seq_prev = 0;
458 block_t *p_prev = NULL;
459 block_t *p_send = *pp_list;
460 block_t *p = *pp_list;
464 i_cur = (p->p_buffer[2] << 8 ) + p->p_buffer[3];
465 if( (i_cur - i_seq) == 0 )
467 msg_Dbg( p_access, "rtp_ChainSend: sequence number %u", i_seq );
469 i_seq++; /* sent all packets that are received in order */
471 /* Remember PCR and sequence number of packet
472 * for next iteration */
473 i_pcr_prev = ( (p->p_buffer[4] << 24) +
474 (p->p_buffer[5] << 16) +
475 (p->p_buffer[6] << 8) +
477 i_seq_prev = ( (p->p_buffer[2] << 8 ) +
480 /* Parse headerfields we need */
481 i_CSRC_count = p->p_buffer[0] & 0x0F;
482 i_payload_type = (p->p_buffer[1] & 0x7F);
483 i_extension_bit = ( p->p_buffer[0] & 0x10 ) >> 4;
484 if ( i_extension_bit == 1)
485 i_extension_length = ( (p->p_buffer[14] << 8 ) +
488 /* Skip header + CSRC extension field n*(32 bits) + extention */
489 i_skip = RTP_HEADER_LEN + 4*i_CSRC_count + i_extension_length;
490 if( i_payload_type == 14 ) i_skip += 4;
492 /* Return the packet without the RTP header. */
493 p->i_buffer -= i_skip;
494 p->p_buffer += i_skip;
496 else if( (i_cur - i_seq) > 0 )
501 p_prev->p_next = NULL;
502 p_sys->i_last_pcr = i_pcr_prev;
503 p_sys->i_sequence_number = i_seq_prev;
509 if (!p->p_next) break;
514 /* We have walked through the complete chain and all packets are
515 * in sequence - so send the whole chain
517 i_payload_type = (p->p_buffer[1] & 0x7F);
518 i_CSRC_count = p->p_buffer[0] & 0x0F;
519 i_extension_bit = ( p->p_buffer[0] & 0x10 ) >> 4;
520 if( i_extension_bit == 1)
521 i_extension_length = ( (p->p_buffer[14] << 8 ) + p->p_buffer[15] );
523 /* Skip header + CSRC extension field n*(32 bits) + extention */
524 i_skip = RTP_HEADER_LEN + 4*i_CSRC_count + i_extension_length;
525 if( i_payload_type == 14 ) i_skip += 4;
527 /* Update the list pointers */
528 p_sys->p_list = NULL;
530 p_sys->i_sequence_number = ( (p->p_buffer[2] << 8 ) +
532 p_sys->i_last_pcr = ( (p->p_buffer[4] << 24) +
533 (p->p_buffer[5] << 16) +
534 (p->p_buffer[6] << 8) +
536 /* Return the packet without the RTP header. */
537 p->i_buffer -= i_skip;
538 p->p_buffer += i_skip;
544 /*****************************************************************************
545 * BlockParseRTP/BlockRTP:
546 *****************************************************************************/
547 static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
549 access_sys_t *p_sys = (access_sys_t *) p_access->p_sys;
554 uint16_t i_sequence_number = 0;
555 uint16_t i_sequence_expected = 0;
556 int i_extension_bit = 0;
557 int i_extension_length = 0;
560 if( p_block == NULL )
563 if( p_block->i_buffer < RTP_HEADER_LEN )
565 msg_Warn( p_access, "received a too short packet for RTP" );
566 block_Release( p_block );
569 /* Parse the header and make some verifications.
571 i_rtp_version = ( p_block->p_buffer[0] & 0xC0 ) >> 6;
572 i_CSRC_count = p_block->p_buffer[0] & 0x0F;
573 i_payload_type = p_block->p_buffer[1] & 0x7F;
574 i_sequence_number = (p_block->p_buffer[2] << 8) +
575 p_block->p_buffer[3];
576 i_pcr = ( (p_block->p_buffer[4] << 24) +
577 (p_block->p_buffer[5] << 16) +
578 (p_block->p_buffer[6] << 8) +
579 p_block->p_buffer[7] );
580 i_extension_bit = ( p_block->p_buffer[0] & 0x10 ) >> 4;
582 if( i_rtp_version != 2 )
583 msg_Dbg( p_access, "RTP version is %u, should be 2", i_rtp_version );
585 if( i_payload_type == 14 )
587 else if( i_payload_type != 33 && i_payload_type != 32 )
588 msg_Dbg( p_access, "unsupported RTP payload type (%u)", i_payload_type );
590 if( i_extension_bit == 1)
591 i_extension_length = 4 +
592 4 * ( (p_block->p_buffer[14] << 8) + p_block->p_buffer[15] );
594 /* Skip header + CSRC extension field n*(32 bits) + extention */
595 i_skip += RTP_HEADER_LEN + 4*i_CSRC_count + i_extension_length;
596 if( i_skip >= p_block->i_buffer )
598 msg_Warn( p_access, "received a too short packet for RTP" );
599 block_Release( p_block );
603 /* Detect RTP packet loss through tracking sequence numbers,
604 * and take RTP PCR into account.
607 if( p_sys->b_first_seqno )
609 p_sys->i_sequence_number = i_sequence_number;
610 p_sys->i_last_pcr = i_pcr;
611 p_sys->b_first_seqno = VLC_FALSE;
612 i_sequence_expected = i_sequence_number;
615 i_sequence_expected = p_sys->i_sequence_number + 1;
618 /* Emulate packet loss */
619 if ( (i_sequence_number % 4000) == 0)
621 msg_Warn( p_access, "Emulating packet drop" );
622 block_Release( p_block );
627 if( (i_sequence_expected - i_sequence_number) != 0 )
629 /* Handle out of order packets */
630 if( p_sys->i_rtp_late > 0 )
632 if( (i_sequence_number - i_sequence_expected) > 0 )
635 "RTP packet out of order (too early) expected %u, current %u",
636 i_sequence_expected, i_sequence_number );
637 if( (i_pcr - p_sys->i_last_pcr) >= (p_sys->i_rtp_late*90) )
639 block_t *p_start = p_sys->p_list;
640 uint16_t i_start = (!p_start) ? p_sys->i_sequence_number :
641 (p_start->p_buffer[2] << 8) +
642 p_start->p_buffer[3];
643 /* Gap too big, we have been holding this data for too long,
647 "Gap too big resyncing: delta %u, held for %d ms",
648 (i_pcr - p_sys->i_last_pcr), p_sys->i_rtp_late );
649 rtp_ChainInsert( p_access, p_block );
650 return rtp_ChainSend( p_access, &p_sys->p_list, i_start );
652 /* hold packets that arrive too early. */
653 rtp_ChainInsert( p_access, p_block );
654 return rtp_ChainSend( p_access, &p_sys->p_list, i_sequence_expected );
656 else if( /* ((i_sequence_expected - i_sequence_number ) > 0) && */
657 (p_sys->i_last_pcr - i_pcr) >= 0 )
660 "RTP packet out of order (duplicate or too late) expected %u, current %u .. trashing it",
661 i_sequence_expected, i_sequence_number );
662 block_Release( p_block );
663 p_sys->i_sequence_number = i_sequence_number;
664 p_sys->i_last_pcr = i_pcr;
671 block_t **p_send = &p_sys->p_list;
674 "RTP packet (unexpected condition) expected %u, current %u",
675 i_sequence_expected, i_sequence_number );
677 /* Append block to the end of chain and send whole chain */
678 block_ChainLastAppend( &p_send, p_block );
679 p_sys->p_list = p_sys->p_end = NULL;
680 p_sys->i_sequence_number = i_sequence_number;
681 p_sys->i_last_pcr = i_pcr;
683 /* Return the packet without the RTP header. */
687 p->i_buffer -= i_skip;
688 p->p_buffer += i_skip;
689 if( !p->p_next ) break;
694 /* This code should never be reached !! */
696 "Bug in algorithme: (unexpected condition) expected %u (pcr=%u), current %u (pcr=%u)",
697 i_sequence_expected, i_sequence_number, p_sys->i_last_pcr, i_pcr );
700 "RTP packet(s) lost, expected sequence number %d got %d",
701 i_sequence_expected, i_sequence_number );
703 /* Mark transport error in the first TS packet in the RTP stream. */
704 if( (i_payload_type == 33) && (p_block->p_buffer[0] == 0x47) )
705 p_block->p_buffer[1] |= 0x80;
707 else if( (p_sys->i_rtp_late > 0) && p_sys->p_list )
709 if( (p_sys->i_last_pcr - i_pcr) >= 0 )
712 "RTP packet out of order (duplicate) expected %u, current %u .. trashing it",
713 i_sequence_expected, i_sequence_number );
714 block_Release( p_block );
715 p_sys->i_sequence_number = i_sequence_number;
716 p_sys->i_last_pcr = i_pcr;
719 rtp_ChainInsert( p_access, p_block );
720 return rtp_ChainSend( p_access, &p_sys->p_list, i_sequence_expected );
723 /* This is the normal case when no packet reordering is effective */
724 p_sys->i_sequence_number = i_sequence_number;
725 p_sys->i_last_pcr = i_pcr;
727 /* Return the packet without the RTP header. */
728 p_block->i_buffer -= i_skip;
729 p_block->p_buffer += i_skip;
733 static block_t *BlockRTP( access_t *p_access )
735 block_t *p_block = BlockUDP( p_access );
737 if ( p_block != NULL )
738 return BlockParseRTP( p_access, p_block );
743 /*****************************************************************************
744 * BlockChoose: decide between RTP and UDP
745 *****************************************************************************/
746 static block_t *BlockChoose( access_t *p_access )
753 if( ( p_block = BlockUDP( p_access ) ) == NULL )
756 if( p_block->p_buffer[0] == 0x47 )
758 msg_Dbg( p_access, "detected TS over raw UDP" );
759 p_access->pf_block = BlockUDP;
763 if( p_block->i_buffer < RTP_HEADER_LEN )
766 /* Parse the header and make some verifications.
769 i_rtp_version = ( p_block->p_buffer[0] & 0xC0 ) >> 6;
770 i_CSRC_count = ( p_block->p_buffer[0] & 0x0F );
771 i_payload_type = ( p_block->p_buffer[1] & 0x7F );
773 if( i_rtp_version != 2 )
775 msg_Dbg( p_access, "no supported RTP header detected" );
776 p_access->pf_block = BlockUDP;
780 switch( i_payload_type )
783 msg_Dbg( p_access, "detected TS over RTP" );
784 p_access->psz_demux = strdup( "ts" );
788 msg_Dbg( p_access, "detected MPEG audio over RTP" );
789 p_access->psz_demux = strdup( "mpga" );
793 msg_Dbg( p_access, "detected MPEG video over RTP" );
794 p_access->psz_demux = strdup( "mpgv" );
798 msg_Dbg( p_access, "no RTP header detected" );
799 p_access->pf_block = BlockUDP;
803 p_access->pf_block = BlockRTP;
805 return BlockParseRTP( p_access, p_block );