diff options
author | Justin Ruggles <justin.ruggles@gmail.com> | 2012-10-11 22:21:56 +0400 |
---|---|---|
committer | Justin Ruggles <justin.ruggles@gmail.com> | 2012-10-13 08:07:10 +0400 |
commit | 61d5313d94c9e6a86d599de781f287b577b7fe11 (patch) | |
tree | f5cb2b79cd2d5a4cfa56ee621f1a27cce9680e3e /libavcodec | |
parent | a77f01c725296321936ef671eff1a8bd2ad96f0a (diff) |
dca: allocate a secondary buffer for extra channels when downmixing
The output AVFrame buffer only has data for the downmix channels.
Fixes a segfault when decoding dca with request_channels == 2.
Diffstat (limited to 'libavcodec')
-rw-r--r-- | libavcodec/dcadec.c | 32 |
1 files changed, 30 insertions, 2 deletions
diff --git a/libavcodec/dcadec.c b/libavcodec/dcadec.c index d38dff81b3..eb12eb2db9 100644 --- a/libavcodec/dcadec.c +++ b/libavcodec/dcadec.c @@ -32,6 +32,7 @@ #include "libavutil/intreadwrite.h" #include "libavutil/mathematics.h" #include "libavutil/audioconvert.h" +#include "libavutil/samplefmt.h" #include "avcodec.h" #include "dsputil.h" #include "fft.h" @@ -357,6 +358,9 @@ typedef struct { DECLARE_ALIGNED(32, float, subband_samples)[DCA_BLOCKS_MAX][DCA_PRIM_CHANNELS_MAX][DCA_SUBBANDS][8]; float *samples_chanptr[DCA_PRIM_CHANNELS_MAX + 1]; + float *extra_channels[DCA_PRIM_CHANNELS_MAX + 1]; + uint8_t *extra_channels_buffer; + unsigned int extra_channels_buffer_size; uint8_t dca_buffer[DCA_MAX_FRAME_SIZE + DCA_MAX_EXSS_HEADER_SIZE + DCA_BUFFER_PADDING_SIZE]; int dca_buffer_size; ///< how much data is in the dca_buffer @@ -1656,7 +1660,7 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data, int i, ret; float **samples_flt; DCAContext *s = avctx->priv_data; - int channels; + int channels, full_channels; int core_ss_end; @@ -1790,7 +1794,7 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data, avctx->profile = s->profile; - channels = s->prim_channels + !!s->lfe; + full_channels = channels = s->prim_channels + !!s->lfe; if (s->amode < 16) { avctx->channel_layout = dca_core_channel_layout[s->amode]; @@ -1852,12 +1856,35 @@ static int dca_decode_frame(AVCodecContext *avctx, void *data, } samples_flt = (float **) s->frame.extended_data; + /* allocate buffer for extra channels if downmixing */ + if (avctx->channels < full_channels) { + ret = av_samples_get_buffer_size(NULL, full_channels - channels, + s->frame.nb_samples, + avctx->sample_fmt, 0); + if (ret < 0) + return ret; + + av_fast_malloc(&s->extra_channels_buffer, + &s->extra_channels_buffer_size, ret); + if (!s->extra_channels_buffer) + return AVERROR(ENOMEM); + + ret = av_samples_fill_arrays((uint8_t **)s->extra_channels, NULL, + s->extra_channels_buffer, + full_channels - channels, + s->frame.nb_samples, avctx->sample_fmt, 0); + if (ret < 0) + return ret; + } + /* filter to get final output */ for (i = 0; i < (s->sample_blocks / 8); i++) { int ch; for (ch = 0; ch < channels; ch++) s->samples_chanptr[ch] = samples_flt[ch] + i * 256; + for (; ch < full_channels; ch++) + s->samples_chanptr[ch] = s->extra_channels[ch - channels] + i * 256; dca_filter_channels(s, i); @@ -1922,6 +1949,7 @@ static av_cold int dca_decode_end(AVCodecContext *avctx) { DCAContext *s = avctx->priv_data; ff_mdct_end(&s->imdct); + av_freep(&s->extra_channels_buffer); return 0; } |