X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Fcodec%2Fschroedinger.c;h=fceae03c05831d93d3468b1ca42fab86d7e08a88;hb=12ade3e3bc975d5426ba4af155b7372c31093b31;hp=5886988cefaf9e640600dc3057a5c35c55a1fbd5;hpb=c80284eddc1dd7005bfeb3a32782345fd57684c7;p=vlc diff --git a/modules/codec/schroedinger.c b/modules/codec/schroedinger.c index 5886988cef..fceae03c05 100644 --- a/modules/codec/schroedinger.c +++ b/modules/codec/schroedinger.c @@ -35,25 +35,38 @@ #include #include #include -#include #include /***************************************************************************** - * picture_pts_t : store pts alongside picture number, not carried through - * decoder + * Module descriptor + *****************************************************************************/ +static int OpenDecoder ( vlc_object_t * ); +static void CloseDecoder ( vlc_object_t * ); + +vlc_module_begin () + set_category( CAT_INPUT ) + set_subcategory( SUBCAT_INPUT_VCODEC ) + set_description( N_("Schroedinger video decoder") ) + set_capability( "decoder", 200 ) + set_callbacks( OpenDecoder, CloseDecoder ) + add_shortcut( "schroedinger" ) +vlc_module_end () + +/***************************************************************************** + * Local prototypes *****************************************************************************/ -struct picture_pts_t +static picture_t *DecodeBlock ( decoder_t *p_dec, block_t **pp_block ); + +struct picture_free_t { - int i_empty; //not in use - uint32_t u_pnum; //picture number from dirac header - mtime_t i_pts; //pts for this picture + picture_t *p_pic; + decoder_t *p_dec; }; /***************************************************************************** * decoder_sys_t : Schroedinger decoder descriptor *****************************************************************************/ -#define PTS_TLB_SIZE 16 struct decoder_sys_t { /* @@ -63,41 +76,8 @@ struct decoder_sys_t mtime_t i_frame_pts_delta; SchroDecoder *p_schro; SchroVideoFormat *p_format; - struct picture_pts_t pts_tlb[PTS_TLB_SIZE]; - int i_ts_resync_hack; }; -/***************************************************************************** - * Local prototypes - *****************************************************************************/ -static int OpenDecoder ( vlc_object_t * ); -static void CloseDecoder ( vlc_object_t * ); -static picture_t *DecodeBlock ( decoder_t *p_dec, block_t **pp_block ); - -/***************************************************************************** - * Module descriptor - *****************************************************************************/ - -vlc_module_begin(); - set_category( CAT_INPUT ); - set_subcategory( SUBCAT_INPUT_VCODEC ); - set_description( N_("Schroedinger video decoder") ); - set_capability( "decoder", 200 ); - set_callbacks( OpenDecoder, CloseDecoder ); - add_shortcut( "schroedinger" ); -vlc_module_end(); - -/***************************************************************************** - * 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; ipts_tlb[i].i_empty = 1; - } -} - /***************************************************************************** * OpenDecoder: probe the decoder and return score *****************************************************************************/ @@ -107,7 +87,7 @@ static int OpenDecoder( vlc_object_t *p_this ) decoder_sys_t *p_sys; SchroDecoder *p_schro; - if( p_dec->fmt_in.i_codec != VLC_FOURCC('d','r','a','c') ) + if( p_dec->fmt_in.i_codec != VLC_CODEC_DIRAC ) { return VLC_EGENERIC; } @@ -131,15 +111,12 @@ static int OpenDecoder( vlc_object_t *p_this ) p_dec->p_sys = p_sys; p_sys->p_schro = p_schro; p_sys->p_format = NULL; - p_sys->i_lastpts = -1; + p_sys->i_lastpts = VLC_TS_INVALID; p_sys->i_frame_pts_delta = 0; - p_sys->i_ts_resync_hack = 0; - - ResetPTStlb(p_dec); /* Set output properties */ p_dec->fmt_out.i_cat = VIDEO_ES; - p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','2','0'); + p_dec->fmt_out.i_codec = VLC_CODEC_I420; /* Set callbacks */ p_dec->pf_decode_video = DecodeBlock; @@ -153,7 +130,6 @@ static int OpenDecoder( vlc_object_t *p_this ) static void SetVideoFormat( decoder_t *p_dec ) { decoder_sys_t *p_sys = p_dec->p_sys; - double f_aspect; p_sys->p_format = schro_decoder_get_video_format(p_sys->p_schro); if( p_sys->p_format == NULL ) return; @@ -164,26 +140,25 @@ static void SetVideoFormat( decoder_t *p_dec ) switch( p_sys->p_format->chroma_format ) { - case SCHRO_CHROMA_420: p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','2','0'); break; - case SCHRO_CHROMA_422: p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','2','2'); break; - case SCHRO_CHROMA_444: p_dec->fmt_out.i_codec = VLC_FOURCC('I','4','4','4'); break; + case SCHRO_CHROMA_420: p_dec->fmt_out.i_codec = VLC_CODEC_I420; break; + case SCHRO_CHROMA_422: p_dec->fmt_out.i_codec = VLC_CODEC_I422; break; + case SCHRO_CHROMA_444: p_dec->fmt_out.i_codec = VLC_CODEC_I444; break; default: p_dec->fmt_out.i_codec = 0; break; } - p_dec->fmt_out.video.i_visible_width = + p_dec->fmt_out.video.i_visible_width = p_sys->p_format->clean_width; + p_dec->fmt_out.video.i_x_offset = p_sys->p_format->left_offset; p_dec->fmt_out.video.i_width = p_sys->p_format->width; - p_dec->fmt_out.video.i_visible_height = + p_dec->fmt_out.video.i_visible_height = p_sys->p_format->clean_height; + p_dec->fmt_out.video.i_y_offset = p_sys->p_format->top_offset; p_dec->fmt_out.video.i_height = p_sys->p_format->height; /* aspect_ratio_[numerator|denominator] describes the pixel aspect ratio */ - f_aspect = (double) - ( p_sys->p_format->aspect_ratio_numerator * p_sys->p_format->width ) / - ( p_sys->p_format->aspect_ratio_denominator * p_sys->p_format->height); - - p_dec->fmt_out.video.i_aspect = VOUT_ASPECT_FACTOR * f_aspect; + p_dec->fmt_out.video.i_sar_num = p_sys->p_format->aspect_ratio_numerator; + p_dec->fmt_out.video.i_sar_den = p_sys->p_format->aspect_ratio_denominator; p_dec->fmt_out.video.i_frame_rate = p_sys->p_format->frame_rate_numerator; @@ -191,53 +166,6 @@ static void SetVideoFormat( decoder_t *p_dec ) 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; - mtime_t i_pts; - - u_pnum = GetDWBE( p_block->p_buffer + i_pupos + 13 ); - i_pts = p_block->i_pts > 0 ? p_block->i_pts : p_block->i_dts; - - for( int i=0; ipts_tlb[i].i_empty ) { - - p_sys->pts_tlb[i].u_pnum = u_pnum; - p_sys->pts_tlb[i].i_pts = i_pts; - p_sys->pts_tlb[i].i_empty = 0; - - return; - } - } - - msg_Err( p_dec, "Could not store PTS %"PRId64" for picture %u", - 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; ipts_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 * When schro_decoder_reset() is called there will be pictures in the @@ -245,13 +173,13 @@ static mtime_t GetPicturePTS( decoder_t *p_dec, uint32_t u_pnum ) *****************************************************************************/ static void SchroFrameFree( SchroFrame *frame, void *priv) { - picture_t *p_pic = priv; + struct picture_free_t *p_free = priv; - if( !p_pic ) + if( !p_free ) return; - /* FIXME it is wrong, you should call pf_vout_buffer_del */ - if( p_pic->pf_release ) p_pic->pf_release( p_pic ); + decoder_DeletePicture( p_free->p_dec, p_free->p_pic ); + free(p_free); (void)frame; } @@ -263,11 +191,12 @@ static SchroFrame *CreateSchroFrameFromPic( decoder_t *p_dec ) decoder_sys_t *p_sys = p_dec->p_sys; SchroFrame *p_schroframe = schro_frame_new(); picture_t *p_pic = NULL; + struct picture_free_t *p_free; if( !p_schroframe ) return NULL; - p_pic = p_dec->pf_vout_buffer_new( p_dec ); + p_pic = decoder_NewPicture( p_dec ); if( !p_pic ) return NULL; @@ -284,7 +213,11 @@ static SchroFrame *CreateSchroFrameFromPic( decoder_t *p_dec ) p_schroframe->width = p_sys->p_format->width; p_schroframe->height = p_sys->p_format->height; - schro_frame_set_free_callback( p_schroframe, SchroFrameFree, p_pic ); + + p_free = malloc( sizeof( *p_free ) ); + p_free->p_pic = p_pic; + p_free->p_dec = p_dec; + schro_frame_set_free_callback( p_schroframe, SchroFrameFree, p_free ); for( int i=0; i<3; i++ ) { @@ -340,16 +273,8 @@ static void CloseDecoder( vlc_object_t *p_this ) /**************************************************************************** * DecodeBlock: the whole thing **************************************************************************** - * Blocks must start with a Dirac parse unit. - * Blocks must contain at least one Dirac parse unit. - * 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. + * Blocks need not be Dirac dataunit aligned. + * If a block has a PTS signaled, it applies to the first picture at or after p_block * * 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; @@ -359,131 +284,59 @@ static void CloseDecoder( vlc_object_t *p_this ) static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) { 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; if( !pp_block ) return NULL; - p_block = *pp_block; - - if ( p_block ) do { - /* prepare block for submission */ - - if (p_sys->i_ts_resync_hack && p_sys->i_ts_resync_hack--) - return NULL; - - if( !p_block->i_buffer ) { - msg_Err( p_dec, "block is of zero size" ); - break; - } + if ( *pp_block ) { + block_t *p_block = *pp_block; /* reset the decoder when seeking as the decode in progress is invalid */ /* discard the block as it is just a null magic block */ - if( p_block->i_flags & (BLOCK_FLAG_DISCONTINUITY|BLOCK_FLAG_CORRUPTED) ) { - msg_Dbg( p_dec, "SCHRO_DECODER_RESET" ); + if( p_block->i_flags & BLOCK_FLAG_DISCONTINUITY ) { schro_decoder_reset( p_sys->p_schro ); - ResetPTStlb( p_dec ); - - p_sys->i_lastpts = -1; - - /* The ts layer manages to corrupt the next packet we are to receive - * Since schro has no sync support, we need to drop it */ - p_sys->i_ts_resync_hack = 1; - + p_sys->i_lastpts = VLC_TS_INVALID; block_Release( p_block ); *pp_block = NULL; return NULL; } - /* Unsatisfactory, and will later be fixed in schro: - * - Schro can only handle a single Dirac parse unit at a time - * - Multiple parse units may exist in p_block - * - All mapping specs so far guarantee that p_block would - * not contain anything after a picture - * So, we can not give the whole block to schro, but piecemeal - */ - size_t i_bufused = 0; - while( schro_decoder_push_ready( p_sys->p_schro )) { - 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; + SchroBuffer *p_schrobuffer; + p_schrobuffer = schro_buffer_new_with_data( p_block->p_buffer, p_block->i_buffer ); + p_schrobuffer->free = SchroBufferFree; + p_schrobuffer->priv = p_block; + if( p_block->i_pts > VLC_TS_INVALID ) { + mtime_t *p_pts = malloc( sizeof(*p_pts) ); + if( p_pts ) { + *p_pts = p_block->i_pts; + /* if this call fails, p_pts is freed automatically */ + p_schrobuffer->tag = schro_tag_new( p_pts, free ); } - - 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; - - /* 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; - } - - msg_Dbg( p_dec, "Inserting bytes into decoder len=%zu of %zu pts=%"PRId64, - i_pulen, p_block->i_buffer, p_block->i_pts); - /* 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 ) { - msg_Dbg( p_dec, "SCHRO_DECODER_FIRST_ACCESS_UNIT"); - SetVideoFormat( p_dec ); - ResetPTStlb( p_dec ); - } - - 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 ) { - 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 ) { + case SCHRO_DECODER_FIRST_ACCESS_UNIT: + SetVideoFormat( p_dec ); + break; + case SCHRO_DECODER_NEED_BITS: - msg_Dbg( p_dec, "SCHRO_DECODER_NEED_BITS" ); return NULL; case SCHRO_DECODER_NEED_FRAME: - msg_Dbg( p_dec, "SCHRO_DECODER_NEED_FRAME" ); p_schroframe = CreateSchroFrameFromPic( p_dec ); if( !p_schroframe ) @@ -495,41 +348,48 @@ static picture_t *DecodeBlock( decoder_t *p_dec, block_t **pp_block ) schro_decoder_add_output_picture( p_sys->p_schro, p_schroframe); break; - case SCHRO_DECODER_OK: - u_pnum = schro_decoder_get_picture_number( p_sys->p_schro ); + case SCHRO_DECODER_OK: { + SchroTag *p_tag = schro_decoder_get_picture_tag( p_sys->p_schro ); p_schroframe = schro_decoder_pull( p_sys->p_schro ); - p_pic = p_schroframe->priv; + if( !p_schroframe || !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 ); + if( p_schroframe ) schro_frame_unref( p_schroframe ); + break; + } + p_pic = ((struct picture_free_t*) p_schroframe->priv)->p_pic; p_schroframe->priv = NULL; - schro_frame_unref( p_schroframe ); - /* solve presentation time stamp for picture. If this picture - * was not tagged with a pts when presented to decoder, interpolate - * one - * This means no need to set p_pic->b_force, as we have a pts on - * each picture */ - p_pic->date = GetPicturePTS( p_dec, u_pnum ); - if (p_sys->i_lastpts >= 0 && p_pic->date == 0) + if( p_tag ) + { + /* free is handled by schro_frame_unref */ + p_pic->date = *(mtime_t*) p_tag->value; + schro_tag_free( p_tag ); + } + else if( p_sys->i_lastpts > VLC_TS_INVALID ) + { + /* NB, this shouldn't happen since the packetizer does a + * very thorough job of inventing timestamps. The + * following is just a very rough fall back incase packetizer + * is missing. */ + /* maybe it would be better to set p_pic->b_force ? */ p_pic->date = p_sys->i_lastpts + p_sys->i_frame_pts_delta; + } p_sys->i_lastpts = p_pic->date; - msg_Dbg( p_dec, "SCHRO_DECODER_OK num=%u date=%"PRId64, - u_pnum, p_pic->date); - + schro_frame_unref( p_schroframe ); return p_pic; - + } case SCHRO_DECODER_EOS: - msg_Dbg( p_dec, "SCHRO_DECODER_EOS"); - /* 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 ); + /* NB, the new api will not emit _EOS, it handles the reset internally */ break; case SCHRO_DECODER_ERROR: - msg_Dbg( p_dec, "SCHRO_DECODER_ERROR"); + msg_Err( p_dec, "SCHRO_DECODER_ERROR"); return NULL; } } - - /* Never reached */ - return NULL; } +