|
|
|
@ -96,8 +96,8 @@ typedef struct ShowSpectrumContext { |
|
|
|
|
float overlap; |
|
|
|
|
float gain; |
|
|
|
|
int hop_size; |
|
|
|
|
float *combine_buffer; ///< color combining buffer (3 * h items)
|
|
|
|
|
float **color_buffer; ///< color buffer (3 * h * ch items)
|
|
|
|
|
float *combine_buffer; ///< color combining buffer (4 * h items)
|
|
|
|
|
float **color_buffer; ///< color buffer (4 * h * ch items)
|
|
|
|
|
int64_t pts; |
|
|
|
|
int64_t old_pts; |
|
|
|
|
int64_t in_pts; |
|
|
|
@ -110,6 +110,8 @@ typedef struct ShowSpectrumContext { |
|
|
|
|
uint64_t samples; |
|
|
|
|
int (*plot_channel)(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs); |
|
|
|
|
|
|
|
|
|
float opacity_factor; |
|
|
|
|
|
|
|
|
|
AVFrame **frames; |
|
|
|
|
unsigned int nb_frames; |
|
|
|
|
unsigned int frames_size; |
|
|
|
@ -174,6 +176,7 @@ static const AVOption showspectrum_options[] = { |
|
|
|
|
{ "legend", "draw legend", OFFSET(legend), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, FLAGS }, |
|
|
|
|
{ "drange", "set dynamic range in dBFS", OFFSET(drange), AV_OPT_TYPE_FLOAT, {.dbl = 120}, 10, 200, FLAGS }, |
|
|
|
|
{ "limit", "set upper limit in dBFS", OFFSET(limit), AV_OPT_TYPE_FLOAT, {.dbl = 0}, -100, 100, FLAGS }, |
|
|
|
|
{ "opacity", "set opacity strength", OFFSET(opacity_factor), AV_OPT_TYPE_FLOAT, {.dbl = 1}, 0, 10, FLAGS }, |
|
|
|
|
{ NULL } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
@ -360,7 +363,7 @@ static int query_formats(AVFilterContext *ctx) |
|
|
|
|
AVFilterLink *inlink = ctx->inputs[0]; |
|
|
|
|
AVFilterLink *outlink = ctx->outputs[0]; |
|
|
|
|
static const enum AVSampleFormat sample_fmts[] = { AV_SAMPLE_FMT_FLTP, AV_SAMPLE_FMT_NONE }; |
|
|
|
|
static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_NONE }; |
|
|
|
|
static const enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_YUV444P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_YUVA444P, AV_PIX_FMT_NONE }; |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
/* set input audio formats */ |
|
|
|
@ -495,11 +498,10 @@ static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o) |
|
|
|
|
{ |
|
|
|
|
const uint8_t *font; |
|
|
|
|
int font_height; |
|
|
|
|
int i; |
|
|
|
|
|
|
|
|
|
font = avpriv_cga_font, font_height = 8; |
|
|
|
|
|
|
|
|
|
for (i = 0; txt[i]; i++) { |
|
|
|
|
for (int i = 0; txt[i]; i++) { |
|
|
|
|
int char_y, mask; |
|
|
|
|
|
|
|
|
|
if (o) { |
|
|
|
@ -523,6 +525,28 @@ static void drawtext(AVFrame *pic, int x, int y, const char *txt, int o) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (int i = 0; txt[i] && pic->data[3]; i++) { |
|
|
|
|
int char_y, mask; |
|
|
|
|
|
|
|
|
|
if (o) { |
|
|
|
|
for (char_y = font_height - 1; char_y >= 0; char_y--) { |
|
|
|
|
uint8_t *p = pic->data[3] + (y + i * 10) * pic->linesize[3] + x; |
|
|
|
|
for (mask = 0x80; mask; mask >>= 1) { |
|
|
|
|
for (int k = 0; k < 8; k++) |
|
|
|
|
p[k] = 255; |
|
|
|
|
p += pic->linesize[3]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
uint8_t *p = pic->data[3] + y*pic->linesize[3] + (x + i*8); |
|
|
|
|
for (char_y = 0; char_y < font_height; char_y++) { |
|
|
|
|
for (mask = 0x80; mask; mask >>= 1) |
|
|
|
|
*p++ = 255; |
|
|
|
|
p += pic->linesize[3] - 8; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void color_range(ShowSpectrumContext *s, int ch, |
|
|
|
@ -591,6 +615,8 @@ static void pick_color(ShowSpectrumContext *s, |
|
|
|
|
float yf, float uf, float vf, |
|
|
|
|
float a, float *out) |
|
|
|
|
{ |
|
|
|
|
const float af = s->opacity_factor * 255.f; |
|
|
|
|
|
|
|
|
|
if (s->color_mode > CHANNEL) { |
|
|
|
|
const int cm = s->color_mode; |
|
|
|
|
float y, u, v; |
|
|
|
@ -624,10 +650,12 @@ static void pick_color(ShowSpectrumContext *s, |
|
|
|
|
out[0] = y * yf; |
|
|
|
|
out[1] = u * uf; |
|
|
|
|
out[2] = v * vf; |
|
|
|
|
out[3] = a * af; |
|
|
|
|
} else { |
|
|
|
|
out[0] = a * yf; |
|
|
|
|
out[1] = a * uf; |
|
|
|
|
out[2] = a * vf; |
|
|
|
|
out[3] = a * af; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -907,23 +935,26 @@ static int draw_legend(AVFilterContext *ctx, uint64_t samples) |
|
|
|
|
int h = multi ? s->h / s->nb_display_channels : s->h; |
|
|
|
|
|
|
|
|
|
for (y = 0; y < h; y++) { |
|
|
|
|
float out[3] = { 0., 127.5, 127.5}; |
|
|
|
|
float out[4] = { 0., 127.5, 127.5, 0.f}; |
|
|
|
|
int chn; |
|
|
|
|
|
|
|
|
|
for (chn = 0; chn < (s->mode == SEPARATE ? 1 : s->nb_display_channels); chn++) { |
|
|
|
|
float yf, uf, vf; |
|
|
|
|
int channel = (multi) ? s->nb_display_channels - ch - 1 : chn; |
|
|
|
|
float lout[3]; |
|
|
|
|
float lout[4]; |
|
|
|
|
|
|
|
|
|
color_range(s, channel, &yf, &uf, &vf); |
|
|
|
|
pick_color(s, yf, uf, vf, y / (float)h, lout); |
|
|
|
|
out[0] += lout[0]; |
|
|
|
|
out[1] += lout[1]; |
|
|
|
|
out[2] += lout[2]; |
|
|
|
|
out[3] += lout[3]; |
|
|
|
|
} |
|
|
|
|
memset(s->outpicref->data[0]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[0] + s->w + s->start_x + 20, av_clip_uint8(out[0]), 10); |
|
|
|
|
memset(s->outpicref->data[1]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[1] + s->w + s->start_x + 20, av_clip_uint8(out[1]), 10); |
|
|
|
|
memset(s->outpicref->data[2]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[2] + s->w + s->start_x + 20, av_clip_uint8(out[2]), 10); |
|
|
|
|
if (s->outpicref->data[3]) |
|
|
|
|
memset(s->outpicref->data[3]+(s->start_y + h * (ch + 1) - y - 1) * s->outpicref->linesize[3] + s->w + s->start_x + 20, av_clip_uint8(out[3]), 10); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for (y = 0; ch == 0 && y < h + 5; y += 25) { |
|
|
|
@ -985,7 +1016,7 @@ static int plot_channel_lin(AVFilterContext *ctx, void *arg, int jobnr, int nb_j |
|
|
|
|
/* draw the channel */ |
|
|
|
|
for (y = 0; y < h; y++) { |
|
|
|
|
int row = (s->mode == COMBINED) ? y : ch * h + y; |
|
|
|
|
float *out = &s->color_buffer[ch][3 * row]; |
|
|
|
|
float *out = &s->color_buffer[ch][4 * row]; |
|
|
|
|
float a = get_value(ctx, ch, y); |
|
|
|
|
|
|
|
|
|
pick_color(s, yf, uf, vf, a, out); |
|
|
|
@ -1016,7 +1047,7 @@ static int plot_channel_log(AVFilterContext *ctx, void *arg, int jobnr, int nb_j |
|
|
|
|
a1 = get_value(ctx, ch, av_clip(pos+1, 0, h-1)); |
|
|
|
|
{ |
|
|
|
|
int row = (s->mode == COMBINED) ? yy : ch * h + yy; |
|
|
|
|
float *out = &s->color_buffer[ch][3 * row]; |
|
|
|
|
float *out = &s->color_buffer[ch][4 * row]; |
|
|
|
|
|
|
|
|
|
pick_color(s, yf, uf, vf, delta * a1 + (1.f - delta) * a0, out); |
|
|
|
|
} |
|
|
|
@ -1155,7 +1186,7 @@ static int config_output(AVFilterLink *outlink) |
|
|
|
|
if (!s->color_buffer) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
for (i = 0; i < s->nb_display_channels; i++) { |
|
|
|
|
s->color_buffer[i] = av_calloc(s->orientation == VERTICAL ? s->h * 3 : s->w * 3, sizeof(**s->color_buffer)); |
|
|
|
|
s->color_buffer[i] = av_calloc(s->orientation == VERTICAL ? s->h * 4 : s->w * 4, sizeof(**s->color_buffer)); |
|
|
|
|
if (!s->color_buffer[i]) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
} |
|
|
|
@ -1214,6 +1245,8 @@ static int config_output(AVFilterLink *outlink) |
|
|
|
|
memset(outpicref->data[0] + i * outpicref->linesize[0], 0, outlink->w); |
|
|
|
|
memset(outpicref->data[1] + i * outpicref->linesize[1], 128, outlink->w); |
|
|
|
|
memset(outpicref->data[2] + i * outpicref->linesize[2], 128, outlink->w); |
|
|
|
|
if (outpicref->data[3]) |
|
|
|
|
memset(outpicref->data[3] + i * outpicref->linesize[3], 0, outlink->w); |
|
|
|
|
} |
|
|
|
|
outpicref->color_range = AVCOL_RANGE_JPEG; |
|
|
|
|
|
|
|
|
@ -1251,11 +1284,11 @@ static int config_output(AVFilterLink *outlink) |
|
|
|
|
|
|
|
|
|
if (s->orientation == VERTICAL) { |
|
|
|
|
s->combine_buffer = |
|
|
|
|
av_realloc_f(s->combine_buffer, s->h * 3, |
|
|
|
|
av_realloc_f(s->combine_buffer, s->h * 4, |
|
|
|
|
sizeof(*s->combine_buffer)); |
|
|
|
|
} else { |
|
|
|
|
s->combine_buffer = |
|
|
|
|
av_realloc_f(s->combine_buffer, s->w * 3, |
|
|
|
|
av_realloc_f(s->combine_buffer, s->w * 4, |
|
|
|
|
sizeof(*s->combine_buffer)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1379,9 +1412,10 @@ static void clear_combine_buffer(ShowSpectrumContext *s, int size) |
|
|
|
|
int y; |
|
|
|
|
|
|
|
|
|
for (y = 0; y < size; y++) { |
|
|
|
|
s->combine_buffer[3 * y ] = 0; |
|
|
|
|
s->combine_buffer[3 * y + 1] = 127.5; |
|
|
|
|
s->combine_buffer[3 * y + 2] = 127.5; |
|
|
|
|
s->combine_buffer[4 * y ] = 0; |
|
|
|
|
s->combine_buffer[4 * y + 1] = 127.5; |
|
|
|
|
s->combine_buffer[4 * y + 2] = 127.5; |
|
|
|
|
s->combine_buffer[4 * y + 3] = 0; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -1392,6 +1426,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) |
|
|
|
|
ShowSpectrumContext *s = ctx->priv; |
|
|
|
|
AVFrame *outpicref = s->outpicref; |
|
|
|
|
int ret, plane, x, y, z = s->orientation == VERTICAL ? s->h : s->w; |
|
|
|
|
const int alpha = outpicref->data[3] != NULL; |
|
|
|
|
|
|
|
|
|
/* fill a new spectrum column */ |
|
|
|
|
/* initialize buffer for combining to black */ |
|
|
|
@ -1399,7 +1434,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) |
|
|
|
|
|
|
|
|
|
ff_filter_execute(ctx, s->plot_channel, NULL, NULL, s->nb_display_channels); |
|
|
|
|
|
|
|
|
|
for (y = 0; y < z * 3; y++) { |
|
|
|
|
for (y = 0; y < z * 4; y++) { |
|
|
|
|
for (x = 0; x < s->nb_display_channels; x++) { |
|
|
|
|
s->combine_buffer[y] += s->color_buffer[x][y]; |
|
|
|
|
} |
|
|
|
@ -1409,7 +1444,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) |
|
|
|
|
/* copy to output */ |
|
|
|
|
if (s->orientation == VERTICAL) { |
|
|
|
|
if (s->sliding == SCROLL) { |
|
|
|
|
for (plane = 0; plane < 3; plane++) { |
|
|
|
|
for (plane = 0; plane < 3 + alpha; plane++) { |
|
|
|
|
for (y = 0; y < s->h; y++) { |
|
|
|
|
uint8_t *p = outpicref->data[plane] + s->start_x + |
|
|
|
|
(y + s->start_y) * outpicref->linesize[plane]; |
|
|
|
@ -1418,7 +1453,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) |
|
|
|
|
} |
|
|
|
|
s->xpos = s->w - 1; |
|
|
|
|
} else if (s->sliding == RSCROLL) { |
|
|
|
|
for (plane = 0; plane < 3; plane++) { |
|
|
|
|
for (plane = 0; plane < 3 + alpha; plane++) { |
|
|
|
|
for (y = 0; y < s->h; y++) { |
|
|
|
|
uint8_t *p = outpicref->data[plane] + s->start_x + |
|
|
|
|
(y + s->start_y) * outpicref->linesize[plane]; |
|
|
|
@ -1432,13 +1467,22 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) |
|
|
|
|
(outlink->h - 1 - s->start_y) * outpicref->linesize[plane] + |
|
|
|
|
s->xpos; |
|
|
|
|
for (y = 0; y < s->h; y++) { |
|
|
|
|
*p = lrintf(av_clipf(s->combine_buffer[3 * y + plane], 0, 255)); |
|
|
|
|
*p = lrintf(av_clipf(s->combine_buffer[4 * y + plane], 0, 255)); |
|
|
|
|
p -= outpicref->linesize[plane]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (alpha) { |
|
|
|
|
uint8_t *p = outpicref->data[3] + s->start_x + |
|
|
|
|
(outlink->h - 1 - s->start_y) * outpicref->linesize[3] + |
|
|
|
|
s->xpos; |
|
|
|
|
for (y = 0; y < s->h; y++) { |
|
|
|
|
*p = lrintf(av_clipf(s->combine_buffer[4 * y + 3], 0, 255)); |
|
|
|
|
p -= outpicref->linesize[3]; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
if (s->sliding == SCROLL) { |
|
|
|
|
for (plane = 0; plane < 3; plane++) { |
|
|
|
|
for (plane = 0; plane < 3 + alpha; plane++) { |
|
|
|
|
for (y = 1; y < s->h; y++) { |
|
|
|
|
memmove(outpicref->data[plane] + (y-1 + s->start_y) * outpicref->linesize[plane] + s->start_x, |
|
|
|
|
outpicref->data[plane] + (y + s->start_y) * outpicref->linesize[plane] + s->start_x, |
|
|
|
@ -1447,7 +1491,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) |
|
|
|
|
} |
|
|
|
|
s->xpos = s->h - 1; |
|
|
|
|
} else if (s->sliding == RSCROLL) { |
|
|
|
|
for (plane = 0; plane < 3; plane++) { |
|
|
|
|
for (plane = 0; plane < 3 + alpha; plane++) { |
|
|
|
|
for (y = s->h - 1; y >= 1; y--) { |
|
|
|
|
memmove(outpicref->data[plane] + (y + s->start_y) * outpicref->linesize[plane] + s->start_x, |
|
|
|
|
outpicref->data[plane] + (y-1 + s->start_y) * outpicref->linesize[plane] + s->start_x, |
|
|
|
@ -1460,7 +1504,15 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples) |
|
|
|
|
uint8_t *p = outpicref->data[plane] + s->start_x + |
|
|
|
|
(s->xpos + s->start_y) * outpicref->linesize[plane]; |
|
|
|
|
for (x = 0; x < s->w; x++) { |
|
|
|
|
*p = lrintf(av_clipf(s->combine_buffer[3 * x + plane], 0, 255)); |
|
|
|
|
*p = lrintf(av_clipf(s->combine_buffer[4 * x + plane], 0, 255)); |
|
|
|
|
p++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (alpha) { |
|
|
|
|
uint8_t *p = outpicref->data[3] + s->start_x + |
|
|
|
|
(s->xpos + s->start_y) * outpicref->linesize[3]; |
|
|
|
|
for (x = 0; x < s->w; x++) { |
|
|
|
|
*p = lrintf(av_clipf(s->combine_buffer[4 * x + 3], 0, 255)); |
|
|
|
|
p++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -1576,12 +1628,16 @@ static int activate(AVFilterContext *ctx) |
|
|
|
|
memset(s->outpicref->data[0] + i * s->outpicref->linesize[0] + s->xpos, 0, outlink->w - s->xpos); |
|
|
|
|
memset(s->outpicref->data[1] + i * s->outpicref->linesize[1] + s->xpos, 128, outlink->w - s->xpos); |
|
|
|
|
memset(s->outpicref->data[2] + i * s->outpicref->linesize[2] + s->xpos, 128, outlink->w - s->xpos); |
|
|
|
|
if (s->outpicref->data[3]) |
|
|
|
|
memset(s->outpicref->data[3] + i * s->outpicref->linesize[3] + s->xpos, 0, outlink->w - s->xpos); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
for (int i = s->xpos; i < outlink->h; i++) { |
|
|
|
|
memset(s->outpicref->data[0] + i * s->outpicref->linesize[0], 0, outlink->w); |
|
|
|
|
memset(s->outpicref->data[1] + i * s->outpicref->linesize[1], 128, outlink->w); |
|
|
|
|
memset(s->outpicref->data[2] + i * s->outpicref->linesize[2], 128, outlink->w); |
|
|
|
|
if (s->outpicref->data[3]) |
|
|
|
|
memset(s->outpicref->data[3] + i * s->outpicref->linesize[3], 0, outlink->w); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
s->outpicref->pts = av_rescale_q(s->in_pts, inlink->time_base, outlink->time_base); |
|
|
|
@ -1687,6 +1743,7 @@ static const AVOption showspectrumpic_options[] = { |
|
|
|
|
{ "stop", "stop frequency", OFFSET(stop), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT32_MAX, FLAGS }, |
|
|
|
|
{ "drange", "set dynamic range in dBFS", OFFSET(drange), AV_OPT_TYPE_FLOAT, {.dbl = 120}, 10, 200, FLAGS }, |
|
|
|
|
{ "limit", "set upper limit in dBFS", OFFSET(limit), AV_OPT_TYPE_FLOAT, {.dbl = 0}, -100, 100, FLAGS }, |
|
|
|
|
{ "opacity", "set opacity strength", OFFSET(opacity_factor), AV_OPT_TYPE_FLOAT, {.dbl = 1}, 0, 10, FLAGS }, |
|
|
|
|
{ NULL } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|