Commit eeab96f1 authored by Jean-Paul Saman's avatar Jean-Paul Saman

Several RTP reordering fixes (Thanks to Marian Durkovic for finding them)

parent 2cf38dd9
...@@ -110,7 +110,7 @@ struct access_sys_t ...@@ -110,7 +110,7 @@ struct access_sys_t
uint32_t i_rtp_late; /* number of ms an RTP packet may be too late*/ uint32_t i_rtp_late; /* number of ms an RTP packet may be too late*/
uint32_t i_last_pcr; /* last known good PCR */ uint32_t i_last_pcr; /* last known good PCR */
block_t *p_list; /* list of packets to rearrange */ block_t *p_list; /* list of packets to rearrange */
block_t *p_end; /* last packet in p_list */ block_t *p_end; /* last packet in p_list */
block_t *p_next; /* p_next ?? */ block_t *p_next; /* p_next ?? */
}; };
...@@ -376,19 +376,17 @@ static inline void rtp_ChainInsert( access_t *p_access, block_t **pp_list, block ...@@ -376,19 +376,17 @@ static inline void rtp_ChainInsert( access_t *p_access, block_t **pp_list, block
p = *pp_end; p = *pp_end;
i_cur = ( (p->p_buffer[2] << 8 ) + p->p_buffer[3] ); i_cur = ( (p->p_buffer[2] << 8 ) + p->p_buffer[3] );
i_expected = ((i_cur+1) % RTP_SEQ_NUM_SIZE); i_expected = ((i_cur+1) % RTP_SEQ_NUM_SIZE);
if( (i_new - i_expected) >= 0 ) /* Append at the end? */
if( i_new == i_expected ) /* Append at the end? */
{ {
msg_Dbg( p_access, ">> append %p(%u)==%p(%u)\n", p_block, i_cur, p, i_new ); msg_Dbg( p_access, ">> append %p(%u)==%p(%u)\n", p_block, i_cur, p, i_new );
p->p_next = *pp_end = p_block; p->p_next = *pp_end = p_block;
return; return;
} }
/* Add to the fron fo the chain? */ /* Add to the front fo the chain? */
p = *pp_list; p = *pp_list;
i_new = ( (p_block->p_buffer[2] << 8 ) + p_block->p_buffer[3] ); i_new = ( (p_block->p_buffer[2] << 8 ) + p_block->p_buffer[3] );
i_cur = ( (p->p_buffer[2] << 8 ) + p->p_buffer[3] ); i_cur = ( (p->p_buffer[2] << 8 ) + p->p_buffer[3] );
i_expected = ((i_cur+1) % RTP_SEQ_NUM_SIZE); if( (i_cur - i_new) > 0 )
if( i_expected > i_new )
{ {
msg_Dbg( p_access, ">> prepend %p(%u)==%p(%u)\n", p_block, i_cur, p, i_new ); msg_Dbg( p_access, ">> prepend %p(%u)==%p(%u)\n", p_block, i_cur, p, i_new );
p_block->p_next = p; p_block->p_next = p;
...@@ -398,7 +396,7 @@ static inline void rtp_ChainInsert( access_t *p_access, block_t **pp_list, block ...@@ -398,7 +396,7 @@ static inline void rtp_ChainInsert( access_t *p_access, block_t **pp_list, block
/* The packet can't be added to the front or the end of the chain, /* The packet can't be added to the front or the end of the chain,
* thus walk the chain from the start. * thus walk the chain from the start.
*/ */
while( p->p_next ) while( p )
{ {
i_cur = (p->p_buffer[2] << 8 ) + p->p_buffer[3]; i_cur = (p->p_buffer[2] << 8 ) + p->p_buffer[3];
i_expected = (i_cur+1) % RTP_SEQ_NUM_SIZE; i_expected = (i_cur+1) % RTP_SEQ_NUM_SIZE;
...@@ -421,7 +419,7 @@ static inline void rtp_ChainInsert( access_t *p_access, block_t **pp_list, block ...@@ -421,7 +419,7 @@ static inline void rtp_ChainInsert( access_t *p_access, block_t **pp_list, block
* else if( i_pcr_cur < i_pcr_new ) */ * else if( i_pcr_cur < i_pcr_new ) */
break; break;
} }
else if( i_expected == i_new ) /* insert in chain */ else if( (i_expected - i_new) >= 0 ) /* insert in chain */
{ {
p_tmp = p->p_next; p_tmp = p->p_next;
msg_Dbg( p_access, ">> insert between %p(%u)==%p(%u)", p, i_cur, p_tmp, i_new ); msg_Dbg( p_access, ">> insert between %p(%u)==%p(%u)", p, i_cur, p_tmp, i_new );
...@@ -449,21 +447,34 @@ static inline block_t *rtp_ChainSend( access_t *p_access, block_t **pp_list, uin ...@@ -449,21 +447,34 @@ static inline block_t *rtp_ChainSend( access_t *p_access, block_t **pp_list, uin
int i_extension_bit = 0; int i_extension_bit = 0;
int i_extension_length = 0; int i_extension_length = 0;
int i_CSRC_count = 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 */ /* Data pointers */
block_t *p_prev = NULL; block_t *p_prev = NULL;
block_t *p_send = *pp_list; block_t *p_send = *pp_list;
block_t *p = *pp_list; block_t *p = *pp_list;
while( p->p_next ) while( p )
{ {
i_cur = ( (p->p_buffer[2] << 8 ) + p->p_buffer[3] ); i_cur = ( (p->p_buffer[2] << 8 ) + p->p_buffer[3] );
msg_Dbg( p_access, "rtp_ChainSend: i_cur %u, i_seq %u", i_cur, i_seq ); msg_Dbg( p_access, "rtp_ChainSend: i_cur %u, i_seq %u", i_cur, i_seq );
if( i_cur == i_seq ) if( (i_cur - i_seq) == 0 )
{ {
/* sent all packets that are received in order */ i_seq++; /* sent all packets that are received in order */
i_seq++;
/* 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_CSRC_count = p->p_buffer[0] & 0x0F;
i_payload_type = (p->p_buffer[1] & 0x7F);
i_extension_bit = ( p->p_buffer[0] & 0x10 ) >> 4; i_extension_bit = ( p->p_buffer[0] & 0x10 ) >> 4;
if ( i_extension_bit == 1) if ( i_extension_bit == 1)
i_extension_length = ( (p->p_buffer[14] << 8 ) + i_extension_length = ( (p->p_buffer[14] << 8 ) +
...@@ -471,23 +482,20 @@ static inline block_t *rtp_ChainSend( access_t *p_access, block_t **pp_list, uin ...@@ -471,23 +482,20 @@ static inline block_t *rtp_ChainSend( access_t *p_access, block_t **pp_list, uin
/* Skip header + CSRC extension field n*(32 bits) + extention */ /* Skip header + CSRC extension field n*(32 bits) + extention */
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_payload_type == 14 ) i_skip += 4;
/* Return the packet without the RTP header. */ /* Return the packet without the RTP header. */
p->i_buffer -= i_skip; p->i_buffer -= i_skip;
p->p_buffer += i_skip; p->p_buffer += i_skip;
} }
else if( i_cur > i_seq ) else if( (i_cur - i_seq) > 0)
{ {
if( p_prev ) if( p_prev )
{ {
*pp_list = p; *pp_list = p;
p_prev->p_next = NULL; p_prev->p_next = NULL;
p_sys->i_last_pcr = ( (p_prev->p_buffer[4] << 24) + p_sys->i_last_pcr = i_pcr_prev;
(p_prev->p_buffer[5] << 16) + p_sys->i_sequence_number = i_seq_prev;
(p_prev->p_buffer[6] << 8) +
p_prev->p_buffer[7] );
p_sys->i_sequence_number = ( (p_prev->p_buffer[2] << 8 ) +
p_prev->p_buffer[3] );
return p_send; return p_send;
} }
/* FiXME: or should we return NULL here? */ /* FiXME: or should we return NULL here? */
...@@ -500,6 +508,7 @@ static inline block_t *rtp_ChainSend( access_t *p_access, block_t **pp_list, uin ...@@ -500,6 +508,7 @@ static inline block_t *rtp_ChainSend( access_t *p_access, block_t **pp_list, uin
/* We have walked through the complete chain and all packets are /* We have walked through the complete chain and all packets are
* in sequence - so send the whole chain * in sequence - so send the whole chain
*/ */
i_payload_type = (p->p_buffer[1] & 0x7F);
i_CSRC_count = p->p_buffer[0] & 0x0F; i_CSRC_count = p->p_buffer[0] & 0x0F;
i_extension_bit = ( p->p_buffer[0] & 0x10 ) >> 4; i_extension_bit = ( p->p_buffer[0] & 0x10 ) >> 4;
if( i_extension_bit == 1) if( i_extension_bit == 1)
...@@ -507,6 +516,7 @@ static inline block_t *rtp_ChainSend( access_t *p_access, block_t **pp_list, uin ...@@ -507,6 +516,7 @@ static inline block_t *rtp_ChainSend( access_t *p_access, block_t **pp_list, uin
/* Skip header + CSRC extension field n*(32 bits) + extention */ /* Skip header + CSRC extension field n*(32 bits) + extention */
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_payload_type == 14 ) i_skip += 4;
/* Update the list pointers */ /* Update the list pointers */
*pp_list = NULL; *pp_list = NULL;
...@@ -591,7 +601,7 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block ) ...@@ -591,7 +601,7 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
*/ */
if( p_sys->b_first_seqno ) if( p_sys->b_first_seqno )
{ {
p_sys->i_sequence_number = i_sequence_number; p_sys->i_sequence_number = i_sequence_number-1;
p_sys->i_last_pcr = i_pcr; p_sys->i_last_pcr = i_pcr;
p_sys->b_first_seqno = VLC_FALSE; p_sys->b_first_seqno = VLC_FALSE;
} }
...@@ -605,18 +615,21 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block ) ...@@ -605,18 +615,21 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
} }
#endif #endif
i_sequence_expected = ((p_sys->i_sequence_number + 1) % RTP_SEQ_NUM_SIZE); i_sequence_expected = ((p_sys->i_sequence_number + 1) % RTP_SEQ_NUM_SIZE);
if( i_sequence_expected != i_sequence_number ) if( (i_sequence_expected - i_sequence_number) != 0 )
{ {
/* Handle out of order packets */ /* Handle out of order packets */
if( p_sys->i_rtp_late > 0 ) if( p_sys->i_rtp_late > 0 )
{ {
if( i_sequence_expected < i_sequence_number ) if( (i_sequence_number - i_sequence_expected) > 0 )
{ {
msg_Warn( p_access, msg_Warn( p_access,
"RTP packet out of order (too early) expected %u, current %u", "RTP packet out of order (too early) expected %u, current %u",
i_sequence_expected, i_sequence_number ); i_sequence_expected, i_sequence_number );
if( (i_pcr - p_sys->i_last_pcr) > (p_sys->i_rtp_late*90) ) 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_buffer[2] << 8) +
p_start->p_buffer[3];
/* Gap too big, we have been holding this data for too long, /* Gap too big, we have been holding this data for too long,
* send what we have. * send what we have.
*/ */
...@@ -624,13 +637,13 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block ) ...@@ -624,13 +637,13 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
"Gap too big resyncing: delta %u, held for %d ms", "Gap too big resyncing: delta %u, held for %d ms",
(i_pcr - p_sys->i_last_pcr), p_sys->i_rtp_late ); (i_pcr - p_sys->i_last_pcr), p_sys->i_rtp_late );
rtp_ChainInsert( p_access, &p_sys->p_list, &p_sys->p_end, p_block ); rtp_ChainInsert( p_access, &p_sys->p_list, &p_sys->p_end, p_block );
return rtp_ChainSend( p_access, &p_sys->p_list, i_sequence_expected ); return rtp_ChainSend( p_access, &p_sys->p_list, i_start );
} }
/* hold packets that arrive too early. */ /* hold packets that arrive too early. */
rtp_ChainInsert( p_access, &p_sys->p_list, &p_sys->p_end, p_block ); rtp_ChainInsert( p_access, &p_sys->p_list, &p_sys->p_end, p_block );
return rtp_ChainSend( p_access, &p_sys->p_list, p_sys->i_sequence_number ); return rtp_ChainSend( p_access, &p_sys->p_list, i_sequence_expected );
} }
else if( /* (i_sequence_expected > i_sequence_number ) && */ else if( /* ((i_sequence_expected - i_sequence_number ) > 0) && */
(i_pcr <= p_sys->i_last_pcr) ) (i_pcr <= p_sys->i_last_pcr) )
{ {
msg_Warn( p_access, msg_Warn( p_access,
...@@ -659,10 +672,11 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block ) ...@@ -659,10 +672,11 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
/* Return the packet without the RTP header. */ /* Return the packet without the RTP header. */
p = *p_send; p = *p_send;
while( p->p_next ) while( p )
{ {
p->i_buffer -= i_skip; p->i_buffer -= i_skip;
p->p_buffer += i_skip; p->p_buffer += i_skip;
if( !p->p_next ) break;
p = p->p_next; p = p->p_next;
} }
return *p_send; return *p_send;
......
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