X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fpacketizer%2Fmpeg4video.c;h=84946a5842c26aeeaba547f84d4a278ce9e357aa;hb=12ade3e3bc975d5426ba4af155b7372c31093b31;hp=cd23db2a167cf1a3936de8c979e9a050a997a710;hpb=4bac829985943b58b25bd9249a0c910375965ab5;p=vlc diff --git a/modules/packetizer/mpeg4video.c b/modules/packetizer/mpeg4video.c index cd23db2a16..84946a5842 100644 --- a/modules/packetizer/mpeg4video.c +++ b/modules/packetizer/mpeg4video.c @@ -1,12 +1,12 @@ /***************************************************************************** * mpeg4video.c: mpeg 4 video packetizer ***************************************************************************** - * Copyright (C) 2001, 2002 VideoLAN + * Copyright (C) 2001-2006 the VideoLAN team * $Id$ * - * Authors: Laurent Aimar + * Authors: Gildas Bazin + * Laurent Aimar * Eric Petit - * Gildas Bazin * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,19 +20,26 @@ * * 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 /* malloc(), free() */ -#include -#include -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif -#include "vlc_bits.h" +#include +#include +#include +#include +#include + +#include +#include +#include "packetizer_helper.h" /***************************************************************************** * Module descriptor @@ -40,22 +47,24 @@ static int Open ( vlc_object_t * ); static void Close( vlc_object_t * ); -vlc_module_begin(); - set_category( CAT_SOUT ); - set_subcategory( SUBCAT_SOUT_PACKETIZER ); - set_description( _("MPEG4 video packetizer") ); - set_capability( "packetizer", 50 ); - set_callbacks( Open, Close ); -vlc_module_end(); - +vlc_module_begin () + set_category( CAT_SOUT ) + set_subcategory( SUBCAT_SOUT_PACKETIZER ) + set_description( N_("MPEG4 video packetizer") ) + set_capability( "packetizer", 50 ) + set_callbacks( Open, Close ) +vlc_module_end () /**************************************************************************** * Local prototypes ****************************************************************************/ -static block_t *Packetize( decoder_t *, block_t ** ); - struct decoder_sys_t { + /* + * Input properties + */ + packetizer_t packetizer; + /* * Common properties */ @@ -67,10 +76,6 @@ struct decoder_sys_t mtime_t i_last_time; mtime_t i_last_timeincr; - vlc_bool_t b_vop; - int i_buffer; - int i_buffer_size; - uint8_t *p_buffer; unsigned int i_flags; int i_fps_num; @@ -78,11 +83,22 @@ struct decoder_sys_t int i_last_incr; int i_last_incr_diff; - vlc_bool_t b_frame; + bool b_frame; + + /* Current frame being built */ + block_t *p_frame; + block_t **pp_last; }; -static int m4v_FindStartCode( uint8_t **, uint8_t * ); -static int m4v_VOLParse( decoder_t *, es_format_t *, uint8_t *, int ); +static block_t *Packetize( decoder_t *, block_t ** ); + +static void PacketizeReset( void *p_private, bool b_broken ); +static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t * ); +static int PacketizeValidate( void *p_private, block_t * ); + +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 @@ -105,6 +121,8 @@ static int vlc_log2( unsigned int ); #define TEXTURE_SPATIAL_LAYER_START_CODE 0x1bf #define TEXTURE_SNR_LAYER_START_CODE 0x1c0 +static const uint8_t p_mp4v_startcode[3] = { 0x00, 0x00, 0x01 }; + /***************************************************************************** * Open: probe the packetizer and return score *****************************************************************************/ @@ -113,53 +131,40 @@ static int Open( vlc_object_t *p_this ) decoder_t *p_dec = (decoder_t*)p_this; decoder_sys_t *p_sys; - 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( '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; - - default: - return VLC_EGENERIC; - } + if( p_dec->fmt_in.i_codec != VLC_CODEC_MP4V ) + 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 ) - { - msg_Err( p_dec, "out of memory" ); - return VLC_EGENERIC; - } + return VLC_ENOMEM; memset( p_sys, 0, sizeof(decoder_sys_t) ); + /* Misc init */ + packetizer_Init( &p_sys->packetizer, + p_mp4v_startcode, sizeof(p_mp4v_startcode), + NULL, 0, 4, + PacketizeReset, PacketizeParse, PacketizeValidate, p_dec ); + + 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' ); + p_dec->fmt_out.i_codec = VLC_CODEC_MP4V; + + free(p_dec->fmt_out.p_extra); 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 ); + p_dec->fmt_out.p_extra = xmalloc( 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 ); - m4v_VOLParse( p_dec, &p_dec->fmt_out, - p_dec->fmt_out.p_extra, p_dec->fmt_out.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 { @@ -180,9 +185,12 @@ static int Open( vlc_object_t *p_this ) static void Close( vlc_object_t *p_this ) { decoder_t *p_dec = (decoder_t*)p_this; + decoder_sys_t *p_sys = p_dec->p_sys; - if( p_dec->p_sys->p_buffer ) free( p_dec->p_sys->p_buffer ); - free( p_dec->p_sys ); + packetizer_Clean( &p_sys->packetizer ); + if( p_sys->p_frame ) + block_ChainRelease( p_sys->p_frame ); + free( p_sys ); } /**************************************************************************** @@ -192,286 +200,163 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) { decoder_sys_t *p_sys = p_dec->p_sys; - block_t *p_chain_out = NULL; - block_t *p_block; - uint8_t *p_vol = NULL; - uint8_t *p_start; - - if( !pp_block || !*pp_block ) return NULL; + return packetizer_Packetize( &p_sys->packetizer, pp_block ); +} - p_block = *pp_block; +/***************************************************************************** + * Helpers: + *****************************************************************************/ +static void PacketizeReset( void *p_private, bool b_broken ) +{ + decoder_t *p_dec = p_private; + decoder_sys_t *p_sys = p_dec->p_sys; - /* Append data */ - if( p_sys->i_buffer + p_block->i_buffer > p_sys->i_buffer_size ) + if( b_broken ) { - p_sys->i_buffer_size += p_block->i_buffer + 1024; - p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size ); + if( p_sys->p_frame ) + block_ChainRelease( p_sys->p_frame ); + p_sys->p_frame = NULL; + p_sys->pp_last = &p_sys->p_frame; } - memcpy( &p_sys->p_buffer[p_sys->i_buffer], p_block->p_buffer, - p_block->i_buffer ); - p_sys->i_buffer += p_block->i_buffer; - if( p_sys->i_buffer > 10*1000000 ) - { - msg_Warn( p_dec, "reseting context" ); - p_sys->i_buffer = 0; - } + p_sys->i_interpolated_pts = + p_sys->i_interpolated_dts = + p_sys->i_last_ref_pts = VLC_TS_INVALID; - /* Search vop */ - p_start = &p_sys->p_buffer[p_sys->i_buffer - p_block->i_buffer - 4]; - if( p_start < p_sys->p_buffer ) - { - p_start = p_sys->p_buffer; - } - for( ;; ) - { - if( m4v_FindStartCode( &p_start, &p_sys->p_buffer[p_sys->i_buffer] ) ) - { - block_Release( p_block ); - *pp_block = NULL; - return p_chain_out; - } - /* fprintf( stderr, "start code=0x1%2.2x\n", p_start[3] ); */ + p_sys->i_last_time_ref = + p_sys->i_time_ref = + p_sys->i_last_time = + p_sys->i_last_timeincr = 0; +} - if( p_vol ) - { - /* Copy the complete VOL */ - p_dec->fmt_out.i_extra = p_start - p_vol; - p_dec->fmt_out.p_extra = - realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); - memcpy( p_dec->fmt_out.p_extra, p_vol, p_dec->fmt_out.i_extra ); - m4v_VOLParse( p_dec, &p_dec->fmt_out, - p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); +static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_block ) +{ + decoder_t *p_dec = p_private; + const mtime_t i_dts = p_block->i_dts; + const mtime_t i_pts = p_block->i_pts; - p_vol = NULL; - } - if( p_sys->b_vop ) - { - /* Output the complete VOP we have */ - int i_out = p_start - p_sys->p_buffer; - block_t *p_out = block_New( p_dec, i_out ); - - /* extract data */ - memcpy( p_out->p_buffer, p_sys->p_buffer, i_out ); - if( i_out < p_sys->i_buffer ) - { - memmove( p_sys->p_buffer, &p_sys->p_buffer[i_out], - p_sys->i_buffer - i_out ); - } - p_sys->i_buffer -= i_out; - p_start -= i_out; - - p_out->i_flags = p_sys->i_flags; - p_out->i_pts = p_sys->i_interpolated_pts; - p_out->i_dts = p_sys->i_interpolated_dts; - - /* FIXME doesn't work when there is multiple VOP in one block */ - if( p_block->i_dts > p_sys->i_interpolated_dts ) - { - p_out->i_length = p_block->i_dts - p_sys->i_interpolated_dts; - } - - if( p_dec->fmt_out.i_extra > 0 ) - { - block_ChainAppend( &p_chain_out, p_out ); - } - else - { - msg_Warn( p_dec, "waiting for VOL" ); - block_Release( p_out ); - } - - p_sys->b_vop = VLC_FALSE; - } + block_t *p_au = ParseMPEGBlock( p_dec, p_block ); - if( p_start[3] >= 0x20 && p_start[3] <= 0x2f ) - { - /* Start of the VOL */ - p_vol = p_start; - } - else if( p_start[3] == 0xb3 ) - { - /* GOP header */ - } - else if( p_start[3] == 0xb6 ) - { - /* Parse the VOP */ - bs_t s; - int i_modulo_time_base = 0; - int i_time_increment_bits; - int64_t i_time_increment, i_time_ref; - - /* FIXME: we don't actually check we received enough data to read - * the VOP time increment. */ - bs_init( &s, &p_start[4], - p_sys->i_buffer - (p_start - p_sys->p_buffer) - 4 ); - - switch( bs_read( &s, 2 ) ) - { - 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 = VLC_TRUE; - break; - case 3: /* gni ? */ - p_sys->i_flags = BLOCK_FLAG_TYPE_PB; - break; - } - - while( bs_read( &s, 1 ) ) i_modulo_time_base++; - if( !bs_read1( &s ) ) continue; /* Marker */ - - /* 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 ); - - /* Interpolate PTS/DTS */ - if( !(p_sys->i_flags & BLOCK_FLAG_TYPE_B) ) - { - 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); - } - - if( p_dec->p_sys->i_fps_num ) - p_sys->i_interpolated_pts += - ( (i_time_ref + i_time_increment - - p_sys->i_last_time - p_sys->i_last_timeincr) * - I64C(1000000) / 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_block->i_pts > 0 ) - p_sys->i_interpolated_pts = p_block->i_pts; - if( p_block->i_dts > 0 ) - p_sys->i_interpolated_dts = p_block->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( p_block->i_pts > 0 ) - p_sys->i_interpolated_dts = p_block->i_pts; - if( p_block->i_dts > 0 ) - p_sys->i_interpolated_dts = p_block->i_dts; - - p_sys->i_interpolated_pts = p_sys->i_interpolated_dts; - } - else - { - 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; - } - - p_sys->b_vop = VLC_TRUE; - - /* Don't re-use the same PTS/DTS twice */ - p_block->i_pts = p_block->i_dts = 0; - } + *pb_ts_used = p_au && p_au->i_dts == i_dts && p_au->i_pts == i_pts; - p_start += 4; /* Next */ - } + return p_au; } -/**************************************************************************** - * m4v_FindStartCode - ****************************************************************************/ -static int m4v_FindStartCode( uint8_t **pp_start, uint8_t *p_end ) + +static int PacketizeValidate( void *p_private, block_t *p_au ) { - uint8_t *p = *pp_start; + decoder_t *p_dec = p_private; + decoder_sys_t *p_sys = p_dec->p_sys; - /* We wait for 4+1 bytes */ - for( p = *pp_start; p < p_end - 5; p++ ) + /* 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 <= VLC_TS_INVALID && + p_sys->i_interpolated_dts <= VLC_TS_INVALID ) { - if( p[0] == 0 && p[1] == 0 && p[2] == 1 ) - { - *pp_start = p; - return VLC_SUCCESS; - } + msg_Dbg( p_dec, "need a starting pts/dts" ); + return VLC_EGENERIC; } - *pp_start = p_end; - return VLC_EGENERIC; + /* When starting the stream we can have the first frame with + * a null DTS (i_interpolated_pts is initialized to 0) */ + if( !p_au->i_dts ) + p_au->i_dts = p_au->i_pts; + return VLC_SUCCESS; } - -/* look at ffmpeg av_log2 ;) */ -static int vlc_log2( unsigned int v ) +/***************************************************************************** + * ParseMPEGBlock: Re-assemble fragments into a block containing a picture + *****************************************************************************/ +static block_t *ParseMPEGBlock( decoder_t *p_dec, block_t *p_frag ) { - 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 ) + decoder_sys_t *p_sys = p_dec->p_sys; + block_t *p_pic = NULL; + + 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 ) { - v >>= 16; - n += 16; + /* Copy the complete VOL */ + if( (size_t)p_dec->fmt_out.i_extra != p_frag->i_buffer ) + { + p_dec->fmt_out.p_extra = + xrealloc( 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; } - if( v&0xff00 ) + else { - v >>= 8; - n += 8; + 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( v&0xf0 ) + + if( p_frag->p_buffer[3] == 0xb6 && + ParseVOP( p_dec, p_frag ) == VLC_SUCCESS ) { - v >>= 4; - n += 4; + /* We are dealing with a VOP */ + p_pic = block_ChainGather( p_sys->p_frame ); + p_pic->i_flags = p_sys->i_flags; + 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; } - n += vlc_log2_table[v]; - return n; + return p_pic; } -/* m4v_VOLParse: +/* ParseVOL: * TODO: * - support aspect ratio */ -static int m4v_VOLParse( decoder_t *p_dec, es_format_t *fmt, - uint8_t *p_vol, int i_vol ) +static int ParseVOL( decoder_t *p_dec, es_format_t *fmt, + uint8_t *p_vol, int i_vol ) { + decoder_sys_t *p_sys = p_dec->p_sys; + int i_vo_type, i_vo_ver_id, i_ar, i_shape; bs_t s; - int i_vo_type; - int i_vo_ver_id; - int i_ar; - int i_shape; for( ;; ) { - 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; - } + 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; } - /* parse the vol */ bs_init( &s, &p_vol[4], i_vol - 4 ); bs_skip( &s, 1 ); /* random access */ @@ -522,19 +407,18 @@ static int m4v_VOLParse( decoder_t *p_dec, es_format_t *fmt, if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */ - p_dec->p_sys->i_fps_num = bs_read( &s, 16 ); /* Time increment resolution*/ - if( !p_dec->p_sys->i_fps_num ) p_dec->p_sys->i_fps_num = 1; + p_sys->i_fps_num = bs_read( &s, 16 ); /* Time increment resolution*/ + if( !p_sys->i_fps_num ) p_sys->i_fps_num = 1; if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */ if( bs_read1( &s ) ) { - int i_time_increment_bits = - vlc_log2( p_dec->p_sys->i_fps_num - 1 ) + 1; + int i_time_increment_bits = vlc_log2( p_sys->i_fps_num - 1 ) + 1; if( i_time_increment_bits < 1 ) i_time_increment_bits = 1; - p_dec->p_sys->i_fps_den = bs_read( &s, i_time_increment_bits ); + p_sys->i_fps_den = bs_read( &s, i_time_increment_bits ); } if( i_shape == 0 ) { @@ -544,5 +428,136 @@ static int m4v_VOLParse( decoder_t *p_dec, es_format_t *fmt, fmt->video.i_height= bs_read( &s, 13 ); bs_skip( &s, 1 ); } + return VLC_SUCCESS; } + +static int ParseVOP( decoder_t *p_dec, block_t *p_vop ) +{ + 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 ) ) + { + 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; + } + + while( bs_read( &s, 1 ) ) i_modulo_time_base++; + if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */ + + /* 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 ); + + /* Interpolate PTS/DTS */ + if( !(p_sys->i_flags & BLOCK_FLAG_TYPE_B) ) + { + 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); + } + +#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 + + 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_dec->fmt_in.video.i_frame_rate; + } + 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_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 > VLC_TS_INVALID ) + p_sys->i_interpolated_pts = p_vop->i_pts; + if( p_vop->i_dts > VLC_TS_INVALID ) + 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( p_vop->i_pts > VLC_TS_INVALID ) + p_sys->i_interpolated_dts = p_vop->i_pts; + if( p_vop->i_dts > VLC_TS_INVALID ) + p_sys->i_interpolated_dts = p_vop->i_dts; + + p_sys->i_interpolated_pts = p_sys->i_interpolated_dts; + } + else + { + if( p_sys->i_last_ref_pts > VLC_TS_INVALID ) + 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; +}