FFmpeg
Loading...
Searching...
No Matches
vf_colorize.c
Go to the documentation of this file.
1/*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19#include "libavutil/opt.h"
20#include "libavutil/pixdesc.h"
21#include "avfilter.h"
22#include "filters.h"
23#include "video.h"
24
25typedef struct ColorizeContext {
26 const AVClass *class;
27
28 float hue;
30 float lightness;
31 float mix;
32
33 int depth;
34 int c[3];
35 int planewidth[4];
37
39 int jobnr, int nb_jobs);
41
42static inline float lerpf(float v0, float v1, float f)
43{
44 return v0 + (v1 - v0) * f;
45}
46
47static int colorizey_slice8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
48{
49 ColorizeContext *s = ctx->priv;
50 AVFrame *frame = arg;
51 const int width = s->planewidth[0];
52 const int height = s->planeheight[0];
53 const int slice_start = ff_slice_pos(height, jobnr, nb_jobs);
54 const int slice_end = ff_slice_pos(height, jobnr + 1, nb_jobs);
55 const ptrdiff_t ylinesize = frame->linesize[0];
56 uint8_t *yptr = frame->data[0] + slice_start * ylinesize;
57 const int yv = s->c[0];
58 const float mix = s->mix;
59
60 for (int y = slice_start; y < slice_end; y++) {
61 for (int x = 0; x < width; x++)
62 yptr[x] = lerpf(yv, yptr[x], mix);
63
64 yptr += ylinesize;
65 }
66
67 return 0;
68}
69
70static int colorizey_slice16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
71{
72 ColorizeContext *s = ctx->priv;
73 AVFrame *frame = arg;
74 const int width = s->planewidth[0];
75 const int height = s->planeheight[0];
76 const int slice_start = ff_slice_pos(height, jobnr, nb_jobs);
77 const int slice_end = ff_slice_pos(height, jobnr + 1, nb_jobs);
78 const ptrdiff_t ylinesize = frame->linesize[0] / 2;
79 uint16_t *yptr = (uint16_t *)frame->data[0] + slice_start * ylinesize;
80 const int yv = s->c[0];
81 const float mix = s->mix;
82
83 for (int y = slice_start; y < slice_end; y++) {
84 for (int x = 0; x < width; x++)
85 yptr[x] = lerpf(yv, yptr[x], mix);
86
87 yptr += ylinesize;
88 }
89
90 return 0;
91}
92
93static int colorize_slice8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
94{
95 ColorizeContext *s = ctx->priv;
96 AVFrame *frame = arg;
97 const int width = s->planewidth[1];
98 const int height = s->planeheight[1];
99 const int slice_start = ff_slice_pos(height, jobnr, nb_jobs);
100 const int slice_end = ff_slice_pos(height, jobnr + 1, nb_jobs);
101 const ptrdiff_t ulinesize = frame->linesize[1];
102 const ptrdiff_t vlinesize = frame->linesize[2];
103 uint8_t *uptr = frame->data[1] + slice_start * ulinesize;
104 uint8_t *vptr = frame->data[2] + slice_start * vlinesize;
105 const int u = s->c[1];
106 const int v = s->c[2];
107
108 for (int y = slice_start; y < slice_end; y++) {
109 for (int x = 0; x < width; x++) {
110 uptr[x] = u;
111 vptr[x] = v;
112 }
113
114 uptr += ulinesize;
115 vptr += vlinesize;
116 }
117
118 return 0;
119}
120
121static int colorize_slice16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
122{
123 ColorizeContext *s = ctx->priv;
124 AVFrame *frame = arg;
125 const int width = s->planewidth[1];
126 const int height = s->planeheight[1];
127 const int slice_start = ff_slice_pos(height, jobnr, nb_jobs);
128 const int slice_end = ff_slice_pos(height, jobnr + 1, nb_jobs);
129 const ptrdiff_t ulinesize = frame->linesize[1] / 2;
130 const ptrdiff_t vlinesize = frame->linesize[2] / 2;
131 uint16_t *uptr = (uint16_t *)frame->data[1] + slice_start * ulinesize;
132 uint16_t *vptr = (uint16_t *)frame->data[2] + slice_start * vlinesize;
133 const int u = s->c[1];
134 const int v = s->c[2];
135
136 for (int y = slice_start; y < slice_end; y++) {
137 for (int x = 0; x < width; x++) {
138 uptr[x] = u;
139 vptr[x] = v;
140 }
141
142 uptr += ulinesize;
143 vptr += vlinesize;
144 }
145
146 return 0;
147}
148
149static int do_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
150{
151 ColorizeContext *s = ctx->priv;
152
153 s->do_plane_slice[0](ctx, arg, jobnr, nb_jobs);
154 s->do_plane_slice[1](ctx, arg, jobnr, nb_jobs);
155
156 return 0;
157}
158
159static float hue2rgb(float p, float q, float t)
160{
161 if (t < 0.f) t += 1.f;
162 if (t > 1.f) t -= 1.f;
163 if (t < 1.f/6.f) return p + (q - p) * 6.f * t;
164 if (t < 1.f/2.f) return q;
165 if (t < 2.f/3.f) return p + (q - p) * (2.f/3.f - t) * 6.f;
166
167 return p;
168}
169
170static void hsl2rgb(float h, float s, float l, float *r, float *g, float *b)
171{
172 h /= 360.f;
173
174 if (s == 0.f) {
175 *r = *g = *b = l;
176 } else {
177 const float q = l < 0.5f ? l * (1.f + s) : l + s - l * s;
178 const float p = 2.f * l - q;
179
180 *r = hue2rgb(p, q, h + 1.f / 3.f);
181 *g = hue2rgb(p, q, h);
182 *b = hue2rgb(p, q, h - 1.f / 3.f);
183 }
184}
185
186static void rgb2yuv(float r, float g, float b, int *y, int *u, int *v, int depth)
187{
188 *y = ((0.21260*219.0/255.0) * r + (0.71520*219.0/255.0) * g +
189 (0.07220*219.0/255.0) * b) * ((1 << depth) - 1);
190 *u = (-(0.11457*224.0/255.0) * r - (0.38543*224.0/255.0) * g +
191 (0.50000*224.0/255.0) * b + 0.5) * ((1 << depth) - 1);
192 *v = ((0.50000*224.0/255.0) * r - (0.45415*224.0/255.0) * g -
193 (0.04585*224.0/255.0) * b + 0.5) * ((1 << depth) - 1);
194}
195
197{
198 AVFilterContext *ctx = inlink->dst;
199 ColorizeContext *s = ctx->priv;
200 float c[3];
201
202 hsl2rgb(s->hue, s->saturation, s->lightness, &c[0], &c[1], &c[2]);
203 rgb2yuv(c[0], c[1], c[2], &s->c[0], &s->c[1], &s->c[2], s->depth);
204
206 FFMIN(s->planeheight[1], ff_filter_get_nb_threads(ctx)));
207
208 return ff_filter_frame(ctx->outputs[0], frame);
209}
210
231
233{
234 AVFilterContext *ctx = inlink->dst;
235 ColorizeContext *s = ctx->priv;
237 int depth;
238
239 s->depth = depth = desc->comp[0].depth;
240
241 s->planewidth[1] = s->planewidth[2] = AV_CEIL_RSHIFT(inlink->w, desc->log2_chroma_w);
242 s->planewidth[0] = s->planewidth[3] = inlink->w;
243 s->planeheight[1] = s->planeheight[2] = AV_CEIL_RSHIFT(inlink->h, desc->log2_chroma_h);
244 s->planeheight[0] = s->planeheight[3] = inlink->h;
245
246 s->do_plane_slice[0] = depth <= 8 ? colorizey_slice8 : colorizey_slice16;
247 s->do_plane_slice[1] = depth <= 8 ? colorize_slice8 : colorize_slice16;
248
249 return 0;
250}
251
252static const AVFilterPad colorize_inputs[] = {
253 {
254 .name = "default",
255 .type = AVMEDIA_TYPE_VIDEO,
257 .filter_frame = filter_frame,
258 .config_props = config_input,
259 },
260};
261
262#define OFFSET(x) offsetof(ColorizeContext, x)
263#define VF AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_RUNTIME_PARAM
264
265static const AVOption colorize_options[] = {
266 { "hue", "set the hue", OFFSET(hue), AV_OPT_TYPE_FLOAT, {.dbl=0}, 0, 360, VF },
267 { "saturation", "set the saturation", OFFSET(saturation), AV_OPT_TYPE_FLOAT, {.dbl=0.5},0, 1, VF },
268 { "lightness", "set the lightness", OFFSET(lightness), AV_OPT_TYPE_FLOAT, {.dbl=0.5},0, 1, VF },
269 { "mix", "set the mix of source lightness", OFFSET(mix), AV_OPT_TYPE_FLOAT, {.dbl=1}, 0, 1, VF },
270 { NULL }
271};
272
274
276 .p.name = "colorize",
277 .p.description = NULL_IF_CONFIG_SMALL("Overlay a solid color on the video stream."),
278 .p.priv_class = &colorize_class,
280 .priv_size = sizeof(ColorizeContext),
284 .process_command = ff_filter_process_command,
285};
static int config_input(AVFilterLink *inlink)
const FFFilter ff_vf_colorize
int ff_filter_frame(AVFilterLink *link, AVFrame *frame)
Send a frame of data to the next filter.
Definition avfilter.c:1068
int ff_filter_process_command(AVFilterContext *ctx, const char *cmd, const char *arg, char *res, int res_len, int flags)
Generic processing of user supplied commands that are set in the same way as the filter options.
Definition avfilter.c:906
int ff_filter_execute(AVFilterContext *ctx, avfilter_action_func *func, void *arg, int *ret, int nb_jobs)
Definition avfilter.c:1696
int ff_filter_get_nb_threads(AVFilterContext *ctx)
Get number of threads for current filter instance.
Definition avfilter.c:846
Main libavfilter public API header.
#define f(width, name)
Definition cbs_vp8.c:236
#define s(width, name)
Definition cbs_vp9.c:198
static IPT saturation(const CmsCtx *ctx, IPT ipt)
Definition cms.c:559
#define AV_CEIL_RSHIFT(a, b)
Definition common.h:60
#define NULL
Definition coverity.c:32
static AVFrame * frame
static int filter_frame(DBEDecodeContext *s, AVFrame *frame)
Definition dolby_e.c:1067
@ AV_OPT_TYPE_FLOAT
Underlying C type is float.
Definition opt.h:270
#define AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
Some filters support a generic "enable" expression option that can be used to enable or disable a fil...
Definition avfilter.h:196
#define AVFILTER_FLAG_SLICE_THREADS
The filter supports multithreading by splitting frames into multiple parts and processing them concur...
Definition avfilter.h:166
@ AVMEDIA_TYPE_VIDEO
Definition avutil.h:200
#define r
Definition input.c:42
#define b
Definition input.c:43
static int mix(int c0, int c1)
Definition 4xm.c:717
#define u(width, name, range_min, range_max)
Definition cbs_apv.c:68
const char * arg
Definition jacosubdec.c:65
#define VF
Definition af_afir.c:731
#define FILTER_INPUTS(array)
Definition filters.h:264
#define FILTER_OUTPUTS(array)
Definition filters.h:265
static int ff_slice_pos(int total, int jobnr, int nb_jobs)
Compute the boundary index for a slice when work of size total is split into nb_jobs slices.
Definition filters.h:763
#define AVFILTERPAD_FLAG_NEEDS_WRITABLE
The filter expects writable frames from its input link, duplicating data buffers if needed.
Definition filters.h:59
#define FILTER_PIXFMTS_ARRAY(array)
Definition filters.h:244
#define AVFILTER_DEFINE_CLASS(fname)
Definition filters.h:478
#define av_cold
Definition attributes.h:117
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification.
Definition internal.h:88
const char * desc
Definition libsvtav1.c:83
#define FFMIN(a, b)
Definition macros.h:49
static int slice_end(AVCodecContext *avctx, AVFrame *pict, int *got_output)
Handle slice ends.
Definition mpeg12dec.c:1697
AVOptions.
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition pixdesc.c:3460
#define AV_PIX_FMT_YUV420P16
Definition pixfmt.h:556
#define AV_PIX_FMT_YUV444P12
Definition pixfmt.h:552
#define AV_PIX_FMT_YUV444P9
Definition pixfmt.h:544
#define AV_PIX_FMT_YUV420P10
Definition pixfmt.h:545
#define AV_PIX_FMT_YUV440P12
Definition pixfmt.h:551
#define AV_PIX_FMT_YUV422P9
Definition pixfmt.h:543
#define AV_PIX_FMT_YUVA444P10
Definition pixfmt.h:598
#define AV_PIX_FMT_YUVA420P16
Definition pixfmt.h:601
#define AV_PIX_FMT_YUV420P12
Definition pixfmt.h:549
#define AV_PIX_FMT_YUVA420P10
Definition pixfmt.h:596
#define AV_PIX_FMT_YUVA422P9
Definition pixfmt.h:594
#define AV_PIX_FMT_YUV422P12
Definition pixfmt.h:550
#define AV_PIX_FMT_YUV422P10
Definition pixfmt.h:546
#define AV_PIX_FMT_YUV420P9
Definition pixfmt.h:542
#define AV_PIX_FMT_YUVA420P9
Definition pixfmt.h:593
#define AV_PIX_FMT_YUVA422P10
Definition pixfmt.h:597
#define AV_PIX_FMT_YUV420P14
Definition pixfmt.h:553
AVPixelFormat
Pixel format.
Definition pixfmt.h:71
@ AV_PIX_FMT_NONE
Definition pixfmt.h:72
@ AV_PIX_FMT_YUV420P
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition pixfmt.h:73
@ AV_PIX_FMT_YUV440P
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition pixfmt.h:106
@ AV_PIX_FMT_YUV422P
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition pixfmt.h:77
@ AV_PIX_FMT_YUVA420P
planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
Definition pixfmt.h:108
@ AV_PIX_FMT_YUVJ440P
planar YUV 4:4:0 full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV440P and setting color_range
Definition pixfmt.h:107
@ AV_PIX_FMT_YUV410P
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition pixfmt.h:79
@ AV_PIX_FMT_YUV411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition pixfmt.h:80
@ AV_PIX_FMT_YUV444P
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition pixfmt.h:78
@ AV_PIX_FMT_YUVA444P
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition pixfmt.h:174
@ AV_PIX_FMT_YUVJ411P
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples) full scale (JPEG), deprecated in favor ...
Definition pixfmt.h:283
@ AV_PIX_FMT_YUVJ422P
planar YUV 4:2:2, 16bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV422P and setting col...
Definition pixfmt.h:86
@ AV_PIX_FMT_YUVA422P
planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
Definition pixfmt.h:173
@ AV_PIX_FMT_YUVJ444P
planar YUV 4:4:4, 24bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV444P and setting col...
Definition pixfmt.h:87
@ AV_PIX_FMT_YUVJ420P
planar YUV 4:2:0, 12bpp, full scale (JPEG), deprecated in favor of AV_PIX_FMT_YUV420P and setting col...
Definition pixfmt.h:85
#define AV_PIX_FMT_YUVA422P12
Definition pixfmt.h:599
#define AV_PIX_FMT_YUV422P14
Definition pixfmt.h:554
#define AV_PIX_FMT_YUV422P16
Definition pixfmt.h:557
#define AV_PIX_FMT_YUV440P10
Definition pixfmt.h:547
#define AV_PIX_FMT_YUVA444P16
Definition pixfmt.h:603
#define AV_PIX_FMT_YUVA422P16
Definition pixfmt.h:602
#define AV_PIX_FMT_YUV444P14
Definition pixfmt.h:555
#define AV_PIX_FMT_YUVA444P9
Definition pixfmt.h:595
#define AV_PIX_FMT_YUVA444P12
Definition pixfmt.h:600
#define AV_PIX_FMT_YUV444P16
Definition pixfmt.h:558
#define AV_PIX_FMT_YUV444P10
Definition pixfmt.h:548
Describe the class of an AVClass context structure.
Definition log.h:76
An instance of a filter.
Definition avfilter.h:273
A filter pad used for either input or output.
Definition filters.h:40
This structure describes decoded (raw) audio or video data.
Definition frame.h:472
AVOption.
Definition opt.h:428
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition pixdesc.h:69
int(* do_plane_slice[2])(AVFilterContext *s, void *arg, int jobnr, int nb_jobs)
Definition vf_colorize.c:38
static AVFormatContext * ctx
Definition movenc.c:49
#define height
Definition dsp.h:89
#define width
Definition dsp.h:89
static enum AVPixelFormat pixel_fmts[]
Definition vf_amplify.c:52
static int colorize_slice8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition vf_colorize.c:93
static int do_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static float hue2rgb(float p, float q, float t)
static int colorizey_slice8(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition vf_colorize.c:47
static int colorizey_slice16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
Definition vf_colorize.c:70
static int filter_frame(AVFilterLink *inlink, AVFrame *frame)
static int colorize_slice16(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs)
static void hsl2rgb(float h, float s, float l, float *r, float *g, float *b)
static av_cold int config_input(AVFilterLink *inlink)
static void rgb2yuv(float r, float g, float b, int *y, int *u, int *v, int depth)
static float lerpf(float v0, float v1, float f)
Definition vf_colorize.c:42
static const AVFilterPad colorize_inputs[]
#define OFFSET(x)
static const AVOption colorize_options[]
const char * g
Definition vf_curves.c:128
const AVFilterPad ff_video_default_filterpad[1]
An AVFilterPad array whose only entry has name "default" and is of type AVMEDIA_TYPE_VIDEO.
Definition video.c:37
static double c[64]
static int slice_start(SliceContext *sc, VVCContext *s, VVCFrameContext *fc, const CodedBitstreamUnit *unit, const int is_first_slice)
Definition dec.c:844