Line | Branch | Exec | Source |
---|---|---|---|
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 | |||
29 | extern const FFPsyModel ff_aac_psy_model; | ||
30 | |||
31 | 11 | av_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 | 11 | int i, j, k = 0; | |
36 | |||
37 | 11 | ctx->avctx = avctx; | |
38 | 11 | ctx->ch = av_calloc(avctx->ch_layout.nb_channels, 2 * sizeof(ctx->ch[0])); | |
39 | 11 | ctx->group = av_calloc(num_groups, sizeof(ctx->group[0])); | |
40 | 11 | ctx->bands = av_malloc_array (sizeof(ctx->bands[0]), num_lens); | |
41 | 11 | ctx->num_bands = av_malloc_array (sizeof(ctx->num_bands[0]), num_lens); | |
42 | 11 | ctx->cutoff = avctx->cutoff; | |
43 | |||
44 |
4/8✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 11 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 11 times.
|
11 | if (!ctx->ch || !ctx->group || !ctx->bands || !ctx->num_bands) { |
45 | ✗ | ff_psy_end(ctx); | |
46 | ✗ | return AVERROR(ENOMEM); | |
47 | } | ||
48 | |||
49 | 11 | memcpy(ctx->bands, bands, sizeof(ctx->bands[0]) * num_lens); | |
50 | 11 | 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 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 11 times.
|
25 | 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 | 14 | ctx->group[i].num_ch = group_map[i] + 1; | |
59 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 14 times.
|
64 | for (j = 0; j < ctx->group[i].num_ch * 2; j++) |
60 | 50 | ctx->group[i].ch[j] = &ctx->ch[k++]; | |
61 | } | ||
62 | |||
63 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | switch (ctx->avctx->codec_id) { |
64 | 11 | case AV_CODEC_ID_AAC: | |
65 | 11 | ctx->model = &ff_aac_psy_model; | |
66 | 11 | break; | |
67 | } | ||
68 |
1/2✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
|
11 | if (ctx->model->init) |
69 | 11 | return ctx->model->init(ctx); | |
70 | ✗ | return 0; | |
71 | } | ||
72 | |||
73 | 5448 | FFPsyChannelGroup *ff_psy_find_group(FFPsyContext *ctx, int channel) | |
74 | { | ||
75 | 5448 | int i = 0, ch = 0; | |
76 | |||
77 |
2/2✓ Branch 0 taken 5880 times.
✓ Branch 1 taken 5448 times.
|
11328 | while (ch <= channel) |
78 | 5880 | ch += ctx->group[i++].num_ch; | |
79 | |||
80 | 5448 | return &ctx->group[i-1]; | |
81 | } | ||
82 | |||
83 | 11 | av_cold void ff_psy_end(FFPsyContext *ctx) | |
84 | { | ||
85 |
2/4✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
11 | if (ctx->model && ctx->model->end) |
86 | 11 | ctx->model->end(ctx); | |
87 | 11 | av_freep(&ctx->bands); | |
88 | 11 | av_freep(&ctx->num_bands); | |
89 | 11 | av_freep(&ctx->group); | |
90 | 11 | av_freep(&ctx->ch); | |
91 | 11 | } | |
92 | |||
93 | typedef 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 | |||
103 | 11 | av_cold struct FFPsyPreprocessContext* ff_psy_preprocess_init(AVCodecContext *avctx) | |
104 | { | ||
105 | FFPsyPreprocessContext *ctx; | ||
106 | int i; | ||
107 | 11 | float cutoff_coeff = 0; | |
108 | 11 | ctx = av_mallocz(sizeof(FFPsyPreprocessContext)); | |
109 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | if (!ctx) |
110 | ✗ | return NULL; | |
111 | 11 | ctx->avctx = avctx; | |
112 | |||
113 | /* AAC has its own LP method */ | ||
114 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | 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 | 11 | ff_iir_filter_init(&ctx->fiir); | |
135 | |||
136 | 11 | return ctx; | |
137 | } | ||
138 | |||
139 | 3816 | void ff_psy_preprocess(struct FFPsyPreprocessContext *ctx, float **audio, int channels) | |
140 | { | ||
141 | int ch; | ||
142 | 3816 | int frame_size = ctx->avctx->frame_size; | |
143 | 3816 | FFIIRFilterContext *iir = &ctx->fiir; | |
144 | |||
145 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3816 times.
|
3816 | 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 | 3816 | } | |
151 | |||
152 | 11 | av_cold void ff_psy_preprocess_end(struct FFPsyPreprocessContext *ctx) | |
153 | { | ||
154 | int i; | ||
155 | 11 | ff_iir_filter_free_coeffsp(&ctx->fcoeffs); | |
156 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
|
11 | 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 | 11 | av_freep(&ctx->fstate); | |
160 | 11 | av_free(ctx); | |
161 | 11 | } | |
162 |