mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-01-24 13:56:33 +02:00
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.
This commit is contained in:
parent
d8cec2d7fc
commit
27360ccc5e
@ -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;
|
||||
|
104
libavcodec/adx_parser.c
Normal file
104
libavcodec/adx_parser.c
Normal file
@ -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;
|
||||
const uint8_t *buf = avpkt->data;
|
||||
int num_blocks, ch;
|
||||
|
||||
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;
|
||||
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 *
|
||||
|
Loading…
x
Reference in New Issue
Block a user