00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029 #include <vlc/vlc.h>
00030
00031 #include <stdlib.h>
00032 #include <string.h>
00033
00034 #include <dts.h>
00035
00036 #include <vlc/decoder.h>
00037 #include "aout_internal.h"
00038 #include "vlc_filter.h"
00039
00040
00041
00042
00043 static int Create ( vlc_object_t * );
00044 static void Destroy ( vlc_object_t * );
00045 static void DoWork ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
00046 aout_buffer_t * );
00047
00048 static int Open ( vlc_object_t *, filter_sys_t *,
00049 audio_format_t, audio_format_t );
00050
00051 static int OpenFilter ( vlc_object_t * );
00052 static void CloseFilter( vlc_object_t * );
00053 static block_t *Convert( filter_t *, block_t * );
00054
00055
00056 static const uint32_t pi_channels_in[] =
00057 { AOUT_CHAN_CENTER, AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT,
00058 AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, AOUT_CHAN_LFE, 0 };
00059
00060 static const uint32_t pi_channels_out[] =
00061 { AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
00062 AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };
00063
00064
00065
00066
00067 struct filter_sys_t
00068 {
00069 dts_state_t * p_libdts;
00070 vlc_bool_t b_dynrng;
00071 int i_flags;
00072 vlc_bool_t b_dontwarn;
00073 int i_nb_channels;
00074
00075 int pi_chan_table[AOUT_CHAN_MAX];
00076 };
00077
00078
00079
00080
00081 #define DYNRNG_TEXT N_("DTS dynamic range compression")
00082 #define DYNRNG_LONGTEXT N_( \
00083 "Dynamic range compression makes the loud sounds softer, and the soft " \
00084 "sounds louder, so you can more easily listen to the stream in a noisy " \
00085 "environment without disturbing anyone. If you disable the dynamic range "\
00086 "compression the playback will be more adapted to a movie theater or a " \
00087 "listening room.")
00088
00089 vlc_module_begin();
00090 set_category( CAT_INPUT );
00091 set_subcategory( SUBCAT_INPUT_ACODEC );
00092 set_shortname( _("DTS" ) );
00093 set_description( _("DTS Coherent Acoustics audio decoder") );
00094 add_bool( "dts-dynrng", 1, NULL, DYNRNG_TEXT, DYNRNG_LONGTEXT, VLC_FALSE );
00095 set_capability( "audio filter", 100 );
00096 set_callbacks( Create, Destroy );
00097
00098 add_submodule();
00099 set_description( _("DTS Coherent Acoustics audio decoder") );
00100 set_capability( "audio filter2", 100 );
00101 set_callbacks( OpenFilter, CloseFilter );
00102 vlc_module_end();
00103
00104
00105
00106
00107 static int Create( vlc_object_t *p_this )
00108 {
00109 aout_filter_t *p_filter = (aout_filter_t *)p_this;
00110 filter_sys_t *p_sys;
00111 int i_ret;
00112
00113 if ( p_filter->input.i_format != VLC_FOURCC('d','t','s',' ')
00114 || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
00115 {
00116 return -1;
00117 }
00118
00119 if ( p_filter->input.i_rate != p_filter->output.i_rate )
00120 {
00121 return -1;
00122 }
00123
00124
00125 p_sys = malloc( sizeof(filter_sys_t) );
00126 p_filter->p_sys = (struct aout_filter_sys_t *)p_sys;
00127 if( p_sys == NULL )
00128 {
00129 msg_Err( p_filter, "out of memory" );
00130 return -1;
00131 }
00132
00133 i_ret = Open( VLC_OBJECT(p_filter), p_sys,
00134 p_filter->input, p_filter->output );
00135
00136 p_filter->pf_do_work = DoWork;
00137 p_filter->b_in_place = 0;
00138
00139 return i_ret;
00140 }
00141
00142
00143
00144
00145 static int Open( vlc_object_t *p_this, filter_sys_t *p_sys,
00146 audio_format_t input, audio_format_t output )
00147 {
00148 p_sys->b_dynrng = config_GetInt( p_this, "dts-dynrng" );
00149 p_sys->b_dontwarn = 0;
00150
00151
00152 p_sys->i_nb_channels = aout_FormatNbChannels( &output );
00153 switch ( (output.i_physical_channels & AOUT_CHAN_PHYSMASK)
00154 & ~AOUT_CHAN_LFE )
00155 {
00156 case AOUT_CHAN_CENTER:
00157 if ( (output.i_original_channels & AOUT_CHAN_CENTER)
00158 || (output.i_original_channels
00159 & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
00160 {
00161 p_sys->i_flags = DTS_MONO;
00162 }
00163 break;
00164
00165 case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT:
00166 if ( output.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
00167 {
00168 p_sys->i_flags = DTS_DOLBY;
00169 }
00170 else if ( input.i_original_channels == AOUT_CHAN_CENTER )
00171 {
00172 p_sys->i_flags = DTS_MONO;
00173 }
00174 else if ( input.i_original_channels & AOUT_CHAN_DUALMONO )
00175 {
00176 p_sys->i_flags = DTS_CHANNEL;
00177 }
00178 else
00179 {
00180 p_sys->i_flags = DTS_STEREO;
00181 }
00182 break;
00183
00184 case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER:
00185 p_sys->i_flags = DTS_3F;
00186 break;
00187
00188 case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARCENTER:
00189 p_sys->i_flags = DTS_2F1R;
00190 break;
00191
00192 case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
00193 | AOUT_CHAN_REARCENTER:
00194 p_sys->i_flags = DTS_3F1R;
00195 break;
00196
00197 case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
00198 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT:
00199 p_sys->i_flags = DTS_2F2R;
00200 break;
00201
00202 case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
00203 | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT:
00204 p_sys->i_flags = DTS_3F2R;
00205 break;
00206
00207 default:
00208 msg_Warn( p_this, "unknown sample format!" );
00209 free( p_sys );
00210 return -1;
00211 }
00212 if ( output.i_physical_channels & AOUT_CHAN_LFE )
00213 {
00214 p_sys->i_flags |= DTS_LFE;
00215 }
00216
00217
00218
00219 p_sys->p_libdts = dts_init( 0 );
00220 if( p_sys->p_libdts == NULL )
00221 {
00222 msg_Err( p_this, "unable to initialize libdts" );
00223 return VLC_EGENERIC;
00224 }
00225
00226 aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
00227 output.i_physical_channels & AOUT_CHAN_PHYSMASK,
00228 p_sys->i_nb_channels,
00229 p_sys->pi_chan_table );
00230
00231 return VLC_SUCCESS;
00232 }
00233
00234
00235
00236
00237 static void Interleave( float * p_out, const float * p_in, int i_nb_channels,
00238 int *pi_chan_table )
00239 {
00240
00241
00242 int i, j;
00243 for ( j = 0; j < i_nb_channels; j++ )
00244 {
00245 for ( i = 0; i < 256; i++ )
00246 {
00247 p_out[i * i_nb_channels + pi_chan_table[j]] = p_in[j * 256 + i];
00248 }
00249 }
00250 }
00251
00252
00253
00254
00255 static void Duplicate( float * p_out, const float * p_in )
00256 {
00257 int i;
00258
00259 for ( i = 256; i--; )
00260 {
00261 *p_out++ = *p_in;
00262 *p_out++ = *p_in;
00263 p_in++;
00264 }
00265 }
00266
00267
00268
00269
00270 static void Exchange( float * p_out, const float * p_in )
00271 {
00272 int i;
00273 const float * p_first = p_in + 256;
00274 const float * p_second = p_in;
00275
00276 for ( i = 0; i < 256; i++ )
00277 {
00278 *p_out++ = *p_first++;
00279 *p_out++ = *p_second++;
00280 }
00281 }
00282
00283
00284
00285
00286 static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
00287 aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
00288 {
00289 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
00290 sample_t i_sample_level = 1;
00291 int i_flags = p_sys->i_flags;
00292 int i_bytes_per_block = 256 * p_sys->i_nb_channels
00293 * sizeof(float);
00294 int i;
00295
00296
00297
00298
00299
00300
00301
00302 int i_sample_rate, i_bit_rate, i_frame_length;
00303 if( !dts_syncinfo( p_sys->p_libdts, p_in_buf->p_buffer, &i_flags,
00304 &i_sample_rate, &i_bit_rate, &i_frame_length ) )
00305 {
00306 msg_Warn( p_aout, "libdts couldn't sync on frame" );
00307 p_out_buf->i_nb_samples = p_out_buf->i_nb_bytes = 0;
00308 return;
00309 }
00310
00311 i_flags = p_sys->i_flags;
00312 dts_frame( p_sys->p_libdts, p_in_buf->p_buffer,
00313 &i_flags, &i_sample_level, 0 );
00314
00315 if ( (i_flags & DTS_CHANNEL_MASK) != (p_sys->i_flags & DTS_CHANNEL_MASK)
00316 && !p_sys->b_dontwarn )
00317 {
00318 msg_Warn( p_aout,
00319 "libdts couldn't do the requested downmix 0x%x->0x%x",
00320 p_sys->i_flags & DTS_CHANNEL_MASK,
00321 i_flags & DTS_CHANNEL_MASK );
00322
00323 p_sys->b_dontwarn = 1;
00324 }
00325
00326 if( 0)
00327 {
00328 dts_dynrng( p_sys->p_libdts, NULL, NULL );
00329 }
00330
00331 for ( i = 0; i < dts_blocks_num(p_sys->p_libdts); i++ )
00332 {
00333 sample_t * p_samples;
00334
00335 if( dts_block( p_sys->p_libdts ) )
00336 {
00337 msg_Warn( p_aout, "dts_block failed for block %d", i );
00338 break;
00339 }
00340
00341 p_samples = dts_samples( p_sys->p_libdts );
00342
00343 if ( (p_sys->i_flags & DTS_CHANNEL_MASK) == DTS_MONO
00344 && (p_filter->output.i_physical_channels
00345 & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
00346 {
00347 Duplicate( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
00348 p_samples );
00349 }
00350 else if ( p_filter->output.i_original_channels
00351 & AOUT_CHAN_REVERSESTEREO )
00352 {
00353 Exchange( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
00354 p_samples );
00355 }
00356 else
00357 {
00358
00359 Interleave( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
00360 p_samples, p_sys->i_nb_channels, p_sys->pi_chan_table);
00361 }
00362 }
00363
00364 p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
00365 p_out_buf->i_nb_bytes = i_bytes_per_block * i;
00366 }
00367
00368
00369
00370
00371 static void Destroy( vlc_object_t *p_this )
00372 {
00373 aout_filter_t *p_filter = (aout_filter_t *)p_this;
00374 filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
00375
00376 dts_free( p_sys->p_libdts );
00377 free( p_sys );
00378 }
00379
00380
00381
00382
00383 static int OpenFilter( vlc_object_t *p_this )
00384 {
00385 filter_t *p_filter = (filter_t *)p_this;
00386 filter_sys_t *p_sys;
00387 int i_ret;
00388
00389 if( p_filter->fmt_in.i_codec != VLC_FOURCC('d','t','s',' ') )
00390 {
00391 return VLC_EGENERIC;
00392 }
00393
00394 p_filter->fmt_out.audio.i_format =
00395 p_filter->fmt_out.i_codec = VLC_FOURCC('f','l','3','2');
00396
00397
00398 p_sys = p_filter->p_sys = malloc( sizeof(filter_sys_t) );
00399 if( p_sys == NULL )
00400 {
00401 msg_Err( p_filter, "out of memory" );
00402 return VLC_EGENERIC;
00403 }
00404
00405
00406 p_filter->p_sys = p_sys = malloc( sizeof(filter_sys_t) );
00407 if( p_sys == NULL )
00408 {
00409 msg_Err( p_filter, "out of memory" );
00410 return VLC_EGENERIC;
00411 }
00412
00413 i_ret = Open( VLC_OBJECT(p_filter), p_sys,
00414 p_filter->fmt_in.audio, p_filter->fmt_out.audio );
00415
00416 p_filter->pf_audio_filter = Convert;
00417 p_filter->fmt_out.audio.i_rate = p_filter->fmt_in.audio.i_rate;
00418
00419 return i_ret;
00420 }
00421
00422
00423
00424
00425 static void CloseFilter( vlc_object_t *p_this )
00426 {
00427 filter_t *p_filter = (filter_t *)p_this;
00428 filter_sys_t *p_sys = p_filter->p_sys;
00429
00430 dts_free( p_sys->p_libdts );
00431 free( p_sys );
00432 }
00433
00434 static block_t *Convert( filter_t *p_filter, block_t *p_block )
00435 {
00436 aout_filter_t aout_filter;
00437 aout_buffer_t in_buf, out_buf;
00438 block_t *p_out;
00439 int i_out_size;
00440
00441 if( !p_block || !p_block->i_samples )
00442 {
00443 if( p_block ) p_block->pf_release( p_block );
00444 return NULL;
00445 }
00446
00447 i_out_size = p_block->i_samples *
00448 p_filter->fmt_out.audio.i_bitspersample *
00449 p_filter->fmt_out.audio.i_channels / 8;
00450
00451 p_out = p_filter->pf_audio_buffer_new( p_filter, i_out_size );
00452 if( !p_out )
00453 {
00454 msg_Warn( p_filter, "can't get output buffer" );
00455 p_block->pf_release( p_block );
00456 return NULL;
00457 }
00458
00459 p_out->i_samples = p_block->i_samples;
00460 p_out->i_dts = p_block->i_dts;
00461 p_out->i_pts = p_block->i_pts;
00462 p_out->i_length = p_block->i_length;
00463
00464 aout_filter.p_sys = (struct aout_filter_sys_t *)p_filter->p_sys;
00465 aout_filter.input = p_filter->fmt_in.audio;
00466 aout_filter.input.i_format = p_filter->fmt_in.i_codec;
00467 aout_filter.output = p_filter->fmt_out.audio;
00468 aout_filter.output.i_format = p_filter->fmt_out.i_codec;
00469
00470 in_buf.p_buffer = p_block->p_buffer;
00471 in_buf.i_nb_bytes = p_block->i_buffer;
00472 in_buf.i_nb_samples = p_block->i_samples;
00473 out_buf.p_buffer = p_out->p_buffer;
00474 out_buf.i_nb_bytes = p_out->i_buffer;
00475 out_buf.i_nb_samples = p_out->i_samples;
00476
00477 DoWork( (aout_instance_t *)p_filter, &aout_filter, &in_buf, &out_buf );
00478
00479 p_out->i_buffer = out_buf.i_nb_bytes;
00480 p_out->i_samples = out_buf.i_nb_samples;
00481
00482 p_block->pf_release( p_block );
00483
00484 return p_out;
00485 }