[vlc-devel] [PATCH] codec: avcodec: adapt code to new API
Francois Cartegnie
fcvlcdev at free.fr
Mon Oct 10 23:38:29 CEST 2016
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 )
{
- 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 );
- 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
More information about the vlc-devel
mailing list