Commit 118c5be3 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

avcodec: update to audio4 decoding API

Note that the input coded buffer is now only freed if the decoding
returns a decoded frame, or the buffer has been entirely consumed
(see *pp_block = NULL).
parent 1267f152
...@@ -29,6 +29,8 @@ ...@@ -29,6 +29,8 @@
# include "config.h" # include "config.h"
#endif #endif
#include <assert.h>
#include <vlc_common.h> #include <vlc_common.h>
#include <vlc_aout.h> #include <vlc_aout.h>
#include <vlc_codec.h> #include <vlc_codec.h>
...@@ -48,10 +50,6 @@ struct decoder_sys_t ...@@ -48,10 +50,6 @@ struct decoder_sys_t
{ {
AVCODEC_COMMON_MEMBERS AVCODEC_COMMON_MEMBERS
/* Temporary buffer for libavcodec */
int i_output_max;
uint8_t *p_output;
/* /*
* Output properties * Output properties
*/ */
...@@ -71,6 +69,7 @@ struct decoder_sys_t ...@@ -71,6 +69,7 @@ struct decoder_sys_t
#define BLOCK_FLAG_PRIVATE_REALLOCATED (1 << BLOCK_FLAG_PRIVATE_SHIFT) #define BLOCK_FLAG_PRIVATE_REALLOCATED (1 << BLOCK_FLAG_PRIVATE_SHIFT)
static void SetupOutputFormat( decoder_t *p_dec, bool b_trust ); static void SetupOutputFormat( decoder_t *p_dec, bool b_trust );
static int GetAudioBuf( struct AVCodecContext *, AVFrame * );
static void InitDecoderConfig( decoder_t *p_dec, AVCodecContext *p_context ) static void InitDecoderConfig( decoder_t *p_dec, AVCodecContext *p_context )
{ {
...@@ -145,6 +144,7 @@ int InitAudioDec( decoder_t *p_dec, AVCodecContext *p_context, ...@@ -145,6 +144,7 @@ int InitAudioDec( decoder_t *p_dec, AVCodecContext *p_context,
p_codec->type = AVMEDIA_TYPE_AUDIO; p_codec->type = AVMEDIA_TYPE_AUDIO;
p_context->codec_type = AVMEDIA_TYPE_AUDIO; p_context->codec_type = AVMEDIA_TYPE_AUDIO;
p_context->codec_id = i_codec_id; p_context->codec_id = i_codec_id;
p_context->get_buffer = GetAudioBuf;
p_sys->p_context = p_context; p_sys->p_context = p_context;
p_sys->p_codec = p_codec; p_sys->p_codec = p_codec;
p_sys->i_codec_id = i_codec_id; p_sys->i_codec_id = i_codec_id;
...@@ -163,29 +163,6 @@ int InitAudioDec( decoder_t *p_dec, AVCodecContext *p_context, ...@@ -163,29 +163,6 @@ int InitAudioDec( decoder_t *p_dec, AVCodecContext *p_context,
return VLC_EGENERIC; return VLC_EGENERIC;
} }
switch( i_codec_id )
{
case CODEC_ID_WAVPACK:
p_sys->i_output_max = 8 * sizeof(int32_t) * 131072;
break;
case CODEC_ID_TTA:
p_sys->i_output_max = p_sys->p_context->channels * sizeof(int32_t) * p_sys->p_context->sample_rate * 2;
break;
case CODEC_ID_FLAC:
p_sys->i_output_max = 8 * sizeof(int32_t) * 65535;
break;
case CODEC_ID_WMAPRO:
p_sys->i_output_max = 8 * sizeof(float) * 6144; /* (1 << 12) * 3/2 */
break;
default:
p_sys->i_output_max = 0;
break;
}
if( p_sys->i_output_max < 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE )
p_sys->i_output_max = 2 * AVCODEC_MAX_AUDIO_FRAME_SIZE;
msg_Dbg( p_dec, "Using %d bytes output buffer", p_sys->i_output_max );
p_sys->p_output = av_malloc( p_sys->i_output_max );
p_sys->i_reject_count = 0; p_sys->i_reject_count = 0;
p_sys->b_extract = false; p_sys->b_extract = false;
p_sys->i_previous_channels = 0; p_sys->i_previous_channels = 0;
...@@ -205,20 +182,63 @@ int InitAudioDec( decoder_t *p_dec, AVCodecContext *p_context, ...@@ -205,20 +182,63 @@ int InitAudioDec( decoder_t *p_dec, AVCodecContext *p_context,
return VLC_SUCCESS; return VLC_SUCCESS;
} }
/**
* Allocates decoded audio buffer for libavcodec to use.
*/
static int GetAudioBuf( AVCodecContext *ctx, AVFrame *buf )
{
block_t *block;
bool planar = av_sample_fmt_is_planar( ctx->sample_fmt );
unsigned channels = planar ? 1 : ctx->channels;
unsigned planes = planar ? ctx->channels : 1;
int bytes = av_samples_get_buffer_size( &buf->linesize[0], channels,
buf->nb_samples, ctx->sample_fmt,
16 );
assert( bytes >= 0 );
block = block_Alloc( bytes * planes );
if( unlikely(block == NULL) )
return AVERROR(ENOMEM);
block->i_nb_samples = buf->nb_samples;
buf->opaque = block;
if( planes > AV_NUM_DATA_POINTERS )
{
uint8_t **ext = malloc( sizeof( *ext ) * planes );
if( unlikely(ext == NULL) )
{
block_Release( block );
return AVERROR(ENOMEM);
}
buf->extended_data = ext;
}
else
buf->extended_data = buf->data;
uint8_t *buffer = block->p_buffer;
for( unsigned i = 0; i < planes; i++ )
{
buf->linesize[i] = buf->linesize[0];
buf->extended_data[i] = buffer;
buffer += bytes;
}
return 0;
}
/***************************************************************************** /*****************************************************************************
* DecodeAudio: Called to decode one frame * DecodeAudio: Called to decode one frame
*****************************************************************************/ *****************************************************************************/
block_t * DecodeAudio ( decoder_t *p_dec, block_t **pp_block ) block_t * DecodeAudio ( decoder_t *p_dec, block_t **pp_block )
{ {
decoder_sys_t *p_sys = p_dec->p_sys; decoder_sys_t *p_sys = p_dec->p_sys;
int i_used, i_output; AVCodecContext *ctx = p_sys->p_context;
AVPacket pkt;
if( !pp_block || !*pp_block ) if( !pp_block || !*pp_block )
return NULL; return NULL;
block_t *p_block = *pp_block; block_t *p_block = *pp_block;
*pp_block = NULL;
if( !p_sys->p_context->extradata_size && p_dec->fmt_in.i_extra && if( !p_sys->p_context->extradata_size && p_dec->fmt_in.i_extra &&
p_sys->b_delayed_open) p_sys->b_delayed_open)
...@@ -260,39 +280,31 @@ block_t * DecodeAudio ( decoder_t *p_dec, block_t **pp_block ) ...@@ -260,39 +280,31 @@ block_t * DecodeAudio ( decoder_t *p_dec, block_t **pp_block )
p_block->i_flags |= BLOCK_FLAG_PRIVATE_REALLOCATED; p_block->i_flags |= BLOCK_FLAG_PRIVATE_REALLOCATED;
} }
do AVFrame frame;
{ memset( &frame, 0, sizeof( frame ) );
i_output = __MAX( p_block->i_buffer, p_sys->i_output_max );
if( i_output > p_sys->i_output_max ) for( int got_frame = 0; !got_frame; )
{ {
/* Grow output buffer if necessary (eg. for PCM data) */ if( p_block->i_buffer == 0 )
p_sys->p_output = av_realloc( p_sys->p_output, i_output ); goto end;
}
AVPacket pkt;
av_init_packet( &pkt ); av_init_packet( &pkt );
pkt.data = p_block->p_buffer; pkt.data = p_block->p_buffer;
pkt.size = p_block->i_buffer; pkt.size = p_block->i_buffer;
i_used = avcodec_decode_audio3( p_sys->p_context,
(int16_t*)p_sys->p_output, &i_output,
&pkt );
if( i_used < 0 || i_output < 0 ) int used = avcodec_decode_audio4( ctx, &frame, &got_frame, &pkt );
if( used < 0 )
{ {
if( i_used < 0 )
msg_Warn( p_dec, "cannot decode one frame (%zu bytes)", msg_Warn( p_dec, "cannot decode one frame (%zu bytes)",
p_block->i_buffer ); p_block->i_buffer );
goto end; goto end;
} }
else if( (size_t)i_used > p_block->i_buffer )
{
i_used = p_block->i_buffer;
}
p_block->i_buffer -= i_used;
p_block->p_buffer += i_used;
} while( p_block->i_buffer > 0 && i_output <= 0 ); assert( p_block->i_buffer >= (unsigned)used );
p_block->p_buffer += used;
p_block->i_buffer -= used;
}
if( p_sys->p_context->channels <= 0 || p_sys->p_context->channels > 8 || if( p_sys->p_context->channels <= 0 || p_sys->p_context->channels > 8 ||
p_sys->p_context->sample_rate <= 0 ) p_sys->p_context->sample_rate <= 0 )
...@@ -311,57 +323,70 @@ block_t * DecodeAudio ( decoder_t *p_dec, block_t **pp_block ) ...@@ -311,57 +323,70 @@ block_t * DecodeAudio ( decoder_t *p_dec, block_t **pp_block )
date_Set( &p_sys->end_date, p_block->i_pts ); date_Set( &p_sys->end_date, p_block->i_pts );
} }
if( p_block->i_buffer == 0 )
{ /* Done with this buffer */
block_Release( p_block ); block_Release( p_block );
*pp_block = NULL;
}
/* NOTE WELL: Beyond this point, p_block now refers to the DECODED block */
p_block = frame.opaque;
SetupOutputFormat( p_dec, true ); SetupOutputFormat( p_dec, true );
/* Silent unwanted samples */ /* Silent unwanted samples */
if( p_sys->i_reject_count > 0 ) if( p_sys->i_reject_count > 0 )
{ {
memset( p_sys->p_output, 0, i_output ); memset( p_block->p_buffer, 0, p_block->i_buffer );
p_sys->i_reject_count--; p_sys->i_reject_count--;
} }
int i_samples = i_output / (p_dec->fmt_out.audio.i_bitspersample / 8) / p_sys->p_context->channels; block_t *p_buffer = decoder_NewAudioBuffer( p_dec, p_block->i_nb_samples );
if (i_samples == 0)
return NULL;
block_t *p_buffer = decoder_NewAudioBuffer( p_dec, i_samples );
if (!p_buffer) if (!p_buffer)
return NULL; return NULL;
p_buffer->i_pts = date_Get( &p_sys->end_date ); assert( p_block->i_nb_samples >= (unsigned)frame.nb_samples );
p_buffer->i_length = date_Increment( &p_sys->end_date, i_samples ) - p_buffer->i_pts; assert( p_buffer->i_buffer >= p_block->i_buffer );
int sample_planar = av_sample_fmt_is_planar( p_sys->p_context->sample_fmt );
if( sample_planar )
aout_Interleave( p_buffer->p_buffer, p_sys->p_output, i_samples, p_sys->p_context->channels, p_dec->fmt_out.audio.i_format );
if( p_sys->b_extract == !!sample_planar ) /* Interleave audio if required */
memcpy( p_sys->p_output, p_buffer->p_buffer, p_buffer->i_buffer ); if( av_sample_fmt_is_planar( ctx->sample_fmt ) )
{
aout_Interleave( p_buffer->p_buffer, p_block->p_buffer,
p_block->i_nb_samples, ctx->channels,
p_dec->fmt_out.audio.i_format );
if( ctx->channels > AV_NUM_DATA_POINTERS )
free( frame.extended_data );
}
else /* TODO: zero copy... need to replace decoder_NewAudioBuffer() */
memcpy( p_buffer->p_buffer, p_block->p_buffer, p_block->i_buffer );
if (p_sys->b_extract) if (p_sys->b_extract)
aout_ChannelExtract( p_buffer->p_buffer, p_dec->fmt_out.audio.i_channels, { /* TODO: do not drop channels... at least not here */
p_sys->p_output, p_sys->p_context->channels, i_samples, aout_ChannelExtract( p_block->p_buffer,
p_sys->pi_extraction, p_dec->fmt_out.audio.i_bitspersample ); p_dec->fmt_out.audio.i_channels,
p_buffer->p_buffer, ctx->channels,
frame.nb_samples, p_sys->pi_extraction,
p_dec->fmt_out.audio.i_bitspersample );
block_Release( p_buffer );
p_buffer = p_block;
}
else
block_Release( p_block );
p_buffer->i_nb_samples = frame.nb_samples;
p_buffer->i_buffer = frame.nb_samples
* p_dec->fmt_out.audio.i_bytes_per_frame;
p_buffer->i_pts = date_Get( &p_sys->end_date );
p_buffer->i_length = date_Increment( &p_sys->end_date, frame.nb_samples )
- p_buffer->i_pts;
return p_buffer; return p_buffer;
end: end:
block_Release(p_block); block_Release(p_block);
*pp_block = NULL;
return NULL; return NULL;
} }
/*****************************************************************************
* EndAudioDec: audio decoder destruction
*****************************************************************************/
void EndAudioDec( decoder_t *p_dec )
{
decoder_sys_t *p_sys = p_dec->p_sys;
av_free( p_sys->p_output );
}
/***************************************************************************** /*****************************************************************************
* *
*****************************************************************************/ *****************************************************************************/
......
...@@ -361,9 +361,6 @@ static void CloseDecoder( vlc_object_t *p_this ) ...@@ -361,9 +361,6 @@ static void CloseDecoder( vlc_object_t *p_this )
switch( p_sys->i_cat ) switch( p_sys->i_cat )
{ {
case AUDIO_ES:
EndAudioDec ( p_dec );
break;
case VIDEO_ES: case VIDEO_ES:
EndVideoDec ( p_dec ); EndVideoDec ( p_dec );
break; break;
......
...@@ -53,7 +53,6 @@ void EndVideoDec( decoder_t *p_dec ); ...@@ -53,7 +53,6 @@ void EndVideoDec( decoder_t *p_dec );
/* Audio Decoder */ /* Audio Decoder */
int InitAudioDec( decoder_t *p_dec, AVCodecContext *p_context, int InitAudioDec( decoder_t *p_dec, AVCodecContext *p_context,
AVCodec *p_codec, int i_codec_id, const char *psz_namecodec ); AVCodec *p_codec, int i_codec_id, const char *psz_namecodec );
void EndAudioDec( decoder_t *p_dec );
/* Subtitle Decoder */ /* Subtitle Decoder */
int InitSubtitleDec( decoder_t *p_dec, AVCodecContext *p_context, int InitSubtitleDec( decoder_t *p_dec, AVCodecContext *p_context,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment