@@ -18,6 +18,7 @@ | |||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |||
*/ | |||
#include "libavutil/intreadwrite.h" | |||
#include "libavutil/mathematics.h" | |||
#include "adx.h" | |||
@@ -32,3 +33,49 @@ void ff_adx_calculate_coeffs(int cutoff, int sample_rate, int bits, int *coeff) | |||
coeff[0] = lrintf(c * 2.0 * (1 << bits)); | |||
coeff[1] = lrintf(-(c * c) * (1 << bits)); | |||
} | |||
int ff_adx_decode_header(AVCodecContext *avctx, const uint8_t *buf, int bufsize, | |||
int *header_size, int *coeff) | |||
{ | |||
int offset, cutoff; | |||
if (bufsize < 24) | |||
return AVERROR_INVALIDDATA; | |||
if (AV_RB16(buf) != 0x8000) | |||
return AVERROR_INVALIDDATA; | |||
offset = AV_RB16(buf + 2) + 4; | |||
/* if copyright string is within the provided data, validate it */ | |||
if (bufsize >= offset && memcmp(buf + offset - 6, "(c)CRI", 6)) | |||
return AVERROR_INVALIDDATA; | |||
/* check for encoding=3 block_size=18, sample_size=4 */ | |||
if (buf[4] != 3 || buf[5] != 18 || buf[6] != 4) { | |||
av_log_ask_for_sample(avctx, "unsupported ADX format\n"); | |||
return AVERROR_PATCHWELCOME; | |||
} | |||
/* channels */ | |||
avctx->channels = buf[7]; | |||
if (avctx->channels > 2) | |||
return AVERROR_INVALIDDATA; | |||
/* sample rate */ | |||
avctx->sample_rate = AV_RB32(buf + 8); | |||
if (avctx->sample_rate < 1 || | |||
avctx->sample_rate > INT_MAX / (avctx->channels * BLOCK_SIZE * 8)) | |||
return AVERROR_INVALIDDATA; | |||
/* bit rate */ | |||
avctx->bit_rate = avctx->sample_rate * avctx->channels * BLOCK_SIZE * 8 / BLOCK_SAMPLES; | |||
/* LPC coefficients */ | |||
if (coeff) { | |||
cutoff = AV_RB16(buf + 16); | |||
ff_adx_calculate_coeffs(cutoff, avctx->sample_rate, COEFF_BITS, coeff); | |||
} | |||
*header_size = offset; | |||
return 0; | |||
} |
@@ -31,6 +31,10 @@ | |||
#ifndef AVCODEC_ADX_H | |||
#define AVCODEC_ADX_H | |||
#include <stdint.h> | |||
#include "avcodec.h" | |||
typedef struct { | |||
int s1,s2; | |||
} ADXChannelState; | |||
@@ -47,6 +51,9 @@ typedef struct { | |||
#define COEFF_BITS 12 | |||
#define BLOCK_SIZE 18 | |||
#define BLOCK_SAMPLES 32 | |||
/** | |||
* Calculate LPC coefficients based on cutoff frequency and sample rate. | |||
* | |||
@@ -57,4 +64,18 @@ typedef struct { | |||
*/ | |||
void ff_adx_calculate_coeffs(int cutoff, int sample_rate, int bits, int *coeff); | |||
/** | |||
* Decode ADX stream header. | |||
* Sets avctx->channels and avctx->sample_rate. | |||
* | |||
* @param avctx codec context | |||
* @param buf header data | |||
* @param bufsize data size, should be at least 24 bytes | |||
* @param[out] header_size size of ADX header | |||
* @param[out] coeff 2 LPC coefficients, can be NULL | |||
* @return data offset or negative error code if header is invalid | |||
*/ | |||
int ff_adx_decode_header(AVCodecContext *avctx, const uint8_t *buf, int bufsize, | |||
int *header_size, int *coeff); | |||
#endif /* AVCODEC_ADX_H */ |
@@ -33,9 +33,6 @@ | |||
* adx2wav & wav2adx http://www.geocities.co.jp/Playtown/2004/ | |||
*/ | |||
#define BLOCK_SIZE 18 | |||
#define BLOCK_SAMPLES 32 | |||
static av_cold int adx_decode_init(AVCodecContext *avctx) | |||
{ | |||
avctx->sample_fmt = AV_SAMPLE_FMT_S16; | |||
@@ -72,45 +69,18 @@ static void adx_decode(ADXContext *c, int16_t *out, const uint8_t *in, int ch) | |||
prev->s2 = s2; | |||
} | |||
/** | |||
* Decode stream header. | |||
* | |||
* @param avctx codec context | |||
* @param buf packet data | |||
* @param bufsize packet size | |||
* @return data offset or negative error code if header is invalid | |||
*/ | |||
static int adx_decode_header(AVCodecContext *avctx, const uint8_t *buf, | |||
int bufsize) | |||
{ | |||
ADXContext *c = avctx->priv_data; | |||
int offset, cutoff; | |||
if (AV_RB16(buf) != 0x8000) | |||
return AVERROR_INVALIDDATA; | |||
offset = AV_RB16(buf + 2) + 4; | |||
if (bufsize < offset || memcmp(buf + offset - 6, "(c)CRI", 6)) | |||
return AVERROR_INVALIDDATA; | |||
/* check for encoding=3 block_size=18, sample_size=4 */ | |||
if (buf[4] != 3 || buf[5] != 18 || buf[6] != 4) { | |||
av_log_ask_for_sample(avctx, "unsupported ADX format\n"); | |||
return AVERROR_PATCHWELCOME; | |||
} | |||
c->channels = avctx->channels = buf[7]; | |||
if (avctx->channels > 2) | |||
return AVERROR_INVALIDDATA; | |||
avctx->sample_rate = AV_RB32(buf + 8); | |||
if (avctx->sample_rate < 1 || | |||
avctx->sample_rate > INT_MAX / (avctx->channels * BLOCK_SIZE * 8)) | |||
return AVERROR_INVALIDDATA; | |||
avctx->bit_rate = avctx->sample_rate * avctx->channels * BLOCK_SIZE * 8 / BLOCK_SAMPLES; | |||
int ret, header_size; | |||
cutoff = AV_RB16(buf + 16); | |||
ff_adx_calculate_coeffs(cutoff, avctx->sample_rate, COEFF_BITS, c->coeff); | |||
if ((ret = ff_adx_decode_header(avctx, buf, bufsize, &header_size, | |||
c->coeff)) < 0) | |||
return ret; | |||
return offset; | |||
c->channels = avctx->channels; | |||
return header_size; | |||
} | |||
static int adx_decode_frame(AVCodecContext *avctx, void *data, int *data_size, | |||