Line |
Branch |
Exec |
Source |
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 |
|
|
/** |
20 |
|
|
* @file |
21 |
|
|
* Perlin noise generator |
22 |
|
|
*/ |
23 |
|
|
|
24 |
|
|
#include <float.h> |
25 |
|
|
|
26 |
|
|
#include "perlin.h" |
27 |
|
|
#include "libavutil/lfg.h" |
28 |
|
|
#include "libavutil/opt.h" |
29 |
|
|
#include "avfilter.h" |
30 |
|
|
#include "filters.h" |
31 |
|
|
#include "formats.h" |
32 |
|
|
#include "video.h" |
33 |
|
|
|
34 |
|
|
typedef struct PerlinContext { |
35 |
|
|
const AVClass *class; |
36 |
|
|
|
37 |
|
|
int w, h; |
38 |
|
|
AVRational frame_rate; |
39 |
|
|
|
40 |
|
|
FFPerlin perlin; |
41 |
|
|
int octaves; |
42 |
|
|
double persistence; |
43 |
|
|
unsigned int random_seed; |
44 |
|
|
enum FFPerlinRandomMode random_mode; |
45 |
|
|
|
46 |
|
|
double xscale, yscale, tscale; |
47 |
|
|
uint64_t pts; |
48 |
|
|
} PerlinContext; |
49 |
|
|
|
50 |
|
|
#define OFFSET(x) offsetof(PerlinContext, x) |
51 |
|
|
#define FLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM |
52 |
|
|
|
53 |
|
|
static const AVOption perlin_options[] = { |
54 |
|
|
{ "size", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="320x240"}, 0, 0, FLAGS }, |
55 |
|
|
{ "s", "set video size", OFFSET(w), AV_OPT_TYPE_IMAGE_SIZE, {.str="320x240"}, 0, 0, FLAGS }, |
56 |
|
|
{ "rate", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, INT_MAX, FLAGS }, |
57 |
|
|
{ "r", "set video rate", OFFSET(frame_rate), AV_OPT_TYPE_VIDEO_RATE, {.str="25"}, 0, INT_MAX, FLAGS }, |
58 |
|
|
{ "octaves", "set the number of components to use to generate the noise", OFFSET(octaves), AV_OPT_TYPE_INT, {.i64=1}, 1, INT_MAX, FLAGS }, |
59 |
|
|
{ "persistence", "set the octaves persistence", OFFSET(persistence), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.0, DBL_MAX, FLAGS }, |
60 |
|
|
|
61 |
|
|
{ "xscale", "set x-scale factor", OFFSET(xscale), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.0, DBL_MAX, FLAGS }, |
62 |
|
|
{ "yscale", "set y-scale factor", OFFSET(yscale), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.0, DBL_MAX, FLAGS }, |
63 |
|
|
{ "tscale", "set t-scale factor", OFFSET(tscale), AV_OPT_TYPE_DOUBLE, {.dbl=1}, 0.0, DBL_MAX, FLAGS }, |
64 |
|
|
|
65 |
|
|
{ "random_mode", "set random mode used to compute initial pattern", OFFSET(random_mode), AV_OPT_TYPE_INT, {.i64=FF_PERLIN_RANDOM_MODE_RANDOM}, 0, FF_PERLIN_RANDOM_MODE_NB-1, FLAGS, .unit = "random_mode" }, |
66 |
|
|
{ "random", "compute and use random seed", 0, AV_OPT_TYPE_CONST, {.i64=FF_PERLIN_RANDOM_MODE_RANDOM}, 0, 0, FLAGS, .unit = "random_mode" }, |
67 |
|
|
{ "ken", "use the predefined initial pattern defined by Ken Perlin in the original article", 0, AV_OPT_TYPE_CONST, {.i64=FF_PERLIN_RANDOM_MODE_KEN}, 0, 0, FLAGS, .unit = "random_mode" }, |
68 |
|
|
{ "seed", "use the value specified by random_seed", 0, AV_OPT_TYPE_CONST, {.i64=FF_PERLIN_RANDOM_MODE_SEED}, 0, 0, FLAGS, .unit="random_mode" }, |
69 |
|
|
|
70 |
|
|
{ "random_seed", "set the seed for filling the initial pattern", OFFSET(random_seed), AV_OPT_TYPE_UINT, {.i64=0}, 0, UINT_MAX, FLAGS }, |
71 |
|
|
{ "seed", "set the seed for filling the initial pattern", OFFSET(random_seed), AV_OPT_TYPE_UINT, {.i64=0}, 0, UINT_MAX, FLAGS }, |
72 |
|
|
{ NULL } |
73 |
|
|
}; |
74 |
|
|
|
75 |
|
|
AVFILTER_DEFINE_CLASS(perlin); |
76 |
|
|
|
77 |
|
✗ |
static av_cold int init(AVFilterContext *ctx) |
78 |
|
|
{ |
79 |
|
✗ |
PerlinContext *perlin = ctx->priv; |
80 |
|
|
int ret; |
81 |
|
|
|
82 |
|
✗ |
if (ret = ff_perlin_init(&perlin->perlin, -1, perlin->octaves, perlin->persistence, |
83 |
|
|
perlin->random_mode, perlin->random_seed)) { |
84 |
|
✗ |
return ret; |
85 |
|
|
} |
86 |
|
|
|
87 |
|
✗ |
av_log(ctx, AV_LOG_VERBOSE, |
88 |
|
|
"s:%dx%d r:%d/%d octaves:%d persistence:%f xscale:%f yscale:%f tscale:%f\n", |
89 |
|
|
perlin->w, perlin->h, perlin->frame_rate.num, perlin->frame_rate.den, |
90 |
|
|
perlin->octaves, perlin->persistence, |
91 |
|
|
perlin->xscale, perlin->yscale, perlin->tscale); |
92 |
|
✗ |
return 0; |
93 |
|
|
} |
94 |
|
|
|
95 |
|
✗ |
static int config_props(AVFilterLink *outlink) |
96 |
|
|
{ |
97 |
|
✗ |
PerlinContext *perlin = outlink->src->priv; |
98 |
|
✗ |
FilterLink *l = ff_filter_link(outlink); |
99 |
|
|
|
100 |
|
✗ |
outlink->w = perlin->w; |
101 |
|
✗ |
outlink->h = perlin->h; |
102 |
|
✗ |
outlink->time_base = av_inv_q(perlin->frame_rate); |
103 |
|
✗ |
l->frame_rate = perlin->frame_rate; |
104 |
|
|
|
105 |
|
✗ |
return 0; |
106 |
|
|
} |
107 |
|
|
|
108 |
|
✗ |
static int request_frame(AVFilterLink *outlink) |
109 |
|
|
{ |
110 |
|
✗ |
AVFilterContext *ctx = outlink->src; |
111 |
|
✗ |
PerlinContext *perlin = ctx->priv; |
112 |
|
✗ |
AVFrame *picref = ff_get_video_buffer(outlink, perlin->w, perlin->h); |
113 |
|
|
int i, j; |
114 |
|
|
uint8_t *data0, *data; |
115 |
|
|
double x, y, t; |
116 |
|
|
|
117 |
|
✗ |
if (!picref) |
118 |
|
✗ |
return AVERROR(ENOMEM); |
119 |
|
|
|
120 |
|
✗ |
picref->sample_aspect_ratio = (AVRational) {1, 1}; |
121 |
|
✗ |
picref->pts = perlin->pts++; |
122 |
|
✗ |
picref->duration = 1; |
123 |
|
|
|
124 |
|
✗ |
t = perlin->tscale * (perlin->pts * av_q2d(outlink->time_base)); |
125 |
|
✗ |
data0 = picref->data[0]; |
126 |
|
|
|
127 |
|
✗ |
for (i = 0; i < perlin->h; i++) { |
128 |
|
✗ |
y = perlin->yscale * (double)i / perlin->h; |
129 |
|
|
|
130 |
|
✗ |
data = data0; |
131 |
|
|
|
132 |
|
✗ |
for (j = 0; j < perlin->w; j++) { |
133 |
|
|
double res; |
134 |
|
✗ |
x = perlin->xscale * (double)j / perlin->w; |
135 |
|
✗ |
res = ff_perlin_get(&perlin->perlin, x, y, t); |
136 |
|
✗ |
av_log(ctx, AV_LOG_DEBUG, "x:%f y:%f t:%f => %f\n", x, y, t, res); |
137 |
|
✗ |
*data++ = res * 255; |
138 |
|
|
} |
139 |
|
✗ |
data0 += picref->linesize[0]; |
140 |
|
|
} |
141 |
|
|
|
142 |
|
✗ |
return ff_filter_frame(outlink, picref); |
143 |
|
|
} |
144 |
|
|
|
145 |
|
✗ |
static int query_formats(const AVFilterContext *ctx, |
146 |
|
|
AVFilterFormatsConfig **cfg_in, |
147 |
|
|
AVFilterFormatsConfig **cfg_out) |
148 |
|
|
{ |
149 |
|
✗ |
enum AVPixelFormat pix_fmts[] = { AV_PIX_FMT_GRAY8, AV_PIX_FMT_NONE }; |
150 |
|
|
|
151 |
|
✗ |
return ff_set_common_formats_from_list2(ctx, cfg_in, cfg_out, pix_fmts); |
152 |
|
|
} |
153 |
|
|
|
154 |
|
|
static const AVFilterPad perlin_outputs[] = { |
155 |
|
|
{ |
156 |
|
|
.name = "default", |
157 |
|
|
.type = AVMEDIA_TYPE_VIDEO, |
158 |
|
|
.request_frame = request_frame, |
159 |
|
|
.config_props = config_props, |
160 |
|
|
}, |
161 |
|
|
}; |
162 |
|
|
|
163 |
|
|
const AVFilter ff_vsrc_perlin = { |
164 |
|
|
.name = "perlin", |
165 |
|
|
.description = NULL_IF_CONFIG_SMALL("Generate Perlin noise"), |
166 |
|
|
.priv_size = sizeof(PerlinContext), |
167 |
|
|
.priv_class = &perlin_class, |
168 |
|
|
.init = init, |
169 |
|
|
.inputs = NULL, |
170 |
|
|
FILTER_OUTPUTS(perlin_outputs), |
171 |
|
|
FILTER_QUERY_FUNC2(query_formats), |
172 |
|
|
}; |
173 |
|
|
|