Commit a1bf965d authored by Gildas Bazin's avatar Gildas Bazin

* modules/packetizer/mpeg4video.c: rewrite using the block helper facility....

* modules/packetizer/mpeg4video.c: rewrite using the block helper facility. Fixes a few issues with the previous packetizer and is simpler.
parent 31a2d53b
/***************************************************************************** /*****************************************************************************
* mpeg4video.c: mpeg 4 video packetizer * mpeg4video.c: mpeg 4 video packetizer
***************************************************************************** *****************************************************************************
* Copyright (C) 2001, 2002, 2006 the VideoLAN team * Copyright (C) 2001-2006 the VideoLAN team
* $Id$ * $Id$
* *
* Authors: Laurent Aimar <fenrir@via.ecp.fr> * Authors: Gildas Bazin <gbazin@videolan.org>
* Laurent Aimar <fenrir@via.ecp.fr>
* Eric Petit <titer@videolan.org> * Eric Petit <titer@videolan.org>
* Gildas Bazin <gbazin@videolan.org>
* *
* This program is free software; you can redistribute it and/or modify * 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 * it under the terms of the GNU General Public License as published by
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
#include <vlc/input.h> /* hmmm, just for INPUT_RATE_DEFAULT */ #include <vlc/input.h> /* hmmm, just for INPUT_RATE_DEFAULT */
#include "vlc_bits.h" #include "vlc_bits.h"
#include "vlc_block_helper.h"
/***************************************************************************** /*****************************************************************************
* Module descriptor * Module descriptor
...@@ -49,7 +50,6 @@ vlc_module_begin(); ...@@ -49,7 +50,6 @@ vlc_module_begin();
set_callbacks( Open, Close ); set_callbacks( Open, Close );
vlc_module_end(); vlc_module_end();
/**************************************************************************** /****************************************************************************
* Local prototypes * Local prototypes
****************************************************************************/ ****************************************************************************/
...@@ -57,6 +57,14 @@ static block_t *Packetize( decoder_t *, block_t ** ); ...@@ -57,6 +57,14 @@ static block_t *Packetize( decoder_t *, block_t ** );
struct decoder_sys_t struct decoder_sys_t
{ {
/*
* Input properties
*/
block_bytestream_t bytestream;
int i_state;
int i_offset;
uint8_t p_startcode[3];
/* /*
* Common properties * Common properties
*/ */
...@@ -68,10 +76,6 @@ struct decoder_sys_t ...@@ -68,10 +76,6 @@ struct decoder_sys_t
mtime_t i_last_time; mtime_t i_last_time;
mtime_t i_last_timeincr; 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; unsigned int i_flags;
int i_fps_num; int i_fps_num;
...@@ -80,10 +84,20 @@ struct decoder_sys_t ...@@ -80,10 +84,20 @@ struct decoder_sys_t
int i_last_incr_diff; int i_last_incr_diff;
vlc_bool_t b_frame; vlc_bool_t b_frame;
/* Current frame being built */
block_t *p_frame;
block_t **pp_last;
}; };
static int m4v_FindStartCode( uint8_t **, uint8_t * ); enum {
static int m4v_VOLParse( decoder_t *, es_format_t *, uint8_t *, int ); 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 ); static int vlc_log2( unsigned int );
#define VIDEO_OBJECT_MASK 0x01f #define VIDEO_OBJECT_MASK 0x01f
...@@ -147,6 +161,16 @@ static int Open( vlc_object_t *p_this ) ...@@ -147,6 +161,16 @@ static int Open( vlc_object_t *p_this )
} }
memset( p_sys, 0, sizeof(decoder_sys_t) ); memset( p_sys, 0, sizeof(decoder_sys_t) );
/* Misc init */
p_sys->i_state = STATE_NOSYNC;
p_sys->bytestream = block_BytestreamInit( p_dec );
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 */ /* Setup properties */
es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); 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_FOURCC( 'm', 'p', '4', 'v' );
...@@ -160,8 +184,8 @@ static int Open( vlc_object_t *p_this ) ...@@ -160,8 +184,8 @@ static int Open( vlc_object_t *p_this )
p_dec->fmt_in.i_extra ); p_dec->fmt_in.i_extra );
msg_Dbg( p_dec, "opening with vol size: %d", 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, ParseVOL( p_dec, &p_dec->fmt_out,
p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
} }
else else
{ {
...@@ -183,7 +207,8 @@ static void Close( vlc_object_t *p_this ) ...@@ -183,7 +207,8 @@ static void Close( vlc_object_t *p_this )
{ {
decoder_t *p_dec = (decoder_t*)p_this; decoder_t *p_dec = (decoder_t*)p_this;
if( p_dec->p_sys->p_buffer ) free( p_dec->p_sys->p_buffer ); 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 ); free( p_dec->p_sys );
} }
...@@ -193,307 +218,191 @@ static void Close( vlc_object_t *p_this ) ...@@ -193,307 +218,191 @@ static void Close( vlc_object_t *p_this )
static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
{ {
decoder_sys_t *p_sys = p_dec->p_sys; decoder_sys_t *p_sys = p_dec->p_sys;
block_t *p_pic;
mtime_t i_pts, i_dts;
block_t *p_chain_out = NULL; if( pp_block == NULL || *pp_block == NULL ) return NULL;
block_t *p_block;
uint8_t *p_vol = NULL;
uint8_t *p_start;
if( !pp_block || !*pp_block ) return NULL;
p_block = *pp_block;
/* Append data */ if( (*pp_block)->i_flags & BLOCK_FLAG_DISCONTINUITY )
if( p_sys->i_buffer + p_block->i_buffer > p_sys->i_buffer_size )
{ {
p_sys->i_buffer_size += p_block->i_buffer + 1024; p_sys->i_state = STATE_NOSYNC;
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;
block_Release( *pp_block );
return NULL;
} }
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 ) block_BytestreamPush( &p_sys->bytestream, *pp_block );
{
msg_Warn( p_dec, "reseting context" );
p_sys->i_buffer = 0;
}
/* Search vop */ while( 1 )
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] ) ) switch( p_sys->i_state )
{ {
block_Release( p_block );
*pp_block = NULL;
return p_chain_out;
}
/* fprintf( stderr, "start code=0x1%2.2x\n", p_start[3] ); */
if( p_vol ) case STATE_NOSYNC:
{ if( block_FindStartcodeFromOffset( &p_sys->bytestream,
if( !p_dec->fmt_out.i_extra ) &p_sys->i_offset, p_sys->p_startcode, 3 ) == VLC_SUCCESS )
{ {
/* Copy the complete VOL */ p_sys->i_state = STATE_NEXT_SYNC;
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 );
} }
/* Remove VOL from the original stream */ if( p_sys->i_offset )
memmove( p_vol, p_start,
p_sys->i_buffer - (p_start - p_sys->p_buffer) );
p_sys->i_buffer -= p_dec->fmt_out.i_extra;
p_start = p_vol;
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], block_SkipBytes( &p_sys->bytestream, p_sys->i_offset );
p_sys->i_buffer - i_out ); p_sys->i_offset = 0;
block_BytestreamFlush( &p_sys->bytestream );
} }
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_sys->i_state != STATE_NEXT_SYNC )
if( p_block->i_dts > p_sys->i_interpolated_dts )
{ {
p_out->i_length = p_block->i_dts - p_sys->i_interpolated_dts; /* Need more data */
return NULL;
} }
if( p_dec->fmt_out.i_extra > 0 ) p_sys->i_offset = 1; /* To find next startcode */
{
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; case STATE_NEXT_SYNC:
} /* TODO: If p_block == NULL, flush the buffer without checking the
* next sync word */
if( p_start[3] >= 0x20 && p_start[3] <= 0x2f ) /* Find the next startcode */
{ if( block_FindStartcodeFromOffset( &p_sys->bytestream,
/* Start of the VOL */ &p_sys->i_offset, p_sys->p_startcode, 3 ) != VLC_SUCCESS )
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: /* Need more data */
p_sys->i_flags = BLOCK_FLAG_TYPE_I; return NULL;
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++; /* Get the new fragment and set the pts/dts */
if( !bs_read1( &s ) ) continue; /* Marker */ 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 );
/* VOP time increment */ p_sys->i_offset = 0;
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 */ /* Get picture if any */
if( !(p_sys->i_flags & BLOCK_FLAG_TYPE_B) ) if( !( p_pic = ParseMPEGBlock( p_dec, p_pic ) ) )
{ {
p_sys->i_last_time_ref = p_sys->i_time_ref; p_sys->i_state = STATE_NOSYNC;
p_sys->i_time_ref += break;
(i_modulo_time_base * p_dec->p_sys->i_fps_num);
i_time_ref = p_sys->i_time_ref;
} }
else
/* 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 )
{ {
i_time_ref = p_sys->i_last_time_ref + p_sys->bytestream.p_block->i_pts = 0;
(i_modulo_time_base * p_dec->p_sys->i_fps_num); p_sys->bytestream.p_block->i_dts = 0;
} }
if( p_dec->p_sys->i_fps_num < 5 && /* Work-around buggy streams */ /* We've just started the stream, wait for the first PTS.
p_dec->fmt_in.video.i_frame_rate > 0 && * We discard here so we can still get the sequence header. */
p_dec->fmt_in.video.i_frame_rate_base > 0 ) if( p_sys->i_interpolated_pts <= 0 &&
p_sys->i_interpolated_dts <= 0 )
{ {
p_sys->i_interpolated_pts += I64C(1000000) * msg_Dbg( p_dec, "need a starting pts/dts" );
p_dec->fmt_in.video.i_frame_rate_base * p_sys->i_state = STATE_NOSYNC;
p_block->i_rate / INPUT_RATE_DEFAULT / block_Release( p_pic );
p_dec->fmt_in.video.i_frame_rate; break;
} }
else if( p_dec->p_sys->i_fps_num )
p_sys->i_interpolated_pts +=
( I64C(1000000) * (i_time_ref + i_time_increment -
p_sys->i_last_time - p_sys->i_last_timeincr) *
p_block->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_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; /* When starting the stream we can have the first frame with
} * a null DTS (i_interpolated_pts is initialized to 0) */
else if( !p_pic->i_dts ) p_pic->i_dts = p_pic->i_pts;
{
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; /* So p_block doesn't get re-added several times */
} *pp_block = block_BytestreamPop( &p_sys->bytestream );
p_sys->b_vop = VLC_TRUE; p_sys->i_state = STATE_NOSYNC;
/* Don't re-use the same PTS/DTS twice */ return p_pic;
p_block->i_pts = p_block->i_dts = 0;
} }
p_start += 4; /* Next */
} }
} }
/**************************************************************************** /*****************************************************************************
* m4v_FindStartCode * ParseMPEGBlock: Re-assemble fragments into a block containing a picture
****************************************************************************/ *****************************************************************************/
static int m4v_FindStartCode( uint8_t **pp_start, uint8_t *p_end ) static block_t *ParseMPEGBlock( decoder_t *p_dec, block_t *p_frag )
{ {
uint8_t *p = *pp_start; decoder_sys_t *p_sys = p_dec->p_sys;
block_t *p_pic = NULL;
/* We wait for 4+1 bytes */ if( p_frag->p_buffer[3] == 0xB0 || p_frag->p_buffer[3] == 0xB1 )
for( p = *pp_start; p < p_end - 5; p++ )
{ {
if( p[0] == 0 && p[1] == 0 && p[2] == 1 ) /* Remove VOS start/end code from the original stream */
{ block_Release( p_frag );
*pp_start = p; return NULL;
return VLC_SUCCESS;
}
} }
if( p_frag->p_buffer[3] >= 0x20 && p_frag->p_buffer[3] <= 0x2f )
*pp_start = p_end;
return VLC_EGENERIC;
}
/* 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 /* Copy the complete VOL */
}; p_dec->fmt_out.i_extra = p_frag->i_buffer;
p_dec->fmt_out.p_extra =
if( v&0xffff0000 ) realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
{ memcpy( p_dec->fmt_out.p_extra, p_frag->p_buffer, p_frag->i_buffer );
v >>= 16; ParseVOL( p_dec, &p_dec->fmt_out,
n += 16; p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
/* Remove from the original stream */
block_Release( p_frag );
return NULL;
} }
if( v&0xff00 ) else
{ {
v >>= 8; if( !p_dec->fmt_out.i_extra )
n += 8; {
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; /* We are dealing with a VOP */
n += 4; 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;
} }
n += vlc_log2_table[v];
return n; return p_pic;
} }
/* m4v_VOLParse: /* ParseVOL:
* TODO: * TODO:
* - support aspect ratio * - support aspect ratio
*/ */
static int m4v_VOLParse( decoder_t *p_dec, es_format_t *fmt, static int ParseVOL( decoder_t *p_dec, es_format_t *fmt,
uint8_t *p_vol, int i_vol ) 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; bs_t s;
int i_vo_type;
int i_vo_ver_id;
int i_ar;
int i_shape;
for( ;; ) for( ;; )
{ {
if( p_vol[0] == 0x00 && p_vol[1] == 0x00 && if( p_vol[0] == 0x00 && p_vol[1] == 0x00 && p_vol[2] == 0x01 &&
p_vol[2] == 0x01 && p_vol[3] >= 0x20 && p_vol[3] <= 0x2f ) break;
p_vol[3] >= 0x20 && p_vol[3] <= 0x2f )
{ p_vol++; i_vol--;
break; if( i_vol <= 4 ) return VLC_EGENERIC;
}
p_vol++;
i_vol--;
if( i_vol <= 4 )
{
return VLC_EGENERIC;
}
} }
/* parse the vol */
bs_init( &s, &p_vol[4], i_vol - 4 ); bs_init( &s, &p_vol[4], i_vol - 4 );
bs_skip( &s, 1 ); /* random access */ bs_skip( &s, 1 ); /* random access */
...@@ -544,19 +453,18 @@ static int m4v_VOLParse( decoder_t *p_dec, es_format_t *fmt, ...@@ -544,19 +453,18 @@ static int m4v_VOLParse( decoder_t *p_dec, es_format_t *fmt,
if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */ if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */
p_dec->p_sys->i_fps_num = bs_read( &s, 16 ); /* Time increment resolution*/ 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; if( !p_sys->i_fps_num ) p_sys->i_fps_num = 1;
if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */ if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */
if( bs_read1( &s ) ) if( bs_read1( &s ) )
{ {
int i_time_increment_bits = int i_time_increment_bits = vlc_log2( p_sys->i_fps_num - 1 ) + 1;
vlc_log2( p_dec->p_sys->i_fps_num - 1 ) + 1;
if( i_time_increment_bits < 1 ) i_time_increment_bits = 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 ) if( i_shape == 0 )
{ {
...@@ -566,5 +474,138 @@ static int m4v_VOLParse( decoder_t *p_dec, es_format_t *fmt, ...@@ -566,5 +474,138 @@ static int m4v_VOLParse( decoder_t *p_dec, es_format_t *fmt,
fmt->video.i_height= bs_read( &s, 13 ); fmt->video.i_height= bs_read( &s, 13 );
bs_skip( &s, 1 ); 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 = 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 ) ) 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 += I64C(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;
}
else if( p_dec->p_sys->i_fps_num )
p_sys->i_interpolated_pts +=
( I64C(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( 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
{
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; 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;
}
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