libavfilter/asrc_aevalsrc.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2011 Stefano Sabatini
00003  *
00004  * This file is part of FFmpeg.
00005  *
00006  * FFmpeg is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * FFmpeg is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with FFmpeg; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00019  */
00020 
00026 #include "libavutil/audioconvert.h"
00027 #include "libavutil/avassert.h"
00028 #include "libavutil/avstring.h"
00029 #include "libavutil/eval.h"
00030 #include "libavutil/opt.h"
00031 #include "libavutil/parseutils.h"
00032 #include "avfilter.h"
00033 #include "internal.h"
00034 
00035 static const char * const var_names[] = {
00036     "n",            
00037     "t",            
00038     "s",            
00039     NULL
00040 };
00041 
00042 enum var_name {
00043     VAR_N,
00044     VAR_T,
00045     VAR_S,
00046     VAR_VARS_NB
00047 };
00048 
00049 typedef struct {
00050     const AVClass *class;
00051     char *sample_rate_str;
00052     int sample_rate;
00053     int64_t chlayout;
00054     int nb_channels;
00055     int64_t pts;
00056     AVExpr *expr[8];
00057     char *expr_str[8];
00058     int nb_samples;             
00059     char *duration_str;         
00060     double duration;
00061     uint64_t n;
00062     double var_values[VAR_VARS_NB];
00063 } EvalContext;
00064 
00065 #define OFFSET(x) offsetof(EvalContext, x)
00066 
00067 static const AVOption eval_options[]= {
00068     { "nb_samples",  "set the number of samples per requested frame", OFFSET(nb_samples),      AV_OPT_TYPE_INT,    {.dbl = 1024},    0,        INT_MAX },
00069     { "n",           "set the number of samples per requested frame", OFFSET(nb_samples),      AV_OPT_TYPE_INT,    {.dbl = 1024},    0,        INT_MAX },
00070     { "sample_rate", "set the sample rate",                           OFFSET(sample_rate_str), AV_OPT_TYPE_STRING, {.str = "44100"}, CHAR_MIN, CHAR_MAX },
00071     { "s",           "set the sample rate",                           OFFSET(sample_rate_str), AV_OPT_TYPE_STRING, {.str = "44100"}, CHAR_MIN, CHAR_MAX },
00072     { "duration",    "set audio duration", OFFSET(duration_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0 },
00073     { "d",           "set audio duration", OFFSET(duration_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0 },
00074 {NULL},
00075 };
00076 
00077 static const char *eval_get_name(void *ctx)
00078 {
00079     return "aevalsrc";
00080 }
00081 
00082 static const AVClass eval_class = {
00083     "AEvalSrcContext",
00084     eval_get_name,
00085     eval_options
00086 };
00087 
00088 static int init(AVFilterContext *ctx, const char *args, void *opaque)
00089 {
00090     EvalContext *eval = ctx->priv;
00091     char *args1 = av_strdup(args);
00092     char *expr, *buf, *bufptr;
00093     int ret, i;
00094 
00095     eval->class = &eval_class;
00096     av_opt_set_defaults(eval);
00097 
00098     /* parse expressions */
00099     buf = args1;
00100     i = 0;
00101     while (expr = av_strtok(buf, ":", &bufptr)) {
00102         if (i >= 8) {
00103             av_log(ctx, AV_LOG_ERROR,
00104                    "More than 8 expressions provided, unsupported.\n");
00105             ret = AVERROR(EINVAL);
00106             return ret;
00107         }
00108         ret = av_expr_parse(&eval->expr[i], expr, var_names,
00109                             NULL, NULL, NULL, NULL, 0, ctx);
00110         if (ret < 0)
00111             goto end;
00112         i++;
00113         if (bufptr && *bufptr == ':') { /* found last expression */
00114             bufptr++;
00115             break;
00116         }
00117         buf = NULL;
00118     }
00119 
00120     /* guess channel layout from nb expressions/channels */
00121     eval->nb_channels = i;
00122     eval->chlayout = av_get_default_channel_layout(eval->nb_channels);
00123     if (!eval->chlayout) {
00124         av_log(ctx, AV_LOG_ERROR, "Invalid number of channels '%d' provided\n",
00125                eval->nb_channels);
00126         ret = AVERROR(EINVAL);
00127         goto end;
00128     }
00129 
00130     if (bufptr && (ret = av_set_options_string(eval, bufptr, "=", ":")) < 0)
00131         goto end;
00132 
00133     if ((ret = ff_parse_sample_rate(&eval->sample_rate, eval->sample_rate_str, ctx)))
00134         goto end;
00135 
00136     eval->duration = -1;
00137     if (eval->duration_str) {
00138         int64_t us = -1;
00139         if ((ret = av_parse_time(&us, eval->duration_str, 1)) < 0) {
00140             av_log(ctx, AV_LOG_ERROR, "Invalid duration: '%s'\n", eval->duration_str);
00141             goto end;
00142         }
00143         eval->duration = (double)us / 1000000;
00144     }
00145     eval->n = 0;
00146 
00147 end:
00148     av_free(args1);
00149     return ret;
00150 }
00151 
00152 static void uninit(AVFilterContext *ctx)
00153 {
00154     EvalContext *eval = ctx->priv;
00155     int i;
00156 
00157     for (i = 0; i < 8; i++) {
00158         av_expr_free(eval->expr[i]);
00159         eval->expr[i] = NULL;
00160     }
00161     av_freep(&eval->duration_str);
00162     av_freep(&eval->sample_rate_str);
00163 }
00164 
00165 static int config_props(AVFilterLink *outlink)
00166 {
00167     EvalContext *eval = outlink->src->priv;
00168     char buf[128];
00169 
00170     outlink->time_base = (AVRational){1, eval->sample_rate};
00171     outlink->sample_rate = eval->sample_rate;
00172 
00173     eval->var_values[VAR_S] = eval->sample_rate;
00174 
00175     av_get_channel_layout_string(buf, sizeof(buf), 0, eval->chlayout);
00176 
00177     av_log(outlink->src, AV_LOG_INFO,
00178            "sample_rate:%d chlayout:%s duration:%f\n",
00179            eval->sample_rate, buf, eval->duration);
00180 
00181     return 0;
00182 }
00183 
00184 static int query_formats(AVFilterContext *ctx)
00185 {
00186     EvalContext *eval = ctx->priv;
00187     enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_NONE };
00188     int64_t chlayouts[] = { eval->chlayout, -1 };
00189     int packing_fmts[] = { AVFILTER_PLANAR, -1 };
00190 
00191     avfilter_set_common_sample_formats (ctx, avfilter_make_format_list(sample_fmts));
00192     avfilter_set_common_channel_layouts(ctx, avfilter_make_format64_list(chlayouts));
00193     avfilter_set_common_packing_formats(ctx, avfilter_make_format_list(packing_fmts));
00194 
00195     return 0;
00196 }
00197 
00198 static int request_frame(AVFilterLink *outlink)
00199 {
00200     EvalContext *eval = outlink->src->priv;
00201     AVFilterBufferRef *samplesref;
00202     int i, j;
00203     double t = eval->var_values[VAR_N] * (double)1/eval->sample_rate;
00204 
00205     if (eval->duration >= 0 && t > eval->duration)
00206         return AVERROR_EOF;
00207 
00208     samplesref = avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, eval->nb_samples);
00209 
00210     /* evaluate expression for each single sample and for each channel */
00211     for (i = 0; i < eval->nb_samples; i++, eval->n++) {
00212         eval->var_values[VAR_N] = eval->n;
00213         eval->var_values[VAR_T] = eval->var_values[VAR_N] * (double)1/eval->sample_rate;
00214 
00215         for (j = 0; j < eval->nb_channels; j++) {
00216             *((double *) samplesref->data[j] + i) =
00217                 av_expr_eval(eval->expr[j], eval->var_values, NULL);
00218         }
00219     }
00220 
00221     samplesref->pts = eval->pts;
00222     samplesref->pos = -1;
00223     samplesref->audio->sample_rate = eval->sample_rate;
00224     eval->pts += eval->nb_samples;
00225 
00226     avfilter_filter_samples(outlink, samplesref);
00227 
00228     return 0;
00229 }
00230 
00231 AVFilter avfilter_asrc_aevalsrc = {
00232     .name        = "aevalsrc",
00233     .description = NULL_IF_CONFIG_SMALL("Generate an audio signal generated by an expression."),
00234 
00235     .query_formats = query_formats,
00236     .init        = init,
00237     .uninit      = uninit,
00238     .priv_size   = sizeof(EvalContext),
00239 
00240     .inputs      = (const AVFilterPad[]) {{ .name = NULL}},
00241 
00242     .outputs     = (const AVFilterPad[]) {{ .name = "default",
00243                                       .type = AVMEDIA_TYPE_AUDIO,
00244                                       .config_props = config_props,
00245                                       .request_frame = request_frame, },
00246                                     { .name = NULL}},
00247 };