Commit 7c229f88 authored by David Flynn's avatar David Flynn Committed by Jean-Baptiste Kempf

codec/schroedinger: Use new autoparse+tagging api

Schroedinger now has an api that allows passing in arbitarily aligned
data units (ie, whole encapsuation units), use this rather than attempt
to chunk up the bitstream ourselves.

This new api also enables buffer tagging, where buffers may be tagged
with arbitary data that gets associated with the next picture to
commence at or after the start of the buffer.  This removes the need
for the TLBs and associated accounting.
Signed-off-by: default avatarDavid Flynn <davidf@rd.bbc.co.uk>
Signed-off-by: default avatarJean-Baptiste Kempf <jb@videolan.org>
parent 9c75ce1c
...@@ -59,17 +59,6 @@ vlc_module_end () ...@@ -59,17 +59,6 @@ vlc_module_end ()
*****************************************************************************/ *****************************************************************************/
static picture_t *DecodeBlock ( decoder_t *p_dec, block_t **pp_block ); static picture_t *DecodeBlock ( decoder_t *p_dec, block_t **pp_block );
/*****************************************************************************
* picture_pts_t : store pts alongside picture number, not carried through
* decoder
*****************************************************************************/
struct picture_pts_t
{
int i_empty; //not in use
uint32_t u_pnum; //picture number from dirac header
mtime_t i_pts; //pts for this picture
};
struct picture_free_t struct picture_free_t
{ {
picture_t *p_pic; picture_t *p_pic;
...@@ -79,7 +68,6 @@ struct picture_free_t ...@@ -79,7 +68,6 @@ struct picture_free_t
/***************************************************************************** /*****************************************************************************
* decoder_sys_t : Schroedinger decoder descriptor * decoder_sys_t : Schroedinger decoder descriptor
*****************************************************************************/ *****************************************************************************/
#define PTS_TLB_SIZE 16
struct decoder_sys_t struct decoder_sys_t
{ {
/* /*
...@@ -89,22 +77,10 @@ struct decoder_sys_t ...@@ -89,22 +77,10 @@ struct decoder_sys_t
mtime_t i_frame_pts_delta; mtime_t i_frame_pts_delta;
SchroDecoder *p_schro; SchroDecoder *p_schro;
SchroVideoFormat *p_format; SchroVideoFormat *p_format;
struct picture_pts_t pts_tlb[PTS_TLB_SIZE];
}; };
//#define TRACE //#define TRACE
/*****************************************************************************
* ResetPTStlb: Purge all entries in @p_dec@'s PTS-tlb
*****************************************************************************/
static void ResetPTStlb( decoder_t *p_dec )
{
decoder_sys_t *p_sys = p_dec->p_sys;
for( int i=0; i<PTS_TLB_SIZE; i++) {
p_sys->pts_tlb[i].i_empty = 1;
}
}
/***************************************************************************** /*****************************************************************************
* OpenDecoder: probe the decoder and return score * OpenDecoder: probe the decoder and return score
*****************************************************************************/ *****************************************************************************/
...@@ -141,8 +117,6 @@ static int OpenDecoder( vlc_object_t *p_this ) ...@@ -141,8 +117,6 @@ static int OpenDecoder( vlc_object_t *p_this )
p_sys->i_lastpts = -1; p_sys->i_lastpts = -1;
p_sys->i_frame_pts_delta = 0; p_sys->i_frame_pts_delta = 0;
ResetPTStlb(p_dec);
/* request packetizer */ /* request packetizer */
p_dec->b_need_packetized = true; p_dec->b_need_packetized = true;
...@@ -200,51 +174,6 @@ static void SetVideoFormat( decoder_t *p_dec ) ...@@ -200,51 +174,6 @@ static void SetVideoFormat( decoder_t *p_dec )
p_sys->p_format->frame_rate_denominator; p_sys->p_format->frame_rate_denominator;
} }
/*****************************************************************************
* StorePicturePTS: Store the PTS value for a particular picture number
*****************************************************************************/
static void StorePicturePTS( decoder_t *p_dec, block_t *p_block, int i_pupos )
{
decoder_sys_t *p_sys = p_dec->p_sys;
uint32_t u_pnum;
u_pnum = GetDWBE( p_block->p_buffer + i_pupos + 13 );
for( int i=0; i<PTS_TLB_SIZE; i++ ) {
if( p_sys->pts_tlb[i].i_empty ) {
p_sys->pts_tlb[i].u_pnum = u_pnum;
p_sys->pts_tlb[i].i_pts = p_block->i_pts;
p_sys->pts_tlb[i].i_empty = 0;
return;
}
}
msg_Err( p_dec, "Could not store PTS %"PRId64" for picture %u",
p_block->i_pts, u_pnum );
}
/*****************************************************************************
* GetPicturePTS: Retrieve the PTS value for a particular picture number
*****************************************************************************/
static mtime_t GetPicturePTS( decoder_t *p_dec, uint32_t u_pnum )
{
decoder_sys_t *p_sys = p_dec->p_sys;
for( int i=0; i<PTS_TLB_SIZE; i++ ) {
if( (!p_sys->pts_tlb[i].i_empty) &&
(p_sys->pts_tlb[i].u_pnum == u_pnum)) {
p_sys->pts_tlb[i].i_empty = 1;
return p_sys->pts_tlb[i].i_pts;
}
}
msg_Err( p_dec, "Could not retrieve PTS for picture %u", u_pnum );
return 0;
}
/***************************************************************************** /*****************************************************************************
* SchroFrameFree: schro_frame callback to release the associated picture_t * SchroFrameFree: schro_frame callback to release the associated picture_t
* When schro_decoder_reset() is called there will be pictures in the * When schro_decoder_reset() is called there will be pictures in the
...@@ -352,16 +281,8 @@ static void CloseDecoder( vlc_object_t *p_this ) ...@@ -352,16 +281,8 @@ static void CloseDecoder( vlc_object_t *p_this )
/**************************************************************************** /****************************************************************************
* DecodeBlock: the whole thing * DecodeBlock: the whole thing
**************************************************************************** ****************************************************************************
* Blocks must start with a Dirac parse unit. * Blocks need not be Dirac dataunit aligned.
* Blocks must contain at least one Dirac parse unit. * If a block has a PTS signaled, it applies to the first picture at or after p_block
* Blocks must end with a picture parse unit.
* Blocks must not contain more than one picture parse unit.
* If a block has a PTS signaled, it applies to the first picture in p_block
* - Schroedinger has no internal means to tag pictures with a PTS
* - In this case, the picture number is extracted and stored in a TLB
* When a picture is extracted from schro, it is looked up in the pts_tlb
* - If the picture was never tagged with a PTS, a new one is calculated
* based upon the frame rate and last output PTS.
* *
* If this function returns a picture (!NULL), it is called again and the * If this function returns a picture (!NULL), it is called again and the
* same block is resubmitted. To avoid this, set *pp_block to NULL; * same block is resubmitted. To avoid this, set *pp_block to NULL;
...@@ -371,24 +292,12 @@ static void CloseDecoder( vlc_object_t *p_this ) ...@@ -371,24 +292,12 @@ static void CloseDecoder( vlc_object_t *p_this )
static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) static picture_t *DecodeBlock( 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;
int state;
SchroBuffer *p_schrobuffer;
SchroFrame *p_schroframe;
picture_t *p_pic;
block_t *p_block;
uint32_t u_pnum; uint32_t u_pnum;
if( !pp_block ) return NULL; if( !pp_block ) return NULL;
p_block = *pp_block; if ( *pp_block ) {
block_t *p_block = *pp_block;
if ( p_block ) do {
/* prepare block for submission */
if( !p_block->i_buffer ) {
msg_Err( p_dec, "block is of zero size" );
break;
}
/* reset the decoder when seeking as the decode in progress is invalid */ /* reset the decoder when seeking as the decode in progress is invalid */
/* discard the block as it is just a null magic block */ /* discard the block as it is just a null magic block */
...@@ -398,8 +307,6 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) ...@@ -398,8 +307,6 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
#endif #endif
schro_decoder_reset( p_sys->p_schro ); schro_decoder_reset( p_sys->p_schro );
ResetPTStlb( p_dec );
p_sys->i_lastpts = -1; p_sys->i_lastpts = -1;
block_Release( p_block ); block_Release( p_block );
...@@ -407,97 +314,36 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) ...@@ -407,97 +314,36 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
return NULL; return NULL;
} }
/* Unsatisfactory, and will later be fixed in schro: SchroBuffer *p_schrobuffer;
* - Schro can only handle a single Dirac parse unit at a time p_schrobuffer = schro_buffer_new_with_data( p_block->p_buffer, p_block->i_buffer );
* - Multiple parse units may exist in p_block p_schrobuffer->free = SchroBufferFree;
* - All mapping specs so far guarantee that p_block would p_schrobuffer->priv = p_block;
* not contain anything after a picture mtime_t *p_pts = malloc( sizeof(*p_pts) );
* So, we can not give the whole block to schro, but piecemeal if( p_pts ) {
*/ *p_pts = p_block->i_pts;
size_t i_bufused = 0; /* if this call fails, p_pts is freed automatically */
while( schro_decoder_push_ready( p_sys->p_schro )) { p_schrobuffer->tag = schro_tag_new( p_pts, free );
if( p_block->i_buffer - i_bufused < 13 ) {
*pp_block = NULL;
block_Release( p_block );
msg_Err( p_dec, "not enough data left in block" );
break;
}
int b_bail = 0;
size_t i_pulen = GetDWBE( p_block->p_buffer + i_bufused + 5 );
uint8_t *p_pu = p_block->p_buffer + i_bufused;
if( 0 == i_pulen ) {
i_pulen = 13;
}
/* blocks that do not start with the parse info prefix are invalid */
if( p_pu[0] != 'B' || p_pu[1] != 'B' ||
p_pu[2] != 'C' || p_pu[3] != 'D')
{
*pp_block = NULL;
block_Release( p_block );
msg_Err( p_dec, "block does not start with dirac parse code" );
break;
}
if( i_bufused + i_pulen > p_block->i_buffer ) {
*pp_block = NULL;
block_Release( p_block );
break;
}
if( p_pu[4] & 0x08 )
StorePicturePTS( p_dec, p_block, i_bufused );
p_schrobuffer = schro_buffer_new_with_data( p_pu, i_pulen );
if( i_pulen + i_bufused < p_block->i_buffer ) {
/* don't let schro free this block, more data still in it */
p_schrobuffer->free = 0;
}
else {
p_schrobuffer->free = SchroBufferFree;
p_schrobuffer->priv = p_block;
b_bail = 1;
}
#ifdef TRACE
msg_Dbg( p_dec, "Inserting bytes into decoder len=%zu of %zu pts=%"PRId64,
i_pulen, p_block->i_buffer, p_block->i_pts);
#endif
/* this stops the same block being fed back into this function if
* we were on the next iteration of this loop to output a picture */
*pp_block = NULL;
state = schro_decoder_push( p_sys->p_schro, p_schrobuffer );
/* DO NOT refer to p_block after this point, it may have been freed */
i_bufused += i_pulen;
if( state == SCHRO_DECODER_FIRST_ACCESS_UNIT ) {
#ifdef TRACE
msg_Dbg( p_dec, "SCHRO_DECODER_FIRST_ACCESS_UNIT");
#endif
SetVideoFormat( p_dec );
ResetPTStlb( p_dec );
p_schroframe = CreateSchroFrameFromPic( p_dec );
if( p_schroframe ) {
schro_decoder_add_output_picture( p_sys->p_schro, p_schroframe);
}
}
if( b_bail )
break;
} }
} while( 0 );
/* this stops the same block being fed back into this function if
* we were on the next iteration of this loop to output a picture */
*pp_block = NULL;
schro_decoder_autoparse_push( p_sys->p_schro, p_schrobuffer );
/* DO NOT refer to p_block after this point, it may have been freed */
}
while( 1 ) while( 1 )
{ {
state = schro_decoder_wait( p_sys->p_schro ); SchroFrame *p_schroframe;
picture_t *p_pic;
int state = schro_decoder_autoparse_wait( p_sys->p_schro );
switch( state ) switch( state )
{ {
case SCHRO_DECODER_FIRST_ACCESS_UNIT:
SetVideoFormat( p_dec );
break;
case SCHRO_DECODER_NEED_BITS: case SCHRO_DECODER_NEED_BITS:
#ifdef TRACE #ifdef TRACE
msg_Dbg( p_dec, "SCHRO_DECODER_NEED_BITS" ); msg_Dbg( p_dec, "SCHRO_DECODER_NEED_BITS" );
...@@ -519,41 +365,53 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) ...@@ -519,41 +365,53 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
schro_decoder_add_output_picture( p_sys->p_schro, p_schroframe); schro_decoder_add_output_picture( p_sys->p_schro, p_schroframe);
break; break;
case SCHRO_DECODER_OK: case SCHRO_DECODER_OK: {
SchroTag *p_tag = schro_decoder_get_picture_tag( p_sys->p_schro );
u_pnum = schro_decoder_get_picture_number( p_sys->p_schro ); u_pnum = schro_decoder_get_picture_number( p_sys->p_schro );
p_schroframe = schro_decoder_pull( p_sys->p_schro ); p_schroframe = schro_decoder_pull( p_sys->p_schro );
if( !p_schroframe->priv ) if( !p_schroframe->priv )
{ {
/* frame can't be one that was allocated by us
* -- no private data: discard */
if( p_tag ) schro_tag_free( p_tag );
schro_frame_unref( p_schroframe ); schro_frame_unref( p_schroframe );
break; break;
} }
p_pic = ((struct picture_free_t*) p_schroframe->priv)->p_pic; p_pic = ((struct picture_free_t*) p_schroframe->priv)->p_pic;
p_schroframe->priv = NULL; p_schroframe->priv = NULL;
schro_frame_unref( p_schroframe );
/* solve presentation time stamp for picture. If this picture /* solve presentation time stamp for picture. If this picture
* was not tagged with a pts when presented to decoder, interpolate * was not tagged with a pts when presented to decoder, interpolate
* one * one
* This means no need to set p_pic->b_force, as we have a pts on * This means no need to set p_pic->b_force, as we have a pts on
* each picture */ * each picture */
p_pic->date = GetPicturePTS( p_dec, u_pnum ); if( p_tag )
if (p_sys->i_lastpts >= 0 && p_pic->date == 0) {
/* free is handled by schro_frame_unref */
p_pic->date = *(mtime_t*) p_tag->value;
schro_tag_free( p_tag );
msg_Err(p_dec, "pts out: %"PRId64, p_pic->date);
}
else if( p_sys->i_lastpts >= 0 )
{
p_pic->date = p_sys->i_lastpts + p_sys->i_frame_pts_delta; p_pic->date = p_sys->i_lastpts + p_sys->i_frame_pts_delta;
/* fixme */
msg_Err(p_dec, "no pts");
}
p_sys->i_lastpts = p_pic->date; p_sys->i_lastpts = p_pic->date;
schro_frame_unref( p_schroframe );
#ifdef TRACE #ifdef TRACE
msg_Dbg( p_dec, "SCHRO_DECODER_OK num=%u date=%"PRId64, msg_Dbg( p_dec, "SCHRO_DECODER_OK num=%u date=%"PRId64,
u_pnum, p_pic->date); u_pnum, p_pic->date);
#endif #endif
return p_pic; return p_pic;
}
case SCHRO_DECODER_EOS: case SCHRO_DECODER_EOS:
/* NB, the new api will not emit _EOS, it handles the reset internally */
#ifdef TRACE #ifdef TRACE
msg_Dbg( p_dec, "SCHRO_DECODER_EOS"); msg_Dbg( p_dec, "SCHRO_DECODER_EOS");
#endif #endif
/* reset the decoder -- schro doesn't do this itself automatically */
/* there are no more pictures in the output buffer at this point */
schro_decoder_reset( p_sys->p_schro );
break; break;
case SCHRO_DECODER_ERROR: case SCHRO_DECODER_ERROR:
......
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