a52tofloat32.c 16.9 KB
Newer Older
1 2 3 4 5
/*****************************************************************************
 * a52tofloat32.c: ATSC A/52 aka AC-3 decoder plugin for VLC.
 *   This plugin makes use of liba52 to decode A/52 audio
 *   (http://liba52.sf.net/).
 *****************************************************************************
6
 * Copyright (C) 2001, 2002 the VideoLAN team
7
 * $Id$
8
 *
9
 * Authors: Gildas Bazin <gbazin@videolan.org>
10
 *          Christophe Massiot <massiot@via.ecp.fr>
11
 *
12 13 14 15
 * 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.
16
 *
17 18 19 20 21 22 23
 * 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
dionoea's avatar
dionoea committed
24
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <vlc/vlc.h>

#include <string.h>                                              /* strdup() */
#ifdef HAVE_STDINT_H
#   include <stdint.h>                                         /* int16_t .. */
#elif HAVE_INTTYPES_H
#   include <inttypes.h>                                       /* int16_t .. */
#endif

#ifdef HAVE_UNISTD_H
#   include <unistd.h>
#endif

#ifdef USE_A52DEC_TREE                                 /* liba52 header file */
#   include "include/a52.h"
#else
#   include "a52dec/a52.h"
#endif

zorglub's avatar
zorglub committed
49 50 51
#include <vlc_aout.h>
#include <vlc_block.h>
#include <vlc_filter.h>
52 53 54 55 56 57

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int  Create    ( vlc_object_t * );
static void Destroy   ( vlc_object_t * );
Jean-Paul Saman's avatar
Jean-Paul Saman committed
58
static void DoWork    ( aout_instance_t *, aout_filter_t *, aout_buffer_t *,
59
                        aout_buffer_t * );
60 61 62 63 64 65
static int  Open      ( vlc_object_t *, filter_sys_t *,
                        audio_format_t, audio_format_t );

static int  OpenFilter ( vlc_object_t * );
static void CloseFilter( vlc_object_t * );
static block_t *Convert( filter_t *, block_t * );
66

67 68 69 70 71 72 73 74 75
/* liba52 channel order */
static const uint32_t pi_channels_in[] =
{ AOUT_CHAN_LFE, AOUT_CHAN_LEFT, AOUT_CHAN_CENTER, AOUT_CHAN_RIGHT,
  AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT, 0 };
/* our internal channel order (WG-4 order) */
static const uint32_t pi_channels_out[] =
{ AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
  AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };

76 77 78
/*****************************************************************************
 * Local structures
 *****************************************************************************/
79
struct filter_sys_t
80 81 82 83
{
    a52_state_t * p_liba52; /* liba52 internal structure */
    vlc_bool_t b_dynrng; /* see below */
    int i_flags; /* liba52 flags, see a52dec/doc/liba52.txt */
84
    vlc_bool_t b_dontwarn;
85
    int i_nb_channels; /* number of float32 per sample */
86 87

    int pi_chan_table[AOUT_CHAN_MAX]; /* channel reordering */
88 89 90 91 92 93 94 95 96 97 98 99
};

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
#define DYNRNG_TEXT N_("A/52 dynamic range compression")
#define DYNRNG_LONGTEXT N_( \
    "Dynamic range compression makes the loud sounds softer, and the soft " \
    "sounds louder, so you can more easily listen to the stream in a noisy " \
    "environment without disturbing anyone. If you disable the dynamic range "\
    "compression the playback will be more adapted to a movie theater or a " \
    "listening room.")
100 101 102
#define UPMIX_TEXT N_("Enable internal upmixing")
#define UPMIX_LONGTEXT N_( \
    "Enable the internal upmixing algorithm (not recommended).")
103 104

vlc_module_begin();
105
    set_shortname( "A/52" );
106
    set_description( _("ATSC A/52 (AC-3) audio decoder") );
zorglub's avatar
zorglub committed
107 108
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_ACODEC );
gbazin's avatar
 
gbazin committed
109
    add_bool( "a52-dynrng", 1, NULL, DYNRNG_TEXT, DYNRNG_LONGTEXT, VLC_FALSE );
110
    add_bool( "a52-upmix", 0, NULL, UPMIX_TEXT, UPMIX_LONGTEXT, VLC_TRUE );
111 112
    set_capability( "audio filter", 100 );
    set_callbacks( Create, Destroy );
113 114 115 116 117

    add_submodule();
    set_description( _("ATSC A/52 (AC-3) audio decoder") );
    set_capability( "audio filter2", 100 );
    set_callbacks( OpenFilter, CloseFilter );
118 119 120
vlc_module_end();

/*****************************************************************************
121
 * Create:
122
 *****************************************************************************/
123
static int Create( vlc_object_t *p_this )
124
{
125 126 127
    aout_filter_t *p_filter = (aout_filter_t *)p_this;
    filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
    int i_ret;
128

129
    if ( p_filter->input.i_format != VLC_FOURCC('a','5','2',' ')
130 131 132
#ifdef LIBA52_FIXED
          || p_filter->output.i_format != VLC_FOURCC('f','i','3','2') )
#else
133
          || p_filter->output.i_format != VLC_FOURCC('f','l','3','2') )
134
#endif
135 136 137 138 139 140 141 142 143 144
    {
        return -1;
    }

    if ( p_filter->input.i_rate != p_filter->output.i_rate )
    {
        return -1;
    }

    /* Allocate the memory needed to store the module's structure */
145 146
    p_sys = malloc( sizeof(filter_sys_t) );
    p_filter->p_sys = (struct aout_filter_sys_t *)p_sys;
147 148 149 150 151 152
    if( p_sys == NULL )
    {
        msg_Err( p_filter, "out of memory" );
        return -1;
    }

153 154 155 156 157 158 159 160 161 162
    i_ret = Open( VLC_OBJECT(p_filter), p_sys,
                  p_filter->input, p_filter->output );

    p_filter->pf_do_work = DoWork;
    p_filter->b_in_place = 0;

    return i_ret;
}

/*****************************************************************************
Jean-Paul Saman's avatar
Jean-Paul Saman committed
163
 * Open:
164 165
 *****************************************************************************/
static int Open( vlc_object_t *p_this, filter_sys_t *p_sys,
166
                 audio_format_t input, audio_format_t output )
167 168
{
    p_sys->b_dynrng = config_GetInt( p_this, "a52-dynrng" );
169
    p_sys->b_dontwarn = 0;
170

171 172 173 174 175 176 177 178 179 180
    /* No upmixing: it's not necessary and some other filters may want to do
     * it themselves. */
    if ( aout_FormatNbChannels( &output ) > aout_FormatNbChannels( &input ) )
    {
        if ( ! config_GetInt( p_this, "a52-upmix" ) )
        {
            return VLC_EGENERIC;
        }
    }

181
    /* We'll do our own downmixing, thanks. */
182 183
    p_sys->i_nb_channels = aout_FormatNbChannels( &output );
    switch ( (output.i_physical_channels & AOUT_CHAN_PHYSMASK)
184
              & ~AOUT_CHAN_LFE )
185
    {
186
    case AOUT_CHAN_CENTER:
187 188
        if ( (output.i_original_channels & AOUT_CHAN_CENTER)
              || (output.i_original_channels
189 190 191 192
                   & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
        {
            p_sys->i_flags = A52_MONO;
        }
193
        else if ( output.i_original_channels & AOUT_CHAN_LEFT )
194 195 196 197 198 199 200 201 202 203
        {
            p_sys->i_flags = A52_CHANNEL1;
        }
        else
        {
            p_sys->i_flags = A52_CHANNEL2;
        }
        break;

    case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT:
204
        if ( output.i_original_channels & AOUT_CHAN_DOLBYSTEREO )
205 206 207
        {
            p_sys->i_flags = A52_DOLBY;
        }
208
        else if ( input.i_original_channels == AOUT_CHAN_CENTER )
209 210 211
        {
            p_sys->i_flags = A52_MONO;
        }
212
        else if ( input.i_original_channels & AOUT_CHAN_DUALMONO )
213 214 215
        {
            p_sys->i_flags = A52_CHANNEL;
        }
216
        else if ( !(output.i_original_channels & AOUT_CHAN_RIGHT) )
217 218 219
        {
            p_sys->i_flags = A52_CHANNEL1;
        }
220
        else if ( !(output.i_original_channels & AOUT_CHAN_LEFT) )
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252
        {
            p_sys->i_flags = A52_CHANNEL2;
        }
        else
        {
            p_sys->i_flags = A52_STEREO;
        }
        break;

    case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER:
        p_sys->i_flags = A52_3F;
        break;

    case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARCENTER:
        p_sys->i_flags = A52_2F1R;
        break;

    case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
          | AOUT_CHAN_REARCENTER:
        p_sys->i_flags = A52_3F1R;
        break;

    case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT
          | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT:
        p_sys->i_flags = A52_2F2R;
        break;

    case AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
          | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT:
        p_sys->i_flags = A52_3F2R;
        break;

253
    default:
254
        msg_Warn( p_this, "unknown sample format!" );
255
        free( p_sys );
256
        return VLC_EGENERIC;
257
    }
258
    if ( output.i_physical_channels & AOUT_CHAN_LFE )
259 260 261 262 263 264 265 266 267
    {
        p_sys->i_flags |= A52_LFE;
    }
    p_sys->i_flags |= A52_ADJUST_LEVEL;

    /* Initialize liba52 */
    p_sys->p_liba52 = a52_init( 0 );
    if( p_sys->p_liba52 == NULL )
    {
268 269 270
        msg_Err( p_this, "unable to initialize liba52" );
        free( p_sys );
        return VLC_EGENERIC;
271 272
    }

273 274 275 276 277
    aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
                              output.i_physical_channels & AOUT_CHAN_PHYSMASK,
                              p_sys->i_nb_channels,
                              p_sys->pi_chan_table );

278
    return VLC_SUCCESS;
279 280 281 282 283
}

/*****************************************************************************
 * Interleave: helper function to interleave channels
 *****************************************************************************/
284 285
static void Interleave( float * p_out, const float * p_in, int i_nb_channels,
                        int *pi_chan_table )
286
{
287
    /* We do not only have to interleave, but also reorder the channels */
288

289
    int i, j;
290
    for ( j = 0; j < i_nb_channels; j++ )
291 292 293
    {
        for ( i = 0; i < 256; i++ )
        {
294
            p_out[i * i_nb_channels + pi_chan_table[j]] = p_in[j * 256 + i];
295 296 297 298
        }
    }
}

299 300 301 302 303 304 305 306 307 308 309 310 311 312 313
/*****************************************************************************
 * Duplicate: helper function to duplicate a unique channel
 *****************************************************************************/
static void Duplicate( float * p_out, const float * p_in )
{
    int i;

    for ( i = 256; i--; )
    {
        *p_out++ = *p_in;
        *p_out++ = *p_in;
        p_in++;
    }
}

Christophe Massiot's avatar
Christophe Massiot committed
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329
/*****************************************************************************
 * Exchange: helper function to exchange left & right channels
 *****************************************************************************/
static void Exchange( float * p_out, const float * p_in )
{
    int i;
    const float * p_first = p_in + 256;
    const float * p_second = p_in;

    for ( i = 0; i < 256; i++ )
    {
        *p_out++ = *p_first++;
        *p_out++ = *p_second++;
    }
}

330 331 332 333 334 335
/*****************************************************************************
 * DoWork: decode an ATSC A/52 frame.
 *****************************************************************************/
static void DoWork( aout_instance_t * p_aout, aout_filter_t * p_filter,
                    aout_buffer_t * p_in_buf, aout_buffer_t * p_out_buf )
{
336
    filter_sys_t    *p_sys = (filter_sys_t *)p_filter->p_sys;
337 338 339
#ifdef LIBA52_FIXED
    sample_t        i_sample_level = (1 << 24);
#else
340
    sample_t        i_sample_level = 1;
341
#endif
342 343 344 345 346 347 348 349 350
    int             i_flags = p_sys->i_flags;
    int             i_bytes_per_block = 256 * p_sys->i_nb_channels
                      * sizeof(float);
    int             i;

    /* Do the actual decoding now. */
    a52_frame( p_sys->p_liba52, p_in_buf->p_buffer,
               &i_flags, &i_sample_level, 0 );

351 352
    if ( (i_flags & A52_CHANNEL_MASK) != (p_sys->i_flags & A52_CHANNEL_MASK)
          && !p_sys->b_dontwarn )
353
    {
354
        msg_Warn( p_aout,
355 356 357 358 359
                  "liba52 couldn't do the requested downmix 0x%x->0x%x",
                  p_sys->i_flags  & A52_CHANNEL_MASK,
                  i_flags & A52_CHANNEL_MASK );

        p_sys->b_dontwarn = 1;
360 361 362 363
    }

    if( !p_sys->b_dynrng )
    {
364
        a52_dynrng( p_sys->p_liba52, NULL, NULL );
365 366 367 368 369 370 371 372
    }

    for ( i = 0; i < 6; i++ )
    {
        sample_t * p_samples;

        if( a52_block( p_sys->p_liba52 ) )
        {
373
            msg_Warn( p_aout, "a52_block failed for block %d", i );
374 375 376 377
        }

        p_samples = a52_samples( p_sys->p_liba52 );

378 379 380
        if ( ((p_sys->i_flags & A52_CHANNEL_MASK) == A52_CHANNEL1
               || (p_sys->i_flags & A52_CHANNEL_MASK) == A52_CHANNEL2
               || (p_sys->i_flags & A52_CHANNEL_MASK) == A52_MONO)
381 382 383 384 385 386
              && (p_filter->output.i_physical_channels 
                   & (AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT)) )
        {
            Duplicate( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
                       p_samples );
        }
Christophe Massiot's avatar
Christophe Massiot committed
387 388 389 390 391 392
        else if ( p_filter->output.i_original_channels
                    & AOUT_CHAN_REVERSESTEREO )
        {
            Exchange( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
                      p_samples );
        }
393 394
        else
        {
395
            /* Interleave the *$£%ù samples. */
396
            Interleave( (float *)(p_out_buf->p_buffer + i * i_bytes_per_block),
397
                        p_samples, p_sys->i_nb_channels, p_sys->pi_chan_table);
398
        }
399 400 401 402 403 404 405 406 407
    }

    p_out_buf->i_nb_samples = p_in_buf->i_nb_samples;
    p_out_buf->i_nb_bytes = i_bytes_per_block * 6;
}

/*****************************************************************************
 * Destroy : deallocate data structures
 *****************************************************************************/
408
static void Destroy( vlc_object_t *p_this )
409
{
410 411
    aout_filter_t *p_filter = (aout_filter_t *)p_this;
    filter_sys_t *p_sys = (filter_sys_t *)p_filter->p_sys;
412 413 414 415 416

    a52_free( p_sys->p_liba52 );
    free( p_sys );
}

417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
/*****************************************************************************
 * OpenFilter: 
 *****************************************************************************/
static int OpenFilter( vlc_object_t *p_this )
{
    filter_t *p_filter = (filter_t *)p_this;
    filter_sys_t *p_sys;
    int i_ret;

    if( p_filter->fmt_in.i_codec != VLC_FOURCC('a','5','2',' ')  )
    {
        return VLC_EGENERIC;
    }

    p_filter->fmt_out.audio.i_format =
432 433 434
#ifdef LIBA52_FIXED
        p_filter->fmt_out.i_codec = VLC_FOURCC('f','i','3','2');
#else
435
        p_filter->fmt_out.i_codec = VLC_FOURCC('f','l','3','2');
436
#endif
437 438 439 440 441 442 443 444 445 446 447 448 449

    /* Allocate the memory needed to store the module's structure */
    p_filter->p_sys = p_sys = malloc( sizeof(filter_sys_t) );
    if( p_sys == NULL )
    {
        msg_Err( p_filter, "out of memory" );
        return VLC_EGENERIC;
    }

    i_ret = Open( VLC_OBJECT(p_filter), p_sys,
                  p_filter->fmt_in.audio, p_filter->fmt_out.audio );

    p_filter->pf_audio_filter = Convert;
450
    p_filter->fmt_out.audio.i_rate = p_filter->fmt_in.audio.i_rate;
451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471

    return i_ret;
}

/*****************************************************************************
 * CloseFilter : deallocate data structures
 *****************************************************************************/
static void CloseFilter( vlc_object_t *p_this )
{
    filter_t *p_filter = (filter_t *)p_this;
    filter_sys_t *p_sys = p_filter->p_sys;

    a52_free( p_sys->p_liba52 );
    free( p_sys );
}

static block_t *Convert( filter_t *p_filter, block_t *p_block )
{
    aout_filter_t aout_filter;
    aout_buffer_t in_buf, out_buf;
    block_t *p_out;
gbazin's avatar
*...  
gbazin committed
472
    int i_out_size;
473

gbazin's avatar
*...  
gbazin committed
474 475 476 477 478 479 480
    if( !p_block || !p_block->i_samples )
    {
        if( p_block ) p_block->pf_release( p_block );
        return NULL;
    }

    i_out_size = p_block->i_samples *
481
      p_filter->fmt_out.audio.i_bitspersample *
482
        p_filter->fmt_out.audio.i_channels / 8;
483 484 485 486 487

    p_out = p_filter->pf_audio_buffer_new( p_filter, i_out_size );
    if( !p_out )
    {
        msg_Warn( p_filter, "can't get output buffer" );
gbazin's avatar
*...  
gbazin committed
488
        p_block->pf_release( p_block );
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511
        return NULL;
    }

    p_out->i_samples = p_block->i_samples;
    p_out->i_dts = p_block->i_dts;
    p_out->i_pts = p_block->i_pts;
    p_out->i_length = p_block->i_length;

    aout_filter.p_sys = (struct aout_filter_sys_t *)p_filter->p_sys;
    aout_filter.input = p_filter->fmt_in.audio;
    aout_filter.input.i_format = p_filter->fmt_in.i_codec;
    aout_filter.output = p_filter->fmt_out.audio;
    aout_filter.output.i_format = p_filter->fmt_out.i_codec;

    in_buf.p_buffer = p_block->p_buffer;
    in_buf.i_nb_bytes = p_block->i_buffer;
    in_buf.i_nb_samples = p_block->i_samples;
    out_buf.p_buffer = p_out->p_buffer;
    out_buf.i_nb_bytes = p_out->i_buffer;
    out_buf.i_nb_samples = p_out->i_samples;

    DoWork( (aout_instance_t *)p_filter, &aout_filter, &in_buf, &out_buf );

512
    p_out->i_buffer = out_buf.i_nb_bytes;
513
    p_out->i_samples = out_buf.i_nb_samples;
514

gbazin's avatar
*...  
gbazin committed
515 516
    p_block->pf_release( p_block );

517 518
    return p_out;
}