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
49f4967d
Commit
49f4967d
authored
Jun 07, 2015
by
Clément Bœsch
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
avfilter: add selectivecolor filter
parent
47c5a305
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
529 additions
and
1 deletion
+529
-1
Changelog
Changelog
+1
-0
filters.texi
doc/filters.texi
+67
-0
Makefile
libavfilter/Makefile
+1
-0
allfilters.c
libavfilter/allfilters.c
+1
-0
version.h
libavfilter/version.h
+1
-1
vf_selectivecolor.c
libavfilter/vf_selectivecolor.c
+458
-0
No files found.
Changelog
View file @
49f4967d
...
@@ -17,6 +17,7 @@ version <next>:
...
@@ -17,6 +17,7 @@ version <next>:
- chromaprint fingerprinting muxer
- chromaprint fingerprinting muxer
- ffplay dynamic volume control
- ffplay dynamic volume control
- displace filter
- displace filter
- selectivecolor filter
version 2.8:
version 2.8:
...
...
doc/filters.texi
View file @
49f4967d
...
@@ -13037,6 +13037,73 @@ select=n=2:e='mod(n, 2)+1' [odd][even]; [odd] pad=h=2*ih [tmp]; [tmp][even] over
...
@@ -13037,6 +13037,73 @@ select=n=2:e='mod(n, 2)+1' [odd][even]; [odd] pad=h=2*ih [tmp]; [tmp][even] over
@end example
@end example
@end itemize
@end itemize
@section selectivecolor
Adjust cyan, magenta, yellow and black (CMYK) to certain ranges of colors (such
as "reds", "yellows", "greens", "cyans", ...). The adjustment range is defined
by the "purity" of the color (that is, how saturated it already is).
This filter is similar to the Adobe Photoshop Selective Color tool.
The filter accepts the following options:
@table @option
@item correction_method
Select color correction method.
Available values are:
@table @samp
@item absolute
Specified adjustments are applied "as-is" (added/subtracted to original pixel
component value).
@item relative
Specified adjustments are relative to the original component value.
@end table
Default is @code{absolute}.
@item reds
Adjustments for red pixels (pixels where the red component is the maximum)
@item yellows
Adjustments for yellow pixels (pixels where the blue component is the minimum)
@item greens
Adjustments for green pixels (pixels where the green component is the maximum)
@item cyans
Adjustments for cyan pixels (pixels where the red component is the minimum)
@item blues
Adjustments for blue pixels (pixels where the blue component is the maximum)
@item magentas
Adjustments for magenta pixels (pixels where the green component is the minimum)
@item whites
Adjustments for white pixels (pixels where all components are greater than 128)
@item neutrals
Adjustments for all pixels except pure black and pure white
@item blacks
Adjustments for black pixels (pixels where all components are lesser than 128)
@item psfile
Specify a Photoshop selective color file (@code{.asv}) to import the settings from.
@end table
All the adjustment settings (@option{reds}, @option{yellows}, ...) accept up to
4 space separated floating point adjustment values in the [-1,1] range,
respectively to adjust the amount of cyan, magenta, yellow and black for the
pixels of its range.
@subsection Examples
@itemize
@item
Increase cyan by 55% and reduce yellow by 33% in every green areas, and
increase magenta by 27% in blue areas:
@example
selectivecolor=greens=.5 0 -.33 0:blues=0 .27
@end example
@item
Use a Photoshop selective color preset:
@example
selectivecolor=psfile=MySelectiveColorPresets/Misty.asv
@end example
@end itemize
@section sendcmd, asendcmd
@section sendcmd, asendcmd
Send commands to filters in the filtergraph.
Send commands to filters in the filtergraph.
...
...
libavfilter/Makefile
View file @
49f4967d
...
@@ -206,6 +206,7 @@ OBJS-$(CONFIG_SAB_FILTER) += vf_sab.o
...
@@ -206,6 +206,7 @@ OBJS-$(CONFIG_SAB_FILTER) += vf_sab.o
OBJS-$(CONFIG_SCALE_FILTER)
+=
vf_scale.o
OBJS-$(CONFIG_SCALE_FILTER)
+=
vf_scale.o
OBJS-$(CONFIG_SCALE2REF_FILTER)
+=
vf_scale.o
OBJS-$(CONFIG_SCALE2REF_FILTER)
+=
vf_scale.o
OBJS-$(CONFIG_SELECT_FILTER)
+=
f_select.o
OBJS-$(CONFIG_SELECT_FILTER)
+=
f_select.o
OBJS-$(CONFIG_SELECTIVECOLOR_FILTER)
+=
vf_selectivecolor.o
OBJS-$(CONFIG_SENDCMD_FILTER)
+=
f_sendcmd.o
OBJS-$(CONFIG_SENDCMD_FILTER)
+=
f_sendcmd.o
OBJS-$(CONFIG_SETDAR_FILTER)
+=
vf_aspect.o
OBJS-$(CONFIG_SETDAR_FILTER)
+=
vf_aspect.o
OBJS-$(CONFIG_SETFIELD_FILTER)
+=
vf_setfield.o
OBJS-$(CONFIG_SETFIELD_FILTER)
+=
vf_setfield.o
...
...
libavfilter/allfilters.c
View file @
49f4967d
...
@@ -226,6 +226,7 @@ void avfilter_register_all(void)
...
@@ -226,6 +226,7 @@ void avfilter_register_all(void)
REGISTER_FILTER
(
SCALE
,
scale
,
vf
);
REGISTER_FILTER
(
SCALE
,
scale
,
vf
);
REGISTER_FILTER
(
SCALE2REF
,
scale2ref
,
vf
);
REGISTER_FILTER
(
SCALE2REF
,
scale2ref
,
vf
);
REGISTER_FILTER
(
SELECT
,
select
,
vf
);
REGISTER_FILTER
(
SELECT
,
select
,
vf
);
REGISTER_FILTER
(
SELECTIVECOLOR
,
selectivecolor
,
vf
);
REGISTER_FILTER
(
SENDCMD
,
sendcmd
,
vf
);
REGISTER_FILTER
(
SENDCMD
,
sendcmd
,
vf
);
REGISTER_FILTER
(
SEPARATEFIELDS
,
separatefields
,
vf
);
REGISTER_FILTER
(
SEPARATEFIELDS
,
separatefields
,
vf
);
REGISTER_FILTER
(
SETDAR
,
setdar
,
vf
);
REGISTER_FILTER
(
SETDAR
,
setdar
,
vf
);
...
...
libavfilter/version.h
View file @
49f4967d
...
@@ -30,7 +30,7 @@
...
@@ -30,7 +30,7 @@
#include "libavutil/version.h"
#include "libavutil/version.h"
#define LIBAVFILTER_VERSION_MAJOR 6
#define LIBAVFILTER_VERSION_MAJOR 6
#define LIBAVFILTER_VERSION_MINOR 1
0
#define LIBAVFILTER_VERSION_MINOR 1
1
#define LIBAVFILTER_VERSION_MICRO 100
#define LIBAVFILTER_VERSION_MICRO 100
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \
...
...
libavfilter/vf_selectivecolor.c
0 → 100644
View file @
49f4967d
/*
* Copyright (c) 2015 Clément Bœsch <u pkh me>
*
* This file is part of FFmpeg.
*
* FFmpeg is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* FFmpeg is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with FFmpeg; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @todo
* - use integers so it can be made bitexact and a FATE test can be added
* - >8 bit support
*/
#include "libavutil/avassert.h"
#include "libavutil/file.h"
#include "libavutil/intreadwrite.h"
#include "libavutil/opt.h"
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
#include "video.h"
enum
color_range
{
// WARNING: do NOT reorder (see parse_psfile())
RANGE_REDS
,
RANGE_YELLOWS
,
RANGE_GREENS
,
RANGE_CYANS
,
RANGE_BLUES
,
RANGE_MAGENTAS
,
RANGE_WHITES
,
RANGE_NEUTRALS
,
RANGE_BLACKS
,
NB_RANGES
};
enum
correction_method
{
CORRECTION_METHOD_ABSOLUTE
,
CORRECTION_METHOD_RELATIVE
,
NB_CORRECTION_METHODS
,
};
static
const
char
*
color_names
[
NB_RANGES
]
=
{
"red"
,
"yellow"
,
"green"
,
"cyan"
,
"blue"
,
"magenta"
,
"white"
,
"neutral"
,
"black"
};
typedef
int
(
*
get_adjust_range_func
)(
int
r
,
int
g
,
int
b
,
int
min_val
,
int
max_val
);
struct
process_range
{
int
range_id
;
uint32_t
mask
;
get_adjust_range_func
get_adjust_range
;
};
typedef
struct
ThreadData
{
AVFrame
*
in
,
*
out
;
}
ThreadData
;
typedef
struct
{
const
AVClass
*
class
;
int
correction_method
;
char
*
opt_cmyk_adjust
[
NB_RANGES
];
float
cmyk_adjust
[
NB_RANGES
][
4
];
struct
process_range
process_ranges
[
NB_RANGES
];
// color ranges to process
int
nb_process_ranges
;
char
*
psfile
;
}
SelectiveColorContext
;
#define OFFSET(x) offsetof(SelectiveColorContext, x)
#define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
#define RANGE_OPTION(color_name, range) \
{ color_name"s", "adjust "color_name" regions", OFFSET(opt_cmyk_adjust[range]), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }
static
const
AVOption
selectivecolor_options
[]
=
{
{
"correction_method"
,
"select correction method"
,
OFFSET
(
correction_method
),
AV_OPT_TYPE_INT
,
{.
i64
=
CORRECTION_METHOD_ABSOLUTE
},
0
,
NB_CORRECTION_METHODS
,
FLAGS
,
"correction_method"
},
{
"absolute"
,
NULL
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
CORRECTION_METHOD_ABSOLUTE
},
INT_MIN
,
INT_MAX
,
FLAGS
,
"correction_method"
},
{
"relative"
,
NULL
,
0
,
AV_OPT_TYPE_CONST
,
{.
i64
=
CORRECTION_METHOD_RELATIVE
},
INT_MIN
,
INT_MAX
,
FLAGS
,
"correction_method"
},
RANGE_OPTION
(
"red"
,
RANGE_REDS
),
RANGE_OPTION
(
"yellow"
,
RANGE_YELLOWS
),
RANGE_OPTION
(
"green"
,
RANGE_GREENS
),
RANGE_OPTION
(
"cyan"
,
RANGE_CYANS
),
RANGE_OPTION
(
"blue"
,
RANGE_BLUES
),
RANGE_OPTION
(
"magenta"
,
RANGE_MAGENTAS
),
RANGE_OPTION
(
"white"
,
RANGE_WHITES
),
RANGE_OPTION
(
"neutral"
,
RANGE_NEUTRALS
),
RANGE_OPTION
(
"black"
,
RANGE_BLACKS
),
{
"psfile"
,
"set Photoshop selectivecolor file name"
,
OFFSET
(
psfile
),
AV_OPT_TYPE_STRING
,
{.
str
=
NULL
},
.
flags
=
FLAGS
},
{
NULL
}
};
AVFILTER_DEFINE_CLASS
(
selectivecolor
);
static
inline
int
get_mid_val
(
int
r
,
int
g
,
int
b
)
{
if
((
r
<
g
&&
r
>
b
)
||
(
r
<
b
&&
r
>
g
))
return
r
;
if
((
g
<
r
&&
g
>
b
)
||
(
g
<
b
&&
g
>
r
))
return
g
;
if
((
b
<
r
&&
b
>
g
)
||
(
b
<
g
&&
b
>
r
))
return
b
;
return
-
1
;
}
static
int
get_rgb_adjust_range
(
int
r
,
int
g
,
int
b
,
int
min_val
,
int
max_val
)
{
// max - mid
const
int
mid_val
=
get_mid_val
(
r
,
g
,
b
);
if
(
mid_val
==
-
1
)
{
// XXX: can be simplified
if
((
r
!=
min_val
&&
g
==
min_val
&&
b
==
min_val
)
||
(
r
==
min_val
&&
g
!=
min_val
&&
b
==
min_val
)
||
(
r
==
min_val
&&
g
==
min_val
&&
b
!=
min_val
))
return
max_val
-
min_val
;
return
0
;
}
return
max_val
-
mid_val
;
}
static
int
get_cmy_adjust_range
(
int
r
,
int
g
,
int
b
,
int
min_val
,
int
max_val
)
{
// mid - min
const
int
mid_val
=
get_mid_val
(
r
,
g
,
b
);
if
(
mid_val
==
-
1
)
{
// XXX: refactor with rgb
if
((
r
!=
max_val
&&
g
==
max_val
&&
b
==
max_val
)
||
(
r
==
max_val
&&
g
!=
max_val
&&
b
==
max_val
)
||
(
r
==
max_val
&&
g
==
max_val
&&
b
!=
max_val
))
return
max_val
-
min_val
;
return
0
;
}
return
mid_val
-
min_val
;
}
static
int
get_neutrals_adjust_range
(
int
r
,
int
g
,
int
b
,
int
min_val
,
int
max_val
)
{
// 1 - (|max-0.5| + |min-0.5|)
return
(
255
*
2
-
(
abs
((
max_val
<<
1
)
-
255
)
+
abs
((
min_val
<<
1
)
-
255
))
+
1
)
>>
1
;
}
static
int
get_whites_adjust_range
(
int
r
,
int
g
,
int
b
,
int
min_val
,
int
max_val
)
{
// (min - 0.5) * 2
return
(
min_val
<<
1
)
-
255
;
}
static
int
get_blacks_adjust_range
(
int
r
,
int
g
,
int
b
,
int
min_val
,
int
max_val
)
{
// (0.5 - max) * 2
return
255
-
(
max_val
<<
1
);
}
static
int
register_range
(
SelectiveColorContext
*
s
,
int
range_id
)
{
const
float
*
cmyk
=
s
->
cmyk_adjust
[
range_id
];
/* If the color range has user settings, register the color range
* as "to be processed" */
if
(
cmyk
[
0
]
||
cmyk
[
1
]
||
cmyk
[
2
]
||
cmyk
[
3
])
{
struct
process_range
*
pr
=
&
s
->
process_ranges
[
s
->
nb_process_ranges
++
];
if
(
cmyk
[
0
]
<
-
1
.
0
||
cmyk
[
0
]
>
1
.
0
||
cmyk
[
1
]
<
-
1
.
0
||
cmyk
[
1
]
>
1
.
0
||
cmyk
[
2
]
<
-
1
.
0
||
cmyk
[
2
]
>
1
.
0
||
cmyk
[
3
]
<
-
1
.
0
||
cmyk
[
3
]
>
1
.
0
)
{
av_log
(
s
,
AV_LOG_ERROR
,
"Invalid %s adjustments (%g %g %g %g). "
"Settings must be set in [-1;1] range
\n
"
,
color_names
[
range_id
],
cmyk
[
0
],
cmyk
[
1
],
cmyk
[
2
],
cmyk
[
3
]);
return
AVERROR
(
EINVAL
);
}
pr
->
range_id
=
range_id
;
pr
->
mask
=
1
<<
range_id
;
if
(
pr
->
mask
&
(
1
<<
RANGE_REDS
|
1
<<
RANGE_GREENS
|
1
<<
RANGE_BLUES
))
pr
->
get_adjust_range
=
get_rgb_adjust_range
;
else
if
(
pr
->
mask
&
(
1
<<
RANGE_CYANS
|
1
<<
RANGE_MAGENTAS
|
1
<<
RANGE_YELLOWS
))
pr
->
get_adjust_range
=
get_cmy_adjust_range
;
else
if
(
pr
->
mask
&
1
<<
RANGE_WHITES
)
pr
->
get_adjust_range
=
get_whites_adjust_range
;
else
if
(
pr
->
mask
&
1
<<
RANGE_NEUTRALS
)
pr
->
get_adjust_range
=
get_neutrals_adjust_range
;
else
if
(
pr
->
mask
&
1
<<
RANGE_BLACKS
)
pr
->
get_adjust_range
=
get_blacks_adjust_range
;
else
av_assert0
(
0
);
}
return
0
;
}
static
int
parse_psfile
(
AVFilterContext
*
ctx
,
const
char
*
fname
)
{
int16_t
val
;
int
ret
,
i
,
version
;
uint8_t
*
buf
;
size_t
size
;
SelectiveColorContext
*
s
=
ctx
->
priv
;
ret
=
av_file_map
(
fname
,
&
buf
,
&
size
,
0
,
NULL
);
if
(
ret
<
0
)
return
ret
;
#define READ16(dst) do { \
if (size < 2) { \
ret = AVERROR_INVALIDDATA; \
goto end; \
} \
dst = AV_RB16(buf); \
buf += 2; \
size -= 2; \
} while (0)
READ16
(
version
);
if
(
version
!=
1
)
av_log
(
s
,
AV_LOG_WARNING
,
"Unsupported selective color file version %d, "
"the settings might not be loaded properly
\n
"
,
version
);
READ16
(
s
->
correction_method
);
// 1st CMYK entry is reserved/unused
for
(
i
=
0
;
i
<
FF_ARRAY_ELEMS
(
s
->
cmyk_adjust
[
0
]);
i
++
)
{
READ16
(
val
);
if
(
val
)
av_log
(
s
,
AV_LOG_WARNING
,
"%c value of first CMYK entry is not 0 "
"but %d
\n
"
,
"CMYK"
[
i
],
val
);
}
for
(
i
=
0
;
i
<
FF_ARRAY_ELEMS
(
s
->
cmyk_adjust
);
i
++
)
{
int
k
;
for
(
k
=
0
;
k
<
FF_ARRAY_ELEMS
(
s
->
cmyk_adjust
[
0
]);
k
++
)
{
READ16
(
val
);
s
->
cmyk_adjust
[
i
][
k
]
=
val
/
100
.;
}
ret
=
register_range
(
s
,
i
);
if
(
ret
<
0
)
goto
end
;
}
end:
av_file_unmap
(
buf
,
size
);
return
ret
;
}
static
av_cold
int
init
(
AVFilterContext
*
ctx
)
{
int
i
,
ret
;
SelectiveColorContext
*
s
=
ctx
->
priv
;
/* If the following conditions are not met, it will cause trouble while
* parsing the PS file */
av_assert0
(
FF_ARRAY_ELEMS
(
s
->
cmyk_adjust
)
==
10
-
1
);
av_assert0
(
FF_ARRAY_ELEMS
(
s
->
cmyk_adjust
[
0
])
==
4
);
if
(
s
->
psfile
)
{
ret
=
parse_psfile
(
ctx
,
s
->
psfile
);
if
(
ret
<
0
)
return
ret
;
}
else
{
for
(
i
=
0
;
i
<
FF_ARRAY_ELEMS
(
s
->
opt_cmyk_adjust
);
i
++
)
{
const
char
*
opt_cmyk_adjust
=
s
->
opt_cmyk_adjust
[
i
];
if
(
opt_cmyk_adjust
)
{
float
*
cmyk
=
s
->
cmyk_adjust
[
i
];
sscanf
(
s
->
opt_cmyk_adjust
[
i
],
"%f %f %f %f"
,
cmyk
,
cmyk
+
1
,
cmyk
+
2
,
cmyk
+
3
);
ret
=
register_range
(
s
,
i
);
if
(
ret
<
0
)
return
ret
;
}
}
}
av_log
(
s
,
AV_LOG_VERBOSE
,
"Adjustments:%s
\n
"
,
s
->
nb_process_ranges
?
""
:
" none"
);
for
(
i
=
0
;
i
<
s
->
nb_process_ranges
;
i
++
)
{
const
struct
process_range
*
pr
=
&
s
->
process_ranges
[
i
];
const
float
*
cmyk
=
s
->
cmyk_adjust
[
pr
->
range_id
];
av_log
(
s
,
AV_LOG_VERBOSE
,
"%8ss: C=%6g M=%6g Y=%6g K=%6g
\n
"
,
color_names
[
pr
->
range_id
],
cmyk
[
0
],
cmyk
[
1
],
cmyk
[
2
],
cmyk
[
3
]);
}
return
0
;
}
static
int
query_formats
(
AVFilterContext
*
ctx
)
{
static
const
enum
AVPixelFormat
pix_fmts
[]
=
{
AV_PIX_FMT_RGB32
,
AV_PIX_FMT_0RGB32
,
AV_PIX_FMT_NONE
};
AVFilterFormats
*
fmts_list
=
ff_make_format_list
(
pix_fmts
);
if
(
!
fmts_list
)
return
AVERROR
(
ENOMEM
);
return
ff_set_common_formats
(
ctx
,
fmts_list
);
}
static
inline
int
comp_adjust
(
int
adjust_range
,
float
value
,
float
adjust
,
float
k
,
int
correction_method
)
{
const
float
min
=
-
value
;
const
float
max
=
1
.
-
value
;
float
res
=
(
-
1
.
-
adjust
)
*
k
-
adjust
;
if
(
correction_method
==
CORRECTION_METHOD_RELATIVE
)
res
*=
max
;
return
lrint
(
av_clipf
(
res
,
min
,
max
)
*
adjust_range
);
}
static
inline
int
selective_color
(
AVFilterContext
*
ctx
,
ThreadData
*
td
,
int
jobnr
,
int
nb_jobs
,
int
direct
,
int
correction_method
)
{
int
i
,
x
,
y
;
const
AVFrame
*
in
=
td
->
in
;
AVFrame
*
out
=
td
->
out
;
const
SelectiveColorContext
*
s
=
ctx
->
priv
;
const
int
height
=
in
->
height
;
const
int
width
=
in
->
width
;
const
int
slice_start
=
(
height
*
jobnr
)
/
nb_jobs
;
const
int
slice_end
=
(
height
*
(
jobnr
+
1
))
/
nb_jobs
;
const
int
dst_linesize
=
out
->
linesize
[
0
];
const
int
src_linesize
=
in
->
linesize
[
0
];
uint8_t
*
dst
=
out
->
data
[
0
]
+
slice_start
*
dst_linesize
;
const
uint8_t
*
src
=
in
->
data
[
0
]
+
slice_start
*
src_linesize
;
for
(
y
=
slice_start
;
y
<
slice_end
;
y
++
)
{
const
uint32_t
*
src32
=
(
const
uint32_t
*
)
src
;
uint32_t
*
dst32
=
(
uint32_t
*
)
dst
;
for
(
x
=
0
;
x
<
width
;
x
++
)
{
const
uint32_t
color
=
*
src32
++
;
const
int
r
=
color
>>
16
&
0xff
;
const
int
g
=
color
>>
8
&
0xff
;
const
int
b
=
color
&
0xff
;
const
int
min_color
=
FFMIN3
(
r
,
g
,
b
);
const
int
max_color
=
FFMAX3
(
r
,
g
,
b
);
const
uint32_t
range_flag
=
(
r
==
max_color
)
<<
RANGE_REDS
|
(
r
==
min_color
)
<<
RANGE_CYANS
|
(
g
==
max_color
)
<<
RANGE_GREENS
|
(
g
==
min_color
)
<<
RANGE_MAGENTAS
|
(
b
==
max_color
)
<<
RANGE_BLUES
|
(
b
==
min_color
)
<<
RANGE_YELLOWS
|
(
r
>
128
&&
g
>
128
&&
b
>
128
)
<<
RANGE_WHITES
|
(
color
&&
(
color
&
0xffffff
)
!=
0xffffff
)
<<
RANGE_NEUTRALS
|
(
r
<
128
&&
g
<
128
&&
b
<
128
)
<<
RANGE_BLACKS
;
const
float
rnorm
=
r
/
255
.;
const
float
gnorm
=
g
/
255
.;
const
float
bnorm
=
b
/
255
.;
int
adjust_r
=
0
,
adjust_g
=
0
,
adjust_b
=
0
;
for
(
i
=
0
;
i
<
s
->
nb_process_ranges
;
i
++
)
{
const
struct
process_range
*
pr
=
&
s
->
process_ranges
[
i
];
if
(
range_flag
&
pr
->
mask
)
{
const
int
adjust_range
=
pr
->
get_adjust_range
(
r
,
g
,
b
,
min_color
,
max_color
);
if
(
adjust_range
>
0
)
{
const
float
*
cmyk_adjust
=
s
->
cmyk_adjust
[
pr
->
range_id
];
const
float
adj_c
=
cmyk_adjust
[
0
];
const
float
adj_m
=
cmyk_adjust
[
1
];
const
float
adj_y
=
cmyk_adjust
[
2
];
const
float
k
=
cmyk_adjust
[
3
];
adjust_r
+=
comp_adjust
(
adjust_range
,
rnorm
,
adj_c
,
k
,
correction_method
);
adjust_g
+=
comp_adjust
(
adjust_range
,
gnorm
,
adj_m
,
k
,
correction_method
);
adjust_b
+=
comp_adjust
(
adjust_range
,
bnorm
,
adj_y
,
k
,
correction_method
);
}
}
}
if
(
!
direct
||
adjust_r
||
adjust_g
||
adjust_b
)
*
dst32
=
(
color
&
0xff000000
)
|
av_clip_uint8
(
r
+
adjust_r
)
<<
16
|
av_clip_uint8
(
g
+
adjust_g
)
<<
8
|
av_clip_uint8
(
b
+
adjust_b
);
dst32
++
;
}
src
+=
src_linesize
;
dst
+=
dst_linesize
;
}
return
0
;
}
#define DEF_SELECTIVE_COLOR_FUNC(name, direct, correction_method) \
static int selective_color_##name(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) \
{ \
return selective_color(ctx, arg, jobnr, nb_jobs, direct, correction_method); \
}
DEF_SELECTIVE_COLOR_FUNC
(
indirect_absolute
,
0
,
CORRECTION_METHOD_ABSOLUTE
)
DEF_SELECTIVE_COLOR_FUNC
(
indirect_relative
,
0
,
CORRECTION_METHOD_RELATIVE
)
DEF_SELECTIVE_COLOR_FUNC
(
direct_absolute
,
1
,
CORRECTION_METHOD_ABSOLUTE
)
DEF_SELECTIVE_COLOR_FUNC
(
direct_relative
,
1
,
CORRECTION_METHOD_RELATIVE
)
typedef
int
(
*
selective_color_func_type
)(
AVFilterContext
*
ctx
,
void
*
td
,
int
jobnr
,
int
nb_jobs
);
static
int
filter_frame
(
AVFilterLink
*
inlink
,
AVFrame
*
in
)
{
AVFilterContext
*
ctx
=
inlink
->
dst
;
AVFilterLink
*
outlink
=
ctx
->
outputs
[
0
];
int
direct
;
AVFrame
*
out
;
ThreadData
td
;
const
SelectiveColorContext
*
s
=
ctx
->
priv
;
static
const
selective_color_func_type
funcs
[
2
][
2
]
=
{
{
selective_color_indirect_absolute
,
selective_color_indirect_relative
},
{
selective_color_direct_absolute
,
selective_color_direct_relative
},
};
if
(
av_frame_is_writable
(
in
))
{
direct
=
1
;
out
=
in
;
}
else
{
direct
=
0
;
out
=
ff_get_video_buffer
(
outlink
,
outlink
->
w
,
outlink
->
h
);
if
(
!
out
)
{
av_frame_free
(
&
in
);
return
AVERROR
(
ENOMEM
);
}
av_frame_copy_props
(
out
,
in
);
}
td
.
in
=
in
;
td
.
out
=
out
;
ctx
->
internal
->
execute
(
ctx
,
funcs
[
direct
][
s
->
correction_method
],
&
td
,
NULL
,
FFMIN
(
inlink
->
h
,
ctx
->
graph
->
nb_threads
));
if
(
!
direct
)
av_frame_free
(
&
in
);
return
ff_filter_frame
(
outlink
,
out
);
}
static
const
AVFilterPad
selectivecolor_inputs
[]
=
{
{
.
name
=
"default"
,
.
type
=
AVMEDIA_TYPE_VIDEO
,
.
filter_frame
=
filter_frame
,
},
{
NULL
}
};
static
const
AVFilterPad
selectivecolor_outputs
[]
=
{
{
.
name
=
"default"
,
.
type
=
AVMEDIA_TYPE_VIDEO
,
},
{
NULL
}
};
AVFilter
ff_vf_selectivecolor
=
{
.
name
=
"selectivecolor"
,
.
description
=
NULL_IF_CONFIG_SMALL
(
"Apply CMYK adjustments to specific color ranges."
),
.
priv_size
=
sizeof
(
SelectiveColorContext
),
.
init
=
init
,
.
query_formats
=
query_formats
,
.
inputs
=
selectivecolor_inputs
,
.
outputs
=
selectivecolor_outputs
,
.
priv_class
=
&
selectivecolor_class
,
.
flags
=
AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
|
AVFILTER_FLAG_SLICE_THREADS
,
};
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