This simplifies the decoder so it doesn't have to process an in-packet header or handle arbitrary-sized packets. It also fixes decoding of files with large headers.tags/n0.9
| @@ -595,6 +595,7 @@ OBJS-$(CONFIG_AAC_PARSER) += aac_parser.o aac_ac3_parser.o \ | |||
| aacadtsdec.o mpeg4audio.o | |||
| OBJS-$(CONFIG_AC3_PARSER) += ac3_parser.o ac3tab.o \ | |||
| aac_ac3_parser.o | |||
| OBJS-$(CONFIG_ADX_PARSER) += adx_parser.o adx.o | |||
| OBJS-$(CONFIG_CAVSVIDEO_PARSER) += cavs_parser.o | |||
| OBJS-$(CONFIG_DCA_PARSER) += dca_parser.o | |||
| OBJS-$(CONFIG_DIRAC_PARSER) += dirac_parser.o | |||
| @@ -43,8 +43,7 @@ typedef struct { | |||
| int channels; | |||
| ADXChannelState prev[2]; | |||
| int header_parsed; | |||
| unsigned char dec_temp[18*2]; | |||
| int in_temp; | |||
| int eof; | |||
| int cutoff; | |||
| int coeff[2]; | |||
| } ADXContext; | |||
| @@ -0,0 +1,104 @@ | |||
| /* | |||
| * Copyright (c) 2011 Justin Ruggles | |||
| * | |||
| * This file is part of Libav. | |||
| * | |||
| * Libav 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, | |||
| * 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 | |||
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
| */ | |||
| /** | |||
| * @file | |||
| * ADX audio parser | |||
| * | |||
| * Reads header to extradata and splits packets into individual blocks. | |||
| */ | |||
| #include "libavutil/intreadwrite.h" | |||
| #include "parser.h" | |||
| #include "adx.h" | |||
| typedef struct ADXParseContext { | |||
| ParseContext pc; | |||
| int header_size; | |||
| int block_size; | |||
| int buf_pos; | |||
| } ADXParseContext; | |||
| #define MIN_HEADER_SIZE 24 | |||
| static int adx_parse(AVCodecParserContext *s1, | |||
| AVCodecContext *avctx, | |||
| const uint8_t **poutbuf, int *poutbuf_size, | |||
| const uint8_t *buf, int buf_size) | |||
| { | |||
| ADXParseContext *s = s1->priv_data; | |||
| ParseContext *pc = &s->pc; | |||
| int next = END_NOT_FOUND; | |||
| if (!avctx->extradata_size) { | |||
| int ret; | |||
| ff_combine_frame(pc, END_NOT_FOUND, &buf, &buf_size); | |||
| if (!s->header_size && pc->index >= MIN_HEADER_SIZE) { | |||
| if (ret = ff_adx_decode_header(avctx, pc->buffer, pc->index, | |||
| &s->header_size, NULL)) | |||
| return AVERROR_INVALIDDATA; | |||
| s->block_size = BLOCK_SIZE * avctx->channels; | |||
| } | |||
| if (s->header_size && s->header_size <= pc->index) { | |||
| avctx->extradata = av_mallocz(s->header_size + FF_INPUT_BUFFER_PADDING_SIZE); | |||
| if (!avctx->extradata) | |||
| return AVERROR(ENOMEM); | |||
| avctx->extradata_size = s->header_size; | |||
| memcpy(avctx->extradata, pc->buffer, s->header_size); | |||
| memmove(pc->buffer, pc->buffer + s->header_size, s->header_size); | |||
| pc->index -= s->header_size; | |||
| } | |||
| *poutbuf = NULL; | |||
| *poutbuf_size = 0; | |||
| return buf_size; | |||
| } | |||
| if (pc->index - s->buf_pos >= s->block_size) { | |||
| *poutbuf = &pc->buffer[s->buf_pos]; | |||
| *poutbuf_size = s->block_size; | |||
| s->buf_pos += s->block_size; | |||
| return 0; | |||
| } | |||
| if (pc->index && s->buf_pos) { | |||
| memmove(pc->buffer, &pc->buffer[s->buf_pos], pc->index - s->buf_pos); | |||
| pc->index -= s->buf_pos; | |||
| s->buf_pos = 0; | |||
| } | |||
| if (buf_size + pc->index >= s->block_size) | |||
| next = s->block_size - pc->index; | |||
| if (ff_combine_frame(pc, next, &buf, &buf_size) < 0 || !buf_size) { | |||
| *poutbuf = NULL; | |||
| *poutbuf_size = 0; | |||
| return buf_size; | |||
| } | |||
| *poutbuf = buf; | |||
| *poutbuf_size = buf_size; | |||
| return next; | |||
| } | |||
| AVCodecParser ff_adx_parser = { | |||
| .codec_ids = { CODEC_ID_ADPCM_ADX }, | |||
| .priv_data_size = sizeof(ADXParseContext), | |||
| .parser_parse = adx_parse, | |||
| .parser_close = ff_parse_close, | |||
| }; | |||
| @@ -35,6 +35,19 @@ | |||
| static av_cold int adx_decode_init(AVCodecContext *avctx) | |||
| { | |||
| ADXContext *c = avctx->priv_data; | |||
| int ret, header_size; | |||
| if (avctx->extradata_size < 24) | |||
| return AVERROR_INVALIDDATA; | |||
| if ((ret = ff_adx_decode_header(avctx, avctx->extradata, avctx->extradata_size, | |||
| &header_size, c->coeff)) < 0) { | |||
| av_log(avctx, AV_LOG_ERROR, "error parsing ADX header\n"); | |||
| return AVERROR_INVALIDDATA; | |||
| } | |||
| c->channels = avctx->channels; | |||
| avctx->sample_fmt = AV_SAMPLE_FMT_S16; | |||
| return 0; | |||
| } | |||
| @@ -46,7 +59,7 @@ static av_cold int adx_decode_init(AVCodecContext *avctx) | |||
| * 2nd-order LPC filter applied to it to form the output signal for a single | |||
| * channel. | |||
| */ | |||
| static void adx_decode(ADXContext *c, int16_t *out, const uint8_t *in, int ch) | |||
| static int adx_decode(ADXContext *c, int16_t *out, const uint8_t *in, int ch) | |||
| { | |||
| ADXChannelState *prev = &c->prev[ch]; | |||
| GetBitContext gb; | |||
| @@ -54,6 +67,10 @@ static void adx_decode(ADXContext *c, int16_t *out, const uint8_t *in, int ch) | |||
| int i; | |||
| int s0, s1, s2, d; | |||
| /* check if this is an EOF packet */ | |||
| if (scale & 0x8000) | |||
| return -1; | |||
| init_get_bits(&gb, in + 2, (BLOCK_SIZE - 2) * 8); | |||
| s1 = prev->s1; | |||
| s2 = prev->s2; | |||
| @@ -67,84 +84,55 @@ static void adx_decode(ADXContext *c, int16_t *out, const uint8_t *in, int ch) | |||
| } | |||
| prev->s1 = s1; | |||
| prev->s2 = s2; | |||
| } | |||
| static int adx_decode_header(AVCodecContext *avctx, const uint8_t *buf, | |||
| int bufsize) | |||
| { | |||
| ADXContext *c = avctx->priv_data; | |||
| int ret, header_size; | |||
| if ((ret = ff_adx_decode_header(avctx, buf, bufsize, &header_size, | |||
| c->coeff)) < 0) | |||
| return ret; | |||
| c->channels = avctx->channels; | |||
| return header_size; | |||
| return 0; | |||
| } | |||
| static int adx_decode_frame(AVCodecContext *avctx, void *data, int *data_size, | |||
| AVPacket *avpkt) | |||
| { | |||
| const uint8_t *buf0 = avpkt->data; | |||
| int buf_size = avpkt->size; | |||
| ADXContext *c = avctx->priv_data; | |||
| int16_t *samples = data; | |||
| const uint8_t *buf = buf0; | |||
| int rest = buf_size; | |||
| int num_blocks; | |||
| if (!c->header_parsed) { | |||
| int hdrsize = adx_decode_header(avctx, buf, rest); | |||
| if (hdrsize < 0) { | |||
| av_log(avctx, AV_LOG_ERROR, "invalid stream header\n"); | |||
| return hdrsize; | |||
| } | |||
| c->header_parsed = 1; | |||
| buf += hdrsize; | |||
| rest -= hdrsize; | |||
| const uint8_t *buf = avpkt->data; | |||
| int num_blocks, ch; | |||
| if (c->eof) { | |||
| *data_size = 0; | |||
| return buf_size; | |||
| } | |||
| /* 18 bytes of data are expanded into 32*2 bytes of audio, | |||
| so guard against buffer overflows */ | |||
| num_blocks = (rest + c->in_temp) / (BLOCK_SIZE * c->channels); | |||
| num_blocks = buf_size / (BLOCK_SIZE * c->channels); | |||
| if (num_blocks > *data_size / (BLOCK_SAMPLES * c->channels)) { | |||
| rest = (*data_size / (BLOCK_SAMPLES * c->channels)) * BLOCK_SIZE; | |||
| num_blocks = (rest + c->in_temp) / (BLOCK_SIZE * c->channels); | |||
| buf_size = (*data_size / (BLOCK_SAMPLES * c->channels)) * BLOCK_SIZE; | |||
| num_blocks = buf_size / (BLOCK_SIZE * c->channels); | |||
| } | |||
| if (!num_blocks) { | |||
| av_log(avctx, AV_LOG_ERROR, "packet is too small\n"); | |||
| if (!buf_size || buf_size % (BLOCK_SIZE * avctx->channels)) { | |||
| if (buf_size >= 4 && (AV_RB16(buf) & 0x8000)) { | |||
| c->eof = 1; | |||
| *data_size = 0; | |||
| return avpkt->size; | |||
| } | |||
| return AVERROR_INVALIDDATA; | |||
| } | |||
| if (c->in_temp) { | |||
| int copysize = BLOCK_SIZE * avctx->channels - c->in_temp; | |||
| memcpy(c->dec_temp + c->in_temp, buf, copysize); | |||
| rest -= copysize; | |||
| buf += copysize; | |||
| adx_decode(c, samples, c->dec_temp, 0); | |||
| if (avctx->channels == 2) | |||
| adx_decode(c, samples + 1, c->dec_temp + BLOCK_SIZE, 1); | |||
| samples += BLOCK_SAMPLES * c->channels; | |||
| num_blocks--; | |||
| } | |||
| while (num_blocks--) { | |||
| adx_decode(c, samples, buf, 0); | |||
| if (c->channels == 2) | |||
| adx_decode(c, samples + 1, buf + BLOCK_SIZE, 1); | |||
| rest -= BLOCK_SIZE * c->channels; | |||
| buf += BLOCK_SIZE * c->channels; | |||
| for (ch = 0; ch < c->channels; ch++) { | |||
| if (adx_decode(c, samples + ch, buf, ch)) { | |||
| c->eof = 1; | |||
| buf = avpkt->data + avpkt->size; | |||
| break; | |||
| } | |||
| buf_size -= BLOCK_SIZE; | |||
| buf += BLOCK_SIZE; | |||
| } | |||
| samples += BLOCK_SAMPLES * c->channels; | |||
| } | |||
| c->in_temp = rest; | |||
| if (rest) { | |||
| memcpy(c->dec_temp, buf, rest); | |||
| buf += rest; | |||
| } | |||
| *data_size = (uint8_t*)samples - (uint8_t*)data; | |||
| return buf - buf0; | |||
| return buf - avpkt->data; | |||
| } | |||
| AVCodec ff_adpcm_adx_decoder = { | |||
| @@ -388,6 +388,7 @@ void avcodec_register_all(void) | |||
| REGISTER_PARSER (AAC, aac); | |||
| REGISTER_PARSER (AAC_LATM, aac_latm); | |||
| REGISTER_PARSER (AC3, ac3); | |||
| REGISTER_PARSER (ADX, adx); | |||
| REGISTER_PARSER (CAVSVIDEO, cavsvideo); | |||
| REGISTER_PARSER (DCA, dca); | |||
| REGISTER_PARSER (DIRAC, dirac); | |||
| @@ -21,8 +21,8 @@ | |||
| #define AVCODEC_VERSION_H | |||
| #define LIBAVCODEC_VERSION_MAJOR 53 | |||
| #define LIBAVCODEC_VERSION_MINOR 22 | |||
| #define LIBAVCODEC_VERSION_MICRO 1 | |||
| #define LIBAVCODEC_VERSION_MINOR 23 | |||
| #define LIBAVCODEC_VERSION_MICRO 0 | |||
| #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ | |||
| LIBAVCODEC_VERSION_MINOR, \ | |||
| @@ -172,6 +172,7 @@ static int film_read_header(AVFormatContext *s, | |||
| if (film->audio_type == CODEC_ID_ADPCM_ADX) { | |||
| st->codec->bits_per_coded_sample = 18 * 8 / 32; | |||
| st->codec->block_align = st->codec->channels * 18; | |||
| st->need_parsing = AVSTREAM_PARSE_FULL; | |||
| } else { | |||
| st->codec->bits_per_coded_sample = film->audio_bits; | |||
| st->codec->block_align = st->codec->channels * | |||