Skip to content
Snippets Groups Projects
ac3enc.c 106 KiB
Newer Older
  • Learn to ignore specific revisions
  • Fabrice Bellard's avatar
    Fabrice Bellard committed
    /*
    
     * Copyright (c) 2000 Fabrice Bellard
    
     * Copyright (c) 2006-2010 Justin Ruggles <justin.ruggles@gmail.com>
     * Copyright (c) 2006-2010 Prakash Punnoor <prakash@punnoor.de>
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     *
    
     * This file is part of Libav.
    
     * Libav 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.
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     *
    
     * Libav is distributed in the hope that it will be useful,
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     * 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.
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     *
    
     * You should have received a copy of the GNU Lesser General Public
    
     * License along with Libav; if not, write to the Free Software
    
     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
     */
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
    
    /**
    
    Michael Niedermayer's avatar
    Michael Niedermayer committed
     */
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    //#define DEBUG
    
    #include <stdint.h>
    
    
    #include "libavutil/audioconvert.h"
    
    #include "libavutil/avstring.h"
    
    #include "libavutil/crc.h"
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    #include "avcodec.h"
    
    #include "ac3dsp.h"
    
    #include "ac3.h"
    
    #include "audioconvert.h"
    
    #include "fft.h"
    
    #ifndef CONFIG_AC3ENC_FLOAT
    #define CONFIG_AC3ENC_FLOAT 0
    #endif
    
    
    
    /** Maximum number of exponent groups. +1 for separate DC exponent. */
    #define AC3_MAX_EXP_GROUPS 85
    
    
    #if CONFIG_AC3ENC_FLOAT
    
    #define MAC_COEF(d,a,b) ((d)+=(a)*(b))
    typedef float SampleType;
    typedef float CoefType;
    typedef float CoefSumType;
    
    #define MAC_COEF(d,a,b) MAC64(d,a,b)
    typedef int16_t SampleType;
    typedef int32_t CoefType;
    typedef int64_t CoefSumType;
    
    typedef struct AC3MDCTContext {
        const SampleType *window;           ///< MDCT window function
        FFTContext fft;                     ///< FFT context for MDCT calculation
    } AC3MDCTContext;
    
    /**
     * Encoding Options used by AVOption.
     */
    typedef struct AC3EncOptions {
        /* AC-3 metadata options*/
        int dialogue_level;
        int bitstream_mode;
        float center_mix_level;
        float surround_mix_level;
        int dolby_surround_mode;
        int audio_production_info;
        int mixing_level;
        int room_type;
        int copyright;
        int original;
        int extended_bsi_1;
        int preferred_stereo_downmix;
        float ltrt_center_mix_level;
        float ltrt_surround_mix_level;
        float loro_center_mix_level;
        float loro_surround_mix_level;
        int extended_bsi_2;
        int dolby_surround_ex_mode;
        int dolby_headphone_mode;
        int ad_converter_type;
    
        /* other encoding options */
        int allow_per_frame_metadata;
    
        int stereo_rematrixing;
    
        int channel_coupling;
        int cpl_start;
    
    /**
     * Data for a single audio block.
     */
    typedef struct AC3Block {
    
        uint8_t  **bap;                             ///< bit allocation pointers (bap)
    
        CoefType **mdct_coef;                       ///< MDCT coefficients
    
        int32_t  **fixed_coef;                      ///< fixed-point MDCT coefficients
    
        uint8_t  **exp;                             ///< original exponents
        uint8_t  **grouped_exp;                     ///< grouped exponents
        int16_t  **psd;                             ///< psd per frequency bin
        int16_t  **band_psd;                        ///< psd per critical band
        int16_t  **mask;                            ///< masking curve
        uint16_t **qmant;                           ///< quantized mantissas
    
        uint8_t  **cpl_coord_exp;                   ///< coupling coord exponents           (cplcoexp)
        uint8_t  **cpl_coord_mant;                  ///< coupling coord mantissas           (cplcomant)
    
        uint8_t  coeff_shift[AC3_MAX_CHANNELS];     ///< fixed-point coefficient shift values
    
        uint8_t  new_rematrixing_strategy;          ///< send new rematrixing flags in this block
    
        int      num_rematrixing_bands;             ///< number of rematrixing bands
    
        uint8_t  rematrixing_flags[4];              ///< rematrixing flags
    
        struct AC3Block *exp_ref_block[AC3_MAX_CHANNELS]; ///< reference blocks for EXP_REUSE
    
        int      new_cpl_strategy;                  ///< send new coupling strategy
        int      cpl_in_use;                        ///< coupling in use for this block     (cplinu)
        uint8_t  channel_in_cpl[AC3_MAX_CHANNELS];  ///< channel in coupling                (chincpl)
        int      num_cpl_channels;                  ///< number of channels in coupling
        uint8_t  new_cpl_coords;                    ///< send new coupling coordinates      (cplcoe)
        uint8_t  cpl_master_exp[AC3_MAX_CHANNELS];  ///< coupling coord master exponents    (mstrcplco)
        int      new_snr_offsets;                   ///< send new SNR offsets
        int      new_cpl_leak;                      ///< send new coupling leak info
        int      end_freq[AC3_MAX_CHANNELS];        ///< end frequency bin                  (endmant)
    
    typedef struct AC3EncodeContext {
    
        AVClass *av_class;                      ///< AVClass used for AVOption
        AC3EncOptions options;                  ///< encoding options
    
        PutBitContext pb;                       ///< bitstream writer context
    
        AC3DSPContext ac3dsp;                   ///< AC-3 optimized functions
    
        AC3MDCTContext mdct;                    ///< MDCT context
    
        AC3Block blocks[AC3_MAX_BLOCKS];        ///< per-block info
    
    
        int eac3;                               ///< indicates if this is E-AC-3 vs. AC-3
    
        int bitstream_id;                       ///< bitstream id                           (bsid)
        int bitstream_mode;                     ///< bitstream mode                         (bsmod)
    
        int bit_rate;                           ///< target bit rate, in bits-per-second
        int sample_rate;                        ///< sampling frequency, in Hz
    
        int frame_size_min;                     ///< minimum frame size in case rounding is necessary
    
        int frame_size;                         ///< current frame size in bytes
    
        int frame_size_code;                    ///< frame size code                        (frmsizecod)
    
        uint16_t crc_inv[2];
    
        int64_t bits_written;                   ///< bit count    (used to avg. bitrate)
        int64_t samples_written;                ///< sample count (used to avg. bitrate)
    
        int fbw_channels;                       ///< number of full-bandwidth channels      (nfchans)
        int channels;                           ///< total number of channels               (nchans)
        int lfe_on;                             ///< indicates if there is an LFE channel   (lfeon)
        int lfe_channel;                        ///< channel index of the LFE channel
    
        int has_center;                         ///< indicates if there is a center channel
        int has_surround;                       ///< indicates if there are one or more surround channels
    
        int channel_mode;                       ///< channel mode                           (acmod)
        const uint8_t *channel_map;             ///< channel map used to reorder channels
    
        int center_mix_level;                   ///< center mix level code
        int surround_mix_level;                 ///< surround mix level code
        int ltrt_center_mix_level;              ///< Lt/Rt center mix level code
        int ltrt_surround_mix_level;            ///< Lt/Rt surround mix level code
        int loro_center_mix_level;              ///< Lo/Ro center mix level code
        int loro_surround_mix_level;            ///< Lo/Ro surround mix level code
    
    
        int cutoff;                             ///< user-specified cutoff frequency, in Hz
    
        int bandwidth_code;                     ///< bandwidth code (0 to 60)               (chbwcod)
    
        int start_freq[AC3_MAX_CHANNELS];       ///< start frequency bin                    (strtmant)
        int cpl_end_freq;                       ///< coupling channel end frequency bin
    
        int cpl_on;                             ///< coupling turned on for this frame
        int cpl_enabled;                        ///< coupling enabled for all frames
        int num_cpl_subbands;                   ///< number of coupling subbands            (ncplsubnd)
        int num_cpl_bands;                      ///< number of coupling bands               (ncplbnd)
        uint8_t cpl_band_sizes[AC3_MAX_CPL_BANDS];  ///< number of coeffs in each coupling band
    
        int rematrixing_enabled;                ///< stereo rematrixing enabled
    
        /* bitrate allocation control */
    
        int slow_gain_code;                     ///< slow gain code                         (sgaincod)
        int slow_decay_code;                    ///< slow decay code                        (sdcycod)
        int fast_decay_code;                    ///< fast decay code                        (fdcycod)
        int db_per_bit_code;                    ///< dB/bit code                            (dbpbcod)
        int floor_code;                         ///< floor code                             (floorcod)
        AC3BitAllocParameters bit_alloc;        ///< bit allocation parameters
        int coarse_snr_offset;                  ///< coarse SNR offsets                     (csnroffst)
        int fast_gain_code[AC3_MAX_CHANNELS];   ///< fast gain codes (signal-to-mask ratio) (fgaincod)
        int fine_snr_offset[AC3_MAX_CHANNELS];  ///< fine SNR offsets                       (fsnroffst)
    
        int frame_bits_fixed;                   ///< number of non-coefficient bits for fixed parameters
    
        int frame_bits;                         ///< all frame bits except exponents and mantissas
        int exponent_bits;                      ///< number of bits used for exponents
    
        SampleType **planar_samples;
    
        uint8_t *bap_buffer;
        uint8_t *bap1_buffer;
    
        uint8_t *exp_buffer;
        uint8_t *grouped_exp_buffer;
        int16_t *psd_buffer;
        int16_t *band_psd_buffer;
        int16_t *mask_buffer;
        uint16_t *qmant_buffer;
    
        uint8_t *cpl_coord_exp_buffer;
        uint8_t *cpl_coord_mant_buffer;
    
        uint8_t exp_strategy[AC3_MAX_CHANNELS][AC3_MAX_BLOCKS]; ///< exponent strategies
    
    
        DECLARE_ALIGNED(32, SampleType, windowed_samples)[AC3_WINDOW_SIZE];
    
    } AC3EncodeContext;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
    typedef struct AC3Mant {
        uint16_t *qmant1_ptr, *qmant2_ptr, *qmant4_ptr; ///< mantissa pointers for bap=1,2,4
        int mant1_cnt, mant2_cnt, mant4_cnt;    ///< mantissa counts for bap=1,2,4
    } AC3Mant;
    
    #define CMIXLEV_NUM_OPTIONS 3
    static const float cmixlev_options[CMIXLEV_NUM_OPTIONS] = {
        LEVEL_MINUS_3DB, LEVEL_MINUS_4POINT5DB, LEVEL_MINUS_6DB
    };
    
    #define SURMIXLEV_NUM_OPTIONS 3
    static const float surmixlev_options[SURMIXLEV_NUM_OPTIONS] = {
        LEVEL_MINUS_3DB, LEVEL_MINUS_6DB, LEVEL_ZERO
    };
    
    #define EXTMIXLEV_NUM_OPTIONS 8
    static const float extmixlev_options[EXTMIXLEV_NUM_OPTIONS] = {
        LEVEL_PLUS_3DB,  LEVEL_PLUS_1POINT5DB,  LEVEL_ONE,       LEVEL_MINUS_4POINT5DB,
        LEVEL_MINUS_3DB, LEVEL_MINUS_4POINT5DB, LEVEL_MINUS_6DB, LEVEL_ZERO
    };
    
    
    #define OFFSET(param) offsetof(AC3EncodeContext, options.param)
    #define AC3ENC_PARAM (AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM)
    
    
    #define AC3ENC_TYPE_AC3_FIXED   0
    #define AC3ENC_TYPE_AC3         1
    
    #define AC3ENC_TYPE_EAC3        2
    
    #define AC3ENC_TYPE AC3ENC_TYPE_AC3
    #include "ac3enc_opts_template.c"
    
    static AVClass ac3enc_class = { "AC-3 Encoder", av_default_item_name,
    
                                    ac3_options, LIBAVUTIL_VERSION_INT };
    
    #undef AC3ENC_TYPE
    #define AC3ENC_TYPE AC3ENC_TYPE_EAC3
    #include "ac3enc_opts_template.c"
    static AVClass eac3enc_class = { "E-AC-3 Encoder", av_default_item_name,
                                     eac3_options, LIBAVUTIL_VERSION_INT };
    
    #define AC3ENC_TYPE AC3ENC_TYPE_AC3_FIXED
    #include "ac3enc_opts_template.c"
    
    static AVClass ac3enc_class = { "Fixed-Point AC-3 Encoder", av_default_item_name,
    
                                    ac3fixed_options, LIBAVUTIL_VERSION_INT };
    
    /* prototypes for functions in ac3enc_fixed.c and ac3enc_float.c */
    
    
    static av_cold void mdct_end(AC3MDCTContext *mdct);
    
    static av_cold int mdct_init(AVCodecContext *avctx, AC3MDCTContext *mdct,
                                 int nbits);
    
    
    static void apply_window(DSPContext *dsp, SampleType *output, const SampleType *input,
    
                             const SampleType *window, unsigned int len);
    
    
    static int normalize_samples(AC3EncodeContext *s);
    
    
    static void scale_coefficients(AC3EncodeContext *s);
    
    
    /**
     * LUT for number of exponent groups.
    
     * exponent_group_tab[coupling][exponent strategy-1][number of coefficients]
    
    static uint8_t exponent_group_tab[2][3][256];
    
    /**
     * List of supported channel layouts.
     */
    static const int64_t ac3_channel_layouts[] = {
         AV_CH_LAYOUT_MONO,
         AV_CH_LAYOUT_STEREO,
         AV_CH_LAYOUT_2_1,
         AV_CH_LAYOUT_SURROUND,
         AV_CH_LAYOUT_2_2,
         AV_CH_LAYOUT_QUAD,
         AV_CH_LAYOUT_4POINT0,
         AV_CH_LAYOUT_5POINT0,
         AV_CH_LAYOUT_5POINT0_BACK,
        (AV_CH_LAYOUT_MONO     | AV_CH_LOW_FREQUENCY),
        (AV_CH_LAYOUT_STEREO   | AV_CH_LOW_FREQUENCY),
        (AV_CH_LAYOUT_2_1      | AV_CH_LOW_FREQUENCY),
        (AV_CH_LAYOUT_SURROUND | AV_CH_LOW_FREQUENCY),
        (AV_CH_LAYOUT_2_2      | AV_CH_LOW_FREQUENCY),
        (AV_CH_LAYOUT_QUAD     | AV_CH_LOW_FREQUENCY),
        (AV_CH_LAYOUT_4POINT0  | AV_CH_LOW_FREQUENCY),
         AV_CH_LAYOUT_5POINT1,
         AV_CH_LAYOUT_5POINT1_BACK,
         0
    };
    
    
    
    /**
     * LUT to select the bandwidth code based on the bit rate, sample rate, and
     * number of full-bandwidth channels.
     * bandwidth_tab[fbw_channels-1][sample rate code][bit rate code]
     */
    static const uint8_t ac3_bandwidth_tab[5][3][19] = {
    //      32  40  48  56  64  80  96 112 128 160 192 224 256 320 384 448 512 576 640
    
        { {  0,  0,  0, 12, 16, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48 },
          {  0,  0,  0, 16, 20, 36, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56 },
          {  0,  0,  0, 32, 40, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 } },
    
        { {  0,  0,  0,  0,  0,  0,  0, 20, 24, 32, 48, 48, 48, 48, 48, 48, 48, 48, 48 },
          {  0,  0,  0,  0,  0,  0,  4, 24, 28, 36, 56, 56, 56, 56, 56, 56, 56, 56, 56 },
          {  0,  0,  0,  0,  0,  0, 20, 44, 52, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60 } },
    
        { {  0,  0,  0,  0,  0,  0,  0,  0,  0, 16, 24, 32, 40, 48, 48, 48, 48, 48, 48 },
          {  0,  0,  0,  0,  0,  0,  0,  0,  4, 20, 28, 36, 44, 56, 56, 56, 56, 56, 56 },
          {  0,  0,  0,  0,  0,  0,  0,  0, 20, 40, 48, 60, 60, 60, 60, 60, 60, 60, 60 } },
    
        { {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 12, 24, 32, 48, 48, 48, 48, 48, 48 },
          {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 16, 28, 36, 56, 56, 56, 56, 56, 56 },
          {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 32, 48, 60, 60, 60, 60, 60, 60, 60 } },
    
        { {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8, 20, 32, 40, 48, 48, 48, 48 },
          {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 12, 24, 36, 44, 56, 56, 56, 56 },
          {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 28, 44, 60, 60, 60, 60, 60, 60 } }
    };
    
    
    
    /**
     * LUT to select the coupling start band based on the bit rate, sample rate, and
     * number of full-bandwidth channels. -1 = coupling off
     * ac3_coupling_start_tab[channel_mode-2][sample rate code][bit rate code]
     *
     * TODO: more testing for optimal parameters.
     *       multi-channel tests at 44.1kHz and 32kHz.
     */
    static const int8_t ac3_coupling_start_tab[6][3][19] = {
    //      32  40  48  56  64  80  96 112 128 160 192 224 256 320 384 448 512 576 640
    
        // 2/0
        { {  0,  0,  0,  0,  0,  0,  0,  1,  1,  7,  8, 11, 12, -1, -1, -1, -1, -1, -1 },
          {  0,  0,  0,  0,  0,  0,  1,  3,  5,  7, 10, 12, 13, -1, -1, -1, -1, -1, -1 },
          {  0,  0,  0,  0,  1,  2,  2,  9, 13, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1 } },
    
        // 3/0
        { {  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,  6,  9, 11, 12, 13, -1, -1, -1, -1 },
          {  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,  6,  9, 11, 12, 13, -1, -1, -1, -1 },
          { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } },
    
        // 2/1 - untested
        { {  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,  6,  9, 11, 12, 13, -1, -1, -1, -1 },
          {  0,  0,  0,  0,  0,  0,  0,  0,  2,  2,  6,  9, 11, 12, 13, -1, -1, -1, -1 },
          { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } },
    
        // 3/1
        { {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  3,  2, 10, 11, 11, 12, 12, 14, -1 },
          {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  3,  2, 10, 11, 11, 12, 12, 14, -1 },
          { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } },
    
        // 2/2 - untested
        { {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  3,  2, 10, 11, 11, 12, 12, 14, -1 },
          {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  3,  2, 10, 11, 11, 12, 12, 14, -1 },
          { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } },
    
        // 3/2
        { {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  6,  8, 11, 12, 12, -1, -1 },
          {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  6,  8, 11, 12, 12, -1, -1 },
          { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 } },
    };
    
    
    
    /**
     * Adjust the frame size to make the average bit rate match the target bit rate.
    
     * This is only needed for 11025, 22050, and 44100 sample rates or any E-AC-3.
    
     */
    static void adjust_frame_size(AC3EncodeContext *s)
    {
        while (s->bits_written >= s->bit_rate && s->samples_written >= s->sample_rate) {
            s->bits_written    -= s->bit_rate;
            s->samples_written -= s->sample_rate;
        }
    
        s->frame_size = s->frame_size_min +
                        2 * (s->bits_written * s->sample_rate < s->samples_written * s->bit_rate);
    
        s->bits_written    += s->frame_size * 8;
        s->samples_written += AC3_FRAME_SIZE;
    }
    
    
    
    /**
     * Deinterleave input samples.
    
     * Channels are reordered from Libav's default order to AC-3 order.
    
     */
    static void deinterleave_input_samples(AC3EncodeContext *s,
    
    {
        int ch, i;
    
        /* deinterleave and remap input samples */
        for (ch = 0; ch < s->channels; ch++) {
    
            int sinc;
    
            /* copy last 256 samples of previous frame to the start of the current frame */
    
            memcpy(&s->planar_samples[ch][0], &s->planar_samples[ch][AC3_FRAME_SIZE],
    
                   AC3_BLOCK_SIZE * sizeof(s->planar_samples[0][0]));
    
    
            /* deinterleave */
            sinc = s->channels;
            sptr = samples + s->channel_map[ch];
            for (i = AC3_BLOCK_SIZE; i < AC3_FRAME_SIZE+AC3_BLOCK_SIZE; i++) {
    
    /**
     * Apply the MDCT to input samples to generate frequency coefficients.
     * This applies the KBD window and normalizes the input to reduce precision
     * loss due to fixed-point calculations.
     */
    
    static void apply_mdct(AC3EncodeContext *s)
    
    {
        int blk, ch;
    
        for (ch = 0; ch < s->channels; ch++) {
            for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
    
                const SampleType *input_samples = &s->planar_samples[ch][blk * AC3_BLOCK_SIZE];
    
                apply_window(&s->dsp, s->windowed_samples, input_samples, s->mdct.window, AC3_WINDOW_SIZE);
    
                block->coeff_shift[ch+1] = normalize_samples(s);
    
                s->mdct.fft.mdct_calcw(&s->mdct.fft, block->mdct_coef[ch+1],
    
                                       s->windowed_samples);
    
    static void compute_coupling_strategy(AC3EncodeContext *s)
    {
        int blk, ch;
        int got_cpl_snr;
    
        /* set coupling use flags for each block/channel */
        /* TODO: turn coupling on/off and adjust start band based on bit usage */
        for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
            AC3Block *block = &s->blocks[blk];
            for (ch = 1; ch <= s->fbw_channels; ch++)
                block->channel_in_cpl[ch] = s->cpl_on;
        }
    
        /* enable coupling for each block if at least 2 channels have coupling
           enabled for that block */
        got_cpl_snr = 0;
        for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
            AC3Block *block = &s->blocks[blk];
            block->num_cpl_channels = 0;
            for (ch = 1; ch <= s->fbw_channels; ch++)
                block->num_cpl_channels += block->channel_in_cpl[ch];
            block->cpl_in_use = block->num_cpl_channels > 1;
            if (!block->cpl_in_use) {
                block->num_cpl_channels = 0;
                for (ch = 1; ch <= s->fbw_channels; ch++)
                    block->channel_in_cpl[ch] = 0;
            }
    
            block->new_cpl_strategy = !blk;
            if (blk) {
                for (ch = 1; ch <= s->fbw_channels; ch++) {
                    if (block->channel_in_cpl[ch] != s->blocks[blk-1].channel_in_cpl[ch]) {
                        block->new_cpl_strategy = 1;
                        break;
                    }
                }
            }
            block->new_cpl_leak = block->new_cpl_strategy;
    
            if (!blk || (block->cpl_in_use && !got_cpl_snr)) {
                block->new_snr_offsets = 1;
                if (block->cpl_in_use)
                    got_cpl_snr = 1;
            } else {
                block->new_snr_offsets = 0;
            }
        }
    
        /* set bandwidth for each channel */
        for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
            AC3Block *block = &s->blocks[blk];
            for (ch = 1; ch <= s->fbw_channels; ch++) {
                if (block->channel_in_cpl[ch])
                    block->end_freq[ch] = s->start_freq[CPL_CH];
                else
                    block->end_freq[ch] = s->bandwidth_code * 3 + 73;
            }
        }
    }
    
    
    /**
     * Calculate a single coupling coordinate.
     */
    static inline float calc_cpl_coord(float energy_ch, float energy_cpl)
    {
        float coord = 0.125;
        if (energy_cpl > 0)
            coord *= sqrtf(energy_ch / energy_cpl);
        return coord;
    }
    
    
    /**
     * Calculate coupling channel and coupling coordinates.
     * TODO: Currently this is only used for the floating-point encoder. I was
     *       able to make it work for the fixed-point encoder, but quality was
     *       generally lower in most cases than not using coupling. If a more
     *       adaptive coupling strategy were to be implemented it might be useful
     *       at that time to use coupling for the fixed-point encoder as well.
     */
    static void apply_channel_coupling(AC3EncodeContext *s)
    {
    #if CONFIG_AC3ENC_FLOAT
    
        DECLARE_ALIGNED(16, float,   cpl_coords)      [AC3_MAX_BLOCKS][AC3_MAX_CHANNELS][16] = {{{0}}};
        DECLARE_ALIGNED(16, int32_t, fixed_cpl_coords)[AC3_MAX_BLOCKS][AC3_MAX_CHANNELS][16] = {{{0}}};
    
        int blk, ch, bnd, i, j;
        CoefSumType energy[AC3_MAX_BLOCKS][AC3_MAX_CHANNELS][16] = {{{0}}};
        int num_cpl_coefs = s->num_cpl_subbands * 12;
    
        /* calculate coupling channel from fbw channels */
        for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
            AC3Block *block = &s->blocks[blk];
            CoefType *cpl_coef = &block->mdct_coef[CPL_CH][s->start_freq[CPL_CH]];
            if (!block->cpl_in_use)
                continue;
            memset(cpl_coef-1, 0, (num_cpl_coefs+4) * sizeof(*cpl_coef));
            for (ch = 1; ch <= s->fbw_channels; ch++) {
                CoefType *ch_coef = &block->mdct_coef[ch][s->start_freq[CPL_CH]];
                if (!block->channel_in_cpl[ch])
                    continue;
                for (i = 0; i < num_cpl_coefs; i++)
                    cpl_coef[i] += ch_coef[i];
            }
            /* note: coupling start bin % 4 will always be 1 and num_cpl_coefs
                     will always be a multiple of 12, so we need to subtract 1 from
                     the start and add 4 to the length when using optimized
                     functions which require 16-byte alignment. */
    
            /* coefficients must be clipped to +/- 1.0 in order to be encoded */
            s->dsp.vector_clipf(cpl_coef-1, cpl_coef-1, -1.0f, 1.0f, num_cpl_coefs+4);
    
            /* scale coupling coefficients from float to 24-bit fixed-point */
            s->ac3dsp.float_to_fixed24(&block->fixed_coef[CPL_CH][s->start_freq[CPL_CH]-1],
                                       cpl_coef-1, num_cpl_coefs+4);
        }
    
        /* calculate energy in each band in coupling channel and each fbw channel */
        /* TODO: possibly use SIMD to speed up energy calculation */
        bnd = 0;
        i = s->start_freq[CPL_CH];
        while (i < s->cpl_end_freq) {
            int band_size = s->cpl_band_sizes[bnd];
            for (ch = CPL_CH; ch <= s->fbw_channels; ch++) {
                for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
                    AC3Block *block = &s->blocks[blk];
                    if (!block->cpl_in_use || (ch > CPL_CH && !block->channel_in_cpl[ch]))
                        continue;
                    for (j = 0; j < band_size; j++) {
                        CoefType v = block->mdct_coef[ch][i+j];
                        MAC_COEF(energy[blk][ch][bnd], v, v);
                    }
                }
            }
            i += band_size;
            bnd++;
        }
    
        /* determine which blocks to send new coupling coordinates for */
        for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
            AC3Block *block  = &s->blocks[blk];
            AC3Block *block0 = blk ? &s->blocks[blk-1] : NULL;
            int new_coords = 0;
            CoefSumType coord_diff[AC3_MAX_CHANNELS] = {0,};
    
            if (block->cpl_in_use) {
                /* calculate coupling coordinates for all blocks and calculate the
                   average difference between coordinates in successive blocks */
                for (ch = 1; ch <= s->fbw_channels; ch++) {
                    if (!block->channel_in_cpl[ch])
                        continue;
    
                    for (bnd = 0; bnd < s->num_cpl_bands; bnd++) {
                        cpl_coords[blk][ch][bnd] = calc_cpl_coord(energy[blk][ch][bnd],
                                                                  energy[blk][CPL_CH][bnd]);
                        if (blk > 0 && block0->cpl_in_use &&
                            block0->channel_in_cpl[ch]) {
                            coord_diff[ch] += fabs(cpl_coords[blk-1][ch][bnd] -
                                                   cpl_coords[blk  ][ch][bnd]);
                        }
                    }
                    coord_diff[ch] /= s->num_cpl_bands;
                }
    
                /* send new coordinates if this is the first block, if previous
                 * block did not use coupling but this block does, the channels
                 * using coupling has changed from the previous block, or the
                 * coordinate difference from the last block for any channel is
                 * greater than a threshold value. */
                if (blk == 0) {
                    new_coords = 1;
                } else if (!block0->cpl_in_use) {
                    new_coords = 1;
                } else {
                    for (ch = 1; ch <= s->fbw_channels; ch++) {
                        if (block->channel_in_cpl[ch] && !block0->channel_in_cpl[ch]) {
                            new_coords = 1;
                            break;
                        }
                    }
                    if (!new_coords) {
                        for (ch = 1; ch <= s->fbw_channels; ch++) {
                            if (block->channel_in_cpl[ch] && coord_diff[ch] > 0.04) {
                                new_coords = 1;
                                break;
                            }
                        }
                    }
                }
            }
            block->new_cpl_coords = new_coords;
        }
    
        /* calculate final coupling coordinates, taking into account reusing of
           coordinates in successive blocks */
        for (bnd = 0; bnd < s->num_cpl_bands; bnd++) {
            blk = 0;
            while (blk < AC3_MAX_BLOCKS) {
                int blk1;
                CoefSumType energy_cpl;
                AC3Block *block  = &s->blocks[blk];
    
                if (!block->cpl_in_use) {
                    blk++;
                    continue;
                }
    
                energy_cpl = energy[blk][CPL_CH][bnd];
                blk1 = blk+1;
                while (!s->blocks[blk1].new_cpl_coords && blk1 < AC3_MAX_BLOCKS) {
                    if (s->blocks[blk1].cpl_in_use)
                        energy_cpl += energy[blk1][CPL_CH][bnd];
                    blk1++;
                }
    
                for (ch = 1; ch <= s->fbw_channels; ch++) {
                    CoefType energy_ch;
                    if (!block->channel_in_cpl[ch])
                        continue;
                    energy_ch = energy[blk][ch][bnd];
                    blk1 = blk+1;
                    while (!s->blocks[blk1].new_cpl_coords && blk1 < AC3_MAX_BLOCKS) {
                        if (s->blocks[blk1].cpl_in_use)
                            energy_ch += energy[blk1][ch][bnd];
                        blk1++;
                    }
                    cpl_coords[blk][ch][bnd] = calc_cpl_coord(energy_ch, energy_cpl);
                }
                blk = blk1;
            }
        }
    
        /* calculate exponents/mantissas for coupling coordinates */
        for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
            AC3Block *block = &s->blocks[blk];
            if (!block->cpl_in_use || !block->new_cpl_coords)
                continue;
    
            s->ac3dsp.float_to_fixed24(fixed_cpl_coords[blk][1],
                                       cpl_coords[blk][1],
                                       s->fbw_channels * 16);
            s->ac3dsp.extract_exponents(block->cpl_coord_exp[1],
                                        fixed_cpl_coords[blk][1],
                                        s->fbw_channels * 16);
    
            for (ch = 1; ch <= s->fbw_channels; ch++) {
                int bnd, min_exp, max_exp, master_exp;
    
                /* determine master exponent */
                min_exp = max_exp = block->cpl_coord_exp[ch][0];
                for (bnd = 1; bnd < s->num_cpl_bands; bnd++) {
                    int exp = block->cpl_coord_exp[ch][bnd];
                    min_exp = FFMIN(exp, min_exp);
                    max_exp = FFMAX(exp, max_exp);
                }
                master_exp = ((max_exp - 15) + 2) / 3;
                master_exp = FFMAX(master_exp, 0);
                while (min_exp < master_exp * 3)
                    master_exp--;
                for (bnd = 0; bnd < s->num_cpl_bands; bnd++) {
                    block->cpl_coord_exp[ch][bnd] = av_clip(block->cpl_coord_exp[ch][bnd] -
                                                            master_exp * 3, 0, 15);
                }
                block->cpl_master_exp[ch] = master_exp;
    
                /* quantize mantissas */
                for (bnd = 0; bnd < s->num_cpl_bands; bnd++) {
                    int cpl_exp  = block->cpl_coord_exp[ch][bnd];
                    int cpl_mant = (fixed_cpl_coords[blk][ch][bnd] << (5 + cpl_exp + master_exp * 3)) >> 24;
                    if (cpl_exp == 15)
                        cpl_mant >>= 1;
                    else
                        cpl_mant -= 16;
    
                    block->cpl_coord_mant[ch][bnd] = cpl_mant;
                }
            }
        }
    
    
        if (s->eac3) {
            /* set first cpl coords */
            int first_cpl_coords[AC3_MAX_CHANNELS];
            for (ch = 1; ch <= s->fbw_channels; ch++)
                first_cpl_coords[ch] = 1;
            for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
                AC3Block *block = &s->blocks[blk];
                for (ch = 1; ch <= s->fbw_channels; ch++) {
                    if (block->channel_in_cpl[ch]) {
                        if (first_cpl_coords[ch]) {
                            block->new_cpl_coords = 2;
                            first_cpl_coords[ch]  = 0;
                        }
                    } else {
                        first_cpl_coords[ch] = 1;
                    }
                }
            }
    
            /* set first cpl leak */
            for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
                AC3Block *block = &s->blocks[blk];
                if (block->cpl_in_use) {
                    block->new_cpl_leak = 2;
                    break;
                }
            }
        }
    
    #endif /* CONFIG_AC3ENC_FLOAT */
    }
    
    
    
    /**
     * Determine rematrixing flags for each block and band.
     */
    static void compute_rematrixing_strategy(AC3EncodeContext *s)
    {
        int nb_coefs;
        int blk, bnd, i;
        AC3Block *block, *block0;
    
    
        if (s->channel_mode != AC3_CHMODE_STEREO)
    
            return;
    
        for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
            block = &s->blocks[blk];
    
            block->new_rematrixing_strategy = !blk;
    
    
            if (!s->rematrixing_enabled) {
                block0 = block;
    
            }
    
            block->num_rematrixing_bands = 4;
            if (block->cpl_in_use) {
                block->num_rematrixing_bands -= (s->start_freq[CPL_CH] <= 61);
                block->num_rematrixing_bands -= (s->start_freq[CPL_CH] == 37);
                if (blk && block->num_rematrixing_bands != block0->num_rematrixing_bands)
                    block->new_rematrixing_strategy = 1;
            }
            nb_coefs = FFMIN(block->end_freq[1], block->end_freq[2]);
    
            for (bnd = 0; bnd < block->num_rematrixing_bands; bnd++) {
    
                /* calculate calculate sum of squared coeffs for one band in one block */
                int start = ff_ac3_rematrix_band_tab[bnd];
                int end   = FFMIN(nb_coefs, ff_ac3_rematrix_band_tab[bnd+1]);
                CoefSumType sum[4] = {0,};
                for (i = start; i < end; i++) {
    
                    CoefType lt = block->mdct_coef[1][i];
                    CoefType rt = block->mdct_coef[2][i];
    
                    CoefType md = lt + rt;
                    CoefType sd = lt - rt;
    
                    MAC_COEF(sum[0], lt, lt);
                    MAC_COEF(sum[1], rt, rt);
                    MAC_COEF(sum[2], md, md);
                    MAC_COEF(sum[3], sd, sd);
    
                }
    
                /* compare sums to determine if rematrixing will be used for this band */
                if (FFMIN(sum[2], sum[3]) < FFMIN(sum[0], sum[1]))
                    block->rematrixing_flags[bnd] = 1;
                else
                    block->rematrixing_flags[bnd] = 0;
    
                /* determine if new rematrixing flags will be sent */
                if (blk &&
                    block->rematrixing_flags[bnd] != block0->rematrixing_flags[bnd]) {
                    block->new_rematrixing_strategy = 1;
                }
            }
            block0 = block;
        }
    }
    
    
    /**
     * Apply stereo rematrixing to coefficients based on rematrixing flags.
     */
    static void apply_rematrixing(AC3EncodeContext *s)
    {
        int nb_coefs;
        int blk, bnd, i;
        int start, end;
        uint8_t *flags;
    
    
        if (!s->rematrixing_enabled)
    
            return;
    
        for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
            AC3Block *block = &s->blocks[blk];
            if (block->new_rematrixing_strategy)
                flags = block->rematrixing_flags;
    
            nb_coefs = FFMIN(block->end_freq[1], block->end_freq[2]);
            for (bnd = 0; bnd < block->num_rematrixing_bands; bnd++) {
    
                if (flags[bnd]) {
                    start = ff_ac3_rematrix_band_tab[bnd];
                    end   = FFMIN(nb_coefs, ff_ac3_rematrix_band_tab[bnd+1]);
                    for (i = start; i < end; i++) {
    
                        int32_t lt = block->fixed_coef[1][i];
                        int32_t rt = block->fixed_coef[2][i];
                        block->fixed_coef[1][i] = (lt + rt) >> 1;
                        block->fixed_coef[2][i] = (lt - rt) >> 1;
    
    /**
     * Initialize exponent tables.
     */
    static av_cold void exponent_init(AC3EncodeContext *s)
    {
    
        int expstr, i, grpsize;
    
        for (expstr = EXP_D15-1; expstr <= EXP_D45-1; expstr++) {
            grpsize = 3 << expstr;
    
            for (i = 12; i < 256; i++) {
                exponent_group_tab[0][expstr][i] = (i + grpsize - 4) / grpsize;
                exponent_group_tab[1][expstr][i] = (i              ) / grpsize;
    
        /* LFE */
    
        exponent_group_tab[0][0][7] = 2;
    
    /**
     * Extract exponents from the MDCT coefficients.
     * This takes into account the normalization that was done to the input samples
     * by adjusting the exponents by the exponent shift values.
     */
    
    static void extract_exponents(AC3EncodeContext *s)
    
        for (ch = !s->cpl_on; ch <= s->channels; ch++) {
    
            for (blk = 0; blk < AC3_MAX_BLOCKS; blk++) {
    
                s->ac3dsp.extract_exponents(block->exp[ch], block->fixed_coef[ch],
                                            AC3_MAX_COEFS);
    
    /**
     * Exponent Difference Threshold.
     * New exponents are sent if their SAD exceed this number.
     */
    
    #define EXP_DIFF_THRESHOLD 500
    
    /**
     * Calculate exponent strategies for all channels.
    
     * Array arrangement is reversed to simplify the per-channel calculation.
    
    static void compute_exp_strategy(AC3EncodeContext *s)
    
        for (ch = !s->cpl_on; ch <= s->fbw_channels; ch++) {
    
            uint8_t *exp_strategy = s->exp_strategy[ch];
            uint8_t *exp          = s->blocks[0].exp[ch];
            int exp_diff;
    
            /* estimate if the exponent variation & decide if they should be
               reused in the next frame */
            exp_strategy[0] = EXP_NEW;
            exp += AC3_MAX_COEFS;
    
            for (blk = 1; blk < AC3_MAX_BLOCKS; blk++, exp += AC3_MAX_COEFS) {
                if ((ch == CPL_CH && (!s->blocks[blk].cpl_in_use || !s->blocks[blk-1].cpl_in_use)) ||
                    (ch  > CPL_CH && (s->blocks[blk].channel_in_cpl[ch] != s->blocks[blk-1].channel_in_cpl[ch]))) {
                    exp_strategy[blk] = EXP_NEW;
                    continue;
                }
    
                exp_diff = s->dsp.sad[0](NULL, exp, exp - AC3_MAX_COEFS, 16, 16);
    
                exp_strategy[blk] = EXP_REUSE;
                if (ch == CPL_CH && exp_diff > (EXP_DIFF_THRESHOLD * (s->blocks[blk].end_freq[ch] - s->start_freq[ch]) / AC3_MAX_COEFS))
                    exp_strategy[blk] = EXP_NEW;
                else if (ch > CPL_CH && exp_diff > EXP_DIFF_THRESHOLD)
    
                    exp_strategy[blk] = EXP_NEW;
            }
    
            /* now select the encoding strategy type : if exponents are often
               recoded, we use a coarse encoding */
            blk = 0;
            while (blk < AC3_MAX_BLOCKS) {
                blk1 = blk + 1;
                while (blk1 < AC3_MAX_BLOCKS && exp_strategy[blk1] == EXP_REUSE)
                    blk1++;
                switch (blk1 - blk) {
                case 1:  exp_strategy[blk] = EXP_D45; break;
                case 2:
                case 3:  exp_strategy[blk] = EXP_D25; break;
                default: exp_strategy[blk] = EXP_D15; break;
                }
                blk = blk1;
            }
    
            for (blk = 1; blk < AC3_MAX_BLOCKS; blk++)
    
                s->exp_strategy[ch][blk] = EXP_REUSE;
    
    /**
     * Update the exponents so that they are the ones the decoder will decode.
     */
    
    static void encode_exponents_blk_ch(uint8_t *exp, int nb_exps, int exp_strategy,
                                        int cpl)
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    {
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
    
        nb_groups = exponent_group_tab[cpl][exp_strategy-1][nb_exps] * 3;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
    
        /* for each group, compute the minimum exponent */
    
            for (i = 1, k = 1-cpl; i <= nb_groups; i++) {
    
                uint8_t exp_min = exp[k];
                if (exp[k+1] < exp_min)
                    exp_min = exp[k+1];
    
                exp[i-cpl] = exp_min;
    
    Fabrice Bellard's avatar
    Fabrice Bellard committed
            }
    
            for (i = 1, k = 1-cpl; i <= nb_groups; i++) {
    
                uint8_t exp_min = exp[k];
                if (exp[k+1] < exp_min)
                    exp_min = exp[k+1];
                if (exp[k+2] < exp_min)