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;
};
enum {
STATE_NOSYNC,
STATE_NEXT_SYNC
}; };
static int m4v_FindStartCode( uint8_t **, uint8_t * ); static block_t *ParseMPEGBlock( decoder_t *, block_t * );
static int m4v_VOLParse( decoder_t *, es_format_t *, uint8_t *, int ); 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,7 +184,7 @@ static int Open( vlc_object_t *p_this ) ...@@ -160,7 +184,7 @@ 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,130 +218,274 @@ static void Close( vlc_object_t *p_this ) ...@@ -193,130 +218,274 @@ 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; if( (*pp_block)->i_flags & BLOCK_FLAG_DISCONTINUITY )
{
p_sys->i_state = STATE_NOSYNC;
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;
}
p_block = *pp_block; block_BytestreamPush( &p_sys->bytestream, *pp_block );
/* Append data */ while( 1 )
if( p_sys->i_buffer + p_block->i_buffer > p_sys->i_buffer_size )
{ {
p_sys->i_buffer_size += p_block->i_buffer + 1024; switch( p_sys->i_state )
p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size ); {
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;
} }
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 ) if( p_sys->i_offset )
{ {
msg_Warn( p_dec, "reseting context" ); block_SkipBytes( &p_sys->bytestream, p_sys->i_offset );
p_sys->i_buffer = 0; p_sys->i_offset = 0;
block_BytestreamFlush( &p_sys->bytestream );
} }
/* Search vop */ if( p_sys->i_state != STATE_NEXT_SYNC )
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; /* Need more data */
return NULL;
} }
for( ;; )
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 )
{ {
if( m4v_FindStartCode( &p_start, &p_sys->p_buffer[p_sys->i_buffer] ) ) /* 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 ) ) )
{ {
block_Release( p_block ); p_sys->i_state = STATE_NOSYNC;
*pp_block = NULL; break;
return p_chain_out;
} }
/* fprintf( stderr, "start code=0x1%2.2x\n", p_start[3] ); */
if( p_vol ) /* 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 )
{ {
if( !p_dec->fmt_out.i_extra ) 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 );
p_sys->i_state = STATE_NOSYNC;
return p_pic;
}
}
}
/*****************************************************************************
* ParseMPEGBlock: Re-assemble fragments into a block containing a picture
*****************************************************************************/
static block_t *ParseMPEGBlock( decoder_t *p_dec, block_t *p_frag )
{
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 )
{
/* Remove VOS start/end code from the original stream */
block_Release( p_frag );
return NULL;
}
if( p_frag->p_buffer[3] >= 0x20 && p_frag->p_buffer[3] <= 0x2f )
{ {
/* Copy the complete VOL */ /* Copy the complete VOL */
p_dec->fmt_out.i_extra = p_start - p_vol; p_dec->fmt_out.i_extra = p_frag->i_buffer;
p_dec->fmt_out.p_extra = p_dec->fmt_out.p_extra =
realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra ); realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
memcpy( p_dec->fmt_out.p_extra, p_vol, memcpy( p_dec->fmt_out.p_extra, p_frag->p_buffer, p_frag->i_buffer );
p_dec->fmt_out.i_extra ); ParseVOL( p_dec, &p_dec->fmt_out,
m4v_VOLParse( 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 );
}
/* Remove VOL from the original stream */ /* Remove from the original stream */
memmove( p_vol, p_start, block_Release( p_frag );
p_sys->i_buffer - (p_start - p_sys->p_buffer) ); return NULL;
p_sys->i_buffer -= p_dec->fmt_out.i_extra;
p_start = p_vol;
p_vol = NULL;
} }
if( p_sys->b_vop ) else
{
if( !p_dec->fmt_out.i_extra )
{ {
/* Output the complete VOP we have */ msg_Warn( p_dec, "waiting for VOL" );
int i_out = p_start - p_sys->p_buffer; block_Release( p_frag );
block_t *p_out = block_New( p_dec, i_out ); return NULL;
}
/* Append the block */
block_ChainLastAppend( &p_sys->pp_last, p_frag );
}
/* extract data */ if( p_frag->p_buffer[3] == 0xb6 &&
memcpy( p_out->p_buffer, p_sys->p_buffer, i_out ); ParseVOP( p_dec, p_frag ) == VLC_SUCCESS )
if( i_out < p_sys->i_buffer )
{ {
memmove( p_sys->p_buffer, &p_sys->p_buffer[i_out], /* We are dealing with a VOP */
p_sys->i_buffer - i_out ); 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_sys->i_buffer -= i_out;
p_start -= i_out;
p_out->i_flags = p_sys->i_flags; return p_pic;
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 */ /* ParseVOL:
if( p_block->i_dts > p_sys->i_interpolated_dts ) * TODO:
* - support aspect ratio
*/
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;
for( ;; )
{ {
p_out->i_length = p_block->i_dts - p_sys->i_interpolated_dts; 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_dec->fmt_out.i_extra > 0 ) 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 ) )
{ {
block_ChainAppend( &p_chain_out, p_out ); i_vo_ver_id = bs_read( &s, 4 );
bs_skip( &s, 3 );
} }
else else
{ {
msg_Warn( p_dec, "waiting for VOL" ); i_vo_ver_id = 1;
block_Release( p_out );
} }
i_ar = bs_read( &s, 4 );
if( i_ar == 0xf )
{
int i_ar_width, i_ar_height;
p_sys->b_vop = VLC_FALSE; i_ar_width = bs_read( &s, 8 );
i_ar_height= bs_read( &s, 8 );
} }
if( bs_read1( &s ) )
{
int i_chroma_format;
int i_low_delay;
/* vol control parameter */
i_chroma_format = bs_read( &s, 2 );
i_low_delay = bs_read1( &s );
if( p_start[3] >= 0x20 && p_start[3] <= 0x2f ) if( bs_read1( &s ) )
{ {
/* Start of the VOL */ bs_skip( &s, 16 );
p_vol = p_start; bs_skip( &s, 16 );
bs_skip( &s, 16 );
bs_skip( &s, 3 );
bs_skip( &s, 11 );
bs_skip( &s, 1 );
bs_skip( &s, 16 );
} }
else if( p_start[3] == 0xb3 ) }
/* 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 )
{ {
/* GOP header */ bs_skip( &s, 4 );
} }
else if( p_start[3] == 0xb6 )
if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */
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 ) )
{ {
/* Parse the VOP */ int i_time_increment_bits = vlc_log2( p_sys->i_fps_num - 1 ) + 1;
bs_t s;
int i_modulo_time_base = 0; if( i_time_increment_bits < 1 ) i_time_increment_bits = 1;
int i_time_increment_bits;
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 );
}
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; int64_t i_time_increment, i_time_ref;
int i_modulo_time_base = 0, i_time_increment_bits;
bs_t s;
/* FIXME: we don't actually check we received enough data to read bs_init( &s, &p_vop->p_buffer[4], p_vop->i_buffer - 4 );
* 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 ) ) switch( bs_read( &s, 2 ) )
{ {
...@@ -336,7 +505,7 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) ...@@ -336,7 +505,7 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
} }
while( bs_read( &s, 1 ) ) i_modulo_time_base++; while( bs_read( &s, 1 ) ) i_modulo_time_base++;
if( !bs_read1( &s ) ) continue; /* Marker */ if( !bs_read1( &s ) ) return VLC_EGENERIC; /* Marker */
/* VOP time increment */ /* VOP time increment */
i_time_increment_bits = vlc_log2(p_dec->p_sys->i_fps_num - 1) + 1; i_time_increment_bits = vlc_log2(p_dec->p_sys->i_fps_num - 1) + 1;
...@@ -357,30 +526,36 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) ...@@ -357,30 +526,36 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
(i_modulo_time_base * p_dec->p_sys->i_fps_num); (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 */ 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 > 0 &&
p_dec->fmt_in.video.i_frame_rate_base > 0 ) p_dec->fmt_in.video.i_frame_rate_base > 0 )
{ {
p_sys->i_interpolated_pts += I64C(1000000) * p_sys->i_interpolated_pts += I64C(1000000) *
p_dec->fmt_in.video.i_frame_rate_base * p_dec->fmt_in.video.i_frame_rate_base *
p_block->i_rate / INPUT_RATE_DEFAULT / p_vop->i_rate / INPUT_RATE_DEFAULT /
p_dec->fmt_in.video.i_frame_rate; p_dec->fmt_in.video.i_frame_rate;
} }
else if( p_dec->p_sys->i_fps_num ) else if( p_dec->p_sys->i_fps_num )
p_sys->i_interpolated_pts += p_sys->i_interpolated_pts +=
( I64C(1000000) * (i_time_ref + i_time_increment - ( I64C(1000000) * (i_time_ref + i_time_increment -
p_sys->i_last_time - p_sys->i_last_timeincr) * p_sys->i_last_time - p_sys->i_last_timeincr) *
p_block->i_rate / INPUT_RATE_DEFAULT / p_vop->i_rate / INPUT_RATE_DEFAULT /
p_dec->p_sys->i_fps_num ); p_dec->p_sys->i_fps_num );
p_sys->i_last_time = i_time_ref; p_sys->i_last_time = i_time_ref;
p_sys->i_last_timeincr = i_time_increment; p_sys->i_last_timeincr = i_time_increment;
/* Correct interpolated dts when we receive a new pts/dts */ /* Correct interpolated dts when we receive a new pts/dts */
if( p_block->i_pts > 0 ) if( p_vop->i_pts > 0 )
p_sys->i_interpolated_pts = p_block->i_pts; p_sys->i_interpolated_pts = p_vop->i_pts;
if( p_block->i_dts > 0 ) if( p_vop->i_dts > 0 )
p_sys->i_interpolated_dts = p_block->i_dts; p_sys->i_interpolated_dts = p_vop->i_dts;
if( (p_sys->i_flags & BLOCK_FLAG_TYPE_B) || !p_sys->b_frame ) if( (p_sys->i_flags & BLOCK_FLAG_TYPE_B) || !p_sys->b_frame )
{ {
...@@ -388,10 +563,10 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) ...@@ -388,10 +563,10 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
p_sys->i_interpolated_dts = p_sys->i_interpolated_pts; p_sys->i_interpolated_dts = p_sys->i_interpolated_pts;
if( p_block->i_pts > 0 ) if( p_vop->i_pts > 0 )
p_sys->i_interpolated_dts = p_block->i_pts; p_sys->i_interpolated_dts = p_vop->i_pts;
if( p_block->i_dts > 0 ) if( p_vop->i_dts > 0 )
p_sys->i_interpolated_dts = p_block->i_dts; p_sys->i_interpolated_dts = p_vop->i_dts;
p_sys->i_interpolated_pts = p_sys->i_interpolated_dts; p_sys->i_interpolated_pts = p_sys->i_interpolated_dts;
} }
...@@ -403,38 +578,9 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) ...@@ -403,38 +578,9 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block )
p_sys->i_last_ref_pts = p_sys->i_interpolated_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;
}
p_start += 4; /* Next */
}
}
/****************************************************************************
* m4v_FindStartCode
****************************************************************************/
static int m4v_FindStartCode( uint8_t **pp_start, uint8_t *p_end )
{
uint8_t *p = *pp_start;
/* We wait for 4+1 bytes */
for( p = *pp_start; p < p_end - 5; p++ )
{
if( p[0] == 0 && p[1] == 0 && p[2] == 1 )
{
*pp_start = p;
return VLC_SUCCESS; return VLC_SUCCESS;
}
}
*pp_start = p_end;
return VLC_EGENERIC;
} }
/* look at ffmpeg av_log2 ;) */ /* look at ffmpeg av_log2 ;) */
static int vlc_log2( unsigned int v ) static int vlc_log2( unsigned int v )
{ {
...@@ -463,108 +609,3 @@ static int vlc_log2( unsigned int v ) ...@@ -463,108 +609,3 @@ static int vlc_log2( unsigned int v )
return n; return n;
} }
/* m4v_VOLParse:
* TODO:
* - support aspect ratio
*/
static int m4v_VOLParse( decoder_t *p_dec, es_format_t *fmt,
uint8_t *p_vol, int i_vol )
{
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;
}
}
/* parse the vol */
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 ) )
{
i_vo_ver_id = bs_read( &s, 4 );
bs_skip( &s, 3 );
}
else
{
i_vo_ver_id = 1;
}
i_ar = bs_read( &s, 4 );
if( i_ar == 0xf )
{
int i_ar_width, i_ar_height;
i_ar_width = bs_read( &s, 8 );
i_ar_height= bs_read( &s, 8 );
}
if( bs_read1( &s ) )
{
int i_chroma_format;
int i_low_delay;
/* vol control parameter */
i_chroma_format = bs_read( &s, 2 );
i_low_delay = bs_read1( &s );
if( bs_read1( &s ) )
{
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 );
}
}
/* 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 );
}
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;
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;
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 );
}
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 );
}
return VLC_SUCCESS;
}
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