diff options
Diffstat (limited to 'libavcodec/vorbisdec.c')
-rw-r--r-- | libavcodec/vorbisdec.c | 132 |
1 files changed, 90 insertions, 42 deletions
diff --git a/libavcodec/vorbisdec.c b/libavcodec/vorbisdec.c index be2e38dfd5..ba5b1a3f94 100644 --- a/libavcodec/vorbisdec.c +++ b/libavcodec/vorbisdec.c @@ -1,18 +1,22 @@ -/* - * This file is part of Libav. +/** + * @file + * Vorbis I decoder + * @author Denes Balatoni ( dbalatoni programozo hu ) + * + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -27,6 +31,7 @@ #define BITSTREAM_READER_LE #include "libavutil/float_dsp.h" +#include "libavutil/avassert.h" #include "avcodec.h" #include "get_bits.h" #include "fft.h" @@ -42,9 +47,6 @@ #define V_MAX_VLCS (1 << 16) #define V_MAX_PARTITIONS (1 << 20) -#undef NDEBUG -#include <assert.h> - typedef struct { uint8_t dimensions; uint8_t lookup_type; @@ -192,37 +194,41 @@ static void vorbis_free(vorbis_context *vc) av_freep(&vc->channel_residues); av_freep(&vc->saved); - for (i = 0; i < vc->residue_count; i++) - av_free(vc->residues[i].classifs); + if (vc->residues) + for (i = 0; i < vc->residue_count; i++) + av_free(vc->residues[i].classifs); av_freep(&vc->residues); av_freep(&vc->modes); ff_mdct_end(&vc->mdct[0]); ff_mdct_end(&vc->mdct[1]); - for (i = 0; i < vc->codebook_count; ++i) { - av_free(vc->codebooks[i].codevectors); - ff_free_vlc(&vc->codebooks[i].vlc); - } + if (vc->codebooks) + for (i = 0; i < vc->codebook_count; ++i) { + av_free(vc->codebooks[i].codevectors); + ff_free_vlc(&vc->codebooks[i].vlc); + } av_freep(&vc->codebooks); - for (i = 0; i < vc->floor_count; ++i) { - if (vc->floors[i].floor_type == 0) { - av_free(vc->floors[i].data.t0.map[0]); - av_free(vc->floors[i].data.t0.map[1]); - av_free(vc->floors[i].data.t0.book_list); - av_free(vc->floors[i].data.t0.lsp); - } else { - av_free(vc->floors[i].data.t1.list); + if (vc->floors) + for (i = 0; i < vc->floor_count; ++i) { + if (vc->floors[i].floor_type == 0) { + av_free(vc->floors[i].data.t0.map[0]); + av_free(vc->floors[i].data.t0.map[1]); + av_free(vc->floors[i].data.t0.book_list); + av_free(vc->floors[i].data.t0.lsp); + } else { + av_free(vc->floors[i].data.t1.list); + } } - } av_freep(&vc->floors); - for (i = 0; i < vc->mapping_count; ++i) { - av_free(vc->mappings[i].magnitude); - av_free(vc->mappings[i].angle); - av_free(vc->mappings[i].mux); - } + if (vc->mappings) + for (i = 0; i < vc->mapping_count; ++i) { + av_free(vc->mappings[i].magnitude); + av_free(vc->mappings[i].angle); + av_free(vc->mappings[i].mux); + } av_freep(&vc->mappings); } @@ -416,6 +422,11 @@ static int vorbis_parse_setup_hdr_codebooks(vorbis_context *vc) } // Initialize VLC table + if (entries <= 0) { + av_log(vc->avctx, AV_LOG_ERROR, "Invalid codebook entry count\n"); + ret = AVERROR_INVALIDDATA; + goto error; + } if (ff_vorbis_len2vlc(tmp_vlc_bits, tmp_vlc_codes, entries)) { av_log(vc->avctx, AV_LOG_ERROR, " Invalid code lengths while generating vlcs. \n"); ret = AVERROR_INVALIDDATA; @@ -695,7 +706,7 @@ static int vorbis_parse_setup_hdr_residues(vorbis_context *vc) res_setup->partition_size = get_bits(gb, 24) + 1; /* Validations to prevent a buffer overflow later. */ if (res_setup->begin>res_setup->end || - res_setup->end > (res_setup->type == 2 ? vc->avctx->channels : 1) * vc->blocksize[1] / 2 || + res_setup->end > (res_setup->type == 2 ? vc->audio_channels : 1) * vc->blocksize[1] / 2 || (res_setup->end-res_setup->begin) / res_setup->partition_size > V_MAX_PARTITIONS) { av_log(vc->avctx, AV_LOG_ERROR, "partition out of bounds: type, begin, end, size, blocksize: %"PRIu16", %"PRIu32", %"PRIu32", %u, %"PRIu32"\n", @@ -964,12 +975,12 @@ static int vorbis_parse_id_hdr(vorbis_context *vc) vc->bitrate_minimum = get_bits_long(gb, 32); bl0 = get_bits(gb, 4); bl1 = get_bits(gb, 4); - vc->blocksize[0] = (1 << bl0); - vc->blocksize[1] = (1 << bl1); if (bl0 > 13 || bl0 < 6 || bl1 > 13 || bl1 < 6 || bl1 < bl0) { av_log(vc->avctx, AV_LOG_ERROR, " Vorbis id header packet corrupt (illegal blocksize). \n"); return AVERROR_INVALIDDATA; } + vc->blocksize[0] = (1 << bl0); + vc->blocksize[1] = (1 << bl1); vc->win[0] = ff_vorbis_vwin[bl0 - 6]; vc->win[1] = ff_vorbis_vwin[bl1 - 6]; @@ -1188,7 +1199,7 @@ static int vorbis_floor1_decode(vorbis_context *vc, uint16_t floor1_Y[258]; uint16_t floor1_Y_final[258]; int floor1_flag[258]; - unsigned class, cdim, cbits, csub, cval, offset, i, j; + unsigned partition_class, cdim, cbits, csub, cval, offset, i, j; int book, adx, ady, dy, off, predicted, err; @@ -1204,20 +1215,20 @@ static int vorbis_floor1_decode(vorbis_context *vc, offset = 2; for (i = 0; i < vf->partitions; ++i) { - class = vf->partition_class[i]; - cdim = vf->class_dimensions[class]; - cbits = vf->class_subclasses[class]; + partition_class = vf->partition_class[i]; + cdim = vf->class_dimensions[partition_class]; + cbits = vf->class_subclasses[partition_class]; csub = (1 << cbits) - 1; cval = 0; av_dlog(NULL, "Cbits %u\n", cbits); if (cbits) // this reads all subclasses for this partition's class - cval = get_vlc2(gb, vc->codebooks[vf->class_masterbook[class]].vlc.table, - vc->codebooks[vf->class_masterbook[class]].nb_bits, 3); + cval = get_vlc2(gb, vc->codebooks[vf->class_masterbook[partition_class]].vlc.table, + vc->codebooks[vf->class_masterbook[partition_class]].nb_bits, 3); for (j = 0; j < cdim; ++j) { - book = vf->subclass_books[class][cval & csub]; + book = vf->subclass_books[partition_class][cval & csub]; av_dlog(NULL, "book %d Cbits %u cval %u bits:%d\n", book, cbits, cval, get_bits_count(gb)); @@ -1353,7 +1364,7 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, av_dlog(NULL, "Classword: %u\n", temp); - assert(vr->classifications > 1 && temp <= 65536); //needed for inverse[] + av_assert0(vr->classifications > 1 && temp <= 65536); //needed for inverse[] for (i = 0; i < c_p_c; ++i) { unsigned temp2; @@ -1682,12 +1693,49 @@ static int vorbis_decode_frame(AVCodecContext *avctx, void *data, av_dlog(NULL, "packet length %d \n", buf_size); + if (*buf == 1 && buf_size > 7) { + init_get_bits(gb, buf+1, buf_size*8 - 8); + vorbis_free(vc); + if ((ret = vorbis_parse_id_hdr(vc))) { + av_log(avctx, AV_LOG_ERROR, "Id header corrupt.\n"); + vorbis_free(vc); + return ret; + } + + if (vc->audio_channels > 8) + avctx->channel_layout = 0; + else + avctx->channel_layout = ff_vorbis_channel_layouts[vc->audio_channels - 1]; + + avctx->channels = vc->audio_channels; + avctx->sample_rate = vc->audio_samplerate; + return buf_size; + } + + if (*buf == 3 && buf_size > 7) { + av_log(avctx, AV_LOG_DEBUG, "Ignoring comment header\n"); + return buf_size; + } + + if (*buf == 5 && buf_size > 7 && vc->channel_residues && !vc->modes) { + init_get_bits(gb, buf+1, buf_size*8 - 8); + if ((ret = vorbis_parse_setup_hdr(vc))) { + av_log(avctx, AV_LOG_ERROR, "Setup header corrupt.\n"); + vorbis_free(vc); + return ret; + } + return buf_size; + } + + if (!vc->channel_residues || !vc->modes) { + av_log(avctx, AV_LOG_ERROR, "Data packet before valid headers\n"); + return AVERROR_INVALIDDATA; + } + /* get output buffer */ frame->nb_samples = vc->blocksize[1] / 2; - if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) { - av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) return ret; - } if (vc->audio_channels > 8) { for (i = 0; i < vc->audio_channels; i++) |