videogen.c 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * Generates a synthetic YUV video sequence suitable for codec testing.
  3. * NOTE: no floats are used to guaranty a bit exact output.
  4. */
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #define SCALEBITS 8
  8. #define ONE_HALF (1 << (SCALEBITS - 1))
  9. #define FIX(x) ((int) ((x) * (1L<<SCALEBITS) + 0.5))
  10. typedef unsigned char uint8_t;
  11. static void rgb24_to_yuv420p(uint8_t *lum, uint8_t *cb, uint8_t *cr,
  12. uint8_t *src, int width, int height)
  13. {
  14. int wrap, wrap3, x, y;
  15. int r, g, b, r1, g1, b1;
  16. uint8_t *p;
  17. wrap = width;
  18. wrap3 = width * 3;
  19. p = src;
  20. for(y=0;y<height;y+=2) {
  21. for(x=0;x<width;x+=2) {
  22. r = p[0];
  23. g = p[1];
  24. b = p[2];
  25. r1 = r;
  26. g1 = g;
  27. b1 = b;
  28. lum[0] = (FIX(0.29900) * r + FIX(0.58700) * g +
  29. FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
  30. r = p[3];
  31. g = p[4];
  32. b = p[5];
  33. r1 += r;
  34. g1 += g;
  35. b1 += b;
  36. lum[1] = (FIX(0.29900) * r + FIX(0.58700) * g +
  37. FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
  38. p += wrap3;
  39. lum += wrap;
  40. r = p[0];
  41. g = p[1];
  42. b = p[2];
  43. r1 += r;
  44. g1 += g;
  45. b1 += b;
  46. lum[0] = (FIX(0.29900) * r + FIX(0.58700) * g +
  47. FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
  48. r = p[3];
  49. g = p[4];
  50. b = p[5];
  51. r1 += r;
  52. g1 += g;
  53. b1 += b;
  54. lum[1] = (FIX(0.29900) * r + FIX(0.58700) * g +
  55. FIX(0.11400) * b + ONE_HALF) >> SCALEBITS;
  56. cb[0] = ((- FIX(0.16874) * r1 - FIX(0.33126) * g1 +
  57. FIX(0.50000) * b1 + 4 * ONE_HALF - 1) >> (SCALEBITS + 2)) + 128;
  58. cr[0] = ((FIX(0.50000) * r1 - FIX(0.41869) * g1 -
  59. FIX(0.08131) * b1 + 4 * ONE_HALF - 1) >> (SCALEBITS + 2)) + 128;
  60. cb++;
  61. cr++;
  62. p += -wrap3 + 2 * 3;
  63. lum += -wrap + 2;
  64. }
  65. p += wrap3;
  66. lum += wrap;
  67. }
  68. }
  69. /* cif format */
  70. #define DEFAULT_WIDTH 352
  71. #define DEFAULT_HEIGHT 288
  72. #define DEFAULT_NB_PICT 50 /* 2 seconds */
  73. void pgmyuv_save(const char *filename, int w, int h,
  74. unsigned char *rgb_tab)
  75. {
  76. FILE *f;
  77. int i, h2, w2;
  78. unsigned char *cb, *cr;
  79. unsigned char *lum_tab, *cb_tab, *cr_tab;
  80. lum_tab = malloc(w * h);
  81. cb_tab = malloc((w * h) / 4);
  82. cr_tab = malloc((w * h) / 4);
  83. rgb24_to_yuv420p(lum_tab, cb_tab, cr_tab, rgb_tab, w, h);
  84. f = fopen(filename,"wb");
  85. fprintf(f, "P5\n%d %d\n%d\n", w, (h * 3) / 2, 255);
  86. fwrite(lum_tab, 1, w * h, f);
  87. h2 = h / 2;
  88. w2 = w / 2;
  89. cb = cb_tab;
  90. cr = cr_tab;
  91. for(i=0;i<h2;i++) {
  92. fwrite(cb, 1, w2, f);
  93. fwrite(cr, 1, w2, f);
  94. cb += w2;
  95. cr += w2;
  96. }
  97. fclose(f);
  98. free(lum_tab);
  99. free(cb_tab);
  100. free(cr_tab);
  101. }
  102. unsigned char *rgb_tab;
  103. int width, height, wrap;
  104. void put_pixel(int x, int y, int r, int g, int b)
  105. {
  106. unsigned char *p;
  107. if (x < 0 || x >= width ||
  108. y < 0 || y >= height)
  109. return;
  110. p = rgb_tab + y * wrap + x * 3;
  111. p[0] = r;
  112. p[1] = g;
  113. p[2] = b;
  114. }
  115. static unsigned int myrnd(unsigned int *seed_ptr, int n)
  116. {
  117. unsigned int seed, val;
  118. seed = *seed_ptr;
  119. seed = (seed * 314159) + 1;
  120. if (n == 256) {
  121. val = seed >> 24;
  122. } else {
  123. val = seed % n;
  124. }
  125. *seed_ptr = seed;
  126. return val;
  127. }
  128. #define NOISE_X 10
  129. #define NOISE_Y 30
  130. #define NOISE_W 26
  131. #define FRAC_BITS 8
  132. #define FRAC_ONE (1 << FRAC_BITS)
  133. /* cosine approximate with 1-x^2 */
  134. int int_cos(int a)
  135. {
  136. int v, neg;
  137. a = a & (FRAC_ONE - 1);
  138. if (a >= (FRAC_ONE / 2))
  139. a = FRAC_ONE - a;
  140. neg = 0;
  141. if (a > (FRAC_ONE / 4)) {
  142. neg = -1;
  143. a = (FRAC_ONE / 2) - a;
  144. }
  145. v = FRAC_ONE - ((a * a) >> 4);
  146. v = (v ^ neg) - neg;
  147. return v;
  148. }
  149. #define NB_OBJS 10
  150. typedef struct VObj {
  151. int x, y, w, h;
  152. int r, g, b;
  153. } VObj;
  154. VObj objs[NB_OBJS];
  155. unsigned int seed = 1;
  156. void gen_image(int num, int w, int h)
  157. {
  158. int r, g, b, x, y, i, dx, dy, x1, y1;
  159. unsigned int seed1;
  160. if (num == 0) {
  161. for(i=0;i<NB_OBJS;i++) {
  162. objs[i].x = myrnd(&seed, w);
  163. objs[i].y = myrnd(&seed, h);
  164. objs[i].w = myrnd(&seed, w / 4) + 10;
  165. objs[i].h = myrnd(&seed, h / 4) + 10;
  166. objs[i].r = myrnd(&seed, 256);
  167. objs[i].g = myrnd(&seed, 256);
  168. objs[i].b = myrnd(&seed, 256);
  169. }
  170. }
  171. /* first a moving background with gradients */
  172. /* test motion estimation */
  173. dx = int_cos(num * FRAC_ONE / 50) * 35;
  174. dy = int_cos(num * FRAC_ONE / 50 + FRAC_ONE / 10) * 30;
  175. for(y=0;y<h;y++) {
  176. for(x=0;x<w;x++) {
  177. x1 = (x << FRAC_BITS) + dx;
  178. y1 = (y << FRAC_BITS) + dx;
  179. r = ((y1 * 7) >> FRAC_BITS) & 0xff;
  180. g = (((x1 + y1) * 9) >> FRAC_BITS) & 0xff;
  181. b = ((x1 * 5) >> FRAC_BITS) & 0xff;
  182. put_pixel(x, y, r, g, b);
  183. }
  184. }
  185. /* then some noise with very high intensity to test saturation */
  186. seed1 = num;
  187. for(y=0;y<NOISE_W;y++) {
  188. for(x=0;x<NOISE_W;x++) {
  189. r = myrnd(&seed1, 256);
  190. g = myrnd(&seed1, 256);
  191. b = myrnd(&seed1, 256);
  192. put_pixel(x + NOISE_X, y + NOISE_Y, r, g, b);
  193. }
  194. }
  195. /* then moving objects */
  196. for(i=0;i<NB_OBJS;i++) {
  197. VObj *p = &objs[i];
  198. seed1 = i;
  199. for(y=0;y<p->h;y++) {
  200. for(x=0;x<p->w;x++) {
  201. r = p->r;
  202. g = p->g;
  203. b = p->b;
  204. /* add a per object noise */
  205. r += myrnd(&seed1, 50);
  206. g += myrnd(&seed1, 50);
  207. b += myrnd(&seed1, 50);
  208. put_pixel(x + p->x, y + p->y, r, g, b);
  209. }
  210. }
  211. p->x += myrnd(&seed, 21) - 10;
  212. p->y += myrnd(&seed, 21) - 10;
  213. }
  214. }
  215. int main(int argc, char **argv)
  216. {
  217. int w, h, i;
  218. char buf[1024];
  219. if (argc != 2) {
  220. printf("usage: %s file\n"
  221. "generate a test video stream\n", argv[0]);
  222. exit(1);
  223. }
  224. #if 0
  225. for(i=0;i<256;i++)
  226. printf("cos(%d)=%d\n", i, int_cos(i));
  227. #endif
  228. w = DEFAULT_WIDTH;
  229. h = DEFAULT_HEIGHT;
  230. rgb_tab = malloc(w * h * 3);
  231. wrap = w * 3;
  232. width = w;
  233. height = h;
  234. for(i=0;i<DEFAULT_NB_PICT;i++) {
  235. snprintf(buf, sizeof(buf), "%s%02d.pgm", argv[1], i);
  236. gen_image(i, w, h);
  237. pgmyuv_save(buf, w, h, rgb_tab);
  238. }
  239. free(rgb_tab);
  240. return 0;
  241. }