X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fpacketizer%2Fdirac.c;h=71b0b11a129601debc73663c68fe9bec88f6993f;hb=020a4deab04ea3bad7dca3cb4296197f05d04c0d;hp=39c48185a60dbddfd43e1fd153157a44e95687a3;hpb=c5c06b64c806052086e5772d64e540a8db7e4a9b;p=vlc diff --git a/modules/packetizer/dirac.c b/modules/packetizer/dirac.c index 39c48185a6..71b0b11a12 100644 --- a/modules/packetizer/dirac.c +++ b/modules/packetizer/dirac.c @@ -1,29 +1,29 @@ /***************************************************************************** * dirac.c ***************************************************************************** - * Copyright (C) 2008 the VideoLAN team + * Copyright (C) 2008 VLC authors and VideoLAN * $Id$ * * Authors: David Flynn * - * 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 + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2 of the License * (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. + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser 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. + * You should have received a copy of the GNU Lesser 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. *****************************************************************************/ /* Dirac packetizer, formed of three parts: * 1) Bitstream synchroniser (dirac_DoSync) - * - Given an arbitary sequence of bytes, extract whole Dirac Data Units + * - Given an arbitrary sequence of bytes, extract whole Dirac Data Units * - Maps timestamps in supplied block_t's to the extracted Data Unit * A time stamp applies to the next Data Unit to commence at, or after * the first byte of the block_t with the timestamp. @@ -51,7 +51,7 @@ * distinguish from the fake dts case.) * * DIRAC_NON_DATED is used to show a block should not have a time stamp - * associated (ie, don't interpolate a counter). At the ouput, these + * associated (ie, don't interpolate a counter). At the output, these * blocks get dated with the last used timestamp (or are merged with * another encapsulation unit). */ @@ -70,8 +70,8 @@ #include #include -#include "vlc_bits.h" -#include "vlc_block_helper.h" +#include +#include #define SANITIZE_PREV_PARSE_OFFSET 1 @@ -128,9 +128,6 @@ struct decoder_sys_t * completed encapsulation units from the front */ block_t *p_outqueue; block_t **pp_outqueue_last; - /* p_out_dts points to an element in p_outqueue. It is used for VLC's - * fake pts hidden in DTS hack, as used by AVI */ - block_t *p_out_dts; uint32_t u_tg_last_picnum; /*< most recent picturenumber output from RoB */ bool b_tg_last_picnum; /*< u_tg_last_picnum valid */ @@ -170,7 +167,6 @@ typedef struct { } parse_info_t; typedef struct { - block_free_t pf_blk_release; /*> next_parse_offset of the final data unit in associated block_t */ uint32_t u_last_next_offset; /*> picture number is invalid if block has flags DIRAC_NON_DATED */ @@ -216,38 +212,44 @@ enum { typedef struct { block_t fake; block_t *p_orig; - void *p_priv; + dirac_block_encap_t *p_dbe; } fake_block_t; static dirac_block_encap_t *dirac_RemoveBlockEncap( block_t *p_block ) { fake_block_t *p_fake = (fake_block_t *)p_block; - dirac_block_encap_t *p_dbe = p_fake->p_priv; - if( !p_dbe ) return NULL; - p_fake->p_priv = NULL; - p_dbe->pf_blk_release = NULL; + dirac_block_encap_t *p_dbe = p_fake->p_dbe; + + p_fake->p_dbe = NULL; return p_dbe; } static void dirac_ReleaseBlockAndEncap( block_t *p_block ) { fake_block_t *p_fake = (fake_block_t *)p_block; + free( dirac_RemoveBlockEncap( p_block ) ); - p_fake->p_orig->pf_release( p_fake->p_orig ); + block_Release( p_fake->p_orig ); free( p_fake ); } static void dirac_AddBlockEncap( block_t **pp_block, dirac_block_encap_t *p_dbe ) { - fake_block_t *p_fake = calloc( 1, sizeof( *p_fake ) ); - assert( p_fake ); /* must not fail, fixby: adding a p_priv to block_t */ - p_fake->p_orig = *pp_block; - memcpy( &p_fake->fake, *pp_block, sizeof( block_t ) ); - *pp_block = &p_fake->fake; - - p_fake->p_priv = p_dbe; - p_dbe->pf_blk_release = p_fake->p_orig->pf_release; - p_fake->fake.pf_release = dirac_ReleaseBlockAndEncap; + /* must not fail, fixby: adding a p_priv to block_t */ + fake_block_t *p_fake = xcalloc( 1, sizeof( *p_fake ) ); + block_t *in = *pp_block, *out = &p_fake->fake; + + block_Init( out, in->p_buffer, in->i_buffer ); + out->i_flags = in->i_flags; + out->i_nb_samples = in->i_nb_samples; + out->i_pts = in->i_pts; + out->i_dts = in->i_dts; + out->i_length = in->i_length; + out->pf_release = dirac_ReleaseBlockAndEncap; + p_fake->p_orig = in; + p_fake->p_dbe = p_dbe; + + *pp_block = out; } static dirac_block_encap_t *dirac_NewBlockEncap( block_t **pp_block ) @@ -259,7 +261,7 @@ static dirac_block_encap_t *dirac_NewBlockEncap( block_t **pp_block ) static dirac_block_encap_t *dirac_GetBlockEncap( block_t *p_block ) { - return (dirac_block_encap_t*) ((fake_block_t *)p_block)->p_priv; + return ((fake_block_t *)p_block)->p_dbe; } /*** @@ -279,7 +281,7 @@ static int block_ChainToArray( block_t *p_block, block_t ***ppp_array) block_ChainProperties( p_block, &i_num_blocks, NULL, NULL ); *ppp_array = calloc( i_num_blocks, sizeof( block_t* ) ); - if( !ppp_array ) return 0; + if( !*ppp_array ) return 0; for( int i = 0; i < i_num_blocks; i++ ) { @@ -292,7 +294,7 @@ static int block_ChainToArray( block_t *p_block, block_t ***ppp_array) /** * Destructively find and recover the earliest timestamp from start of - * bytestream, upto i_length. + * bytestream, up to i_length. */ static void dirac_RecoverTimestamps ( decoder_t *p_dec, size_t i_length ) { @@ -515,7 +517,7 @@ static bool dirac_UnpackSeqHdr( struct seq_hdr_t *p_sh, block_t *p_block ) uint32_t u_video_format = dirac_uint( &bs ); /* index */ if( u_video_format > 20 ) { - /* dont know how to parse this header */ + /* don't know how to parse this header */ return false; } @@ -566,13 +568,13 @@ static bool dirac_UnpackSeqHdr( struct seq_hdr_t *p_sh, block_t *p_block ) if( dirac_bool( &bs ) ) { uint32_t frame_rate_index = dirac_uint( &bs ); - p_sh->u_fps_num = dirac_frate_tbl[frame_rate_index].u_n; - p_sh->u_fps_den = dirac_frate_tbl[frame_rate_index].u_d; if( frame_rate_index >= dirac_frate_tbl_size ) { /* invalid header */ return false; } + p_sh->u_fps_num = dirac_frate_tbl[frame_rate_index].u_n; + p_sh->u_fps_den = dirac_frate_tbl[frame_rate_index].u_d; if( frame_rate_index == 0 ) { p_sh->u_fps_num = dirac_uint( &bs ); /* frame_rate_numerator */ @@ -646,7 +648,7 @@ static bool dirac_UnpackSeqHdr( struct seq_hdr_t *p_sh, block_t *p_block ) static block_t *dirac_EmitEOS( decoder_t *p_dec, uint32_t i_prev_parse_offset ) { const uint8_t p_eos[] = { 'B','B','C','D',0x10,0,0,0,13,0,0,0,0 }; - block_t *p_block = block_New( p_dec, 13 ); + block_t *p_block = block_Alloc( 13 ); if( !p_block ) return NULL; memcpy( p_block->p_buffer, p_eos, 13 ); @@ -655,9 +657,8 @@ static block_t *dirac_EmitEOS( decoder_t *p_dec, uint32_t i_prev_parse_offset ) p_block->i_flags = DIRAC_NON_DATED; - return p_block; - (void) p_dec; + return p_block; } /*** @@ -730,7 +731,7 @@ static block_t *dirac_DoSync( decoder_t *p_dec ) { return NULL; /* retry later */ } - /* attempt to syncronise backwards from pu.u_next_offset */ + /* attempt to synchronise backwards from pu.u_next_offset */ p_sys->i_offset = pu.u_next_offset; /* fall through */ case TRY_SYNC: /* -> SYNCED | NOT_SYNCED */ @@ -786,13 +787,13 @@ sync_fail: /* recover any timestamps from the data that is about to be flushed */ dirac_RecoverTimestamps( p_dec, p_sys->i_offset ); - /* flush everything upto the start of the DU */ + /* flush everything up to the start of the DU */ block_SkipBytes( &p_sys->bytestream, p_sys->i_offset ); block_BytestreamFlush( &p_sys->bytestream ); p_sys->i_offset = 0; /* setup the data unit buffer */ - block_t *p_block = block_New( p_dec, pu.u_next_offset ); + block_t *p_block = block_Alloc( pu.u_next_offset ); if( !p_block ) return NULL; @@ -846,7 +847,7 @@ static int dirac_InspectDataUnit( decoder_t *p_dec, block_t **pp_block, block_t Actually, this is a bad idea: - It sets the discontinuity for every dirac EOS packet which doesnt imply a time discontinuity. - - When the syncronizer detects a real discontinuity, it + - When the synchronizer detects a real discontinuity, it should copy the flags through. p_eu->i_flags |= BLOCK_FLAG_DISCONTINUITY; */ @@ -922,8 +923,7 @@ static int dirac_InspectDataUnit( decoder_t *p_dec, block_t **pp_block, block_t * - required for ogg muxing * - useful for error checking * - it isn't allowed to change until an eos */ - if( p_es->p_extra ) - free( p_es->p_extra ); + free( p_es->p_extra ); p_es->p_extra = calloc( 1, p_block->i_buffer + 13 ); if( !p_es->p_extra ) { @@ -1034,7 +1034,7 @@ static block_t *dirac_BuildEncapsulationUnit( decoder_t *p_dec, block_t *p_block * * Returns: * 0: everything ok - * 1: EOS occured, please flush and reset + * 1: EOS occurred, please flush and reset * 2: picture number discontinuity, please flush and reset */ static int dirac_TimeGenPush( decoder_t *p_dec, block_t *p_block_in ) @@ -1140,9 +1140,6 @@ static int dirac_TimeGenPush( decoder_t *p_dec, block_t *p_block_in ) if( p_sys->b_dts == p_sys->b_pts ) return 0; - if( !p_sys->p_out_dts ) - p_sys->p_out_dts = p_sys->p_outqueue; - /* model the reorder buffer */ block_t *p_block = dirac_Reorder( p_dec, p_block_in, u_picnum ); if( !p_block ) @@ -1179,25 +1176,35 @@ static int dirac_TimeGenPush( decoder_t *p_dec, block_t *p_block_in ) p_sys->b_tg_last_picnum = true; p_sys->u_tg_last_picnum = u_picnum; - if( !p_sys->b_pts ) + return 0; +} + + +static void dirac_ReorderDequeueAndReleaseBlock( decoder_t *p_dec, block_t *p_block ) +{ + decoder_sys_t *p_sys = p_dec->p_sys; + /* Check if that block is present in reorder queue and release it + if needed */ + struct dirac_reorder_entry **pp_at = &p_sys->reorder_buf.p_head; + for( ; *pp_at; pp_at = &(*pp_at)->p_next ) { - /* some demuxers (eg, AVI) will provide a series of fake dts values, - * which are actually inorder pts values (ie, what should be seen at - * the output of a decoder. A main reason for simulating the reorder - * buffer is to turn the inorder fakedts into an out-of-order pts */ - p_block->i_pts = p_sys->p_out_dts->i_dts; - p_sys->p_out_dts->i_dts = VLC_TS_INVALID; - } + /* backup address in case we remove member */ + struct dirac_reorder_entry *p_entry = *pp_at; + if ( p_entry->p_eu == p_block ) + { + /* unlink member */ + *pp_at = (*pp_at)->p_next; - /* If pts was copied from dts, the dts needs to be corrected to account for reordering*/ - /* If dts has never been seen, the same needs to happen */ - p_sys->p_out_dts->i_dts = p_block->i_pts - p_sys->i_pts_offset; + /* Add to empty reorder entry list*/ + p_entry->p_next = p_sys->reorder_buf.p_empty; + p_sys->reorder_buf.p_empty = p_entry; - /* move dts pointer */ - if( p_sys->p_out_dts ) - p_sys->p_out_dts = p_sys->p_out_dts->p_next; + p_sys->reorder_buf.u_size--; + break; + } + } - return 0; + block_Release( p_block ); } /***************************************************************************** @@ -1223,7 +1230,7 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) if( p_block ) { p_block->p_next = dirac_EmitEOS( p_dec, 13 ); - /* need two EOS to ensure it gets detected by syncro + /* need two EOS to ensure it gets detected by synchro * duplicates get discarded in forming encapsulation unit */ } } @@ -1241,7 +1248,7 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) } /* form as many encapsulation units as possible, give up - * when the syncronizer runs out of input data */ + * when the synchronizer runs out of input data */ while( ( p_block = dirac_DoSync( p_dec ) ) ) { p_block = dirac_BuildEncapsulationUnit( p_dec, p_block ); @@ -1259,7 +1266,7 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) block_t *p_output = NULL; block_t **pp_output = &p_output; - /* extract all the dated packets from the head of the ouput queue */ + /* extract all the dated packets from the head of the output queue */ /* explicitly nondated packets repeat the previous timestamps to * stop vlc discarding them */ while( (p_block = p_sys->p_outqueue) ) @@ -1310,7 +1317,6 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) dirac_ReorderInit( &p_sys->reorder_buf ); assert( p_sys->p_outqueue == NULL ); - p_sys->p_out_dts = NULL; } /* perform sanity check: @@ -1329,7 +1335,7 @@ static block_t *Packetize( decoder_t *p_dec, block_t **pp_block ) block_t *p_block_next = p_block->p_next; if( p_block->i_pts > VLC_TS_INVALID && p_block->i_dts > VLC_TS_INVALID ) break; - block_Release( p_block ); + dirac_ReorderDequeueAndReleaseBlock( p_dec, p_block ); p_sys->p_outqueue = p_block = p_block_next; } } @@ -1366,7 +1372,7 @@ static int Open( vlc_object_t *p_this ) p_sys->i_dts_last_out = p_sys->i_pts_last_out = VLC_TS_INVALID; p_sys->i_state = NOT_SYNCED; - p_sys->bytestream = block_BytestreamInit(); + block_BytestreamInit( &p_sys->bytestream ); p_sys->pp_outqueue_last = &p_sys->p_outqueue; p_sys->pp_eu_last = &p_sys->p_eu; @@ -1379,7 +1385,7 @@ static int Open( vlc_object_t *p_this ) /* handle hacky systems like ogg that dump some headers * in p_extra. and packetizers that expect it to be filled * in before real startup */ - block_t *p_init = block_New( p_dec, p_dec->fmt_in.i_extra ); + block_t *p_init = block_Alloc( p_dec->fmt_in.i_extra ); if( !p_init ) { /* memory might be avaliable soon. it isn't the end of