1/* 2 * audio encoder psychoacoustic model 3 * Copyright (C) 2008 Konstantin Shishkov 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22#include <string.h> 23 24#include "avcodec.h" 25#include "psymodel.h" 26#include "iirfilter.h" 27#include "libavutil/mem.h" 28 29extern const FFPsyModel ff_aac_psy_model; 30 31av_cold int ff_psy_init(FFPsyContext *ctx, AVCodecContext *avctx, int num_lens, 32 const uint8_t **bands, const int* num_bands, 33 int num_groups, const uint8_t *group_map) 34{ 35 int i, j, k = 0; 36 37 ctx->avctx = avctx; 38 ctx->ch = av_calloc(avctx->ch_layout.nb_channels, 2 * sizeof(ctx->ch[0])); 39 ctx->group = av_calloc(num_groups, sizeof(ctx->group[0])); 40 ctx->bands = av_malloc_array (sizeof(ctx->bands[0]), num_lens); 41 ctx->num_bands = av_malloc_array (sizeof(ctx->num_bands[0]), num_lens); 42 ctx->cutoff = avctx->cutoff; 43 44 if (!ctx->ch || !ctx->group || !ctx->bands || !ctx->num_bands) { 45 ff_psy_end(ctx); 46 return AVERROR(ENOMEM); 47 } 48 49 memcpy(ctx->bands, bands, sizeof(ctx->bands[0]) * num_lens); 50 memcpy(ctx->num_bands, num_bands, sizeof(ctx->num_bands[0]) * num_lens); 51 52 /* assign channels to groups (with virtual channels for coupling) */ 53 for (i = 0; i < num_groups; i++) { 54 /* NOTE: Add 1 to handle the AAC chan_config without modification. 55 * This has the side effect of allowing an array of 0s to map 56 * to one channel per group. 57 */ 58 ctx->group[i].num_ch = group_map[i] + 1; 59 for (j = 0; j < ctx->group[i].num_ch * 2; j++) 60 ctx->group[i].ch[j] = &ctx->ch[k++]; 61 } 62 63 switch (ctx->avctx->codec_id) { 64 case AV_CODEC_ID_AAC: 65 ctx->model = &ff_aac_psy_model; 66 break; 67 } 68 if (ctx->model->init) 69 return ctx->model->init(ctx); 70 return 0; 71} 72 73FFPsyChannelGroup *ff_psy_find_group(FFPsyContext *ctx, int channel) 74{ 75 int i = 0, ch = 0; 76 77 while (ch <= channel) 78 ch += ctx->group[i++].num_ch; 79 80 return &ctx->group[i-1]; 81} 82 83av_cold void ff_psy_end(FFPsyContext *ctx) 84{ 85 if (ctx->model && ctx->model->end) 86 ctx->model->end(ctx); 87 av_freep(&ctx->bands); 88 av_freep(&ctx->num_bands); 89 av_freep(&ctx->group); 90 av_freep(&ctx->ch); 91} 92 93typedef struct FFPsyPreprocessContext{ 94 AVCodecContext *avctx; 95 float stereo_att; 96 struct FFIIRFilterCoeffs *fcoeffs; 97 struct FFIIRFilterState **fstate; 98 struct FFIIRFilterContext fiir; 99}FFPsyPreprocessContext; 100 101#define FILT_ORDER 4 102 103av_cold struct FFPsyPreprocessContext* ff_psy_preprocess_init(AVCodecContext *avctx) 104{ 105 FFPsyPreprocessContext *ctx; 106 int i; 107 float cutoff_coeff = 0; 108 ctx = av_mallocz(sizeof(FFPsyPreprocessContext)); 109 if (!ctx) 110 return NULL; 111 ctx->avctx = avctx; 112 113 /* AAC has its own LP method */ 114 if (avctx->codec_id != AV_CODEC_ID_AAC) { 115 if (avctx->cutoff > 0) 116 cutoff_coeff = 2.0 * avctx->cutoff / avctx->sample_rate; 117 118 if (cutoff_coeff && cutoff_coeff < 0.98) 119 ctx->fcoeffs = ff_iir_filter_init_coeffs(avctx, FF_FILTER_TYPE_BUTTERWORTH, 120 FF_FILTER_MODE_LOWPASS, FILT_ORDER, 121 cutoff_coeff, 0.0, 0.0); 122 if (ctx->fcoeffs) { 123 ctx->fstate = av_calloc(avctx->ch_layout.nb_channels, sizeof(ctx->fstate[0])); 124 if (!ctx->fstate) { 125 av_free(ctx->fcoeffs); 126 av_free(ctx); 127 return NULL; 128 } 129 for (i = 0; i < avctx->ch_layout.nb_channels; i++) 130 ctx->fstate[i] = ff_iir_filter_init_state(FILT_ORDER); 131 } 132 } 133 134 ff_iir_filter_init(&ctx->fiir); 135 136 return ctx; 137} 138 139void ff_psy_preprocess(struct FFPsyPreprocessContext *ctx, float **audio, int channels) 140{ 141 int ch; 142 int frame_size = ctx->avctx->frame_size; 143 FFIIRFilterContext *iir = &ctx->fiir; 144 145 if (ctx->fstate) { 146 for (ch = 0; ch < channels; ch++) 147 iir->filter_flt(ctx->fcoeffs, ctx->fstate[ch], frame_size, 148 &audio[ch][frame_size], 1, &audio[ch][frame_size], 1); 149 } 150} 151 152av_cold void ff_psy_preprocess_end(struct FFPsyPreprocessContext *ctx) 153{ 154 int i; 155 ff_iir_filter_free_coeffsp(&ctx->fcoeffs); 156 if (ctx->fstate) 157 for (i = 0; i < ctx->avctx->ch_layout.nb_channels; i++) 158 ff_iir_filter_free_statep(&ctx->fstate[i]); 159 av_freep(&ctx->fstate); 160 av_free(ctx); 161} 162