You've already forked FFmpeg
mirror of
https://github.com/FFmpeg/FFmpeg.git
synced 2025-08-15 14:13:16 +02:00
avfilter/avf_showwaves: add draw mode which controls how single sample is drawn
Signed-off-by: Paul B Mahol <onemda@gmail.com>
This commit is contained in:
@@ -20033,6 +20033,20 @@ Cubic root.
|
|||||||
@end table
|
@end table
|
||||||
|
|
||||||
Default is linear.
|
Default is linear.
|
||||||
|
|
||||||
|
@item draw
|
||||||
|
Set the draw mode. This is mostly useful to set for high @var{n}.
|
||||||
|
|
||||||
|
Available values are:
|
||||||
|
@table @samp
|
||||||
|
@item scale
|
||||||
|
Scale pixel values for each drawn sample.
|
||||||
|
|
||||||
|
@item full
|
||||||
|
Draw every sample directly.
|
||||||
|
@end table
|
||||||
|
|
||||||
|
Default vlaue is @code{scale}.
|
||||||
@end table
|
@end table
|
||||||
|
|
||||||
@subsection Examples
|
@subsection Examples
|
||||||
|
@@ -50,6 +50,12 @@ enum ShowWavesScale {
|
|||||||
SCALE_NB,
|
SCALE_NB,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum ShowWavesDrawMode {
|
||||||
|
DRAW_SCALE,
|
||||||
|
DRAW_FULL,
|
||||||
|
DRAW_NB,
|
||||||
|
};
|
||||||
|
|
||||||
struct frame_node {
|
struct frame_node {
|
||||||
AVFrame *frame;
|
AVFrame *frame;
|
||||||
struct frame_node *next;
|
struct frame_node *next;
|
||||||
@@ -68,6 +74,7 @@ typedef struct ShowWavesContext {
|
|||||||
int sample_count_mod;
|
int sample_count_mod;
|
||||||
int mode; ///< ShowWavesMode
|
int mode; ///< ShowWavesMode
|
||||||
int scale; ///< ShowWavesScale
|
int scale; ///< ShowWavesScale
|
||||||
|
int draw_mode; ///< ShowWavesDrawMode
|
||||||
int split_channels;
|
int split_channels;
|
||||||
uint8_t *fg;
|
uint8_t *fg;
|
||||||
|
|
||||||
@@ -104,6 +111,9 @@ static const AVOption showwaves_options[] = {
|
|||||||
{ "log", "logarithmic", 0, AV_OPT_TYPE_CONST, {.i64=SCALE_LOG}, .flags=FLAGS, .unit="scale"},
|
{ "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"},
|
{ "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"},
|
{ "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"},
|
||||||
{ NULL }
|
{ NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -202,7 +212,7 @@ static int get_cbrt_h2(int16_t sample, int height)
|
|||||||
return cbrt(FFABS(sample)) * height / cbrt(INT16_MAX);
|
return cbrt(FFABS(sample)) * height / cbrt(INT16_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_sample_point_rgba(uint8_t *buf, int height, int linesize,
|
static void draw_sample_point_rgba_scale(uint8_t *buf, int height, int linesize,
|
||||||
int16_t *prev_y,
|
int16_t *prev_y,
|
||||||
const uint8_t color[4], int h)
|
const uint8_t color[4], int h)
|
||||||
{
|
{
|
||||||
@@ -214,7 +224,19 @@ static void draw_sample_point_rgba(uint8_t *buf, int height, int linesize,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_sample_line_rgba(uint8_t *buf, int height, int linesize,
|
static void draw_sample_point_rgba_full(uint8_t *buf, int height, int linesize,
|
||||||
|
int16_t *prev_y,
|
||||||
|
const uint8_t color[4], int h)
|
||||||
|
{
|
||||||
|
if (h >= 0 && h < height) {
|
||||||
|
buf[h * linesize + 0] = color[0];
|
||||||
|
buf[h * linesize + 1] = color[1];
|
||||||
|
buf[h * linesize + 2] = color[2];
|
||||||
|
buf[h * linesize + 3] = color[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_sample_line_rgba_scale(uint8_t *buf, int height, int linesize,
|
||||||
int16_t *prev_y,
|
int16_t *prev_y,
|
||||||
const uint8_t color[4], int h)
|
const uint8_t color[4], int h)
|
||||||
{
|
{
|
||||||
@@ -231,7 +253,24 @@ static void draw_sample_line_rgba(uint8_t *buf, int height, int linesize,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_sample_p2p_rgba(uint8_t *buf, int height, int linesize,
|
static void draw_sample_line_rgba_full(uint8_t *buf, int height, int linesize,
|
||||||
|
int16_t *prev_y,
|
||||||
|
const uint8_t color[4], int h)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
int start = height/2;
|
||||||
|
int end = av_clip(h, 0, height-1);
|
||||||
|
if (start > end)
|
||||||
|
FFSWAP(int16_t, start, end);
|
||||||
|
for (k = start; k < end; k++) {
|
||||||
|
buf[k * linesize + 0] = color[0];
|
||||||
|
buf[k * linesize + 1] = color[1];
|
||||||
|
buf[k * linesize + 2] = color[2];
|
||||||
|
buf[k * linesize + 3] = color[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_sample_p2p_rgba_scale(uint8_t *buf, int height, int linesize,
|
||||||
int16_t *prev_y,
|
int16_t *prev_y,
|
||||||
const uint8_t color[4], int h)
|
const uint8_t color[4], int h)
|
||||||
{
|
{
|
||||||
@@ -257,7 +296,33 @@ static void draw_sample_p2p_rgba(uint8_t *buf, int height, int linesize,
|
|||||||
*prev_y = h;
|
*prev_y = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_sample_cline_rgba(uint8_t *buf, int height, int linesize,
|
static void draw_sample_p2p_rgba_full(uint8_t *buf, int height, int linesize,
|
||||||
|
int16_t *prev_y,
|
||||||
|
const uint8_t color[4], int h)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
if (h >= 0 && h < height) {
|
||||||
|
buf[h * linesize + 0] = color[0];
|
||||||
|
buf[h * linesize + 1] = color[1];
|
||||||
|
buf[h * linesize + 2] = color[2];
|
||||||
|
buf[h * linesize + 3] = color[3];
|
||||||
|
if (*prev_y && h != *prev_y) {
|
||||||
|
int start = *prev_y;
|
||||||
|
int end = av_clip(h, 0, height-1);
|
||||||
|
if (start > end)
|
||||||
|
FFSWAP(int16_t, start, end);
|
||||||
|
for (k = start + 1; k < end; k++) {
|
||||||
|
buf[k * linesize + 0] = color[0];
|
||||||
|
buf[k * linesize + 1] = color[1];
|
||||||
|
buf[k * linesize + 2] = color[2];
|
||||||
|
buf[k * linesize + 3] = color[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*prev_y = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_sample_cline_rgba_scale(uint8_t *buf, int height, int linesize,
|
||||||
int16_t *prev_y,
|
int16_t *prev_y,
|
||||||
const uint8_t color[4], int h)
|
const uint8_t color[4], int h)
|
||||||
{
|
{
|
||||||
@@ -271,6 +336,20 @@ static void draw_sample_cline_rgba(uint8_t *buf, int height, int linesize,
|
|||||||
buf[k * linesize + 3] += color[3];
|
buf[k * linesize + 3] += color[3];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
static void draw_sample_cline_rgba_full(uint8_t *buf, int height, int linesize,
|
||||||
|
int16_t *prev_y,
|
||||||
|
const uint8_t color[4], int h)
|
||||||
|
{
|
||||||
|
int k;
|
||||||
|
const int start = (height - h) / 2;
|
||||||
|
const int end = start + h;
|
||||||
|
for (k = start; k < end; k++) {
|
||||||
|
buf[k * linesize + 0] = color[0];
|
||||||
|
buf[k * linesize + 1] = color[1];
|
||||||
|
buf[k * linesize + 2] = color[2];
|
||||||
|
buf[k * linesize + 3] = color[3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void draw_sample_point_gray(uint8_t *buf, int height, int linesize,
|
static void draw_sample_point_gray(uint8_t *buf, int height, int linesize,
|
||||||
int16_t *prev_y,
|
int16_t *prev_y,
|
||||||
@@ -368,10 +447,10 @@ static int config_output(AVFilterLink *outlink)
|
|||||||
break;
|
break;
|
||||||
case AV_PIX_FMT_RGBA:
|
case AV_PIX_FMT_RGBA:
|
||||||
switch (showwaves->mode) {
|
switch (showwaves->mode) {
|
||||||
case MODE_POINT: showwaves->draw_sample = draw_sample_point_rgba; break;
|
case MODE_POINT: showwaves->draw_sample = showwaves->draw_mode == DRAW_SCALE ? draw_sample_point_rgba_scale : draw_sample_point_rgba_full; break;
|
||||||
case MODE_LINE: showwaves->draw_sample = draw_sample_line_rgba; break;
|
case MODE_LINE: showwaves->draw_sample = showwaves->draw_mode == DRAW_SCALE ? draw_sample_line_rgba_scale : draw_sample_line_rgba_full; break;
|
||||||
case MODE_P2P: showwaves->draw_sample = draw_sample_p2p_rgba; break;
|
case MODE_P2P: showwaves->draw_sample = showwaves->draw_mode == DRAW_SCALE ? draw_sample_p2p_rgba_scale : draw_sample_p2p_rgba_full; break;
|
||||||
case MODE_CENTERED_LINE: showwaves->draw_sample = draw_sample_cline_rgba; break;
|
case MODE_CENTERED_LINE: showwaves->draw_sample = showwaves->draw_mode == DRAW_SCALE ? draw_sample_cline_rgba_scale : draw_sample_cline_rgba_full; break;
|
||||||
default:
|
default:
|
||||||
return AVERROR_BUG;
|
return AVERROR_BUG;
|
||||||
}
|
}
|
||||||
@@ -430,8 +509,12 @@ static int config_output(AVFilterLink *outlink)
|
|||||||
if (!colors)
|
if (!colors)
|
||||||
return AVERROR(ENOMEM);
|
return AVERROR(ENOMEM);
|
||||||
|
|
||||||
|
if (showwaves->draw_mode == DRAW_SCALE) {
|
||||||
/* multiplication factor, pre-computed to avoid in-loop divisions */
|
/* multiplication factor, pre-computed to avoid in-loop divisions */
|
||||||
x = 255 / ((showwaves->split_channels ? 1 : nb_channels) * showwaves->n);
|
x = 255 / ((showwaves->split_channels ? 1 : nb_channels) * showwaves->n);
|
||||||
|
} else {
|
||||||
|
x = 255;
|
||||||
|
}
|
||||||
if (outlink->format == AV_PIX_FMT_RGBA) {
|
if (outlink->format == AV_PIX_FMT_RGBA) {
|
||||||
uint8_t fg[4] = { 0xff, 0xff, 0xff, 0xff };
|
uint8_t fg[4] = { 0xff, 0xff, 0xff, 0xff };
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user