00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00027 #include "libavutil/audioconvert.h"
00028 #include "libavutil/eval.h"
00029 #include "audio.h"
00030 #include "avfilter.h"
00031 #include "formats.h"
00032
00033 typedef struct {
00034 double volume;
00035 int volume_i;
00036 } VolumeContext;
00037
00038 static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
00039 {
00040 VolumeContext *vol = ctx->priv;
00041 char *tail;
00042 int ret = 0;
00043
00044 vol->volume = 1.0;
00045
00046 if (args) {
00047
00048 double d = strtod(args, &tail);
00049
00050 if (*tail) {
00051 if (!strcmp(tail, "dB")) {
00052
00053 d = pow(10, d/20);
00054 } else {
00055
00056 ret = av_expr_parse_and_eval(&d, args, NULL, NULL,
00057 NULL, NULL, NULL, NULL,
00058 NULL, 0, ctx);
00059 }
00060 }
00061
00062 if (ret < 0) {
00063 av_log(ctx, AV_LOG_ERROR,
00064 "Invalid volume argument '%s'\n", args);
00065 return AVERROR(EINVAL);
00066 }
00067
00068 if (d < 0 || d > 65536) {
00069 av_log(ctx, AV_LOG_ERROR,
00070 "Negative or too big volume value %f\n", d);
00071 return AVERROR(EINVAL);
00072 }
00073
00074 vol->volume = d;
00075 }
00076
00077 vol->volume_i = (int)(vol->volume * 256 + 0.5);
00078 av_log(ctx, AV_LOG_INFO, "volume=%f\n", vol->volume);
00079 return 0;
00080 }
00081
00082 static int query_formats(AVFilterContext *ctx)
00083 {
00084 AVFilterFormats *formats = NULL;
00085 AVFilterChannelLayouts *layouts;
00086 enum AVSampleFormat sample_fmts[] = {
00087 AV_SAMPLE_FMT_U8,
00088 AV_SAMPLE_FMT_S16,
00089 AV_SAMPLE_FMT_S32,
00090 AV_SAMPLE_FMT_FLT,
00091 AV_SAMPLE_FMT_DBL,
00092 AV_SAMPLE_FMT_NONE
00093 };
00094
00095 layouts = ff_all_channel_layouts();
00096 if (!layouts)
00097 return AVERROR(ENOMEM);
00098 ff_set_common_channel_layouts(ctx, layouts);
00099
00100 formats = avfilter_make_format_list(sample_fmts);
00101 if (!formats)
00102 return AVERROR(ENOMEM);
00103 avfilter_set_common_sample_formats(ctx, formats);
00104
00105 formats = ff_all_samplerates();
00106 if (!formats)
00107 return AVERROR(ENOMEM);
00108 ff_set_common_samplerates(ctx, formats);
00109
00110 return 0;
00111 }
00112
00113 static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
00114 {
00115 VolumeContext *vol = inlink->dst->priv;
00116 AVFilterLink *outlink = inlink->dst->outputs[0];
00117 const int nb_samples = insamples->audio->nb_samples *
00118 av_get_channel_layout_nb_channels(insamples->audio->channel_layout);
00119 const double volume = vol->volume;
00120 const int volume_i = vol->volume_i;
00121 int i;
00122
00123 if (volume_i != 256) {
00124 switch (insamples->format) {
00125 case AV_SAMPLE_FMT_U8:
00126 {
00127 uint8_t *p = (void *)insamples->data[0];
00128 for (i = 0; i < nb_samples; i++) {
00129 int v = (((*p - 128) * volume_i + 128) >> 8) + 128;
00130 *p++ = av_clip_uint8(v);
00131 }
00132 break;
00133 }
00134 case AV_SAMPLE_FMT_S16:
00135 {
00136 int16_t *p = (void *)insamples->data[0];
00137 for (i = 0; i < nb_samples; i++) {
00138 int v = ((int64_t)*p * volume_i + 128) >> 8;
00139 *p++ = av_clip_int16(v);
00140 }
00141 break;
00142 }
00143 case AV_SAMPLE_FMT_S32:
00144 {
00145 int32_t *p = (void *)insamples->data[0];
00146 for (i = 0; i < nb_samples; i++) {
00147 int64_t v = (((int64_t)*p * volume_i + 128) >> 8);
00148 *p++ = av_clipl_int32(v);
00149 }
00150 break;
00151 }
00152 case AV_SAMPLE_FMT_FLT:
00153 {
00154 float *p = (void *)insamples->data[0];
00155 float scale = (float)volume;
00156 for (i = 0; i < nb_samples; i++) {
00157 *p++ *= scale;
00158 }
00159 break;
00160 }
00161 case AV_SAMPLE_FMT_DBL:
00162 {
00163 double *p = (void *)insamples->data[0];
00164 for (i = 0; i < nb_samples; i++) {
00165 *p *= volume;
00166 p++;
00167 }
00168 break;
00169 }
00170 }
00171 }
00172 ff_filter_samples(outlink, insamples);
00173 }
00174
00175 AVFilter avfilter_af_volume = {
00176 .name = "volume",
00177 .description = NULL_IF_CONFIG_SMALL("Change input volume."),
00178 .query_formats = query_formats,
00179 .priv_size = sizeof(VolumeContext),
00180 .init = init,
00181
00182 .inputs = (const AVFilterPad[]) {{ .name = "default",
00183 .type = AVMEDIA_TYPE_AUDIO,
00184 .filter_samples = filter_samples,
00185 .min_perms = AV_PERM_READ|AV_PERM_WRITE},
00186 { .name = NULL}},
00187
00188 .outputs = (const AVFilterPad[]) {{ .name = "default",
00189 .type = AVMEDIA_TYPE_AUDIO, },
00190 { .name = NULL}},
00191 };