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     if (!args1) {
00099         av_log(ctx, AV_LOG_ERROR, "Argument is empty\n");
00100         ret = args ? AVERROR(ENOMEM) : AVERROR(EINVAL);
00101         goto end;
00102     }
00103 
00104     /* parse expressions */
00105     buf = args1;
00106     i = 0;
00107     while (expr = av_strtok(buf, ":", &bufptr)) {
00108         if (i >= 8) {
00109             av_log(ctx, AV_LOG_ERROR,
00110                    "More than 8 expressions provided, unsupported.\n");
00111             ret = AVERROR(EINVAL);
00112             return ret;
00113         }
00114         ret = av_expr_parse(&eval->expr[i], expr, var_names,
00115                             NULL, NULL, NULL, NULL, 0, ctx);
00116         if (ret < 0)
00117             goto end;
00118         i++;
00119         if (bufptr && *bufptr == ':') { /* found last expression */
00120             bufptr++;
00121             break;
00122         }
00123         buf = NULL;
00124     }
00125 
00126     /* guess channel layout from nb expressions/channels */
00127     eval->nb_channels = i;
00128     eval->chlayout = av_get_default_channel_layout(eval->nb_channels);
00129     if (!eval->chlayout) {
00130         av_log(ctx, AV_LOG_ERROR, "Invalid number of channels '%d' provided\n",
00131                eval->nb_channels);
00132         ret = AVERROR(EINVAL);
00133         goto end;
00134     }
00135 
00136     if (bufptr && (ret = av_set_options_string(eval, bufptr, "=", ":")) < 0)
00137         goto end;
00138 
00139     if ((ret = ff_parse_sample_rate(&eval->sample_rate, eval->sample_rate_str, ctx)))
00140         goto end;
00141 
00142     eval->duration = -1;
00143     if (eval->duration_str) {
00144         int64_t us = -1;
00145         if ((ret = av_parse_time(&us, eval->duration_str, 1)) < 0) {
00146             av_log(ctx, AV_LOG_ERROR, "Invalid duration: '%s'\n", eval->duration_str);
00147             goto end;
00148         }
00149         eval->duration = (double)us / 1000000;
00150     }
00151     eval->n = 0;
00152 
00153 end:
00154     av_free(args1);
00155     return ret;
00156 }
00157 
00158 static void uninit(AVFilterContext *ctx)
00159 {
00160     EvalContext *eval = ctx->priv;
00161     int i;
00162 
00163     for (i = 0; i < 8; i++) {
00164         av_expr_free(eval->expr[i]);
00165         eval->expr[i] = NULL;
00166     }
00167     av_freep(&eval->duration_str);
00168     av_freep(&eval->sample_rate_str);
00169 }
00170 
00171 static int config_props(AVFilterLink *outlink)
00172 {
00173     EvalContext *eval = outlink->src->priv;
00174     char buf[128];
00175 
00176     outlink->time_base = (AVRational){1, eval->sample_rate};
00177     outlink->sample_rate = eval->sample_rate;
00178 
00179     eval->var_values[VAR_S] = eval->sample_rate;
00180 
00181     av_get_channel_layout_string(buf, sizeof(buf), 0, eval->chlayout);
00182 
00183     av_log(outlink->src, AV_LOG_INFO,
00184            "sample_rate:%d chlayout:%s duration:%f\n",
00185            eval->sample_rate, buf, eval->duration);
00186 
00187     return 0;
00188 }
00189 
00190 static int query_formats(AVFilterContext *ctx)
00191 {
00192     EvalContext *eval = ctx->priv;
00193     enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_DBL, AV_SAMPLE_FMT_NONE };
00194     int64_t chlayouts[] = { eval->chlayout, -1 };
00195     int packing_fmts[] = { AVFILTER_PLANAR, -1 };
00196 
00197     avfilter_set_common_sample_formats (ctx, avfilter_make_format_list(sample_fmts));
00198     avfilter_set_common_channel_layouts(ctx, avfilter_make_format64_list(chlayouts));
00199     avfilter_set_common_packing_formats(ctx, avfilter_make_format_list(packing_fmts));
00200 
00201     return 0;
00202 }
00203 
00204 static int request_frame(AVFilterLink *outlink)
00205 {
00206     EvalContext *eval = outlink->src->priv;
00207     AVFilterBufferRef *samplesref;
00208     int i, j;
00209     double t = eval->var_values[VAR_N] * (double)1/eval->sample_rate;
00210 
00211     if (eval->duration >= 0 && t > eval->duration)
00212         return AVERROR_EOF;
00213 
00214     samplesref = avfilter_get_audio_buffer(outlink, AV_PERM_WRITE, eval->nb_samples);
00215 
00216     /* evaluate expression for each single sample and for each channel */
00217     for (i = 0; i < eval->nb_samples; i++, eval->n++) {
00218         eval->var_values[VAR_N] = eval->n;
00219         eval->var_values[VAR_T] = eval->var_values[VAR_N] * (double)1/eval->sample_rate;
00220 
00221         for (j = 0; j < eval->nb_channels; j++) {
00222             *((double *) samplesref->data[j] + i) =
00223                 av_expr_eval(eval->expr[j], eval->var_values, NULL);
00224         }
00225     }
00226 
00227     samplesref->pts = eval->pts;
00228     samplesref->pos = -1;
00229     samplesref->audio->sample_rate = eval->sample_rate;
00230     eval->pts += eval->nb_samples;
00231 
00232     avfilter_filter_samples(outlink, samplesref);
00233 
00234     return 0;
00235 }
00236 
00237 AVFilter avfilter_asrc_aevalsrc = {
00238     .name        = "aevalsrc",
00239     .description = NULL_IF_CONFIG_SMALL("Generate an audio signal generated by an expression."),
00240 
00241     .query_formats = query_formats,
00242     .init        = init,
00243     .uninit      = uninit,
00244     .priv_size   = sizeof(EvalContext),
00245 
00246     .inputs      = (const AVFilterPad[]) {{ .name = NULL}},
00247 
00248     .outputs     = (const AVFilterPad[]) {{ .name = "default",
00249                                       .type = AVMEDIA_TYPE_AUDIO,
00250                                       .config_props = config_props,
00251                                       .request_frame = request_frame, },
00252                                     { .name = NULL}},
00253 };