diff options
Diffstat (limited to 'libavcodec/vorbisdec.c')
-rw-r--r-- | libavcodec/vorbisdec.c | 202 |
1 files changed, 138 insertions, 64 deletions
diff --git a/libavcodec/vorbisdec.c b/libavcodec/vorbisdec.c index d7fec98..2ad5b4f 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" @@ -146,7 +151,7 @@ typedef struct vorbis_context_s { uint8_t mode_count; vorbis_mode *modes; uint8_t mode_number; // mode number for the current packet - uint8_t previous_window; + int8_t previous_window; float *channel_residues; float *saved; } vorbis_context; @@ -189,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_freep(&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_freep(&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_freep(&vc->floors[i].data.t0.map[0]); + av_freep(&vc->floors[i].data.t0.map[1]); + av_freep(&vc->floors[i].data.t0.book_list); + av_freep(&vc->floors[i].data.t0.lsp); + } else { + av_freep(&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_freep(&vc->mappings[i].magnitude); + av_freep(&vc->mappings[i].angle); + av_freep(&vc->mappings[i].mux); + } av_freep(&vc->mappings); } @@ -369,7 +378,7 @@ static int vorbis_parse_setup_hdr_codebooks(vorbis_context *vc) } // Weed out unused vlcs and build codevector vector - codebook_setup->codevectors = used_entries ? av_mallocz(used_entries * + codebook_setup->codevectors = used_entries ? av_mallocz_array(used_entries, codebook_setup->dimensions * sizeof(*codebook_setup->codevectors)) : NULL; @@ -552,7 +561,7 @@ static int vorbis_parse_setup_hdr_floors(vorbis_context *vc) for (j = 0; j < floor_setup->data.t1.partitions; ++j) floor_setup->data.t1.x_list_dim+=floor_setup->data.t1.class_dimensions[floor_setup->data.t1.partition_class[j]]; - floor_setup->data.t1.list = av_mallocz(floor_setup->data.t1.x_list_dim * + floor_setup->data.t1.list = av_mallocz_array(floor_setup->data.t1.x_list_dim, sizeof(*floor_setup->data.t1.list)); if (!floor_setup->data.t1.list) return AVERROR(ENOMEM); @@ -631,8 +640,8 @@ static int vorbis_parse_setup_hdr_floors(vorbis_context *vc) /* codebook dim is for padding if codebook dim doesn't * * divide order+1 then we need to read more data */ floor_setup->data.t0.lsp = - av_malloc((floor_setup->data.t0.order + 1 + max_codebook_dim) - * sizeof(*floor_setup->data.t0.lsp)); + av_malloc_array((floor_setup->data.t0.order + 1 + max_codebook_dim), + sizeof(*floor_setup->data.t0.lsp)); if (!floor_setup->data.t0.lsp) return AVERROR(ENOMEM); @@ -692,8 +701,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->begin) / res_setup->partition_size > V_MAX_PARTITIONS) { + (res_setup->end-res_setup->begin) / res_setup->partition_size > FFMIN(V_MAX_PARTITIONS, 65535)) { av_log(vc->avctx, AV_LOG_ERROR, "partition out of bounds: type, begin, end, size, blocksize: %"PRIu16", %"PRIu32", %"PRIu32", %u, %"PRIu32"\n", res_setup->type, res_setup->begin, res_setup->end, @@ -706,7 +714,7 @@ static int vorbis_parse_setup_hdr_residues(vorbis_context *vc) res_setup->ptns_to_read = (res_setup->end - res_setup->begin) / res_setup->partition_size; - res_setup->classifs = av_malloc(res_setup->ptns_to_read * + res_setup->classifs = av_malloc_array(res_setup->ptns_to_read, vc->audio_channels * sizeof(*res_setup->classifs)); if (!res_setup->classifs) @@ -799,7 +807,7 @@ static int vorbis_parse_setup_hdr_mappings(vorbis_context *vc) } if (mapping_setup->submaps>1) { - mapping_setup->mux = av_mallocz(vc->audio_channels * + mapping_setup->mux = av_mallocz_array(vc->audio_channels, sizeof(*mapping_setup->mux)); if (!mapping_setup->mux) return AVERROR(ENOMEM); @@ -834,7 +842,7 @@ static int create_map(vorbis_context *vc, unsigned floor_number) for (blockflag = 0; blockflag < 2; ++blockflag) { n = vc->blocksize[blockflag] / 2; floors[floor_number].data.t0.map[blockflag] = - av_malloc((n + 1) * sizeof(int32_t)); // n + sentinel + av_malloc_array(n + 1, sizeof(int32_t)); // n + sentinel if (!floors[floor_number].data.t0.map[blockflag]) return AVERROR(ENOMEM); @@ -961,12 +969,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]; @@ -975,12 +983,12 @@ static int vorbis_parse_id_hdr(vorbis_context *vc) return AVERROR_INVALIDDATA; } - vc->channel_residues = av_malloc((vc->blocksize[1] / 2) * vc->audio_channels * sizeof(*vc->channel_residues)); - vc->saved = av_mallocz((vc->blocksize[1] / 4) * vc->audio_channels * sizeof(*vc->saved)); + vc->channel_residues = av_malloc_array(vc->blocksize[1] / 2, vc->audio_channels * sizeof(*vc->channel_residues)); + vc->saved = av_mallocz_array(vc->blocksize[1] / 4, vc->audio_channels * sizeof(*vc->saved)); if (!vc->channel_residues || !vc->saved) return AVERROR(ENOMEM); - vc->previous_window = 0; + vc->previous_window = -1; ff_mdct_init(&vc->mdct[0], bl0, 1, -1.0); ff_mdct_init(&vc->mdct[1], bl1, 1, -1.0); @@ -1185,7 +1193,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; @@ -1201,28 +1209,31 @@ 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)); cval = cval >> cbits; if (book > -1) { - floor1_Y[offset+j] = get_vlc2(gb, vc->codebooks[book].vlc.table, - vc->codebooks[book].nb_bits, 3); + int v = get_vlc2(gb, vc->codebooks[book].vlc.table, + vc->codebooks[book].nb_bits, 3); + if (v < 0) + return AVERROR_INVALIDDATA; + floor1_Y[offset+j] = v; } else { floor1_Y[offset+j] = 0; } @@ -1303,7 +1314,9 @@ static av_always_inline int setup_classifs(vorbis_context *vc, vorbis_residue *vr, uint8_t *do_not_decode, unsigned ch_used, - int partition_count) + int partition_count, + int ptns_to_read + ) { int p, j, i; unsigned c_p_c = vc->codebooks[vr->classbook].dimensions; @@ -1316,11 +1329,16 @@ static av_always_inline int setup_classifs(vorbis_context *vc, av_dlog(NULL, "Classword: %u\n", temp); + if ((int)temp < 0) + return temp; + + av_assert0(vr->classifications > 1); //needed for inverse[] + if (temp <= 65536) { for (i = partition_count + c_p_c - 1; i >= partition_count; i--) { temp2 = (((uint64_t)temp) * inverse_class) >> 32; - if (i < vr->ptns_to_read) + if (i < ptns_to_read) vr->classifs[p + i] = temp - temp2 * vr->classifications; temp = temp2; } @@ -1328,13 +1346,13 @@ static av_always_inline int setup_classifs(vorbis_context *vc, for (i = partition_count + c_p_c - 1; i >= partition_count; i--) { temp2 = temp / vr->classifications; - if (i < vr->ptns_to_read) + if (i < ptns_to_read) vr->classifs[p + i] = temp - temp2 * vr->classifications; temp = temp2; } } } - p += vr->ptns_to_read; + p += ptns_to_read; } return 0; } @@ -1355,6 +1373,7 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, unsigned pass, ch_used, i, j, k, l; unsigned max_output = (ch - 1) * vlen; int ptns_to_read = vr->ptns_to_read; + int libvorbis_bug = 0; if (vr_type == 2) { for (j = 1; j < ch; ++j) @@ -1369,8 +1388,13 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, } if (max_output > ch_left * vlen) { - av_log(vc->avctx, AV_LOG_ERROR, "Insufficient output buffer\n"); - return AVERROR_INVALIDDATA; + if (max_output <= ch_left * vlen + vr->partition_size*ch_used/ch) { + ptns_to_read--; + libvorbis_bug = 1; + } else { + av_log(vc->avctx, AV_LOG_ERROR, "Insufficient output buffer\n"); + return AVERROR_INVALIDDATA; + } } av_dlog(NULL, " residue type 0/1/2 decode begin, ch: %d cpc %d \n", ch, c_p_c); @@ -1381,7 +1405,9 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, voffset = vr->begin; for (partition_count = 0; partition_count < ptns_to_read;) { // SPEC error if (!pass) { - setup_classifs(vc, vr, do_not_decode, ch_used, partition_count); + int ret; + if ((ret = setup_classifs(vc, vr, do_not_decode, ch_used, partition_count, ptns_to_read)) < 0) + return ret; } for (i = 0; (i < c_p_c) && (partition_count < ptns_to_read); ++i) { for (j_times_ptns_to_read = 0, j = 0; j < ch_used; ++j) { @@ -1477,6 +1503,14 @@ static av_always_inline int vorbis_residue_decode_internal(vorbis_context *vc, voffset += vr->partition_size; } } + if (libvorbis_bug && !pass) { + for (j = 0; j < ch_used; ++j) { + if (!do_not_decode[j]) { + get_vlc2(&vc->gb, vc->codebooks[vr->classbook].vlc.table, + vc->codebooks[vr->classbook].nb_bits, 3); + } + } + } } return 0; } @@ -1529,7 +1563,7 @@ static int vorbis_parse_audio_packet(vorbis_context *vc, float **floor_ptr) { GetBitContext *gb = &vc->gb; FFTContext *mdct; - unsigned previous_window = vc->previous_window; + int previous_window = vc->previous_window; unsigned mode_number, blockflag, blocksize; int i, j; uint8_t no_residue[255]; @@ -1562,9 +1596,11 @@ static int vorbis_parse_audio_packet(vorbis_context *vc, float **floor_ptr) blocksize = vc->blocksize[blockflag]; vlen = blocksize / 2; if (blockflag) { - previous_window = get_bits(gb, 1); - skip_bits1(gb); // next_window - } + int code = get_bits(gb, 2); + if (previous_window < 0) + previous_window = code>>1; + } else if (previous_window < 0) + previous_window = 0; memset(ch_res_ptr, 0, sizeof(float) * vc->audio_channels * vlen); //FIXME can this be removed ? for (i = 0; i < vc->audio_channels; ++i) @@ -1699,12 +1735,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++) @@ -1756,7 +1829,8 @@ static av_cold void vorbis_decode_flush(AVCodecContext *avctx) memset(vc->saved, 0, (vc->blocksize[1] / 4) * vc->audio_channels * sizeof(*vc->saved)); } - vc->previous_window = 0; + vc->previous_window = -1; + vc->first_frame = 0; } AVCodec ff_vorbis_decoder = { |