2007-02-27 08:30:40 +02:00
/*
* DCA compatible decoder
* Copyright ( C ) 2004 Gildas Bazin
* Copyright ( C ) 2004 Benjamin Zores
* Copyright ( C ) 2006 Benjamin Larsson
* Copyright ( C ) 2007 Konstantin Shishkov
*
* This file is part of FFmpeg .
*
* FFmpeg 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.1 of the License , or ( at your option ) any later version .
*
* FFmpeg 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 FFmpeg ; if not , write to the Free Software
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
*/
/**
* @ file dca . c
*/
# include <math.h>
# include <stddef.h>
# include <stdio.h>
# include "avcodec.h"
# include "dsputil.h"
# include "bitstream.h"
# include "dcadata.h"
# include "dcahuff.h"
2007-05-04 02:50:24 +03:00
# include "dca.h"
2007-02-27 08:30:40 +02:00
//#define TRACE
# define DCA_PRIM_CHANNELS_MAX (5)
# define DCA_SUBBANDS (32)
# define DCA_ABITS_MAX (32) /* Should be 28 */
# define DCA_SUBSUBFAMES_MAX (4)
# define DCA_LFE_MAX (3)
enum DCAMode {
DCA_MONO = 0 ,
DCA_CHANNEL ,
DCA_STEREO ,
DCA_STEREO_SUMDIFF ,
DCA_STEREO_TOTAL ,
DCA_3F ,
DCA_2F1R ,
DCA_3F1R ,
DCA_2F2R ,
DCA_3F2R ,
DCA_4F2R
} ;
2008-11-01 22:27:05 +02:00
/* Tables for mapping dts channel configurations to libavcodec multichannel api.
* Some compromises have been made for special configurations . Most configurations
* are never used so complete accuracy is not needed .
*
* L = left , R = right , C = center , S = surround , F = front , R = rear , T = total , OV = overhead .
2008-11-11 10:46:29 +02:00
* S - > side , when both rear and back are configured move one of them to the side channel
2008-11-01 22:27:05 +02:00
* OV - > center back
2008-11-02 23:04:28 +02:00
* All 2 channel configurations - > CH_LAYOUT_STEREO
2008-11-01 22:27:05 +02:00
*/
static const int64_t dca_core_channel_layout [ ] = {
2008-11-02 23:04:28 +02:00
CH_FRONT_CENTER , ///< 1, A
CH_LAYOUT_STEREO , ///< 2, A + B (dual mono)
CH_LAYOUT_STEREO , ///< 2, L + R (stereo)
CH_LAYOUT_STEREO , ///< 2, (L+R) + (L-R) (sum-difference)
CH_LAYOUT_STEREO , ///< 2, LT +RT (left and right total)
2008-11-02 23:51:27 +02:00
CH_LAYOUT_STEREO | CH_FRONT_CENTER , ///< 3, C+L+R
CH_LAYOUT_STEREO | CH_BACK_CENTER , ///< 3, L+R+S
CH_LAYOUT_STEREO | CH_FRONT_CENTER | CH_BACK_CENTER , ///< 4, C + L + R+ S
CH_LAYOUT_STEREO | CH_SIDE_LEFT | CH_SIDE_RIGHT , ///< 4, L + R +SL+ SR
CH_LAYOUT_STEREO | CH_FRONT_CENTER | CH_SIDE_LEFT | CH_SIDE_RIGHT , ///< 5, C + L + R+ SL+SR
CH_LAYOUT_STEREO | CH_SIDE_LEFT | CH_SIDE_RIGHT | CH_FRONT_LEFT_OF_CENTER | CH_FRONT_RIGHT_OF_CENTER , ///< 6, CL + CR + L + R + SL + SR
CH_LAYOUT_STEREO | CH_BACK_LEFT | CH_BACK_RIGHT | CH_FRONT_CENTER | CH_BACK_CENTER , ///< 6, C + L + R+ LR + RR + OV
CH_FRONT_CENTER | CH_FRONT_RIGHT_OF_CENTER | CH_FRONT_LEFT_OF_CENTER | CH_BACK_CENTER | CH_BACK_LEFT | CH_BACK_RIGHT , ///< 6, CF+ CR+LF+ RF+LR + RR
CH_FRONT_LEFT_OF_CENTER | CH_FRONT_CENTER | CH_FRONT_RIGHT_OF_CENTER | CH_LAYOUT_STEREO | CH_SIDE_LEFT | CH_SIDE_RIGHT , ///< 7, CL + C + CR + L + R + SL + SR
2008-11-02 23:04:28 +02:00
CH_FRONT_LEFT_OF_CENTER | CH_FRONT_RIGHT_OF_CENTER | CH_LAYOUT_STEREO | CH_SIDE_LEFT | CH_SIDE_RIGHT | CH_BACK_LEFT | CH_BACK_RIGHT , ///< 8, CL + CR + L + R + SL1 + SL2+ SR1 + SR2
2008-11-02 23:51:27 +02:00
CH_FRONT_LEFT_OF_CENTER | CH_FRONT_CENTER | CH_FRONT_RIGHT_OF_CENTER | CH_LAYOUT_STEREO | CH_SIDE_LEFT | CH_BACK_CENTER | CH_SIDE_RIGHT , ///< 8, CL + C+ CR + L + R + SL + S+ SR
2008-11-01 22:27:05 +02:00
} ;
2008-11-15 22:31:03 +02:00
static const int8_t dca_lfe_index [ ] = {
1 , 2 , 2 , 2 , 2 , 3 , 2 , 3 , 2 , 3 , 2 , 3 , 1 , 3 , 2 , 3
} ;
static const int8_t dca_channel_reorder_lfe [ ] [ 8 ] = {
{ 0 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ,
{ 0 , 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ,
{ 0 , 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ,
{ 0 , 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ,
{ 0 , 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ,
{ 2 , 0 , 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ,
{ 0 , 1 , 3 , - 1 , - 1 , - 1 , - 1 , - 1 } ,
{ 2 , 0 , 1 , 4 , - 1 , - 1 , - 1 , - 1 } ,
{ 0 , 1 , 3 , 4 , - 1 , - 1 , - 1 , - 1 } ,
{ 2 , 0 , 1 , 4 , 5 , - 1 , - 1 , - 1 } ,
{ 3 , 4 , 0 , 1 , 5 , 6 , - 1 , - 1 } ,
{ 2 , 0 , 1 , 4 , 5 , 6 , - 1 , - 1 } ,
{ 0 , 6 , 4 , 5 , 2 , 3 , - 1 , - 1 } ,
{ 4 , 2 , 5 , 0 , 1 , 6 , 7 , - 1 } ,
{ 5 , 6 , 0 , 1 , 7 , 3 , 8 , 4 } ,
{ 4 , 2 , 5 , 0 , 1 , 6 , 8 , 7 } ,
} ;
static const int8_t dca_channel_reorder_nolfe [ ] [ 8 ] = {
{ 0 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ,
{ 0 , 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ,
{ 0 , 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ,
{ 0 , 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ,
{ 0 , 1 , - 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ,
{ 2 , 0 , 1 , - 1 , - 1 , - 1 , - 1 , - 1 } ,
{ 0 , 1 , 2 , - 1 , - 1 , - 1 , - 1 , - 1 } ,
{ 2 , 0 , 1 , 3 , - 1 , - 1 , - 1 , - 1 } ,
{ 0 , 1 , 2 , 3 , - 1 , - 1 , - 1 , - 1 } ,
{ 2 , 0 , 1 , 3 , 4 , - 1 , - 1 , - 1 } ,
{ 2 , 3 , 0 , 1 , 4 , 5 , - 1 , - 1 } ,
{ 2 , 0 , 1 , 3 , 4 , 5 , - 1 , - 1 } ,
{ 0 , 5 , 3 , 4 , 1 , 2 , - 1 , - 1 } ,
{ 3 , 2 , 4 , 0 , 1 , 5 , 6 , - 1 } ,
{ 4 , 5 , 0 , 1 , 6 , 2 , 7 , 3 } ,
{ 3 , 2 , 4 , 0 , 1 , 5 , 7 , 6 } ,
} ;
2008-11-01 22:27:05 +02:00
2007-02-27 08:30:40 +02:00
# define DCA_DOLBY 101 /* FIXME */
# define DCA_CHANNEL_BITS 6
# define DCA_CHANNEL_MASK 0x3F
# define DCA_LFE 0x80
# define HEADER_SIZE 14
2008-08-23 16:29:13 +03:00
# define DCA_MAX_FRAME_SIZE 16384
2007-02-27 08:30:40 +02:00
/** Bit allocation */
typedef struct {
int offset ; ///< code values offset
int maxbits [ 8 ] ; ///< max bits in VLC
int wrap ; ///< wrap for get_vlc2()
VLC vlc [ 8 ] ; ///< actual codes
} BitAlloc ;
static BitAlloc dca_bitalloc_index ; ///< indexes for samples VLC select
static BitAlloc dca_tmode ; ///< transition mode VLCs
static BitAlloc dca_scalefactor ; ///< scalefactor VLCs
static BitAlloc dca_smpl_bitalloc [ 11 ] ; ///< samples VLCs
2007-05-05 15:18:14 +03:00
static av_always_inline int get_bitalloc ( GetBitContext * gb , BitAlloc * ba , int idx )
2007-02-27 08:30:40 +02:00
{
return get_vlc2 ( gb , ba - > vlc [ idx ] . table , ba - > vlc [ idx ] . bits , ba - > wrap ) + ba - > offset ;
}
typedef struct {
AVCodecContext * avctx ;
/* Frame header */
int frame_type ; ///< type of the current frame
int samples_deficit ; ///< deficit sample count
int crc_present ; ///< crc is present in the bitstream
int sample_blocks ; ///< number of PCM sample blocks
int frame_size ; ///< primary frame byte size
int amode ; ///< audio channels arrangement
int sample_rate ; ///< audio sampling rate
int bit_rate ; ///< transmission bit rate
2008-10-28 16:50:46 +02:00
int bit_rate_index ; ///< transmission bit rate index
2007-02-27 08:30:40 +02:00
int downmix ; ///< embedded downmix enabled
int dynrange ; ///< embedded dynamic range flag
int timestamp ; ///< embedded time stamp flag
int aux_data ; ///< auxiliary data flag
int hdcd ; ///< source material is mastered in HDCD
int ext_descr ; ///< extension audio descriptor flag
int ext_coding ; ///< extended coding flag
int aspf ; ///< audio sync word insertion flag
int lfe ; ///< low frequency effects flag
int predictor_history ; ///< predictor history flag
int header_crc ; ///< header crc check bytes
int multirate_inter ; ///< multirate interpolator switch
int version ; ///< encoder software revision
int copy_history ; ///< copy history
int source_pcm_res ; ///< source pcm resolution
int front_sum ; ///< front sum/difference flag
int surround_sum ; ///< surround sum/difference flag
int dialog_norm ; ///< dialog normalisation parameter
/* Primary audio coding header */
int subframes ; ///< number of subframes
2008-03-06 16:22:02 +02:00
int total_channels ; ///< number of channels including extensions
2007-02-27 08:30:40 +02:00
int prim_channels ; ///< number of primary audio channels
int subband_activity [ DCA_PRIM_CHANNELS_MAX ] ; ///< subband activity count
int vq_start_subband [ DCA_PRIM_CHANNELS_MAX ] ; ///< high frequency vq start subband
int joint_intensity [ DCA_PRIM_CHANNELS_MAX ] ; ///< joint intensity coding index
int transient_huffman [ DCA_PRIM_CHANNELS_MAX ] ; ///< transient mode code book
int scalefactor_huffman [ DCA_PRIM_CHANNELS_MAX ] ; ///< scale factor code book
int bitalloc_huffman [ DCA_PRIM_CHANNELS_MAX ] ; ///< bit allocation quantizer select
int quant_index_huffman [ DCA_PRIM_CHANNELS_MAX ] [ DCA_ABITS_MAX ] ; ///< quantization index codebook select
float scalefactor_adj [ DCA_PRIM_CHANNELS_MAX ] [ DCA_ABITS_MAX ] ; ///< scale factor adjustment
/* Primary audio coding side information */
int subsubframes ; ///< number of subsubframes
int partial_samples ; ///< partial subsubframe samples count
int prediction_mode [ DCA_PRIM_CHANNELS_MAX ] [ DCA_SUBBANDS ] ; ///< prediction mode (ADPCM used or not)
int prediction_vq [ DCA_PRIM_CHANNELS_MAX ] [ DCA_SUBBANDS ] ; ///< prediction VQ coefs
int bitalloc [ DCA_PRIM_CHANNELS_MAX ] [ DCA_SUBBANDS ] ; ///< bit allocation index
int transition_mode [ DCA_PRIM_CHANNELS_MAX ] [ DCA_SUBBANDS ] ; ///< transition mode (transients)
int scale_factor [ DCA_PRIM_CHANNELS_MAX ] [ DCA_SUBBANDS ] [ 2 ] ; ///< scale factors (2 if transient)
int joint_huff [ DCA_PRIM_CHANNELS_MAX ] ; ///< joint subband scale factors codebook
int joint_scale_factor [ DCA_PRIM_CHANNELS_MAX ] [ DCA_SUBBANDS ] ; ///< joint subband scale factors
int downmix_coef [ DCA_PRIM_CHANNELS_MAX ] [ 2 ] ; ///< stereo downmix coefficients
int dynrange_coef ; ///< dynamic range coefficient
int high_freq_vq [ DCA_PRIM_CHANNELS_MAX ] [ DCA_SUBBANDS ] ; ///< VQ encoded high frequency subbands
float lfe_data [ 2 * DCA_SUBSUBFAMES_MAX * DCA_LFE_MAX *
2 /*history */ ] ; ///< Low frequency effect data
int lfe_scale_factor ;
/* Subband samples history (for ADPCM) */
float subband_samples_hist [ DCA_PRIM_CHANNELS_MAX ] [ DCA_SUBBANDS ] [ 4 ] ;
2008-08-30 13:47:13 +03:00
DECLARE_ALIGNED_16 ( float , subband_fir_hist [ DCA_PRIM_CHANNELS_MAX ] [ 512 ] ) ;
2008-08-29 21:37:40 +03:00
float subband_fir_noidea [ DCA_PRIM_CHANNELS_MAX ] [ 32 ] ;
2008-08-30 13:41:53 +03:00
int hist_index [ DCA_PRIM_CHANNELS_MAX ] ;
2007-02-27 08:30:40 +02:00
int output ; ///< type of output
2008-10-26 11:54:53 +02:00
float add_bias ; ///< output bias
float scale_bias ; ///< output scale
2007-02-27 08:30:40 +02:00
DECLARE_ALIGNED_16 ( float , samples [ 1536 ] ) ; /* 6 * 256 = 1536, might only need 5 */
2008-08-29 13:14:01 +03:00
const float * samples_chanptr [ 6 ] ;
2007-02-27 08:30:40 +02:00
uint8_t dca_buffer [ DCA_MAX_FRAME_SIZE ] ;
int dca_buffer_size ; ///< how much data is in the dca_buffer
2008-11-15 22:31:03 +02:00
const int8_t * channel_order_tab ; ///< channel reordering table, lfe and non lfe
2007-02-27 08:30:40 +02:00
GetBitContext gb ;
/* Current position in DCA frame */
int current_subframe ;
int current_subsubframe ;
int debug_flag ; ///< used for suppressing repeated error messages output
DSPContext dsp ;
2008-08-30 13:47:13 +03:00
MDCTContext imdct ;
2007-02-27 08:30:40 +02:00
} DCAContext ;
2008-03-21 05:11:20 +02:00
static av_cold void dca_init_vlcs ( void )
2007-02-27 08:30:40 +02:00
{
2008-02-13 11:26:10 +02:00
static int vlcs_initialized = 0 ;
2007-02-27 08:30:40 +02:00
int i , j ;
2008-02-13 11:26:10 +02:00
if ( vlcs_initialized )
2007-02-27 08:30:40 +02:00
return ;
dca_bitalloc_index . offset = 1 ;
2007-05-24 07:08:48 +03:00
dca_bitalloc_index . wrap = 2 ;
2007-02-27 08:30:40 +02:00
for ( i = 0 ; i < 5 ; i + + )
init_vlc ( & dca_bitalloc_index . vlc [ i ] , bitalloc_12_vlc_bits [ i ] , 12 ,
bitalloc_12_bits [ i ] , 1 , 1 ,
bitalloc_12_codes [ i ] , 2 , 2 , 1 ) ;
dca_scalefactor . offset = - 64 ;
dca_scalefactor . wrap = 2 ;
for ( i = 0 ; i < 5 ; i + + )
init_vlc ( & dca_scalefactor . vlc [ i ] , SCALES_VLC_BITS , 129 ,
scales_bits [ i ] , 1 , 1 ,
scales_codes [ i ] , 2 , 2 , 1 ) ;
dca_tmode . offset = 0 ;
dca_tmode . wrap = 1 ;
for ( i = 0 ; i < 4 ; i + + )
init_vlc ( & dca_tmode . vlc [ i ] , tmode_vlc_bits [ i ] , 4 ,
tmode_bits [ i ] , 1 , 1 ,
tmode_codes [ i ] , 2 , 2 , 1 ) ;
for ( i = 0 ; i < 10 ; i + + )
for ( j = 0 ; j < 7 ; j + + ) {
if ( ! bitalloc_codes [ i ] [ j ] ) break ;
dca_smpl_bitalloc [ i + 1 ] . offset = bitalloc_offsets [ i ] ;
dca_smpl_bitalloc [ i + 1 ] . wrap = 1 + ( j > 4 ) ;
init_vlc ( & dca_smpl_bitalloc [ i + 1 ] . vlc [ j ] , bitalloc_maxbits [ i ] [ j ] ,
bitalloc_sizes [ i ] ,
bitalloc_bits [ i ] [ j ] , 1 , 1 ,
bitalloc_codes [ i ] [ j ] , 2 , 2 , 1 ) ;
}
2008-02-13 11:26:10 +02:00
vlcs_initialized = 1 ;
2007-02-27 08:30:40 +02:00
}
static inline void get_array ( GetBitContext * gb , int * dst , int len , int bits )
{
while ( len - - )
* dst + + = get_bits ( gb , bits ) ;
}
static int dca_parse_frame_header ( DCAContext * s )
{
int i , j ;
static const float adj_table [ 4 ] = { 1.0 , 1.1250 , 1.2500 , 1.4375 } ;
static const int bitlen [ 11 ] = { 0 , 1 , 2 , 2 , 2 , 2 , 3 , 3 , 3 , 3 , 3 } ;
static const int thr [ 11 ] = { 0 , 1 , 3 , 3 , 3 , 3 , 7 , 7 , 7 , 7 , 7 } ;
init_get_bits ( & s - > gb , s - > dca_buffer , s - > dca_buffer_size * 8 ) ;
/* Sync code */
get_bits ( & s - > gb , 32 ) ;
/* Frame header */
s - > frame_type = get_bits ( & s - > gb , 1 ) ;
s - > samples_deficit = get_bits ( & s - > gb , 5 ) + 1 ;
s - > crc_present = get_bits ( & s - > gb , 1 ) ;
s - > sample_blocks = get_bits ( & s - > gb , 7 ) + 1 ;
s - > frame_size = get_bits ( & s - > gb , 14 ) + 1 ;
if ( s - > frame_size < 95 )
return - 1 ;
s - > amode = get_bits ( & s - > gb , 6 ) ;
s - > sample_rate = dca_sample_rates [ get_bits ( & s - > gb , 4 ) ] ;
if ( ! s - > sample_rate )
return - 1 ;
2008-10-28 17:20:52 +02:00
s - > bit_rate_index = get_bits ( & s - > gb , 5 ) ;
2008-10-28 16:50:46 +02:00
s - > bit_rate = dca_bit_rates [ s - > bit_rate_index ] ;
2007-02-27 08:30:40 +02:00
if ( ! s - > bit_rate )
return - 1 ;
s - > downmix = get_bits ( & s - > gb , 1 ) ;
s - > dynrange = get_bits ( & s - > gb , 1 ) ;
s - > timestamp = get_bits ( & s - > gb , 1 ) ;
s - > aux_data = get_bits ( & s - > gb , 1 ) ;
s - > hdcd = get_bits ( & s - > gb , 1 ) ;
s - > ext_descr = get_bits ( & s - > gb , 3 ) ;
s - > ext_coding = get_bits ( & s - > gb , 1 ) ;
s - > aspf = get_bits ( & s - > gb , 1 ) ;
s - > lfe = get_bits ( & s - > gb , 2 ) ;
s - > predictor_history = get_bits ( & s - > gb , 1 ) ;
/* TODO: check CRC */
if ( s - > crc_present )
s - > header_crc = get_bits ( & s - > gb , 16 ) ;
s - > multirate_inter = get_bits ( & s - > gb , 1 ) ;
s - > version = get_bits ( & s - > gb , 4 ) ;
s - > copy_history = get_bits ( & s - > gb , 2 ) ;
s - > source_pcm_res = get_bits ( & s - > gb , 3 ) ;
s - > front_sum = get_bits ( & s - > gb , 1 ) ;
s - > surround_sum = get_bits ( & s - > gb , 1 ) ;
s - > dialog_norm = get_bits ( & s - > gb , 4 ) ;
/* FIXME: channels mixing levels */
2007-05-02 23:31:32 +03:00
s - > output = s - > amode ;
if ( s - > lfe ) s - > output | = DCA_LFE ;
2007-02-27 08:30:40 +02:00
# ifdef TRACE
av_log ( s - > avctx , AV_LOG_DEBUG , " frame type: %i \n " , s - > frame_type ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " samples deficit: %i \n " , s - > samples_deficit ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " crc present: %i \n " , s - > crc_present ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " sample blocks: %i (%i samples) \n " ,
s - > sample_blocks , s - > sample_blocks * 32 ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " frame size: %i bytes \n " , s - > frame_size ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " amode: %i (%i channels) \n " ,
s - > amode , dca_channels [ s - > amode ] ) ;
2008-10-26 11:50:15 +02:00
av_log ( s - > avctx , AV_LOG_DEBUG , " sample rate: %i Hz \n " ,
s - > sample_rate ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " bit rate: %i bits/s \n " ,
s - > bit_rate ) ;
2007-02-27 08:30:40 +02:00
av_log ( s - > avctx , AV_LOG_DEBUG , " downmix: %i \n " , s - > downmix ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " dynrange: %i \n " , s - > dynrange ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " timestamp: %i \n " , s - > timestamp ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " aux_data: %i \n " , s - > aux_data ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " hdcd: %i \n " , s - > hdcd ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " ext descr: %i \n " , s - > ext_descr ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " ext coding: %i \n " , s - > ext_coding ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " aspf: %i \n " , s - > aspf ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " lfe: %i \n " , s - > lfe ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " predictor history: %i \n " ,
s - > predictor_history ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " header crc: %i \n " , s - > header_crc ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " multirate inter: %i \n " ,
s - > multirate_inter ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " version number: %i \n " , s - > version ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " copy history: %i \n " , s - > copy_history ) ;
av_log ( s - > avctx , AV_LOG_DEBUG ,
" source pcm resolution: %i (%i bits/sample) \n " ,
s - > source_pcm_res , dca_bits_per_sample [ s - > source_pcm_res ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " front sum: %i \n " , s - > front_sum ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " surround sum: %i \n " , s - > surround_sum ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " dialog norm: %i \n " , s - > dialog_norm ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " \n " ) ;
# endif
/* Primary audio coding header */
s - > subframes = get_bits ( & s - > gb , 4 ) + 1 ;
2008-03-06 16:22:02 +02:00
s - > total_channels = get_bits ( & s - > gb , 3 ) + 1 ;
s - > prim_channels = s - > total_channels ;
if ( s - > prim_channels > DCA_PRIM_CHANNELS_MAX )
s - > prim_channels = DCA_PRIM_CHANNELS_MAX ; /* We only support DTS core */
2007-02-27 08:30:40 +02:00
for ( i = 0 ; i < s - > prim_channels ; i + + ) {
s - > subband_activity [ i ] = get_bits ( & s - > gb , 5 ) + 2 ;
if ( s - > subband_activity [ i ] > DCA_SUBBANDS )
s - > subband_activity [ i ] = DCA_SUBBANDS ;
}
for ( i = 0 ; i < s - > prim_channels ; i + + ) {
s - > vq_start_subband [ i ] = get_bits ( & s - > gb , 5 ) + 1 ;
if ( s - > vq_start_subband [ i ] > DCA_SUBBANDS )
s - > vq_start_subband [ i ] = DCA_SUBBANDS ;
}
get_array ( & s - > gb , s - > joint_intensity , s - > prim_channels , 3 ) ;
get_array ( & s - > gb , s - > transient_huffman , s - > prim_channels , 2 ) ;
get_array ( & s - > gb , s - > scalefactor_huffman , s - > prim_channels , 3 ) ;
get_array ( & s - > gb , s - > bitalloc_huffman , s - > prim_channels , 3 ) ;
/* Get codebooks quantization indexes */
memset ( s - > quant_index_huffman , 0 , sizeof ( s - > quant_index_huffman ) ) ;
for ( j = 1 ; j < 11 ; j + + )
for ( i = 0 ; i < s - > prim_channels ; i + + )
s - > quant_index_huffman [ i ] [ j ] = get_bits ( & s - > gb , bitlen [ j ] ) ;
/* Get scale factor adjustment */
for ( j = 0 ; j < 11 ; j + + )
for ( i = 0 ; i < s - > prim_channels ; i + + )
s - > scalefactor_adj [ i ] [ j ] = 1 ;
for ( j = 1 ; j < 11 ; j + + )
for ( i = 0 ; i < s - > prim_channels ; i + + )
if ( s - > quant_index_huffman [ i ] [ j ] < thr [ j ] )
s - > scalefactor_adj [ i ] [ j ] = adj_table [ get_bits ( & s - > gb , 2 ) ] ;
if ( s - > crc_present ) {
/* Audio header CRC check */
get_bits ( & s - > gb , 16 ) ;
}
s - > current_subframe = 0 ;
s - > current_subsubframe = 0 ;
# ifdef TRACE
av_log ( s - > avctx , AV_LOG_DEBUG , " subframes: %i \n " , s - > subframes ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " prim channels: %i \n " , s - > prim_channels ) ;
for ( i = 0 ; i < s - > prim_channels ; i + + ) {
av_log ( s - > avctx , AV_LOG_DEBUG , " subband activity: %i \n " , s - > subband_activity [ i ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " vq start subband: %i \n " , s - > vq_start_subband [ i ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " joint intensity: %i \n " , s - > joint_intensity [ i ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " transient mode codebook: %i \n " , s - > transient_huffman [ i ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " scale factor codebook: %i \n " , s - > scalefactor_huffman [ i ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " bit allocation quantizer: %i \n " , s - > bitalloc_huffman [ i ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " quant index huff: " ) ;
for ( j = 0 ; j < 11 ; j + + )
av_log ( s - > avctx , AV_LOG_DEBUG , " %i " ,
s - > quant_index_huffman [ i ] [ j ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " \n " ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " scalefac adj: " ) ;
for ( j = 0 ; j < 11 ; j + + )
av_log ( s - > avctx , AV_LOG_DEBUG , " %1.3f " , s - > scalefactor_adj [ i ] [ j ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " \n " ) ;
}
# endif
return 0 ;
}
2007-04-24 20:31:39 +03:00
static inline int get_scale ( GetBitContext * gb , int level , int value )
2007-02-27 08:30:40 +02:00
{
if ( level < 5 ) {
/* huffman encoded */
2007-04-24 20:31:39 +03:00
value + = get_bitalloc ( gb , & dca_scalefactor , level ) ;
2007-02-27 08:30:40 +02:00
} else if ( level < 8 )
value = get_bits ( gb , level + 1 ) ;
return value ;
}
static int dca_subframe_header ( DCAContext * s )
{
/* Primary audio coding side information */
int j , k ;
s - > subsubframes = get_bits ( & s - > gb , 2 ) + 1 ;
s - > partial_samples = get_bits ( & s - > gb , 3 ) ;
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
for ( k = 0 ; k < s - > subband_activity [ j ] ; k + + )
s - > prediction_mode [ j ] [ k ] = get_bits ( & s - > gb , 1 ) ;
}
/* Get prediction codebook */
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
for ( k = 0 ; k < s - > subband_activity [ j ] ; k + + ) {
if ( s - > prediction_mode [ j ] [ k ] > 0 ) {
/* (Prediction coefficient VQ address) */
s - > prediction_vq [ j ] [ k ] = get_bits ( & s - > gb , 12 ) ;
}
}
}
/* Bit allocation index */
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
for ( k = 0 ; k < s - > vq_start_subband [ j ] ; k + + ) {
if ( s - > bitalloc_huffman [ j ] = = 6 )
s - > bitalloc [ j ] [ k ] = get_bits ( & s - > gb , 5 ) ;
else if ( s - > bitalloc_huffman [ j ] = = 5 )
s - > bitalloc [ j ] [ k ] = get_bits ( & s - > gb , 4 ) ;
2008-03-06 16:22:02 +02:00
else if ( s - > bitalloc_huffman [ j ] = = 7 ) {
av_log ( s - > avctx , AV_LOG_ERROR ,
" Invalid bit allocation index \n " ) ;
return - 1 ;
} else {
2007-02-27 08:30:40 +02:00
s - > bitalloc [ j ] [ k ] =
2007-04-24 20:31:39 +03:00
get_bitalloc ( & s - > gb , & dca_bitalloc_index , s - > bitalloc_huffman [ j ] ) ;
2007-02-27 08:30:40 +02:00
}
if ( s - > bitalloc [ j ] [ k ] > 26 ) {
// av_log(s->avctx,AV_LOG_DEBUG,"bitalloc index [%i][%i] too big (%i)\n",
// j, k, s->bitalloc[j][k]);
return - 1 ;
}
}
}
/* Transition mode */
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
for ( k = 0 ; k < s - > subband_activity [ j ] ; k + + ) {
s - > transition_mode [ j ] [ k ] = 0 ;
if ( s - > subsubframes > 1 & &
k < s - > vq_start_subband [ j ] & & s - > bitalloc [ j ] [ k ] > 0 ) {
s - > transition_mode [ j ] [ k ] =
get_bitalloc ( & s - > gb , & dca_tmode , s - > transient_huffman [ j ] ) ;
}
}
}
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
2008-02-01 03:40:46 +02:00
const uint32_t * scale_table ;
2007-02-27 08:30:40 +02:00
int scale_sum ;
memset ( s - > scale_factor [ j ] , 0 , s - > subband_activity [ j ] * sizeof ( s - > scale_factor [ 0 ] [ 0 ] [ 0 ] ) * 2 ) ;
if ( s - > scalefactor_huffman [ j ] = = 6 )
2008-02-01 03:40:46 +02:00
scale_table = scale_factor_quant7 ;
2007-02-27 08:30:40 +02:00
else
2008-02-01 03:40:46 +02:00
scale_table = scale_factor_quant6 ;
2007-02-27 08:30:40 +02:00
/* When huffman coded, only the difference is encoded */
scale_sum = 0 ;
for ( k = 0 ; k < s - > subband_activity [ j ] ; k + + ) {
if ( k > = s - > vq_start_subband [ j ] | | s - > bitalloc [ j ] [ k ] > 0 ) {
2007-04-24 20:31:39 +03:00
scale_sum = get_scale ( & s - > gb , s - > scalefactor_huffman [ j ] , scale_sum ) ;
2007-02-27 08:30:40 +02:00
s - > scale_factor [ j ] [ k ] [ 0 ] = scale_table [ scale_sum ] ;
}
if ( k < s - > vq_start_subband [ j ] & & s - > transition_mode [ j ] [ k ] ) {
/* Get second scale factor */
2007-04-24 20:31:39 +03:00
scale_sum = get_scale ( & s - > gb , s - > scalefactor_huffman [ j ] , scale_sum ) ;
2007-02-27 08:30:40 +02:00
s - > scale_factor [ j ] [ k ] [ 1 ] = scale_table [ scale_sum ] ;
}
}
}
/* Joint subband scale factor codebook select */
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
/* Transmitted only if joint subband coding enabled */
if ( s - > joint_intensity [ j ] > 0 )
s - > joint_huff [ j ] = get_bits ( & s - > gb , 3 ) ;
}
/* Scale factors for joint subband coding */
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
int source_channel ;
/* Transmitted only if joint subband coding enabled */
if ( s - > joint_intensity [ j ] > 0 ) {
int scale = 0 ;
source_channel = s - > joint_intensity [ j ] - 1 ;
/* When huffman coded, only the difference is encoded
* ( is this valid as well for joint scales ? ? ? ) */
for ( k = s - > subband_activity [ j ] ; k < s - > subband_activity [ source_channel ] ; k + + ) {
2007-04-24 20:31:39 +03:00
scale = get_scale ( & s - > gb , s - > joint_huff [ j ] , 0 ) ;
2007-02-27 08:30:40 +02:00
scale + = 64 ; /* bias */
s - > joint_scale_factor [ j ] [ k ] = scale ; /*joint_scale_table[scale]; */
}
if ( ! s - > debug_flag & 0x02 ) {
av_log ( s - > avctx , AV_LOG_DEBUG ,
" Joint stereo coding not supported \n " ) ;
s - > debug_flag | = 0x02 ;
}
}
}
/* Stereo downmix coefficients */
2007-05-02 23:33:32 +03:00
if ( s - > prim_channels > 2 ) {
if ( s - > downmix ) {
2007-05-02 23:42:44 +03:00
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
s - > downmix_coef [ j ] [ 0 ] = get_bits ( & s - > gb , 7 ) ;
s - > downmix_coef [ j ] [ 1 ] = get_bits ( & s - > gb , 7 ) ;
}
2007-05-02 23:33:32 +03:00
} else {
int am = s - > amode & DCA_CHANNEL_MASK ;
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
s - > downmix_coef [ j ] [ 0 ] = dca_default_coeffs [ am ] [ j ] [ 0 ] ;
s - > downmix_coef [ j ] [ 1 ] = dca_default_coeffs [ am ] [ j ] [ 1 ] ;
}
}
2007-02-27 08:30:40 +02:00
}
/* Dynamic range coefficient */
if ( s - > dynrange )
s - > dynrange_coef = get_bits ( & s - > gb , 8 ) ;
/* Side information CRC check word */
if ( s - > crc_present ) {
get_bits ( & s - > gb , 16 ) ;
}
/*
* Primary audio data arrays
*/
/* VQ encoded high frequency subbands */
for ( j = 0 ; j < s - > prim_channels ; j + + )
for ( k = s - > vq_start_subband [ j ] ; k < s - > subband_activity [ j ] ; k + + )
/* 1 vector -> 32 samples */
s - > high_freq_vq [ j ] [ k ] = get_bits ( & s - > gb , 10 ) ;
/* Low frequency effect data */
if ( s - > lfe ) {
/* LFE samples */
int lfe_samples = 2 * s - > lfe * s - > subsubframes ;
float lfe_scale ;
for ( j = lfe_samples ; j < lfe_samples * 2 ; j + + ) {
/* Signed 8 bits int */
s - > lfe_data [ j ] = get_sbits ( & s - > gb , 8 ) ;
}
/* Scale factor index */
s - > lfe_scale_factor = scale_factor_quant7 [ get_bits ( & s - > gb , 8 ) ] ;
/* Quantization step size * scale factor */
lfe_scale = 0.035 * s - > lfe_scale_factor ;
for ( j = lfe_samples ; j < lfe_samples * 2 ; j + + )
s - > lfe_data [ j ] * = lfe_scale ;
}
# ifdef TRACE
av_log ( s - > avctx , AV_LOG_DEBUG , " subsubframes: %i \n " , s - > subsubframes ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " partial samples: %i \n " ,
s - > partial_samples ) ;
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
av_log ( s - > avctx , AV_LOG_DEBUG , " prediction mode: " ) ;
for ( k = 0 ; k < s - > subband_activity [ j ] ; k + + )
av_log ( s - > avctx , AV_LOG_DEBUG , " %i " , s - > prediction_mode [ j ] [ k ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " \n " ) ;
}
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
for ( k = 0 ; k < s - > subband_activity [ j ] ; k + + )
av_log ( s - > avctx , AV_LOG_DEBUG ,
" prediction coefs: %f, %f, %f, %f \n " ,
( float ) adpcm_vb [ s - > prediction_vq [ j ] [ k ] ] [ 0 ] / 8192 ,
( float ) adpcm_vb [ s - > prediction_vq [ j ] [ k ] ] [ 1 ] / 8192 ,
( float ) adpcm_vb [ s - > prediction_vq [ j ] [ k ] ] [ 2 ] / 8192 ,
( float ) adpcm_vb [ s - > prediction_vq [ j ] [ k ] ] [ 3 ] / 8192 ) ;
}
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
av_log ( s - > avctx , AV_LOG_DEBUG , " bitalloc index: " ) ;
for ( k = 0 ; k < s - > vq_start_subband [ j ] ; k + + )
av_log ( s - > avctx , AV_LOG_DEBUG , " %2.2i " , s - > bitalloc [ j ] [ k ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " \n " ) ;
}
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
av_log ( s - > avctx , AV_LOG_DEBUG , " Transition mode: " ) ;
for ( k = 0 ; k < s - > subband_activity [ j ] ; k + + )
av_log ( s - > avctx , AV_LOG_DEBUG , " %i " , s - > transition_mode [ j ] [ k ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " \n " ) ;
}
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
av_log ( s - > avctx , AV_LOG_DEBUG , " Scale factor: " ) ;
for ( k = 0 ; k < s - > subband_activity [ j ] ; k + + ) {
if ( k > = s - > vq_start_subband [ j ] | | s - > bitalloc [ j ] [ k ] > 0 )
av_log ( s - > avctx , AV_LOG_DEBUG , " %i " , s - > scale_factor [ j ] [ k ] [ 0 ] ) ;
if ( k < s - > vq_start_subband [ j ] & & s - > transition_mode [ j ] [ k ] )
av_log ( s - > avctx , AV_LOG_DEBUG , " %i(t) " , s - > scale_factor [ j ] [ k ] [ 1 ] ) ;
}
av_log ( s - > avctx , AV_LOG_DEBUG , " \n " ) ;
}
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
if ( s - > joint_intensity [ j ] > 0 ) {
2007-05-24 07:02:47 +03:00
int source_channel = s - > joint_intensity [ j ] - 1 ;
2007-02-27 08:30:40 +02:00
av_log ( s - > avctx , AV_LOG_DEBUG , " Joint scale factor index: \n " ) ;
for ( k = s - > subband_activity [ j ] ; k < s - > subband_activity [ source_channel ] ; k + + )
av_log ( s - > avctx , AV_LOG_DEBUG , " %i " , s - > joint_scale_factor [ j ] [ k ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " \n " ) ;
}
}
if ( s - > prim_channels > 2 & & s - > downmix ) {
av_log ( s - > avctx , AV_LOG_DEBUG , " Downmix coeffs: \n " ) ;
for ( j = 0 ; j < s - > prim_channels ; j + + ) {
av_log ( s - > avctx , AV_LOG_DEBUG , " Channel 0,%d = %f \n " , j , dca_downmix_coeffs [ s - > downmix_coef [ j ] [ 0 ] ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " Channel 1,%d = %f \n " , j , dca_downmix_coeffs [ s - > downmix_coef [ j ] [ 1 ] ] ) ;
}
av_log ( s - > avctx , AV_LOG_DEBUG , " \n " ) ;
}
for ( j = 0 ; j < s - > prim_channels ; j + + )
for ( k = s - > vq_start_subband [ j ] ; k < s - > subband_activity [ j ] ; k + + )
av_log ( s - > avctx , AV_LOG_DEBUG , " VQ index: %i \n " , s - > high_freq_vq [ j ] [ k ] ) ;
if ( s - > lfe ) {
2007-05-24 07:02:47 +03:00
int lfe_samples = 2 * s - > lfe * s - > subsubframes ;
2007-02-27 08:30:40 +02:00
av_log ( s - > avctx , AV_LOG_DEBUG , " LFE samples: \n " ) ;
for ( j = lfe_samples ; j < lfe_samples * 2 ; j + + )
av_log ( s - > avctx , AV_LOG_DEBUG , " %f " , s - > lfe_data [ j ] ) ;
av_log ( s - > avctx , AV_LOG_DEBUG , " \n " ) ;
}
# endif
return 0 ;
}
static void qmf_32_subbands ( DCAContext * s , int chans ,
float samples_in [ 32 ] [ 8 ] , float * samples_out ,
float scale , float bias )
{
2007-12-02 23:12:43 +02:00
const float * prCoeff ;
2008-08-30 13:47:13 +03:00
int i , j ;
DECLARE_ALIGNED_16 ( float , raXin [ 32 ] ) ;
2007-02-27 08:30:40 +02:00
2008-08-30 13:41:53 +03:00
int hist_index = s - > hist_index [ chans ] ;
2007-02-27 08:30:40 +02:00
float * subband_fir_hist2 = s - > subband_fir_noidea [ chans ] ;
2008-08-30 13:47:13 +03:00
int subindex ;
2007-02-27 08:30:40 +02:00
2008-08-30 13:47:13 +03:00
scale * = sqrt ( 1 / 8.0 ) ;
2007-02-27 08:30:40 +02:00
/* Select filter */
if ( ! s - > multirate_inter ) /* Non-perfect reconstruction */
2007-12-02 23:12:43 +02:00
prCoeff = fir_32bands_nonperfect ;
2007-02-27 08:30:40 +02:00
else /* Perfect reconstruction */
2007-12-02 23:12:43 +02:00
prCoeff = fir_32bands_perfect ;
2007-02-27 08:30:40 +02:00
/* Reconstructed channel sample index */
for ( subindex = 0 ; subindex < 8 ; subindex + + ) {
2008-08-30 13:41:53 +03:00
float * subband_fir_hist = s - > subband_fir_hist [ chans ] + hist_index ;
2007-02-27 08:30:40 +02:00
/* Load in one sample from each subband and clear inactive subbands */
2008-08-30 13:47:13 +03:00
for ( i = 0 ; i < s - > subband_activity [ chans ] ; i + + ) {
if ( ( i - 1 ) & 2 ) raXin [ i ] = - samples_in [ i ] [ subindex ] ;
else raXin [ i ] = samples_in [ i ] [ subindex ] ;
}
2007-02-27 08:30:40 +02:00
for ( ; i < 32 ; i + + )
raXin [ i ] = 0.0 ;
2008-08-30 13:47:13 +03:00
ff_imdct_half ( & s - > imdct , subband_fir_hist , raXin ) ;
2007-02-27 08:30:40 +02:00
/* Multiply by filter coefficients */
2008-08-30 13:47:13 +03:00
for ( i = 0 ; i < 16 ; i + + ) {
float a = subband_fir_hist2 [ i ] ;
float b = subband_fir_hist2 [ i + 16 ] ;
float c = 0 ;
float d = 0 ;
2008-08-30 13:41:53 +03:00
for ( j = 0 ; j < 512 - hist_index ; j + = 64 ) {
2008-08-30 13:47:13 +03:00
a + = prCoeff [ i + j ] * ( - subband_fir_hist [ 15 - i + j ] ) ;
b + = prCoeff [ i + j + 16 ] * ( subband_fir_hist [ i + j ] ) ;
c + = prCoeff [ i + j + 32 ] * ( subband_fir_hist [ 16 + i + j ] ) ;
d + = prCoeff [ i + j + 48 ] * ( subband_fir_hist [ 31 - i + j ] ) ;
2007-02-27 08:30:40 +02:00
}
2008-08-30 13:41:53 +03:00
for ( ; j < 512 ; j + = 64 ) {
2008-08-30 13:47:13 +03:00
a + = prCoeff [ i + j ] * ( - subband_fir_hist [ 15 - i + j - 512 ] ) ;
b + = prCoeff [ i + j + 16 ] * ( subband_fir_hist [ i + j - 512 ] ) ;
c + = prCoeff [ i + j + 32 ] * ( subband_fir_hist [ 16 + i + j - 512 ] ) ;
d + = prCoeff [ i + j + 48 ] * ( subband_fir_hist [ 31 - i + j - 512 ] ) ;
2008-08-30 13:41:53 +03:00
}
2008-08-30 13:47:13 +03:00
samples_out [ i ] = a * scale + bias ;
samples_out [ i + 16 ] = b * scale + bias ;
subband_fir_hist2 [ i ] = c ;
subband_fir_hist2 [ i + 16 ] = d ;
2008-08-29 21:37:40 +03:00
}
2008-08-30 13:47:13 +03:00
samples_out + = 32 ;
2007-02-27 08:30:40 +02:00
2008-08-30 13:41:53 +03:00
hist_index = ( hist_index - 32 ) & 511 ;
2007-02-27 08:30:40 +02:00
}
2008-08-30 13:41:53 +03:00
s - > hist_index [ chans ] = hist_index ;
2007-02-27 08:30:40 +02:00
}
static void lfe_interpolation_fir ( int decimation_select ,
int num_deci_sample , float * samples_in ,
float * samples_out , float scale ,
float bias )
{
/* samples_in: An array holding decimated samples.
* Samples in current subframe starts from samples_in [ 0 ] ,
* while samples_in [ - 1 ] , samples_in [ - 2 ] , . . . , stores samples
* from last subframe as history .
*
* samples_out : An array holding interpolated samples
*/
int decifactor , k , j ;
const float * prCoeff ;
int interp_index = 0 ; /* Index to the interpolated samples */
int deciindex ;
/* Select decimation filter */
if ( decimation_select = = 1 ) {
decifactor = 128 ;
prCoeff = lfe_fir_128 ;
} else {
decifactor = 64 ;
prCoeff = lfe_fir_64 ;
}
/* Interpolation */
for ( deciindex = 0 ; deciindex < num_deci_sample ; deciindex + + ) {
/* One decimated sample generates decifactor interpolated ones */
for ( k = 0 ; k < decifactor ; k + + ) {
float rTmp = 0.0 ;
//FIXME the coeffs are symetric, fix that
for ( j = 0 ; j < 512 / decifactor ; j + + )
rTmp + = samples_in [ deciindex - j ] * prCoeff [ k + j * decifactor ] ;
2008-10-26 11:54:53 +02:00
samples_out [ interp_index + + ] = ( rTmp * scale ) + bias ;
2007-02-27 08:30:40 +02:00
}
}
}
/* downmixing routines */
2007-05-02 23:33:32 +03:00
# define MIX_REAR1(samples, si1, rs, coef) \
samples [ i ] + = samples [ si1 ] * coef [ rs ] [ 0 ] ; \
samples [ i + 256 ] + = samples [ si1 ] * coef [ rs ] [ 1 ] ;
2007-02-27 08:30:40 +02:00
2007-05-02 23:33:32 +03:00
# define MIX_REAR2(samples, si1, si2, rs, coef) \
samples [ i ] + = samples [ si1 ] * coef [ rs ] [ 0 ] + samples [ si2 ] * coef [ rs + 1 ] [ 0 ] ; \
samples [ i + 256 ] + = samples [ si1 ] * coef [ rs ] [ 1 ] + samples [ si2 ] * coef [ rs + 1 ] [ 1 ] ;
2007-02-27 08:30:40 +02:00
2007-05-02 23:33:32 +03:00
# define MIX_FRONT3(samples, coef) \
2007-02-27 08:30:40 +02:00
t = samples [ i ] ; \
2007-05-02 23:33:32 +03:00
samples [ i ] = t * coef [ 0 ] [ 0 ] + samples [ i + 256 ] * coef [ 1 ] [ 0 ] + samples [ i + 512 ] * coef [ 2 ] [ 0 ] ; \
samples [ i + 256 ] = t * coef [ 0 ] [ 1 ] + samples [ i + 256 ] * coef [ 1 ] [ 1 ] + samples [ i + 512 ] * coef [ 2 ] [ 1 ] ;
2007-02-27 08:30:40 +02:00
# define DOWNMIX_TO_STEREO(op1, op2) \
for ( i = 0 ; i < 256 ; i + + ) { \
op1 \
op2 \
}
2007-05-02 23:33:32 +03:00
static void dca_downmix ( float * samples , int srcfmt ,
int downmix_coef [ DCA_PRIM_CHANNELS_MAX ] [ 2 ] )
2007-02-27 08:30:40 +02:00
{
int i ;
float t ;
2007-05-02 23:33:32 +03:00
float coef [ DCA_PRIM_CHANNELS_MAX ] [ 2 ] ;
for ( i = 0 ; i < DCA_PRIM_CHANNELS_MAX ; i + + ) {
coef [ i ] [ 0 ] = dca_downmix_coeffs [ downmix_coef [ i ] [ 0 ] ] ;
coef [ i ] [ 1 ] = dca_downmix_coeffs [ downmix_coef [ i ] [ 1 ] ] ;
}
2007-02-27 08:30:40 +02:00
switch ( srcfmt ) {
case DCA_MONO :
case DCA_CHANNEL :
case DCA_STEREO_TOTAL :
case DCA_STEREO_SUMDIFF :
case DCA_4F2R :
av_log ( NULL , 0 , " Not implemented! \n " ) ;
break ;
case DCA_STEREO :
break ;
case DCA_3F :
2007-05-02 23:33:32 +03:00
DOWNMIX_TO_STEREO ( MIX_FRONT3 ( samples , coef ) , ) ;
2007-02-27 08:30:40 +02:00
break ;
case DCA_2F1R :
2007-05-02 23:33:32 +03:00
DOWNMIX_TO_STEREO ( MIX_REAR1 ( samples , i + 512 , 2 , coef ) , ) ;
2007-02-27 08:30:40 +02:00
break ;
case DCA_3F1R :
2007-05-02 23:33:32 +03:00
DOWNMIX_TO_STEREO ( MIX_FRONT3 ( samples , coef ) ,
MIX_REAR1 ( samples , i + 768 , 3 , coef ) ) ;
2007-02-27 08:30:40 +02:00
break ;
case DCA_2F2R :
2007-05-02 23:33:32 +03:00
DOWNMIX_TO_STEREO ( MIX_REAR2 ( samples , i + 512 , i + 768 , 2 , coef ) , ) ;
2007-02-27 08:30:40 +02:00
break ;
case DCA_3F2R :
2007-05-02 23:33:32 +03:00
DOWNMIX_TO_STEREO ( MIX_FRONT3 ( samples , coef ) ,
MIX_REAR2 ( samples , i + 768 , i + 1024 , 3 , coef ) ) ;
2007-02-27 08:30:40 +02:00
break ;
}
}
/* Very compact version of the block code decoder that does not use table
* look - up but is slightly slower */
static int decode_blockcode ( int code , int levels , int * values )
{
int i ;
int offset = ( levels - 1 ) > > 1 ;
for ( i = 0 ; i < 4 ; i + + ) {
values [ i ] = ( code % levels ) - offset ;
code / = levels ;
}
if ( code = = 0 )
return 0 ;
else {
av_log ( NULL , AV_LOG_ERROR , " ERROR: block code look-up failed \n " ) ;
return - 1 ;
}
}
static const uint8_t abits_sizes [ 7 ] = { 7 , 10 , 12 , 13 , 15 , 17 , 19 } ;
static const uint8_t abits_levels [ 7 ] = { 3 , 5 , 7 , 9 , 13 , 17 , 25 } ;
static int dca_subsubframe ( DCAContext * s )
{
int k , l ;
int subsubframe = s - > current_subsubframe ;
2008-02-01 03:40:46 +02:00
const float * quant_step_table ;
2007-02-27 08:30:40 +02:00
/* FIXME */
float subband_samples [ DCA_PRIM_CHANNELS_MAX ] [ DCA_SUBBANDS ] [ 8 ] ;
/*
* Audio data
*/
/* Select quantization step size table */
2008-10-28 16:50:46 +02:00
if ( s - > bit_rate_index = = 0x1f )
2008-02-01 03:40:46 +02:00
quant_step_table = lossless_quant_d ;
2007-02-27 08:30:40 +02:00
else
2008-02-01 03:40:46 +02:00
quant_step_table = lossy_quant_d ;
2007-02-27 08:30:40 +02:00
for ( k = 0 ; k < s - > prim_channels ; k + + ) {
for ( l = 0 ; l < s - > vq_start_subband [ k ] ; l + + ) {
int m ;
/* Select the mid-tread linear quantizer */
int abits = s - > bitalloc [ k ] [ l ] ;
float quant_step_size = quant_step_table [ abits ] ;
float rscale ;
/*
* Determine quantization index code book and its type
*/
/* Select quantization index code book */
int sel = s - > quant_index_huffman [ k ] [ abits ] ;
/*
* Extract bits from the bit stream
*/
if ( ! abits ) {
memset ( subband_samples [ k ] [ l ] , 0 , 8 * sizeof ( subband_samples [ 0 ] [ 0 ] [ 0 ] ) ) ;
} else if ( abits > = 11 | | ! dca_smpl_bitalloc [ abits ] . vlc [ sel ] . table ) {
if ( abits < = 7 ) {
/* Block code */
int block_code1 , block_code2 , size , levels ;
int block [ 8 ] ;
size = abits_sizes [ abits - 1 ] ;
levels = abits_levels [ abits - 1 ] ;
block_code1 = get_bits ( & s - > gb , size ) ;
/* FIXME Should test return value */
decode_blockcode ( block_code1 , levels , block ) ;
block_code2 = get_bits ( & s - > gb , size ) ;
decode_blockcode ( block_code2 , levels , & block [ 4 ] ) ;
for ( m = 0 ; m < 8 ; m + + )
subband_samples [ k ] [ l ] [ m ] = block [ m ] ;
} else {
/* no coding */
for ( m = 0 ; m < 8 ; m + + )
subband_samples [ k ] [ l ] [ m ] = get_sbits ( & s - > gb , abits - 3 ) ;
}
} else {
/* Huffman coded */
for ( m = 0 ; m < 8 ; m + + )
subband_samples [ k ] [ l ] [ m ] = get_bitalloc ( & s - > gb , & dca_smpl_bitalloc [ abits ] , sel ) ;
}
/* Deal with transients */
if ( s - > transition_mode [ k ] [ l ] & &
subsubframe > = s - > transition_mode [ k ] [ l ] )
rscale = quant_step_size * s - > scale_factor [ k ] [ l ] [ 1 ] ;
else
rscale = quant_step_size * s - > scale_factor [ k ] [ l ] [ 0 ] ;
rscale * = s - > scalefactor_adj [ k ] [ sel ] ;
for ( m = 0 ; m < 8 ; m + + )
subband_samples [ k ] [ l ] [ m ] * = rscale ;
/*
* Inverse ADPCM if in prediction mode
*/
if ( s - > prediction_mode [ k ] [ l ] ) {
int n ;
for ( m = 0 ; m < 8 ; m + + ) {
for ( n = 1 ; n < = 4 ; n + + )
if ( m > = n )
subband_samples [ k ] [ l ] [ m ] + =
( adpcm_vb [ s - > prediction_vq [ k ] [ l ] ] [ n - 1 ] *
subband_samples [ k ] [ l ] [ m - n ] / 8192 ) ;
else if ( s - > predictor_history )
subband_samples [ k ] [ l ] [ m ] + =
( adpcm_vb [ s - > prediction_vq [ k ] [ l ] ] [ n - 1 ] *
s - > subband_samples_hist [ k ] [ l ] [ m - n +
4 ] / 8192 ) ;
}
}
}
/*
* Decode VQ encoded high frequencies
*/
for ( l = s - > vq_start_subband [ k ] ; l < s - > subband_activity [ k ] ; l + + ) {
/* 1 vector -> 32 samples but we only need the 8 samples
* for this subsubframe . */
int m ;
if ( ! s - > debug_flag & 0x01 ) {
av_log ( s - > avctx , AV_LOG_DEBUG , " Stream with high frequencies VQ coding \n " ) ;
s - > debug_flag | = 0x01 ;
}
for ( m = 0 ; m < 8 ; m + + ) {
subband_samples [ k ] [ l ] [ m ] =
high_freq_vq [ s - > high_freq_vq [ k ] [ l ] ] [ subsubframe * 8 +
m ]
* ( float ) s - > scale_factor [ k ] [ l ] [ 0 ] / 16.0 ;
}
}
}
/* Check for DSYNC after subsubframe */
if ( s - > aspf | | subsubframe = = s - > subsubframes - 1 ) {
if ( 0xFFFF = = get_bits ( & s - > gb , 16 ) ) { /* 0xFFFF */
# ifdef TRACE
av_log ( s - > avctx , AV_LOG_DEBUG , " Got subframe DSYNC \n " ) ;
# endif
} else {
av_log ( s - > avctx , AV_LOG_ERROR , " Didn't get subframe DSYNC \n " ) ;
}
}
/* Backup predictor history for adpcm */
for ( k = 0 ; k < s - > prim_channels ; k + + )
for ( l = 0 ; l < s - > vq_start_subband [ k ] ; l + + )
memcpy ( s - > subband_samples_hist [ k ] [ l ] , & subband_samples [ k ] [ l ] [ 4 ] ,
4 * sizeof ( subband_samples [ 0 ] [ 0 ] [ 0 ] ) ) ;
/* 32 subbands QMF */
for ( k = 0 ; k < s - > prim_channels ; k + + ) {
/* static float pcm_to_double[8] =
{ 32768.0 , 32768.0 , 524288.0 , 524288.0 , 0 , 8388608.0 , 8388608.0 } ; */
2008-11-15 22:31:03 +02:00
qmf_32_subbands ( s , k , subband_samples [ k ] , & s - > samples [ 256 * s - > channel_order_tab [ k ] ] ,
2008-10-26 11:54:53 +02:00
M_SQRT1_2 * s - > scale_bias /*pcm_to_double[s->source_pcm_res] */ ,
s - > add_bias ) ;
2007-02-27 08:30:40 +02:00
}
/* Down mixing */
if ( s - > prim_channels > dca_channels [ s - > output & DCA_CHANNEL_MASK ] ) {
2007-05-02 23:33:32 +03:00
dca_downmix ( s - > samples , s - > amode , s - > downmix_coef ) ;
2007-02-27 08:30:40 +02:00
}
/* Generate LFE samples for this subsubframe FIXME!!! */
if ( s - > output & DCA_LFE ) {
int lfe_samples = 2 * s - > lfe * s - > subsubframes ;
lfe_interpolation_fir ( s - > lfe , 2 * s - > lfe ,
s - > lfe_data + lfe_samples +
2 * s - > lfe * subsubframe ,
2008-11-15 22:31:03 +02:00
& s - > samples [ 256 * dca_lfe_index [ s - > amode ] ] ,
2008-10-26 11:54:53 +02:00
( 1.0 / 256.0 ) * s - > scale_bias , s - > add_bias ) ;
2007-02-27 08:30:40 +02:00
/* Outputs 20bits pcm samples */
}
return 0 ;
}
static int dca_subframe_footer ( DCAContext * s )
{
int aux_data_count = 0 , i ;
int lfe_samples ;
/*
* Unpack optional information
*/
if ( s - > timestamp )
get_bits ( & s - > gb , 32 ) ;
if ( s - > aux_data )
aux_data_count = get_bits ( & s - > gb , 6 ) ;
for ( i = 0 ; i < aux_data_count ; i + + )
get_bits ( & s - > gb , 8 ) ;
if ( s - > crc_present & & ( s - > downmix | | s - > dynrange ) )
get_bits ( & s - > gb , 16 ) ;
lfe_samples = 2 * s - > lfe * s - > subsubframes ;
for ( i = 0 ; i < lfe_samples ; i + + ) {
s - > lfe_data [ i ] = s - > lfe_data [ i + lfe_samples ] ;
}
return 0 ;
}
/**
* Decode a dca frame block
*
* @ param s pointer to the DCAContext
*/
static int dca_decode_block ( DCAContext * s )
{
/* Sanity check */
if ( s - > current_subframe > = s - > subframes ) {
av_log ( s - > avctx , AV_LOG_DEBUG , " check failed: %i>%i " ,
s - > current_subframe , s - > subframes ) ;
return - 1 ;
}
if ( ! s - > current_subsubframe ) {
# ifdef TRACE
av_log ( s - > avctx , AV_LOG_DEBUG , " DSYNC dca_subframe_header \n " ) ;
# endif
/* Read subframe header */
if ( dca_subframe_header ( s ) )
return - 1 ;
}
/* Read subsubframe */
# ifdef TRACE
av_log ( s - > avctx , AV_LOG_DEBUG , " DSYNC dca_subsubframe \n " ) ;
# endif
if ( dca_subsubframe ( s ) )
return - 1 ;
/* Update state */
s - > current_subsubframe + + ;
if ( s - > current_subsubframe > = s - > subsubframes ) {
s - > current_subsubframe = 0 ;
s - > current_subframe + + ;
}
if ( s - > current_subframe > = s - > subframes ) {
# ifdef TRACE
av_log ( s - > avctx , AV_LOG_DEBUG , " DSYNC dca_subframe_footer \n " ) ;
# endif
/* Read subframe footer */
if ( dca_subframe_footer ( s ) )
return - 1 ;
}
return 0 ;
}
/**
* Convert bitstream to one representation based on sync marker
*/
2008-02-01 03:40:46 +02:00
static int dca_convert_bitstream ( const uint8_t * src , int src_size , uint8_t * dst ,
2007-02-27 08:30:40 +02:00
int max_size )
{
uint32_t mrk ;
int i , tmp ;
2008-02-01 03:40:46 +02:00
const uint16_t * ssrc = ( const uint16_t * ) src ;
uint16_t * sdst = ( uint16_t * ) dst ;
2007-02-27 08:30:40 +02:00
PutBitContext pb ;
2007-05-18 13:06:07 +03:00
if ( ( unsigned ) src_size > ( unsigned ) max_size ) {
2008-11-29 12:06:37 +02:00
// av_log(NULL, AV_LOG_ERROR, "Input frame size larger then DCA_MAX_FRAME_SIZE!\n");
// return -1;
src_size = max_size ;
2007-05-18 13:06:07 +03:00
}
2007-04-27 15:41:55 +03:00
2007-02-27 08:30:40 +02:00
mrk = AV_RB32 ( src ) ;
switch ( mrk ) {
case DCA_MARKER_RAW_BE :
2008-08-23 16:35:12 +03:00
memcpy ( dst , src , src_size ) ;
return src_size ;
2007-02-27 08:30:40 +02:00
case DCA_MARKER_RAW_LE :
2008-08-23 16:35:12 +03:00
for ( i = 0 ; i < ( src_size + 1 ) > > 1 ; i + + )
2007-02-27 08:30:40 +02:00
* sdst + + = bswap_16 ( * ssrc + + ) ;
2008-08-23 16:35:12 +03:00
return src_size ;
2007-02-27 08:30:40 +02:00
case DCA_MARKER_14B_BE :
case DCA_MARKER_14B_LE :
init_put_bits ( & pb , dst , max_size ) ;
for ( i = 0 ; i < ( src_size + 1 ) > > 1 ; i + + , src + = 2 ) {
tmp = ( ( mrk = = DCA_MARKER_14B_BE ) ? AV_RB16 ( src ) : AV_RL16 ( src ) ) & 0x3FFF ;
put_bits ( & pb , 14 , tmp ) ;
}
flush_put_bits ( & pb ) ;
return ( put_bits_count ( & pb ) + 7 ) > > 3 ;
default :
return - 1 ;
}
}
/**
* Main frame decoding function
* FIXME add arguments
*/
static int dca_decode_frame ( AVCodecContext * avctx ,
void * data , int * data_size ,
2008-02-01 03:40:46 +02:00
const uint8_t * buf , int buf_size )
2007-02-27 08:30:40 +02:00
{
2008-08-29 13:09:51 +03:00
int i ;
2007-02-27 08:30:40 +02:00
int16_t * samples = data ;
DCAContext * s = avctx - > priv_data ;
int channels ;
s - > dca_buffer_size = dca_convert_bitstream ( buf , buf_size , s - > dca_buffer , DCA_MAX_FRAME_SIZE ) ;
if ( s - > dca_buffer_size = = - 1 ) {
2007-05-18 13:06:07 +03:00
av_log ( avctx , AV_LOG_ERROR , " Not a valid DCA frame \n " ) ;
2007-02-27 08:30:40 +02:00
return - 1 ;
}
init_get_bits ( & s - > gb , s - > dca_buffer , s - > dca_buffer_size * 8 ) ;
if ( dca_parse_frame_header ( s ) < 0 ) {
//seems like the frame is corrupt, try with the next one
2007-09-06 17:55:13 +03:00
* data_size = 0 ;
2007-02-27 08:30:40 +02:00
return buf_size ;
}
//set AVCodec values with parsed data
avctx - > sample_rate = s - > sample_rate ;
avctx - > bit_rate = s - > bit_rate ;
2007-05-02 23:31:32 +03:00
channels = s - > prim_channels + ! ! s - > lfe ;
2008-11-15 22:31:03 +02:00
if ( s - > amode < 16 ) {
2008-11-01 22:27:05 +02:00
avctx - > channel_layout = dca_core_channel_layout [ s - > amode ] ;
2008-11-15 22:31:03 +02:00
if ( s - > lfe ) {
avctx - > channel_layout | = CH_LOW_FREQUENCY ;
s - > channel_order_tab = dca_channel_reorder_lfe [ s - > amode ] ;
} else
s - > channel_order_tab = dca_channel_reorder_nolfe [ s - > amode ] ;
if ( avctx - > request_channels = = 2 & & s - > prim_channels > 2 ) {
channels = 2 ;
s - > output = DCA_STEREO ;
avctx - > channel_layout = CH_LAYOUT_STEREO ;
}
} else {
av_log ( avctx , AV_LOG_ERROR , " Non standard configuration %d ! \n " , s - > amode ) ;
return - 1 ;
}
2007-05-02 23:31:32 +03:00
2008-04-10 09:15:17 +03:00
/* There is nothing that prevents a dts frame to change channel configuration
but FFmpeg doesn ' t support that so only set the channels if it is previously
unset . Ideally during the first probe for channels the crc should be checked
and only set avctx - > channels when the crc is ok . Right now the decoder could
set the channels based on a broken first frame . */
if ( ! avctx - > channels )
avctx - > channels = channels ;
2007-02-27 08:30:40 +02:00
if ( * data_size < ( s - > sample_blocks / 8 ) * 256 * sizeof ( int16_t ) * channels )
return - 1 ;
2008-08-29 13:12:44 +03:00
* data_size = 256 / 8 * s - > sample_blocks * sizeof ( int16_t ) * channels ;
2007-02-27 08:30:40 +02:00
for ( i = 0 ; i < ( s - > sample_blocks / 8 ) ; i + + ) {
dca_decode_block ( s ) ;
2008-08-29 13:09:51 +03:00
s - > dsp . float_to_int16_interleave ( samples , s - > samples_chanptr , 256 , channels ) ;
samples + = 256 * channels ;
2007-02-27 08:30:40 +02:00
}
return buf_size ;
}
/**
* DCA initialization
*
* @ param avctx pointer to the AVCodecContext
*/
2008-03-21 05:11:20 +02:00
static av_cold int dca_decode_init ( AVCodecContext * avctx )
2007-02-27 08:30:40 +02:00
{
DCAContext * s = avctx - > priv_data ;
2008-08-29 13:09:51 +03:00
int i ;
2007-02-27 08:30:40 +02:00
s - > avctx = avctx ;
dca_init_vlcs ( ) ;
dsputil_init ( & s - > dsp , avctx ) ;
2008-08-30 13:47:13 +03:00
ff_mdct_init ( & s - > imdct , 6 , 1 ) ;
2008-01-05 23:23:57 +02:00
2008-08-29 13:09:51 +03:00
for ( i = 0 ; i < 6 ; i + + )
s - > samples_chanptr [ i ] = s - > samples + i * 256 ;
2008-07-31 13:47:31 +03:00
avctx - > sample_fmt = SAMPLE_FMT_S16 ;
2008-10-26 11:54:53 +02:00
if ( s - > dsp . float_to_int16 = = ff_float_to_int16_c ) {
s - > add_bias = 385.0f ;
s - > scale_bias = 1.0 / 32768.0 ;
} else {
s - > add_bias = 0.0f ;
s - > scale_bias = 1.0 ;
2008-10-26 12:14:16 +02:00
/* allow downmixing to stereo */
if ( avctx - > channels > 0 & & avctx - > request_channels < avctx - > channels & &
avctx - > request_channels = = 2 ) {
avctx - > channels = avctx - > request_channels ;
}
2008-10-26 11:54:53 +02:00
}
2007-02-27 08:30:40 +02:00
return 0 ;
}
2008-08-30 13:47:13 +03:00
static av_cold int dca_decode_end ( AVCodecContext * avctx )
{
DCAContext * s = avctx - > priv_data ;
ff_mdct_end ( & s - > imdct ) ;
return 0 ;
}
2007-02-27 08:30:40 +02:00
AVCodec dca_decoder = {
. name = " dca " ,
. type = CODEC_TYPE_AUDIO ,
. id = CODEC_ID_DTS ,
. priv_data_size = sizeof ( DCAContext ) ,
. init = dca_decode_init ,
. decode = dca_decode_frame ,
2008-08-30 13:47:13 +03:00
. close = dca_decode_end ,
2008-06-13 00:50:13 +03:00
. long_name = NULL_IF_CONFIG_SMALL ( " DCA (DTS Coherent Acoustics) " ) ,
2007-02-27 08:30:40 +02:00
} ;