]> git.sesse.net Git - vlc/commitdiff
modifications for RTP reordering:
authorMarian Durkovic <md@videolan.org>
Mon, 24 Oct 2005 17:08:54 +0000 (17:08 +0000)
committerMarian Durkovic <md@videolan.org>
Mon, 24 Oct 2005 17:08:54 +0000 (17:08 +0000)
 * for RTP, prebuffering is done within RTP access
 * reordering now working within this buffer
 * solves synchro problems since packet rate is preserved

include/vlc_access.h
include/vlc_block.h
modules/access/udp.c
src/input/access.c
src/input/stream.c
src/misc/block.c

index b06d243a00feb24f7795325e94305d60c7f9b910..26dcac11acb95a1e5da1ff3a5c80d6f21e8a0f0d 100644 (file)
@@ -103,6 +103,8 @@ struct access_t
 
         int          i_title;    /* idem, start from 0 (could be menu) */
         int          i_seekpoint;/* idem, start from 0 */
+
+        vlc_bool_t   b_prebuffered; /* Read only for input */ 
     } info;
     access_sys_t *p_sys;
 };
index d2ad6c463ac6fc8bb0dd0856eec057f64c7cca03..5048b6c6bf91c4d8ee563b419af3d89d0e0414dc 100644 (file)
@@ -77,6 +77,7 @@ typedef struct block_sys_t block_sys_t;
 struct block_t
 {
     block_t     *p_next;
+    block_t     *p_prev;
 
     uint32_t    i_flags;
 
@@ -87,6 +88,8 @@ struct block_t
     int         i_samples; /* Used for audio */
     int         i_rate;
 
+    uint16_t   i_seqno;   /* Used for RTP */
+
     int         i_buffer;
     uint8_t     *p_buffer;
 
index c2eb7bf4646a9475649230c38e01946b30efc6e8..4189a3454180b30c40f4aa9bece1a187ac51e681 100644 (file)
 #define AUTO_MTU_LONGTEXT N_( \
     "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_( \
-    "Allows you to modify the RTP packets reorder and late behaviour. " \
-    "If enabled (value>0) then out-of-order packets will be held for the " \
-    "specified timeout in ms. " \
-    "The default behaviour is not to reorder." )
+    "Allows you to modify the RTP reordering behaviour. " \
+    "RTP input will wait for late packets upto " \
+    "the specified timeout in milisecond units." )
 
 static int  Open ( vlc_object_t * );
 static void Close( vlc_object_t * );
@@ -66,11 +65,11 @@ vlc_module_begin();
 
     add_integer( "udp-caching", DEFAULT_PTS_DELAY / 1000, NULL, CACHING_TEXT,
                  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,
               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 );
     add_shortcut( "udp" );
     add_shortcut( "udpstream" );
@@ -86,7 +85,6 @@ vlc_module_end();
  * Local prototypes
  *****************************************************************************/
 #define RTP_HEADER_LEN 12
-#define RTP_SEQ_NUM_SIZE 65536
 
 static block_t *BlockUDP( access_t * );
 static block_t *BlockRTP( access_t * );
@@ -100,17 +98,11 @@ struct access_sys_t
     int i_mtu;
     vlc_bool_t b_auto_mtu;
 
-    /* rtp only */
-    uint16_t i_sequence_number;
-    vlc_bool_t b_first_seqno;
-
-    /* reorder rtp packets when out-of-bounds 
-     * 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 */
+    /* reorder rtp packets when out-of-sequence */
+    int64_t i_rtp_late;
+    uint16_t i_last_seqno;
+    block_t *p_list;
+    block_t *p_end;
 };
 
 /*****************************************************************************
@@ -215,6 +207,7 @@ static int Open( vlc_object_t *p_this )
     p_access->info.i_size = 0;
     p_access->info.i_pos = 0;
     p_access->info.b_eof = VLC_FALSE;
+    p_access->info.b_prebuffered = VLC_FALSE;
     p_access->info.i_title = 0;
     p_access->info.i_seekpoint = 0;
 
@@ -242,16 +235,12 @@ static int Open( vlc_object_t *p_this )
     /* Update default_pts to a suitable value for udp access */
     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 */
-    p_sys->i_last_pcr = 0;
-    p_sys->i_rtp_late = var_CreateGetInteger( p_access, "rtp-late" );
+    /* RTP reordering for out-of-sequence packets */
+    p_sys->i_rtp_late = var_CreateGetInteger( p_access, "rtp-late" ) * 1000;
+    p_sys->i_last_seqno = 0;
     p_sys->p_list = NULL;
     p_sys->p_end = NULL;
-
     return VLC_SUCCESS;
 }
 
@@ -349,196 +338,77 @@ static block_t *BlockUDP( access_t *p_access )
  * rtp_ChainInsert - insert a p_block in the chain and
  * 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;
-    block_t *p_list = p_sys->p_list;
-    block_t *p_end  = p_sys->p_end;
-    block_t *p = NULL;
-    uint16_t i_new = 0;
-    uint16_t i_cur = 0;
-    uint16_t i_expected = 0;
-    uint32_t i_pcr_new = 0;
-
-    if( !p_block ) return;
-    if( !p_list )
-    {
-        p_sys->p_list = p_block;
-        p_sys->p_end  = p_block;
-        return;
-    }
+    block_t *p_prev = NULL;
+    block_t *p = p_sys->p_end;
+    uint16_t i_new = p_block->i_seqno;
+    uint16_t i_tmp = 0;
 
-    /* Appending packets at the end of the chain is the normal case */
-    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 )
+    if( !p_sys->p_list )
     {
-        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;
+        p_sys->p_end = p_block;
+        return VLC_TRUE;
     }
-    /* The packet can't be added to the front or the end of the chain,
-     * thus walk the chain from the start.
-     */
-    while( p )
+    /* walk through the queue from top down since the new packet is in 
+    most cases just appended to the end */
+
+    for( ;; )
     {
-        i_cur = (p->p_buffer[2] << 8 ) + p->p_buffer[3];
-        i_expected = i_cur+1;
+        i_tmp = i_new - p->i_seqno;
 
-        if( (i_cur - i_new) == 0 )
-        {
-            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;
-        }
-        else if( (i_expected - i_new) >= 0 ) /* insert in chain */
-        {
-            block_t *p_tmp = NULL;
+        if( !i_tmp )   /* trash duplicate */
+            break; 
 
-            p_tmp = p->p_next;
-            msg_Dbg( p_access, "RTP: insert %u after  %u", i_new, i_cur );
+        if ( i_tmp < 32768 )
+        {   /* insert after this block ( i_new > p->i_seqno ) */
+            p_block->p_next = p->p_next;
             p->p_next = p_block;
-            p_block->p_next = p_tmp;
-            return;
-        }
-        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];
-            if( (i_cur - i_seq) == 0 )
+            p_block->p_prev = p;
+            if (p_prev)
             {
-                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;
+                p_prev->p_prev = p_block;
+                msg_Dbg(p_access, "RTP reordering: insert after %d, new %d", 
+                    p->i_seqno, i_new );
             }
-            else if( (i_cur - i_seq) > 0 )
+            else 
             {
-                if( p_prev )
-                {
-                    p_sys->p_list = p;
-                    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;
+                p_sys->p_end = p_block;
             }
-            p_prev = p;
-            if (!p->p_next) break;
-            p = p->p_next;
+            return VLC_TRUE;
         }
+        if( p == p_sys->p_list )
+        {   /* we've reached bottom of chain */
+            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:
-        /* We have walked through the complete chain and all packets are
-         * 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 */
-        p_sys->p_list = NULL;
-        p_sys->p_end = NULL;
-        p_sys->i_sequence_number = ( (p->p_buffer[2] << 8 ) +
-                                      p->p_buffer[3] );
-        p_sys->i_last_pcr = ( (p->p_buffer[4] << 24) +
-                              (p->p_buffer[5] << 16) +
-                              (p->p_buffer[6] << 8) +
-                               p->p_buffer[7] );
-        /* Return the packet without the RTP header. */
-        p->i_buffer -= i_skip;
-        p->p_buffer += i_skip;
-        return p_send;
+            if( !i_tmp )   /* trash duplicate */
+                break;    
+
+            /* reordering failed - append the packet to the end of queue */
+            msg_Dbg(p_access, "RTP: sequence changed (or buffer too small) "
+                "new: %d, buffer %d...%d", i_new, p->i_seqno, 
+                p_sys->p_end->i_seqno);
+            p_sys->p_end->p_next = p_block;
+            p_block->p_prev = p_sys->p_end;
+            p_sys->p_end = p_block;
+            return VLC_TRUE;
+        }
+        p_prev = p;
+        p = p->p_prev;
     }
-    return NULL;
+    block_Release( p_block );
+    return VLC_FALSE;
 }
 
 /*****************************************************************************
@@ -551,33 +421,23 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
     int      i_CSRC_count;
     int      i_payload_type;
     int      i_skip = 0;
-    uint16_t i_sequence_number = 0;
-    uint16_t i_sequence_expected = 0;
-    int      i_extension_bit = 0;
+    int      i_extension_flag = 0;
     int      i_extension_length = 0;
-    uint32_t i_pcr = 0;
+    uint16_t i_sequence_number = 0;
 
     if( p_block == NULL )
         return NULL;
 
     if( p_block->i_buffer < RTP_HEADER_LEN )
-    {
-        msg_Warn( p_access, "received a too short packet for RTP" );
-        block_Release( p_block );
-        return NULL;
-    }
+        goto trash;
+
     /* Parse the header and make some verifications.
      * See RFC 3550. */
     i_rtp_version     = ( p_block->p_buffer[0] & 0xC0 ) >> 6;
     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_sequence_number = (p_block->p_buffer[2] << 8) +
-                         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;
+    i_sequence_number = (p_block->p_buffer[2] << 8 ) + p_block->p_buffer[3];
 
     if( i_rtp_version != 2 )
         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 )
         i_skip = 4;
     else if( i_payload_type !=  33 && i_payload_type != 32 )
         msg_Dbg( p_access, "unsupported RTP payload type (%u)", i_payload_type );
-
-    if( i_extension_bit == 1)
+    if( i_extension_flag )
         i_extension_length = 4 +
             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;
+
     if( i_skip >= p_block->i_buffer )
-    {
-        msg_Warn( p_access, "received a too short packet for RTP" );
-        block_Release( p_block );
-        return NULL;
-    }
+        goto trash;
 
-    /* Detect RTP packet loss through tracking sequence numbers,
-     * and take RTP PCR into account.
-     * See RFC 3550.
-     */
-    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;
+    /* Return the packet without the RTP header, remember seqno */
+    p_block->i_buffer -= i_skip;
+    p_block->p_buffer += i_skip;
+    p_block->i_seqno = i_sequence_number;
 
 #if 0
     /* Emulate packet loss */
@@ -624,120 +471,78 @@ static block_t *BlockParseRTP( access_t *p_access, block_t *p_block )
     }
 #endif
 
-    if( (i_sequence_expected - i_sequence_number) != 0 )
-    {
-        /* Handle out of order packets */
-        if( p_sys->i_rtp_late > 0 )
-        {
-            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 );
-                p_sys->i_sequence_number = i_sequence_number;
-                p_sys->i_last_pcr = i_pcr;
-                return NULL;
-            }
+    return p_block;
 
-            if( p_sys->p_list )
-            {
-                block_t *p = NULL;
-                block_t **p_send = &p_sys->p_list;
-
-                msg_Warn( p_access,
-                    "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. */
-        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 )
+trash:
+    msg_Warn( p_access, "received a too short packet for RTP" );
+    block_Release( p_block );
+    return NULL;
+}
+
+static block_t *BlockPrebufferRTP( access_t *p_access, block_t *p_block )
+{
+    access_sys_t *p_sys = p_access->p_sys;
+    int64_t   i_first = mdate();
+    int       i_count = 0;
+    block_t   *p = p_block;
+
+    for( ;; )
     {
-        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,
-                "RTP packet out of order (duplicate) expected %u, current %u .. trashing it",
-                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;
+            msg_Err( p_access, "Error in RTP prebuffering!" );
+            break;
         }
-        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 */
-    p_sys->i_sequence_number = i_sequence_number;
-    p_sys->i_last_pcr = i_pcr;
-
-    /* Return the packet without the RTP header. */
-    p_block->i_buffer -= i_skip;
-    p_block->p_buffer += i_skip;
-    return p_block;
+    msg_Dbg( p_access, "RTP: prebuffered %d packets", i_count - 1 );
+    p_access->info.b_prebuffered = VLC_TRUE;
+    p = p_sys->p_list;
+    p_sys->p_list = p_sys->p_list->p_next;
+    p_sys->i_last_seqno = p->i_seqno;
+    p->p_next = NULL;
+    return p;
 }
 
 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 )
-        return BlockParseRTP( p_access, p_block );
-    else
+again:
+    p = BlockParseRTP( p_access, BlockUDP( p_access ));
+
+    if ( !p ) 
         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 )
             return p_block;
     }
 
+    if( !BlockParseRTP( p_access, p_block )) return NULL;
+
     p_access->pf_block = BlockRTP;
 
-    return BlockParseRTP( p_access, p_block );
+    return BlockPrebufferRTP( p_access, p_block );
 }
index 4a4c74a8b918cef7d3b0d6c3041bdd12df77820a..39b0ba5efbc9ce1d17640662993767fb924fcafd 100644 (file)
@@ -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_pos    = 0;
     p_access->info.b_eof    = VLC_FALSE;
+    p_access->info.b_prebuffered = VLC_FALSE;
     p_access->info.i_title  = 0;
     p_access->info.i_seekpoint = 0;
 
index cb9bfbc5bbf595b8941db68e72554a7d2b494f62..3a6623da7620c18c434af98b9e8588e5578b7e4d 100644 (file)
@@ -566,6 +566,7 @@ static int AStreamControl( stream_t *s, int i_query, va_list args )
 static void AStreamPrebufferBlock( stream_t *s )
 {
     stream_sys_t *p_sys = s->p_sys;
+    access_t     *p_access = p_sys->p_access;
 
     int64_t i_first = 0;
     int64_t i_start;
@@ -606,12 +607,6 @@ static void AStreamPrebufferBlock( stream_t *s )
             continue;
         }
 
-        if( i_first == 0 )
-        {
-            i_first = mdate();
-            msg_Dbg( s, "received first data for our buffer");
-        }
-
         while( b )
         {
             /* Append the block */
@@ -622,6 +617,21 @@ static void AStreamPrebufferBlock( stream_t *s )
             p_sys->stat.i_read_count++;
             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;
index cb54997af08c9e197a3817f05ebd9b2305e6de90..c7edf1b5ec085ae6ece1a1edf9141dc0528de506 100644 (file)
@@ -64,11 +64,13 @@ block_t *__block_New( vlc_object_t *p_obj, int i_size )
 
     /* Fill all fields */
     p_block->p_next         = NULL;
+    p_block->p_prev         = NULL;
     p_block->i_flags        = 0;
     p_block->i_pts          = 0;
     p_block->i_dts          = 0;
     p_block->i_length       = 0;
     p_block->i_rate         = 0;
+    p_block->i_seqno        = 0;
     p_block->i_buffer       = i_size;
     p_block->p_buffer       =
         &p_sys->p_allocated_buffer[BLOCK_PADDING_SIZE +