Add gen-image tool
[renesas/vsp-tests.git] / src / gen-image.c
1 /*
2  * Copyright (C) 2016 Laurent Pinchart <laurent.pinchart@ideasonboard.com>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  */
9
10 #include <ctype.h>
11 #include <errno.h>
12 #include <fcntl.h>
13 #include <getopt.h>
14 #include <math.h>
15 #include <stdbool.h>
16 #include <stdint.h>
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/stat.h>
22 #include <sys/types.h>
23
24 #include <linux/videodev2.h>
25
26 #define ARRAY_SIZE(a)           (sizeof(a) / sizeof(a[0]))
27
28 #define min(a, b)               ({      \
29         typeof(a) _a = (a);             \
30         typeof(b) _b = (b);             \
31         _a < _b ? _a : _b;              \
32 })
33
34 #define max(a, b)               ({      \
35         typeof(a) _a = (a);             \
36         typeof(b) _b = (b);             \
37         _a > _b ? _a : _b;              \
38 })
39
40 #define clamp(val, low, high)   max(low, min(high, val));
41
42 struct format_color_component {
43         unsigned char length;
44         unsigned char offset;
45 };
46
47 struct format_rgb_info {
48         unsigned int bpp;
49         struct format_color_component red;
50         struct format_color_component green;
51         struct format_color_component blue;
52         struct format_color_component alpha;
53 };
54
55 enum format_yuv_order {
56         YUV_YCbCr = 1,
57         YUV_YCrCb = 2,
58         YUV_YC = 4,
59         YUV_CY = 8,
60 };
61
62 struct format_yuv_info {
63         unsigned int num_planes;
64         enum format_yuv_order order;
65         unsigned int xsub;
66         unsigned int ysub;
67 };
68
69 struct format_info {
70         const char *name;
71         bool is_yuv;
72         struct format_rgb_info rgb;
73         struct format_yuv_info yuv;
74 };
75
76 struct image {
77         const struct format_info *format;
78         unsigned int width;
79         unsigned int height;
80         unsigned int size;
81         void *data;
82 };
83
84 struct params {
85         unsigned int alpha;
86         enum v4l2_ycbcr_encoding encoding;
87         enum v4l2_quantization quantization;
88 };
89
90 struct options {
91         const char *input_filename;
92         const char *output_filename;
93         const char *histo_filename;
94
95         const struct format_info *output_format;
96         unsigned int output_height;
97         unsigned int output_width;
98
99         bool process_yuv;
100         unsigned int compose;
101         struct params params;
102 };
103
104 /* -----------------------------------------------------------------------------
105  * Format information
106  */
107
108 #define MAKE_RGB_INFO(rl, ro, gl, go, bl, bo, al, ao) \
109         .red = { (rl), (ro) }, .green = { (gl), (go) }, \
110         .blue = { (bl), (bo) }, .alpha = { (al), (ao) }
111
112 static const struct format_info format_info[] = {
113         /*
114          * The alpha channel maps to the X (don't care) bits for the XRGB
115          * formats.
116          */
117         { "RGB332",     false, .rgb = { 8,  MAKE_RGB_INFO(3, 5, 3, 2, 2, 0, 0, 0) } },
118         { "ARGB444",    false, .rgb = { 16, MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 4, 12) } },
119         { "XRGB444",    false, .rgb = { 16, MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 4, 12) } },
120         { "ARGB555",    false, .rgb = { 16, MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 1, 15) } },
121         { "XRGB555",    false, .rgb = { 16, MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 1, 15) } },
122         { "RGB565",     false, .rgb = { 16, MAKE_RGB_INFO(5, 11, 6, 5, 5, 0, 0, 0) } },
123         { "BGR24",      false, .rgb = { 24, MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) } },
124         { "RGB24",      false, .rgb = { 24, MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) } },
125         { "ABGR32",     false, .rgb = { 32, MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 8, 24) } },
126         { "XBGR32",     false, .rgb = { 32, MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 8, 24) } },
127         { "ARGB32",     false, .rgb = { 32, MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 8, 0) } },
128         { "XRGB32",     false, .rgb = { 32, MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 8, 0) } },
129         { "UYVY",       true,  .yuv = { 1, YUV_YCbCr | YUV_CY, 2, 1 } },
130         { "VYUY",       true,  .yuv = { 1, YUV_YCrCb | YUV_CY, 2, 1 } },
131         { "YUYV",       true,  .yuv = { 1, YUV_YCbCr | YUV_YC, 2, 1 } },
132         { "YVYU",       true,  .yuv = { 1, YUV_YCrCb | YUV_YC, 2, 1 } },
133         { "NV12M",      true,  .yuv = { 2, YUV_YCbCr, 2, 2 } },
134         { "NV21M",      true,  .yuv = { 2, YUV_YCrCb, 2, 2 } },
135         { "NV16M",      true,  .yuv = { 2, YUV_YCbCr, 2, 1 } },
136         { "NV61M",      true,  .yuv = { 2, YUV_YCrCb, 2, 1 } },
137         { "YUV420M",    true,  .yuv = { 3, YUV_YCbCr, 2, 2 } },
138         { "YVU420M",    true,  .yuv = { 3, YUV_YCrCb, 2, 2 } },
139         { "YUV422M",    true,  .yuv = { 3, YUV_YCbCr, 2, 1 } },
140         { "YVU422M",    true,  .yuv = { 3, YUV_YCrCb, 2, 1 } },
141         { "YUV444M",    true,  .yuv = { 3, YUV_YCbCr, 1, 1 } },
142         { "YVU444M",    true,  .yuv = { 3, YUV_YCrCb, 1, 1 } },
143         { "YUV24",      true,  .yuv = { 1, YUV_YCbCr | YUV_YC, 1, 1 } },
144 };
145
146 static const struct format_info *format_by_name(const char *name)
147 {
148         unsigned int i;
149
150         for (i = 0; i < ARRAY_SIZE(format_info); i++) {
151                 if (!strcmp(name, format_info[i].name))
152                         return &format_info[i];
153         }
154
155         return NULL;
156 }
157
158 /* -----------------------------------------------------------------------------
159  * File I/O
160  */
161
162 static int file_read(int fd, void *buffer, size_t size)
163 {
164         unsigned int offset = 0;
165
166         while (offset < size) {
167                 ssize_t nbytes;
168
169                 nbytes = read(fd, buffer + offset, size - offset);
170                 if (nbytes < 0) {
171                         if (errno == EINTR)
172                                 continue;
173
174                         return -errno;
175                 }
176
177                 if (nbytes == 0)
178                         return offset;
179
180                 offset += nbytes;
181         }
182
183         return size;
184 }
185
186 static int file_write(int fd, const void *buffer, size_t size)
187 {
188         unsigned int offset = 0;
189
190         while (offset < size) {
191                 ssize_t nbytes;
192
193                 nbytes = write(fd, buffer + offset, size - offset);
194                 if (nbytes < 0) {
195                         if (errno == EINTR)
196                                 continue;
197
198                         return -errno;
199                 }
200
201                 offset += nbytes;
202         }
203
204         return 0;
205 }
206
207 /* -----------------------------------------------------------------------------
208  * Image initialization
209  */
210
211 static struct image *image_new(const struct format_info *format,
212                                unsigned int width, unsigned int height)
213 {
214         struct image *image;
215
216         image = malloc(sizeof(*image));
217         if (!image)
218                 return NULL;
219
220         memset(image, 0, sizeof(*image));
221         image->format = format;
222         image->width = width;
223         image->height = height;
224
225         if (format->is_yuv)
226                 image->size = image->width * image->height
227                              * (8 + 2 * 8 / format->yuv.xsub / format->yuv.ysub)
228                              / 8;
229         else
230                 image->size = image->width * image->height
231                              * format->rgb.bpp / 8;
232
233         image->data = malloc(image->size);
234         if (!image->data) {
235                 printf("Not enough memory for image data\n");
236                 free(image);
237                 return NULL;
238         }
239
240         return image;
241 }
242
243 static void image_delete(struct image *image)
244 {
245         if (!image)
246                 return;
247
248         free(image->data);
249         free(image);
250 }
251
252 /* -----------------------------------------------------------------------------
253  * Image read and write
254  */
255
256 static int pnm_read_bytes(int fd, char *buffer, size_t size)
257 {
258         int ret;
259
260         ret = file_read(fd, buffer, size);
261         if (ret < 0) {
262                 printf("Unable to read PNM file: %s (%d)\n", strerror(-ret),
263                        ret);
264                 return ret;
265         }
266         if ((size_t)ret != size) {
267                 printf("Invalid PNM file: file too short\n");
268                 return -ENODATA;
269         }
270
271         return 0;
272 }
273
274 static int pnm_read_integer(int fd)
275 {
276         unsigned int value = 0;
277         int ret;
278         char c;
279
280         do {
281                 ret = pnm_read_bytes(fd, &c, 1);
282         } while (!ret && isspace(c));
283
284         if (ret)
285                 return ret;
286
287         while (!ret && isdigit(c)) {
288                 value = value * 10 + c - '0';
289                 ret = pnm_read_bytes(fd, &c, 1);
290         }
291
292         if (ret)
293                 return ret;
294
295         if (!isspace(c))
296                 return -EINVAL;
297
298         return value;
299 }
300
301 static struct image *pnm_read(const char *filename)
302 {
303         struct image *image;
304         unsigned int width;
305         unsigned int height;
306         char buffer[2];
307         int ret;
308         int fd;
309
310         fd = open(filename, O_RDONLY);
311         if (fd < 0) {
312                 printf("Unable to open PNM file %s: %s (%d)\n", filename,
313                        strerror(errno), errno);
314                 return NULL;
315         }
316
317         /* Read and validate the header. */
318         ret = pnm_read_bytes(fd, buffer, 2);
319         if (ret < 0)
320                 goto done;
321
322         if (buffer[0] != 'P' || buffer[1] != '6') {
323                 printf("Invalid PNM file: invalid signature\n");
324                 ret = -EINVAL;
325                 goto done;
326         }
327
328         /* Read the width, height and depth. */
329         ret = pnm_read_integer(fd);
330         if (ret < 0) {
331                 printf("Invalid PNM file: invalid width\n");
332                 goto done;
333         }
334
335         width = ret;
336
337         ret = pnm_read_integer(fd);
338         if (ret < 0) {
339                 printf("Invalid PNM file: invalid height\n");
340                 goto done;
341         }
342
343         height = ret;
344
345         ret = pnm_read_integer(fd);
346         if (ret < 0) {
347                 printf("Invalid PNM file: invalid depth\n");
348                 goto done;
349         }
350
351         if (ret != 255) {
352                 printf("Invalid PNM file: unsupported depth %u\n", ret);
353                 ret = -EINVAL;
354                 goto done;
355         }
356
357         /* Allocate the image and read the data. */
358         image = image_new(format_by_name("RGB24"), width, height);
359         if (!image)
360                 goto done;
361
362         ret = pnm_read_bytes(fd, image->data, image->size);
363         if (ret < 0) {
364                 image_delete(image);
365                 image = NULL;
366         }
367
368 done:
369         close(fd);
370
371         return ret ? NULL : image;
372 }
373
374 static struct image *image_read(const char *filename)
375 {
376         return pnm_read(filename);
377 }
378
379 static int image_write(const struct image *image, const char *filename)
380 {
381         int ret;
382         int fd;
383
384         fd = open(filename, O_WRONLY | O_CREAT,
385                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
386         if (fd < 0) {
387                 printf("Unable to open output file %s: %s (%d)\n", filename,
388                        strerror(errno), errno);
389                 return -errno;
390         }
391
392         ret = file_write(fd, image->data, image->size);
393         if (ret < 0)
394                 printf("Unable to write output image: %s (%d)\n",
395                        strerror(-ret), ret);
396         else
397                 ftruncate(fd, image->size);
398
399         close(fd);
400         return ret;
401 }
402
403 /* -----------------------------------------------------------------------------
404  * Image formatting
405  */
406
407 static void image_format_rgb8(const struct image *input, struct image *output,
408                               const struct params *params)
409 {
410         const uint8_t *idata = input->data;
411         uint8_t *odata = output->data;
412         uint8_t r, g, b;
413         unsigned int x, y;
414
415         idata = input->data;
416         odata = output->data;
417
418         for (y = 0; y < input->height; ++y) {
419                 for (x = 0; x < input->width; ++x) {
420                         /* There's only one RGB8 variant supported, hardcode it. */
421                         r = *idata++ >> 5;
422                         g = *idata++ >> 5;
423                         b = *idata++ >> 6;
424
425                         *odata++ = (r << 5) | (g << 2) | b;
426                 }
427         }
428 }
429
430 static void image_format_rgb16(const struct image *input, struct image *output,
431                                const struct params *params)
432 {
433         const struct format_info *format = output->format;
434         const uint8_t *idata = input->data;
435         uint16_t *odata = output->data;
436         uint8_t r, g, b, a;
437         unsigned int x, y;
438
439         for (y = 0; y < input->height; ++y) {
440                 for (x = 0; x < input->width; ++x) {
441                         r = *idata++ >> (8 - format->rgb.red.length);
442                         g = *idata++ >> (8 - format->rgb.green.length);
443                         b = *idata++ >> (8 - format->rgb.blue.length);
444                         a = params->alpha >> (8 - format->rgb.alpha.length);
445
446                         *odata++ = (r << format->rgb.red.offset)
447                                  | (g << format->rgb.green.offset)
448                                  | (b << format->rgb.blue.offset)
449                                  | (a << format->rgb.alpha.offset);
450                 }
451         }
452 }
453
454 static void image_format_rgb24(const struct image *input, struct image *output,
455                                const struct params *params)
456 {
457         struct color_rgb24 {
458                 unsigned int value:24;
459         } __attribute__((__packed__));
460
461         const struct format_info *format = output->format;
462         const uint8_t *idata = input->data;
463         struct color_rgb24 *odata = output->data;
464         uint8_t r, g, b, a;
465         unsigned int x, y;
466
467         idata = input->data;
468         odata = output->data;
469
470         for (y = 0; y < input->height; ++y) {
471                 for (x = 0; x < input->width; ++x) {
472                         r = *idata++ >> (8 - format->rgb.red.length);
473                         g = *idata++ >> (8 - format->rgb.green.length);
474                         b = *idata++ >> (8 - format->rgb.blue.length);
475                         a = params->alpha >> (8 - format->rgb.alpha.length);
476
477                         *odata++ = (struct color_rgb24){ .value =
478                                         (r << format->rgb.red.offset) |
479                                         (g << format->rgb.green.offset) |
480                                         (b << format->rgb.blue.offset) |
481                                         (a << format->rgb.alpha.offset) };
482                 }
483         }
484 }
485
486 static void image_format_rgb32(const struct image *input, struct image *output,
487                                const struct params *params)
488 {
489         const struct format_info *format = output->format;
490         const uint8_t *idata = input->data;
491         uint32_t *odata = output->data;
492         uint8_t r, g, b, a;
493         unsigned int x, y;
494
495         for (y = 0; y < input->height; ++y) {
496                 for (x = 0; x < input->width; ++x) {
497                         r = *idata++ >> (8 - format->rgb.red.length);
498                         g = *idata++ >> (8 - format->rgb.green.length);
499                         b = *idata++ >> (8 - format->rgb.blue.length);
500                         a = params->alpha >> (8 - format->rgb.alpha.length);
501
502                         *odata++ = (r << format->rgb.red.offset)
503                                  | (g << format->rgb.green.offset)
504                                  | (b << format->rgb.blue.offset)
505                                  | (a << format->rgb.alpha.offset);
506                 }
507         }
508 }
509
510 /*
511  * In YUV packed and planar formats, when subsampling horizontally average the
512  * chroma components of the two pixels to match the hardware behaviour.
513  */
514 static void image_format_yuv_packed(const struct image *input, struct image *output,
515                                     const struct params *params)
516 {
517         const struct format_info *format = output->format;
518         const uint8_t *idata = input->data;
519         uint8_t *o_y = output->data + ((format->yuv.order & YUV_YC) ? 0 : 1);
520         uint8_t *o_c = output->data + ((format->yuv.order & YUV_CY) ? 0 : 1);
521         unsigned int u_offset = (format->yuv.order & YUV_YCrCb) ? 2 : 0;
522         unsigned int v_offset = (format->yuv.order & YUV_YCbCr) ? 2 : 0;
523         unsigned int x;
524         unsigned int y;
525
526         for (y = 0; y < output->height; ++y) {
527                 for (x = 0; x < output->width; x += 2) {
528                         o_y[2*x] = idata[3*x];
529                         o_y[2*x + 2] = idata[3*x + 3];
530                         o_c[2*x + u_offset] = (idata[3*x + 1] + idata[3*x + 4]) / 2;
531                         o_c[2*x + v_offset] = (idata[3*x + 2] + idata[3*x + 5]) / 2;
532                 }
533
534                 o_y += input->width * 2;
535                 o_c += input->width * 2;
536                 idata += input->width * 3;
537         }
538 }
539
540 static void image_format_yuv_planar(const struct image *input, struct image *output,
541                                     const struct params *params)
542 {
543         const struct format_info *format = output->format;
544         const uint8_t *idata;
545         uint8_t *o_y = output->data;
546         uint8_t *o_c = o_y + output->width * output->height;
547         uint8_t *o_u;
548         uint8_t *o_v;
549         unsigned int xsub = format->yuv.xsub;
550         unsigned int ysub = format->yuv.ysub;
551         unsigned int c_stride;
552         unsigned int x;
553         unsigned int y;
554
555         if (format->yuv.num_planes == 2) {
556                 o_u = (format->yuv.order & YUV_YCbCr) ? o_c : o_c + 1;
557                 o_v = (format->yuv.order & YUV_YCrCb) ? o_c : o_c + 1;
558                 c_stride = 2;
559         } else {
560                 unsigned int c_size = output->width * output->height
561                                     / xsub / ysub;
562
563                 o_u = (format->yuv.order & YUV_YCbCr) ? o_c : o_c + c_size;
564                 o_v = (format->yuv.order & YUV_YCrCb) ? o_c : o_c + c_size;
565                 c_stride = 1;
566         }
567
568         idata = input->data;
569         for (y = 0; y < output->height; ++y) {
570                 for (x = 0; x < output->width; ++x)
571                         *o_y++ = idata[3*x];
572
573                 idata += input->width * 3;
574         }
575
576         idata = input->data;
577         for (y = 0; y < output->height / ysub; ++y) {
578                 if (xsub == 1) {
579                         for (x = 0; x < output->width; x += xsub) {
580                                 o_u[x*c_stride/xsub] = idata[3*x + 1];
581                                 o_v[x*c_stride/xsub] = idata[3*x + 2];
582                         }
583                 } else {
584                         for (x = 0; x < output->width; x += xsub) {
585                                 o_u[x*c_stride/xsub] = (idata[3*x + 1] + idata[3*x + 4]) / 2;
586                                 o_v[x*c_stride/xsub] = (idata[3*x + 2] + idata[3*x + 5]) / 2;
587                         }
588                 }
589
590                 o_u += output->width * c_stride / xsub;
591                 o_v += output->width * c_stride / xsub;
592                 idata += input->width * 3 * ysub;
593         }
594 }
595
596 /* -----------------------------------------------------------------------------
597  * Colorspace handling
598  *
599  * The code is inspired by the v4l2-tpg Linux kernel driver.
600  */
601
602 static void colorspace_matrix(enum v4l2_ycbcr_encoding encoding,
603                               enum v4l2_quantization quantization,
604                               int (*matrix)[3][3])
605 {
606 #define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
607
608         static const int bt601[3][3] = {
609                 { COEFF(0.299, 219),  COEFF(0.587, 219),  COEFF(0.114, 219)  },
610                 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224)    },
611                 { COEFF(0.5, 224),    COEFF(-0.419, 224), COEFF(-0.081, 224) },
612         };
613         static const int bt601_full[3][3] = {
614                 { COEFF(0.299, 255),  COEFF(0.587, 255),  COEFF(0.114, 255)  },
615                 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255)    },
616                 { COEFF(0.5, 255),    COEFF(-0.419, 255), COEFF(-0.081, 255) },
617         };
618         static const int rec709[3][3] = {
619                 { COEFF(0.2126, 219),  COEFF(0.7152, 219),  COEFF(0.0722, 219)  },
620                 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224)     },
621                 { COEFF(0.5, 224),     COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
622         };
623         static const int rec709_full[3][3] = {
624                 { COEFF(0.2126, 255),  COEFF(0.7152, 255),  COEFF(0.0722, 255)  },
625                 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255)     },
626                 { COEFF(0.5, 255),     COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
627         };
628         static const int smpte240m[3][3] = {
629                 { COEFF(0.212, 219),  COEFF(0.701, 219),  COEFF(0.087, 219)  },
630                 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224)    },
631                 { COEFF(0.5, 224),    COEFF(-0.445, 224), COEFF(-0.055, 224) },
632         };
633         static const int smpte240m_full[3][3] = {
634                 { COEFF(0.212, 255),  COEFF(0.701, 255),  COEFF(0.087, 255)  },
635                 { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255)    },
636                 { COEFF(0.5, 255),    COEFF(-0.445, 255), COEFF(-0.055, 255) },
637         };
638         static const int bt2020[3][3] = {
639                 { COEFF(0.2627, 219),  COEFF(0.6780, 219),  COEFF(0.0593, 219)  },
640                 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224)     },
641                 { COEFF(0.5, 224),     COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
642         };
643         static const int bt2020_full[3][3] = {
644                 { COEFF(0.2627, 255),  COEFF(0.6780, 255),  COEFF(0.0593, 255)  },
645                 { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255)     },
646                 { COEFF(0.5, 255),     COEFF(-0.4698, 255), COEFF(-0.0402, 255) },
647         };
648
649         bool full = quantization == V4L2_QUANTIZATION_FULL_RANGE;
650         unsigned int i;
651         const int (*m)[3][3];
652
653         switch (encoding) {
654         case V4L2_YCBCR_ENC_601:
655         default:
656                 m = full ? &bt601_full : &bt601;
657                 break;
658         case V4L2_YCBCR_ENC_709:
659                 m = full ? &rec709_full : &rec709;
660                 break;
661         case V4L2_YCBCR_ENC_BT2020:
662                 m = full ? &bt2020_full : &bt2020;
663                 break;
664         case V4L2_YCBCR_ENC_SMPTE240M:
665                 m = full ? &smpte240m_full : &smpte240m;
666                 break;
667         }
668
669         for (i = 0; i < ARRAY_SIZE(*m); ++i)
670                 memcpy((*matrix)[i], (*m)[i], sizeof((*m)[i]));
671 }
672
673 static void colorspace_rgb2ycbcr(int m[3][3],
674                                  enum v4l2_quantization quantization,
675                                  const uint8_t rgb[3], uint8_t ycbcr[3])
676 {
677         bool full = quantization == V4L2_QUANTIZATION_FULL_RANGE;
678         unsigned int y_offset = full ? 0 : 16;
679         int r, g, b;
680         int y, cb, cr;
681         int div;
682
683         r = rgb[0] << 4;
684         g = rgb[1] << 4;
685         b = rgb[2] << 4;
686
687         div = (1 << (8 + 4)) * 255;
688         y  = (m[0][0] * r + m[0][1] * g + m[0][2] * b + y_offset * div) / div;
689         cb = (m[1][0] * r + m[1][1] * g + m[1][2] * b + 128 * div) / div;
690         cr = (m[2][0] * r + m[2][1] * g + m[2][2] * b + 128 * div) / div;
691
692         ycbcr[0] = y;
693         ycbcr[1] = cb;
694         ycbcr[2] = cr;
695 }
696
697 static void image_colorspace_rgb_to_yuv(const struct image *input,
698                                         struct image *output,
699                                         const struct params *params)
700 {
701         int matrix[3][3];
702         const uint8_t *idata = input->data;
703         uint8_t *odata = output->data;
704         unsigned int x;
705         unsigned int y;
706
707         colorspace_matrix(params->encoding, params->quantization, &matrix);
708
709         for (y = 0; y < output->height; ++y) {
710                 for (x = 0; x < output->width; ++x) {
711                         colorspace_rgb2ycbcr(matrix, params->quantization, idata, odata);
712                         idata += 3;
713                         odata += 3;
714                 }
715         }
716 }
717
718 /* -----------------------------------------------------------------------------
719  * Image scaling
720  */
721
722 static void image_scale_bilinear(const struct image *input, struct image *output)
723 {
724 #define _C0(x, y)       (idata[0][((y)*input->width+(x)) * 3])
725 #define _C1(x, y)       (idata[1][((y)*input->width+(x)) * 3])
726 #define _C2(x, y)       (idata[2][((y)*input->width+(x)) * 3])
727         const uint8_t *idata[3] = { input->data, input->data + 1, input->data + 2 };
728         uint8_t *odata = output->data;
729         uint8_t c0, c1, c2;
730         unsigned int u, v;
731
732         for (v = 0; v < output->height; ++v) {
733                 double v_input = (double)v / (output->height - 1) * (input->height - 1);
734                 unsigned int y = floor(v_input);
735                 double v_ratio = v_input - y;
736
737                 for (u = 0; u < output->width; ++u) {
738                         double u_input = (double)u / (output->width - 1) * (input->width - 1);
739                         unsigned int x = floor(u_input);
740                         double u_ratio = u_input - x;
741
742                         c0 = (_C0(x, y)   * (1 - u_ratio) + _C0(x+1, y)   * u_ratio) * (1 - v_ratio)
743                            + (_C0(x, y+1) * (1 - u_ratio) + _C0(x+1, y+1) * u_ratio) * v_ratio;
744                         c1 = (_C1(x, y)   * (1 - u_ratio) + _C1(x+1, y)   * u_ratio) * (1 - v_ratio)
745                            + (_C1(x, y+1) * (1 - u_ratio) + _C1(x+1, y+1) * u_ratio) * v_ratio;
746                         c2 = (_C2(x, y)   * (1 - u_ratio) + _C2(x+1, y)   * u_ratio) * (1 - v_ratio)
747                            + (_C2(x, y+1) * (1 - u_ratio) + _C2(x+1, y+1) * u_ratio) * v_ratio;
748
749                         *odata++ = c0;
750                         *odata++ = c1;
751                         *odata++ = c2;
752                 }
753         }
754 #undef _C0
755 #undef _C1
756 #undef _C2
757 }
758
759 static void image_scale(const struct image *input, struct image *output,
760                         const struct params *params)
761 {
762         image_scale_bilinear(input, output);
763 }
764
765 /* -----------------------------------------------------------------------------
766  * Image composing
767  */
768
769 static void image_compose(const struct image *input, struct image *output,
770                           unsigned int num_inputs)
771 {
772         const uint8_t *idata = input->data;
773         uint8_t *odata = output->data;
774         unsigned int offset = 50;
775         unsigned int y;
776         unsigned int i;
777
778         memset(odata, 0, output->size);
779
780         for (i = 0; i < num_inputs; ++i) {
781                 unsigned int dst_offset = (offset * output->width + offset) * 3;
782
783                 if (offset >= output->width || offset >= output->height)
784                         break;
785
786                 for (y = 0; y < output->height - offset; ++y)
787                         memcpy(odata + y * output->width * 3 + dst_offset,
788                                idata + y * output->width * 3,
789                                (output->width - offset) * 3);
790
791                 offset += 50;
792         }
793 }
794
795 /* -----------------------------------------------------------------------------
796  * Histogram
797  */
798
799 static void histogram_compute(const struct image *image, void *histo)
800 {
801         const uint8_t *data = image->data;
802         uint8_t comp_min[3] = { 255, 255, 255 };
803         uint8_t comp_max[3] = { 0, 0, 0 };
804         uint32_t comp_sums[3] = { 0, 0, 0 };
805         uint32_t comp_bins[3][64];
806         unsigned int comp_map[3];
807         unsigned int x, y;
808         unsigned int i, j;
809
810         if (image->format->is_yuv)
811                 memcpy(comp_map, (unsigned int[3]){ 2, 0, 1 }, sizeof(comp_map));
812         else
813                 memcpy(comp_map, (unsigned int[3]){ 0, 1, 2 }, sizeof(comp_map));
814
815         memset(comp_bins, 0, sizeof(comp_bins));
816
817         for (y = 0; y < image->height; ++y) {
818                 for (x = 0; x < image->width; ++x) {
819                         for (i = 0; i < 3; ++i) {
820                                 comp_min[i] = min(*data, comp_min[i]);
821                                 comp_max[i] = max(*data, comp_max[i]);
822                                 comp_sums[i] += *data;
823                                 comp_bins[i][*data >> 2]++;
824                                 data++;
825                         }
826                 }
827         }
828
829         for (i = 0; i < ARRAY_SIZE(comp_min); ++i) {
830                 *(uint8_t *)histo++ = comp_min[comp_map[i]];
831                 *(uint8_t *)histo++ = 0;
832                 *(uint8_t *)histo++ = comp_max[comp_map[i]];
833                 *(uint8_t *)histo++ = 0;
834         }
835
836         for (i = 0; i < ARRAY_SIZE(comp_sums); ++i) {
837                 *(uint32_t *)histo = comp_sums[comp_map[i]];
838                 histo += 4;
839         }
840
841         for (i = 0; i < ARRAY_SIZE(comp_bins); ++i) {
842                 for (j = 0; j < ARRAY_SIZE(comp_bins[i]); ++j) {
843                         *(uint32_t *)histo = comp_bins[comp_map[i]][j];
844                         histo += 4;
845                 }
846         }
847 }
848
849 static int histogram(const struct image *image, const char *filename)
850 {
851         uint8_t data[3*4 + 3*4 + 3*64*4];
852         int ret;
853         int fd;
854
855         histogram_compute(image, data);
856
857         fd = open(filename, O_WRONLY | O_CREAT,
858                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
859         if (fd < 0) {
860                 printf("Unable to open histogram file %s: %s (%d)\n", filename,
861                        strerror(errno), errno);
862                 return -errno;
863         }
864
865         ret = file_write(fd, data, sizeof(data));
866         if (ret < 0)
867                 printf("Unable to write histogram: %s (%d)\n",
868                        strerror(-ret), ret);
869         else
870                 ftruncate(fd, sizeof(data));
871
872         close(fd);
873         return ret;
874 }
875
876 /* -----------------------------------------------------------------------------
877  * Processing pipeline
878  */
879
880 static int process(const struct options *options)
881 {
882         struct image *input = NULL;
883         struct image *output = NULL;
884         unsigned int output_width;
885         unsigned int output_height;
886         int ret = 0;
887
888         /* Read the input image */
889         input = image_read(options->input_filename);
890         if (!input) {
891                 ret = -EINVAL;
892                 goto done;
893         }
894
895         /* Convert colorspace */
896         if (options->process_yuv) {
897                 struct image *yuv;
898
899                 yuv = image_new(format_by_name("YUV24"), input->width,
900                                 input->height);
901                 if (!yuv) {
902                         ret = -ENOMEM;
903                         goto done;
904                 }
905
906                 image_colorspace_rgb_to_yuv(input, yuv, &options->params);
907                 image_delete(input);
908                 input = yuv;
909         }
910
911         /* Scale */
912         if (options->output_width && options->output_height) {
913                 output_width = options->output_width;
914                 output_height = options->output_height;
915         } else {
916                 output_width = input->width;
917                 output_height = input->height;
918         }
919
920         if (input->width != output_width ||
921             input->height != output_height) {
922                 struct image *scaled;
923
924                 scaled = image_new(input->format, output_width, output_height);
925                 if (!scaled) {
926                         ret = -ENOMEM;
927                         goto done;
928                 }
929
930                 image_scale(input, scaled, &options->params);
931                 image_delete(input);
932                 input = scaled;
933         }
934
935         /* Compose */
936         if (options->compose) {
937                 struct image *composed;
938
939                 composed = image_new(input->format, input->width, input->height);
940                 if (!composed) {
941                         ret = -ENOMEM;
942                         goto done;
943                 }
944
945                 image_compose(input, composed, options->compose);
946                 image_delete(input);
947                 input = composed;
948         }
949
950         /* Compute the histogram */
951         if (options->histo_filename) {
952                 ret = histogram(input, options->histo_filename);
953                 if (ret)
954                         goto done;
955         }
956
957         /* Format the output */
958         if (input->format->is_yuv && !options->output_format->is_yuv) {
959                 printf("RGB output with YUV processing not supported\n");
960                 ret = -EINVAL;
961                 goto done;
962         }
963
964         if (!input->format->is_yuv && options->output_format->is_yuv) {
965                 const struct format_info *format = format_by_name("YUV24");
966                 struct image *converted;
967
968                 converted = image_new(format, input->width, input->height);
969                 if (!converted) {
970                         ret = -ENOMEM;
971                         goto done;
972                 }
973
974                 image_colorspace_rgb_to_yuv(input, converted, &options->params);
975                 image_delete(input);
976                 input = converted;
977         }
978
979         output = image_new(options->output_format, input->width, input->height);
980         if (!output) {
981                 ret = -ENOMEM;
982                 goto done;
983         }
984
985         if (output->format->is_yuv) {
986                 switch (output->format->yuv.num_planes) {
987                 case 1:
988                         image_format_yuv_packed(input, output, &options->params);
989                         break;
990                 case 2:
991                 case 3:
992                         image_format_yuv_planar(input, output, &options->params);
993                         break;
994                 default:
995                         ret = -EINVAL;
996                         break;
997                 }
998         } else {
999                 switch (output->format->rgb.bpp) {
1000                 case 8:
1001                         image_format_rgb8(input, output, &options->params);
1002                         break;
1003                 case 16:
1004                         image_format_rgb16(input, output, &options->params);
1005                         break;
1006                 case 24:
1007                         image_format_rgb24(input, output, &options->params);
1008                         break;
1009                 case 32:
1010                         image_format_rgb32(input, output, &options->params);
1011                         break;
1012                 default:
1013                         ret = -EINVAL;
1014                         break;
1015                 }
1016         }
1017
1018         if (ret < 0) {
1019                 printf("Output formatting failed\n");
1020                 goto done;
1021         }
1022
1023         /* Write the output image */
1024         if (options->output_filename) {
1025                 ret = image_write(output, options->output_filename);
1026                 if (ret)
1027                         goto done;
1028         }
1029
1030         ret = 0;
1031
1032 done:
1033         image_delete(input);
1034         image_delete(output);
1035         return ret;
1036 }
1037
1038 /* -----------------------------------------------------------------------------
1039  * Usage, argument parsing and main
1040  */
1041
1042 static void usage(const char *argv0)
1043 {
1044         printf("Usage: %s [options] <infile.pnm>\n\n", argv0);
1045         printf("Convert the input image stored in <infile> in PNM format to\n");
1046         printf("the target format and resolution and store the resulting\n");
1047         printf("image in raw binary form\n\n");
1048         printf("Supported options:\n");
1049         printf("-a, --alpha value       Set the alpha value. Valid syntaxes are floating\n");
1050         printf("                        point values ([0.0 - 1.0]), fixed point values ([0-255])\n");
1051         printf("                        or percentages ([0%% - 100%%]). Defaults to 1.0\n");
1052         printf("-c, --compose n         Compose n copies of the image offset by (50,50) over a black background\n");
1053         printf("-e, --encoding enc      Set the YCbCr encoding method. Valid values are\n");
1054         printf("                        BT.601, REC.709, BT.2020 and SMPTE240M\n");
1055         printf("-f, --format format     Set the output image format\n");
1056         printf("                        Defaults to RGB24 if not specified\n");
1057         printf("                        Use -f help to list the supported formats\n");
1058         printf("-h, --help              Show this help screen\n");
1059         printf("-H, --histogram file    Compute histogram on the output image and store it to file\n");
1060         printf("-o, --output file       Store the output image to file\n");
1061         printf("-q, --quantization q    Set the quantization method. Valid values are\n");
1062         printf("                        limited or full\n");
1063         printf("-s, --size WxH          Set the output image size\n");
1064         printf("                        Defaults to the input size if not specified\n");
1065         printf("-y, --yuv               Perform all processing in YUV space\n");
1066 }
1067
1068 static void list_formats(void)
1069 {
1070         unsigned int i;
1071
1072         for (i = 0; i < ARRAY_SIZE(format_info); i++)
1073                 printf("%s\n", format_info[i].name);
1074 }
1075
1076 static struct option opts[] = {
1077         {"alpha", 1, 0, 'a'},
1078         {"compose", 1, 0, 'c'},
1079         {"encoding", 1, 0, 'e'},
1080         {"format", 1, 0, 'f'},
1081         {"help", 0, 0, 'h'},
1082         {"histogram", 1, 0, 'H'},
1083         {"output", 1, 0, 'o'},
1084         {"quantization", 1, 0, 'q'},
1085         {"size", 1, 0, 's'},
1086         {"yuv", 0, 0, 'y'},
1087         {0, 0, 0, 0}
1088 };
1089
1090 static int parse_args(struct options *options, int argc, char *argv[])
1091 {
1092         char *endptr;
1093         int c;
1094
1095         if (argc < 3) {
1096                 usage(argv[0]);
1097                 return 1;
1098         }
1099
1100         memset(options, 0, sizeof(*options));
1101         options->output_format = format_by_name("RGB24");
1102         options->params.alpha = 255;
1103         options->params.encoding = V4L2_YCBCR_ENC_601;
1104         options->params.quantization = V4L2_QUANTIZATION_LIM_RANGE;
1105
1106         opterr = 0;
1107         while ((c = getopt_long(argc, argv, "a:c:e:f:hH:o:q:s:y", opts, NULL)) != -1) {
1108
1109                 switch (c) {
1110                 case 'a': {
1111                         int alpha;
1112
1113                         if (strchr(optarg, '.')) {
1114                                 alpha = strtod(optarg, &endptr) * 255;
1115                                 if (*endptr != 0)
1116                                         alpha = -1;
1117                         } else {
1118                                 alpha = strtoul(optarg, &endptr, 10);
1119                                 if (*endptr == '%')
1120                                         alpha = alpha * 255 / 100;
1121                                 else if (*endptr != 0)
1122                                         alpha = -1;
1123                         }
1124
1125                         if (alpha < 0 || alpha > 255) {
1126                                 printf("Invalid alpha value '%s'\n", optarg);
1127                                 return 1;
1128                         }
1129
1130                         options->params.alpha = alpha;
1131                         break;
1132                 }
1133
1134                 case 'c':
1135                           options->compose = strtoul(optarg, &endptr, 10);
1136                           if (*endptr != 0) {
1137                                 printf("Invalid compose value '%s'\n", optarg);
1138                                 return 1;
1139                           }
1140                           break;
1141
1142                 case 'e':
1143                         if (!strcmp(optarg, "BT.601")) {
1144                                 options->params.encoding = V4L2_YCBCR_ENC_601;
1145                         } else if (!strcmp(optarg, "REC.709")) {
1146                                 options->params.encoding = V4L2_YCBCR_ENC_709;
1147                         } else if (!strcmp(optarg, "BT.2020")) {
1148                                 options->params.encoding = V4L2_YCBCR_ENC_BT2020;
1149                         } else if (!strcmp(optarg, "SMPTE240M")) {
1150                                 options->params.encoding = V4L2_YCBCR_ENC_SMPTE240M;
1151                         } else {
1152                                 printf("Invalid encoding value '%s'\n", optarg);
1153                                 return 1;
1154                         }
1155                         break;
1156
1157                 case 'f':
1158                         if (!strcmp("help", optarg)) {
1159                                 list_formats();
1160                                 return 1;
1161                         }
1162
1163                         options->output_format = format_by_name(optarg);
1164                         if (!options->output_format) {
1165                                 printf("Unsupported output format '%s'\n", optarg);
1166                                 return 1;
1167                         }
1168
1169                         break;
1170
1171                 case 'h':
1172                         usage(argv[0]);
1173                         exit(0);
1174                         break;
1175
1176                 case 'H':
1177                         options->histo_filename = optarg;
1178                         break;
1179
1180                 case 'o':
1181                         options->output_filename = optarg;
1182                         break;
1183
1184                 case 'q':
1185                         if (!strcmp(optarg, "limited")) {
1186                                 options->params.quantization = V4L2_QUANTIZATION_LIM_RANGE;
1187                         } else if (!strcmp(optarg, "full")) {
1188                                 options->params.quantization = V4L2_QUANTIZATION_FULL_RANGE;
1189                         } else {
1190                                 printf("Invalid quantization value '%s'\n", optarg);
1191                                 return 1;
1192                         }
1193                         break;
1194
1195                         break;
1196
1197                 case 's':
1198                         options->output_width = strtol(optarg, &endptr, 10);
1199                         if (*endptr != 'x' || endptr == optarg) {
1200                                 printf("Invalid size '%s'\n", optarg);
1201                                 return 1;
1202                         }
1203
1204                         options->output_height = strtol(endptr + 1, &endptr, 10);
1205                         if (*endptr != 0) {
1206                                 printf("Invalid size '%s'\n", optarg);
1207                                 return 1;
1208                         }
1209                         break;
1210
1211                 case 'y':
1212                         options->process_yuv = true;
1213                         break;
1214
1215                 default:
1216                         printf("Invalid option -%c\n", c);
1217                         printf("Run %s -h for help.\n", argv[0]);
1218                         return 1;
1219                 }
1220         }
1221
1222         if (optind != argc - 1) {
1223                 usage(argv[0]);
1224                 return 1;
1225         }
1226
1227         options->input_filename = argv[optind];
1228
1229         return 0;
1230 }
1231
1232 int main(int argc, char *argv[])
1233 {
1234         struct options options;
1235         int ret;
1236
1237         ret = parse_args(&options, argc, argv);
1238         if (ret)
1239                 return ret;
1240
1241         ret = process(&options);
1242         if (ret)
1243                 return 1;
1244
1245         return 0;
1246 }