/*****************************************************************************
* dirac.c
*****************************************************************************
- * Copyright (C) 2008 the VideoLAN team
+ * Copyright (C) 2008 VLC authors and VideoLAN
* $Id$
*
* Authors: David Flynn <davidf@rd.bbc.co.uk>
*
- * 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.
* 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).
*/
#include <vlc_codec.h>
#include <vlc_block.h>
-#include "vlc_bits.h"
-#include "vlc_block_helper.h"
+#include <vlc_bits.h>
+#include <vlc_block_helper.h>
#define SANITIZE_PREV_PARSE_OFFSET 1
* 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 */
} 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 */
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 )
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;
}
/***
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++ )
{
/**
* 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 )
{
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;
}
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 */
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 );
p_block->i_flags = DIRAC_NON_DATED;
- return p_block;
-
(void) p_dec;
+ return p_block;
}
/***
{
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 */
/* 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;
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;
*/
* - 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 )
{
*
* 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 )
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 )
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 );
}
/*****************************************************************************
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 */
}
}
}
/* 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 );
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) )
dirac_ReorderInit( &p_sys->reorder_buf );
assert( p_sys->p_outqueue == NULL );
- p_sys->p_out_dts = NULL;
}
/* perform sanity check:
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;
}
}
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;
/* 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