diff options
Diffstat (limited to 'libavformat/tta.c')
-rw-r--r-- | libavformat/tta.c | 102 |
1 files changed, 64 insertions, 38 deletions
diff --git a/libavformat/tta.c b/libavformat/tta.c index bc86a77..7566939 100644 --- a/libavformat/tta.c +++ b/libavformat/tta.c @@ -2,27 +2,30 @@ * TTA demuxer * Copyright (c) 2006 Alex Beregszaszi * - * This file is part of Libav. + * 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 */ #include "libavcodec/get_bits.h" +#include "apetag.h" #include "avformat.h" +#include "avio_internal.h" #include "internal.h" #include "id3v1.h" +#include "libavutil/crc.h" #include "libavutil/dict.h" typedef struct TTAContext { @@ -31,11 +34,19 @@ typedef struct TTAContext { int last_frame_size; } TTAContext; -static int tta_probe(AVProbeData *p) +static unsigned long tta_check_crc(unsigned long checksum, const uint8_t *buf, + unsigned int len) { - const uint8_t *d = p->buf; + return av_crc(av_crc_get_table(AV_CRC_32_IEEE_LE), checksum, buf, len); +} - if (d[0] == 'T' && d[1] == 'T' && d[2] == 'A' && d[3] == '1') +static int tta_probe(AVProbeData *p) +{ + if (AV_RL32(&p->buf[0]) == MKTAG('T', 'T', 'A', '1') && + (AV_RL16(&p->buf[4]) == 1 || AV_RL16(&p->buf[4]) == 2) && + AV_RL16(&p->buf[6]) > 0 && + AV_RL16(&p->buf[8]) > 0 && + AV_RL32(&p->buf[10]) > 0) return AVPROBE_SCORE_EXTENSION + 30; return 0; } @@ -44,17 +55,18 @@ static int tta_read_header(AVFormatContext *s) { TTAContext *c = s->priv_data; AVStream *st; - int i, channels, bps, samplerate, datalen; + int i, channels, bps, samplerate; int64_t framepos, start_offset; + uint32_t nb_samples, crc; - if (!av_dict_get(s->metadata, "", NULL, AV_DICT_IGNORE_SUFFIX)) - ff_id3v1_read(s); + ff_id3v1_read(s); start_offset = avio_tell(s->pb); if (start_offset < 0) return start_offset; + ffio_init_checksum(s->pb, tta_check_crc, UINT32_MAX); if (avio_rl32(s->pb) != AV_RL32("TTA1")) - return -1; // not tta file + return AVERROR_INVALIDDATA; avio_skip(s->pb, 2); // FIXME: flags channels = avio_rl16(s->pb); @@ -62,27 +74,31 @@ static int tta_read_header(AVFormatContext *s) samplerate = avio_rl32(s->pb); if(samplerate <= 0 || samplerate > 1000000){ av_log(s, AV_LOG_ERROR, "nonsense samplerate\n"); - return -1; + return AVERROR_INVALIDDATA; } - datalen = avio_rl32(s->pb); - if(datalen < 0){ - av_log(s, AV_LOG_ERROR, "nonsense datalen\n"); - return -1; + nb_samples = avio_rl32(s->pb); + if (!nb_samples) { + av_log(s, AV_LOG_ERROR, "invalid number of samples\n"); + return AVERROR_INVALIDDATA; } - avio_skip(s->pb, 4); // header crc + crc = ffio_get_checksum(s->pb) ^ UINT32_MAX; + if (crc != avio_rl32(s->pb) && s->error_recognition & AV_EF_CRCCHECK) { + av_log(s, AV_LOG_ERROR, "Header CRC error\n"); + return AVERROR_INVALIDDATA; + } c->frame_size = samplerate * 256 / 245; - c->last_frame_size = datalen % c->frame_size; + c->last_frame_size = nb_samples % c->frame_size; if (!c->last_frame_size) c->last_frame_size = c->frame_size; - c->totalframes = datalen / c->frame_size + (c->last_frame_size < c->frame_size); + c->totalframes = nb_samples / c->frame_size + (c->last_frame_size < c->frame_size); c->currentframe = 0; - if(c->totalframes >= UINT_MAX/sizeof(uint32_t)){ - av_log(s, AV_LOG_ERROR, "totalframes too large\n"); - return -1; + if(c->totalframes >= UINT_MAX/sizeof(uint32_t) || c->totalframes <= 0){ + av_log(s, AV_LOG_ERROR, "totalframes %d invalid\n", c->totalframes); + return AVERROR_INVALIDDATA; } st = avformat_new_stream(s, NULL); @@ -91,20 +107,33 @@ static int tta_read_header(AVFormatContext *s) avpriv_set_pts_info(st, 64, 1, samplerate); st->start_time = 0; - st->duration = datalen; + st->duration = nb_samples; framepos = avio_tell(s->pb); if (framepos < 0) return framepos; framepos += 4 * c->totalframes + 4; + if (ff_alloc_extradata(st->codec, avio_tell(s->pb) - start_offset)) + return AVERROR(ENOMEM); + + avio_seek(s->pb, start_offset, SEEK_SET); + avio_read(s->pb, st->codec->extradata, st->codec->extradata_size); + + ffio_init_checksum(s->pb, tta_check_crc, UINT32_MAX); for (i = 0; i < c->totalframes; i++) { uint32_t size = avio_rl32(s->pb); - av_add_index_entry(st, framepos, i * c->frame_size, size, 0, - AVINDEX_KEYFRAME); + int r; + if ((r = av_add_index_entry(st, framepos, i * c->frame_size, size, 0, + AVINDEX_KEYFRAME)) < 0) + return r; framepos += size; } - avio_skip(s->pb, 4); // seektable crc + crc = ffio_get_checksum(s->pb) ^ UINT32_MAX; + if (crc != avio_rl32(s->pb) && s->error_recognition & AV_EF_CRCCHECK) { + av_log(s, AV_LOG_ERROR, "Seek table CRC error\n"); + return AVERROR_INVALIDDATA; + } st->codec->codec_type = AVMEDIA_TYPE_AUDIO; st->codec->codec_id = AV_CODEC_ID_TTA; @@ -112,19 +141,11 @@ static int tta_read_header(AVFormatContext *s) st->codec->sample_rate = samplerate; st->codec->bits_per_coded_sample = bps; - st->codec->extradata_size = avio_tell(s->pb) - start_offset; - if(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE <= (unsigned)st->codec->extradata_size){ - //this check is redundant as avio_read should fail - av_log(s, AV_LOG_ERROR, "extradata_size too large\n"); - return -1; - } - st->codec->extradata = av_mallocz(st->codec->extradata_size+FF_INPUT_BUFFER_PADDING_SIZE); - if (!st->codec->extradata) { - st->codec->extradata_size = 0; - return AVERROR(ENOMEM); + if (s->pb->seekable) { + int64_t pos = avio_tell(s->pb); + ff_ape_parse_tag(s); + avio_seek(s->pb, pos, SEEK_SET); } - avio_seek(s->pb, start_offset, SEEK_SET); - avio_read(s->pb, st->codec->extradata, st->codec->extradata_size); return 0; } @@ -139,6 +160,11 @@ static int tta_read_packet(AVFormatContext *s, AVPacket *pkt) if (c->currentframe >= c->totalframes) return AVERROR_EOF; + if (st->nb_index_entries < c->totalframes) { + av_log(s, AV_LOG_ERROR, "Index entry disappeared\n"); + return AVERROR_INVALIDDATA; + } + size = st->index_entries[c->currentframe].size; ret = av_get_packet(s->pb, pkt, size); |