X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fpacketizer%2Fmpeg4video.c;h=449ec36d08337c5988627a3b8cc44d62198ac0e1;hb=7ca4e3eb624251feb1f97cfc25104cce473e04a0;hp=ef2f7820e835a415c3cf5f8f0501326206bcf2fb;hpb=949a4ce261b3f115b283a4804b289a7ddd00b7a5;p=vlc diff --git a/modules/packetizer/mpeg4video.c b/modules/packetizer/mpeg4video.c index ef2f7820e8..449ec36d08 100644 --- a/modules/packetizer/mpeg4video.c +++ b/modules/packetizer/mpeg4video.c @@ -1,10 +1,11 @@ /***************************************************************************** - * mpeg4video.c + * mpeg4video.c: mpeg 4 video packetizer ***************************************************************************** - * Copyright (C) 2001, 2002 VideoLAN - * $Id: mpeg4video.c,v 1.8 2003/03/11 19:02:31 fenrir Exp $ + * Copyright (C) 2001-2006 the VideoLAN team + * $Id$ * - * Authors: Laurent Aimar + * Authors: Gildas Bazin + * Laurent Aimar * Eric Petit * * This program is free software; you can redistribute it and/or modify @@ -19,62 +20,91 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ -#include -#include -#include -#include -#include -#include /* malloc(), free() */ -#include /* strdup() */ - -#include "codecs.h" - -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -typedef struct packetizer_thread_s -{ - /* Input properties */ - decoder_fifo_t *p_fifo; - - /* Output properties */ - sout_packetizer_input_t *p_sout_input; - sout_packet_format_t output_format; - - mtime_t i_pts_start; - - int i_vol; - uint8_t *p_vol; - -} packetizer_thread_t; - -static int Open ( vlc_object_t * ); -static int Run ( decoder_fifo_t * ); - -static int InitThread ( packetizer_thread_t * ); -static void PacketizeThread ( packetizer_thread_t * ); -static void EndThread ( packetizer_thread_t * ); +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif +#include +#include +#include +#include +#include +#include /* hmmm, just for INPUT_RATE_DEFAULT */ -static void input_ShowPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes ); +#include "vlc_bits.h" +#include "vlc_block_helper.h" /***************************************************************************** * Module descriptor *****************************************************************************/ +static int Open ( vlc_object_t * ); +static void Close( vlc_object_t * ); vlc_module_begin(); - set_description( _("MPEG4 Video packetizer") ); + set_category( CAT_SOUT ); + set_subcategory( SUBCAT_SOUT_PACKETIZER ); + set_description( N_("MPEG4 video packetizer") ); set_capability( "packetizer", 50 ); - set_callbacks( Open, NULL ); + set_callbacks( Open, Close ); vlc_module_end(); +/**************************************************************************** + * Local prototypes + ****************************************************************************/ +static block_t *Packetize( decoder_t *, block_t ** ); + +struct decoder_sys_t +{ + /* + * Input properties + */ + block_bytestream_t bytestream; + int i_state; + size_t i_offset; + uint8_t p_startcode[3]; + + /* + * Common properties + */ + mtime_t i_interpolated_pts; + mtime_t i_interpolated_dts; + mtime_t i_last_ref_pts; + mtime_t i_last_time_ref; + mtime_t i_time_ref; + mtime_t i_last_time; + mtime_t i_last_timeincr; + + unsigned int i_flags; + + int i_fps_num; + int i_fps_den; + int i_last_incr; + int i_last_incr_diff; + + bool b_frame; + + /* Current frame being built */ + block_t *p_frame; + block_t **pp_last; +}; + +enum { + STATE_NOSYNC, + STATE_NEXT_SYNC +}; + +static block_t *ParseMPEGBlock( decoder_t *, block_t * ); +static int ParseVOL( decoder_t *, es_format_t *, uint8_t *, int ); +static int ParseVOP( decoder_t *, block_t * ); +static int vlc_log2( unsigned int ); + #define VIDEO_OBJECT_MASK 0x01f #define VIDEO_OBJECT_LAYER_MASK 0x00f @@ -95,382 +125,518 @@ vlc_module_end(); #define TEXTURE_SPATIAL_LAYER_START_CODE 0x1bf #define TEXTURE_SNR_LAYER_START_CODE 0x1c0 - /***************************************************************************** - * OpenDecoder: probe the packetizer and return score - ***************************************************************************** - * Tries to launch a decoder and return score so that the interface is able - * to choose. + * Open: probe the packetizer and return score *****************************************************************************/ static int Open( vlc_object_t *p_this ) { - decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this; - - p_fifo->pf_run = Run; + decoder_t *p_dec = (decoder_t*)p_this; + decoder_sys_t *p_sys; - switch( p_fifo->i_fourcc ) + switch( p_dec->fmt_in.i_codec ) { case VLC_FOURCC( 'm', '4', 's', '2'): case VLC_FOURCC( 'M', '4', 'S', '2'): case VLC_FOURCC( 'm', 'p', '4', 's'): case VLC_FOURCC( 'M', 'P', '4', 'S'): case VLC_FOURCC( 'm', 'p', '4', 'v'): + case VLC_FOURCC( 'M', 'P', '4', 'V'): case VLC_FOURCC( 'D', 'I', 'V', 'X'): case VLC_FOURCC( 'd', 'i', 'v', 'x'): case VLC_FOURCC( 'X', 'V', 'I', 'D'): case VLC_FOURCC( 'X', 'v', 'i', 'D'): case VLC_FOURCC( 'x', 'v', 'i', 'd'): case VLC_FOURCC( 'D', 'X', '5', '0'): + case VLC_FOURCC( 'd', 'x', '5', '0'): case VLC_FOURCC( 0x04, 0, 0, 0): case VLC_FOURCC( '3', 'I', 'V', '2'): + case VLC_FOURCC( 'm', '4', 'c', 'c'): + case VLC_FOURCC( 'M', '4', 'C', 'C'): + break; - return VLC_SUCCESS; default: return VLC_EGENERIC; } + + /* Allocate the memory needed to store the decoder's structure */ + if( ( p_dec->p_sys = p_sys = malloc( sizeof(decoder_sys_t) ) ) == NULL ) + return VLC_ENOMEM; + memset( p_sys, 0, sizeof(decoder_sys_t) ); + + /* Misc init */ + p_sys->i_state = STATE_NOSYNC; + p_sys->bytestream = block_BytestreamInit(); + p_sys->p_startcode[0] = 0; + p_sys->p_startcode[1] = 0; + p_sys->p_startcode[2] = 1; + p_sys->i_offset = 0; + p_sys->p_frame = NULL; + p_sys->pp_last = &p_sys->p_frame; + + /* Setup properties */ + es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); + p_dec->fmt_out.i_codec = VLC_FOURCC( 'm', 'p', '4', 'v' ); + + if( p_dec->fmt_in.i_extra ) + { + /* We have a vol */ + p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra; + p_dec->fmt_out.p_extra = malloc( p_dec->fmt_in.i_extra ); + memcpy( p_dec->fmt_out.p_extra, p_dec->fmt_in.p_extra, + p_dec->fmt_in.i_extra ); + + msg_Dbg( p_dec, "opening with vol size: %d", p_dec->fmt_in.i_extra ); + ParseVOL( p_dec, &p_dec->fmt_out, + p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); + } + else + { + /* No vol, we'll have to look for one later on */ + p_dec->fmt_out.i_extra = 0; + p_dec->fmt_out.p_extra = 0; + } + + /* Set callback */ + p_dec->pf_packetize = Packetize; + + return VLC_SUCCESS; } /***************************************************************************** - * RunDecoder: this function is called just after the thread is created + * Close: clean up the packetizer *****************************************************************************/ -static int Run( decoder_fifo_t *p_fifo ) +static void Close( vlc_object_t *p_this ) { - packetizer_thread_t *p_pack; - int b_error; + decoder_t *p_dec = (decoder_t*)p_this; - msg_Info( p_fifo, "Running MPEG4 Video packetizer" ); - if( !( p_pack = malloc( sizeof( packetizer_thread_t ) ) ) ) - { - msg_Err( p_fifo, "out of memory" ); - DecoderError( p_fifo ); - return( -1 ); - } - memset( p_pack, 0, sizeof( packetizer_thread_t ) ); + block_BytestreamRelease( &p_dec->p_sys->bytestream ); + if( p_dec->p_sys->p_frame ) block_ChainRelease( p_dec->p_sys->p_frame ); + free( p_dec->p_sys ); +} - p_pack->p_fifo = p_fifo; +/**************************************************************************** + * Packetize: the whole thing + ****************************************************************************/ +static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + block_t *p_pic; + mtime_t i_pts, i_dts; - if( InitThread( p_pack ) != 0 ) - { - DecoderError( p_fifo ); - return( -1 ); - } + if( pp_block == NULL || *pp_block == NULL ) return NULL; - while( ( !p_pack->p_fifo->b_die )&&( !p_pack->p_fifo->b_error ) ) + if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { - PacketizeThread( p_pack ); + if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED ) + { + p_sys->i_state = STATE_NOSYNC; + block_BytestreamFlush( &p_sys->bytestream ); + + if( p_sys->p_frame ) + block_ChainRelease( p_sys->p_frame ); + p_sys->p_frame = NULL; + p_sys->pp_last = &p_sys->p_frame; + } +// p_sys->i_interpolated_pts = +// p_sys->i_interpolated_dts = +// p_sys->i_last_ref_pts = +// p_sys->i_last_time_ref = +// p_sys->i_time_ref = +// p_sys->i_last_time = +// p_sys->i_last_timeincr = 0; + + block_Release( *pp_block ); + return NULL; } + block_BytestreamPush( &p_sys->bytestream, *pp_block ); - if( ( b_error = p_pack->p_fifo->b_error ) ) + while( 1 ) { - DecoderError( p_pack->p_fifo ); - } + switch( p_sys->i_state ) + { - EndThread( p_pack ); - if( b_error ) - { - return( -1 ); - } + case STATE_NOSYNC: + if( block_FindStartcodeFromOffset( &p_sys->bytestream, + &p_sys->i_offset, p_sys->p_startcode, 3 ) == VLC_SUCCESS ) + { + p_sys->i_state = STATE_NEXT_SYNC; + } - return( 0 ); -} + if( p_sys->i_offset ) + { + block_SkipBytes( &p_sys->bytestream, p_sys->i_offset ); + p_sys->i_offset = 0; + block_BytestreamFlush( &p_sys->bytestream ); + } + + if( p_sys->i_state != STATE_NEXT_SYNC ) + { + /* Need more data */ + return NULL; + } + + p_sys->i_offset = 1; /* To find next startcode */ + + case STATE_NEXT_SYNC: + /* TODO: If p_block == NULL, flush the buffer without checking the + * next sync word */ + + /* Find the next startcode */ + if( block_FindStartcodeFromOffset( &p_sys->bytestream, + &p_sys->i_offset, p_sys->p_startcode, 3 ) != VLC_SUCCESS ) + { + /* Need more data */ + return NULL; + } + + /* Get the new fragment and set the pts/dts */ + p_pic = block_New( p_dec, p_sys->i_offset ); + block_BytestreamFlush( &p_sys->bytestream ); + p_pic->i_pts = i_pts = p_sys->bytestream.p_block->i_pts; + p_pic->i_dts = i_dts = p_sys->bytestream.p_block->i_dts; + p_pic->i_rate = p_sys->bytestream.p_block->i_rate; + + block_GetBytes( &p_sys->bytestream, p_pic->p_buffer, + p_pic->i_buffer ); + + p_sys->i_offset = 0; + + /* Get picture if any */ + if( !( p_pic = ParseMPEGBlock( p_dec, p_pic ) ) ) + { + p_sys->i_state = STATE_NOSYNC; + break; + } + + /* don't reuse the same timestamps several times */ + if( i_pts == p_sys->bytestream.p_block->i_pts && + i_dts == p_sys->bytestream.p_block->i_dts ) + { + p_sys->bytestream.p_block->i_pts = 0; + p_sys->bytestream.p_block->i_dts = 0; + } + + /* We've just started the stream, wait for the first PTS. + * We discard here so we can still get the sequence header. */ + if( p_sys->i_interpolated_pts <= 0 && + p_sys->i_interpolated_dts <= 0 ) + { + msg_Dbg( p_dec, "need a starting pts/dts" ); + p_sys->i_state = STATE_NOSYNC; + block_Release( p_pic ); + break; + } + + /* When starting the stream we can have the first frame with + * a null DTS (i_interpolated_pts is initialized to 0) */ + if( !p_pic->i_dts ) p_pic->i_dts = p_pic->i_pts; + /* So p_block doesn't get re-added several times */ + *pp_block = block_BytestreamPop( &p_sys->bytestream ); -#define FREE( p ) if( p ) free( p ); p = NULL + p_sys->i_state = STATE_NOSYNC; + + return p_pic; + } + } +} /***************************************************************************** - * InitThread: initialize data before entering main loop + * ParseMPEGBlock: Re-assemble fragments into a block containing a picture *****************************************************************************/ - -static int InitThread( packetizer_thread_t *p_pack ) +static block_t *ParseMPEGBlock( decoder_t *p_dec, block_t *p_frag ) { - BITMAPINFOHEADER *p_bih; + decoder_sys_t *p_sys = p_dec->p_sys; + block_t *p_pic = NULL; - p_bih = (BITMAPINFOHEADER*)p_pack->p_fifo->p_bitmapinfoheader; - - if( p_bih && p_bih->biSize > sizeof( BITMAPINFOHEADER ) ) + if( p_frag->p_buffer[3] == 0xB0 || p_frag->p_buffer[3] == 0xB1 || p_frag->p_buffer[3] == 0xB2 ) + { /* VOS and USERDATA */ +#if 0 + /* Remove VOS start/end code from the original stream */ + block_Release( p_frag ); +#else + /* Append the block for now since ts/ps muxers rely on VOL + * being present in the stream */ + block_ChainLastAppend( &p_sys->pp_last, p_frag ); +#endif + return NULL; + } + if( p_frag->p_buffer[3] >= 0x20 && p_frag->p_buffer[3] <= 0x2f ) { - /* We have a vol */ - p_pack->i_vol = p_bih->biSize - sizeof( BITMAPINFOHEADER ); - p_pack->p_vol = malloc( p_pack->i_vol ); - memcpy( p_pack->p_vol, &p_bih[1], p_pack->i_vol ); - - /* create stream input output */ - p_pack->output_format.i_cat = VIDEO_ES; - p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v' ); - p_pack->output_format.p_format = malloc( p_bih->biSize ); - memcpy( p_pack->output_format.p_format, p_bih, p_bih->biSize ); - - msg_Warn( p_pack->p_fifo, "opening with vol size:%d", p_pack->i_vol ); - p_pack->p_sout_input = - sout_InputNew( p_pack->p_fifo, - &p_pack->output_format ); + /* Copy the complete VOL */ + if( (size_t)p_dec->fmt_out.i_extra != p_frag->i_buffer ) + { + p_dec->fmt_out.p_extra = + realloc( p_dec->fmt_out.p_extra, p_frag->i_buffer ); + p_dec->fmt_out.i_extra = p_frag->i_buffer; + } + memcpy( p_dec->fmt_out.p_extra, p_frag->p_buffer, p_frag->i_buffer ); + ParseVOL( p_dec, &p_dec->fmt_out, + p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); + +#if 0 + /* Remove from the original stream */ + block_Release( p_frag ); +#else + /* Append the block for now since ts/ps muxers rely on VOL + * being present in the stream */ + block_ChainLastAppend( &p_sys->pp_last, p_frag ); +#endif + return NULL; } else { - p_pack->i_vol = 0; - p_pack->p_vol = 0; - p_pack->output_format.i_cat = UNKNOWN_ES; - p_pack->output_format.i_fourcc = VLC_FOURCC( 'n', 'u', 'l', 'l' ); - p_pack->output_format.p_format = NULL; - - p_pack->p_sout_input = - sout_InputNew( p_pack->p_fifo, - &p_pack->output_format ); + if( !p_dec->fmt_out.i_extra ) + { + msg_Warn( p_dec, "waiting for VOL" ); + block_Release( p_frag ); + return NULL; + } + + /* Append the block */ + block_ChainLastAppend( &p_sys->pp_last, p_frag ); } - if( !p_pack->p_sout_input ) + if( p_frag->p_buffer[3] == 0xb6 && + ParseVOP( p_dec, p_frag ) == VLC_SUCCESS ) { - msg_Err( p_pack->p_fifo, "cannot add a new stream" ); - return( -1 ); + /* We are dealing with a VOP */ + p_pic = block_ChainGather( p_sys->p_frame ); + p_pic->i_pts = p_sys->i_interpolated_pts; + p_pic->i_dts = p_sys->i_interpolated_dts; + + /* Reset context */ + p_sys->p_frame = NULL; + p_sys->pp_last = &p_sys->p_frame; } - p_pack->i_pts_start = -1; - return( 0 ); + + return p_pic; } -static int m4v_FindStartCode( uint8_t **pp_data, uint8_t *p_end ) +/* ParseVOL: + * TODO: + * - support aspect ratio + */ +static int ParseVOL( decoder_t *p_dec, es_format_t *fmt, + uint8_t *p_vol, int i_vol ) { - for( ; *pp_data < p_end - 4; (*pp_data)++ ) + decoder_sys_t *p_sys = p_dec->p_sys; + int i_vo_type, i_vo_ver_id, i_ar, i_shape; + bs_t s; + + for( ;; ) { - if( (*pp_data)[0] == 0 && (*pp_data)[1] == 0 && (*pp_data)[2] == 1 ) - { - return( 0 ); - } + if( p_vol[0] == 0x00 && p_vol[1] == 0x00 && p_vol[2] == 0x01 && + p_vol[3] >= 0x20 && p_vol[3] <= 0x2f ) break; + + p_vol++; i_vol--; + if( i_vol <= 4 ) return VLC_EGENERIC; } - fprintf( stderr, "\n********* cannot find startcode\n" ); - return( -1 ); -} -/***************************************************************************** - * PacketizeThread: packetize an unit (here copy a complete pes) - *****************************************************************************/ -static void PacketizeThread( packetizer_thread_t *p_pack ) -{ - sout_buffer_t *p_sout_buffer; - pes_packet_t *p_pes; - ssize_t i_size; - /* **** get samples count **** */ - input_ExtractPES( p_pack->p_fifo, &p_pes ); - if( !p_pes ) + bs_init( &s, &p_vol[4], i_vol - 4 ); + + bs_skip( &s, 1 ); /* random access */ + i_vo_type = bs_read( &s, 8 ); + if( bs_read1( &s ) ) { - p_pack->p_fifo->b_error = 1; - return; + i_vo_ver_id = bs_read( &s, 4 ); + bs_skip( &s, 3 ); } - if( p_pack->i_pts_start < 0 ) + else { - p_pack->i_pts_start = p_pes->i_pts; + i_vo_ver_id = 1; } + i_ar = bs_read( &s, 4 ); + if( i_ar == 0xf ) + { + int i_ar_width, i_ar_height; - i_size = p_pes->i_pes_size; - if( i_size > 0 ) + i_ar_width = bs_read( &s, 8 ); + i_ar_height= bs_read( &s, 8 ); + } + if( bs_read1( &s ) ) { - pes_packet_t *p_pes_next; - data_packet_t *p_data; - ssize_t i_buffer; + int i_chroma_format; + int i_low_delay; + + /* vol control parameter */ + i_chroma_format = bs_read( &s, 2 ); + i_low_delay = bs_read1( &s ); - p_sout_buffer = - sout_BufferNew( p_pack->p_sout_input->p_sout, i_size ); - if( !p_sout_buffer ) + if( bs_read1( &s ) ) { - p_pack->p_fifo->b_error = 1; - return; + bs_skip( &s, 16 ); + bs_skip( &s, 16 ); + bs_skip( &s, 16 ); + bs_skip( &s, 3 ); + bs_skip( &s, 11 ); + bs_skip( &s, 1 ); + bs_skip( &s, 16 ); } - /* TODO: memcpy of the pes packet */ - for( i_buffer = 0, p_data = p_pes->p_first; - p_data != NULL && i_buffer < i_size; - p_data = p_data->p_next) - { - ssize_t i_copy; + } + /* shape 0->RECT, 1->BIN, 2->BIN_ONLY, 3->GRAY */ + i_shape = bs_read( &s, 2 ); + if( i_shape == 3 && i_vo_ver_id != 1 ) + { + bs_skip( &s, 4 ); + } - i_copy = __MIN( p_data->p_payload_end - p_data->p_payload_start, - i_size - i_buffer ); - if( i_copy > 0 ) - { - p_pack->p_fifo->p_vlc->pf_memcpy( p_sout_buffer->p_buffer + i_buffer, - p_data->p_payload_start, - i_copy ); - } - i_buffer += i_copy; - } - p_sout_buffer->i_length = 0; - p_sout_buffer->i_dts = p_pes->i_pts - p_pack->i_pts_start; - p_sout_buffer->i_pts = p_pes->i_pts - p_pack->i_pts_start; - p_sout_buffer->i_bitrate = 0; + if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */ - if( p_pack->p_vol == NULL ) - { - uint8_t *p_vol_begin, *p_vol_end, *p_end; - /* search if p_sout_buffer contains with a vol */ - p_vol_begin = p_sout_buffer->p_buffer; - p_vol_end = NULL; - p_end = p_sout_buffer->p_buffer + p_sout_buffer->i_size; + p_sys->i_fps_num = bs_read( &s, 16 ); /* Time increment resolution*/ + if( !p_sys->i_fps_num ) p_sys->i_fps_num = 1; - for( ;; ) - { - if( m4v_FindStartCode( &p_vol_begin, p_end ) ) - { - break; - } - msg_Dbg( p_pack->p_fifo, - "starcode 0x%2.2x%2.2x%2.2x%2.2x", - p_vol_begin[0], p_vol_begin[1], p_vol_begin[2], p_vol_begin[3] ); - - if( ( p_vol_begin[3] & ~VIDEO_OBJECT_MASK ) == ( VIDEO_OBJECT_START_CODE&0xff ) ) - { - p_vol_end = p_vol_begin + 4; - if( m4v_FindStartCode( &p_vol_end, p_end ) ) - { - break; - } - if( ( p_vol_end[3] & ~VIDEO_OBJECT_LAYER_MASK ) == ( VIDEO_OBJECT_LAYER_START_CODE&0xff ) ) - { - p_vol_end += 4; - if( m4v_FindStartCode( &p_vol_end, p_end ) ) - { - p_vol_end = p_end; - } - } - else - { - p_vol_end = NULL; - } - } - else if( ( p_vol_begin[3] & ~VIDEO_OBJECT_LAYER_MASK ) == ( VIDEO_OBJECT_LAYER_START_CODE&0xff) ) - { - p_vol_end = p_vol_begin + 4; - if( m4v_FindStartCode( &p_vol_end, p_end ) ) - { - p_vol_end = p_end; - } - } - - if( p_vol_end != NULL && p_vol_begin < p_vol_end ) - { - BITMAPINFOHEADER *p_bih; - - p_pack->i_vol = p_vol_end - p_vol_begin; - msg_Dbg( p_pack->p_fifo, "Reopening output" ); - - p_pack->p_vol = malloc( p_pack->i_vol ); - memcpy( p_pack->p_vol, p_vol_begin, p_pack->i_vol ); - - sout_InputDelete( p_pack->p_sout_input ); - - p_pack->output_format.i_cat = VIDEO_ES; - p_pack->output_format.i_fourcc = VLC_FOURCC( 'm', 'p', '4', 'v' ); - p_pack->output_format.p_format = - (void*)p_bih = malloc( sizeof( BITMAPINFOHEADER ) + p_pack->i_vol); - - p_bih->biSize = sizeof( BITMAPINFOHEADER ) + p_pack->i_vol; - p_bih->biWidth = 0; - p_bih->biHeight = 0; - p_bih->biPlanes = 1; - p_bih->biBitCount = 24; - p_bih->biCompression = VLC_FOURCC( 'd', 'i', 'v', 'x' ); - p_bih->biSizeImage = 0; - p_bih->biXPelsPerMeter = 0; - p_bih->biYPelsPerMeter = 0; - p_bih->biClrUsed = 0; - p_bih->biClrImportant = 0; - memcpy( &p_bih[1], p_pack->p_vol, p_pack->i_vol ); - - p_pack->p_sout_input = - sout_InputNew( p_pack->p_fifo, - &p_pack->output_format ); - if( !p_pack->p_sout_input ) - { - p_pack->p_fifo->b_error = 1; - return; - } - - break; - } - else - { - p_vol_begin += 4; - } - } - } + if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */ - input_ShowPES( p_pack->p_fifo, &p_pes_next ); - if( p_pes_next ) - { - mtime_t i_gap; + if( bs_read1( &s ) ) + { + int i_time_increment_bits = vlc_log2( p_sys->i_fps_num - 1 ) + 1; - i_gap = p_pes_next->i_pts - p_pes->i_pts; -#if 0 - if( i_gap > 1000000 / 4 ) // too littl fps < 4 is no sense - { - i_gap = 1000000 / 25; - p_pack->i_pts_start = - - ( p_pes->i_pts - p_pack->i_pts_start ) + p_pes_next->i_pts - i_gap; + if( i_time_increment_bits < 1 ) i_time_increment_bits = 1; - } - else if( i_gap < 0 ) - { - p_pack->i_pts_start = - ( p_pes->i_pts - p_pack->i_pts_start ) + p_pes_next->i_pts; - i_gap = 0; - } - if( i_gap < 0 ) - { - msg_Dbg( p_pack->p_fifo, "pts:%lld next_pts:%lld", p_pes->i_pts, p_pes_next->i_pts ); - /* work around for seek */ - p_pack->i_pts_start -= i_gap; - } - -// msg_Dbg( p_pack->p_fifo, "gap %lld date %lld next diff %lld", i_gap, p_pes->i_pts, p_pes_next->i_pts-p_pack->i_pts_start ); -#endif - p_sout_buffer->i_length = i_gap; - } - sout_InputSendBuffer( p_pack->p_sout_input, - p_sout_buffer ); + p_sys->i_fps_den = bs_read( &s, i_time_increment_bits ); + } + if( i_shape == 0 ) + { + bs_skip( &s, 1 ); + fmt->video.i_width = bs_read( &s, 13 ); + bs_skip( &s, 1 ); + fmt->video.i_height= bs_read( &s, 13 ); + bs_skip( &s, 1 ); } - input_DeletePES( p_pack->p_fifo->p_packets_mgt, p_pes ); + return VLC_SUCCESS; } - -/***************************************************************************** - * EndThread : packetizer thread destruction - *****************************************************************************/ -static void EndThread ( packetizer_thread_t *p_pack) +static int ParseVOP( decoder_t *p_dec, block_t *p_vop ) { - if( p_pack->p_sout_input ) + decoder_sys_t *p_sys = p_dec->p_sys; + int64_t i_time_increment, i_time_ref; + int i_modulo_time_base = 0, i_time_increment_bits; + bs_t s; + + bs_init( &s, &p_vop->p_buffer[4], p_vop->i_buffer - 4 ); + + switch( bs_read( &s, 2 ) ) { - sout_InputDelete( p_pack->p_sout_input ); + case 0: + p_sys->i_flags = BLOCK_FLAG_TYPE_I; + break; + case 1: + p_sys->i_flags = BLOCK_FLAG_TYPE_P; + break; + case 2: + p_sys->i_flags = BLOCK_FLAG_TYPE_B; + p_sys->b_frame = true; + break; + case 3: /* gni ? */ + p_sys->i_flags = BLOCK_FLAG_TYPE_PB; + break; } -} -static void input_ShowPES( decoder_fifo_t *p_fifo, pes_packet_t **pp_pes ) -{ - pes_packet_t *p_pes; + while( bs_read( &s, 1 ) ) i_modulo_time_base++; + if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */ - vlc_mutex_lock( &p_fifo->data_lock ); + /* VOP time increment */ + i_time_increment_bits = vlc_log2(p_dec->p_sys->i_fps_num - 1) + 1; + if( i_time_increment_bits < 1 ) i_time_increment_bits = 1; + i_time_increment = bs_read( &s, i_time_increment_bits ); - if( p_fifo->p_first == NULL ) + /* Interpolate PTS/DTS */ + if( !(p_sys->i_flags & BLOCK_FLAG_TYPE_B) ) { - if( p_fifo->b_die ) - { - vlc_mutex_unlock( &p_fifo->data_lock ); - if( pp_pes ) *pp_pes = NULL; - return; - } + p_sys->i_last_time_ref = p_sys->i_time_ref; + p_sys->i_time_ref += + (i_modulo_time_base * p_dec->p_sys->i_fps_num); + i_time_ref = p_sys->i_time_ref; + } + else + { + i_time_ref = p_sys->i_last_time_ref + + (i_modulo_time_base * p_dec->p_sys->i_fps_num); + } - /* Signal the input thread we're waiting. This is only - * needed in case of slave clock (ES plug-in) but it won't - * harm. */ - vlc_cond_signal( &p_fifo->data_wait ); +#if 0 + msg_Err( p_dec, "interp pts/dts (%lli,%lli), pts/dts (%lli,%lli)", + p_sys->i_interpolated_pts, p_sys->i_interpolated_dts, + p_vop->i_pts, p_vop->i_dts ); +#endif - /* Wait for the input to tell us when we received a packet. */ - vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock ); + if( p_dec->p_sys->i_fps_num < 5 && /* Work-around buggy streams */ + p_dec->fmt_in.video.i_frame_rate > 0 && + p_dec->fmt_in.video.i_frame_rate_base > 0 ) + { + p_sys->i_interpolated_pts += INT64_C(1000000) * + p_dec->fmt_in.video.i_frame_rate_base * + p_vop->i_rate / INPUT_RATE_DEFAULT / + p_dec->fmt_in.video.i_frame_rate; } - p_pes = p_fifo->p_first; - vlc_mutex_unlock( &p_fifo->data_lock ); + else if( p_dec->p_sys->i_fps_num ) + p_sys->i_interpolated_pts += + ( INT64_C(1000000) * (i_time_ref + i_time_increment - + p_sys->i_last_time - p_sys->i_last_timeincr) * + p_vop->i_rate / INPUT_RATE_DEFAULT / + p_dec->p_sys->i_fps_num ); + + p_sys->i_last_time = i_time_ref; + p_sys->i_last_timeincr = i_time_increment; + + /* Correct interpolated dts when we receive a new pts/dts */ + if( p_vop->i_pts > 0 ) + p_sys->i_interpolated_pts = p_vop->i_pts; + if( p_vop->i_dts > 0 ) + p_sys->i_interpolated_dts = p_vop->i_dts; + + if( (p_sys->i_flags & BLOCK_FLAG_TYPE_B) || !p_sys->b_frame ) + { + /* Trivial case (DTS == PTS) */ + + p_sys->i_interpolated_dts = p_sys->i_interpolated_pts; - if( pp_pes ) + if( p_vop->i_pts > 0 ) + p_sys->i_interpolated_dts = p_vop->i_pts; + if( p_vop->i_dts > 0 ) + p_sys->i_interpolated_dts = p_vop->i_dts; + + p_sys->i_interpolated_pts = p_sys->i_interpolated_dts; + } + else { - *pp_pes = p_pes; + if( p_sys->i_last_ref_pts > 0 ) + p_sys->i_interpolated_dts = p_sys->i_last_ref_pts; + + p_sys->i_last_ref_pts = p_sys->i_interpolated_pts; } + + return VLC_SUCCESS; } +/* look at ffmpeg av_log2 ;) */ +static int vlc_log2( unsigned int v ) +{ + int n = 0; + static const int vlc_log2_table[16] = + { + 0,0,1,1,2,2,2,2, 3,3,3,3,3,3,3,3 + }; + + if( v&0xffff0000 ) + { + v >>= 16; + n += 16; + } + if( v&0xff00 ) + { + v >>= 8; + n += 8; + } + if( v&0xf0 ) + { + v >>= 4; + n += 4; + } + n += vlc_log2_table[v]; + + return n; +}