From: Laurent Aimar Date: Tue, 28 Apr 2009 17:27:16 +0000 (+0200) Subject: Moved and fixed all common code from video packetizers into packetizer_helper.h X-Git-Tag: 1.0.0-rc1~177 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=55441fa5440b6aceddc8ef6888750350a22d0c2f;p=vlc Moved and fixed all common code from video packetizers into packetizer_helper.h There are some risks of regression (in case of typo), but it was a nightmare to maintain. Also by using the right model (h264.c) it fixes some timing issues in vc1 and mpeg2 packetizer. --- diff --git a/modules/packetizer/h264.c b/modules/packetizer/h264.c index 175643e093..d1f7f88262 100644 --- a/modules/packetizer/h264.c +++ b/modules/packetizer/h264.c @@ -41,6 +41,7 @@ #include "vlc_block_helper.h" #include "vlc_bits.h" #include "../codec/cc.h" +#include "packetizer_helper.h" /***************************************************************************** * Module descriptor @@ -60,10 +61,6 @@ vlc_module_end () /**************************************************************************** * Local prototypes ****************************************************************************/ -static block_t *Packetize( decoder_t *, block_t ** ); -static block_t *PacketizeAVC1( decoder_t *, block_t ** ); -static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] ); - typedef struct { int i_nal_type; @@ -89,12 +86,10 @@ typedef struct #define PPS_MAX (256) struct decoder_sys_t { - block_bytestream_t bytestream; - - int i_state; - size_t i_offset; - uint8_t startcode[4]; + /* */ + packetizer_t packetizer; + /* */ bool b_slice; block_t *p_frame; @@ -133,12 +128,6 @@ struct decoder_sys_t cc_data_t cc_next; }; -enum -{ - STATE_NOSYNC, - STATE_NEXT_SYNC, -}; - enum nal_unit_type_e { NAL_UNKNOWN = 0, @@ -162,8 +151,15 @@ enum nal_priority_e NAL_PRIORITY_HIGHEST = 3, }; -static block_t *ParseNALBlock( decoder_t *, bool *pb_used_ts, block_t * ); +static block_t *Packetize( decoder_t *, block_t ** ); +static block_t *PacketizeAVC1( decoder_t *, block_t ** ); +static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] ); +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 *ParseNALBlock( decoder_t *, bool *pb_used_ts, block_t * ); static block_t *CreateAnnexbNAL( decoder_t *, const uint8_t *p, int ); static block_t *OutputPicture( decoder_t *p_dec ); @@ -174,6 +170,8 @@ static void ParseSlice( decoder_t *p_dec, bool *pb_new_picture, slice_t *p_slice static void ParseSei( decoder_t *, block_t * ); +static const uint8_t p_h264_startcode[3] = { 0x00, 0x00, 0x01 }; + /***************************************************************************** * Open: probe the packetizer and return score * When opening after demux, the packetizer is only loaded AFTER the decoder @@ -203,13 +201,12 @@ static int Open( vlc_object_t *p_this ) { return VLC_ENOMEM; } - p_sys->i_state = STATE_NOSYNC; - p_sys->i_offset = 0; - p_sys->startcode[0] = 0; - p_sys->startcode[1] = 0; - p_sys->startcode[2] = 0; - p_sys->startcode[3] = 1; - p_sys->bytestream = block_BytestreamInit(); + + packetizer_Init( &p_sys->packetizer, + p_h264_startcode, sizeof(p_h264_startcode), + p_h264_startcode, 1, + PacketizeReset, PacketizeParse, PacketizeValidate, p_dec ); + p_sys->b_slice = false; p_sys->p_frame = NULL; p_sys->b_header= false; @@ -397,7 +394,8 @@ static void Close( vlc_object_t *p_this ) if( p_sys->pp_pps[i] ) block_Release( p_sys->pp_pps[i] ); } - block_BytestreamRelease( &p_sys->bytestream ); + packetizer_Clean( &p_sys->packetizer ); + if( p_dec->pf_get_cc ) { cc_Exit( &p_sys->cc_next ); @@ -415,117 +413,8 @@ static void Close( vlc_object_t *p_this ) 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; - - if( !pp_block || !*pp_block ) - return NULL; - - if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) - { - if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED ) - { - p_sys->i_state = STATE_NOSYNC; - block_BytestreamEmpty( &p_sys->bytestream ); - - if( p_sys->p_frame ) - block_ChainRelease( p_sys->p_frame ); - p_sys->p_frame = NULL; - p_sys->slice.i_frame_type = 0; - p_sys->b_slice = false; - } - p_sys->i_frame_pts = -1; - p_sys->i_frame_dts = -1; - - block_Release( *pp_block ); - return NULL; - } - - block_BytestreamPush( &p_sys->bytestream, *pp_block ); - - for( ;; ) - { - bool b_used_ts; - - switch( p_sys->i_state ) - { - case STATE_NOSYNC: - /* Skip until 3 byte startcode 0 0 1 */ - if( block_FindStartcodeFromOffset( &p_sys->bytestream, - &p_sys->i_offset, p_sys->startcode+1, 3 ) == VLC_SUCCESS) - { - p_sys->i_state = STATE_NEXT_SYNC; - } - - if( p_sys->i_offset ) - { - /* skip the data */ - 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: - /* Find the next 3 byte startcode 0 0 1*/ - if( block_FindStartcodeFromOffset( &p_sys->bytestream, - &p_sys->i_offset, p_sys->startcode+1, 3 ) != VLC_SUCCESS) - { - /* Need more data */ - return NULL; - } - block_BytestreamFlush( &p_sys->bytestream ); - - /* Get the new fragment and set the pts/dts */ - block_t *p_block_bytestream = p_sys->bytestream.p_block; - - p_pic = block_New( p_dec, p_sys->i_offset +1 ); - p_pic->i_pts = p_block_bytestream->i_pts; - p_pic->i_dts = p_block_bytestream->i_dts; - - /* Force 4 byte startcode 0 0 0 1 */ - p_pic->p_buffer[0] = 0; - - block_GetBytes( &p_sys->bytestream, &p_pic->p_buffer[1], - p_pic->i_buffer-1 ); - - /* Remove trailing 0 bytes */ - while( p_pic->i_buffer && (!p_pic->p_buffer[p_pic->i_buffer-1] ) ) - p_pic->i_buffer--; - p_sys->i_offset = 0; - - /* Parse the NAL */ - p_pic = ParseNALBlock( p_dec, &b_used_ts, p_pic ); - if( b_used_ts ) - { - p_block_bytestream->i_dts = -1; - p_block_bytestream->i_pts = -1; - } - - if( !p_pic ) - { - p_sys->i_state = STATE_NOSYNC; - break; - } -#if 0 - msg_Dbg( p_dec, "pts=%"PRId64" dts=%"PRId64, - p_pic->i_pts, p_pic->i_dts ); -#endif - - /* 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; - } - } + return packetizer_Packetize( &p_sys->packetizer, pp_block ); } /**************************************************************************** @@ -618,6 +507,39 @@ static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] ) /**************************************************************************** * 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; + + if( b_broken ) + { + if( p_sys->p_frame ) + block_ChainRelease( p_sys->p_frame ); + p_sys->p_frame = NULL; + p_sys->slice.i_frame_type = 0; + p_sys->b_slice = false; + } + p_sys->i_frame_pts = -1; + p_sys->i_frame_dts = -1; +} +static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_block ) +{ + decoder_t *p_dec = p_private; + + /* Remove trailing 0 bytes */ + while( p_block->i_buffer && p_block->p_buffer[p_block->i_buffer-1] == 0x00 ) + p_block->i_buffer--; + + return ParseNALBlock( p_dec, pb_ts_used, p_block ); +} +static int PacketizeValidate( void *p_private, block_t *p_au ) +{ + VLC_UNUSED(p_private); + VLC_UNUSED(p_au); + return VLC_SUCCESS; +} + static block_t *CreateAnnexbNAL( decoder_t *p_dec, const uint8_t *p, int i_size ) { block_t *p_nal; diff --git a/modules/packetizer/mpeg4video.c b/modules/packetizer/mpeg4video.c index 06e5f4eb6d..018846c998 100644 --- a/modules/packetizer/mpeg4video.c +++ b/modules/packetizer/mpeg4video.c @@ -39,6 +39,7 @@ #include "vlc_bits.h" #include "vlc_block_helper.h" +#include "packetizer_helper.h" /***************************************************************************** * Module descriptor @@ -57,17 +58,12 @@ 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]; + packetizer_t packetizer; /* * Common properties @@ -94,10 +90,11 @@ struct decoder_sys_t block_t **pp_last; }; -enum { - STATE_NOSYNC, - STATE_NEXT_SYNC -}; +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 ); @@ -124,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 *****************************************************************************/ @@ -163,12 +162,11 @@ static int Open( vlc_object_t *p_this ) 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; + packetizer_Init( &p_sys->packetizer, + p_mp4v_startcode, sizeof(p_mp4v_startcode), + NULL, 0, + PacketizeReset, PacketizeParse, PacketizeValidate, p_dec ); + p_sys->p_frame = NULL; p_sys->pp_last = &p_sys->p_frame; @@ -207,10 +205,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; - 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 ); + packetizer_Clean( &p_sys->packetizer ); + if( p_sys->p_frame ) + block_ChainRelease( p_sys->p_frame ); + free( p_sys ); } /**************************************************************************** @@ -219,125 +219,68 @@ static void Close( vlc_object_t *p_this ) 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( pp_block == NULL || *pp_block == NULL ) return NULL; + return packetizer_Packetize( &p_sys->packetizer, 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; - if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) + if( b_broken ) { - if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED ) - { - p_sys->i_state = STATE_NOSYNC; - block_BytestreamEmpty( &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; + 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_BytestreamPush( &p_sys->bytestream, *pp_block ); + 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; +} - while( 1 ) - { - switch( p_sys->i_state ) - { +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; - 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; - } - - 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; - - 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 ); - - p_sys->i_state = STATE_NOSYNC; - - return p_pic; - } + block_t *p_au = ParseMPEGBlock( p_dec, p_block ); + + *pb_ts_used = p_au && p_au->i_dts == i_dts && p_au->i_pts == i_pts; + + return p_au; +} + + +static int PacketizeValidate( void *p_private, block_t *p_au ) +{ + decoder_t *p_dec = p_private; + decoder_sys_t *p_sys = p_dec->p_sys; + + /* 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" ); + 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; } /***************************************************************************** diff --git a/modules/packetizer/mpegvideo.c b/modules/packetizer/mpegvideo.c index e841928ff3..a3a4020cfb 100644 --- a/modules/packetizer/mpegvideo.c +++ b/modules/packetizer/mpegvideo.c @@ -52,6 +52,7 @@ #include #include #include "../codec/cc.h" +#include "packetizer_helper.h" #define SYNC_INTRAFRAME_TEXT N_("Sync on Intra Frame") #define SYNC_INTRAFRAME_LONGTEXT N_("Normally the packetizer would " \ @@ -79,19 +80,12 @@ vlc_module_end () /***************************************************************************** * Local prototypes *****************************************************************************/ -static block_t *Packetize( decoder_t *, block_t ** ); -static block_t *ParseMPEGBlock( decoder_t *, block_t * ); -static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] ); - struct decoder_sys_t { /* * Input properties */ - block_bytestream_t bytestream; - int i_state; - size_t i_offset; - uint8_t p_startcode[3]; + packetizer_t packetizer; /* Sequence header and extension */ block_t *p_seq; @@ -140,10 +134,16 @@ struct decoder_sys_t cc_data_t cc; }; -enum { - STATE_NOSYNC, - STATE_NEXT_SYNC -}; +static block_t *Packetize( decoder_t *, block_t ** ); +static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] ); + +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 const uint8_t p_mp2v_startcode[3] = { 0x00, 0x00, 0x01 }; /***************************************************************************** * Open: @@ -170,12 +170,10 @@ static int Open( vlc_object_t *p_this ) memset( p_dec->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; + packetizer_Init( &p_sys->packetizer, + p_mp2v_startcode, sizeof(p_mp2v_startcode), + NULL, 0, + PacketizeReset, PacketizeParse, PacketizeValidate, p_dec ); p_sys->p_seq = NULL; p_sys->p_ext = NULL; @@ -225,8 +223,6 @@ 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; - block_BytestreamRelease( &p_sys->bytestream ); - if( p_sys->p_seq ) { block_Release( p_sys->p_seq ); @@ -239,6 +235,7 @@ static void Close( vlc_object_t *p_this ) { block_ChainRelease( p_sys->p_frame ); } + packetizer_Clean( &p_sys->packetizer ); var_Destroy( p_dec, "packetizer-mpegvideo-sync-iframe" ); @@ -251,147 +248,8 @@ static void Close( vlc_object_t *p_this ) 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; - - if( pp_block == NULL || *pp_block == NULL ) - { - return NULL; - } - - if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) - { - if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED ) - { - p_sys->i_state = STATE_NOSYNC; - block_BytestreamEmpty( &p_sys->bytestream ); - - p_sys->b_discontinuity = true; - 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->b_frame_slice = false; - } - p_sys->i_dts = 0; - p_sys->i_pts = 0; - p_sys->i_interpolated_dts = 0; - p_sys->i_last_ref_pts = 0; - - block_Release( *pp_block ); - return NULL; - } - - - block_BytestreamPush( &p_sys->bytestream, *pp_block ); - - while( 1 ) - { - switch( p_sys->i_state ) - { - - 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; - } - - 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 = p_sys->bytestream.p_block->i_pts; - p_pic->i_dts = p_sys->bytestream.p_block->i_dts; - - block_GetBytes( &p_sys->bytestream, p_pic->p_buffer, - p_pic->i_buffer ); - - /* don't reuse the same timestamps several times */ - if( p_pic->i_buffer >= 4 && p_pic->p_buffer[3] == 0x00 ) - { - /* We have a picture start code */ - p_sys->bytestream.p_block->i_pts = 0; - p_sys->bytestream.p_block->i_dts = 0; - } - - p_sys->i_offset = 0; - - /* Get picture if any */ - if( !( p_pic = ParseMPEGBlock( p_dec, p_pic ) ) ) - { - p_sys->i_state = STATE_NOSYNC; - break; - } - /* If a discontinuity has been encountered, then wait till - * the next Intra frame before continuing with packetizing */ - if( p_sys->b_discontinuity && - p_sys->b_sync_on_intra_frame ) - { - if( p_pic->i_flags & BLOCK_FLAG_TYPE_I ) - { - msg_Dbg( p_dec, "synced on intra frame" ); - p_sys->b_discontinuity = false; - p_pic->i_flags |= BLOCK_FLAG_DISCONTINUITY; - } - else - { - msg_Dbg( p_dec, "waiting on intra frame" ); - p_sys->i_state = STATE_NOSYNC; - block_Release( p_pic ); - break; - } - } - - /* 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_dts <= 0 && p_sys->i_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; - } - } + return packetizer_Packetize( &p_sys->packetizer, pp_block ); } /***************************************************************************** @@ -421,6 +279,76 @@ static block_t *GetCc( decoder_t *p_dec, bool pb_present[4] ) return p_cc; } +/***************************************************************************** + * 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; + + if( b_broken ) + { + p_sys->b_discontinuity = true; + 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->b_frame_slice = false; + } + p_sys->i_dts = 0; + p_sys->i_pts = 0; + p_sys->i_interpolated_dts = 0; + p_sys->i_last_ref_pts = 0; +} + +static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_block ) +{ + decoder_t *p_dec = p_private; + + /* Check if we have a picture start code */ + *pb_ts_used = p_block->i_buffer >= 4 && p_block->p_buffer[3] == 0x00; + + return ParseMPEGBlock( p_dec, p_block ); +} + + +static int PacketizeValidate( void *p_private, block_t *p_au ) +{ + decoder_t *p_dec = p_private; + decoder_sys_t *p_sys = p_dec->p_sys; + + /* If a discontinuity has been encountered, then wait till + * the next Intra frame before continuing with packetizing */ + if( p_sys->b_discontinuity && + p_sys->b_sync_on_intra_frame ) + { + if( (p_au->i_flags & BLOCK_FLAG_TYPE_I) == 0 ) + { + msg_Dbg( p_dec, "waiting on intra frame" ); + return VLC_EGENERIC; + } + msg_Dbg( p_dec, "synced on intra frame" ); + p_sys->b_discontinuity = false; + p_au->i_flags |= BLOCK_FLAG_DISCONTINUITY; + } + + /* 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_dts <= 0 && p_sys->i_pts <= 0 && + p_sys->i_interpolated_dts <= 0 ) + { + msg_Dbg( p_dec, "need a starting pts/dts" ); + 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; +} /***************************************************************************** * ParseMPEGBlock: Re-assemble fragments into a block containing a picture *****************************************************************************/ diff --git a/modules/packetizer/packetizer_helper.h b/modules/packetizer/packetizer_helper.h new file mode 100644 index 0000000000..33e9c77cda --- /dev/null +++ b/modules/packetizer/packetizer_helper.h @@ -0,0 +1,186 @@ +/***************************************************************************** + * packetizer.h: Packetizer helpers + ***************************************************************************** + * Copyright (C) 2009 Laurent Aimar + * $Id$ + * + * Authors: Laurent Aimar + * + * 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 + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * 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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. + *****************************************************************************/ + +#ifndef _PACKETIZER_H +#define _PACKETIZER_H 1 + +#include + +enum +{ + STATE_NOSYNC, + STATE_NEXT_SYNC +}; + +typedef void (*packetizer_reset_t)( void *p_private, bool b_broken ); +typedef block_t *(*packetizer_parse_t)( void *p_private, bool *pb_ts_used, block_t * ); +typedef int (*packetizer_validate_t)( void *p_private, block_t * ); + +typedef struct +{ + int i_state; + block_bytestream_t bytestream; + size_t i_offset; + + int i_startcode; + const uint8_t *p_startcode; + + int i_au_prepend; + const uint8_t *p_au_prepend; + + void *p_private; + packetizer_reset_t pf_reset; + packetizer_parse_t pf_parse; + packetizer_validate_t pf_validate; + +} packetizer_t; + +static inline void packetizer_Init( packetizer_t *p_pack, + const uint8_t *p_startcode, int i_startcode, + const uint8_t *p_au_prepend, int i_au_prepend, + packetizer_reset_t pf_reset, + packetizer_parse_t pf_parse, + packetizer_validate_t pf_validate, + void *p_private ) +{ + p_pack->i_state = STATE_NOSYNC; + p_pack->bytestream = block_BytestreamInit(); + p_pack->i_offset = 0; + + p_pack->i_au_prepend = i_au_prepend; + p_pack->p_au_prepend = p_au_prepend; + + p_pack->i_startcode = i_startcode; + p_pack->p_startcode = p_startcode; + p_pack->pf_reset = pf_reset; + p_pack->pf_parse = pf_parse; + p_pack->pf_validate = pf_validate; + p_pack->p_private = p_private; +} + +static inline void packetizer_Clean( packetizer_t *p_pack ) +{ + block_BytestreamRelease( &p_pack->bytestream ); +} + +static inline block_t *packetizer_Packetize( packetizer_t *p_pack, block_t **pp_block ) +{ + if( !pp_block || !*pp_block ) + return NULL; + + if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) + { + const bool b_broken = ( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED ) != 0; + if( b_broken ) + { + p_pack->i_state = STATE_NOSYNC; + block_BytestreamEmpty( &p_pack->bytestream ); + p_pack->i_offset = 0; + } + p_pack->pf_reset( p_pack->p_private, b_broken ); + + block_Release( *pp_block ); + return NULL; + } + + block_BytestreamPush( &p_pack->bytestream, *pp_block ); + + for( ;; ) + { + bool b_used_ts; + block_t *p_pic; + + switch( p_pack->i_state ) + { + case STATE_NOSYNC: + /* Find a startcode */ + if( !block_FindStartcodeFromOffset( &p_pack->bytestream, &p_pack->i_offset, + p_pack->p_startcode, p_pack->i_startcode ) ) + p_pack->i_state = STATE_NEXT_SYNC; + + if( p_pack->i_offset ) + { + block_SkipBytes( &p_pack->bytestream, p_pack->i_offset ); + p_pack->i_offset = 0; + block_BytestreamFlush( &p_pack->bytestream ); + } + + if( p_pack->i_state != STATE_NEXT_SYNC ) + return NULL; /* Need more data */ + + p_pack->i_offset = 1; /* To find next startcode */ + + case STATE_NEXT_SYNC: + /* Find the next startcode */ + if( block_FindStartcodeFromOffset( &p_pack->bytestream, &p_pack->i_offset, + p_pack->p_startcode, p_pack->i_startcode ) ) + return NULL; /* Need more data */ + + block_BytestreamFlush( &p_pack->bytestream ); + + /* Get the new fragment and set the pts/dts */ + block_t *p_block_bytestream = p_pack->bytestream.p_block; + + p_pic = block_New( p_dec, p_pack->i_offset + p_pack->i_au_prepend ); + p_pic->i_pts = p_block_bytestream->i_pts; + p_pic->i_dts = p_block_bytestream->i_dts; + + block_GetBytes( &p_pack->bytestream, &p_pic->p_buffer[p_pack->i_au_prepend], + p_pic->i_buffer - p_pack->i_au_prepend ); + if( p_pack->i_au_prepend > 0 ) + memcpy( p_pic->p_buffer, p_pack->p_au_prepend, p_pack->i_au_prepend ); + + p_pack->i_offset = 0; + + /* Parse the NAL */ + p_pic = p_pack->pf_parse( p_pack->p_private, &b_used_ts, p_pic ); + if( b_used_ts ) + { + p_block_bytestream->i_dts = -1; + p_block_bytestream->i_pts = -1; + } + + if( !p_pic ) + { + p_pack->i_state = STATE_NOSYNC; + break; + } + if( p_pack->pf_validate( p_pack->p_private, p_pic ) ) + { + p_pack->i_state = STATE_NOSYNC; + block_Release( p_pic ); + break; + } + + /* So p_block doesn't get re-added several times */ + *pp_block = block_BytestreamPop( &p_pack->bytestream ); + + p_pack->i_state = STATE_NOSYNC; + + return p_pic; + } + } +} + +#endif + diff --git a/modules/packetizer/vc1.c b/modules/packetizer/vc1.c index e62894057d..2cd4bc8b71 100644 --- a/modules/packetizer/vc1.c +++ b/modules/packetizer/vc1.c @@ -37,6 +37,7 @@ #include "vlc_bits.h" #include "vlc_block_helper.h" +#include "packetizer_helper.h" /***************************************************************************** * Module descriptor @@ -60,10 +61,7 @@ struct decoder_sys_t /* * Input properties */ - block_bytestream_t bytestream; - int i_state; - size_t i_offset; - uint8_t p_startcode[3]; + packetizer_t packetizer; /* Current sequence header */ bool b_sequence_header; @@ -93,12 +91,6 @@ struct decoder_sys_t mtime_t i_interpolated_dts; }; -enum -{ - STATE_NOSYNC, - STATE_NEXT_SYNC -}; - typedef enum { IDU_TYPE_SEQUENCE_HEADER = 0x0f, @@ -117,6 +109,13 @@ typedef enum static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ); +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 *ParseIDU( decoder_t *p_dec, bool *pb_used_ts, block_t *p_frag ); + +static const uint8_t p_vc1_startcode[3] = { 0x00, 0x00, 0x01 }; /***************************************************************************** * Open: probe the packetizer and return score ***************************************************************************** @@ -137,12 +136,10 @@ static int Open( vlc_object_t *p_this ) es_format_Copy( &p_dec->fmt_out, &p_dec->fmt_in ); p_dec->p_sys = p_sys = malloc( sizeof( decoder_sys_t ) ); - p_sys->i_state = STATE_NOSYNC; - p_sys->bytestream = block_BytestreamInit(); - p_sys->p_startcode[0] = 0x00; - p_sys->p_startcode[1] = 0x00; - p_sys->p_startcode[2] = 0x01; - p_sys->i_offset = 0; + packetizer_Init( &p_sys->packetizer, + p_vc1_startcode, sizeof(p_vc1_startcode), + NULL, 0, + PacketizeReset, PacketizeParse, PacketizeValidate, p_dec ); p_sys->b_sequence_header = false; p_sys->sh.p_sh = NULL; @@ -155,7 +152,6 @@ static int Open( vlc_object_t *p_this ) p_sys->i_interpolated_dts = -1; - /* */ if( p_dec->fmt_out.i_extra > 0 ) { uint8_t *p_extra = p_dec->fmt_out.p_extra; @@ -192,7 +188,7 @@ 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; - block_BytestreamRelease( &p_sys->bytestream ); + packetizer_Clean( &p_sys->packetizer ); if( p_sys->p_frame ) block_Release( p_sys->p_frame ); free( p_sys ); @@ -201,112 +197,50 @@ static void Close( vlc_object_t *p_this ) /***************************************************************************** * Packetize: packetize an access unit *****************************************************************************/ -static block_t *ParseIDU( decoder_t *p_dec, bool *pb_used_ts, block_t *p_frag ); - 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; - - if( pp_block == NULL || *pp_block == NULL ) - return NULL; - if( (*pp_block)->i_flags&(BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) - { - if( (*pp_block)->i_flags&BLOCK_FLAG_CORRUPTED ) - { - p_sys->i_state = STATE_NOSYNC; - block_BytestreamEmpty( &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->b_frame = false; - } - p_sys->i_interpolated_dts = 0; - block_Release( *pp_block ); - return NULL; - } + return packetizer_Packetize( &p_sys->packetizer, pp_block ); +} - block_BytestreamPush( &p_sys->bytestream, *pp_block ); +static void PacketizeReset( void *p_private, bool b_broken ) +{ + decoder_t *p_dec = p_private; + decoder_sys_t *p_sys = p_dec->p_sys; - for( ;; ) + if( b_broken ) { - bool b_used_ts; - - switch( p_sys->i_state ) - { - - 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; - - 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 ) - return NULL; /* Need more data */ - - p_sys->i_offset = 4; /* 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 ) - return NULL; /* Need more data */ - - /* 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 = p_sys->bytestream.p_block->i_pts; - p_pic->i_dts = p_sys->bytestream.p_block->i_dts; - - block_GetBytes( &p_sys->bytestream, p_pic->p_buffer, p_pic->i_buffer ); - - p_sys->i_offset = 0; - - /* Parse and return complete frame */ - p_pic = ParseIDU( p_dec, &b_used_ts, p_pic ); - - /* Don't reuse the same timestamps several times */ - if( b_used_ts ) - { - p_sys->bytestream.p_block->i_pts = -1; - p_sys->bytestream.p_block->i_dts = -1; - } - - /* */ - if( !p_pic ) - { - p_sys->i_state = STATE_NOSYNC; - break; - } - /* */ - if( 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; - } + 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->b_frame = false; + } + p_sys->i_interpolated_dts = 0; +} +static block_t *PacketizeParse( void *p_private, bool *pb_ts_used, block_t *p_block ) +{ + decoder_t *p_dec = p_private; - /* So p_block doesn't get re-added several times */ - *pp_block = block_BytestreamPop( &p_sys->bytestream ); + return ParseIDU( p_dec, pb_ts_used, p_block ); +} - p_sys->i_state = STATE_NOSYNC; +static int PacketizeValidate( void *p_private, block_t *p_au ) +{ + decoder_t *p_dec = p_private; + decoder_sys_t *p_sys = p_dec->p_sys; - return p_pic; - } + if( p_sys->i_interpolated_dts < 0 ) + { + msg_Dbg( p_dec, "need a starting pts/dts" ); + return VLC_EGENERIC; } + VLC_UNUSED(p_au); + return VLC_SUCCESS; } + /* DecodeRIDU: decode the startcode emulation prevention (same than h264) */ static void DecodeRIDU( uint8_t *p_ret, int *pi_ret, uint8_t *src, int i_src ) {