2 * Generates a synthetic YUV video sequence suitable for codec testing.
3 * NOTE: No floats are used to guarantee a bit exact output.
5 * Copyright (c) 2002 Fabrice Bellard
7 * This file is part of FFmpeg.
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 #define ONE_HALF (1 << (SCALEBITS - 1))
30 #define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5))
32 static void rgb24_to_yuv420p(uint8_t *lum
, uint8_t *cb
, uint8_t *cr
,
33 uint8_t *src
, int width
, int height
)
35 int wrap
, wrap3
, x
, y
;
36 int r
, g
, b
, r1
, g1
, b1
;
42 for(y
=0;y
<height
;y
+=2) {
43 for(x
=0;x
<width
;x
+=2) {
50 lum
[0] = (FIX(0.29900) * r
+ FIX(0.58700) * g
+
51 FIX(0.11400) * b
+ ONE_HALF
) >> SCALEBITS
;
58 lum
[1] = (FIX(0.29900) * r
+ FIX(0.58700) * g
+
59 FIX(0.11400) * b
+ ONE_HALF
) >> SCALEBITS
;
69 lum
[0] = (FIX(0.29900) * r
+ FIX(0.58700) * g
+
70 FIX(0.11400) * b
+ ONE_HALF
) >> SCALEBITS
;
77 lum
[1] = (FIX(0.29900) * r
+ FIX(0.58700) * g
+
78 FIX(0.11400) * b
+ ONE_HALF
) >> SCALEBITS
;
80 cb
[0] = ((- FIX(0.16874) * r1
- FIX(0.33126) * g1
+
81 FIX(0.50000) * b1
+ 4 * ONE_HALF
- 1) >> (SCALEBITS
+ 2)) + 128;
82 cr
[0] = ((FIX(0.50000) * r1
- FIX(0.41869) * g1
-
83 FIX(0.08131) * b1
+ 4 * ONE_HALF
- 1) >> (SCALEBITS
+ 2)) + 128;
96 #define DEFAULT_WIDTH 352
97 #define DEFAULT_HEIGHT 288
98 #define DEFAULT_NB_PICT 50 /* 2 seconds */
100 static void pgmyuv_save(const char *filename
, int w
, int h
,
101 unsigned char *rgb_tab
)
105 unsigned char *cb
, *cr
;
106 unsigned char *lum_tab
, *cb_tab
, *cr_tab
;
108 lum_tab
= malloc(w
* h
);
109 cb_tab
= malloc((w
* h
) / 4);
110 cr_tab
= malloc((w
* h
) / 4);
112 rgb24_to_yuv420p(lum_tab
, cb_tab
, cr_tab
, rgb_tab
, w
, h
);
114 f
= fopen(filename
,"wb");
115 fprintf(f
, "P5\n%d %d\n%d\n", w
, (h
* 3) / 2, 255);
116 fwrite(lum_tab
, 1, w
* h
, f
);
122 fwrite(cb
, 1, w2
, f
);
123 fwrite(cr
, 1, w2
, f
);
134 unsigned char *rgb_tab
;
135 int width
, height
, wrap
;
137 static void put_pixel(int x
, int y
, int r
, int g
, int b
)
141 if (x
< 0 || x
>= width
||
142 y
< 0 || y
>= height
)
145 p
= rgb_tab
+ y
* wrap
+ x
* 3;
151 static unsigned int myrnd(unsigned int *seed_ptr
, int n
)
153 unsigned int seed
, val
;
156 seed
= (seed
* 314159) + 1;
171 #define FRAC_ONE (1 << FRAC_BITS)
173 /* cosine approximate with 1-x^2 */
174 static int int_cos(int a
)
177 a
= a
& (FRAC_ONE
- 1);
178 if (a
>= (FRAC_ONE
/ 2))
181 if (a
> (FRAC_ONE
/ 4)) {
183 a
= (FRAC_ONE
/ 2) - a
;
185 v
= FRAC_ONE
- ((a
* a
) >> 4);
192 typedef struct VObj
{
199 unsigned int seed
= 1;
201 static void gen_image(int num
, int w
, int h
)
203 int r
, g
, b
, x
, y
, i
, dx
, dy
, x1
, y1
;
207 for(i
=0;i
<NB_OBJS
;i
++) {
208 objs
[i
].x
= myrnd(&seed
, w
);
209 objs
[i
].y
= myrnd(&seed
, h
);
210 objs
[i
].w
= myrnd(&seed
, w
/ 4) + 10;
211 objs
[i
].h
= myrnd(&seed
, h
/ 4) + 10;
212 objs
[i
].r
= myrnd(&seed
, 256);
213 objs
[i
].g
= myrnd(&seed
, 256);
214 objs
[i
].b
= myrnd(&seed
, 256);
218 /* first a moving background with gradients */
219 /* test motion estimation */
220 dx
= int_cos(num
* FRAC_ONE
/ 50) * 35;
221 dy
= int_cos(num
* FRAC_ONE
/ 50 + FRAC_ONE
/ 10) * 30;
224 x1
= (x
<< FRAC_BITS
) + dx
;
225 y1
= (y
<< FRAC_BITS
) + dy
;
226 r
= ((y1
* 7) >> FRAC_BITS
) & 0xff;
227 g
= (((x1
+ y1
) * 9) >> FRAC_BITS
) & 0xff;
228 b
= ((x1
* 5) >> FRAC_BITS
) & 0xff;
229 put_pixel(x
, y
, r
, g
, b
);
233 /* then some noise with very high intensity to test saturation */
235 for(y
=0;y
<NOISE_W
;y
++) {
236 for(x
=0;x
<NOISE_W
;x
++) {
237 r
= myrnd(&seed1
, 256);
238 g
= myrnd(&seed1
, 256);
239 b
= myrnd(&seed1
, 256);
240 put_pixel(x
+ NOISE_X
, y
+ NOISE_Y
, r
, g
, b
);
244 /* then moving objects */
245 for(i
=0;i
<NB_OBJS
;i
++) {
248 for(y
=0;y
<p
->h
;y
++) {
249 for(x
=0;x
<p
->w
;x
++) {
253 /* add a per object noise */
254 r
+= myrnd(&seed1
, 50);
255 g
+= myrnd(&seed1
, 50);
256 b
+= myrnd(&seed1
, 50);
257 put_pixel(x
+ p
->x
, y
+ p
->y
, r
, g
, b
);
260 p
->x
+= myrnd(&seed
, 21) - 10;
261 p
->y
+= myrnd(&seed
, 21) - 10;
265 int main(int argc
, char **argv
)
271 printf("usage: %s file\n"
272 "generate a test video stream\n", argv
[0]);
279 rgb_tab
= malloc(w
* h
* 3);
284 for(i
=0;i
<DEFAULT_NB_PICT
;i
++) {
285 snprintf(buf
, sizeof(buf
), "%s%02d.pgm", argv
[1], i
);
287 pgmyuv_save(buf
, w
, h
, rgb_tab
);