| @@ -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, | |||