| @@ -34,13 +34,17 @@ typedef struct AudioBitScopeContext { · 33 unmodified lines |
| 34 | 34 | int w, h; |
| 35 | 35 | AVRational frame_rate; |
| 36 | 36 | char *colors; |
| 37 | + int mode; |
| 37 | 38 | |
| 38 | 39 | int nb_channels; |
| 39 | 40 | int nb_samples; |
| 40 | 41 | int depth; |
| 42 | + int current_vpos; |
| 41 | 43 | uint8_t *fg; |
| 42 | 44 | |
| 43 | 45 | uint64_t counter[64]; |
| 46 | + |
| 47 | + AVFrame *outpicref; |
| 44 | 48 | } AudioBitScopeContext; |
| 45 | 49 | |
| 46 | 50 | #define OFFSET(x) offsetof(AudioBitScopeContext, x) |
| @@ -52,6 +56,10 @@ static const AVOption abitscope_options[] = { · 5 unmodified lines |
| 52 | 56 | { "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="1024x256"}, 0, 0, FLAGS }, |
| 53 | 57 | { "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="1024x256"}, 0, 0, FLAGS }, |
| 54 | 58 | { "colors", "set channels colors", OFFSET(colors), AV_OPT_TYPE_STRING, {.str = "red|green|blue|yellow|orange|lime|pink|magenta|brown" }, 0, 0, FLAGS }, |
| 59 | + { "mode", "set output mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, FLAGS, "mode" }, |
| 60 | + { "m", "set output mode", OFFSET(mode), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, FLAGS, "mode" }, |
| 61 | + { "bars", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, "mode" }, |
| 62 | + { "trace", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "mode" }, |
| 55 | 63 | { NULL } |
| 56 | 64 | }; |
| 57 | 65 | |
| @@ -146,75 +154,99 @@ static void count_bits(AudioBitScopeContext *s, uint32_t sample, int max) · 88 unmodified lines |
| 146 | 154 | } |
| 147 | 155 | } |
| 148 | 156 | |
| 157 | + |
| 158 | +#define BARS(type, depth) \ |
| 159 | + for (int ch = 0; ch < inlink->channels; ch++) { \ |
| 160 | + const type *in = (const type *)insamples->extended_data[ch]; \ |
| 161 | + const int w = outpicref->width / inlink->channels; \ |
| 162 | + const int h = outpicref->height / depth; \ |
| 163 | + const uint32_t color = AV_RN32(&s->fg[4 * ch]); \ |
| 164 | + \ |
| 165 | + memset(s->counter, 0, sizeof(s->counter)); \ |
| 166 | + for (int i = 0; i < insamples->nb_samples; i++) \ |
| 167 | + count_bits(s, in[i], depth); \ |
| 168 | + \ |
| 169 | + for (int b = 0; b < depth; b++) { \ |
| 170 | + for (int j = 1; j < h - 1; j++) { \ |
| 171 | + uint8_t *dst = outpicref->data[0] + (b * h + j) * outpicref->linesize[0] + w * ch * 4; \ |
| 172 | + const int ww = (s->counter[depth - b - 1] / (float)insamples->nb_samples) * (w - 1); \ |
| 173 | + \ |
| 174 | + for (int i = 0; i < ww; i++) { \ |
| 175 | + AV_WN32(&dst[i * 4], color); \ |
| 176 | + } \ |
| 177 | + } \ |
| 178 | + } \ |
| 179 | + } |
| 180 | + |
| 181 | +#define TRACE(type, depth) \ |
| 182 | + for (int ch = 0; ch < inlink->channels; ch++) { \ |
| 183 | + const int w = outpicref->width / inlink->channels; \ |
| 184 | + const type *in = (const type *)insamples->extended_data[ch]; \ |
| 185 | + const int wb = w / depth; \ |
| 186 | + int wv; \ |
| 187 | + \ |
| 188 | + memset(s->counter, 0, sizeof(s->counter)); \ |
| 189 | + for (int i = 0; i < insamples->nb_samples; i++) \ |
| 190 | + count_bits(s, in[i], depth); \ |
| 191 | + \ |
| 192 | + for (int b = 0; b < depth; b++) { \ |
| 193 | + uint8_t colors[4]; \ |
| 194 | + uint32_t color; \ |
| 195 | + uint8_t *dst = outpicref->data[0] + w * ch * 4 + wb * b * 4 + \ |
| 196 | + s->current_vpos * outpicref->linesize[0]; \ |
| 197 | + wv = (s->counter[depth - b - 1] * 255) / insamples->nb_samples; \ |
| 198 | + colors[0] = (wv * s->fg[ch * 4 + 0] + 127) / 255; \ |
| 199 | + colors[1] = (wv * s->fg[ch * 4 + 1] + 127) / 255; \ |
| 200 | + colors[2] = (wv * s->fg[ch * 4 + 2] + 127) / 255; \ |
| 201 | + colors[3] = (wv * s->fg[ch * 4 + 3] + 127) / 255; \ |
| 202 | + color = AV_RN32(colors); \ |
| 203 | + \ |
| 204 | + for (int x = 0; x < wb; x++) \ |
| 205 | + AV_WN32(&dst[x * 4], color); \ |
| 206 | + } \ |
| 207 | + } |
| 208 | + |
| 149 | 209 | static int filter_frame(AVFilterLink *inlink, AVFrame *insamples) |
| 150 | 210 | { |
| 151 | 211 | AVFilterContext *ctx = inlink->dst; |
| 152 | 212 | AVFilterLink *outlink = ctx->outputs[0]; |
| 153 | 213 | AudioBitScopeContext *s = ctx->priv; |
| 154 | 214 | AVFrame *outpicref; |
| 155 | | − int ch, i, j, b; |
| 156 | 215 | |
| 157 | | − outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h); |
| 158 | | − if (!outpicref) { |
| 159 | | − av_frame_free(&insamples); |
| 160 | | − return AVERROR(ENOMEM); |
| 216 | + if (s->mode == 0 || !s->outpicref) { |
| 217 | + outpicref = ff_get_video_buffer(outlink, outlink->w, outlink->h); |
| 218 | + if (!outpicref) { |
| 219 | + av_frame_free(&insamples); |
| 220 | + return AVERROR(ENOMEM); |
| 221 | + } |
| 222 | + |
| 223 | + for (int i = 0; i < outlink->h; i++) |
| 224 | + memset(outpicref->data[0] + i * outpicref->linesize[0], 0, outlink->w * 4); |
| 225 | + if (!s->outpicref && s->mode == 1) |
| 226 | + s->outpicref = outpicref; |
| 161 | 227 | } |
| 162 | 228 | |
| 163 | | − for (i = 0; i < outlink->h; i++) |
| 164 | | − memset(outpicref->data[0] + i * outpicref->linesize[0], 0, outlink->w * 4); |
| 229 | + if (s->mode == 1) { |
| 230 | + outpicref = av_frame_clone(s->outpicref); |
| 231 | + if (!outpicref) |
| 232 | + return AVERROR(ENOMEM); |
| 233 | + } |
| 165 | 234 | |
| 166 | 235 | outpicref->pts = insamples->pts; |
| 167 | 236 | outpicref->sample_aspect_ratio = (AVRational){1,1}; |
| 168 | 237 | |
| 169 | 238 | switch (insamples->format) { |
| 170 | 239 | 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 | | − } |
| 240 | + if (s->mode == 0) { BARS(uint16_t, 16) } else { TRACE(uint16_t, 16) } |
| 192 | 241 | break; |
| 193 | 242 | 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 | | − } |
| 243 | + if (s->mode == 0) { BARS(uint32_t, 32) } else { TRACE(uint32_t, 32) } |
| 215 | 244 | break; |
| 216 | 245 | } |
| 217 | 246 | |
| 247 | + s->current_vpos++; |
| 248 | + if (s->current_vpos >= outlink->h) |
| 249 | + s->current_vpos = 0; |
| 218 | 250 | av_frame_free(&insamples); |
| 219 | 251 | |
| 220 | 252 | return ff_filter_frame(outlink, outpicref); |
| @@ -242,6 +274,13 @@ static int activate(AVFilterContext *ctx) · 21 unmodified lines |
| 242 | 274 | return FFERROR_NOT_READY; |
| 243 | 275 | } |
| 244 | 276 | |
| 277 | +static av_cold void uninit(AVFilterContext *ctx) |
| 278 | +{ |
| 279 | + AudioBitScopeContext *s = ctx->priv; |
| 280 | + |
| 281 | + av_frame_free(&s->outpicref); |
| 282 | +} |
| 283 | + |
| 245 | 284 | static const AVFilterPad inputs[] = { |
| 246 | 285 | { |
| 247 | 286 | .name = "default", |
| @@ -265,6 +304,7 @@ const AVFilter ff_avf_abitscope = { · 17 unmodified lines |
| 265 | 304 | FILTER_INPUTS(inputs), |
| 266 | 305 | FILTER_OUTPUTS(outputs), |
| 267 | 306 | FILTER_QUERY_FUNC(query_formats), |
| 307 | + .uninit = uninit, |
| 268 | 308 | .activate = activate, |
| 269 | 309 | .priv_class = &abitscope_class, |
| 270 | 310 | }; |