Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
F
ffmpeg.wasm-core
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Linshizhi
ffmpeg.wasm-core
Commits
ce774e30
Commit
ce774e30
authored
Apr 28, 2019
by
Paul B Mahol
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
avfilter/avf_showspectrum: add log scale for frequency plot
parent
90b21ae5
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
200 additions
and
65 deletions
+200
-65
filters.texi
doc/filters.texi
+26
-0
avf_showspectrum.c
libavfilter/avf_showspectrum.c
+174
-65
No files found.
doc/filters.texi
View file @
ce774e30
...
...
@@ -22226,6 +22226,19 @@ logarithmic
Default
value
is
@
samp
{
sqrt
}.
@
item
fscale
Specify
frequency
scale
.
It
accepts
the
following
values
:
@
table
@
samp
@
item
lin
linear
@
item
log
logarithmic
@
end
table
Default
value
is
@
samp
{
lin
}.
@
item
saturation
Set
saturation
modifier
for
displayed
colors
.
Negative
values
provide
alternative
color
scheme
.
@
code
{
0
}
is
no
saturation
at
all
.
...
...
@@ -22398,6 +22411,19 @@ logarithmic
@
end
table
Default
value
is
@
samp
{
log
}.
@
item
fscale
Specify
frequency
scale
.
It
accepts
the
following
values
:
@
table
@
samp
@
item
lin
linear
@
item
log
logarithmic
@
end
table
Default
value
is
@
samp
{
lin
}.
@
item
saturation
Set
saturation
modifier
for
displayed
colors
.
Negative
values
provide
alternative
color
scheme
.
@
code
{
0
}
is
no
saturation
at
all
.
...
...
libavfilter/avf_showspectrum.c
View file @
ce774e30
...
...
@@ -45,6 +45,7 @@
enum
DisplayMode
{
COMBINED
,
SEPARATE
,
NB_MODES
};
enum
DataMode
{
D_MAGNITUDE
,
D_PHASE
,
NB_DMODES
};
enum
FrequencyScale
{
F_LINEAR
,
F_LOG
,
NB_FSCALES
};
enum
DisplayScale
{
LINEAR
,
SQRT
,
CBRT
,
LOG
,
FOURTHRT
,
FIFTHRT
,
NB_SCALES
};
enum
ColorMode
{
CHANNEL
,
INTENSITY
,
RAINBOW
,
MORELAND
,
NEBULAE
,
FIRE
,
FIERY
,
FRUIT
,
COOL
,
MAGMA
,
GREEN
,
VIRIDIS
,
PLASMA
,
CIVIDIS
,
TERRAIN
,
NB_CLMODES
};
enum
SlideMode
{
REPLACE
,
SCROLL
,
FULLFRAME
,
RSCROLL
,
NB_SLIDES
};
...
...
@@ -65,6 +66,7 @@ typedef struct ShowSpectrumContext {
int
mode
;
///< channel display mode
int
color_mode
;
///< display color scheme
int
scale
;
int
fscale
;
float
saturation
;
///< color saturation multiplier
float
rotation
;
///< color rotation
int
start
,
stop
;
///< zoom mode
...
...
@@ -95,6 +97,7 @@ typedef struct ShowSpectrumContext {
int
single_pic
;
int
legend
;
int
start_x
,
start_y
;
int
(
*
plot_channel
)(
AVFilterContext
*
ctx
,
void
*
arg
,
int
jobnr
,
int
nb_jobs
);
}
ShowSpectrumContext
;
#define OFFSET(x) offsetof(ShowSpectrumContext, x)
...
...
@@ -134,6 +137,9 @@ static const AVOption showspectrum_options[] = {
{
"log"
,
"logarithmic"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
LOG
},
0
,
0
,
FLAGS
,
"scale"
},
{
"4thrt"
,
"4th root"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
FOURTHRT
},
0
,
0
,
FLAGS
,
"scale"
},
{
"5thrt"
,
"5th root"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
FIFTHRT
},
0
,
0
,
FLAGS
,
"scale"
},
{
"fscale"
,
"set frequency scale"
,
OFFSET
(
fscale
),
AV_OPT_TYPE_INT
,
{.
i64
=
F_LINEAR
},
0
,
NB_FSCALES
-
1
,
FLAGS
,
"fscale"
},
{
"lin"
,
"linear"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
F_LINEAR
},
0
,
0
,
FLAGS
,
"fscale"
},
{
"log"
,
"logarithmic"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
F_LOG
},
0
,
0
,
FLAGS
,
"fscale"
},
{
"saturation"
,
"color saturation multiplier"
,
OFFSET
(
saturation
),
AV_OPT_TYPE_FLOAT
,
{.
dbl
=
1
},
-
10
,
10
,
FLAGS
},
{
"win_func"
,
"set window function"
,
OFFSET
(
win_func
),
AV_OPT_TYPE_INT
,
{.
i64
=
WFUNC_HANNING
},
0
,
NB_WFUNC
-
1
,
FLAGS
,
"win_func"
},
{
"rect"
,
"Rectangular"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
WFUNC_RECT
},
0
,
0
,
FLAGS
,
"win_func"
},
...
...
@@ -623,6 +629,56 @@ static char *get_time(AVFilterContext *ctx, float seconds, int x)
return
units
;
}
static
float
log_scale
(
const
float
value
,
const
float
min
,
const
float
max
)
{
if
(
value
<
min
)
return
min
;
if
(
value
>
max
)
return
max
;
{
const
float
b
=
logf
(
max
/
min
)
/
(
max
-
min
);
const
float
a
=
max
/
expf
(
max
*
b
);
return
expf
(
value
*
b
)
*
a
;
}
}
static
float
get_log_hz
(
const
int
bin
,
const
int
num_bins
,
const
float
sample_rate
)
{
const
float
max_freq
=
sample_rate
/
2
;
const
float
hz_per_bin
=
max_freq
/
num_bins
;
const
float
freq
=
hz_per_bin
*
bin
;
const
float
scaled_freq
=
log_scale
(
freq
+
1
,
21
,
max_freq
)
-
1
;
return
num_bins
*
scaled_freq
/
max_freq
;
}
static
float
inv_log_scale
(
const
float
value
,
const
float
min
,
const
float
max
)
{
if
(
value
<
min
)
return
min
;
if
(
value
>
max
)
return
max
;
{
const
float
b
=
logf
(
max
/
min
)
/
(
max
-
min
);
const
float
a
=
max
/
expf
(
max
*
b
);
return
logf
(
value
/
a
)
/
b
;
}
}
static
float
bin_pos
(
const
int
bin
,
const
int
num_bins
,
const
float
sample_rate
)
{
const
float
max_freq
=
sample_rate
/
2
;
const
float
hz_per_bin
=
max_freq
/
num_bins
;
const
float
freq
=
hz_per_bin
*
bin
;
const
float
scaled_freq
=
inv_log_scale
(
freq
+
1
,
21
,
max_freq
)
-
1
;
return
num_bins
*
scaled_freq
/
max_freq
;
}
static
int
draw_legend
(
AVFilterContext
*
ctx
,
int
samples
)
{
ShowSpectrumContext
*
s
=
ctx
->
priv
;
...
...
@@ -691,7 +747,8 @@ static int draw_legend(AVFilterContext *ctx, int samples)
}
for
(
y
=
0
;
y
<
h
;
y
+=
40
)
{
float
range
=
s
->
stop
?
s
->
stop
-
s
->
start
:
inlink
->
sample_rate
/
2
;
float
hertz
=
s
->
start
+
y
*
range
/
(
float
)(
1
<<
(
int
)
ceil
(
log2
(
h
)));
float
bin
=
s
->
fscale
==
F_LINEAR
?
y
:
get_log_hz
(
y
,
h
,
inlink
->
sample_rate
);
float
hertz
=
s
->
start
+
bin
*
range
/
(
float
)(
1
<<
(
int
)
ceil
(
log2
(
h
)));
char
*
units
;
if
(
hertz
==
0
)
...
...
@@ -746,7 +803,8 @@ static int draw_legend(AVFilterContext *ctx, int samples)
}
for
(
x
=
0
;
x
<
w
-
79
;
x
+=
80
)
{
float
range
=
s
->
stop
?
s
->
stop
-
s
->
start
:
inlink
->
sample_rate
/
2
;
float
hertz
=
s
->
start
+
x
*
range
/
(
float
)(
1
<<
(
int
)
ceil
(
log2
(
w
)));
float
bin
=
s
->
fscale
==
F_LINEAR
?
x
:
get_log_hz
(
x
,
w
,
inlink
->
sample_rate
);
float
hertz
=
s
->
start
+
bin
*
range
/
(
float
)(
1
<<
(
int
)
ceil
(
log2
(
w
)));
char
*
units
;
if
(
hertz
==
0
)
...
...
@@ -812,6 +870,110 @@ static int draw_legend(AVFilterContext *ctx, int samples)
return
0
;
}
static
float
get_value
(
AVFilterContext
*
ctx
,
int
ch
,
int
y
)
{
ShowSpectrumContext
*
s
=
ctx
->
priv
;
float
*
magnitudes
=
s
->
magnitudes
[
ch
];
float
*
phases
=
s
->
phases
[
ch
];
float
a
;
switch
(
s
->
data
)
{
case
D_MAGNITUDE
:
/* get magnitude */
a
=
magnitudes
[
y
];
break
;
case
D_PHASE
:
/* get phase */
a
=
phases
[
y
];
break
;
default:
av_assert0
(
0
);
}
/* apply scale */
switch
(
s
->
scale
)
{
case
LINEAR
:
a
=
av_clipf
(
a
,
0
,
1
);
break
;
case
SQRT
:
a
=
av_clipf
(
sqrt
(
a
),
0
,
1
);
break
;
case
CBRT
:
a
=
av_clipf
(
cbrt
(
a
),
0
,
1
);
break
;
case
FOURTHRT
:
a
=
av_clipf
(
sqrt
(
sqrt
(
a
)),
0
,
1
);
break
;
case
FIFTHRT
:
a
=
av_clipf
(
pow
(
a
,
0
.
20
),
0
,
1
);
break
;
case
LOG
:
a
=
1
+
log10
(
av_clipd
(
a
,
1e-6
,
1
))
/
6
;
// zero = -120dBFS
break
;
default:
av_assert0
(
0
);
}
return
a
;
}
static
int
plot_channel_lin
(
AVFilterContext
*
ctx
,
void
*
arg
,
int
jobnr
,
int
nb_jobs
)
{
ShowSpectrumContext
*
s
=
ctx
->
priv
;
const
int
h
=
s
->
orientation
==
VERTICAL
?
s
->
channel_height
:
s
->
channel_width
;
const
int
ch
=
jobnr
;
float
yf
,
uf
,
vf
;
int
y
;
/* decide color range */
color_range
(
s
,
ch
,
&
yf
,
&
uf
,
&
vf
);
/* 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
a
=
get_value
(
ctx
,
ch
,
y
);
pick_color
(
s
,
yf
,
uf
,
vf
,
a
,
out
);
}
return
0
;
}
static
int
plot_channel_log
(
AVFilterContext
*
ctx
,
void
*
arg
,
int
jobnr
,
int
nb_jobs
)
{
ShowSpectrumContext
*
s
=
ctx
->
priv
;
AVFilterLink
*
inlink
=
ctx
->
inputs
[
0
];
const
int
h
=
s
->
orientation
==
VERTICAL
?
s
->
channel_height
:
s
->
channel_width
;
const
int
ch
=
jobnr
;
float
y
,
yf
,
uf
,
vf
;
int
yy
=
0
;
/* decide color range */
color_range
(
s
,
ch
,
&
yf
,
&
uf
,
&
vf
);
/* draw the channel */
for
(
y
=
0
;
y
<
h
&&
yy
<
h
;
yy
++
)
{
float
pos0
=
bin_pos
(
yy
+
0
,
h
,
inlink
->
sample_rate
);
float
pos1
=
bin_pos
(
yy
+
1
,
h
,
inlink
->
sample_rate
);
float
delta
=
pos1
-
pos0
;
float
a0
,
a1
;
a0
=
get_value
(
ctx
,
ch
,
yy
+
0
);
a1
=
get_value
(
ctx
,
ch
,
FFMIN
(
yy
+
1
,
h
-
1
));
for
(
float
j
=
pos0
;
j
<
pos1
&&
y
+
j
-
pos0
<
h
;
j
++
)
{
float
row
=
(
s
->
mode
==
COMBINED
)
?
y
+
j
-
pos0
:
ch
*
h
+
y
+
j
-
pos0
;
float
*
out
=
&
s
->
color_buffer
[
ch
][
3
*
FFMIN
(
lrintf
(
row
),
h
-
1
)];
float
lerpfrac
=
(
j
-
pos0
)
/
delta
;
pick_color
(
s
,
yf
,
uf
,
vf
,
lerpfrac
*
a1
+
(
1
.
f
-
lerpfrac
)
*
a0
,
out
);
}
y
+=
delta
;
}
return
0
;
}
static
int
config_output
(
AVFilterLink
*
outlink
)
{
AVFilterContext
*
ctx
=
outlink
->
src
;
...
...
@@ -820,6 +982,12 @@ static int config_output(AVFilterLink *outlink)
int
i
,
fft_bits
,
h
,
w
;
float
overlap
;
switch
(
s
->
fscale
)
{
case
F_LINEAR
:
s
->
plot_channel
=
plot_channel_lin
;
break
;
case
F_LOG
:
s
->
plot_channel
=
plot_channel_log
;
break
;
default:
return
AVERROR_BUG
;
}
s
->
stop
=
FFMIN
(
s
->
stop
,
inlink
->
sample_rate
/
2
);
if
(
s
->
stop
&&
s
->
stop
<=
s
->
start
)
{
av_log
(
ctx
,
AV_LOG_ERROR
,
"Stop frequency should be greater than start.
\n
"
);
...
...
@@ -1099,68 +1267,6 @@ static void clear_combine_buffer(ShowSpectrumContext *s, int size)
}
}
static
int
plot_channel
(
AVFilterContext
*
ctx
,
void
*
arg
,
int
jobnr
,
int
nb_jobs
)
{
ShowSpectrumContext
*
s
=
ctx
->
priv
;
const
int
h
=
s
->
orientation
==
VERTICAL
?
s
->
channel_height
:
s
->
channel_width
;
const
int
ch
=
jobnr
;
float
*
magnitudes
=
s
->
magnitudes
[
ch
];
float
*
phases
=
s
->
phases
[
ch
];
float
yf
,
uf
,
vf
;
int
y
;
/* decide color range */
color_range
(
s
,
ch
,
&
yf
,
&
uf
,
&
vf
);
/* 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
a
;
switch
(
s
->
data
)
{
case
D_MAGNITUDE
:
/* get magnitude */
a
=
magnitudes
[
y
];
break
;
case
D_PHASE
:
/* get phase */
a
=
phases
[
y
];
break
;
default:
av_assert0
(
0
);
}
/* apply scale */
switch
(
s
->
scale
)
{
case
LINEAR
:
a
=
av_clipf
(
a
,
0
,
1
);
break
;
case
SQRT
:
a
=
av_clipf
(
sqrt
(
a
),
0
,
1
);
break
;
case
CBRT
:
a
=
av_clipf
(
cbrt
(
a
),
0
,
1
);
break
;
case
FOURTHRT
:
a
=
av_clipf
(
sqrt
(
sqrt
(
a
)),
0
,
1
);
break
;
case
FIFTHRT
:
a
=
av_clipf
(
pow
(
a
,
0
.
20
),
0
,
1
);
break
;
case
LOG
:
a
=
1
+
log10
(
av_clipd
(
a
,
1e-6
,
1
))
/
6
;
// zero = -120dBFS
break
;
default:
av_assert0
(
0
);
}
pick_color
(
s
,
yf
,
uf
,
vf
,
a
,
out
);
}
return
0
;
}
static
int
plot_spectrum_column
(
AVFilterLink
*
inlink
,
AVFrame
*
insamples
)
{
AVFilterContext
*
ctx
=
inlink
->
dst
;
...
...
@@ -1173,7 +1279,7 @@ static int plot_spectrum_column(AVFilterLink *inlink, AVFrame *insamples)
/* initialize buffer for combining to black */
clear_combine_buffer
(
s
,
z
);
ctx
->
internal
->
execute
(
ctx
,
plot_channel
,
NULL
,
NULL
,
s
->
nb_display_channels
);
ctx
->
internal
->
execute
(
ctx
,
s
->
plot_channel
,
NULL
,
NULL
,
s
->
nb_display_channels
);
for
(
y
=
0
;
y
<
z
*
3
;
y
++
)
{
for
(
x
=
0
;
x
<
s
->
nb_display_channels
;
x
++
)
{
...
...
@@ -1447,6 +1553,9 @@ static const AVOption showspectrumpic_options[] = {
{
"log"
,
"logarithmic"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
LOG
},
0
,
0
,
FLAGS
,
"scale"
},
{
"4thrt"
,
"4th root"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
FOURTHRT
},
0
,
0
,
FLAGS
,
"scale"
},
{
"5thrt"
,
"5th root"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
FIFTHRT
},
0
,
0
,
FLAGS
,
"scale"
},
{
"fscale"
,
"set frequency scale"
,
OFFSET
(
fscale
),
AV_OPT_TYPE_INT
,
{.
i64
=
F_LINEAR
},
0
,
NB_FSCALES
-
1
,
FLAGS
,
"fscale"
},
{
"lin"
,
"linear"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
F_LINEAR
},
0
,
0
,
FLAGS
,
"fscale"
},
{
"log"
,
"logarithmic"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
F_LOG
},
0
,
0
,
FLAGS
,
"fscale"
},
{
"saturation"
,
"color saturation multiplier"
,
OFFSET
(
saturation
),
AV_OPT_TYPE_FLOAT
,
{.
dbl
=
1
},
-
10
,
10
,
FLAGS
},
{
"win_func"
,
"set window function"
,
OFFSET
(
win_func
),
AV_OPT_TYPE_INT
,
{.
i64
=
WFUNC_HANNING
},
0
,
NB_WFUNC
-
1
,
FLAGS
,
"win_func"
},
{
"rect"
,
"Rectangular"
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
WFUNC_RECT
},
0
,
0
,
FLAGS
,
"win_func"
},
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment