X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fpacketizer%2Fmpegvideo.c;h=97a1dd3a686b40161caf927b19599d10fd160cd3;hb=277ca5711cb0cc2ed8fe748597beb884bc678178;hp=559b20d95651e4b5cd0625e6a89bda3e4c093959;hpb=fd08bdbe1ed571c6e3366af433167741f62a3945;p=vlc diff --git a/modules/packetizer/mpegvideo.c b/modules/packetizer/mpegvideo.c index 559b20d956..97a1dd3a68 100644 --- a/modules/packetizer/mpegvideo.c +++ b/modules/packetizer/mpegvideo.c @@ -2,7 +2,7 @@ * mpegvideo.c ***************************************************************************** * Copyright (C) 2001, 2002 VideoLAN - * $Id: mpegvideo.c,v 1.13 2003/04/16 00:12:36 fenrir Exp $ + * $Id: mpegvideo.c,v 1.20 2003/11/07 16:53:54 massiot Exp $ * * Authors: Laurent Aimar * Eric Petit @@ -22,6 +22,20 @@ * 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,17 @@ 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; + vlc_bool_t b_expect_discontinuity; - int i_last_picture_structure; } packetizer_t; static int Open ( vlc_object_t * ); @@ -64,6 +80,7 @@ static int Run ( decoder_fifo_t * ); static int InitThread ( packetizer_t * ); static void PacketizeThread ( packetizer_t * ); static void EndThread ( packetizer_t * ); +static void BitstreamCallback ( bit_stream_t *, vlc_bool_t ); /***************************************************************************** * Module descriptor @@ -83,16 +100,16 @@ vlc_module_end(); *****************************************************************************/ static int Open( vlc_object_t *p_this ) { - decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this; + decoder_t *p_dec = (decoder_t*)p_this; - if( p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', 'v') && - p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', '1') && - p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', '2') ) + if( p_dec->p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', 'v') && + p_dec->p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', '1') && + p_dec->p_fifo->i_fourcc != VLC_FOURCC( 'm', 'p', 'g', '2') ) { return VLC_EGENERIC; } - p_fifo->pf_run = Run; + p_dec->pf_run = Run; return VLC_SUCCESS; } @@ -163,16 +180,16 @@ static int InitThread( packetizer_t *p_pack ) p_pack->output_format.i_extra_data = 0; p_pack->output_format.p_extra_data = NULL; + p_pack->b_expect_discontinuity = 0; p_pack->p_sout_input = NULL; if( InitBitstream( &p_pack->bit_stream, p_pack->p_fifo, - NULL, NULL ) != VLC_SUCCESS ) + BitstreamCallback, (void *)p_pack ) != VLC_SUCCESS ) { msg_Err( p_pack->p_fifo, "cannot initialize bitstream" ); return -1; } - p_pack->i_last_picture_structure = 0x03; /* frame picture */ return( 0 ); } @@ -180,7 +197,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,14 +237,16 @@ 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; + int i_progressive_frame = 0; if( !p_pack->p_sout_input ) { @@ -290,12 +309,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; } @@ -331,7 +351,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; } @@ -364,11 +384,7 @@ 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 + p_sout_buffer->i_flags |= SOUT_BUFFER_FLAGS_GOP; CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos ); } else if( i_code == 0x100 ) /* Picture */ @@ -379,6 +395,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 ); } @@ -403,6 +420,12 @@ static void PacketizeThread( packetizer_t *p_pack ) ShowBits( &p_pack->bit_stream, 25 ) & 0x01; i_repeat_first_field = ShowBits( &p_pack->bit_stream, 31 ) & 0x01; + + GetChunk( &p_pack->bit_stream, + p_sout_buffer->p_buffer + i_pos, 4 ); i_pos += 4; + + i_progressive_frame = + ShowBits( &p_pack->bit_stream, 1 ) & 0x01; } CopyUntilNextStartCode( p_pack, p_sout_buffer, &i_pos ); } @@ -421,11 +444,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 ); @@ -435,70 +465,83 @@ 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 ) + if( p_pack->i_progressive_sequence ) { - msg_Dbg( p_pack->p_fifo, "need a starting pts" ); - sout_BufferDelete( p_pack->p_sout_input->p_sout, - p_sout_buffer ); - return; + if( i_top_field_first == 0 && i_repeat_first_field == 1 ) + { + i_duration = 2 * i_duration; + } + else if( i_top_field_first == 1 && i_repeat_first_field == 1 ) + { + i_duration = 3 * i_duration; + } } - -#if 1 - if( i_dts > 0 ) + else { - //if( i_dts - p_pack->i_last_dts > 200000 || - // i_dts - p_pack->i_last_dts < 200000 ) + if( i_picture_structure == 0x03 ) { - p_pack->i_last_dts = i_dts; - if( i_pts > 0 ) + if( i_progressive_frame && i_repeat_first_field ) { - p_pack->i_last_ref_pts = i_pts - - i_temporal_ref * (mtime_t)( 1000000 / p_pack->d_frame_rate ); + i_duration += i_duration / 2; } } } -#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; + 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_length = p_pack->i_interpolated_dts - + p_sout_buffer->i_dts; + 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 0 + msg_Dbg( p_pack->p_fifo, "------------> dts=%lld pts=%lld duration=%lld", + p_sout_buffer->i_dts, p_sout_buffer->i_pts, + p_sout_buffer->i_length ); +#endif + + if ( p_pack->b_expect_discontinuity ) { - 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 ) - { - p_pack->i_last_dts += 2 * i_duration; - } - else if( i_top_field_first == 1 && i_repeat_first_field == 1 ) - { - p_pack->i_last_dts += 3 * i_duration; - } + msg_Warn( p_pack->p_fifo, "discontinuity encountered, dropping a frame" ); + p_pack->b_expect_discontinuity = 0; + sout_BufferDelete( p_pack->p_sout_input->p_sout, p_sout_buffer ); } else { - if( i_picture_structure == 0x03 ) - { - p_pack->i_last_dts += i_duration; - } - 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; - } + sout_InputSendBuffer( p_pack->p_sout_input, p_sout_buffer ); } - p_pack->i_last_picture_structure = i_picture_structure; } @@ -512,3 +555,21 @@ static void EndThread ( packetizer_t *p_pack) sout_InputDelete( p_pack->p_sout_input ); } } + +/***************************************************************************** + * BitstreamCallback: Import parameters from the new data/PES packet + ***************************************************************************** + * This function is called by input's NextDataPacket. + *****************************************************************************/ +static void BitstreamCallback ( bit_stream_t * p_bit_stream, + vlc_bool_t b_new_pes ) +{ + packetizer_t * p_pack = (packetizer_t *)p_bit_stream->p_callback_arg; + + if( p_bit_stream->p_data->b_discard_payload + || (b_new_pes && p_bit_stream->p_pes->b_discontinuity) ) + { + p_pack->b_expect_discontinuity = 1; + } +} +