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/emms.h"
28 #include "libavutil/mem.h"
29 #include "libavutil/opt.h"
30 #include "libavutil/imgutils.h"
31 #include "libavutil/lfg.h"
32 #include "libavutil/pixdesc.h"
39 typedef struct ThreadData
{
43 #define OFFSET(x) offsetof(NoiseContext, x)
44 #define FLAGS AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM
46 #define NOISE_PARAMS(name, x, param) \
47 {#name"_seed", "set component #"#x" noise seed", OFFSET(param.seed), AV_OPT_TYPE_INT, {.i64=-1}, -1, INT_MAX, FLAGS}, \
48 {#name"_strength", "set component #"#x" strength", OFFSET(param.strength), AV_OPT_TYPE_INT, {.i64=0}, 0, 100, FLAGS}, \
49 {#name"s", "set component #"#x" strength", OFFSET(param.strength), AV_OPT_TYPE_INT, {.i64=0}, 0, 100, FLAGS}, \
50 {#name"_flags", "set component #"#x" flags", OFFSET(param.flags), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 31, FLAGS, .unit = #name"_flags"}, \
51 {#name"f", "set component #"#x" flags", OFFSET(param.flags), AV_OPT_TYPE_FLAGS, {.i64=0}, 0, 31, FLAGS, .unit = #name"_flags"}, \
52 {"a", "averaged noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_AVERAGED}, 0, 0, FLAGS, .unit = #name"_flags"}, \
53 {"p", "(semi)regular pattern", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_PATTERN}, 0, 0, FLAGS, .unit = #name"_flags"}, \
54 {"t", "temporal noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_TEMPORAL}, 0, 0, FLAGS, .unit = #name"_flags"}, \
55 {"u", "uniform noise", 0, AV_OPT_TYPE_CONST, {.i64=NOISE_UNIFORM}, 0, 0, FLAGS, .unit = #name"_flags"},
57 static const AVOption noise_options
[] = {
58 NOISE_PARAMS(all
, 0, all
)
59 NOISE_PARAMS(c0
, 0, param
[0])
60 NOISE_PARAMS(c1
, 1, param
[1])
61 NOISE_PARAMS(c2
, 2, param
[2])
62 NOISE_PARAMS(c3
, 3, param
[3])
66 AVFILTER_DEFINE_CLASS(noise
);
68 static const int8_t patt
[4] = { -1, 0, 1, 0 };
70 #define RAND_N(range) ((int) ((double) range * av_lfg_get(lfg) / (UINT_MAX + 1.0)))
71 static av_cold
int init_noise(NoiseContext
*n
, int comp
)
73 int8_t *noise
= av_malloc(MAX_NOISE
* sizeof(int8_t));
74 FilterParams
*fp
= &n
->param
[comp
];
75 AVLFG
*lfg
= &n
->param
[comp
].lfg
;
76 int strength
= fp
->strength
;
77 int flags
= fp
->flags
;
81 return AVERROR(ENOMEM
);
83 av_lfg_init(&fp
->lfg
, fp
->seed
+ comp
*31415U);
85 for (i
= 0, j
= 0; i
< MAX_NOISE
; i
++, j
++) {
86 if (flags
& NOISE_UNIFORM
) {
87 if (flags
& NOISE_AVERAGED
) {
88 if (flags
& NOISE_PATTERN
) {
89 noise
[i
] = (RAND_N(strength
) - strength
/ 2) / 6
90 + patt
[j
% 4] * strength
* 0.25 / 3;
92 noise
[i
] = (RAND_N(strength
) - strength
/ 2) / 3;
95 if (flags
& NOISE_PATTERN
) {
96 noise
[i
] = (RAND_N(strength
) - strength
/ 2) / 2
97 + patt
[j
% 4] * strength
* 0.25;
99 noise
[i
] = RAND_N(strength
) - strength
/ 2;
103 double x1
, x2
, w
, y1
;
105 x1
= 2.0 * av_lfg_get(lfg
) / (float)UINT_MAX
- 1.0;
106 x2
= 2.0 * av_lfg_get(lfg
) / (float)UINT_MAX
- 1.0;
107 w
= x1
* x1
+ x2
* x2
;
110 w
= sqrt((-2.0 * log(w
)) / w
);
112 y1
*= strength
/ sqrt(3.0);
113 if (flags
& NOISE_PATTERN
) {
115 y1
+= patt
[j
% 4] * strength
* 0.35;
117 y1
= av_clipf(y1
, -128, 127);
118 if (flags
& NOISE_AVERAGED
)
126 for (i
= 0; i
< MAX_RES
; i
++)
127 for (j
= 0; j
< 3; j
++)
128 fp
->prev_shift
[i
][j
] = noise
+ (av_lfg_get(lfg
) & (MAX_SHIFT
- 1));
134 static int query_formats(const AVFilterContext
*ctx
,
135 AVFilterFormatsConfig
**cfg_in
,
136 AVFilterFormatsConfig
**cfg_out
)
138 AVFilterFormats
*formats
= NULL
;
141 for (fmt
= 0; av_pix_fmt_desc_get(fmt
); fmt
++) {
142 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(fmt
);
143 if (desc
->flags
& AV_PIX_FMT_FLAG_PLANAR
&& !(desc
->comp
[0].depth
& 7)
144 && (ret
= ff_add_format(&formats
, fmt
)) < 0)
148 return ff_set_common_formats2(ctx
, cfg_in
, cfg_out
, formats
);
151 static int config_input(AVFilterLink
*inlink
)
153 NoiseContext
*n
= inlink
->dst
->priv
;
154 const AVPixFmtDescriptor
*desc
= av_pix_fmt_desc_get(inlink
->format
);
157 n
->nb_planes
= av_pix_fmt_count_planes(inlink
->format
);
159 if ((ret
= av_image_fill_linesizes(n
->bytewidth
, inlink
->format
, inlink
->w
)) < 0)
162 n
->height
[1] = n
->height
[2] = AV_CEIL_RSHIFT(inlink
->h
, desc
->log2_chroma_h
);
163 n
->height
[0] = n
->height
[3] = inlink
->h
;
168 void ff_line_noise_c(uint8_t *dst
, const uint8_t *src
, const int8_t *noise
,
174 for (i
= 0; i
< len
; i
++) {
175 int v
= src
[i
] + noise
[i
];
177 dst
[i
] = av_clip_uint8(v
);
181 void ff_line_noise_avg_c(uint8_t *dst
, const uint8_t *src
,
182 int len
, const int8_t * const *shift
)
185 const int8_t *src2
= (const int8_t*)src
;
187 for (i
= 0; i
< len
; i
++) {
188 const int n
= shift
[0][i
] + shift
[1][i
] + shift
[2][i
];
189 dst
[i
] = src2
[i
] + ((n
* src2
[i
]) >> 7);
193 static void noise(uint8_t *dst
, const uint8_t *src
,
194 int dst_linesize
, int src_linesize
,
195 int width
, int start
, int end
, NoiseContext
*n
, int comp
)
197 FilterParams
*p
= &n
->param
[comp
];
198 int8_t *noise
= p
->noise
;
199 const int flags
= p
->flags
;
204 av_image_copy_plane(dst
, dst_linesize
, src
, src_linesize
, width
, end
- start
);
208 for (y
= start
; y
< end
; y
++) {
209 const int ix
= y
& (MAX_RES
- 1);
211 for (x
=0; x
< width
; x
+= MAX_RES
) {
212 int w
= FFMIN(width
- x
, MAX_RES
);
213 int shift
= p
->rand_shift
[ix
];
215 if (flags
& NOISE_AVERAGED
) {
216 n
->line_noise_avg(dst
+ x
, src
+ x
, w
, (const int8_t**)p
->prev_shift
[ix
]);
217 p
->prev_shift
[ix
][shift
& 3] = noise
+ shift
;
219 n
->line_noise(dst
+ x
, src
+ x
, noise
, w
, shift
);
227 static int filter_slice(AVFilterContext
*ctx
, void *arg
, int jobnr
, int nb_jobs
)
229 NoiseContext
*s
= ctx
->priv
;
230 ThreadData
*td
= arg
;
233 for (plane
= 0; plane
< s
->nb_planes
; plane
++) {
234 const int height
= s
->height
[plane
];
235 const int start
= (height
* jobnr
) / nb_jobs
;
236 const int end
= (height
* (jobnr
+1)) / nb_jobs
;
237 noise(td
->out
->data
[plane
] + start
* td
->out
->linesize
[plane
],
238 td
->in
->data
[plane
] + start
* td
->in
->linesize
[plane
],
239 td
->out
->linesize
[plane
], td
->in
->linesize
[plane
],
240 s
->bytewidth
[plane
], start
, end
, s
, plane
);
245 static int filter_frame(AVFilterLink
*inlink
, AVFrame
*inpicref
)
247 AVFilterContext
*ctx
= inlink
->dst
;
248 AVFilterLink
*outlink
= ctx
->outputs
[0];
249 NoiseContext
*n
= ctx
->priv
;
254 if (av_frame_is_writable(inpicref
)) {
257 out
= ff_get_video_buffer(outlink
, outlink
->w
, outlink
->h
);
259 av_frame_free(&inpicref
);
260 return AVERROR(ENOMEM
);
262 av_frame_copy_props(out
, inpicref
);
265 for (comp
= 0; comp
< 4; comp
++) {
266 FilterParams
*fp
= &n
->param
[comp
];
268 if ((!fp
->rand_shift_init
|| (fp
->flags
& NOISE_TEMPORAL
)) && fp
->strength
) {
270 for (i
= 0; i
< MAX_RES
; i
++) {
271 fp
->rand_shift
[i
] = av_lfg_get(&fp
->lfg
) & (MAX_SHIFT
- 1);
273 fp
->rand_shift_init
= 1;
277 td
.in
= inpicref
; td
.out
= out
;
278 ff_filter_execute(ctx
, filter_slice
, &td
, NULL
,
279 FFMIN(n
->height
[0], ff_filter_get_nb_threads(ctx
)));
283 av_frame_free(&inpicref
);
284 return ff_filter_frame(outlink
, out
);
287 static av_cold
int init(AVFilterContext
*ctx
)
289 NoiseContext
*n
= ctx
->priv
;
292 for (i
= 0; i
< 4; i
++) {
293 if (n
->all
.seed
>= 0)
294 n
->param
[i
].seed
= n
->all
.seed
;
296 n
->param
[i
].seed
= 123457;
298 n
->param
[i
].strength
= n
->all
.strength
;
300 n
->param
[i
].flags
= n
->all
.flags
;
303 for (i
= 0; i
< 4; i
++) {
304 if (n
->param
[i
].strength
&& ((ret
= init_noise(n
, i
)) < 0))
308 n
->line_noise
= ff_line_noise_c
;
309 n
->line_noise_avg
= ff_line_noise_avg_c
;
312 ff_noise_init_x86(n
);
318 static av_cold
void uninit(AVFilterContext
*ctx
)
320 NoiseContext
*n
= ctx
->priv
;
323 for (i
= 0; i
< 4; i
++)
324 av_freep(&n
->param
[i
].noise
);
327 static const AVFilterPad noise_inputs
[] = {
330 .type
= AVMEDIA_TYPE_VIDEO
,
331 .filter_frame
= filter_frame
,
332 .config_props
= config_input
,
336 const FFFilter ff_vf_noise
= {
338 .p
.description
= NULL_IF_CONFIG_SMALL("Add noise."),
339 .p
.priv_class
= &noise_class
,
340 .p
.flags
= AVFILTER_FLAG_SUPPORT_TIMELINE_GENERIC
| AVFILTER_FLAG_SLICE_THREADS
,
341 .priv_size
= sizeof(NoiseContext
),
344 FILTER_INPUTS(noise_inputs
),
345 FILTER_OUTPUTS(ff_video_default_filterpad
),
346 FILTER_QUERY_FUNC2(query_formats
),