2 * Copyright (c) 2002 Michael Niedermayer <michaelni@gmx.at>
3 * Copyright (c) 2013 Paul B Mahol
5 * This file is part of FFmpeg.
7 * FFmpeg is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
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 GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with FFmpeg; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 #include "libavutil/opt.h"
28 #include "libavutil/imgutils.h"
29 #include "libavutil/lfg.h"
30 #include "libavutil/parseutils.h"
31 #include "libavutil/pixdesc.h"
38 typedef struct ThreadData
{
42 #define OFFSET(x) offsetof(NoiseContext, x)
43 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
45 #define NOISE_PARAMS(name, x, param) \
46 {#name"_seed", "set component #"#x" noise seed", OFFSET(param.seed), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, FLAGS}, \
47 {#name"_strength", "set component #"#x" strength", OFFSET(param.strength), AV_OPT_TYPE_INT, {.i64=0}, 0, 100, FLAGS}, \
48 {#name"s", "set component #"#x" strength", OFFSET(param.strength), AV_OPT_TYPE_INT, {.i64=0}, 0, 100, FLAGS}, \
49 {#name"_flags", "set component #"#x" flags", OFFSET(param.flags), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 31, FLAGS, #name"_flags"}, \
50 {#name"f", "set component #"#x" flags", OFFSET(param.flags), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 31, FLAGS, #name"_flags"}, \
51 {"a", "averaged noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_AVERAGED}, 0, 0, FLAGS, #name"_flags"}, \
52 {"p", "(semi)regular pattern", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_PATTERN}, 0, 0, FLAGS, #name"_flags"}, \
53 {"t", "temporal noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_TEMPORAL}, 0, 0, FLAGS, #name"_flags"}, \
54 {"u", "uniform noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_UNIFORM}, 0, 0, FLAGS, #name"_flags"},
56 static const AVOption noise_options
[] = {
57 NOISE_PARAMS(all
, 0, all
)
58 NOISE_PARAMS(c0
, 0, param
[0])
59 NOISE_PARAMS(c1
, 1, param
[1])
60 NOISE_PARAMS(c2
, 2, param
[2])
61 NOISE_PARAMS(c3
, 3, param
[3])
65 AVFILTER_DEFINE_CLASS(noise
);
67 static const int8_t patt
[4] = { -1, 0, 1, 0 };
69 #define RAND_N(range) ((int) ((double) range * av_lfg_get(lfg) / (UINT_MAX + 1.0)))
70 static av_cold
int init_noise(NoiseContext
*n
, int comp
)
72 int8_t *noise
= av_malloc(MAX_NOISE
* sizeof(int8_t));
73 FilterParams
*fp
= &n
->param
[comp
];
74 AVLFG
*lfg
= &n
->param
[comp
].lfg
;
75 int strength
= fp
->strength
;
76 int flags
= fp
->flags
;
80 return AVERROR(ENOMEM
);
82 av_lfg_init(&fp
->lfg
, fp
->seed
+ comp
*31415U);
84 for (i
= 0, j
= 0; i
< MAX_NOISE
; i
++, j
++) {
85 if (flags
& NOISE_UNIFORM
) {
86 if (flags
& NOISE_AVERAGED
) {
87 if (flags
& NOISE_PATTERN
) {
88 noise
[i
] = (RAND_N(strength
) - strength
/ 2) / 6
89 + patt
[j
% 4] * strength
* 0.25 / 3;
91 noise
[i
] = (RAND_N(strength
) - strength
/ 2) / 3;
94 if (flags
& NOISE_PATTERN
) {
95 noise
[i
] = (RAND_N(strength
) - strength
/ 2) / 2
96 + patt
[j
% 4] * strength
* 0.25;
98 noise
[i
] = RAND_N(strength
) - strength
/ 2;
102 double x1
, x2
, w
, y1
;
104 x1
= 2.0 * av_lfg_get(lfg
) / (float)UINT_MAX
- 1.0;
105 x2
= 2.0 * av_lfg_get(lfg
) / (float)UINT_MAX
- 1.0;
106 w
= x1
* x1
+ x2
* x2
;
109 w
= sqrt((-2.0 * log(w
)) / w
);
111 y1
*= strength
/ sqrt(3.0);
112 if (flags
& NOISE_PATTERN
) {
114 y1
+= patt
[j
% 4] * strength
* 0.35;
116 y1
= av_clipf(y1
, -128, 127);
117 if (flags
& NOISE_AVERAGED
)
125 for (i
= 0; i
< MAX_RES
; i
++)
126 for (j
= 0; j
< 3; j
++)
127 fp
->prev_shift
[i
][j
] = noise
+ (av_lfg_get(lfg
) & (MAX_SHIFT
- 1));
133 static int query_formats(AVFilterContext
*ctx
)
135 AVFilterFormats
*formats
= NULL
;
138 for (fmt
= 0; av_pix_fmt_desc_get(fmt
); fmt
++) {
139 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(fmt
);
140 if (desc
->flags
& AV_PIX_FMT_FLAG_PLANAR
&& !((desc
->comp
[0].depth_minus1
+ 1) & 7))
141 ff_add_format(&formats
, fmt
);
144 ff_set_common_formats(ctx
, formats
);
148 static int config_input(AVFilterLink
*inlink
)
150 NoiseContext
*n
= inlink
->dst
->priv
;
151 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(inlink
->format
);
154 n
->nb_planes
= av_pix_fmt_count_planes(inlink
->format
);
156 if ((ret
= av_image_fill_linesizes(n
->bytewidth
, inlink
->format
, inlink
->w
)) < 0)
159 n
->height
[1] = n
->height
[2] = FF_CEIL_RSHIFT(inlink
->h
, desc
->log2_chroma_h
);
160 n
->height
[0] = n
->height
[3] = inlink
->h
;
165 void ff_line_noise_c(uint8_t *dst
, const uint8_t *src
, const int8_t *noise
,
171 for (i
= 0; i
< len
; i
++) {
172 int v
= src
[i
] + noise
[i
];
174 dst
[i
] = av_clip_uint8(v
);
178 void ff_line_noise_avg_c(uint8_t *dst
, const uint8_t *src
,
179 int len
, const int8_t * const *shift
)
182 const int8_t *src2
= (const int8_t*)src
;
184 for (i
= 0; i
< len
; i
++) {
185 const int n
= shift
[0][i
] + shift
[1][i
] + shift
[2][i
];
186 dst
[i
] = src2
[i
] + ((n
* src2
[i
]) >> 7);
190 static void noise(uint8_t *dst
, const uint8_t *src
,
191 int dst_linesize
, int src_linesize
,
192 int width
, int start
, int end
, NoiseContext
*n
, int comp
)
194 FilterParams
*p
= &n
->param
[comp
];
195 int8_t *noise
= p
->noise
;
196 const int flags
= p
->flags
;
201 av_image_copy_plane(dst
, dst_linesize
, src
, src_linesize
, width
, end
- start
);
205 for (y
= start
; y
< end
; y
++) {
206 const int ix
= y
& (MAX_RES
- 1);
208 for (x
=0; x
< width
; x
+= MAX_RES
) {
209 int w
= FFMIN(width
- x
, MAX_RES
);
210 int shift
= p
->rand_shift
[ix
];
212 if (flags
& NOISE_AVERAGED
) {
213 n
->line_noise_avg(dst
+ x
, src
+ x
, w
, (const int8_t**)p
->prev_shift
[ix
]);
214 p
->prev_shift
[ix
][shift
& 3] = noise
+ shift
;
216 n
->line_noise(dst
+ x
, src
+ x
, noise
, w
, shift
);
224 static int filter_slice(AVFilterContext
*ctx
, void *arg
, int jobnr
, int nb_jobs
)
226 NoiseContext
*s
= ctx
->priv
;
227 ThreadData
*td
= arg
;
230 for (plane
= 0; plane
< s
->nb_planes
; plane
++) {
231 const int height
= s
->height
[plane
];
232 const int start
= (height
* jobnr
) / nb_jobs
;
233 const int end
= (height
* (jobnr
+1)) / nb_jobs
;
234 noise(td
->out
->data
[plane
] + start
* td
->out
->linesize
[plane
],
235 td
->in
->data
[plane
] + start
* td
->in
->linesize
[plane
],
236 td
->out
->linesize
[plane
], td
->in
->linesize
[plane
],
237 s
->bytewidth
[plane
], start
, end
, s
, plane
);
242 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*inpicref
)
244 AVFilterContext
*ctx
= inlink
->dst
;
245 AVFilterLink
*outlink
= ctx
->outputs
[0];
246 NoiseContext
*n
= ctx
->priv
;
251 if (av_frame_is_writable(inpicref
)) {
254 out
= ff_get_video_buffer(outlink
, outlink
->w
, outlink
->h
);
256 av_frame_free(&inpicref
);
257 return AVERROR(ENOMEM
);
259 av_frame_copy_props(out
, inpicref
);
262 for (comp
= 0; comp
< 4; comp
++) {
263 FilterParams
*fp
= &n
->param
[comp
];
265 if ((!fp
->rand_shift_init
|| (fp
->flags
& NOISE_TEMPORAL
)) && fp
->strength
) {
267 for (i
= 0; i
< MAX_RES
; i
++) {
268 fp
->rand_shift
[i
] = av_lfg_get(&fp
->lfg
) & (MAX_SHIFT
- 1);
270 fp
->rand_shift_init
= 1;
274 td
.in
= inpicref
; td
.out
= out
;
275 ctx
->internal
->execute(ctx
, filter_slice
, &td
, NULL
, FFMIN(n
->height
[0], ctx
->graph
->nb_threads
));
279 av_frame_free(&inpicref
);
280 return ff_filter_frame(outlink
, out
);
283 static av_cold
int init(AVFilterContext
*ctx
)
285 NoiseContext
*n
= ctx
->priv
;
288 for (i
= 0; i
< 4; i
++) {
289 if (n
->all
.seed
>= 0)
290 n
->param
[i
].seed
= n
->all
.seed
;
292 n
->param
[i
].seed
= 123457;
294 n
->param
[i
].strength
= n
->all
.strength
;
296 n
->param
[i
].flags
= n
->all
.flags
;
299 for (i
= 0; i
< 4; i
++) {
300 if (n
->param
[i
].strength
&& ((ret
= init_noise(n
, i
)) < 0))
304 n
->line_noise
= ff_line_noise_c
;
305 n
->line_noise_avg
= ff_line_noise_avg_c
;
308 ff_noise_init_x86(n
);
313 static av_cold
void uninit(AVFilterContext
*ctx
)
315 NoiseContext
*n
= ctx
->priv
;
318 for (i
= 0; i
< 4; i
++)
319 av_freep(&n
->param
[i
].noise
);
322 static const AVFilterPad noise_inputs
[] = {
325 .type
= AVMEDIA_TYPE_VIDEO
,
326 .filter_frame
= filter_frame
,
327 .config_props
= config_input
,
332 static const AVFilterPad noise_outputs
[] = {
335 .type
= AVMEDIA_TYPE_VIDEO
,
340 AVFilter ff_vf_noise
= {
342 .description
= NULL_IF_CONFIG_SMALL("Add noise."),
343 .priv_size
= sizeof(NoiseContext
),
346 .query_formats
= query_formats
,
347 .inputs
= noise_inputs
,
348 .outputs
= noise_outputs
,
349 .priv_class
= &noise_class
,
350 .flags
= AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
| AVFILTER_FLAG_SLICE_THREADS
,