[vlc-devel] [PATCH] codec: avcodec: adapt code to new API

Thomas Guillem thomas at gllm.fr
Tue Oct 11 09:51:59 CEST 2016


By the way, it seems that avcodec audio is still no drained (pp_block ==
NULL).

On Mon, Oct 10, 2016, at 23:38, Francois Cartegnie wrote:
> adapting to the new API requires more than local
> patches.
> 
> The block is always passed in full, and we can
> expect more than a single frame when push returns
> EAGAIN.
> Requires then more interpolation for timestamps before
> using next input packet pts.
> Should also be correct when dequeing end of stream.
> ---
>  modules/codec/avcodec/audio.c | 181
>  +++++++++++++++++++++++-------------------
>  1 file changed, 98 insertions(+), 83 deletions(-)
> 
> diff --git a/modules/codec/avcodec/audio.c
> b/modules/codec/avcodec/audio.c
> index a0d5c03..bf4b1ae 100644
> --- a/modules/codec/avcodec/audio.c
> +++ b/modules/codec/avcodec/audio.c
> @@ -70,6 +70,7 @@ struct decoder_sys_t
>  #define BLOCK_FLAG_PRIVATE_REALLOCATED (1 << BLOCK_FLAG_PRIVATE_SHIFT)
>  
>  static void SetupOutputFormat( decoder_t *p_dec, bool b_trust );
> +static block_t * ConvertAVFrame( decoder_t *p_dec, AVFrame *frame );
>  static block_t *DecodeAudio( decoder_t *, block_t ** );
>  static void Flush( decoder_t * );
>  
> @@ -309,130 +310,144 @@ static block_t *DecodeAudio( decoder_t *p_dec,
> block_t **pp_block )
>          p_block->i_flags |= BLOCK_FLAG_PRIVATE_REALLOCATED;
>      }
>  
> +    block_t *p_decoded = NULL;
> +    block_t **pp_decoded_last = &p_decoded;
> +
>      frame = av_frame_alloc();
>      if (unlikely(frame == NULL))
>          goto end;
>  
> -    for( int got_frame = 0; !got_frame; )
> +    for( int ret = 0; ret == 0; )
>      {
> -        if( p_block->i_buffer == 0 )
> -            goto end;
> -
> -        AVPacket pkt;
> -        av_init_packet( &pkt );
> -        pkt.data = p_block->p_buffer;
> -        pkt.size = p_block->i_buffer;
> -
> -        int ret = avcodec_send_packet( ctx, &pkt );
> -        if( ret != 0 && ret != AVERROR(EAGAIN) )
> +        /* Feed in the loop as buffer could have been full */
> +        if( p_block->i_buffer )
>          {
> -            msg_Warn( p_dec, "cannot decode one frame (%zu bytes)",
> -                      p_block->i_buffer );
> -            goto end;
> +            AVPacket pkt;
> +            av_init_packet( &pkt );
> +            pkt.data = p_block->p_buffer;
> +            pkt.size = p_block->i_buffer;
> +            ret = avcodec_send_packet( ctx, &pkt );
> +            if( ret == 0 || ret != AVERROR(EAGAIN) )
> +                p_block->i_buffer = 0;
>          }
> -        int used = ret != AVERROR(EAGAIN) ? pkt.size : 0;
>  
>          ret = avcodec_receive_frame( ctx, frame );
> -        if( ret != 0 && ret != AVERROR(EAGAIN) )
> +        if( ret == 0 )

Maybe set p_dec->b_error to true and abort if the error is critical:
(ret == AVERROR(ENOMEM) || ret == AVERROR(EINVAL))

>          {
> -            msg_Warn( p_dec, "cannot decode one frame (%zu bytes)",
> -                      p_block->i_buffer );
> -            goto end;
> -        }
> -        got_frame = ret == 0;
> +            /* checks and init from first decoded frame */
> +            if( ctx->channels <= 0 || ctx->channels > 8 ||
> ctx->sample_rate <= 0 )
> +            {
> +                msg_Warn( p_dec, "invalid audio properties channels
> count %d, sample rate %d",
> +                          ctx->channels, ctx->sample_rate );
> +                goto end;
> +            }
> +            else if( p_dec->fmt_out.audio.i_rate != (unsigned
> int)ctx->sample_rate )
> +            {
> +                date_Init( &p_sys->end_date, ctx->sample_rate, 1 );
> +            }
>  
> -        p_block->p_buffer += used;
> -        p_block->i_buffer -= used;
> -    }
> +            block_t *p_converted = ConvertAVFrame( p_dec, frame );
> +            if( p_converted )
> +                block_ChainLastAppend( &pp_decoded_last, p_converted );

pf_decode_audio (and all pf_decode_* cbs) assume that the returned block
is unique.
So, either, you call block_ChainGather() to gater all the blocks into
one (ugly) or you return one block per pf_decode_audio call.
By the way, if you return a valid block in pf_decode, it'll be called
again with the same pp_block pointer. So if *pp_block->i_buffer is 0,
you can return the next blocks of the chain.

>  
> -    if( ctx->channels <= 0 || ctx->channels > 8 || ctx->sample_rate <= 0
> )
> +            /* Prepare new frame */
> +            frame = av_frame_alloc();
> +            if (unlikely(frame == NULL))
> +                break;
> +        }
> +        else av_frame_free( &frame );
> +    };
> +
> +    /* If block has been consumed */
> +    if( p_block->i_buffer == 0 )
>      {
> -        msg_Warn( p_dec, "invalid audio properties channels count %d,
> sample rate %d",
> -                  ctx->channels, ctx->sample_rate );
> -        goto end;
> -    }
> +        /* Only set new pts from input block if it has been used,
> +         * otherwise let it be through interpolation */
> +        if( p_block->i_pts > date_Get( &p_sys->end_date ) )
> +        {
> +            date_Set( &p_sys->end_date, p_block->i_pts );
> +        }
>  
> -    if( p_dec->fmt_out.audio.i_rate != (unsigned int)ctx->sample_rate )
> -        date_Init( &p_sys->end_date, ctx->sample_rate, 1 );
> +        block_Release( p_block );
> +        *pp_block = p_block = NULL;
>  
> -    if( p_block->i_pts > date_Get( &p_sys->end_date ) )
> -    {
> -        date_Set( &p_sys->end_date, p_block->i_pts );
> +        SetupOutputFormat( p_dec, true );
> +        if( decoder_UpdateAudioFormat( p_dec ) )
> +            goto drop;
>      }
>  
> -    if( p_block->i_buffer == 0 )
> -    {   /* Done with this buffer */
> -        block_Release( p_block );
> -        p_block = NULL;
> -        *pp_block = NULL;
> +    block_t *p_current = p_decoded;
> +    for( ; p_current; p_current = p_current->p_next )
> +    {
> +        /* Silent unwanted samples */
> +        if( p_sys->i_reject_count > 0 )
> +        {
> +            memset( p_block->p_buffer, 0, p_block->i_buffer );
> +            p_sys->i_reject_count--;
> +        }
> +        p_current->i_buffer = p_current->i_nb_samples
> +                            * p_dec->fmt_out.audio.i_bytes_per_frame;
> +        p_current->i_pts = date_Get( &p_sys->end_date );
> +        p_current->i_length = date_Increment( &p_sys->end_date,
> +                                              p_current->i_nb_samples )
> - p_current->i_pts;
>      }
>  
> -    /* NOTE WELL: Beyond this point, p_block refers to the DECODED
> block! */
> -    SetupOutputFormat( p_dec, true );
> -    if( decoder_UpdateAudioFormat( p_dec ) )
> -        goto drop;
> +    return p_decoded;
> +
> +end:
> +    *pp_block = NULL;
> +drop:
> +    if( p_block != NULL )
> +        block_Release(p_block);
> +    return NULL;
> +}
> +
> +static block_t * ConvertAVFrame( decoder_t *p_dec, AVFrame *frame )
> +{
> +    decoder_sys_t *p_sys = p_dec->p_sys;
> +    AVCodecContext *ctx = p_sys->p_context;
> +    block_t *p_block;
>  
>      /* Interleave audio if required */
>      if( av_sample_fmt_is_planar( ctx->sample_fmt ) )
>      {
>          p_block = block_Alloc(frame->linesize[0] * ctx->channels);
> -        if (unlikely(p_block == NULL))
> -            goto drop;
> -
> -        const void *planes[ctx->channels];
> -        for (int i = 0; i < ctx->channels; i++)
> -            planes[i] = frame->extended_data[i];
> +        if ( likely(p_block) )
> +        {
> +            const void *planes[ctx->channels];
> +            for (int i = 0; i < ctx->channels; i++)
> +                planes[i] = frame->extended_data[i];
>  
> -        aout_Interleave(p_block->p_buffer, planes, frame->nb_samples,
> -                        ctx->channels, p_dec->fmt_out.audio.i_format);
> -        p_block->i_nb_samples = frame->nb_samples;
> +            aout_Interleave(p_block->p_buffer, planes,
> frame->nb_samples,
> +                            ctx->channels,
> p_dec->fmt_out.audio.i_format);
> +            p_block->i_nb_samples = frame->nb_samples;
> +        }
>          av_frame_free(&frame);
>      }
>      else
>      {
>          p_block = vlc_av_frame_Wrap(frame);
> -        if (unlikely(p_block == NULL))
> -            goto drop;
>          frame = NULL;
>      }
>  
> -    if (p_sys->b_extract)
> +    if (p_sys->b_extract && p_block)
>      {   /* TODO: do not drop channels... at least not here */
>          block_t *p_buffer = block_Alloc(
>          p_dec->fmt_out.audio.i_bytes_per_frame
>                                           * p_block->i_nb_samples );
> -        if( unlikely(p_buffer == NULL) )
> -            goto drop;
> -        aout_ChannelExtract( p_buffer->p_buffer,
> -                             p_dec->fmt_out.audio.i_channels,
> -                             p_block->p_buffer, ctx->channels,
> -                             p_block->i_nb_samples,
> p_sys->pi_extraction,
> -                             p_dec->fmt_out.audio.i_bitspersample );
> -        p_buffer->i_nb_samples = p_block->i_nb_samples;
> +        if( likely(p_buffer) )
> +        {
> +            aout_ChannelExtract( p_buffer->p_buffer,
> +                                 p_dec->fmt_out.audio.i_channels,
> +                                 p_block->p_buffer, ctx->channels,
> +                                 p_block->i_nb_samples,
> p_sys->pi_extraction,
> +                                 p_dec->fmt_out.audio.i_bitspersample );
> +            p_buffer->i_nb_samples = p_block->i_nb_samples;
> +        }
>          block_Release( p_block );
>          p_block = p_buffer;
>      }
>  
> -    /* Silent unwanted samples */
> -    if( p_sys->i_reject_count > 0 )
> -    {
> -        memset( p_block->p_buffer, 0, p_block->i_buffer );
> -        p_sys->i_reject_count--;
> -    }
> -
> -    p_block->i_buffer = p_block->i_nb_samples
> -                        * p_dec->fmt_out.audio.i_bytes_per_frame;
> -    p_block->i_pts = date_Get( &p_sys->end_date );
> -    p_block->i_length = date_Increment( &p_sys->end_date,
> -                                      p_block->i_nb_samples ) -
> p_block->i_pts;
>      return p_block;
> -
> -end:
> -    *pp_block = NULL;
> -drop:
> -    av_frame_free(&frame);
> -    if( p_block != NULL )
> -        block_Release(p_block);
> -    return NULL;
>  }
>  
>  /*****************************************************************************
> -- 
> 2.7.4
> 
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list