History

adx: add an ADX parser.

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.

Justin Ruggles committed 14 years ago

Commit 27360cc1 parent d8cec2d7 files · +154 −60Browse files

Unified · Split

7 files
  1. libavcodec/Makefile +1 −0
  2. libavcodec/adx.h +1 −2
  3. libavcodec/adx_parser.c +104 −0
  4. libavcodec/adxdec.c +44 −56
  5. libavcodec/allcodecs.c +1 −0
  6. libavcodec/version.h +2 −2
  7. libavformat/segafilm.c +1 −0
libavcodec/Makefile+1−0
@@ -595,6 +595,7 @@ OBJS-$(CONFIG_AAC_PARSER) += aac_parser.o aac_ac3_parser.o \ · 594 unmodified lines
595 aacadtsdec.o mpeg4audio.o595 aacadtsdec.o mpeg4audio.o
596OBJS-$(CONFIG_AC3_PARSER) += ac3_parser.o ac3tab.o \596OBJS-$(CONFIG_AC3_PARSER) += ac3_parser.o ac3tab.o \
597 aac_ac3_parser.o597 aac_ac3_parser.o
598OBJS-$(CONFIG_ADX_PARSER) += adx_parser.o adx.o
598OBJS-$(CONFIG_CAVSVIDEO_PARSER) += cavs_parser.o599OBJS-$(CONFIG_CAVSVIDEO_PARSER) += cavs_parser.o
599OBJS-$(CONFIG_DCA_PARSER) += dca_parser.o600OBJS-$(CONFIG_DCA_PARSER) += dca_parser.o
600OBJS-$(CONFIG_DIRAC_PARSER) += dirac_parser.o601OBJS-$(CONFIG_DIRAC_PARSER) += dirac_parser.o
libavcodec/adx.h+1−2
@@ -43,8 +43,7 @@ typedef struct { · 42 unmodified lines
43 int channels;43 int channels;
44 ADXChannelState prev[2];44 ADXChannelState prev[2];
45 int header_parsed;45 int header_parsed;
46 unsigned char dec_temp[18*2];46 int eof;
47 int in_temp;
48 int cutoff;47 int cutoff;
49 int coeff[2];48 int coeff[2];
50} ADXContext;49} ADXContext;
libavcodec/adx_parser.c+104−0
@@ -0,0 +1,104 @@
1/*
2 * Copyright (c) 2011 Justin Ruggles
3 *
4 * This file is part of Libav.
5 *
6 * Libav is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * Libav is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with Libav; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/**
22 * @file
23 * ADX audio parser
24 *
25 * Reads header to extradata and splits packets into individual blocks.
26 */
27
28#include "libavutil/intreadwrite.h"
29#include "parser.h"
30#include "adx.h"
31
32typedef struct ADXParseContext {
33 ParseContext pc;
34 int header_size;
35 int block_size;
36 int buf_pos;
37} ADXParseContext;
38
39#define MIN_HEADER_SIZE 24
40
41static int adx_parse(AVCodecParserContext *s1,
42 AVCodecContext *avctx,
43 const uint8_t **poutbuf, int *poutbuf_size,
44 const uint8_t *buf, int buf_size)
45{
46 ADXParseContext *s = s1->priv_data;
47 ParseContext *pc = &s->pc;
48 int next = END_NOT_FOUND;
49
50 if (!avctx->extradata_size) {
51 int ret;
52
53 ff_combine_frame(pc, END_NOT_FOUND, &buf, &buf_size);
54
55 if (!s->header_size && pc->index >= MIN_HEADER_SIZE) {
56 if (ret = ff_adx_decode_header(avctx, pc->buffer, pc->index,
57 &s->header_size, NULL))
58 return AVERROR_INVALIDDATA;
59 s->block_size = BLOCK_SIZE * avctx->channels;
60 }
61 if (s->header_size && s->header_size <= pc->index) {
62 avctx->extradata = av_mallocz(s->header_size + FF_INPUT_BUFFER_PADDING_SIZE);
63 if (!avctx->extradata)
64 return AVERROR(ENOMEM);
65 avctx->extradata_size = s->header_size;
66 memcpy(avctx->extradata, pc->buffer, s->header_size);
67 memmove(pc->buffer, pc->buffer + s->header_size, s->header_size);
68 pc->index -= s->header_size;
69 }
70 *poutbuf = NULL;
71 *poutbuf_size = 0;
72 return buf_size;
73 }
74
75 if (pc->index - s->buf_pos >= s->block_size) {
76 *poutbuf = &pc->buffer[s->buf_pos];
77 *poutbuf_size = s->block_size;
78 s->buf_pos += s->block_size;
79 return 0;
80 }
81 if (pc->index && s->buf_pos) {
82 memmove(pc->buffer, &pc->buffer[s->buf_pos], pc->index - s->buf_pos);
83 pc->index -= s->buf_pos;
84 s->buf_pos = 0;
85 }
86 if (buf_size + pc->index >= s->block_size)
87 next = s->block_size - pc->index;
88
89 if (ff_combine_frame(pc, next, &buf, &buf_size) < 0 || !buf_size) {
90 *poutbuf = NULL;
91 *poutbuf_size = 0;
92 return buf_size;
93 }
94 *poutbuf = buf;
95 *poutbuf_size = buf_size;
96 return next;
97}
98
99AVCodecParser ff_adx_parser = {
100 .codec_ids = { CODEC_ID_ADPCM_ADX },
101 .priv_data_size = sizeof(ADXParseContext),
102 .parser_parse = adx_parse,
103 .parser_close = ff_parse_close,
104};
libavcodec/adxdec.c+44−56
@@ -35,6 +35,19 @@ · 34 unmodified lines
35 35
36static av_cold int adx_decode_init(AVCodecContext *avctx)36static av_cold int adx_decode_init(AVCodecContext *avctx)
37{37{
38 ADXContext *c = avctx->priv_data;
39 int ret, header_size;
40
41 if (avctx->extradata_size < 24)
42 return AVERROR_INVALIDDATA;
43
44 if ((ret = ff_adx_decode_header(avctx, avctx->extradata, avctx->extradata_size,
45 &header_size, c->coeff)) < 0) {
46 av_log(avctx, AV_LOG_ERROR, "error parsing ADX header\n");
47 return AVERROR_INVALIDDATA;
48 }
49 c->channels = avctx->channels;
50
38 avctx->sample_fmt = AV_SAMPLE_FMT_S16;51 avctx->sample_fmt = AV_SAMPLE_FMT_S16;
39 return 0;52 return 0;
40}53}
@@ -46,7 +59,7 @@ static av_cold int adx_decode_init(AVCodecContext *avctx) · 5 unmodified lines
46 * 2nd-order LPC filter applied to it to form the output signal for a single59 * 2nd-order LPC filter applied to it to form the output signal for a single
47 * channel.60 * channel.
48 */61 */
49static void adx_decode(ADXContext *c, int16_t *out, const uint8_t *in, int ch)62static int adx_decode(ADXContext *c, int16_t *out, const uint8_t *in, int ch)
50{63{
51 ADXChannelState *prev = &c->prev[ch];64 ADXChannelState *prev = &c->prev[ch];
52 GetBitContext gb;65 GetBitContext gb;
@@ -54,6 +67,10 @@ static void adx_decode(ADXContext *c, int16_t *out, const uint8_t *in, int ch) · 1 unmodified line
54 int i;67 int i;
55 int s0, s1, s2, d;68 int s0, s1, s2, d;
56 69
70 /* check if this is an EOF packet */
71 if (scale & 0x8000)
72 return -1;
73
57 init_get_bits(&gb, in + 2, (BLOCK_SIZE - 2) * 8);74 init_get_bits(&gb, in + 2, (BLOCK_SIZE - 2) * 8);
58 s1 = prev->s1;75 s1 = prev->s1;
59 s2 = prev->s2;76 s2 = prev->s2;
@@ -67,84 +84,55 @@ static void adx_decode(ADXContext *c, int16_t *out, const uint8_t *in, int ch) · 7 unmodified lines
67 }84 }
68 prev->s1 = s1;85 prev->s1 = s1;
69 prev->s2 = s2;86 prev->s2 = s2;
70}
71
72static int adx_decode_header(AVCodecContext *avctx, const uint8_t *buf,
73 int bufsize)
74{
75 ADXContext *c = avctx->priv_data;
76 int ret, header_size;
77 87
78 if ((ret = ff_adx_decode_header(avctx, buf, bufsize, &header_size,88 return 0;
79 c->coeff)) < 0)
80 return ret;
81
82 c->channels = avctx->channels;
83 return header_size;
84}89}
85 90
86static int adx_decode_frame(AVCodecContext *avctx, void *data, int *data_size,91static int adx_decode_frame(AVCodecContext *avctx, void *data, int *data_size,
87 AVPacket *avpkt)92 AVPacket *avpkt)
88{93{
89 const uint8_t *buf0 = avpkt->data;
90 int buf_size = avpkt->size;94 int buf_size = avpkt->size;
91 ADXContext *c = avctx->priv_data;95 ADXContext *c = avctx->priv_data;
92 int16_t *samples = data;96 int16_t *samples = data;
93 const uint8_t *buf = buf0;97 const uint8_t *buf = avpkt->data;
94 int rest = buf_size;98 int num_blocks, ch;
95 int num_blocks;99
96 100 if (c->eof) {
97 if (!c->header_parsed) {101 *data_size = 0;
98 int hdrsize = adx_decode_header(avctx, buf, rest);102 return buf_size;
99 if (hdrsize < 0) {
100 av_log(avctx, AV_LOG_ERROR, "invalid stream header\n");
101 return hdrsize;
102 }
103 c->header_parsed = 1;
104 buf += hdrsize;
105 rest -= hdrsize;
106 }103 }
107 104
108 /* 18 bytes of data are expanded into 32*2 bytes of audio,105 /* 18 bytes of data are expanded into 32*2 bytes of audio,
109 so guard against buffer overflows */106 so guard against buffer overflows */
110 num_blocks = (rest + c->in_temp) / (BLOCK_SIZE * c->channels);107 num_blocks = buf_size / (BLOCK_SIZE * c->channels);
111 if (num_blocks > *data_size / (BLOCK_SAMPLES * c->channels)) {108 if (num_blocks > *data_size / (BLOCK_SAMPLES * c->channels)) {
112 rest = (*data_size / (BLOCK_SAMPLES * c->channels)) * BLOCK_SIZE;109 buf_size = (*data_size / (BLOCK_SAMPLES * c->channels)) * BLOCK_SIZE;
113 num_blocks = (rest + c->in_temp) / (BLOCK_SIZE * c->channels);110 num_blocks = buf_size / (BLOCK_SIZE * c->channels);
114 }111 }
115 if (!num_blocks) {112 if (!buf_size || buf_size % (BLOCK_SIZE * avctx->channels)) {
116 av_log(avctx, AV_LOG_ERROR, "packet is too small\n");113 if (buf_size >= 4 && (AV_RB16(buf) & 0x8000)) {
114 c->eof = 1;
115 *data_size = 0;
116 return avpkt->size;
117 }
117 return AVERROR_INVALIDDATA;118 return AVERROR_INVALIDDATA;
118 }119 }
119 120
120 if (c->in_temp) {
121 int copysize = BLOCK_SIZE * avctx->channels - c->in_temp;
122 memcpy(c->dec_temp + c->in_temp, buf, copysize);
123 rest -= copysize;
124 buf += copysize;
125 adx_decode(c, samples, c->dec_temp, 0);
126 if (avctx->channels == 2)
127 adx_decode(c, samples + 1, c->dec_temp + BLOCK_SIZE, 1);
128 samples += BLOCK_SAMPLES * c->channels;
129 num_blocks--;
130 }
131
132 while (num_blocks--) {121 while (num_blocks--) {
133 adx_decode(c, samples, buf, 0);122 for (ch = 0; ch < c->channels; ch++) {
134 if (c->channels == 2)123 if (adx_decode(c, samples + ch, buf, ch)) {
135 adx_decode(c, samples + 1, buf + BLOCK_SIZE, 1);124 c->eof = 1;
136 rest -= BLOCK_SIZE * c->channels;125 buf = avpkt->data + avpkt->size;
137 buf += BLOCK_SIZE * c->channels;126 break;
127 }
128 buf_size -= BLOCK_SIZE;
129 buf += BLOCK_SIZE;
130 }
138 samples += BLOCK_SAMPLES * c->channels;131 samples += BLOCK_SAMPLES * c->channels;
139 }132 }
140 133
141 c->in_temp = rest;
142 if (rest) {
143 memcpy(c->dec_temp, buf, rest);
144 buf += rest;
145 }
146 *data_size = (uint8_t*)samples - (uint8_t*)data;134 *data_size = (uint8_t*)samples - (uint8_t*)data;
147 return buf - buf0;135 return buf - avpkt->data;
148}136}
149 137
150AVCodec ff_adpcm_adx_decoder = {138AVCodec ff_adpcm_adx_decoder = {
libavcodec/allcodecs.c+1−0
@@ -388,6 +388,7 @@ void avcodec_register_all(void) · 387 unmodified lines
388 REGISTER_PARSER (AAC, aac);388 REGISTER_PARSER (AAC, aac);
389 REGISTER_PARSER (AAC_LATM, aac_latm);389 REGISTER_PARSER (AAC_LATM, aac_latm);
390 REGISTER_PARSER (AC3, ac3);390 REGISTER_PARSER (AC3, ac3);
391 REGISTER_PARSER (ADX, adx);
391 REGISTER_PARSER (CAVSVIDEO, cavsvideo);392 REGISTER_PARSER (CAVSVIDEO, cavsvideo);
392 REGISTER_PARSER (DCA, dca);393 REGISTER_PARSER (DCA, dca);
393 REGISTER_PARSER (DIRAC, dirac);394 REGISTER_PARSER (DIRAC, dirac);
libavcodec/version.h+2−2
@@ -21,8 +21,8 @@ · 20 unmodified lines
21#define AVCODEC_VERSION_H21#define AVCODEC_VERSION_H
22 22
23#define LIBAVCODEC_VERSION_MAJOR 5323#define LIBAVCODEC_VERSION_MAJOR 53
24#define LIBAVCODEC_VERSION_MINOR 2224#define LIBAVCODEC_VERSION_MINOR 23
25#define LIBAVCODEC_VERSION_MICRO 125#define LIBAVCODEC_VERSION_MICRO 0
26 26
27#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \27#define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
28 LIBAVCODEC_VERSION_MINOR, \28 LIBAVCODEC_VERSION_MINOR, \
libavformat/segafilm.c+1−0
@@ -172,6 +172,7 @@ static int film_read_header(AVFormatContext *s, · 171 unmodified lines
172 if (film->audio_type == CODEC_ID_ADPCM_ADX) {172 if (film->audio_type == CODEC_ID_ADPCM_ADX) {
173 st->codec->bits_per_coded_sample = 18 * 8 / 32;173 st->codec->bits_per_coded_sample = 18 * 8 / 32;
174 st->codec->block_align = st->codec->channels * 18;174 st->codec->block_align = st->codec->channels * 18;
175 st->need_parsing = AVSTREAM_PARSE_FULL;
175 } else {176 } else {
176 st->codec->bits_per_coded_sample = film->audio_bits;177 st->codec->bits_per_coded_sample = film->audio_bits;
177 st->codec->block_align = st->codec->channels *178 st->codec->block_align = st->codec->channels *

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t