Signed-off-by: Paul B Mahol <one...@gmail.com> --- libavfilter/Makefile | 1 + libavfilter/allfilters.c | 1 + libavfilter/avf_ahistogram.c | 235 +++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 237 insertions(+) create mode 100644 libavfilter/avf_ahistogram.c
diff --git a/libavfilter/Makefile b/libavfilter/Makefile index e334016..931ced6 100644 --- a/libavfilter/Makefile +++ b/libavfilter/Makefile @@ -280,6 +280,7 @@ OBJS-$(CONFIG_NULLSINK_FILTER) += vsink_nullsink.o # multimedia filters OBJS-$(CONFIG_ADRAWGRAPH_FILTER) += f_drawgraph.o +OBJS-$(CONFIG_AHISTOGRAM_FILTER) += avf_ahistogram.o OBJS-$(CONFIG_APHASEMETER_FILTER) += avf_aphasemeter.o OBJS-$(CONFIG_AVECTORSCOPE_FILTER) += avf_avectorscope.o OBJS-$(CONFIG_CONCAT_FILTER) += avf_concat.o diff --git a/libavfilter/allfilters.c b/libavfilter/allfilters.c index a039a39..0f96c3e 100644 --- a/libavfilter/allfilters.c +++ b/libavfilter/allfilters.c @@ -300,6 +300,7 @@ void avfilter_register_all(void) /* multimedia filters */ REGISTER_FILTER(ADRAWGRAPH, adrawgraph, avf); + REGISTER_FILTER(AHISTOGRAM, ahistogram, avf); REGISTER_FILTER(APHASEMETER, aphasemeter, avf); REGISTER_FILTER(AVECTORSCOPE, avectorscope, avf); REGISTER_FILTER(CONCAT, concat, avf); diff --git a/libavfilter/avf_ahistogram.c b/libavfilter/avf_ahistogram.c new file mode 100644 index 0000000..46862c7 --- /dev/null +++ b/libavfilter/avf_ahistogram.c @@ -0,0 +1,235 @@ +/* + * Copyright (c) 2015 Paul B Mahol + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "libavutil/avassert.h" +#include "libavutil/opt.h" +#include "libavutil/parseutils.h" +#include "avfilter.h" +#include "formats.h" +#include "audio.h" +#include "video.h" +#include "internal.h" + +enum DisplayScale { LINEAR, SQRT, CBRT, LOG, NB_SCALES }; +enum AmplitudeScale { ALINEAR, ALOG, NB_ASCALES }; + +typedef struct AudioHistogramContext { + const AVClass *class; + AVFrame *out; + int w, h; + AVRational frame_rate; + uint64_t *histogram; + int ascale; + int scale; +} AudioHistogramContext; + +#define OFFSET(x) offsetof(AudioHistogramContext, x) +#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM + +static const AVOption ahistogram_options[] = { + { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, 0, FLAGS }, + { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, 0, FLAGS }, + { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="hd720"}, 0, 0, FLAGS }, + { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="hd720"}, 0, 0, FLAGS }, + { "scale", "set display scale", OFFSET(scale), AV_OPT_TYPE_INT, {.i64=LINEAR}, LINEAR, NB_SCALES-1, FLAGS, "scale" }, + { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=LOG}, 0, 0, FLAGS, "scale" }, + { "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SQRT}, 0, 0, FLAGS, "scale" }, + { "cbrt", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64=CBRT}, 0, 0, FLAGS, "scale" }, + { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=LINEAR}, 0, 0, FLAGS, "scale" }, + { "ascale", "set amplitude scale", OFFSET(ascale), AV_OPT_TYPE_INT, {.i64=LINEAR}, LINEAR, NB_ASCALES-1, FLAGS, "ascale" }, + { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=ALOG}, 0, 0, FLAGS, "ascale" }, + { "lin", "linear", 0, AV_OPT_TYPE_CONST, {.i64=ALINEAR}, 0, 0, FLAGS, "ascale" }, + { NULL } +}; + +AVFILTER_DEFINE_CLASS(ahistogram); + +static int query_formats(AVFilterContext *ctx) +{ + AVFilterFormats *formats = NULL; + AVFilterChannelLayouts *layouts = NULL; + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_NONE }; + static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE }; + int ret = AVERROR(EINVAL); + + formats = ff_make_format_list(sample_fmts); + if ((ret = ff_formats_ref (formats, &inlink->out_formats )) < 0 || + (layouts = ff_all_channel_counts()) == NULL || + (ret = ff_channel_layouts_ref (layouts, &inlink->out_channel_layouts)) < 0) + return ret; + + formats = ff_all_samplerates(); + if ((ret = ff_formats_ref(formats, &inlink->out_samplerates)) < 0) + return ret; + + formats = ff_make_format_list(pix_fmts); + if ((ret = ff_formats_ref(formats, &outlink->in_formats)) < 0) + return ret; + + return 0; +} + +static int config_input(AVFilterLink *inlink) +{ + AVFilterContext *ctx = inlink->dst; + AudioHistogramContext *s = ctx->priv; + int nb_samples; + + nb_samples = FFMAX(1024, ((double)inlink->sample_rate / av_q2d(s->frame_rate)) + 0.5); + inlink->partial_buf_size = + inlink->min_samples = + inlink->max_samples = nb_samples; + + s->histogram = av_malloc_array(s->w, sizeof(*s->histogram)); + if (!s->histogram) + return AVERROR(ENOMEM); + + return 0; +} + +static int config_output(AVFilterLink *outlink) +{ + AudioHistogramContext *s = outlink->src->priv; + + outlink->w = s->w; + outlink->h = s->h; + outlink->sample_aspect_ratio = (AVRational){1,1}; + outlink->frame_rate = s->frame_rate; + + return 0; +} + +static int filter_frame(AVFilterLink *inlink, AVFrame *in) +{ + AVFilterContext *ctx = inlink->dst; + AVFilterLink *outlink = ctx->outputs[0]; + AudioHistogramContext *s = ctx->priv; + const float *src = (const float *)in->data[0]; + const int w = s->w; + int y, n, bin; + uint64_t max = 0; + uint8_t *dst; + + if (!s->out || s->out->width != outlink->w || + s->out->height != outlink->h) { + av_frame_free(&s->out); + s->out = ff_get_video_buffer(outlink, outlink->w, outlink->h); + if (!s->out) { + av_frame_free(&in); + return AVERROR(ENOMEM); + } + } + memset(s->histogram, 0, sizeof(*s->histogram) * w); + for (n = 0; n < outlink->h; n++) + memset(s->out->data[0] + n * s->out->linesize[0], 0, outlink->w * 4); + s->out->pts = in->pts; + + switch (s->ascale) { + case ALINEAR: + for (n = 0; n < in->nb_samples * in->channels; n++) { + bin = lrint(av_clipf(fabsf(src[n]), 0, 1) * (w - 1)); + + s->histogram[bin]++; + } + break; + case ALOG: + for (n = 0; n < in->nb_samples * in->channels; n++) { + bin = lrint(av_clipf(1 + log10(fabsf(src[n])) / 6, 0, 1) * (w - 1)); + + s->histogram[bin]++; + } + break; + } + + av_frame_free(&in); + + for (n = 0; n < w; n++) { + max = FFMAX(s->histogram[n], max); + } + + for (n = 0; n < w; n++) { + int h; + + switch (s->scale) { + case LINEAR: + h = (s->histogram[n] / (double)max) * (s->h - 1); + break; + case SQRT: + h = (sqrt(s->histogram[n]) / sqrt(max)) * (s->h - 1); + break; + case CBRT: + h = (cbrt(s->histogram[n]) / cbrt(max)) * (s->h - 1); + break; + case LOG: + h = (log2(s->histogram[n] + 1) / log2(max + 1)) * (s->h - 1); + break; + } + + for (y = s->h - h; y < s->h; y++) { + dst = s->out->data[0] + y * s->out->linesize[0] + n * 4; + dst[0] = 255; + dst[1] = 255; + dst[2] = 255; + dst[3] = 255; + } + } + + return ff_filter_frame(outlink, av_frame_clone(s->out)); +} + +static av_cold void uninit(AVFilterContext *ctx) +{ + AudioHistogramContext *s = ctx->priv; + + av_frame_free(&s->out); + av_freep(&s->histogram); +} + +static const AVFilterPad audiovectorscope_inputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_AUDIO, + .config_props = config_input, + .filter_frame = filter_frame, + }, + { NULL } +}; + +static const AVFilterPad audiovectorscope_outputs[] = { + { + .name = "default", + .type = AVMEDIA_TYPE_VIDEO, + .config_props = config_output, + }, + { NULL } +}; + +AVFilter ff_avf_ahistogram = { + .name = "ahistogram", + .description = NULL_IF_CONFIG_SMALL("Convert input audio to histogram video output."), + .uninit = uninit, + .query_formats = query_formats, + .priv_size = sizeof(AudioHistogramContext), + .inputs = audiovectorscope_inputs, + .outputs = audiovectorscope_outputs, + .priv_class = &ahistogram_class, +}; -- 1.9.1 _______________________________________________ ffmpeg-devel mailing list ffmpeg-devel@ffmpeg.org http://ffmpeg.org/mailman/listinfo/ffmpeg-devel