[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