Libav 0.7.1
|
00001 /* 00002 * Generates a synthetic YUV video sequence suitable for codec testing. 00003 * NOTE: No floats are used to guarantee a bit exact output. 00004 * 00005 * Copyright (c) 2002 Fabrice Bellard 00006 * 00007 * This file is part of Libav. 00008 * 00009 * Libav is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Lesser General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2.1 of the License, or (at your option) any later version. 00013 * 00014 * Libav is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Lesser General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Lesser General Public 00020 * License along with Libav; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 */ 00023 00024 #include <stdlib.h> 00025 #include <stdint.h> 00026 #include <stdio.h> 00027 00028 #define SCALEBITS 8 00029 #define ONE_HALF (1 << (SCALEBITS - 1)) 00030 #define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5)) 00031 00032 static void rgb24_to_yuv420p(uint8_t *lum, uint8_t *cb, uint8_t *cr, 00033 uint8_t *src, int width, int height) 00034 { 00035 int wrap, wrap3, x, y; 00036 int r, g, b, r1, g1, b1; 00037 uint8_t *p; 00038 00039 wrap = width; 00040 wrap3 = width * 3; 00041 p = src; 00042 for(y=0;y<height;y+=2) { 00043 for(x=0;x<width;x+=2) { 00044 r = p[0]; 00045 g = p[1]; 00046 b = p[2]; 00047 r1 = r; 00048 g1 = g; 00049 b1 = b; 00050 lum[0] = (FIX(0.29900) * r + FIX(0.58700) * g + 00051 FIX(0.11400) * b + ONE_HALF) >> SCALEBITS; 00052 r = p[3]; 00053 g = p[4]; 00054 b = p[5]; 00055 r1 += r; 00056 g1 += g; 00057 b1 += b; 00058 lum[1] = (FIX(0.29900) * r + FIX(0.58700) * g + 00059 FIX(0.11400) * b + ONE_HALF) >> SCALEBITS; 00060 p += wrap3; 00061 lum += wrap; 00062 00063 r = p[0]; 00064 g = p[1]; 00065 b = p[2]; 00066 r1 += r; 00067 g1 += g; 00068 b1 += b; 00069 lum[0] = (FIX(0.29900) * r + FIX(0.58700) * g + 00070 FIX(0.11400) * b + ONE_HALF) >> SCALEBITS; 00071 r = p[3]; 00072 g = p[4]; 00073 b = p[5]; 00074 r1 += r; 00075 g1 += g; 00076 b1 += b; 00077 lum[1] = (FIX(0.29900) * r + FIX(0.58700) * g + 00078 FIX(0.11400) * b + ONE_HALF) >> SCALEBITS; 00079 00080 cb[0] = ((- FIX(0.16874) * r1 - FIX(0.33126) * g1 + 00081 FIX(0.50000) * b1 + 4 * ONE_HALF - 1) >> (SCALEBITS + 2)) + 128; 00082 cr[0] = ((FIX(0.50000) * r1 - FIX(0.41869) * g1 - 00083 FIX(0.08131) * b1 + 4 * ONE_HALF - 1) >> (SCALEBITS + 2)) + 128; 00084 00085 cb++; 00086 cr++; 00087 p += -wrap3 + 2 * 3; 00088 lum += -wrap + 2; 00089 } 00090 p += wrap3; 00091 lum += wrap; 00092 } 00093 } 00094 00095 /* cif format */ 00096 #define DEFAULT_WIDTH 352 00097 #define DEFAULT_HEIGHT 288 00098 #define DEFAULT_NB_PICT 50 /* 2 seconds */ 00099 00100 static void pgmyuv_save(const char *filename, int w, int h, 00101 unsigned char *rgb_tab) 00102 { 00103 FILE *f; 00104 int i, h2, w2; 00105 unsigned char *cb, *cr; 00106 unsigned char *lum_tab, *cb_tab, *cr_tab; 00107 00108 lum_tab = malloc(w * h); 00109 cb_tab = malloc((w * h) / 4); 00110 cr_tab = malloc((w * h) / 4); 00111 00112 rgb24_to_yuv420p(lum_tab, cb_tab, cr_tab, rgb_tab, w, h); 00113 00114 f = fopen(filename,"wb"); 00115 fprintf(f, "P5\n%d %d\n%d\n", w, (h * 3) / 2, 255); 00116 fwrite(lum_tab, 1, w * h, f); 00117 h2 = h / 2; 00118 w2 = w / 2; 00119 cb = cb_tab; 00120 cr = cr_tab; 00121 for(i=0;i<h2;i++) { 00122 fwrite(cb, 1, w2, f); 00123 fwrite(cr, 1, w2, f); 00124 cb += w2; 00125 cr += w2; 00126 } 00127 fclose(f); 00128 00129 free(lum_tab); 00130 free(cb_tab); 00131 free(cr_tab); 00132 } 00133 00134 unsigned char *rgb_tab; 00135 int width, height, wrap; 00136 00137 static void put_pixel(int x, int y, int r, int g, int b) 00138 { 00139 unsigned char *p; 00140 00141 if (x < 0 || x >= width || 00142 y < 0 || y >= height) 00143 return; 00144 00145 p = rgb_tab + y * wrap + x * 3; 00146 p[0] = r; 00147 p[1] = g; 00148 p[2] = b; 00149 } 00150 00151 static unsigned int myrnd(unsigned int *seed_ptr, int n) 00152 { 00153 unsigned int seed, val; 00154 00155 seed = *seed_ptr; 00156 seed = (seed * 314159) + 1; 00157 if (n == 256) { 00158 val = seed >> 24; 00159 } else { 00160 val = seed % n; 00161 } 00162 *seed_ptr = seed; 00163 return val; 00164 } 00165 00166 #define NOISE_X 10 00167 #define NOISE_Y 30 00168 #define NOISE_W 26 00169 00170 #define FRAC_BITS 8 00171 #define FRAC_ONE (1 << FRAC_BITS) 00172 00173 /* cosine approximate with 1-x^2 */ 00174 static int int_cos(int a) 00175 { 00176 int v, neg; 00177 a = a & (FRAC_ONE - 1); 00178 if (a >= (FRAC_ONE / 2)) 00179 a = FRAC_ONE - a; 00180 neg = 0; 00181 if (a > (FRAC_ONE / 4)) { 00182 neg = -1; 00183 a = (FRAC_ONE / 2) - a; 00184 } 00185 v = FRAC_ONE - ((a * a) >> 4); 00186 v = (v ^ neg) - neg; 00187 return v; 00188 } 00189 00190 #define NB_OBJS 10 00191 00192 typedef struct VObj { 00193 int x, y, w, h; 00194 int r, g, b; 00195 } VObj; 00196 00197 VObj objs[NB_OBJS]; 00198 00199 unsigned int seed = 1; 00200 00201 static void gen_image(int num, int w, int h) 00202 { 00203 int r, g, b, x, y, i, dx, dy, x1, y1; 00204 unsigned int seed1; 00205 00206 if (num == 0) { 00207 for(i=0;i<NB_OBJS;i++) { 00208 objs[i].x = myrnd(&seed, w); 00209 objs[i].y = myrnd(&seed, h); 00210 objs[i].w = myrnd(&seed, w / 4) + 10; 00211 objs[i].h = myrnd(&seed, h / 4) + 10; 00212 objs[i].r = myrnd(&seed, 256); 00213 objs[i].g = myrnd(&seed, 256); 00214 objs[i].b = myrnd(&seed, 256); 00215 } 00216 } 00217 00218 /* first a moving background with gradients */ 00219 /* test motion estimation */ 00220 dx = int_cos(num * FRAC_ONE / 50) * 35; 00221 dy = int_cos(num * FRAC_ONE / 50 + FRAC_ONE / 10) * 30; 00222 for(y=0;y<h;y++) { 00223 for(x=0;x<w;x++) { 00224 x1 = (x << FRAC_BITS) + dx; 00225 y1 = (y << FRAC_BITS) + dy; 00226 r = ((y1 * 7) >> FRAC_BITS) & 0xff; 00227 g = (((x1 + y1) * 9) >> FRAC_BITS) & 0xff; 00228 b = ((x1 * 5) >> FRAC_BITS) & 0xff; 00229 put_pixel(x, y, r, g, b); 00230 } 00231 } 00232 00233 /* then some noise with very high intensity to test saturation */ 00234 seed1 = num; 00235 for(y=0;y<NOISE_W;y++) { 00236 for(x=0;x<NOISE_W;x++) { 00237 r = myrnd(&seed1, 256); 00238 g = myrnd(&seed1, 256); 00239 b = myrnd(&seed1, 256); 00240 put_pixel(x + NOISE_X, y + NOISE_Y, r, g, b); 00241 } 00242 } 00243 00244 /* then moving objects */ 00245 for(i=0;i<NB_OBJS;i++) { 00246 VObj *p = &objs[i]; 00247 seed1 = i; 00248 for(y=0;y<p->h;y++) { 00249 for(x=0;x<p->w;x++) { 00250 r = p->r; 00251 g = p->g; 00252 b = p->b; 00253 /* add a per object noise */ 00254 r += myrnd(&seed1, 50); 00255 g += myrnd(&seed1, 50); 00256 b += myrnd(&seed1, 50); 00257 put_pixel(x + p->x, y + p->y, r, g, b); 00258 } 00259 } 00260 p->x += myrnd(&seed, 21) - 10; 00261 p->y += myrnd(&seed, 21) - 10; 00262 } 00263 } 00264 00265 int main(int argc, char **argv) 00266 { 00267 int w, h, i; 00268 char buf[1024]; 00269 00270 if (argc != 2) { 00271 printf("usage: %s file\n" 00272 "generate a test video stream\n", argv[0]); 00273 exit(1); 00274 } 00275 00276 w = DEFAULT_WIDTH; 00277 h = DEFAULT_HEIGHT; 00278 00279 rgb_tab = malloc(w * h * 3); 00280 wrap = w * 3; 00281 width = w; 00282 height = h; 00283 00284 for(i=0;i<DEFAULT_NB_PICT;i++) { 00285 snprintf(buf, sizeof(buf), "%s%02d.pgm", argv[1], i); 00286 gen_image(i, w, h); 00287 pgmyuv_save(buf, w, h, rgb_tab); 00288 } 00289 00290 free(rgb_tab); 00291 return 0; 00292 }