vf_hue.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2003 Michael Niedermayer
3  * Copyright (c) 2012 Jeremy Tran
4  *
5  * This file is part of FFmpeg.
6  *
7  * FFmpeg is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * FFmpeg is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License along
18  * with FFmpeg; if not, write to the Free Software Foundation, Inc.,
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20  */
21 
22 /**
23  * @file
24  * Apply a hue/saturation filter to the input video
25  * Ported from MPlayer libmpcodecs/vf_hue.c.
26  */
27 
28 #include <float.h>
29 #include "libavutil/eval.h"
30 #include "libavutil/imgutils.h"
31 #include "libavutil/opt.h"
32 #include "libavutil/pixdesc.h"
33 
34 #include "avfilter.h"
35 #include "formats.h"
36 #include "internal.h"
37 #include "video.h"
38 
39 #define SAT_MIN_VAL -10
40 #define SAT_MAX_VAL 10
41 
42 static const char *const var_names[] = {
43  "n", // frame count
44  "pts", // presentation timestamp expressed in AV_TIME_BASE units
45  "r", // frame rate
46  "t", // timestamp expressed in seconds
47  "tb", // timebase
48  NULL
49 };
50 
51 enum var_name {
58 };
59 
60 typedef struct {
61  const AVClass *class;
62  float hue_deg; /* hue expressed in degrees */
63  float hue; /* hue expressed in radians */
64  char *hue_deg_expr;
65  char *hue_expr;
68  float saturation;
71  int hsub;
72  int vsub;
75  double var_values[VAR_NB];
76 } HueContext;
77 
78 #define OFFSET(x) offsetof(HueContext, x)
79 #define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
80 static const AVOption hue_options[] = {
81  { "h", "set the hue angle degrees expression", OFFSET(hue_deg_expr), AV_OPT_TYPE_STRING,
82  { .str = NULL }, .flags = FLAGS },
83  { "s", "set the saturation expression", OFFSET(saturation_expr), AV_OPT_TYPE_STRING,
84  { .str = "1" }, .flags = FLAGS },
85  { "H", "set the hue angle radians expression", OFFSET(hue_expr), AV_OPT_TYPE_STRING,
86  { .str = NULL }, .flags = FLAGS },
87  { NULL }
88 };
89 
91 
92 static inline void compute_sin_and_cos(HueContext *hue)
93 {
94  /*
95  * Scale the value to the norm of the resulting (U,V) vector, that is
96  * the saturation.
97  * This will be useful in the process_chrominance function.
98  */
99  hue->hue_sin = rint(sin(hue->hue) * (1 << 16) * hue->saturation);
100  hue->hue_cos = rint(cos(hue->hue) * (1 << 16) * hue->saturation);
101 }
102 
103 static int set_expr(AVExpr **pexpr, const char *expr, const char *option, void *log_ctx)
104 {
105  int ret;
106  AVExpr *old = NULL;
107 
108  if (*pexpr)
109  old = *pexpr;
110  ret = av_expr_parse(pexpr, expr, var_names,
111  NULL, NULL, NULL, NULL, 0, log_ctx);
112  if (ret < 0) {
113  av_log(log_ctx, AV_LOG_ERROR,
114  "Error when evaluating the expression '%s' for %s\n",
115  expr, option);
116  *pexpr = old;
117  return ret;
118  }
119  av_expr_free(old);
120  return 0;
121 }
122 
123 static av_cold int init(AVFilterContext *ctx)
124 {
125  HueContext *hue = ctx->priv;
126  int ret;
127 
128  if (hue->hue_expr && hue->hue_deg_expr) {
129  av_log(ctx, AV_LOG_ERROR,
130  "H and h options are incompatible and cannot be specified "
131  "at the same time\n");
132  return AVERROR(EINVAL);
133  }
134 
135 #define SET_EXPR(expr, option) \
136  if (hue->expr##_expr) do { \
137  ret = set_expr(&hue->expr##_pexpr, hue->expr##_expr, option, ctx); \
138  if (ret < 0) \
139  return ret; \
140  } while (0)
141  SET_EXPR(saturation, "s");
142  SET_EXPR(hue_deg, "h");
143  SET_EXPR(hue, "H");
144 
145  av_log(ctx, AV_LOG_VERBOSE,
146  "H_expr:%s h_deg_expr:%s s_expr:%s\n",
147  hue->hue_expr, hue->hue_deg_expr, hue->saturation_expr);
148  compute_sin_and_cos(hue);
149 
150  return 0;
151 }
152 
153 static av_cold void uninit(AVFilterContext *ctx)
154 {
155  HueContext *hue = ctx->priv;
156 
158  av_expr_free(hue->hue_pexpr);
160 }
161 
163 {
164  static const enum AVPixelFormat pix_fmts[] = {
171  };
172 
174 
175  return 0;
176 }
177 
178 static int config_props(AVFilterLink *inlink)
179 {
180  HueContext *hue = inlink->dst->priv;
181  const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(inlink->format);
182 
183  hue->hsub = desc->log2_chroma_w;
184  hue->vsub = desc->log2_chroma_h;
185 
186  hue->var_values[VAR_N] = 0;
187  hue->var_values[VAR_TB] = av_q2d(inlink->time_base);
188  hue->var_values[VAR_R] = inlink->frame_rate.num == 0 || inlink->frame_rate.den == 0 ?
189  NAN : av_q2d(inlink->frame_rate);
190 
191  return 0;
192 }
193 
194 static void process_chrominance(uint8_t *udst, uint8_t *vdst, const int dst_linesize,
195  uint8_t *usrc, uint8_t *vsrc, const int src_linesize,
196  int w, int h,
197  const int32_t c, const int32_t s)
198 {
199  int32_t u, v, new_u, new_v;
200  int i;
201 
202  /*
203  * If we consider U and V as the components of a 2D vector then its angle
204  * is the hue and the norm is the saturation
205  */
206  while (h--) {
207  for (i = 0; i < w; i++) {
208  /* Normalize the components from range [16;140] to [-112;112] */
209  u = usrc[i] - 128;
210  v = vsrc[i] - 128;
211  /*
212  * Apply the rotation of the vector : (c * u) - (s * v)
213  * (s * u) + (c * v)
214  * De-normalize the components (without forgetting to scale 128
215  * by << 16)
216  * Finally scale back the result by >> 16
217  */
218  new_u = ((c * u) - (s * v) + (1 << 15) + (128 << 16)) >> 16;
219  new_v = ((s * u) + (c * v) + (1 << 15) + (128 << 16)) >> 16;
220 
221  /* Prevent a potential overflow */
222  udst[i] = av_clip_uint8_c(new_u);
223  vdst[i] = av_clip_uint8_c(new_v);
224  }
225 
226  usrc += src_linesize;
227  vsrc += src_linesize;
228  udst += dst_linesize;
229  vdst += dst_linesize;
230  }
231 }
232 
233 #define TS2D(ts) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts))
234 #define TS2T(ts, tb) ((ts) == AV_NOPTS_VALUE ? NAN : (double)(ts) * av_q2d(tb))
235 
236 static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
237 {
238  HueContext *hue = inlink->dst->priv;
239  AVFilterLink *outlink = inlink->dst->outputs[0];
240  AVFrame *outpic;
241  int direct = 0;
242 
243  if (av_frame_is_writable(inpic)) {
244  direct = 1;
245  outpic = inpic;
246  } else {
247  outpic = ff_get_video_buffer(outlink, outlink->w, outlink->h);
248  if (!outpic) {
249  av_frame_free(&inpic);
250  return AVERROR(ENOMEM);
251  }
252  av_frame_copy_props(outpic, inpic);
253  }
254 
255  hue->var_values[VAR_T] = TS2T(inpic->pts, inlink->time_base);
256  hue->var_values[VAR_PTS] = TS2D(inpic->pts);
257 
258  if (hue->saturation_expr) {
260 
261  if (hue->saturation < SAT_MIN_VAL || hue->saturation > SAT_MAX_VAL) {
262  hue->saturation = av_clip(hue->saturation, SAT_MIN_VAL, SAT_MAX_VAL);
263  av_log(inlink->dst, AV_LOG_WARNING,
264  "Saturation value not in range [%d,%d]: clipping value to %0.1f\n",
266  }
267  }
268 
269  if (hue->hue_deg_expr) {
270  hue->hue_deg = av_expr_eval(hue->hue_deg_pexpr, hue->var_values, NULL);
271  hue->hue = hue->hue_deg * M_PI / 180;
272  } else if (hue->hue_expr) {
273  hue->hue = av_expr_eval(hue->hue_pexpr, hue->var_values, NULL);
274  hue->hue_deg = hue->hue * 180 / M_PI;
275  }
276 
277  av_log(inlink->dst, AV_LOG_DEBUG,
278  "H:%0.1f*PI h:%0.1f s:%0.f t:%0.1f n:%d\n",
279  hue->hue/M_PI, hue->hue_deg, hue->saturation,
280  hue->var_values[VAR_T], (int)hue->var_values[VAR_N]);
281 
282  compute_sin_and_cos(hue);
283 
284  hue->var_values[VAR_N] += 1;
285 
286  if (!direct) {
287  av_image_copy_plane(outpic->data[0], outpic->linesize[0],
288  inpic->data[0], inpic->linesize[0],
289  inlink->w, inlink->h);
290  if (inpic->data[3])
291  av_image_copy_plane(outpic->data[3], outpic->linesize[3],
292  inpic->data[3], inpic->linesize[3],
293  inlink->w, inlink->h);
294  }
295 
296  process_chrominance(outpic->data[1], outpic->data[2], outpic->linesize[1],
297  inpic->data[1], inpic->data[2], inpic->linesize[1],
298  inlink->w >> hue->hsub, inlink->h >> hue->vsub,
299  hue->hue_cos, hue->hue_sin);
300 
301  if (!direct)
302  av_frame_free(&inpic);
303  return ff_filter_frame(outlink, outpic);
304 }
305 
306 static int process_command(AVFilterContext *ctx, const char *cmd, const char *args,
307  char *res, int res_len, int flags)
308 {
309  HueContext *hue = ctx->priv;
310 
311 #define SET_CMD(expr, option) do { \
312  if (!strcmp(cmd, option)) \
313  return set_expr(&hue->expr##_pexpr, args, cmd, ctx); \
314 } while (0)
315  SET_CMD(hue_deg, "h");
316  SET_CMD(hue, "H");
317  SET_CMD(saturation, "s");
318 
319  return AVERROR(ENOSYS);
320 }
321 
322 static const AVFilterPad hue_inputs[] = {
323  {
324  .name = "default",
325  .type = AVMEDIA_TYPE_VIDEO,
326  .filter_frame = filter_frame,
327  .config_props = config_props,
328  },
329  { NULL }
330 };
331 
332 static const AVFilterPad hue_outputs[] = {
333  {
334  .name = "default",
335  .type = AVMEDIA_TYPE_VIDEO,
336  },
337  { NULL }
338 };
339 
341  .name = "hue",
342  .description = NULL_IF_CONFIG_SMALL("Adjust the hue and saturation of the input video."),
343 
344  .priv_size = sizeof(HueContext),
345 
346  .init = init,
347  .uninit = uninit,
350  .inputs = hue_inputs,
351  .outputs = hue_outputs,
352  .priv_class = &hue_class,
353 };
Definition: vf_hue.c:55
float v
const char * s
Definition: avisynth_c.h:668
int av_frame_copy_props(AVFrame *dst, const AVFrame *src)
Copy only "metadata" fields from src to dst.
Definition: frame.c:424
const AVPixFmtDescriptor * av_pix_fmt_desc_get(enum AVPixelFormat pix_fmt)
Definition: pixdesc.c:1778
This structure describes decoded (raw) audio or video data.
Definition: frame.h:76
static double rint(double x)
Definition: libm.h:141
double var_values[VAR_NB]
Definition: vf_hue.c:75
AVOption.
Definition: opt.h:251
planar YUV 4:4:4, 24bpp, (1 Cr & Cb sample per 1x1 Y samples)
Definition: pixfmt.h:73
misc image utilities
static const AVFilterPad outputs[]
Definition: af_ashowinfo.c:117
external API header
#define SAT_MAX_VAL
Definition: vf_hue.c:40
#define AV_LOG_WARNING
Something somehow does not look correct.
Definition: log.h:154
int num
numerator
Definition: rational.h:44
static int query_formats(AVFilterContext *ctx)
Definition: vf_hue.c:162
int32_t hue_sin
Definition: vf_hue.c:73
static const AVFilterPad hue_inputs[]
Definition: vf_hue.c:322
#define FLAGS
Definition: vf_hue.c:79
int av_expr_parse(AVExpr **expr, const char *s, const char *const *const_names, const char *const *func1_names, double(*const *funcs1)(void *, double), const char *const *func2_names, double(*const *funcs2)(void *, double, double), int log_offset, void *log_ctx)
Parse an expression.
Definition: eval.c:640
AVFrame * ff_get_video_buffer(AVFilterLink *link, int w, int h)
Request a picture buffer with a specific set of permissions.
Definition: video.c:143
uint8_t log2_chroma_w
Amount to shift the luma width right to find the chroma width.
Definition: pixdesc.h:66
output residual component w
Definition: vf_hue.c:56
char * saturation_expr
Definition: vf_hue.c:69
AVFilterFormats * ff_make_format_list(const int *fmts)
Create a list of supported formats.
Definition: formats.c:308
#define SET_EXPR(expr, option)
int hsub
Definition: vf_hue.c:71
const char * name
Pad name.
planar YUV 4:2:0, 20bpp, (1 Cr & Cb sample per 2x2 Y & A samples)
Definition: pixfmt.h:105
uint8_t
static void compute_sin_and_cos(HueContext *hue)
Definition: vf_hue.c:92
it can be given away to ff_start_frame *A reference passed to ff_filter_frame(or the deprecated ff_start_frame) is given away and must no longer be used.*A reference created with avfilter_ref_buffer belongs to the code that created it.*A reference obtained with ff_get_video_buffer or ff_get_audio_buffer belongs to the code that requested it.*A reference given as return value by the get_video_buffer or get_audio_buffer method is given away and must no longer be used.Link reference fields---------------------The AVFilterLink structure has a few AVFilterBufferRef fields.The cur_buf and out_buf were used with the deprecated start_frame/draw_slice/end_frame API and should no longer be used.src_buf
#define av_cold
Definition: attributes.h:78
AVOptions.
#define NAN
Definition: math.h:7
int64_t pts
Presentation timestamp in time_base units (time when frame should be shown to user).
Definition: frame.h:159
Definition: eval.c:140
static double av_q2d(AVRational a)
Convert rational to double.
Definition: rational.h:69
char * hue_deg_expr
Definition: vf_hue.c:64
void ff_set_common_formats(AVFilterContext *ctx, AVFilterFormats *formats)
A helper for query_formats() which sets all links to the same list of formats.
Definition: formats.c:545
float hue_deg
Definition: vf_hue.c:62
Definition: vf_hue.c:52
A filter pad used for either input or output.
static int process_command(AVFilterContext *ctx, const char *cmd, const char *args, char *res, int res_len, int flags)
Definition: vf_hue.c:306
planar YUV 4:2:2 24bpp, (1 Cr & Cb sample per 2x1 Y & A samples)
Definition: pixfmt.h:219
uint8_t log2_chroma_h
Amount to shift the luma height right to find the chroma height.
Definition: pixdesc.h:75
static av_cold int init(AVFilterContext *ctx)
Definition: vf_hue.c:123
#define SAT_MIN_VAL
Definition: vf_hue.c:39
#define NULL_IF_CONFIG_SMALL(x)
Return NULL if CONFIG_SMALL is true, otherwise the argument without modification. ...
void * priv
private data for use by the filter
Definition: avfilter.h:545
AVExpr * saturation_pexpr
Definition: vf_hue.c:70
int av_frame_is_writable(AVFrame *frame)
Check if the frame data is writable.
Definition: frame.c:361
void av_log(void *avcl, int level, const char *fmt,...)
Definition: log.c:246
float saturation
Definition: vf_hue.c:68
float hue
Definition: vf_hue.c:63
static av_always_inline av_const uint8_t av_clip_uint8_c(int a)
Clip a signed integer value into the 0-255 range.
Definition: common.h:129
static int filter_frame(AVFilterLink *inlink, AVFrame *inpic)
Definition: vf_hue.c:236
planar YUV 4:2:2, 16bpp, (1 Cr & Cb sample per 2x1 Y samples)
Definition: pixfmt.h:72
#define AV_LOG_VERBOSE
Definition: log.h:157
AVFilter avfilter_vf_hue
Definition: vf_hue.c:340
var_name
Definition: vf_hue.c:54
ret
Definition: avfilter.c:821
int32_t
float u
AVFILTER_DEFINE_CLASS(hue)
AVExpr * hue_pexpr
Definition: vf_hue.c:67
#define TS2T(ts, tb)
Definition: vf_hue.c:234
NULL
Definition: eval.c:55
int32_t hue_cos
Definition: vf_hue.c:74
static int set_expr(AVExpr **pexpr, const char *expr, const char *option, void *log_ctx)
Definition: vf_hue.c:103
void av_expr_free(AVExpr *e)
Free a parsed expression previously created with av_expr_parse().
Definition: eval.c:302
static av_cold void uninit(AVFilterContext *ctx)
Definition: vf_hue.c:153
int linesize[AV_NUM_DATA_POINTERS]
For video, size in bytes of each picture line.
Definition: frame.h:101
planar YUV 4:4:4 32bpp, (1 Cr & Cb sample per 1x1 Y & A samples)
Definition: pixfmt.h:218
Descriptor that unambiguously describes how the bits of a pixel are stored in the up to 4 data planes...
Definition: pixdesc.h:55
AVExpr * hue_deg_pexpr
Definition: vf_hue.c:66
#define AV_LOG_ERROR
Something went wrong and cannot losslessly be recovered.
Definition: log.h:148
Definition: vf_hue.c:53
planar YUV 4:1:0, 9bpp, (1 Cr & Cb sample per 4x4 Y samples)
Definition: pixfmt.h:74
Describe the class of an AVClass context structure.
Definition: log.h:50
Filter definition.
Definition: avfilter.h:436
synthesis window for stochastic i
const char * name
filter name
Definition: avfilter.h:437
static const AVOption hue_options[]
Definition: vf_hue.c:80
static const AVFilterPad hue_outputs[]
Definition: vf_hue.c:332
Filter the word “frame” indicates either a video frame or a group of audio as stored in an AVFilterBuffer structure Format for each input and each output the list of supported formats For video that means pixel format For audio that means channel sample they are references to shared objects When the negotiation mechanism computes the intersection of the formats supported at each end of a all references to both lists are replaced with a reference to the intersection And when a single format is eventually chosen for a link amongst the remaining all references to the list are updated That means that if a filter requires that its input and output have the same format amongst a supported all it has to do is use a reference to the same list of formats query_formats can leave some formats unset and return AVERROR(EAGAIN) to cause the negotiation mechanism toagain later.That can be used by filters with complex requirements to use the format negotiated on one link to set the formats supported on another.Buffer references ownership and permissions
option
Definition: dnxhdenc.c:49
AVFilterLink ** outputs
array of pointers to output links
Definition: avfilter.h:539
static int flags
Definition: cpu.c:23
uint8_t * data[AV_NUM_DATA_POINTERS]
pointer to the picture/channel planes.
Definition: frame.h:87
static void process_chrominance(uint8_t *udst, uint8_t *vdst, const int dst_linesize, uint8_t *usrc, uint8_t *vsrc, const int src_linesize, int w, int h, const int32_t c, const int32_t s)
Definition: vf_hue.c:194
char * hue_expr
Definition: vf_hue.c:65
Definition: vf_hue.c:57
planar YUV 4:2:0, 12bpp, (1 Cr & Cb sample per 2x2 Y samples)
Definition: pixfmt.h:68
#define AV_LOG_DEBUG
Stuff which is only useful for libav* developers.
Definition: log.h:162
void av_frame_free(AVFrame **frame)
Free the frame and any dynamically allocated objects in it, e.g.
Definition: frame.c:108
static double c[64]
planar YUV 4:1:1, 12bpp, (1 Cr & Cb sample per 4x1 Y samples)
Definition: pixfmt.h:75
int vsub
Definition: vf_hue.c:72
int den
denominator
Definition: rational.h:45
#define OFFSET(x)
Definition: vf_hue.c:78
double av_expr_eval(AVExpr *e, const double *const_values, void *opaque)
Evaluate a previously parsed expression.
Definition: eval.c:691
#define TS2D(ts)
Definition: vf_hue.c:233
An instance of a filter.
Definition: avfilter.h:524
planar YUV 4:4:0 (1 Cr & Cb sample per 1x2 Y samples)
Definition: pixfmt.h:103
#define SET_CMD(expr, option)
#define M_PI
Definition: mathematics.h:46
void av_image_copy_plane(uint8_t *dst, int dst_linesize, const uint8_t *src, int src_linesize, int bytewidth, int height)
Copy image plane from src to dst.
Definition: imgutils.c:242
internal API functions
static int config_props(AVFilterLink *inlink)
Definition: vf_hue.c:178
AVPixelFormat
Pixel format.
Definition: pixfmt.h:66
these buffered frames must be flushed immediately if a new input produces new the filter must not call request_frame to get more It must just process the frame or queue it The task of requesting more frames is left to the filter s request_frame method or the application If a filter has several inputs
static const char *const var_names[]
Definition: vf_hue.c:42
simple arithmetic expression evaluator