/* * AC3 decoder * Copyright (c) 2001 Gerard Lantau. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include #include #include #include "avcodec.h" #include #include "libac3/ac3.h" /* currently, I use libac3 which is Copyright (C) Aaron Holtzman and released under the GPL license. I may reimplement it someday... */ typedef struct AC3DecodeState { UINT8 inbuf[4096]; /* input buffer */ UINT8 *inbuf_ptr; int frame_size; int flags; ac3_state_t state; } AC3DecodeState; static int ac3_decode_init(AVCodecContext *avctx) { AC3DecodeState *s = avctx->priv_data; ac3_init (); s->inbuf_ptr = s->inbuf; s->frame_size = 0; return 0; } stream_samples_t samples; /**** the following two functions comes from ac3dec */ static inline int blah (int32_t i) { if (i > 0x43c07fff) return 32767; else if (i < 0x43bf8000) return -32768; else return i - 0x43c00000; } static inline void float_to_int (float * _f, INT16 * s16) { int i; int32_t * f = (int32_t *) _f; // XXX assumes IEEE float format for (i = 0; i < 256; i++) { s16[2*i] = blah (f[i]); s16[2*i+1] = blah (f[i+256]); } } static inline void float_to_int_mono (float * _f, INT16 * s16) { int i; int32_t * f = (int32_t *) _f; // XXX assumes IEEE float format for (i = 0; i < 256; i++) { s16[i] = blah (f[i]); } } /**** end */ #define HEADER_SIZE 7 static int ac3_decode_frame(AVCodecContext *avctx, void *data, int *data_size, UINT8 *buf, int buf_size) { AC3DecodeState *s = avctx->priv_data; UINT8 *buf_ptr; int flags, i, len; int sample_rate, bit_rate; short *out_samples = data; float level; *data_size = 0; buf_ptr = buf; while (buf_size > 0) { len = s->inbuf_ptr - s->inbuf; if (s->frame_size == 0) { /* no header seen : find one. We need at least 7 bytes to parse it */ len = HEADER_SIZE - len; if (len > buf_size) len = buf_size; memcpy(s->inbuf_ptr, buf_ptr, len); buf_ptr += len; s->inbuf_ptr += len; buf_size -= len; if ((s->inbuf_ptr - s->inbuf) == HEADER_SIZE) { len = ac3_syncinfo (s->inbuf, &s->flags, &sample_rate, &bit_rate); if (len == 0) { /* no sync found : move by one byte (inefficient, but simple!) */ memcpy(s->inbuf, s->inbuf + 1, HEADER_SIZE - 1); s->inbuf_ptr--; } else { s->frame_size = len; /* update codec info */ avctx->sample_rate = sample_rate; if ((s->flags & AC3_CHANNEL_MASK) == AC3_MONO) avctx->channels = 1; else avctx->channels = 2; avctx->bit_rate = bit_rate; } } } else if (len < s->frame_size) { len = s->frame_size - len; if (len > buf_size) len = buf_size; memcpy(s->inbuf_ptr, buf_ptr, len); buf_ptr += len; s->inbuf_ptr += len; buf_size -= len; } else { if (avctx->channels == 1) flags = AC3_MONO; else flags = AC3_STEREO; flags |= AC3_ADJUST_LEVEL; level = 1; if (ac3_frame (&s->state, s->inbuf, &flags, &level, 384)) { fail: s->inbuf_ptr = s->inbuf; s->frame_size = 0; continue; } for (i = 0; i < 6; i++) { if (ac3_block (&s->state)) goto fail; if (avctx->channels == 1) float_to_int_mono (*samples, out_samples + i * 256); else float_to_int (*samples, out_samples + i * 512); } s->inbuf_ptr = s->inbuf; s->frame_size = 0; *data_size = 6 * avctx->channels * 256 * sizeof(INT16); break; } } return buf_ptr - buf; } static int ac3_decode_end(AVCodecContext *s) { return 0; } AVCodec ac3_decoder = { "ac3", CODEC_TYPE_AUDIO, CODEC_ID_AC3, sizeof(AC3DecodeState), ac3_decode_init, NULL, ac3_decode_end, ac3_decode_frame, }; /* register codecs which could clash with mplayer symbols */ /* XXX: rename all symbols to avoid clashed */ void avcodec_register_more(void) { register_avcodec(&mp3_decoder); register_avcodec(&ac3_decoder); }