00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00026 #include "libavutil/audioconvert.h"
00027 #include "libavutil/opt.h"
00028 #include "libavutil/parseutils.h"
00029 #include "avfilter.h"
00030 #include "formats.h"
00031 #include "audio.h"
00032 #include "video.h"
00033 #include "internal.h"
00034
00035 typedef struct {
00036 const AVClass *class;
00037 int w, h;
00038 char *rate_str;
00039 AVRational rate;
00040 int buf_idx;
00041 AVFilterBufferRef *outpicref;
00042 int req_fullfilled;
00043 int n;
00044 int sample_count_mod;
00045 } ShowWavesContext;
00046
00047 #define OFFSET(x) offsetof(ShowWavesContext, x)
00048 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
00049
00050 static const AVOption showwaves_options[] = {
00051 { "rate", "set video rate", OFFSET(rate_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
00052 { "r", "set video rate", OFFSET(rate_str), AV_OPT_TYPE_STRING, {.str = NULL}, 0, 0, FLAGS },
00053 { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "600x240"}, 0, 0, FLAGS },
00054 { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str = "600x240"}, 0, 0, FLAGS },
00055 { "n", "set how many samples to show in the same point", OFFSET(n), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, FLAGS },
00056 { NULL },
00057 };
00058
00059 AVFILTER_DEFINE_CLASS(showwaves);
00060
00061 static av_cold int init(AVFilterContext *ctx, const char *args)
00062 {
00063 ShowWavesContext *showwaves = ctx->priv;
00064 int err;
00065
00066 showwaves->class = &showwaves_class;
00067 av_opt_set_defaults(showwaves);
00068 showwaves->buf_idx = 0;
00069
00070 if ((err = av_set_options_string(showwaves, args, "=", ":")) < 0)
00071 return err;
00072
00073 return 0;
00074 }
00075
00076 static av_cold void uninit(AVFilterContext *ctx)
00077 {
00078 ShowWavesContext *showwaves = ctx->priv;
00079
00080 av_freep(&showwaves->rate_str);
00081 avfilter_unref_bufferp(&showwaves->outpicref);
00082 }
00083
00084 static int query_formats(AVFilterContext *ctx)
00085 {
00086 AVFilterFormats *formats = NULL;
00087 AVFilterChannelLayouts *layouts = NULL;
00088 AVFilterLink *inlink = ctx->inputs[0];
00089 AVFilterLink *outlink = ctx->outputs[0];
00090 static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16, -1 };
00091 static const enum PixelFormat pix_fmts[] = { PIX_FMT_GRAY8, -1 };
00092
00093
00094 formats = ff_make_format_list(sample_fmts);
00095 if (!formats)
00096 return AVERROR(ENOMEM);
00097 ff_formats_ref(formats, &inlink->out_formats);
00098
00099 layouts = ff_all_channel_layouts();
00100 if (!layouts)
00101 return AVERROR(ENOMEM);
00102 ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts);
00103
00104 formats = ff_all_samplerates();
00105 if (!formats)
00106 return AVERROR(ENOMEM);
00107 ff_formats_ref(formats, &inlink->out_samplerates);
00108
00109
00110 formats = ff_make_format_list(pix_fmts);
00111 if (!formats)
00112 return AVERROR(ENOMEM);
00113 ff_formats_ref(formats, &outlink->in_formats);
00114
00115 return 0;
00116 }
00117
00118 static int config_output(AVFilterLink *outlink)
00119 {
00120 AVFilterContext *ctx = outlink->src;
00121 AVFilterLink *inlink = ctx->inputs[0];
00122 ShowWavesContext *showwaves = ctx->priv;
00123 int err;
00124
00125 if (showwaves->n && showwaves->rate_str) {
00126 av_log(ctx, AV_LOG_ERROR, "Options 'n' and 'rate' cannot be set at the same time\n");
00127 return AVERROR(EINVAL);
00128 }
00129
00130 if (!showwaves->n) {
00131 if (!showwaves->rate_str)
00132 showwaves->rate = (AVRational){25,1};
00133 else if ((err = av_parse_video_rate(&showwaves->rate, showwaves->rate_str)) < 0) {
00134 av_log(ctx, AV_LOG_ERROR, "Invalid frame rate: '%s'\n", showwaves->rate_str);
00135 return err;
00136 }
00137 showwaves->n = FFMAX(1, ((double)inlink->sample_rate / (showwaves->w * av_q2d(showwaves->rate))) + 0.5);
00138 }
00139
00140 outlink->w = showwaves->w;
00141 outlink->h = showwaves->h;
00142 outlink->sample_aspect_ratio = (AVRational){1,1};
00143
00144 outlink->frame_rate = av_div_q((AVRational){inlink->sample_rate,showwaves->n},
00145 (AVRational){showwaves->w,1});
00146
00147 av_log(ctx, AV_LOG_VERBOSE, "s:%dx%d r:%f n:%d\n",
00148 showwaves->w, showwaves->h, av_q2d(outlink->frame_rate), showwaves->n);
00149 return 0;
00150 }
00151
00152 inline static void push_frame(AVFilterLink *outlink)
00153 {
00154 ShowWavesContext *showwaves = outlink->src->priv;
00155
00156 ff_start_frame(outlink, showwaves->outpicref);
00157 ff_draw_slice(outlink, 0, outlink->h, 1);
00158 ff_end_frame(outlink);
00159 showwaves->req_fullfilled = 1;
00160 showwaves->outpicref = NULL;
00161 showwaves->buf_idx = 0;
00162 }
00163
00164 static int request_frame(AVFilterLink *outlink)
00165 {
00166 ShowWavesContext *showwaves = outlink->src->priv;
00167 AVFilterLink *inlink = outlink->src->inputs[0];
00168 int ret;
00169
00170 showwaves->req_fullfilled = 0;
00171 do {
00172 ret = ff_request_frame(inlink);
00173 } while (!showwaves->req_fullfilled && ret >= 0);
00174
00175 if (ret == AVERROR_EOF && showwaves->outpicref)
00176 push_frame(outlink);
00177 return ret;
00178 }
00179
00180 #define MAX_INT16 ((1<<15) -1)
00181
00182 static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples)
00183 {
00184 AVFilterContext *ctx = inlink->dst;
00185 AVFilterLink *outlink = ctx->outputs[0];
00186 ShowWavesContext *showwaves = ctx->priv;
00187 const int nb_samples = insamples->audio->nb_samples;
00188 AVFilterBufferRef *outpicref = showwaves->outpicref;
00189 int linesize = outpicref ? outpicref->linesize[0] : 0;
00190 int16_t *p = (int16_t *)insamples->data[0];
00191 int nb_channels = av_get_channel_layout_nb_channels(insamples->audio->channel_layout);
00192 int i, j, h;
00193 const int n = showwaves->n;
00194 const int x = 255 / (nb_channels * n);
00195
00196
00197 for (i = 0; i < nb_samples; i++) {
00198 if (showwaves->buf_idx == 0 && showwaves->sample_count_mod == 0) {
00199 showwaves->outpicref = outpicref =
00200 ff_get_video_buffer(outlink, AV_PERM_WRITE|AV_PERM_ALIGN,
00201 outlink->w, outlink->h);
00202 outpicref->video->w = outlink->w;
00203 outpicref->video->h = outlink->h;
00204 outpicref->pts = insamples->pts +
00205 av_rescale_q((p - (int16_t *)insamples->data[0]) / nb_channels,
00206 (AVRational){ 1, inlink->sample_rate },
00207 outlink->time_base);
00208 linesize = outpicref->linesize[0];
00209 memset(outpicref->data[0], 0, showwaves->h*linesize);
00210 }
00211 for (j = 0; j < nb_channels; j++) {
00212 h = showwaves->h/2 - av_rescale(*p++, showwaves->h/2, MAX_INT16);
00213 if (h >= 0 && h < outlink->h)
00214 *(outpicref->data[0] + showwaves->buf_idx + h * linesize) += x;
00215 }
00216 showwaves->sample_count_mod++;
00217 if (showwaves->sample_count_mod == n) {
00218 showwaves->sample_count_mod = 0;
00219 showwaves->buf_idx++;
00220 }
00221 if (showwaves->buf_idx == showwaves->w)
00222 push_frame(outlink);
00223 }
00224
00225 avfilter_unref_buffer(insamples);
00226 return 0;
00227 }
00228
00229 AVFilter avfilter_avf_showwaves = {
00230 .name = "showwaves",
00231 .description = NULL_IF_CONFIG_SMALL("Convert input audio to a video output."),
00232 .init = init,
00233 .uninit = uninit,
00234 .query_formats = query_formats,
00235 .priv_size = sizeof(ShowWavesContext),
00236
00237 .inputs = (const AVFilterPad[]) {
00238 {
00239 .name = "default",
00240 .type = AVMEDIA_TYPE_AUDIO,
00241 .filter_samples = filter_samples,
00242 .min_perms = AV_PERM_READ,
00243 },
00244 { .name = NULL }
00245 },
00246
00247 .outputs = (const AVFilterPad[]) {
00248 {
00249 .name = "default",
00250 .type = AVMEDIA_TYPE_VIDEO,
00251 .config_props = config_output,
00252 .request_frame = request_frame,
00253 },
00254 { .name = NULL }
00255 },
00256
00257 .priv_class = &showwaves_class,
00258 };