[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