~ubuntu-branches/ubuntu/trusty/libav/trusty-proposed

« back to all changes in this revision

Viewing changes to libavfilter/af_volume.c

  • Committer: Package Import Robot
  • Author(s): Reinhard Tartler
  • Date: 2013-10-22 23:24:08 UTC
  • mfrom: (1.3.36 sid)
  • Revision ID: package-import@ubuntu.com-20131022232408-b8tvvn4pyzri9mi3
Tags: 6:9.10-1ubuntu1
* Build all -extra flavors from this source package, as libav got demoted
  from main to universe, cf LP: #1243235
* Simplify debian/rules to follow exactly the code that debian executes
* New upstream (LP: #1180288) fixes lots of security issues (LP: #1242802)
* Merge from unstable, remaining changes:
  - build-depend on libtiff5-dev rather than libtiff4-dev,
    avoids FTBFS caused by imlib
  - follow the regular debian codepaths

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2011 Stefano Sabatini
 
3
 * Copyright (c) 2012 Justin Ruggles <justin.ruggles@gmail.com>
 
4
 *
 
5
 * This file is part of Libav.
 
6
 *
 
7
 * Libav 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
 * Libav 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 Libav; if not, write to the Free Software
 
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 
20
 */
 
21
 
 
22
/**
 
23
 * @file
 
24
 * audio volume filter
 
25
 */
 
26
 
 
27
#include "libavutil/audioconvert.h"
 
28
#include "libavutil/common.h"
 
29
#include "libavutil/eval.h"
 
30
#include "libavutil/float_dsp.h"
 
31
#include "libavutil/opt.h"
 
32
#include "audio.h"
 
33
#include "avfilter.h"
 
34
#include "formats.h"
 
35
#include "internal.h"
 
36
#include "af_volume.h"
 
37
 
 
38
static const char *precision_str[] = {
 
39
    "fixed", "float", "double"
 
40
};
 
41
 
 
42
#define OFFSET(x) offsetof(VolumeContext, x)
 
43
#define A AV_OPT_FLAG_AUDIO_PARAM
 
44
 
 
45
static const AVOption options[] = {
 
46
    { "volume", "Volume adjustment.",
 
47
            OFFSET(volume), AV_OPT_TYPE_DOUBLE, { .dbl = 1.0 }, 0, 0x7fffff, A },
 
48
    { "precision", "Mathematical precision.",
 
49
            OFFSET(precision), AV_OPT_TYPE_INT, { .i64 = PRECISION_FLOAT }, PRECISION_FIXED, PRECISION_DOUBLE, A, "precision" },
 
50
        { "fixed",  "8-bit fixed-point.",     0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_FIXED  }, INT_MIN, INT_MAX, A, "precision" },
 
51
        { "float",  "32-bit floating-point.", 0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_FLOAT  }, INT_MIN, INT_MAX, A, "precision" },
 
52
        { "double", "64-bit floating-point.", 0, AV_OPT_TYPE_CONST, { .i64 = PRECISION_DOUBLE }, INT_MIN, INT_MAX, A, "precision" },
 
53
    { NULL },
 
54
};
 
55
 
 
56
static const AVClass volume_class = {
 
57
    .class_name = "volume filter",
 
58
    .item_name  = av_default_item_name,
 
59
    .option     = options,
 
60
    .version    = LIBAVUTIL_VERSION_INT,
 
61
};
 
62
 
 
63
static av_cold int init(AVFilterContext *ctx, const char *args)
 
64
{
 
65
    VolumeContext *vol = ctx->priv;
 
66
    int ret;
 
67
 
 
68
    vol->class = &volume_class;
 
69
    av_opt_set_defaults(vol);
 
70
 
 
71
    if ((ret = av_set_options_string(vol, args, "=", ":")) < 0) {
 
72
        av_log(ctx, AV_LOG_ERROR, "Error parsing options string '%s'.\n", args);
 
73
        return ret;
 
74
    }
 
75
 
 
76
    if (vol->precision == PRECISION_FIXED) {
 
77
        vol->volume_i = (int)(vol->volume * 256 + 0.5);
 
78
        vol->volume   = vol->volume_i / 256.0;
 
79
        av_log(ctx, AV_LOG_VERBOSE, "volume:(%d/256)(%f)(%1.2fdB) precision:fixed\n",
 
80
               vol->volume_i, vol->volume, 20.0*log(vol->volume)/M_LN10);
 
81
    } else {
 
82
        av_log(ctx, AV_LOG_VERBOSE, "volume:(%f)(%1.2fdB) precision:%s\n",
 
83
               vol->volume, 20.0*log(vol->volume)/M_LN10,
 
84
               precision_str[vol->precision]);
 
85
    }
 
86
 
 
87
    av_opt_free(vol);
 
88
    return ret;
 
89
}
 
90
 
 
91
static int query_formats(AVFilterContext *ctx)
 
92
{
 
93
    VolumeContext *vol = ctx->priv;
 
94
    AVFilterFormats *formats = NULL;
 
95
    AVFilterChannelLayouts *layouts;
 
96
    static const enum AVSampleFormat sample_fmts[][7] = {
 
97
        /* PRECISION_FIXED */
 
98
        {
 
99
            AV_SAMPLE_FMT_U8,
 
100
            AV_SAMPLE_FMT_U8P,
 
101
            AV_SAMPLE_FMT_S16,
 
102
            AV_SAMPLE_FMT_S16P,
 
103
            AV_SAMPLE_FMT_S32,
 
104
            AV_SAMPLE_FMT_S32P,
 
105
            AV_SAMPLE_FMT_NONE
 
106
        },
 
107
        /* PRECISION_FLOAT */
 
108
        {
 
109
            AV_SAMPLE_FMT_FLT,
 
110
            AV_SAMPLE_FMT_FLTP,
 
111
            AV_SAMPLE_FMT_NONE
 
112
        },
 
113
        /* PRECISION_DOUBLE */
 
114
        {
 
115
            AV_SAMPLE_FMT_DBL,
 
116
            AV_SAMPLE_FMT_DBLP,
 
117
            AV_SAMPLE_FMT_NONE
 
118
        }
 
119
    };
 
120
 
 
121
    layouts = ff_all_channel_layouts();
 
122
    if (!layouts)
 
123
        return AVERROR(ENOMEM);
 
124
    ff_set_common_channel_layouts(ctx, layouts);
 
125
 
 
126
    formats = ff_make_format_list(sample_fmts[vol->precision]);
 
127
    if (!formats)
 
128
        return AVERROR(ENOMEM);
 
129
    ff_set_common_formats(ctx, formats);
 
130
 
 
131
    formats = ff_all_samplerates();
 
132
    if (!formats)
 
133
        return AVERROR(ENOMEM);
 
134
    ff_set_common_samplerates(ctx, formats);
 
135
 
 
136
    return 0;
 
137
}
 
138
 
 
139
static inline void scale_samples_u8(uint8_t *dst, const uint8_t *src,
 
140
                                    int nb_samples, int volume)
 
141
{
 
142
    int i;
 
143
    for (i = 0; i < nb_samples; i++)
 
144
        dst[i] = av_clip_uint8(((((int64_t)src[i] - 128) * volume + 128) >> 8) + 128);
 
145
}
 
146
 
 
147
static inline void scale_samples_u8_small(uint8_t *dst, const uint8_t *src,
 
148
                                          int nb_samples, int volume)
 
149
{
 
150
    int i;
 
151
    for (i = 0; i < nb_samples; i++)
 
152
        dst[i] = av_clip_uint8((((src[i] - 128) * volume + 128) >> 8) + 128);
 
153
}
 
154
 
 
155
static inline void scale_samples_s16(uint8_t *dst, const uint8_t *src,
 
156
                                     int nb_samples, int volume)
 
157
{
 
158
    int i;
 
159
    int16_t *smp_dst       = (int16_t *)dst;
 
160
    const int16_t *smp_src = (const int16_t *)src;
 
161
    for (i = 0; i < nb_samples; i++)
 
162
        smp_dst[i] = av_clip_int16(((int64_t)smp_src[i] * volume + 128) >> 8);
 
163
}
 
164
 
 
165
static inline void scale_samples_s16_small(uint8_t *dst, const uint8_t *src,
 
166
                                           int nb_samples, int volume)
 
167
{
 
168
    int i;
 
169
    int16_t *smp_dst       = (int16_t *)dst;
 
170
    const int16_t *smp_src = (const int16_t *)src;
 
171
    for (i = 0; i < nb_samples; i++)
 
172
        smp_dst[i] = av_clip_int16((smp_src[i] * volume + 128) >> 8);
 
173
}
 
174
 
 
175
static inline void scale_samples_s32(uint8_t *dst, const uint8_t *src,
 
176
                                     int nb_samples, int volume)
 
177
{
 
178
    int i;
 
179
    int32_t *smp_dst       = (int32_t *)dst;
 
180
    const int32_t *smp_src = (const int32_t *)src;
 
181
    for (i = 0; i < nb_samples; i++)
 
182
        smp_dst[i] = av_clipl_int32((((int64_t)smp_src[i] * volume + 128) >> 8));
 
183
}
 
184
 
 
185
 
 
186
 
 
187
static void volume_init(VolumeContext *vol)
 
188
{
 
189
    vol->samples_align = 1;
 
190
 
 
191
    switch (av_get_packed_sample_fmt(vol->sample_fmt)) {
 
192
    case AV_SAMPLE_FMT_U8:
 
193
        if (vol->volume_i < 0x1000000)
 
194
            vol->scale_samples = scale_samples_u8_small;
 
195
        else
 
196
            vol->scale_samples = scale_samples_u8;
 
197
        break;
 
198
    case AV_SAMPLE_FMT_S16:
 
199
        if (vol->volume_i < 0x10000)
 
200
            vol->scale_samples = scale_samples_s16_small;
 
201
        else
 
202
            vol->scale_samples = scale_samples_s16;
 
203
        break;
 
204
    case AV_SAMPLE_FMT_S32:
 
205
        vol->scale_samples = scale_samples_s32;
 
206
        break;
 
207
    case AV_SAMPLE_FMT_FLT:
 
208
        avpriv_float_dsp_init(&vol->fdsp, 0);
 
209
        vol->samples_align = 4;
 
210
        break;
 
211
    case AV_SAMPLE_FMT_DBL:
 
212
        avpriv_float_dsp_init(&vol->fdsp, 0);
 
213
        vol->samples_align = 8;
 
214
        break;
 
215
    }
 
216
 
 
217
    if (ARCH_X86)
 
218
        ff_volume_init_x86(vol);
 
219
}
 
220
 
 
221
static int config_output(AVFilterLink *outlink)
 
222
{
 
223
    AVFilterContext *ctx = outlink->src;
 
224
    VolumeContext *vol   = ctx->priv;
 
225
    AVFilterLink *inlink = ctx->inputs[0];
 
226
 
 
227
    vol->sample_fmt = inlink->format;
 
228
    vol->channels   = av_get_channel_layout_nb_channels(inlink->channel_layout);
 
229
    vol->planes     = av_sample_fmt_is_planar(inlink->format) ? vol->channels : 1;
 
230
 
 
231
    volume_init(vol);
 
232
 
 
233
    return 0;
 
234
}
 
235
 
 
236
static int filter_frame(AVFilterLink *inlink, AVFilterBufferRef *buf)
 
237
{
 
238
    VolumeContext *vol    = inlink->dst->priv;
 
239
    AVFilterLink *outlink = inlink->dst->outputs[0];
 
240
    int nb_samples        = buf->audio->nb_samples;
 
241
    AVFilterBufferRef *out_buf;
 
242
 
 
243
    if (vol->volume == 1.0 || vol->volume_i == 256)
 
244
        return ff_filter_frame(outlink, buf);
 
245
 
 
246
    /* do volume scaling in-place if input buffer is writable */
 
247
    if (buf->perms & AV_PERM_WRITE) {
 
248
        out_buf = buf;
 
249
    } else {
 
250
        out_buf = ff_get_audio_buffer(inlink, AV_PERM_WRITE, nb_samples);
 
251
        if (!out_buf)
 
252
            return AVERROR(ENOMEM);
 
253
        out_buf->pts = buf->pts;
 
254
    }
 
255
 
 
256
    if (vol->precision != PRECISION_FIXED || vol->volume_i > 0) {
 
257
        int p, plane_samples;
 
258
 
 
259
        if (av_sample_fmt_is_planar(buf->format))
 
260
            plane_samples = FFALIGN(nb_samples, vol->samples_align);
 
261
        else
 
262
            plane_samples = FFALIGN(nb_samples * vol->channels, vol->samples_align);
 
263
 
 
264
        if (vol->precision == PRECISION_FIXED) {
 
265
            for (p = 0; p < vol->planes; p++) {
 
266
                vol->scale_samples(out_buf->extended_data[p],
 
267
                                   buf->extended_data[p], plane_samples,
 
268
                                   vol->volume_i);
 
269
            }
 
270
        } else if (av_get_packed_sample_fmt(vol->sample_fmt) == AV_SAMPLE_FMT_FLT) {
 
271
            for (p = 0; p < vol->planes; p++) {
 
272
                vol->fdsp.vector_fmul_scalar((float *)out_buf->extended_data[p],
 
273
                                             (const float *)buf->extended_data[p],
 
274
                                             vol->volume, plane_samples);
 
275
            }
 
276
        } else {
 
277
            for (p = 0; p < vol->planes; p++) {
 
278
                vol->fdsp.vector_dmul_scalar((double *)out_buf->extended_data[p],
 
279
                                             (const double *)buf->extended_data[p],
 
280
                                             vol->volume, plane_samples);
 
281
            }
 
282
        }
 
283
    }
 
284
 
 
285
    if (buf != out_buf)
 
286
        avfilter_unref_buffer(buf);
 
287
 
 
288
    return ff_filter_frame(outlink, out_buf);
 
289
}
 
290
 
 
291
static const AVFilterPad avfilter_af_volume_inputs[] = {
 
292
    {
 
293
        .name           = "default",
 
294
        .type           = AVMEDIA_TYPE_AUDIO,
 
295
        .filter_frame   = filter_frame,
 
296
    },
 
297
    { NULL }
 
298
};
 
299
 
 
300
static const AVFilterPad avfilter_af_volume_outputs[] = {
 
301
    {
 
302
        .name         = "default",
 
303
        .type         = AVMEDIA_TYPE_AUDIO,
 
304
        .config_props = config_output,
 
305
    },
 
306
    { NULL }
 
307
};
 
308
 
 
309
AVFilter avfilter_af_volume = {
 
310
    .name           = "volume",
 
311
    .description    = NULL_IF_CONFIG_SMALL("Change input volume."),
 
312
    .query_formats  = query_formats,
 
313
    .priv_size      = sizeof(VolumeContext),
 
314
    .init           = init,
 
315
    .inputs         = avfilter_af_volume_inputs,
 
316
    .outputs        = avfilter_af_volume_outputs,
 
317
};