X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=libavfilter%2Favf_showwaves.c;h=b3639f46a525e6eeee4cf0315537f547275b1708;hb=a04ad248a05e7b613abe09b3bb067f555108d794;hp=bb7f4ea87e0466abe6a3667860fd39b6d0cae768;hpb=0dda0f3bdb7e8a2d5bef7457375f72f38a100ccb;p=ffmpeg diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c index bb7f4ea87e0..b3639f46a52 100644 --- a/libavfilter/avf_showwaves.c +++ b/libavfilter/avf_showwaves.c @@ -29,6 +29,7 @@ #include "libavutil/opt.h" #include "libavutil/parseutils.h" #include "avfilter.h" +#include "filters.h" #include "formats.h" #include "audio.h" #include "video.h" @@ -56,6 +57,12 @@ enum ShowWavesDrawMode { DRAW_NB, }; +enum ShowWavesFilterMode { + FILTER_AVERAGE, + FILTER_PEAK, + FILTER_NB, +}; + struct frame_node { AVFrame *frame; struct frame_node *next; @@ -76,6 +83,7 @@ typedef struct ShowWavesContext { int scale; ///< ShowWavesScale int draw_mode; ///< ShowWavesDrawMode int split_channels; + int filter_mode; uint8_t *fg; int (*get_h)(int16_t sample, int height); @@ -153,20 +161,20 @@ static int query_formats(AVFilterContext *ctx) /* set input audio formats */ formats = ff_make_format_list(sample_fmts); - if ((ret = ff_formats_ref(formats, &inlink->out_formats)) < 0) + if ((ret = ff_formats_ref(formats, &inlink->outcfg.formats)) < 0) return ret; layouts = ff_all_channel_layouts(); - if ((ret = ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts)) < 0) + if ((ret = ff_channel_layouts_ref(layouts, &inlink->outcfg.channel_layouts)) < 0) return ret; formats = ff_all_samplerates(); - if ((ret = ff_formats_ref(formats, &inlink->out_samplerates)) < 0) + if ((ret = ff_formats_ref(formats, &inlink->outcfg.samplerates)) < 0) return ret; /* set output video format */ formats = ff_make_format_list(pix_fmts); - if ((ret = ff_formats_ref(formats, &outlink->in_formats)) < 0) + if ((ret = ff_formats_ref(formats, &outlink->incfg.formats)) < 0) return ret; return 0; @@ -416,7 +424,7 @@ static int config_output(AVFilterLink *outlink) showwaves->n = 1; if (!showwaves->n) - showwaves->n = FFMAX(1, ((double)inlink->sample_rate / (showwaves->w * av_q2d(showwaves->rate))) + 0.5); + showwaves->n = FFMAX(1, av_rescale_q(inlink->sample_rate, av_make_q(1, showwaves->w), showwaves->rate)); showwaves->buf_idx = 0; if (!(showwaves->buf_idy = av_mallocz_array(nb_channels, sizeof(*showwaves->buf_idy)))) { @@ -559,7 +567,9 @@ static int push_single_pic(AVFilterLink *outlink) AVFilterContext *ctx = outlink->src; AVFilterLink *inlink = ctx->inputs[0]; ShowWavesContext *showwaves = ctx->priv; - int64_t n = 0, max_samples = showwaves->total_samples / outlink->w; + int64_t n = 0, column_max_samples = showwaves->total_samples / outlink->w; + int64_t remaining_samples = showwaves->total_samples - (column_max_samples * outlink->w); + int64_t last_column_samples = column_max_samples + remaining_samples; AVFrame *out = showwaves->outpicref; struct frame_node *node; const int nb_channels = inlink->channels; @@ -569,12 +579,12 @@ static int push_single_pic(AVFilterLink *outlink) int col = 0; int64_t *sum = showwaves->sum; - if (max_samples == 0) { + if (column_max_samples == 0) { av_log(ctx, AV_LOG_ERROR, "Too few samples\n"); return AVERROR(EINVAL); } - av_log(ctx, AV_LOG_DEBUG, "Create frame averaging %"PRId64" samples per column\n", max_samples); + av_log(ctx, AV_LOG_DEBUG, "Create frame averaging %"PRId64" samples per column\n", column_max_samples); memset(sum, 0, nb_channels); @@ -584,13 +594,24 @@ static int push_single_pic(AVFilterLink *outlink) const int16_t *p = (const int16_t *)frame->data[0]; for (i = 0; i < frame->nb_samples; i++) { + int64_t max_samples = col == outlink->w - 1 ? last_column_samples: column_max_samples; int ch; - for (ch = 0; ch < nb_channels; ch++) - sum[ch] += abs(p[ch + i*nb_channels]) << 1; - if (n++ == max_samples) { + switch (showwaves->filter_mode) { + case FILTER_AVERAGE: + for (ch = 0; ch < nb_channels; ch++) + sum[ch] += abs(p[ch + i*nb_channels]) << 1; + break; + case FILTER_PEAK: + for (ch = 0; ch < nb_channels; ch++) + sum[ch] = FFMAX(sum[ch], abs(p[ch + i*nb_channels])); + break; + } + + n++; + if (n == max_samples) { for (ch = 0; ch < nb_channels; ch++) { - int16_t sample = sum[ch] / max_samples; + int16_t sample = sum[ch] / (showwaves->filter_mode == FILTER_AVERAGE ? max_samples : 1); uint8_t *buf = out->data[0] + col * pixstep; int h; @@ -702,7 +723,8 @@ static int showwaves_filter_frame(AVFilterLink *inlink, AVFrame *insamples) showwaves->sample_count_mod = 0; showwaves->buf_idx++; } - if (showwaves->buf_idx == showwaves->w) + if (showwaves->buf_idx == showwaves->w || + (ff_outlink_get_status(inlink) && i == nb_samples - 1)) if ((ret = push_frame(outlink)) < 0) break; outpicref = showwaves->outpicref; @@ -713,11 +735,33 @@ end: return ret; } +static int activate(AVFilterContext *ctx) +{ + AVFilterLink *inlink = ctx->inputs[0]; + AVFilterLink *outlink = ctx->outputs[0]; + ShowWavesContext *showwaves = ctx->priv; + AVFrame *in; + const int nb_samples = showwaves->n * outlink->w; + int ret; + + FF_FILTER_FORWARD_STATUS_BACK(outlink, inlink); + + ret = ff_inlink_consume_samples(inlink, nb_samples, nb_samples, &in); + if (ret < 0) + return ret; + if (ret > 0) + return showwaves_filter_frame(inlink, in); + + FF_FILTER_FORWARD_STATUS(inlink, outlink); + FF_FILTER_FORWARD_WANTED(outlink, inlink); + + return FFERROR_NOT_READY; +} + static const AVFilterPad showwaves_inputs[] = { { .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .filter_frame = showwaves_filter_frame, }, { NULL } }; @@ -727,12 +771,11 @@ static const AVFilterPad showwaves_outputs[] = { .name = "default", .type = AVMEDIA_TYPE_VIDEO, .config_props = config_output, - .request_frame = request_frame, }, { NULL } }; -AVFilter ff_avf_showwaves = { +const AVFilter ff_avf_showwaves = { .name = "showwaves", .description = NULL_IF_CONFIG_SMALL("Convert input audio to a video output."), .init = init, @@ -740,6 +783,7 @@ AVFilter ff_avf_showwaves = { .query_formats = query_formats, .priv_size = sizeof(ShowWavesContext), .inputs = showwaves_inputs, + .activate = activate, .outputs = showwaves_outputs, .priv_class = &showwaves_class, }; @@ -761,6 +805,12 @@ static const AVOption showwavespic_options[] = { { "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=SCALE_LOG}, .flags=FLAGS, .unit="scale"}, { "sqrt", "square root", 0, AV_OPT_TYPE_CONST, {.i64=SCALE_SQRT}, .flags=FLAGS, .unit="scale"}, { "cbrt", "cubic root", 0, AV_OPT_TYPE_CONST, {.i64=SCALE_CBRT}, .flags=FLAGS, .unit="scale"}, + { "draw", "set draw mode", OFFSET(draw_mode), AV_OPT_TYPE_INT, {.i64 = DRAW_SCALE}, 0, DRAW_NB-1, FLAGS, .unit="draw" }, + { "scale", "scale pixel values for each drawn sample", 0, AV_OPT_TYPE_CONST, {.i64=DRAW_SCALE}, .flags=FLAGS, .unit="draw"}, + { "full", "draw every pixel for sample directly", 0, AV_OPT_TYPE_CONST, {.i64=DRAW_FULL}, .flags=FLAGS, .unit="draw"}, + { "filter", "set filter mode", OFFSET(filter_mode), AV_OPT_TYPE_INT, {.i64 = FILTER_AVERAGE}, 0, FILTER_NB-1, FLAGS, .unit="filter" }, + { "average", "use average samples", 0, AV_OPT_TYPE_CONST, {.i64=FILTER_AVERAGE}, .flags=FLAGS, .unit="filter"}, + { "peak", "use peak samples", 0, AV_OPT_TYPE_CONST, {.i64=FILTER_PEAK}, .flags=FLAGS, .unit="filter"}, { NULL } }; @@ -840,7 +890,7 @@ static const AVFilterPad showwavespic_outputs[] = { { NULL } }; -AVFilter ff_avf_showwavespic = { +const AVFilter ff_avf_showwavespic = { .name = "showwavespic", .description = NULL_IF_CONFIG_SMALL("Convert input audio to a video output single picture."), .init = init,