Commit 85d9938a authored by Gildas Bazin's avatar Gildas Bazin

* modules/packetizer/mpegvideo.c, modules/mux/mpeg/*: fixed the dts/pts calculation in the mpegvideo packetizer. It should now handle streams where all the pictures don't have the same duration (eg. 3:2 pulldown). We don't calculate anymore the pts for every frame as it is impossible to do so for non low-delay streams.
parent 586295b9
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* pes.c * pes.c
***************************************************************************** *****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN * 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> * Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Eric Petit <titer@videolan.org> * Eric Petit <titer@videolan.org>
...@@ -46,7 +46,8 @@ ...@@ -46,7 +46,8 @@
#define PES_PAYLOAD_SIZE_MAX 65500 #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; bits_buffer_t bits;
...@@ -196,8 +197,8 @@ int E_( EStoPES )( sout_instance_t *p_sout, ...@@ -196,8 +197,8 @@ int E_( EStoPES )( sout_instance_t *p_sout,
i_stream_id = PES_PRIVATE_STREAM_1; i_stream_id = PES_PRIVATE_STREAM_1;
} }
i_pts = p_es->i_pts * 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 * 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; i_size = p_es->i_size;
p_data = p_es->p_buffer; p_data = p_es->p_buffer;
...@@ -208,14 +209,17 @@ int E_( EStoPES )( sout_instance_t *p_sout, ...@@ -208,14 +209,17 @@ int E_( EStoPES )( sout_instance_t *p_sout,
do do
{ {
i_pes_payload = __MIN( i_size, PES_PAYLOAD_SIZE_MAX ); 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_pes_header = PESHeader( header, i_pts, i_dts, i_pes_payload,
i_dts = -1; // only first PES has a dts i_stream_id, i_private_id );
i_dts = -1; // only first PES has a dts/pts
i_pts = -1;
if( p_es ) if( p_es )
{ {
if( sout_BufferReallocFromPreHeader( p_sout, p_es, i_pes_header ) ) 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 ); return( -1 );
} }
/* reuse p_es for first frame */ /* reuse p_es for first frame */
...@@ -225,7 +229,8 @@ int E_( EStoPES )( sout_instance_t *p_sout, ...@@ -225,7 +229,8 @@ int E_( EStoPES )( sout_instance_t *p_sout,
} }
else 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 = p_pes->p_next;
p_pes->i_dts = 0; p_pes->i_dts = 0;
...@@ -233,7 +238,8 @@ int E_( EStoPES )( sout_instance_t *p_sout, ...@@ -233,7 +238,8 @@ int E_( EStoPES )( sout_instance_t *p_sout,
p_pes->i_length = 0; p_pes->i_length = 0;
if( i_pes_payload > 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, ...@@ -254,7 +260,3 @@ int E_( EStoPES )( sout_instance_t *p_sout,
return( 0 ); return( 0 );
} }
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* ts.c * ts.c
***************************************************************************** *****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN * 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> * Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Eric Petit <titer@videolan.org> * Eric Petit <titer@videolan.org>
...@@ -614,6 +614,7 @@ static int Mux( sout_mux_t *p_mux ) ...@@ -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 CalculateCRC( uint8_t *p_begin, int i_count )
{ {
static uint32_t CRC32[256] = static uint32_t CRC32[256] =
...@@ -697,7 +698,6 @@ static uint32_t CalculateCRC( uint8_t *p_begin, int i_count ) ...@@ -697,7 +698,6 @@ static uint32_t CalculateCRC( uint8_t *p_begin, int i_count )
return( i_crc ); return( i_crc );
} }
#if defined MODULE_NAME_IS_mux_ts
static int GetPAT( sout_mux_t *p_mux, static int GetPAT( sout_mux_t *p_mux,
sout_buffer_t **pp_ts ) sout_buffer_t **pp_ts )
{ {
...@@ -762,7 +762,7 @@ static int GetPMT( sout_mux_t *p_mux, ...@@ -762,7 +762,7 @@ static int GetPMT( sout_mux_t *p_mux,
bits_write( &bits, 16, 1 ); // FIXME program number bits_write( &bits, 16, 1 ); // FIXME program number
bits_write( &bits, 2, 0 ); // FIXME bits_write( &bits, 2, 0 ); // FIXME
bits_write( &bits, 5, p_sys->i_pmt_version_number ); 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 ); // section number
bits_write( &bits, 8, 0 ); // last section number bits_write( &bits, 8, 0 ); // last section number
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
* mpegvideo.c * mpegvideo.c
***************************************************************************** *****************************************************************************
* Copyright (C) 2001, 2002 VideoLAN * 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> * Authors: Laurent Aimar <fenrir@via.ecp.fr>
* Eric Petit <titer@videolan.org> * Eric Petit <titer@videolan.org>
...@@ -22,6 +22,20 @@ ...@@ -22,6 +22,20 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. * 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 * Preamble
*****************************************************************************/ *****************************************************************************/
...@@ -47,15 +61,16 @@ typedef struct packetizer_s ...@@ -47,15 +61,16 @@ typedef struct packetizer_s
sout_packetizer_input_t *p_sout_input; sout_packetizer_input_t *p_sout_input;
sout_format_t output_format; 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; mtime_t i_last_ref_pts;
double d_frame_rate; double d_frame_rate;
int i_progressive_sequence; int i_progressive_sequence;
int i_low_delay;
uint8_t p_sequence_header[150]; uint8_t p_sequence_header[150];
int i_sequence_header_length; int i_sequence_header_length;
int i_last_sequence_header; int i_last_sequence_header;
int i_last_picture_structure;
} packetizer_t; } packetizer_t;
static int Open ( vlc_object_t * ); static int Open ( vlc_object_t * );
...@@ -172,7 +187,6 @@ static int InitThread( packetizer_t *p_pack ) ...@@ -172,7 +187,6 @@ static int InitThread( packetizer_t *p_pack )
return -1; return -1;
} }
p_pack->i_last_picture_structure = 0x03; /* frame picture */
return( 0 ); return( 0 );
} }
...@@ -180,7 +194,7 @@ static int InitThread( packetizer_t *p_pack ) ...@@ -180,7 +194,7 @@ static int InitThread( packetizer_t *p_pack )
/* converting frame_rate_code to frame_rate */ /* converting frame_rate_code to frame_rate */
static const double pd_frame_rates[16] = 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 0, 0, 0, 0, 0, 0, 0
}; };
...@@ -220,11 +234,12 @@ static void PacketizeThread( packetizer_t *p_pack ) ...@@ -220,11 +234,12 @@ static void PacketizeThread( packetizer_t *p_pack )
int i_skipped; int i_skipped;
mtime_t i_duration; /* of the parsed picture */ mtime_t i_duration; /* of the parsed picture */
mtime_t i_pts; mtime_t i_pts = 0;
mtime_t i_dts; mtime_t i_dts = 0;
/* needed to calculate pts/dts */ /* needed to calculate pts/dts */
int i_temporal_ref = 0; int i_temporal_ref = 0;
int i_picture_coding_type = 0;
int i_picture_structure = 0x03; /* frame picture */ int i_picture_structure = 0x03; /* frame picture */
int i_top_field_first = 0; int i_top_field_first = 0;
int i_repeat_first_field = 0; int i_repeat_first_field = 0;
...@@ -291,12 +306,13 @@ static void PacketizeThread( packetizer_t *p_pack ) ...@@ -291,12 +306,13 @@ static void PacketizeThread( packetizer_t *p_pack )
{ {
msg_Dbg( p_pack->p_fifo, "ARRGG no extension_start_code" ); msg_Dbg( p_pack->p_fifo, "ARRGG no extension_start_code" );
p_pack->i_progressive_sequence = 1; p_pack->i_progressive_sequence = 1;
p_pack->i_low_delay = 1;
} }
else else
{ {
GetChunk( &p_pack->bit_stream, p_temp + i_pos, 10 ); 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_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; i_pos += 10;
} }
...@@ -365,11 +381,6 @@ static void PacketizeThread( packetizer_t *p_pack ) ...@@ -365,11 +381,6 @@ static void PacketizeThread( packetizer_t *p_pack )
i_pos += p_pack->i_sequence_header_length; i_pos += p_pack->i_sequence_header_length;
p_pack->i_last_sequence_header = 0; 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 ); CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos );
} }
else if( i_code == 0x100 ) /* Picture */ else if( i_code == 0x100 ) /* Picture */
...@@ -380,6 +391,7 @@ static void PacketizeThread( packetizer_t *p_pack ) ...@@ -380,6 +391,7 @@ static void PacketizeThread( packetizer_t *p_pack )
NextPTS( &p_pack->bit_stream, &i_pts, &i_dts ); NextPTS( &p_pack->bit_stream, &i_pts, &i_dts );
i_temporal_ref = ShowBits( &p_pack->bit_stream, 10 ); 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 ); CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos );
} }
...@@ -428,11 +440,18 @@ static void PacketizeThread( packetizer_t *p_pack ) ...@@ -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, sout_BufferRealloc( p_pack->p_sout_input->p_sout,
p_sout_buffer, i_pos ); p_sout_buffer, i_pos );
p_sout_buffer->i_size = 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) if( p_pack->i_progressive_sequence || i_picture_structure == 0x03)
{ {
i_duration = (mtime_t)( 1000000 / p_pack->d_frame_rate ); i_duration = (mtime_t)( 1000000 / p_pack->d_frame_rate );
...@@ -442,75 +461,66 @@ static void PacketizeThread( packetizer_t *p_pack ) ...@@ -442,75 +461,66 @@ static void PacketizeThread( packetizer_t *p_pack )
i_duration = (mtime_t)( 1000000 / p_pack->d_frame_rate / 2); 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( p_pack->i_progressive_sequence )
{ {
if( i_top_field_first == 0 && i_repeat_first_field == 0 ) if( i_top_field_first == 0 && i_repeat_first_field == 1 )
{ {
p_pack->i_last_dts += i_duration; i_duration = 2 * i_duration;
}
else if( i_top_field_first == 0 && i_repeat_first_field == 1 )
{
p_pack->i_last_dts += 2 * i_duration;
} }
else if( i_top_field_first == 1 && i_repeat_first_field == 1 ) 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 else
{ {
if( i_picture_structure == 0x03 ) if( i_picture_structure == 0x03 )
{ {
p_pack->i_last_dts += i_duration;
if( i_progressive_frame && i_repeat_first_field ) 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 ) }
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
{ {
p_pack->i_last_dts += 2 * i_duration; /* 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;
} }
else if( ( !i_top_field_first && i_picture_structure == 0x01 ) ||
( i_top_field_first && i_picture_structure == 0x02 ) ) /* 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 )
{ {
p_pack->i_last_dts += 2 * i_duration; /* 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_pack->i_last_picture_structure = i_picture_structure;
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 );
} }
......
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