Mercurial > mplayer.hg
view libmpcodecs/ad_libdca.c @ 36851:5a61b8dd0aad
Normalize 8-bit format "endianness".
author | reimar |
---|---|
date | Wed, 26 Feb 2014 19:54:15 +0000 |
parents | baa7a9f7ce9e |
children |
line wrap: on
line source
/* * DTS Coherent Acoustics stream decoder using libdca * This file is partially based on dtsdec.c r9036 from FFmpeg and ad_liba52.c * * Copyright (C) 2007 Roberto Togni * * This file is part of MPlayer. * * MPlayer 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. * * MPlayer 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 MPlayer; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <assert.h> #include "config.h" #include "mp_msg.h" #include "ad_internal.h" #include "dec_audio.h" #include <dca.h> static const ad_info_t info = { "DTS decoding with libdca", "libdca", "Roberto Togni", "", "" }; LIBAD_EXTERN(libdca) #define DTSBUFFER_SIZE 18726 #define HEADER_SIZE 14 #define CONVERT_LEVEL 1 #define CONVERT_BIAS 0 static const char ch2flags[6] = { DCA_MONO, DCA_STEREO, DCA_3F, DCA_2F2R, DCA_3F2R, DCA_3F2R | DCA_LFE }; static inline int16_t convert(sample_t s) { int i = s * 0x7fff; return (i > 32767) ? 32767 : ((i < -32768) ? -32768 : i); } static void convert2s16_multi(sample_t *f, int16_t *s16, int flags, int ch_out) { int i; switch(flags & (DCA_CHANNEL_MASK | DCA_LFE)){ case DCA_MONO: if (ch_out == 1) for(i = 0; i < 256; i++) s16[i] = convert(f[i]); else 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 DCA_CHANNEL: case DCA_STEREO: case DCA_DOLBY: for(i = 0; i < 256; i++){ s16[2*i] = convert(f[i]); s16[2*i+1] = convert(f[i+256]); } break; case DCA_3F: for(i = 0; i < 256; i++){ s16[3*i] = convert(f[i+256]); s16[3*i+1] = convert(f[i+512]); s16[3*i+2] = convert(f[i]); } break; case DCA_2F2R: 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]); } break; case DCA_3F2R: for(i = 0; i < 256; i++){ s16[5*i] = convert(f[i+256]); s16[5*i+1] = convert(f[i+512]); s16[5*i+2] = convert(f[i+768]); s16[5*i+3] = convert(f[i+1024]); s16[5*i+4] = convert(f[i]); } break; case DCA_MONO | DCA_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]); s16[6*i+5] = convert(f[i+256]); } break; case DCA_CHANNEL | DCA_LFE: case DCA_STEREO | DCA_LFE: case DCA_DOLBY | DCA_LFE: for(i = 0; i < 256; i++){ s16[6*i] = convert(f[i]); s16[6*i+1] = convert(f[i+256]); s16[6*i+2] = s16[6*i+3] = s16[6*i+4] = 0; s16[6*i+5] = convert(f[i+512]); } break; case DCA_3F | DCA_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] = 0; s16[6*i+4] = convert(f[i]); s16[6*i+5] = convert(f[i+768]); } break; case DCA_2F2R | DCA_LFE: for(i = 0; i < 256; i++){ s16[6*i] = convert(f[i]); s16[6*i+1] = convert(f[i+256]); s16[6*i+2] = convert(f[i+512]); s16[6*i+3] = convert(f[i+768]); s16[6*i+4] = 0; s16[6*i+5] = convert(f[1024]); } break; case DCA_3F2R | DCA_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] = convert(f[i]); s16[6*i+5] = convert(f[i+1280]); } break; } } static void channels_info(int flags) { int lfe = 0; char lfestr[5] = ""; if (flags & DCA_LFE) { lfe = 1; strcpy(lfestr, "+lfe"); } mp_msg(MSGT_DECAUDIO, MSGL_V, "DTS: "); switch(flags & DCA_CHANNEL_MASK){ case DCA_MONO: mp_msg(MSGT_DECAUDIO, MSGL_V, "1.%d (mono%s)", lfe, lfestr); break; case DCA_CHANNEL: mp_msg(MSGT_DECAUDIO, MSGL_V, "2.%d (channel%s)", lfe, lfestr); break; case DCA_STEREO: mp_msg(MSGT_DECAUDIO, MSGL_V, "2.%d (stereo%s)", lfe, lfestr); break; case DCA_3F: mp_msg(MSGT_DECAUDIO, MSGL_V, "3.%d (3f%s)", lfe, lfestr); break; case DCA_2F2R: mp_msg(MSGT_DECAUDIO, MSGL_V, "4.%d (2f+2r%s)", lfe, lfestr); break; case DCA_3F2R: mp_msg(MSGT_DECAUDIO, MSGL_V, "5.%d (3f+2r%s)", lfe, lfestr); break; default: mp_msg(MSGT_DECAUDIO, MSGL_V, "x.%d (unknown%s)", lfe, lfestr); } mp_msg(MSGT_DECAUDIO, MSGL_V, "\n"); } static int dts_sync(sh_audio_t *sh, int *flags) { dca_state_t *s = sh->context; int length; int sample_rate; int frame_length; int bit_rate; sh->a_in_buffer_len=0; while(1) { while(sh->a_in_buffer_len < HEADER_SIZE) { int c = demux_getc(sh->ds); if(c < 0) return -1; sh->a_in_buffer[sh->a_in_buffer_len++] = c; } length = dca_syncinfo(s, sh->a_in_buffer, flags, &sample_rate, &bit_rate, &frame_length); if(length >= HEADER_SIZE) break; // mp_msg(MSGT_DECAUDIO, MSGL_V, "skip\n"); memmove(sh->a_in_buffer, sh->a_in_buffer+1, HEADER_SIZE-1); --sh->a_in_buffer_len; } demux_read_data(sh->ds, sh->a_in_buffer + HEADER_SIZE, length - HEADER_SIZE); sh->samplerate = sample_rate; sh->i_bps = bit_rate/8; return length; } static int decode_audio(sh_audio_t *sh, unsigned char *buf, int minlen, int maxlen) { dca_state_t *s = sh->context; int16_t *out_samples = (int16_t*)buf; int flags; level_t level; sample_t bias; int nblocks; int i; int data_size = 0; if(!sh->a_in_buffer_len) if(dts_sync(sh, &flags) < 0) return -1; /* EOF */ sh->a_in_buffer_len=0; flags &= ~(DCA_CHANNEL_MASK | DCA_LFE); flags |= ch2flags[sh->channels - 1]; level = CONVERT_LEVEL; bias = CONVERT_BIAS; flags |= DCA_ADJUST_LEVEL; if(dca_frame(s, sh->a_in_buffer, &flags, &level, bias)) { mp_msg(MSGT_DECAUDIO, MSGL_ERR, "dca_frame() failed\n"); goto end; } nblocks = dca_blocks_num(s); for(i = 0; i < nblocks; i++) { if(dca_block(s)) { mp_msg(MSGT_DECAUDIO, MSGL_ERR, "dca_block() failed\n"); goto end; } convert2s16_multi(dca_samples(s), out_samples, flags, sh->channels); out_samples += 256 * sh->channels; data_size += 256 * sizeof(int16_t) * sh->channels; } end: return data_size; } static int preinit(sh_audio_t *sh) { /* 256 = samples per block, 16 = max number of blocks */ sh->audio_out_minsize = audio_output_channels * sizeof(int16_t) * 256 * 16; sh->audio_in_minsize = DTSBUFFER_SIZE; sh->samplesize=2; return 1; } static int init(sh_audio_t *sh) { dca_state_t *s; int flags; int decoded_bytes; s = dca_init(0); if(s == NULL) { mp_msg(MSGT_DECAUDIO, MSGL_ERR, "dca_init() failed\n"); return 0; } sh->context = s; if(dts_sync(sh, &flags) < 0) { mp_msg(MSGT_DECAUDIO, MSGL_ERR, "dca sync failed\n"); dca_free(s); return 0; } channels_info(flags); assert(audio_output_channels >= 1 && audio_output_channels <= 6); sh->channels = audio_output_channels; decoded_bytes = decode_audio(sh, sh->a_buffer, 1, sh->a_buffer_size); if(decoded_bytes > 0) sh->a_buffer_len = decoded_bytes; else { mp_msg(MSGT_DECAUDIO, MSGL_ERR, "dts decode failed on first frame (up/downmix problem?)\n"); dca_free(s); return 0; } return 1; } static void uninit(sh_audio_t *sh) { dca_state_t *s = sh->context; dca_free(s); } static int control(sh_audio_t *sh,int cmd,void* arg, ...) { int flags; switch(cmd){ case ADCTRL_RESYNC_STREAM: dts_sync(sh, &flags); return CONTROL_TRUE; } return CONTROL_UNKNOWN; }