Commit 4a3274fb authored by Marian Durkovic's avatar Marian Durkovic

modifications for RTP reordering:

 * for RTP, prebuffering is done within RTP access
 * reordering now working within this buffer
 * solves synchro problems since packet rate is preserved 
parent 60acd31a
...@@ -103,6 +103,8 @@ struct access_t ...@@ -103,6 +103,8 @@ struct access_t
int i_title; /* idem, start from 0 (could be menu) */ int i_title; /* idem, start from 0 (could be menu) */
int i_seekpoint;/* idem, start from 0 */ int i_seekpoint;/* idem, start from 0 */
vlc_bool_t b_prebuffered; /* Read only for input */
} info; } info;
access_sys_t *p_sys; access_sys_t *p_sys;
}; };
......
...@@ -77,6 +77,7 @@ typedef struct block_sys_t block_sys_t; ...@@ -77,6 +77,7 @@ typedef struct block_sys_t block_sys_t;
struct block_t struct block_t
{ {
block_t *p_next; block_t *p_next;
block_t *p_prev;
uint32_t i_flags; uint32_t i_flags;
...@@ -87,6 +88,8 @@ struct block_t ...@@ -87,6 +88,8 @@ struct block_t
int i_samples; /* Used for audio */ int i_samples; /* Used for audio */
int i_rate; int i_rate;
uint16_t i_seqno; /* Used for RTP */
int i_buffer; int i_buffer;
uint8_t *p_buffer; uint8_t *p_buffer;
......
...@@ -48,12 +48,11 @@ ...@@ -48,12 +48,11 @@
#define AUTO_MTU_LONGTEXT N_( \ #define AUTO_MTU_LONGTEXT N_( \
"Allows growing the MTU if truncated packets are found" ) "Allows growing the MTU if truncated packets are found" )
#define RTP_LATE_TEXT N_("Reorder timeout in ms for late RTP packets") #define RTP_LATE_TEXT N_("RTP reordering timeout in ms")
#define RTP_LATE_LONGTEXT N_( \ #define RTP_LATE_LONGTEXT N_( \
"Allows you to modify the RTP packets reorder and late behaviour. " \ "Allows you to modify the RTP reordering behaviour. " \
"If enabled (value>0) then out-of-order packets will be held for the " \ "RTP input will wait for late packets upto " \
"specified timeout in ms. " \ "the specified timeout in milisecond units." )
"The default behaviour is not to reorder." )
static int Open ( vlc_object_t * ); static int Open ( vlc_object_t * );
static void Close( vlc_object_t * ); static void Close( vlc_object_t * );
...@@ -66,11 +65,11 @@ vlc_module_begin(); ...@@ -66,11 +65,11 @@ vlc_module_begin();
add_integer( "udp-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT, add_integer( "udp-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT,
CACHING_LONGTEXT, VLC_TRUE ); CACHING_LONGTEXT, VLC_TRUE );
add_integer( "rtp-late", 100, NULL, RTP_LATE_TEXT, RTP_LATE_LONGTEXT, VLC_TRUE );
add_bool( "udp-auto-mtu", 1, NULL, add_bool( "udp-auto-mtu", 1, NULL,
AUTO_MTU_TEXT, AUTO_MTU_LONGTEXT, VLC_TRUE ); AUTO_MTU_TEXT, AUTO_MTU_LONGTEXT, VLC_TRUE );
add_integer( "rtp-late", 0, NULL, RTP_LATE_TEXT, RTP_LATE_LONGTEXT, VLC_TRUE );
set_capability( "access2", 0 ); set_capability( "access2", 0 );
add_shortcut( "udp" ); add_shortcut( "udp" );
add_shortcut( "udpstream" ); add_shortcut( "udpstream" );
...@@ -86,7 +85,6 @@ vlc_module_end(); ...@@ -86,7 +85,6 @@ vlc_module_end();
* Local prototypes * Local prototypes
*****************************************************************************/ *****************************************************************************/
#define RTP_HEADER_LEN 12 #define RTP_HEADER_LEN 12
#define RTP_SEQ_NUM_SIZE 65536
static block_t *BlockUDP( access_t * ); static block_t *BlockUDP( access_t * );
static block_t *BlockRTP( access_t * ); static block_t *BlockRTP( access_t * );
...@@ -100,17 +98,11 @@ struct access_sys_t ...@@ -100,17 +98,11 @@ struct access_sys_t
int i_mtu; int i_mtu;
vlc_bool_t b_auto_mtu; vlc_bool_t b_auto_mtu;
/* rtp only */ /* reorder rtp packets when out-of-sequence */
uint16_t i_sequence_number; int64_t i_rtp_late;
vlc_bool_t b_first_seqno; uint16_t i_last_seqno;
block_t *p_list;
/* reorder rtp packets when out-of-bounds block_t *p_end;
* the packets hold queue is one level deep
*/
uint32_t i_rtp_late; /* number of ms an RTP packet may be too late*/
uint32_t i_last_pcr; /* last known good PCR */
block_t *p_list; /* list of packets to rearrange */
block_t *p_end; /* last packet in p_list */
}; };
/***************************************************************************** /*****************************************************************************
...@@ -215,6 +207,7 @@ static int Open( vlc_object_t *p_this ) ...@@ -215,6 +207,7 @@ static int Open( vlc_object_t *p_this )
p_access->info.i_size = 0; p_access->info.i_size = 0;
p_access->info.i_pos = 0; p_access->info.i_pos = 0;
p_access->info.b_eof = VLC_FALSE; p_access->info.b_eof = VLC_FALSE;
p_access->info.b_prebuffered = VLC_FALSE;
p_access->info.i_title = 0; p_access->info.i_title = 0;
p_access->info.i_seekpoint = 0; p_access->info.i_seekpoint = 0;
...@@ -242,16 +235,12 @@ static int Open( vlc_object_t *p_this ) ...@@ -242,16 +235,12 @@ static int Open( vlc_object_t *p_this )
/* Update default_pts to a suitable value for udp access */ /* Update default_pts to a suitable value for udp access */
var_Create( p_access, "udp-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); var_Create( p_access, "udp-caching", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
/* Keep track of RTP sequence number */
p_sys->i_sequence_number = 0;
p_sys->b_first_seqno = VLC_TRUE;
/* RTP reordering out-of-bound packets */ /* RTP reordering for out-of-sequence packets */
p_sys->i_last_pcr = 0; p_sys->i_rtp_late = var_CreateGetInteger( p_access, "rtp-late" ) * 1000;
p_sys->i_rtp_late = var_CreateGetInteger( p_access, "rtp-late" ); p_sys->i_last_seqno = 0;
p_sys->p_list = NULL; p_sys->p_list = NULL;
p_sys->p_end = NULL; p_sys->p_end = NULL;
return VLC_SUCCESS; return VLC_SUCCESS;
} }
...@@ -349,196 +338,77 @@ static block_t *BlockUDP( access_t *p_access ) ...@@ -349,196 +338,77 @@ static block_t *BlockUDP( access_t *p_access )
* rtp_ChainInsert - insert a p_block in the chain and * rtp_ChainInsert - insert a p_block in the chain and
* look at the sequence numbers. * look at the sequence numbers.
*/ */
static inline void rtp_ChainInsert( access_t *p_access, block_t *p_block ) static inline vlc_bool_t rtp_ChainInsert( access_t *p_access, block_t *p_block )
{ {
access_sys_t *p_sys = (access_sys_t *) p_access->p_sys; access_sys_t *p_sys = (access_sys_t *) p_access->p_sys;
block_t *p_list = p_sys->p_list; block_t *p_prev = NULL;
block_t *p_end = p_sys->p_end; block_t *p = p_sys->p_end;
block_t *p = NULL; uint16_t i_new = p_block->i_seqno;
uint16_t i_new = 0; uint16_t i_tmp = 0;
uint16_t i_cur = 0;
uint16_t i_expected = 0; if( !p_sys->p_list )
uint32_t i_pcr_new = 0;
if( !p_block ) return;
if( !p_list )
{ {
p_sys->p_list = p_block; p_sys->p_list = p_block;
p_sys->p_end = p_block; p_sys->p_end = p_block;
return; return VLC_TRUE;
} }
/* walk through the queue from top down since the new packet is in
most cases just appended to the end */
/* Appending packets at the end of the chain is the normal case */ for( ;; )
i_pcr_new = ( (p_block->p_buffer[4] << 24) +
(p_block->p_buffer[5] << 16) +
(p_block->p_buffer[6] << 8) +
p_block->p_buffer[7] );
i_new = ( (p_block->p_buffer[2] << 8 ) + p_block->p_buffer[3] );
i_cur = ( (p_end->p_buffer[2] << 8 ) + p_end->p_buffer[3] );
i_expected = i_cur + 1;
if( (i_new - i_expected) >= 0 ) /* Append at the end? */
{
msg_Dbg( p_access, "RTP: append %u after %u", i_new, i_cur );
p_end->p_next = p_block;
p_sys->p_end = p_end->p_next;
return;
}
/* Add to the front fo the chain? */
p = p_list;
i_cur = ( (p->p_buffer[2] << 8 ) + p->p_buffer[3] );
if( (i_expected - i_new) > 0 )
{
msg_Dbg( p_access, "RTP: prepend %u before %u", i_cur, i_new );
p_block->p_next = p;
p_sys->p_list = p_block;
return;
}
/* The packet can't be added to the front or the end of the chain,
* thus walk the chain from the start.
*/
while( p )
{ {
i_cur = (p->p_buffer[2] << 8 ) + p->p_buffer[3]; i_tmp = i_new - p->i_seqno;
i_expected = i_cur+1;
if( (i_cur - i_new) == 0 ) if( !i_tmp ) /* trash duplicate */
{
uint32_t i_pcr_cur = ( (p->p_buffer[4] << 24) +
(p->p_buffer[5] << 16) +
(p->p_buffer[6] << 8) +
p->p_buffer[7] );
/* This packet might be a duplicate, so check PCR's */
if( i_pcr_cur >= i_pcr_new )
{
/* packet way too late drop it. */
block_Release( p_block );
return;
}
/* Add it to list later on
* else if( i_pcr_cur < i_pcr_new ) */
break; break;
}
else if( (i_expected - i_new) >= 0 ) /* insert in chain */
{
block_t *p_tmp = NULL;
p_tmp = p->p_next; if ( i_tmp < 32768 )
msg_Dbg( p_access, "RTP: insert %u after %u", i_new, i_cur ); { /* insert after this block ( i_new > p->i_seqno ) */
p_block->p_next = p->p_next;
p->p_next = p_block; p->p_next = p_block;
p_block->p_next = p_tmp; p_block->p_prev = p;
return; if (p_prev)
}
if( !p->p_next ) break;
p = p->p_next;
}
msg_Dbg(p_access, "RTP: trashing duplicate %d", i_new );
block_Release( p_block );
}
/*
* rtp_ChainSend - look which packets are ready for sending.
*/
static inline block_t *rtp_ChainSend( access_t *p_access, block_t **pp_list, uint16_t i_seq )
{
access_sys_t *p_sys = (access_sys_t *) p_access->p_sys;
uint16_t i_cur = 0;
if( *pp_list )
{
/* Parse RTP header */
int i_skip = 0;
int i_extension_bit = 0;
int i_extension_length = 0;
int i_CSRC_count = 0;
int i_payload_type = 0;
uint32_t i_pcr_prev = 0;
uint16_t i_seq_prev = 0;
/* Data pointers */
block_t *p_prev = NULL;
block_t *p_send = *pp_list;
block_t *p = *pp_list;
while( p )
{ {
i_cur = (p->p_buffer[2] << 8 ) + p->p_buffer[3]; p_prev->p_prev = p_block;
if( (i_cur - i_seq) == 0 ) msg_Dbg(p_access, "RTP reordering: insert after %d, new %d",
{ p->i_seqno, i_new );
msg_Dbg( p_access, "rtp_ChainSend: sequence number %u", i_seq );
i_seq++; /* sent all packets that are received in order */
/* Remember PCR and sequence number of packet
* for next iteration */
i_pcr_prev = ( (p->p_buffer[4] << 24) +
(p->p_buffer[5] << 16) +
(p->p_buffer[6] << 8) +
p->p_buffer[7] );
i_seq_prev = ( (p->p_buffer[2] << 8 ) +
p->p_buffer[3] );
/* Parse headerfields we need */
i_CSRC_count = p->p_buffer[0] & 0x0F;
i_payload_type = (p->p_buffer[1] & 0x7F);
i_extension_bit = ( p->p_buffer[0] & 0x10 ) >> 4;
if ( i_extension_bit == 1)
i_extension_length = ( (p->p_buffer[14] << 8 ) +
p->p_buffer[15] );
/* Skip header + CSRC extension field n*(32 bits) + extention */
i_skip = RTP_HEADER_LEN + 4*i_CSRC_count + i_extension_length;
if( i_payload_type == 14 ) i_skip += 4;
/* Return the packet without the RTP header. */
p->i_buffer -= i_skip;
p->p_buffer += i_skip;
} }
else if( (i_cur - i_seq) > 0 ) else
{
if( p_prev )
{ {
p_sys->p_list = p; p_sys->p_end = p_block;
p_prev->p_next = NULL;
p_sys->i_last_pcr = i_pcr_prev;
p_sys->i_sequence_number = i_seq_prev;
return p_send;
} }
goto out; return VLC_TRUE;
} }
p_prev = p; if( p == p_sys->p_list )
if (!p->p_next) break; { /* we've reached bottom of chain */
p = p->p_next; i_tmp = p_sys->i_last_seqno - i_new;
if( !p_access->info.b_prebuffered || (i_tmp > 32767) )
{
msg_Dbg(p_access, "RTP reordering: prepend %d before %d",
i_new, p->i_seqno );
p_block->p_next = p;
p->p_prev = p_block;
p_sys->p_list = p_block;
return VLC_TRUE;
} }
out: if( !i_tmp ) /* trash duplicate */
/* We have walked through the complete chain and all packets are break;
* in sequence - so send the whole chain
*/
i_payload_type = (p->p_buffer[1] & 0x7F);
i_CSRC_count = p->p_buffer[0] & 0x0F;
i_extension_bit = ( p->p_buffer[0] & 0x10 ) >> 4;
if( i_extension_bit == 1)
i_extension_length = ( (p->p_buffer[14] << 8 ) + p->p_buffer[15] );
/* Skip header + CSRC extension field n*(32 bits) + extention */
i_skip = RTP_HEADER_LEN + 4*i_CSRC_count + i_extension_length;
if( i_payload_type == 14 ) i_skip += 4;
/* Update the list pointers */ /* reordering failed - append the packet to the end of queue */
p_sys->p_list = NULL; msg_Dbg(p_access, "RTP: sequence changed (or buffer too small) "
p_sys->p_end = NULL; "new: %d, buffer %d...%d", i_new, p->i_seqno,
p_sys->i_sequence_number = ( (p->p_buffer[2] << 8 ) + p_sys->p_end->i_seqno);
p->p_buffer[3] ); p_sys->p_end->p_next = p_block;
p_sys->i_last_pcr = ( (p->p_buffer[4] << 24) + p_block->p_prev = p_sys->p_end;
(p->p_buffer[5] << 16) + p_sys->p_end = p_block;
(p->p_buffer[6] << 8) + return VLC_TRUE;
p->p_buffer[7] );
/* Return the packet without the RTP header. */
p->i_buffer -= i_skip;
p->p_buffer += i_skip;
return p_send;
} }
return NULL; p_prev = p;
p = p->p_prev;
}
block_Release( p_block );
return VLC_FALSE;
} }
/***************************************************************************** /*****************************************************************************
...@@ -551,33 +421,23 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block ) ...@@ -551,33 +421,23 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
int i_CSRC_count; int i_CSRC_count;
int i_payload_type; int i_payload_type;
int i_skip = 0; int i_skip = 0;
uint16_t i_sequence_number = 0; int i_extension_flag = 0;
uint16_t i_sequence_expected = 0;
int i_extension_bit = 0;
int i_extension_length = 0; int i_extension_length = 0;
uint32_t i_pcr = 0; uint16_t i_sequence_number = 0;
if( p_block == NULL ) if( p_block == NULL )
return NULL; return NULL;
if( p_block->i_buffer < RTP_HEADER_LEN ) if( p_block->i_buffer < RTP_HEADER_LEN )
{ goto trash;
msg_Warn( p_access, "received a too short packet for RTP" );
block_Release( p_block );
return NULL;
}
/* Parse the header and make some verifications. /* Parse the header and make some verifications.
* See RFC 3550. */ * See RFC 3550. */
i_rtp_version = ( p_block->p_buffer[0] & 0xC0 ) >> 6; i_rtp_version = ( p_block->p_buffer[0] & 0xC0 ) >> 6;
i_CSRC_count = p_block->p_buffer[0] & 0x0F; i_CSRC_count = p_block->p_buffer[0] & 0x0F;
i_extension_flag = p_block->p_buffer[0] & 0x10;
i_payload_type = p_block->p_buffer[1] & 0x7F; i_payload_type = p_block->p_buffer[1] & 0x7F;
i_sequence_number = (p_block->p_buffer[2] << 8) + i_sequence_number = (p_block->p_buffer[2] << 8 ) + p_block->p_buffer[3];
p_block->p_buffer[3];
i_pcr = ( (p_block->p_buffer[4] << 24) +
(p_block->p_buffer[5] << 16) +
(p_block->p_buffer[6] << 8) +
p_block->p_buffer[7] );
i_extension_bit = ( p_block->p_buffer[0] & 0x10 ) >> 4;
if( i_rtp_version != 2 ) if( i_rtp_version != 2 )
msg_Dbg( p_access, "RTP version is %u, should be 2", i_rtp_version ); msg_Dbg( p_access, "RTP version is %u, should be 2", i_rtp_version );
...@@ -586,33 +446,20 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block ) ...@@ -586,33 +446,20 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
i_skip = 4; i_skip = 4;
else if( i_payload_type != 33 && i_payload_type != 32 ) else if( i_payload_type != 33 && i_payload_type != 32 )
msg_Dbg( p_access, "unsupported RTP payload type (%u)", i_payload_type ); msg_Dbg( p_access, "unsupported RTP payload type (%u)", i_payload_type );
if( i_extension_flag )
if( i_extension_bit == 1)
i_extension_length = 4 + i_extension_length = 4 +
4 * ( (p_block->p_buffer[14] << 8) + p_block->p_buffer[15] ); 4 * ( (p_block->p_buffer[14] << 8) + p_block->p_buffer[15] );
/* Skip header + CSRC extension field n*(32 bits) + extention */ /* Skip header + CSRC extension field n*(32 bits) + extension */
i_skip += RTP_HEADER_LEN + 4*i_CSRC_count + i_extension_length; i_skip += RTP_HEADER_LEN + 4*i_CSRC_count + i_extension_length;
if( i_skip >= p_block->i_buffer ) if( i_skip >= p_block->i_buffer )
{ goto trash;
msg_Warn( p_access, "received a too short packet for RTP" );
block_Release( p_block );
return NULL;
}
/* Detect RTP packet loss through tracking sequence numbers, /* Return the packet without the RTP header, remember seqno */
* and take RTP PCR into account. p_block->i_buffer -= i_skip;
* See RFC 3550. p_block->p_buffer += i_skip;
*/ p_block->i_seqno = i_sequence_number;
if( p_sys->b_first_seqno )
{
p_sys->i_sequence_number = i_sequence_number;
p_sys->i_last_pcr = i_pcr;
p_sys->b_first_seqno = VLC_FALSE;
i_sequence_expected = i_sequence_number;
}
else
i_sequence_expected = p_sys->i_sequence_number + 1;
#if 0 #if 0
/* Emulate packet loss */ /* Emulate packet loss */
...@@ -624,120 +471,78 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block ) ...@@ -624,120 +471,78 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
} }
#endif #endif
if( (i_sequence_expected - i_sequence_number) != 0 ) return p_block;
{
/* Handle out of order packets */
if( p_sys->i_rtp_late > 0 ) trash:
{ msg_Warn( p_access, "received a too short packet for RTP" );
if( (i_sequence_number - i_sequence_expected) > 0 )
{
msg_Warn( p_access,
"RTP packet out of order (too early) expected %u, current %u",
i_sequence_expected, i_sequence_number );
if( (i_pcr - p_sys->i_last_pcr) >= (p_sys->i_rtp_late*90) )
{
block_t *p_start = p_sys->p_list;
uint16_t i_start = (!p_start) ? p_sys->i_sequence_number :
(p_start->p_buffer[2] << 8) +
p_start->p_buffer[3];
/* Gap too big, we have been holding this data for too long,
* send what we have.
*/
msg_Warn( p_access,
"Gap too big resyncing: delta %u, held for %d ms",
(i_pcr - p_sys->i_last_pcr), p_sys->i_rtp_late );
rtp_ChainInsert( p_access, p_block );
return rtp_ChainSend( p_access, &p_sys->p_list, i_start );
}
/* hold packets that arrive too early. */
rtp_ChainInsert( p_access, p_block );
return rtp_ChainSend( p_access, &p_sys->p_list, i_sequence_expected );
}
else if( /* ((i_sequence_expected - i_sequence_number ) > 0) && */
(p_sys->i_last_pcr - i_pcr) >= 0 )
{
msg_Warn( p_access,
"RTP packet out of order (duplicate or too late) expected %u, current %u .. trashing it",
i_sequence_expected, i_sequence_number );
block_Release( p_block ); block_Release( p_block );
p_sys->i_sequence_number = i_sequence_number;
p_sys->i_last_pcr = i_pcr;
return NULL; return NULL;
} }
if( p_sys->p_list ) static block_t *BlockPrebufferRTP( access_t *p_access, block_t *p_block )
{ {
block_t *p = NULL; access_sys_t *p_sys = p_access->p_sys;
block_t **p_send = &p_sys->p_list; int64_t i_first = mdate();
int i_count = 0;
msg_Warn( p_access, block_t *p = p_block;
"RTP packet (unexpected condition) expected %u, current %u",
i_sequence_expected, i_sequence_number );
/* Append block to the end of chain and send whole chain */
block_ChainLastAppend( &p_send, p_block );
p_sys->p_list = p_sys->p_end = NULL;
p_sys->i_sequence_number = i_sequence_number;
p_sys->i_last_pcr = i_pcr;
/* Return the packet without the RTP header. */
p = *p_send;
while( p )
{
p->i_buffer -= i_skip;
p->p_buffer += i_skip;
if( !p->p_next ) break;
p = p->p_next;
}
return *p_send;
}
/* This code should never be reached !! */
msg_Err( p_access,
"Bug in algorithme: (unexpected condition) expected %u (pcr=%u), current %u (pcr=%u)",
i_sequence_expected, i_sequence_number, p_sys->i_last_pcr, i_pcr );
}
msg_Warn( p_access,
"RTP packet(s) lost, expected sequence number %d got %d",
i_sequence_expected, i_sequence_number );
/* Mark transport error in the first TS packet in the RTP stream. */ for( ;; )
if( (i_payload_type == 33) && (p_block->p_buffer[0] == 0x47) )
p_block->p_buffer[1] |= 0x80;
}
else if( (p_sys->i_rtp_late > 0) && p_sys->p_list )
{ {
if( (p_sys->i_last_pcr - i_pcr) >= 0 ) int64_t i_date = mdate();
if( p && rtp_ChainInsert( p_access, p ))
i_count++;
/* Require at least 3 packets in the buffer */
if( i_count > 3 && (i_date - i_first) > p_sys->i_rtp_late )
break;
p = BlockParseRTP( p_access, BlockUDP( p_access ));
if( !p && (i_date - i_first) > p_sys->i_rtp_late )
{ {
msg_Warn( p_access, msg_Err( p_access, "Error in RTP prebuffering!" );
"RTP packet out of order (duplicate) expected %u, current %u .. trashing it", break;
i_sequence_expected, i_sequence_number );
block_Release( p_block );
p_sys->i_sequence_number = i_sequence_number;
p_sys->i_last_pcr = i_pcr;
return NULL;
} }
rtp_ChainInsert( p_access, p_block );
return rtp_ChainSend( p_access, &p_sys->p_list, i_sequence_expected );
} }
/* This is the normal case when no packet reordering is effective */ msg_Dbg( p_access, "RTP: prebuffered %d packets", i_count - 1 );
p_sys->i_sequence_number = i_sequence_number; p_access->info.b_prebuffered = VLC_TRUE;
p_sys->i_last_pcr = i_pcr; p = p_sys->p_list;
p_sys->p_list = p_sys->p_list->p_next;
/* Return the packet without the RTP header. */ p_sys->i_last_seqno = p->i_seqno;
p_block->i_buffer -= i_skip; p->p_next = NULL;
p_block->p_buffer += i_skip; return p;
return p_block;
} }
static block_t *BlockRTP( access_t *p_access ) static block_t *BlockRTP( access_t *p_access )
{ {
block_t *p_block = BlockUDP( p_access ); access_sys_t *p_sys = p_access->p_sys;
block_t *p;
if ( p_block != NULL ) again:
return BlockParseRTP( p_access, p_block ); p = BlockParseRTP( p_access, BlockUDP( p_access ));
else
if ( !p )
return NULL; return NULL;
if ( !p_access->info.b_prebuffered )
return BlockPrebufferRTP( p_access, p );
if( !rtp_ChainInsert( p_access, p ))
goto again;
p = p_sys->p_list;
p_sys->p_list = p_sys->p_list->p_next;
p_sys->i_last_seqno++;
if( p_sys->i_last_seqno != p->i_seqno )
{
msg_Dbg( p_access, "RTP: packet(s) lost, expected %d, got %d",
p_sys->i_last_seqno, p->i_seqno );
p_sys->i_last_seqno = p->i_seqno;
}
p->p_next = NULL;
return p;
} }
/***************************************************************************** /*****************************************************************************
...@@ -800,7 +605,9 @@ static block_t *BlockChoose( access_t *p_access ) ...@@ -800,7 +605,9 @@ static block_t *BlockChoose( access_t *p_access )
return p_block; return p_block;
} }
if( !BlockParseRTP( p_access, p_block )) return NULL;
p_access->pf_block = BlockRTP; p_access->pf_block = BlockRTP;
return BlockParseRTP( p_access, p_block ); return BlockPrebufferRTP( p_access, p_block );
} }
...@@ -72,6 +72,7 @@ static access_t *access2_InternalNew( vlc_object_t *p_obj, char *psz_access, ...@@ -72,6 +72,7 @@ static access_t *access2_InternalNew( vlc_object_t *p_obj, char *psz_access,
p_access->info.i_size = 0; p_access->info.i_size = 0;
p_access->info.i_pos = 0; p_access->info.i_pos = 0;
p_access->info.b_eof = VLC_FALSE; p_access->info.b_eof = VLC_FALSE;
p_access->info.b_prebuffered = VLC_FALSE;
p_access->info.i_title = 0; p_access->info.i_title = 0;
p_access->info.i_seekpoint = 0; p_access->info.i_seekpoint = 0;
......
...@@ -566,6 +566,7 @@ static int AStreamControl( stream_t *s, int i_query, va_list args ) ...@@ -566,6 +566,7 @@ static int AStreamControl( stream_t *s, int i_query, va_list args )
static void AStreamPrebufferBlock( stream_t *s ) static void AStreamPrebufferBlock( stream_t *s )
{ {
stream_sys_t *p_sys = s->p_sys; stream_sys_t *p_sys = s->p_sys;
access_t *p_access = p_sys->p_access;
int64_t i_first = 0; int64_t i_first = 0;
int64_t i_start; int64_t i_start;
...@@ -606,12 +607,6 @@ static void AStreamPrebufferBlock( stream_t *s ) ...@@ -606,12 +607,6 @@ static void AStreamPrebufferBlock( stream_t *s )
continue; continue;
} }
if( i_first == 0 )
{
i_first = mdate();
msg_Dbg( s, "received first data for our buffer");
}
while( b ) while( b )
{ {
/* Append the block */ /* Append the block */
...@@ -622,6 +617,21 @@ static void AStreamPrebufferBlock( stream_t *s ) ...@@ -622,6 +617,21 @@ static void AStreamPrebufferBlock( stream_t *s )
p_sys->stat.i_read_count++; p_sys->stat.i_read_count++;
b = b->p_next; b = b->p_next;
} }
if( p_access->info.b_prebuffered )
{
/* Access has already prebufferred - update stats and exit */
p_sys->stat.i_bytes = p_sys->block.i_size;
p_sys->stat.i_read_time = mdate() - i_start;
break;
}
if( i_first == 0 )
{
i_first = mdate();
msg_Dbg( s, "received first data for our buffer");
}
} }
p_sys->block.p_current = p_sys->block.p_first; p_sys->block.p_current = p_sys->block.p_first;
......
...@@ -64,11 +64,13 @@ block_t *__block_New( vlc_object_t *p_obj, int i_size ) ...@@ -64,11 +64,13 @@ block_t *__block_New( vlc_object_t *p_obj, int i_size )
/* Fill all fields */ /* Fill all fields */
p_block->p_next = NULL; p_block->p_next = NULL;
p_block->p_prev = NULL;
p_block->i_flags = 0; p_block->i_flags = 0;
p_block->i_pts = 0; p_block->i_pts = 0;
p_block->i_dts = 0; p_block->i_dts = 0;
p_block->i_length = 0; p_block->i_length = 0;
p_block->i_rate = 0; p_block->i_rate = 0;
p_block->i_seqno = 0;
p_block->i_buffer = i_size; p_block->i_buffer = i_size;
p_block->p_buffer = p_block->p_buffer =
&p_sys->p_allocated_buffer[BLOCK_PADDING_SIZE + &p_sys->p_allocated_buffer[BLOCK_PADDING_SIZE +
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment