diff options
author | Michael Niedermayer <michaelni@gmx.at> | 2004-07-14 01:32:14 +0000 |
---|---|---|
committer | Michael Niedermayer <michaelni@gmx.at> | 2004-07-14 01:32:14 +0000 |
commit | 23c992532927afa9d3a00677ff40cd071e21dc8f (patch) | |
tree | 232b97558b925172d4c6372c10a5c7e156469f27 /libavcodec/dtsdec.c | |
parent | eb507b21c410515b179c0ca85b3db3d83fc296bd (diff) | |
download | ffmpeg-23c992532927afa9d3a00677ff40cd071e21dc8f.tar.gz |
libdts support by (Benjamin Zores <ben at geexbox dot org>)
Originally committed as revision 3310 to svn://svn.ffmpeg.org/ffmpeg/trunk
Diffstat (limited to 'libavcodec/dtsdec.c')
-rw-r--r-- | libavcodec/dtsdec.c | 349 |
1 files changed, 349 insertions, 0 deletions
diff --git a/libavcodec/dtsdec.c b/libavcodec/dtsdec.c new file mode 100644 index 0000000000..d683a08e61 --- /dev/null +++ b/libavcodec/dtsdec.c @@ -0,0 +1,349 @@ +/* + * dtsdec.c : free DTS Coherent Acoustics stream decoder. + * Copyright (C) 2004 Benjamin Zores <ben@geexbox.org> + * + * This file is part of libavcodec. + * + * This library 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 of the License, or (at your option) any later version. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_AV_CONFIG_H +#undef HAVE_AV_CONFIG_H +#endif + +#include "avcodec.h" +#include <dts.h> +#include "dts_internal.h" + +#include <stdlib.h> +#include <string.h> +#include <malloc.h> +#include <math.h> + +#define INBUF_SIZE 4096 +#define BUFFER_SIZE 4096 +#define HEADER_SIZE 14 + +#ifdef LIBDTS_FIXED +#define CONVERT_LEVEL (1 << 26) +#define CONVERT_BIAS 0 +#else +#define CONVERT_LEVEL 1 +#define CONVERT_BIAS 384 +#endif + +static void +pre_calc_cosmod (dts_state_t * state) +{ + int i, j, k; + + for (j=0,k=0;k<16;k++) + for (i=0;i<16;i++) + state->cos_mod[j++] = cos((2*i+1)*(2*k+1)*M_PI/64); + + for (k=0;k<16;k++) + for (i=0;i<16;i++) + state->cos_mod[j++] = cos((i)*(2*k+1)*M_PI/32); + + for (k=0;k<16;k++) + state->cos_mod[j++] = 0.25/(2*cos((2*k+1)*M_PI/128)); + + for (k=0;k<16;k++) + state->cos_mod[j++] = -0.25/(2.0*sin((2*k+1)*M_PI/128)); +} + +static inline +int16_t convert (int32_t i) +{ +#ifdef LIBDTS_FIXED + i >>= 15; +#else + i -= 0x43c00000; +#endif + return (i > 32767) ? 32767 : ((i < -32768) ? -32768 : i); +} + +void +convert2s16_2 (sample_t * _f, int16_t * s16) +{ + int i; + int32_t * f = (int32_t *) _f; + + for (i = 0; i < 256; i++) + { + s16[2*i] = convert (f[i]); + s16[2*i+1] = convert (f[i+256]); + } +} + +void +convert2s16_4 (sample_t * _f, int16_t * s16) +{ + int i; + int32_t * f = (int32_t *) _f; + + for (i = 0; i < 256; i++) + { + s16[4*i] = convert (f[i]); + s16[4*i+1] = convert (f[i+256]); + s16[4*i+2] = convert (f[i+512]); + s16[4*i+3] = convert (f[i+768]); + } +} + +void +convert2s16_5 (sample_t * _f, int16_t * s16) +{ + int i; + int32_t * f = (int32_t *) _f; + + for (i = 0; i < 256; i++) + { + s16[5*i] = convert (f[i]); + s16[5*i+1] = convert (f[i+256]); + s16[5*i+2] = convert (f[i+512]); + s16[5*i+3] = convert (f[i+768]); + s16[5*i+4] = convert (f[i+1024]); + } +} + +static void +convert2s16_multi (sample_t * _f, int16_t * s16, int flags) +{ + int i; + int32_t * f = (int32_t *) _f; + + switch (flags) + { + case DTS_MONO: + for (i = 0; i < 256; i++) + { + s16[5*i] = s16[5*i+1] = s16[5*i+2] = s16[5*i+3] = 0; + s16[5*i+4] = convert (f[i]); + } + break; + case DTS_CHANNEL: + case DTS_STEREO: + case DTS_DOLBY: + convert2s16_2 (_f, s16); + break; + case DTS_3F: + for (i = 0; i < 256; i++) + { + s16[5*i] = convert (f[i]); + s16[5*i+1] = convert (f[i+512]); + s16[5*i+2] = s16[5*i+3] = 0; + s16[5*i+4] = convert (f[i+256]); + } + break; + case DTS_2F2R: + convert2s16_4 (_f, s16); + break; + case DTS_3F2R: + convert2s16_5 (_f, s16); + break; + case DTS_MONO | DTS_LFE: + for (i = 0; i < 256; i++) + { + s16[6*i] = s16[6*i+1] = s16[6*i+2] = s16[6*i+3] = 0; + s16[6*i+4] = convert (f[i+256]); + s16[6*i+5] = convert (f[i]); + } + break; + case DTS_CHANNEL | DTS_LFE: + case DTS_STEREO | DTS_LFE: + case DTS_DOLBY | DTS_LFE: + for (i = 0; i < 256; i++) + { + s16[6*i] = convert (f[i+256]); + s16[6*i+1] = convert (f[i+512]); + s16[6*i+2] = s16[6*i+3] = s16[6*i+4] = 0; + s16[6*i+5] = convert (f[i]); + } + break; + case DTS_3F | DTS_LFE: + for (i = 0; i < 256; i++) + { + s16[6*i] = convert (f[i+256]); + s16[6*i+1] = convert (f[i+768]); + s16[6*i+2] = s16[6*i+3] = 0; + s16[6*i+4] = convert (f[i+512]); + s16[6*i+5] = convert (f[i]); + } + break; + case DTS_2F2R | DTS_LFE: + for (i = 0; i < 256; i++) + { + s16[6*i] = convert (f[i+256]); + s16[6*i+1] = convert (f[i+512]); + s16[6*i+2] = convert (f[i+768]); + s16[6*i+3] = convert (f[i+1024]); + s16[6*i+4] = 0; + s16[6*i+5] = convert (f[i]); + } + break; + case DTS_3F2R | DTS_LFE: + for (i = 0; i < 256; i++) + { + s16[6*i] = convert (f[i+256]); + s16[6*i+1] = convert (f[i+768]); + s16[6*i+2] = convert (f[i+1024]); + s16[6*i+3] = convert (f[i+1280]); + s16[6*i+4] = convert (f[i+512]); + s16[6*i+5] = convert (f[i]); + } + break; + } +} + +static int +channels_multi (int flags) +{ + if (flags & DTS_LFE) + return 6; + else if (flags & 1) /* center channel */ + return 5; + else if ((flags & DTS_CHANNEL_MASK) == DTS_2F2R) + return 4; + else + return 2; +} + +static int +dts_decode_frame (AVCodecContext *avctx, void *data, int *data_size, + uint8_t *buff, int buff_size) +{ + uint8_t * start = buff; + uint8_t * end = buff + buff_size; + *data_size = 0; + + static uint8_t buf[BUFFER_SIZE]; + static uint8_t * bufptr = buf; + static uint8_t * bufpos = buf + HEADER_SIZE; + + static int sample_rate; + static int frame_length; + static int flags; + int bit_rate; + int len; + dts_state_t *state = avctx->priv_data; + + while (1) + { + len = end - start; + if (!len) + break; + if (len > bufpos - bufptr) + len = bufpos - bufptr; + memcpy (bufptr, start, len); + bufptr += len; + start += len; + if (bufptr == bufpos) + { + if (bufpos == buf + HEADER_SIZE) + { + int length; + + length = dts_syncinfo (state, buf, &flags, &sample_rate, + &bit_rate, &frame_length); + if (!length) + { + av_log (NULL, AV_LOG_INFO, "skip\n"); + for (bufptr = buf; bufptr < buf + HEADER_SIZE-1; bufptr++) + bufptr[0] = bufptr[1]; + continue; + } + bufpos = buf + length; + } + else + { + level_t level; + sample_t bias; + int i; + + flags = 2; /* ???????????? */ + level = CONVERT_LEVEL; + bias = CONVERT_BIAS; + + flags |= DTS_ADJUST_LEVEL; + if (dts_frame (state, buf, &flags, &level, bias)) + goto error; + for (i = 0; i < dts_blocks_num (state); i++) + { + if (dts_block (state)) + goto error; + { + int chans; + chans = channels_multi (flags); + convert2s16_multi (dts_samples (state), data, + flags & (DTS_CHANNEL_MASK | DTS_LFE)); + + data += 256 * sizeof (int16_t) * chans; + *data_size += 256 * sizeof (int16_t) * chans; + } + } + bufptr = buf; + bufpos = buf + HEADER_SIZE; + continue; + error: + av_log (NULL, AV_LOG_ERROR, "error\n"); + bufptr = buf; + bufpos = buf + HEADER_SIZE; + } + } + } + + return buff_size; +} + +static int +dts_decode_init (AVCodecContext *avctx) +{ + dts_state_t * state; + int i; + + state = avctx->priv_data; + memset (state, 0, sizeof (dts_state_t)); + + state->samples = (sample_t *) memalign (16, 256 * 12 * sizeof (sample_t)); + if (state->samples == NULL) + return 1; + + for (i = 0; i < 256 * 12; i++) + state->samples[i] = 0; + + /* Pre-calculate cosine modulation coefficients */ + pre_calc_cosmod (state); + state->downmixed = 1; + + return 0; +} + +static int +dts_decode_end (AVCodecContext *s) +{ + return 0; +} + +AVCodec dts_decoder = { + "dts", + CODEC_TYPE_AUDIO, + CODEC_ID_DTS, + sizeof (dts_state_t), + dts_decode_init, + NULL, + dts_decode_end, + dts_decode_frame, +}; |