summaryrefslogtreecommitdiff
path: root/libavfilter/avf_abitscope.c (plain)
blob: 0f3e3594c1f315fd0751b149958e912cdcee33ee
1/*
2 * Copyright (c) 2016 Paul B Mahol
3 *
4 * This file is part of FFmpeg.
5 *
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21#include "libavutil/avassert.h"
22#include "libavutil/avstring.h"
23#include "libavutil/intreadwrite.h"
24#include "libavutil/opt.h"
25#include "libavutil/parseutils.h"
26#include "avfilter.h"
27#include "formats.h"
28#include "audio.h"
29#include "video.h"
30#include "internal.h"
31
32typedef struct AudioBitScopeContext {
33 const AVClass *class;
34 int w, h;
35 AVRational frame_rate;
36 char *colors;
37
38 int nb_channels;
39 int depth;
40 uint8_t *fg;
41
42 uint64_t counter[64];
43} AudioBitScopeContext;
44
45#define OFFSET(x) offsetof(AudioBitScopeContext, x)
46#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
47
48static const AVOption abitscope_options[] = {
49 { "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, INT_MAX, FLAGS },
50 { "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, INT_MAX, FLAGS },
51 { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="1024x256"}, 0, 0, FLAGS },
52 { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="1024x256"}, 0, 0, FLAGS },
53 { "colors", "set channels colors", OFFSET(colors), AV_OPT_TYPE_STRING, {.str = "red|green|blue|yellow|orange|lime|pink|magenta|brown" }, 0, 0, FLAGS },
54 { NULL }
55};
56
57AVFILTER_DEFINE_CLASS(abitscope);
58
59static int query_formats(AVFilterContext *ctx)
60{
61 AVFilterFormats *formats = NULL;
62 AVFilterChannelLayouts *layouts;
63 AVFilterLink *inlink = ctx->inputs[0];
64 AVFilterLink *outlink = ctx->outputs[0];
65 static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_S16P, AV_SAMPLE_FMT_S32P, AV_SAMPLE_FMT_NONE };
66 static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_RGBA, AV_PIX_FMT_NONE };
67 int ret;
68
69 formats = ff_make_format_list(sample_fmts);
70 if ((ret = ff_formats_ref(formats, &inlink->out_formats)) < 0)
71 return ret;
72
73 layouts = ff_all_channel_counts();
74 if (!layouts)
75 return AVERROR(ENOMEM);
76 if ((ret = ff_channel_layouts_ref(layouts, &inlink->out_channel_layouts)) < 0)
77 return ret;
78
79 formats = ff_all_samplerates();
80 if ((ret = ff_formats_ref(formats, &inlink->out_samplerates)) < 0)
81 return ret;
82
83 formats = ff_make_format_list(pix_fmts);
84 if ((ret = ff_formats_ref(formats, &outlink->in_formats)) < 0)
85 return ret;
86
87 return 0;
88}
89
90static int config_input(AVFilterLink *inlink)
91{
92 AVFilterContext *ctx = inlink->dst;
93 AudioBitScopeContext *s = ctx->priv;
94 int ch, nb_samples;
95 char *colors, *saveptr = NULL;
96
97 nb_samples = FFMAX(1024, ((double)inlink->sample_rate / av_q2d(s->frame_rate)) + 0.5);
98 inlink->partial_buf_size =
99 inlink->min_samples =
100 inlink->max_samples = nb_samples;
101 s->nb_channels = inlink->channels;
102 s->depth = inlink->format == AV_SAMPLE_FMT_S16P ? 16 : 32;
103
104 s->fg = av_malloc_array(s->nb_channels, 4 * sizeof(*s->fg));
105 if (!s->fg)
106 return AVERROR(ENOMEM);
107
108 colors = av_strdup(s->colors);
109 if (!colors)
110 return AVERROR(ENOMEM);
111
112 for (ch = 0; ch < s->nb_channels; ch++) {
113 uint8_t fg[4] = { 0xff, 0xff, 0xff, 0xff };
114 char *color;
115
116 color = av_strtok(ch == 0 ? colors : NULL, " |", &saveptr);
117 if (color)
118 av_parse_color(fg, color, -1, ctx);
119 s->fg[4 * ch + 0] = fg[0];
120 s->fg[4 * ch + 1] = fg[1];
121 s->fg[4 * ch + 2] = fg[2];
122 s->fg[4 * ch + 3] = fg[3];
123 }
124 av_free(colors);
125
126 return 0;
127}
128
129static int config_output(AVFilterLink *outlink)
130{
131 AudioBitScopeContext *s = outlink->src->priv;
132
133 outlink->w = s->w;
134 outlink->h = s->h;
135 outlink->sample_aspect_ratio = (AVRational){1,1};
136 outlink->frame_rate = s->frame_rate;
137
138 return 0;
139}
140
141static void count_bits(AudioBitScopeContext *s, uint32_t sample, int max)
142{
143 int i;
144
145 for (i = 0; i < max; i++) {
146 if (sample & (1 << i))
147 s->counter[i]++;
148 }
149}
150
151static int filter_frame(AVFilterLink *inlink, AVFrame *insamples)
152{
153 AVFilterContext *ctx = inlink->dst;
154 AVFilterLink *outlink = ctx->outputs[0];
155 AudioBitScopeContext *s = ctx->priv;
156 AVFrame *outpicref;
157 int ch, i, j, b;
158
159 outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h);
160 if (!outpicref) {
161 av_frame_free(&insamples);
162 return AVERROR(ENOMEM);
163 }
164
165 for (i = 0; i < outlink->h; i++)
166 memset(outpicref->data[0] + i * outpicref->linesize[0], 0, outlink->w * 4);
167
168 outpicref->pts = insamples->pts;
169 switch (insamples->format) {
170 case AV_SAMPLE_FMT_S16P:
171 for (ch = 0; ch < inlink->channels; ch++) {
172 uint16_t *in = (uint16_t *)insamples->extended_data[ch];
173 int w = outpicref->width / inlink->channels;
174 int h = outpicref->height / 16;
175 uint32_t color = AV_RN32(&s->fg[4 * ch]);
176
177 memset(s->counter, 0, sizeof(s->counter));
178 for (i = 0; i < insamples->nb_samples; i++)
179 count_bits(s, in[i], 16);
180
181 for (b = 0; b < 16; b++) {
182 for (j = 1; j < h - 1; j++) {
183 uint8_t *dst = outpicref->data[0] + (b * h + j) * outpicref->linesize[0] + w * ch * 4;
184 int ww = (s->counter[16 - b - 1] / (float)insamples->nb_samples) * (w - 1);
185
186 for (i = 0; i < ww; i++) {
187 AV_WN32(&dst[i * 4], color);
188 }
189 }
190 }
191 }
192 break;
193 case AV_SAMPLE_FMT_S32P:
194 for (ch = 0; ch < inlink->channels; ch++) {
195 uint32_t *in = (uint32_t *)insamples->extended_data[ch];
196 int w = outpicref->width / inlink->channels;
197 int h = outpicref->height / 32;
198 uint32_t color = AV_RN32(&s->fg[4 * ch]);
199
200 memset(s->counter, 0, sizeof(s->counter));
201 for (i = 0; i < insamples->nb_samples; i++)
202 count_bits(s, in[i], 32);
203
204 for (b = 0; b < 32; b++) {
205 for (j = 1; j < h - 1; j++) {
206 uint8_t *dst = outpicref->data[0] + (b * h + j) * outpicref->linesize[0] + w * ch * 4;
207 int ww = (s->counter[32 - b - 1] / (float)insamples->nb_samples) * (w - 1);
208
209 for (i = 0; i < ww; i++) {
210 AV_WN32(&dst[i * 4], color);
211 }
212 }
213 }
214 }
215 break;
216 }
217
218 av_frame_free(&insamples);
219
220 return ff_filter_frame(outlink, outpicref);
221}
222
223static const AVFilterPad inputs[] = {
224 {
225 .name = "default",
226 .type = AVMEDIA_TYPE_AUDIO,
227 .config_props = config_input,
228 .filter_frame = filter_frame,
229 },
230 { NULL }
231};
232
233static const AVFilterPad outputs[] = {
234 {
235 .name = "default",
236 .type = AVMEDIA_TYPE_VIDEO,
237 .config_props = config_output,
238 },
239 { NULL }
240};
241
242AVFilter ff_avf_abitscope = {
243 .name = "abitscope",
244 .description = NULL_IF_CONFIG_SMALL("Convert input audio to audio bit scope video output."),
245 .query_formats = query_formats,
246 .priv_size = sizeof(AudioBitScopeContext),
247 .inputs = inputs,
248 .outputs = outputs,
249 .priv_class = &abitscope_class,
250};
251