* modules/packetizer/mpegvideo.c, modules/mux/mpeg/*: fixed the dts/pts calculation...
authorGildas Bazin <gbazin@videolan.org>
Tue, 10 Jun 2003 22:42:59 +0000 (22:42 +0000)
committerGildas Bazin <gbazin@videolan.org>
Tue, 10 Jun 2003 22:42:59 +0000 (22:42 +0000)
modules/mux/mpeg/pes.c
modules/mux/mpeg/ts.c
modules/packetizer/mpegvideo.c

index b2f8c6c..1f687c7 100644 (file)
@@ -2,7 +2,7 @@
  * pes.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: pes.c,v 1.6 2003/06/09 07:16:41 gbazin Exp $
+ * $Id: pes.c,v 1.7 2003/06/10 22:42:59 gbazin Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Eric Petit <titer@videolan.org>
@@ -46,7 +46,8 @@
 
 #define PES_PAYLOAD_SIZE_MAX 65500
 
-static inline int PESHeader( uint8_t *p_hdr, mtime_t i_pts, mtime_t i_dts, int i_es_size, int i_stream_id, int i_private_id )
+static inline int PESHeader( uint8_t *p_hdr, mtime_t i_pts, mtime_t i_dts,
+                             int i_es_size, int i_stream_id, int i_private_id )
 {
     bits_buffer_t bits;
 
@@ -196,8 +197,8 @@ int E_( EStoPES )( sout_instance_t *p_sout,
         i_stream_id  = PES_PRIVATE_STREAM_1;
     }
 
-    i_pts = p_es->i_pts * 9 / 100; // 90000 units clock
-    i_dts = p_es->i_dts * 9 / 100; // 90000 units clock
+    i_pts = p_es->i_pts < 0 ? -1 : p_es->i_pts * 9 / 100; // 90000 units clock
+    i_dts = p_es->i_dts < 0 ? -1 : p_es->i_dts * 9 / 100; // 90000 units clock
 
     i_size = p_es->i_size;
     p_data = p_es->p_buffer;
@@ -208,14 +209,17 @@ int E_( EStoPES )( sout_instance_t *p_sout,
     do
     {
         i_pes_payload = __MIN( i_size, PES_PAYLOAD_SIZE_MAX );
-        i_pes_header  = PESHeader( header, i_pts, i_dts, i_pes_payload, i_stream_id, i_private_id );
-        i_dts = -1; // only first PES has a dts
+        i_pes_header  = PESHeader( header, i_pts, i_dts, i_pes_payload,
+                                   i_stream_id, i_private_id );
+        i_dts = -1; // only first PES has a dts/pts
+        i_pts = -1;
 
         if( p_es  )
         {
             if( sout_BufferReallocFromPreHeader( p_sout, p_es, i_pes_header ) )
             {
-                msg_Err( p_sout, "cannot realloc prehader (should never happen)" );
+                msg_Err( p_sout,
+                         "cannot realloc preheader (should never happen)" );
                 return( -1 );
             }
             /* reuse p_es for first frame */
@@ -225,7 +229,8 @@ int E_( EStoPES )( sout_instance_t *p_sout,
         }
         else
         {
-            p_pes->p_next = sout_BufferNew( p_sout, i_pes_header + i_pes_payload );
+            p_pes->p_next = sout_BufferNew( p_sout,
+                                            i_pes_header + i_pes_payload );
             p_pes = p_pes->p_next;
 
             p_pes->i_dts    = 0;
@@ -233,7 +238,8 @@ int E_( EStoPES )( sout_instance_t *p_sout,
             p_pes->i_length = 0;
             if( i_pes_payload > 0 )
             {
-                p_sout->p_vlc->pf_memcpy( p_pes->p_buffer + i_pes_header, p_data, i_pes_payload );
+                p_sout->p_vlc->pf_memcpy( p_pes->p_buffer + i_pes_header,
+                                          p_data, i_pes_payload );
             }
         }
 
@@ -254,7 +260,3 @@ int E_( EStoPES )( sout_instance_t *p_sout,
 
     return( 0 );
 }
-
-
-
-
index eed15a5..afcccfe 100644 (file)
@@ -2,7 +2,7 @@
  * ts.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: ts.c,v 1.21 2003/06/01 00:26:41 fenrir Exp $
+ * $Id: ts.c,v 1.22 2003/06/10 22:42:59 gbazin Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Eric Petit <titer@videolan.org>
@@ -614,6 +614,7 @@ static int Mux( sout_mux_t *p_mux )
 }
 
 
+#if defined MODULE_NAME_IS_mux_ts
 static uint32_t CalculateCRC( uint8_t *p_begin, int i_count )
 {
     static uint32_t CRC32[256] =
@@ -697,7 +698,6 @@ static uint32_t CalculateCRC( uint8_t *p_begin, int i_count )
     return( i_crc );
 }
 
-#if defined MODULE_NAME_IS_mux_ts
 static int GetPAT( sout_mux_t *p_mux,
                    sout_buffer_t **pp_ts )
 {
@@ -762,7 +762,7 @@ static int GetPMT( sout_mux_t *p_mux,
     bits_write( &bits, 16, 1 );     // FIXME program number
     bits_write( &bits, 2,  0 );     //  FIXME
     bits_write( &bits, 5,  p_sys->i_pmt_version_number );
-    bits_write( &bits, 1,  0 );     // current_next_indicator
+    bits_write( &bits, 1,  1 );     // current_next_indicator
     bits_write( &bits, 8,  0 );     // section number
     bits_write( &bits, 8,  0 );     // last section number
 
index 9d29a22..bab30bf 100644 (file)
@@ -2,7 +2,7 @@
  * mpegvideo.c
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: mpegvideo.c,v 1.14 2003/06/06 13:34:21 gbazin Exp $
+ * $Id: mpegvideo.c,v 1.15 2003/06/10 22:42:59 gbazin Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *          Eric Petit <titer@videolan.org>
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  *****************************************************************************/
 
+/*****************************************************************************
+ * Problem with this implementation:
+ *
+ * Although we should time-stamp each picture with a PTS, this isn't possible
+ * with the current implementation.
+ * The problem comes from the fact that for non-low-delay streams we can't
+ * calculate the PTS of pictures used as backward reference. Even the temporal
+ * reference number doesn't help here because all the pictures don't
+ * necessarily have the same duration (eg. 3:2 pulldown).
+ *
+ * However this doesn't really matter as far as the MPEG muxers are concerned
+ * because they allow having empty PTS fields. --gibalou
+ *****************************************************************************/
+
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
@@ -47,15 +61,16 @@ typedef struct packetizer_s
     sout_packetizer_input_t *p_sout_input;
     sout_format_t           output_format;
 
-    mtime_t                 i_last_dts;
+    mtime_t                 i_interpolated_dts;
+    mtime_t                 i_old_duration;
     mtime_t                 i_last_ref_pts;
     double                  d_frame_rate;
     int                     i_progressive_sequence;
+    int                     i_low_delay;
     uint8_t                 p_sequence_header[150];
     int                     i_sequence_header_length;
     int                     i_last_sequence_header;
 
-    int                     i_last_picture_structure;
 } packetizer_t;
 
 static int  Open    ( vlc_object_t * );
@@ -172,7 +187,6 @@ static int InitThread( packetizer_t *p_pack )
         return -1;
     }
 
-    p_pack->i_last_picture_structure = 0x03; /* frame picture */
     return( 0 );
 }
 
@@ -180,7 +194,7 @@ static int InitThread( packetizer_t *p_pack )
 /* converting frame_rate_code to frame_rate */
 static const double pd_frame_rates[16] =
 {
-    0, 24000/1001, 24, 25, 30000/1001, 30, 50, 60000/1001, 60,
+    0, 24000.0/1001, 24, 25, 30000.0/1001, 30, 50, 60000.0/1001, 60,
     0, 0, 0, 0, 0, 0, 0
 };
 
@@ -220,11 +234,12 @@ static void PacketizeThread( packetizer_t *p_pack )
     int           i_skipped;
     mtime_t       i_duration; /* of the parsed picture */
 
-    mtime_t       i_pts;
-    mtime_t       i_dts;
+    mtime_t       i_pts = 0;
+    mtime_t       i_dts = 0;
 
     /* needed to calculate pts/dts */
     int i_temporal_ref = 0;
+    int i_picture_coding_type = 0;
     int i_picture_structure = 0x03; /* frame picture */
     int i_top_field_first = 0;
     int i_repeat_first_field = 0;
@@ -291,12 +306,13 @@ static void PacketizeThread( packetizer_t *p_pack )
         {
             msg_Dbg( p_pack->p_fifo, "ARRGG no extension_start_code" );
             p_pack->i_progressive_sequence = 1;
+            p_pack->i_low_delay = 1;
         }
         else
         {
             GetChunk( &p_pack->bit_stream, p_temp + i_pos, 10 );
             p_pack->i_progressive_sequence = ( p_temp[i_pos+5]&0x08 ) ? 1 : 0;
-
+            p_pack->i_low_delay = ( p_temp[i_pos+9]&0x80 ) ? 1 : 0;
             i_pos += 10;
         }
 
@@ -332,7 +348,7 @@ static void PacketizeThread( packetizer_t *p_pack )
     else
     {
         p_sout_buffer =
-                sout_BufferNew( p_pack->p_sout_input->p_sout, 100 * 1024 );
+            sout_BufferNew( p_pack->p_sout_input->p_sout, 100 * 1024 );
         i_pos = 0;
     }
 
@@ -365,11 +381,6 @@ static void PacketizeThread( packetizer_t *p_pack )
                i_pos += p_pack->i_sequence_header_length;
                p_pack->i_last_sequence_header = 0;
             }
-#if 1
-            p_pack->i_last_ref_pts =
-                   p_pack->i_last_dts +
-                        (mtime_t)( 1000000 / p_pack->d_frame_rate); /* FIXME */
-#endif
             CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos );
         }
         else if( i_code == 0x100 ) /* Picture */
@@ -380,6 +391,7 @@ static void PacketizeThread( packetizer_t *p_pack )
 
             NextPTS( &p_pack->bit_stream, &i_pts, &i_dts );
             i_temporal_ref = ShowBits( &p_pack->bit_stream, 10 );
+            i_picture_coding_type = ShowBits( &p_pack->bit_stream, 13 ) & 0x3;
 
             CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos );
         }
@@ -428,11 +440,18 @@ static void PacketizeThread( packetizer_t *p_pack )
         }
     }
 
+    if( i_pts <= 0 && i_dts <= 0 && p_pack->i_interpolated_dts <= 0 )
+    {
+        msg_Dbg( p_pack->p_fifo, "need a starting pts/dts" );
+        sout_BufferDelete( p_pack->p_sout_input->p_sout, p_sout_buffer );
+        return;
+    }
+
     sout_BufferRealloc( p_pack->p_sout_input->p_sout,
                         p_sout_buffer, i_pos );
     p_sout_buffer->i_size = i_pos;
 
-    /* calculate dts/pts */
+    /* calculate frame duration */
     if( p_pack->i_progressive_sequence || i_picture_structure == 0x03)
     {
         i_duration = (mtime_t)( 1000000 / p_pack->d_frame_rate );
@@ -442,75 +461,66 @@ static void PacketizeThread( packetizer_t *p_pack )
         i_duration = (mtime_t)( 1000000 / p_pack->d_frame_rate / 2);
     }
 
-    /* fix i_last_dts and i_last_ref_pts with i_dts and i_pts from stream */
-    if( i_dts <= 0 && p_pack->i_last_dts <= 0 )
-    {
-        msg_Dbg( p_pack->p_fifo, "need a starting pts" );
-        sout_BufferDelete( p_pack->p_sout_input->p_sout,
-                           p_sout_buffer );
-        return;
-    }
-
-#if 1
-    if( i_dts > 0 )
-    {
-        //if( i_dts - p_pack->i_last_dts > 200000 ||
-        //    i_dts - p_pack->i_last_dts < 200000 )
-        {
-            p_pack->i_last_dts = i_dts;
-            if( i_pts > 0 )
-            {
-                p_pack->i_last_ref_pts = i_pts -
-                    i_temporal_ref * (mtime_t)( 1000000 / p_pack->d_frame_rate );
-            }
-        }
-    }
-#endif
-
-    p_sout_buffer->i_dts = p_pack->i_last_dts;
-    p_sout_buffer->i_pts = p_pack->i_last_ref_pts + 
-        i_temporal_ref * (mtime_t)( 1000000 / p_pack->d_frame_rate );
-    p_sout_buffer->i_length = i_duration;
-    p_sout_buffer->i_bitrate = (int)( 8 * i_pos * p_pack->d_frame_rate );
-    sout_InputSendBuffer( p_pack->p_sout_input, p_sout_buffer );
-
     if( p_pack->i_progressive_sequence )
     {
-        if( i_top_field_first == 0 && i_repeat_first_field == 0 )
-        {
-            p_pack->i_last_dts += i_duration;
-        }
-        else if( i_top_field_first == 0 && i_repeat_first_field == 1 )
+        if( i_top_field_first == 0 && i_repeat_first_field == 1 )
         {
-            p_pack->i_last_dts += 2 * i_duration;
+            i_duration = 2 * i_duration;
         }
         else if( i_top_field_first == 1 && i_repeat_first_field == 1 )
         {
-            p_pack->i_last_dts += 3 * i_duration;
+            i_duration = 3 * i_duration;
         }
     }
     else
     {
         if( i_picture_structure == 0x03 )
         {
-            p_pack->i_last_dts += i_duration;
-
             if( i_progressive_frame && i_repeat_first_field )
             {
-                p_pack->i_last_dts += i_duration / 2;
+                i_duration += i_duration / 2;
             }
         }
-        else if( i_picture_structure == p_pack->i_last_picture_structure )
-        {
-            p_pack->i_last_dts += 2 * i_duration;
-        }
-        else if( ( !i_top_field_first && i_picture_structure == 0x01 ) ||
-                 (  i_top_field_first && i_picture_structure == 0x02 ) )
-        {
-            p_pack->i_last_dts += 2 * i_duration;
-        }
     }
-    p_pack->i_last_picture_structure = i_picture_structure;
+
+    if( p_pack->i_low_delay || i_picture_coding_type == 0x03 )
+    {
+        /* Trivial case (DTS == PTS) */
+        /* Correct interpolated dts when we receive a new pts/dts */
+        if( i_pts > 0 ) p_pack->i_interpolated_dts = i_pts;
+        if( i_dts > 0 ) p_pack->i_interpolated_dts = i_dts;
+    }
+    else
+    {
+        /* Correct interpolated dts when we receive a new pts/dts */
+        if( p_pack->i_last_ref_pts )
+            p_pack->i_interpolated_dts = p_pack->i_last_ref_pts;
+        if( i_dts > 0 ) p_pack->i_interpolated_dts = i_dts;
+
+        p_pack->i_last_ref_pts = i_pts;
+    }
+
+    /* Don't even try to calculate the PTS unless it is given in the
+     * original stream */
+    p_sout_buffer->i_pts = i_pts ? i_pts : -1;
+
+    p_sout_buffer->i_dts = p_pack->i_interpolated_dts;
+
+    if( p_pack->i_low_delay || i_picture_coding_type == 0x03 )
+    {
+        /* Trivial case (DTS == PTS) */
+        p_pack->i_interpolated_dts += i_duration;
+    }
+    else
+    {
+        p_pack->i_interpolated_dts += p_pack->i_old_duration;
+        p_pack->i_old_duration = i_duration;
+    }
+
+    p_sout_buffer->i_bitrate = (int)( 8 * i_pos * p_pack->d_frame_rate );
+    p_sout_buffer->i_length = i_duration;
+
+    sout_InputSendBuffer( p_pack->p_sout_input, p_sout_buffer );
 }