gen-image: Implement option to parse an input crop
[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 #define swap(a, b)                      \
43 do {    \
44         typeof(a) __tmp = (a);          \
45         (a) = (b);                      \
46         (b) = __tmp;                    \
47 } while (0)
48
49 enum format_type {
50         FORMAT_RGB,
51         FORMAT_YUV,
52         FORMAT_HSV,
53 };
54
55 struct format_color_component {
56         unsigned char length;
57         unsigned char offset;
58 };
59
60 struct format_rgb_info {
61         unsigned int bpp;
62         struct format_color_component red;
63         struct format_color_component green;
64         struct format_color_component blue;
65         struct format_color_component alpha;
66 };
67
68 struct format_hsv_info {
69         unsigned int bpp;
70         struct format_color_component hue;
71         struct format_color_component saturation;
72         struct format_color_component value;
73         struct format_color_component alpha;
74 };
75
76 enum format_yuv_order {
77         YUV_YCbCr = 1,
78         YUV_YCrCb = 2,
79         YUV_YC = 4,
80         YUV_CY = 8,
81 };
82
83 struct format_yuv_info {
84         unsigned int num_planes;
85         enum format_yuv_order order;
86         unsigned int xsub;
87         unsigned int ysub;
88 };
89
90 struct format_info {
91         const char *name;
92         enum format_type type;
93         struct format_rgb_info rgb;
94         struct format_hsv_info hsv;
95         struct format_yuv_info yuv;
96 };
97
98 struct image_rect {
99         int left;
100         int top;
101         unsigned int width;
102         unsigned int height;
103 };
104
105 struct image {
106         const struct format_info *format;
107         unsigned int width;
108         unsigned int height;
109         unsigned int size;
110         void *data;
111 };
112
113 struct params {
114         unsigned int alpha;
115         enum v4l2_ycbcr_encoding encoding;
116         enum v4l2_quantization quantization;
117         bool no_chroma_average;
118 };
119
120 struct options {
121         const char *input_filename;
122         const char *output_filename;
123         const char *histo_filename;
124         const char *clu_filename;
125         const char *lut_filename;
126
127         const struct format_info *input_format;
128         const struct format_info *output_format;
129         unsigned int output_height;
130         unsigned int output_width;
131
132         bool hflip;
133         bool vflip;
134         bool rotate;
135         unsigned int compose;
136         struct params params;
137         bool crop;
138         struct image_rect inputcrop;
139 };
140
141 /* -----------------------------------------------------------------------------
142  * Format information
143  */
144
145 #define MAKE_HSV_INFO(hl, ho, sl, so, vl, vo, al, ao) \
146         .hue = { (hl), (ho) }, .saturation = { (sl), (so) }, \
147         .value = { (vl), (vo) }, .alpha = { (al), (ao) }
148
149 #define MAKE_RGB_INFO(rl, ro, gl, go, bl, bo, al, ao) \
150         .red = { (rl), (ro) }, .green = { (gl), (go) }, \
151         .blue = { (bl), (bo) }, .alpha = { (al), (ao) }
152
153 static const struct format_info format_info[] = {
154         /*
155          * The alpha channel maps to the X (don't care) bits for the XRGB
156          * formats.
157          */
158         { "RGB332",     FORMAT_RGB, .rgb = { 8,  MAKE_RGB_INFO(3, 5, 3, 2, 2, 0, 0, 0) } },
159         { "ARGB444",    FORMAT_RGB, .rgb = { 16, MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 4, 12) } },
160         { "XRGB444",    FORMAT_RGB, .rgb = { 16, MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 4, 12) } },
161         { "ARGB555",    FORMAT_RGB, .rgb = { 16, MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 1, 15) } },
162         { "XRGB555",    FORMAT_RGB, .rgb = { 16, MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 1, 15) } },
163         { "RGB565",     FORMAT_RGB, .rgb = { 16, MAKE_RGB_INFO(5, 11, 6, 5, 5, 0, 0, 0) } },
164         { "BGR24",      FORMAT_RGB, .rgb = { 24, MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) } },
165         { "RGB24",      FORMAT_RGB, .rgb = { 24, MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) } },
166         { "ABGR32",     FORMAT_RGB, .rgb = { 32, MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 8, 24) } },
167         { "XBGR32",     FORMAT_RGB, .rgb = { 32, MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 8, 24) } },
168         { "ARGB32",     FORMAT_RGB, .rgb = { 32, MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 8, 0) } },
169         { "XRGB32",     FORMAT_RGB, .rgb = { 32, MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 8, 0) } },
170         { "HSV24",      FORMAT_HSV, .hsv = { 24, MAKE_HSV_INFO(8, 0, 8, 8, 8, 16, 0, 0) } },
171         { "HSV32",      FORMAT_HSV, .hsv = { 32, MAKE_HSV_INFO(8, 8, 8, 16, 8, 24, 8, 0) } },
172         { "UYVY",       FORMAT_YUV, .yuv = { 1, YUV_YCbCr | YUV_CY, 2, 1 } },
173         { "VYUY",       FORMAT_YUV, .yuv = { 1, YUV_YCrCb | YUV_CY, 2, 1 } },
174         { "YUYV",       FORMAT_YUV, .yuv = { 1, YUV_YCbCr | YUV_YC, 2, 1 } },
175         { "YVYU",       FORMAT_YUV, .yuv = { 1, YUV_YCrCb | YUV_YC, 2, 1 } },
176         { "NV12M",      FORMAT_YUV, .yuv = { 2, YUV_YCbCr, 2, 2 } },
177         { "NV21M",      FORMAT_YUV, .yuv = { 2, YUV_YCrCb, 2, 2 } },
178         { "NV16M",      FORMAT_YUV, .yuv = { 2, YUV_YCbCr, 2, 1 } },
179         { "NV61M",      FORMAT_YUV, .yuv = { 2, YUV_YCrCb, 2, 1 } },
180         { "YUV420M",    FORMAT_YUV, .yuv = { 3, YUV_YCbCr, 2, 2 } },
181         { "YVU420M",    FORMAT_YUV, .yuv = { 3, YUV_YCrCb, 2, 2 } },
182         { "YUV422M",    FORMAT_YUV, .yuv = { 3, YUV_YCbCr, 2, 1 } },
183         { "YVU422M",    FORMAT_YUV, .yuv = { 3, YUV_YCrCb, 2, 1 } },
184         { "YUV444M",    FORMAT_YUV, .yuv = { 3, YUV_YCbCr, 1, 1 } },
185         { "YVU444M",    FORMAT_YUV, .yuv = { 3, YUV_YCrCb, 1, 1 } },
186         { "YUV24",      FORMAT_YUV, .yuv = { 1, YUV_YCbCr | YUV_YC, 1, 1 } },
187 };
188
189 static const struct format_info *format_by_name(const char *name)
190 {
191         unsigned int i;
192
193         for (i = 0; i < ARRAY_SIZE(format_info); i++) {
194                 if (!strcmp(name, format_info[i].name))
195                         return &format_info[i];
196         }
197
198         return NULL;
199 }
200
201 /* -----------------------------------------------------------------------------
202  * File I/O
203  */
204
205 static int file_read(int fd, void *buffer, size_t size)
206 {
207         unsigned int offset = 0;
208
209         while (offset < size) {
210                 ssize_t nbytes;
211
212                 nbytes = read(fd, buffer + offset, size - offset);
213                 if (nbytes < 0) {
214                         if (errno == EINTR)
215                                 continue;
216
217                         return -errno;
218                 }
219
220                 if (nbytes == 0)
221                         return offset;
222
223                 offset += nbytes;
224         }
225
226         return size;
227 }
228
229 static int file_write(int fd, const void *buffer, size_t size)
230 {
231         unsigned int offset = 0;
232
233         while (offset < size) {
234                 ssize_t nbytes;
235
236                 nbytes = write(fd, buffer + offset, size - offset);
237                 if (nbytes < 0) {
238                         if (errno == EINTR)
239                                 continue;
240
241                         return -errno;
242                 }
243
244                 offset += nbytes;
245         }
246
247         return 0;
248 }
249
250 /* -----------------------------------------------------------------------------
251  * Image initialization
252  */
253
254 static struct image *image_new(const struct format_info *format,
255                                unsigned int width, unsigned int height)
256 {
257         struct image *image;
258
259         image = malloc(sizeof(*image));
260         if (!image)
261                 return NULL;
262
263         memset(image, 0, sizeof(*image));
264         image->format = format;
265         image->width = width;
266         image->height = height;
267
268         switch (format->type) {
269         case FORMAT_RGB:
270                 image->size = image->width * image->height
271                              * format->rgb.bpp / 8;
272                 break;
273
274         case FORMAT_HSV:
275                 image->size = image->width * image->height
276                              * format->hsv.bpp / 8;
277                 break;
278
279         case FORMAT_YUV:
280                 image->size = image->width * image->height
281                              * (8 + 2 * 8 / format->yuv.xsub / format->yuv.ysub)
282                              / 8;
283                 break;
284         }
285
286         image->data = malloc(image->size);
287         if (!image->data) {
288                 printf("Not enough memory for image data\n");
289                 free(image);
290                 return NULL;
291         }
292
293         return image;
294 }
295
296 static void image_delete(struct image *image)
297 {
298         if (!image)
299                 return;
300
301         free(image->data);
302         free(image);
303 }
304
305 /* -----------------------------------------------------------------------------
306  * Image read and write
307  */
308
309 static int pnm_read_bytes(int fd, char *buffer, size_t size)
310 {
311         int ret;
312
313         ret = file_read(fd, buffer, size);
314         if (ret < 0) {
315                 printf("Unable to read PNM file: %s (%d)\n", strerror(-ret),
316                        ret);
317                 return ret;
318         }
319         if ((size_t)ret != size) {
320                 printf("Invalid PNM file: file too short\n");
321                 return -ENODATA;
322         }
323
324         return 0;
325 }
326
327 static int pnm_read_integer(int fd)
328 {
329         unsigned int value = 0;
330         int ret;
331         char c;
332
333         do {
334                 ret = pnm_read_bytes(fd, &c, 1);
335         } while (!ret && isspace(c));
336
337         if (ret)
338                 return ret;
339
340         while (!ret && isdigit(c)) {
341                 value = value * 10 + c - '0';
342                 ret = pnm_read_bytes(fd, &c, 1);
343         }
344
345         if (ret)
346                 return ret;
347
348         if (!isspace(c))
349                 return -EINVAL;
350
351         return value;
352 }
353
354 static struct image *pnm_read(const char *filename)
355 {
356         struct image *image;
357         unsigned int width;
358         unsigned int height;
359         char buffer[2];
360         int ret;
361         int fd;
362
363         fd = open(filename, O_RDONLY);
364         if (fd < 0) {
365                 printf("Unable to open PNM file %s: %s (%d)\n", filename,
366                        strerror(errno), errno);
367                 return NULL;
368         }
369
370         /* Read and validate the header. */
371         ret = pnm_read_bytes(fd, buffer, 2);
372         if (ret < 0)
373                 goto done;
374
375         if (buffer[0] != 'P' || buffer[1] != '6') {
376                 printf("Invalid PNM file: invalid signature\n");
377                 ret = -EINVAL;
378                 goto done;
379         }
380
381         /* Read the width, height and depth. */
382         ret = pnm_read_integer(fd);
383         if (ret < 0) {
384                 printf("Invalid PNM file: invalid width\n");
385                 goto done;
386         }
387
388         width = ret;
389
390         ret = pnm_read_integer(fd);
391         if (ret < 0) {
392                 printf("Invalid PNM file: invalid height\n");
393                 goto done;
394         }
395
396         height = ret;
397
398         ret = pnm_read_integer(fd);
399         if (ret < 0) {
400                 printf("Invalid PNM file: invalid depth\n");
401                 goto done;
402         }
403
404         if (ret != 255) {
405                 printf("Invalid PNM file: unsupported depth %u\n", ret);
406                 ret = -EINVAL;
407                 goto done;
408         }
409
410         /* Allocate the image and read the data. */
411         image = image_new(format_by_name("RGB24"), width, height);
412         if (!image)
413                 goto done;
414
415         ret = pnm_read_bytes(fd, image->data, image->size);
416         if (ret < 0) {
417                 image_delete(image);
418                 image = NULL;
419         }
420
421 done:
422         close(fd);
423
424         return ret ? NULL : image;
425 }
426
427 static struct image *image_read(const char *filename)
428 {
429         return pnm_read(filename);
430 }
431
432 static int image_write(const struct image *image, const char *filename)
433 {
434         int ret;
435         int fd;
436
437         fd = open(filename, O_WRONLY | O_CREAT,
438                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
439         if (fd < 0) {
440                 printf("Unable to open output file %s: %s (%d)\n", filename,
441                        strerror(errno), errno);
442                 return -errno;
443         }
444
445         ret = file_write(fd, image->data, image->size);
446         if (ret < 0)
447                 printf("Unable to write output image: %s (%d)\n",
448                        strerror(-ret), ret);
449         else
450                 ftruncate(fd, image->size);
451
452         close(fd);
453         return ret;
454 }
455
456 /* -----------------------------------------------------------------------------
457  * Image formatting
458  */
459
460 static void image_format_rgb8(const struct image *input, struct image *output,
461                               const struct params *params)
462 {
463         const uint8_t *idata = input->data;
464         uint8_t *odata = output->data;
465         uint8_t r, g, b;
466         unsigned int x, y;
467
468         idata = input->data;
469         odata = output->data;
470
471         for (y = 0; y < input->height; ++y) {
472                 for (x = 0; x < input->width; ++x) {
473                         /* There's only one RGB8 variant supported, hardcode it. */
474                         r = *idata++ >> 5;
475                         g = *idata++ >> 5;
476                         b = *idata++ >> 6;
477
478                         *odata++ = (r << 5) | (g << 2) | b;
479                 }
480         }
481 }
482
483 static void image_format_rgb16(const struct image *input, struct image *output,
484                                const struct params *params)
485 {
486         const struct format_info *format = output->format;
487         const uint8_t *idata = input->data;
488         uint16_t *odata = output->data;
489         uint8_t r, g, b, a;
490         unsigned int x, y;
491
492         for (y = 0; y < input->height; ++y) {
493                 for (x = 0; x < input->width; ++x) {
494                         r = *idata++ >> (8 - format->rgb.red.length);
495                         g = *idata++ >> (8 - format->rgb.green.length);
496                         b = *idata++ >> (8 - format->rgb.blue.length);
497                         a = params->alpha >> (8 - format->rgb.alpha.length);
498
499                         *odata++ = (r << format->rgb.red.offset)
500                                  | (g << format->rgb.green.offset)
501                                  | (b << format->rgb.blue.offset)
502                                  | (a << format->rgb.alpha.offset);
503                 }
504         }
505 }
506
507 static void image_format_rgb24(const struct image *input, struct image *output,
508                                const struct params *params)
509 {
510         struct color_rgb24 {
511                 unsigned int value:24;
512         } __attribute__((__packed__));
513
514         const struct format_info *format = output->format;
515         const uint8_t *idata = input->data;
516         struct color_rgb24 *odata = output->data;
517         uint8_t r, g, b, a;
518         unsigned int x, y;
519
520         idata = input->data;
521         odata = output->data;
522
523         for (y = 0; y < input->height; ++y) {
524                 for (x = 0; x < input->width; ++x) {
525                         r = *idata++ >> (8 - format->rgb.red.length);
526                         g = *idata++ >> (8 - format->rgb.green.length);
527                         b = *idata++ >> (8 - format->rgb.blue.length);
528                         a = params->alpha >> (8 - format->rgb.alpha.length);
529
530                         *odata++ = (struct color_rgb24){ .value =
531                                         (r << format->rgb.red.offset) |
532                                         (g << format->rgb.green.offset) |
533                                         (b << format->rgb.blue.offset) |
534                                         (a << format->rgb.alpha.offset) };
535                 }
536         }
537 }
538
539 static void image_format_rgb32(const struct image *input, struct image *output,
540                                const struct params *params)
541 {
542         const struct format_info *format = output->format;
543         const uint8_t *idata = input->data;
544         uint32_t *odata = output->data;
545         uint8_t r, g, b, a;
546         unsigned int x, y;
547
548         for (y = 0; y < input->height; ++y) {
549                 for (x = 0; x < input->width; ++x) {
550                         r = *idata++ >> (8 - format->rgb.red.length);
551                         g = *idata++ >> (8 - format->rgb.green.length);
552                         b = *idata++ >> (8 - format->rgb.blue.length);
553                         a = params->alpha >> (8 - format->rgb.alpha.length);
554
555                         *odata++ = (r << format->rgb.red.offset)
556                                  | (g << format->rgb.green.offset)
557                                  | (b << format->rgb.blue.offset)
558                                  | (a << format->rgb.alpha.offset);
559                 }
560         }
561 }
562
563 static void image_format_hsv24(const struct image *input, struct image *output,
564                                const struct params *params)
565 {
566         memcpy(output->data, input->data, input->width * input->height * 3);
567 }
568
569 static void image_format_hsv32(const struct image *input, struct image *output,
570                                const struct params *params)
571 {
572         const struct format_info *format = output->format;
573         const uint8_t *idata = input->data;
574         uint32_t *odata = output->data;
575         uint8_t h, s, v, a;
576         unsigned int x, y;
577
578         for (y = 0; y < input->height; ++y) {
579                 for (x = 0; x < input->width; ++x) {
580                         h = *idata++;
581                         s = *idata++;
582                         v = *idata++;
583                         a = params->alpha;
584
585                         *odata++ = (h << format->hsv.hue.offset)
586                                  | (s << format->hsv.saturation.offset)
587                                  | (v << format->hsv.value.offset)
588                                  | (a << format->hsv.alpha.offset);
589                 }
590         }
591 }
592
593 /*
594  * In YUV packed and planar formats, when subsampling horizontally average the
595  * chroma components of the two pixels to match the hardware behaviour.
596  */
597 static void image_format_yuv_packed(const struct image *input, struct image *output,
598                                     const struct params *params)
599 {
600         const struct format_info *format = output->format;
601         const uint8_t *idata = input->data;
602         uint8_t *o_y = output->data + ((format->yuv.order & YUV_YC) ? 0 : 1);
603         uint8_t *o_c = output->data + ((format->yuv.order & YUV_CY) ? 0 : 1);
604         unsigned int u_offset = (format->yuv.order & YUV_YCrCb) ? 2 : 0;
605         unsigned int v_offset = (format->yuv.order & YUV_YCbCr) ? 2 : 0;
606         unsigned int x;
607         unsigned int y;
608
609         for (y = 0; y < output->height; ++y) {
610                 for (x = 0; x < output->width; x += 2) {
611                         o_y[2*x] = idata[3*x];
612                         o_y[2*x + 2] = idata[3*x + 3];
613
614                         if (params->no_chroma_average) {
615                                 o_c[2*x + u_offset] = idata[3*x + 1];
616                                 o_c[2*x + v_offset] = idata[3*x + 2];
617                         } else {
618                                 o_c[2*x + u_offset] = (idata[3*x + 1] + idata[3*x + 4]) / 2;
619                                 o_c[2*x + v_offset] = (idata[3*x + 2] + idata[3*x + 5]) / 2;
620                         }
621                 }
622
623                 o_y += input->width * 2;
624                 o_c += input->width * 2;
625                 idata += input->width * 3;
626         }
627 }
628
629 static void image_format_yuv_planar(const struct image *input, struct image *output,
630                                     const struct params *params)
631 {
632         const struct format_info *format = output->format;
633         const uint8_t *idata;
634         uint8_t *o_y = output->data;
635         uint8_t *o_c = o_y + output->width * output->height;
636         uint8_t *o_u;
637         uint8_t *o_v;
638         unsigned int xsub = format->yuv.xsub;
639         unsigned int ysub = format->yuv.ysub;
640         unsigned int c_stride;
641         unsigned int x;
642         unsigned int y;
643
644         if (format->yuv.num_planes == 2) {
645                 o_u = (format->yuv.order & YUV_YCbCr) ? o_c : o_c + 1;
646                 o_v = (format->yuv.order & YUV_YCrCb) ? o_c : o_c + 1;
647                 c_stride = 2;
648         } else {
649                 unsigned int c_size = output->width * output->height
650                                     / xsub / ysub;
651
652                 o_u = (format->yuv.order & YUV_YCbCr) ? o_c : o_c + c_size;
653                 o_v = (format->yuv.order & YUV_YCrCb) ? o_c : o_c + c_size;
654                 c_stride = 1;
655         }
656
657         idata = input->data;
658         for (y = 0; y < output->height; ++y) {
659                 for (x = 0; x < output->width; ++x)
660                         *o_y++ = idata[3*x];
661
662                 idata += input->width * 3;
663         }
664
665         idata = input->data;
666         for (y = 0; y < output->height / ysub; ++y) {
667                 if (xsub == 1 || params->no_chroma_average) {
668                         for (x = 0; x < output->width; x += xsub) {
669                                 o_u[x*c_stride/xsub] = idata[3*x + 1];
670                                 o_v[x*c_stride/xsub] = idata[3*x + 2];
671                         }
672                 } else {
673                         for (x = 0; x < output->width; x += xsub) {
674                                 o_u[x*c_stride/xsub] = (idata[3*x + 1] + idata[3*x + 4]) / 2;
675                                 o_v[x*c_stride/xsub] = (idata[3*x + 2] + idata[3*x + 5]) / 2;
676                         }
677                 }
678
679                 o_u += output->width * c_stride / xsub;
680                 o_v += output->width * c_stride / xsub;
681                 idata += input->width * 3 * ysub;
682         }
683 }
684
685 /* -----------------------------------------------------------------------------
686  * Colorspace handling
687  *
688  * The code is inspired by the v4l2-tpg Linux kernel driver.
689  */
690
691 static void colorspace_matrix(enum v4l2_ycbcr_encoding encoding,
692                               enum v4l2_quantization quantization,
693                               int (*matrix)[3][3])
694 {
695 #define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
696
697         static const int bt601[3][3] = {
698                 { COEFF(0.299, 219),  COEFF(0.587, 219),  COEFF(0.114, 219)  },
699                 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224)    },
700                 { COEFF(0.5, 224),    COEFF(-0.419, 224), COEFF(-0.081, 224) },
701         };
702         static const int bt601_full[3][3] = {
703                 { COEFF(0.299, 255),  COEFF(0.587, 255),  COEFF(0.114, 255)  },
704                 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255)    },
705                 { COEFF(0.5, 255),    COEFF(-0.419, 255), COEFF(-0.081, 255) },
706         };
707         static const int rec709[3][3] = {
708                 { COEFF(0.2126, 219),  COEFF(0.7152, 219),  COEFF(0.0722, 219)  },
709                 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224)     },
710                 { COEFF(0.5, 224),     COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
711         };
712         static const int rec709_full[3][3] = {
713                 { COEFF(0.2126, 255),  COEFF(0.7152, 255),  COEFF(0.0722, 255)  },
714                 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255)     },
715                 { COEFF(0.5, 255),     COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
716         };
717         static const int smpte240m[3][3] = {
718                 { COEFF(0.212, 219),  COEFF(0.701, 219),  COEFF(0.087, 219)  },
719                 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224)    },
720                 { COEFF(0.5, 224),    COEFF(-0.445, 224), COEFF(-0.055, 224) },
721         };
722         static const int smpte240m_full[3][3] = {
723                 { COEFF(0.212, 255),  COEFF(0.701, 255),  COEFF(0.087, 255)  },
724                 { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255)    },
725                 { COEFF(0.5, 255),    COEFF(-0.445, 255), COEFF(-0.055, 255) },
726         };
727         static const int bt2020[3][3] = {
728                 { COEFF(0.2627, 219),  COEFF(0.6780, 219),  COEFF(0.0593, 219)  },
729                 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224)     },
730                 { COEFF(0.5, 224),     COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
731         };
732         static const int bt2020_full[3][3] = {
733                 { COEFF(0.2627, 255),  COEFF(0.6780, 255),  COEFF(0.0593, 255)  },
734                 { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255)     },
735                 { COEFF(0.5, 255),     COEFF(-0.4698, 255), COEFF(-0.0402, 255) },
736         };
737
738         bool full = quantization == V4L2_QUANTIZATION_FULL_RANGE;
739         unsigned int i;
740         const int (*m)[3][3];
741
742         switch (encoding) {
743         case V4L2_YCBCR_ENC_601:
744         default:
745                 m = full ? &bt601_full : &bt601;
746                 break;
747         case V4L2_YCBCR_ENC_709:
748                 m = full ? &rec709_full : &rec709;
749                 break;
750         case V4L2_YCBCR_ENC_BT2020:
751                 m = full ? &bt2020_full : &bt2020;
752                 break;
753         case V4L2_YCBCR_ENC_SMPTE240M:
754                 m = full ? &smpte240m_full : &smpte240m;
755                 break;
756         }
757
758         for (i = 0; i < ARRAY_SIZE(*m); ++i)
759                 memcpy((*matrix)[i], (*m)[i], sizeof((*m)[i]));
760 }
761
762 static void colorspace_rgb2ycbcr(int m[3][3],
763                                  enum v4l2_quantization quantization,
764                                  const uint8_t rgb[3], uint8_t ycbcr[3])
765 {
766         bool full = quantization == V4L2_QUANTIZATION_FULL_RANGE;
767         unsigned int y_offset = full ? 0 : 16;
768         int r, g, b;
769         int y, cb, cr;
770         int div;
771
772         r = rgb[0] << 4;
773         g = rgb[1] << 4;
774         b = rgb[2] << 4;
775
776         div = (1 << (8 + 4)) * 255;
777         y  = (m[0][0] * r + m[0][1] * g + m[0][2] * b + y_offset * div) / div;
778         cb = (m[1][0] * r + m[1][1] * g + m[1][2] * b + 128 * div) / div;
779         cr = (m[2][0] * r + m[2][1] * g + m[2][2] * b + 128 * div) / div;
780
781         ycbcr[0] = y;
782         ycbcr[1] = cb;
783         ycbcr[2] = cr;
784 }
785
786 static void image_colorspace_rgb_to_yuv(const struct image *input,
787                                         struct image *output,
788                                         const struct format_info *format,
789                                         const struct params *params)
790 {
791         int matrix[3][3];
792         const uint8_t *idata = input->data;
793         uint8_t *odata = output->data;
794         unsigned int x;
795         unsigned int y;
796
797         colorspace_matrix(params->encoding, params->quantization, &matrix);
798
799         for (y = 0; y < output->height; ++y) {
800                 for (x = 0; x < output->width; ++x) {
801                         colorspace_rgb2ycbcr(matrix, params->quantization,
802                                              &idata[3*x], &odata[3*x]);
803                 }
804                 if (format->yuv.xsub == 2) {
805                         for (x = 1; x < output->width - 1; x += 2) {
806                                 odata[3*x + 1] = (odata[3*(x-1) + 1] + odata[3*(x+1) + 1]) / 2;
807                                 odata[3*x + 2] = (odata[3*(x-1) + 2] + odata[3*(x+1) + 2]) / 2;
808                         }
809                 }
810                 idata += 3 * output->width;
811                 odata += 3 * output->width;
812         }
813 }
814
815 static void image_convert_rgb_to_rgb(const struct image *input,
816                                      struct image *output,
817                                      const struct format_info *format)
818 {
819         const uint8_t *idata = input->data;
820         uint8_t *odata = output->data;
821         unsigned int x;
822         unsigned int y;
823         uint8_t r, g, b;
824
825         for (y = 0; y < output->height; ++y) {
826                 for (x = 0; x < output->width; ++x) {
827                         r = *idata++ & (0xff << (8 - format->rgb.red.length));
828                         g = *idata++ & (0xff << (8 - format->rgb.green.length));
829                         b = *idata++ & (0xff << (8 - format->rgb.blue.length));
830                         *odata++ = r;
831                         *odata++ = g;
832                         *odata++ = b;
833                 }
834         }
835 }
836
837 /* -----------------------------------------------------------------------------
838  * RGB to HSV conversion (as performed by the Renesas VSP HST)
839  */
840
841 #define K 4
842 static uint8_t hst_calc_h(uint8_t r, uint8_t g, uint8_t b)
843 {
844         uint8_t max, min;
845         int delta;
846         int diff;
847         unsigned int third;
848         int aux;
849
850         max = max(r, max(g, b));
851         min = min(r, min(g, b));
852         delta = max - min;
853
854         if (!delta)
855                 return 0;
856
857         if (max == r) {
858                 diff = g - b;
859                 third = 0;
860         } else if (max == g) {
861                 diff = b - r;
862                 third = 256 * K;
863         } else {
864                 diff = r - g;
865                 third = 512 * K;
866         }
867
868         aux = diff;
869         aux *= 128;
870         aux *= K;
871
872         /* Round up */
873         if (aux >= 0)
874                 aux += delta - 1;
875         else
876                 aux -= delta - 1;
877
878         aux /= delta;
879         aux += third;
880
881         if (diff < 0 && third)
882                 aux--;
883
884         /*
885          * Divide by three and remove K scaling
886          */
887         if (aux > 0)
888                 aux += (3 * K)/2;
889         else
890                 aux -= (3 * K)/2;
891         aux /= 3 * K;
892
893         aux &= 0xff;
894
895         return  aux;
896 }
897
898 static uint8_t hst_calc_s(uint8_t r8, uint8_t g8, uint8_t b8)
899 {
900         uint8_t max, min, delta;
901         unsigned int s;
902
903         max = max(r8, max(g8, b8));
904         min = min(r8, min(g8, b8));
905
906         delta = max - min;
907         if (!delta)
908                 return 0;
909
910         s = delta * 255;
911
912         /* Special rounding,
913          *
914          * If the minimum RGB component is less then 128 the calculated
915          * S value should be rounded half down else half should be
916          * rounded up.
917          */
918         if (min < 128)
919                 return (s * 2 + max - 1) / max / 2;
920         else
921                 return (s * 2 + max) / max / 2;
922 }
923
924 static uint8_t hst_calc_v(uint8_t r, uint8_t g, uint8_t b)
925 {
926         return max(r, max(g, b));
927 }
928
929 static void hst_rgb_to_hsv(const uint8_t rgb[3], uint8_t hsv[3])
930 {
931         hsv[0] = hst_calc_h(rgb[0], rgb[1], rgb[2]);
932         hsv[1] = hst_calc_s(rgb[0], rgb[1], rgb[2]);
933         hsv[2] = hst_calc_v(rgb[0], rgb[1], rgb[2]);
934 }
935
936 static void image_rgb_to_hsv(const struct image *input,
937                              struct image *output,
938                              const struct params *params)
939 {
940         const uint8_t *idata = input->data;
941         uint8_t *odata = output->data;
942         unsigned int x;
943         unsigned int y;
944
945         for (y = 0; y < output->height; ++y) {
946                 for (x = 0; x < output->width; ++x) {
947                         hst_rgb_to_hsv(idata, odata);
948                         idata += 3;
949                         odata += 3;
950                 }
951         }
952 }
953
954 /* -----------------------------------------------------------------------------
955  * Image scaling
956  */
957
958 static void image_scale_bilinear(const struct image *input, struct image *output)
959 {
960 #define _C0(x, y)       (idata[0][((y)*input->width+(x)) * 3])
961 #define _C1(x, y)       (idata[1][((y)*input->width+(x)) * 3])
962 #define _C2(x, y)       (idata[2][((y)*input->width+(x)) * 3])
963         const uint8_t *idata[3] = { input->data, input->data + 1, input->data + 2 };
964         uint8_t *odata = output->data;
965         uint8_t c0, c1, c2;
966         unsigned int u, v;
967
968         for (v = 0; v < output->height; ++v) {
969                 double v_input = (double)v / (output->height - 1) * (input->height - 1);
970                 unsigned int y = floor(v_input);
971                 double v_ratio = v_input - y;
972
973                 for (u = 0; u < output->width; ++u) {
974                         double u_input = (double)u / (output->width - 1) * (input->width - 1);
975                         unsigned int x = floor(u_input);
976                         double u_ratio = u_input - x;
977
978                         c0 = (_C0(x, y)   * (1 - u_ratio) + _C0(x+1, y)   * u_ratio) * (1 - v_ratio)
979                            + (_C0(x, y+1) * (1 - u_ratio) + _C0(x+1, y+1) * u_ratio) * v_ratio;
980                         c1 = (_C1(x, y)   * (1 - u_ratio) + _C1(x+1, y)   * u_ratio) * (1 - v_ratio)
981                            + (_C1(x, y+1) * (1 - u_ratio) + _C1(x+1, y+1) * u_ratio) * v_ratio;
982                         c2 = (_C2(x, y)   * (1 - u_ratio) + _C2(x+1, y)   * u_ratio) * (1 - v_ratio)
983                            + (_C2(x, y+1) * (1 - u_ratio) + _C2(x+1, y+1) * u_ratio) * v_ratio;
984
985                         *odata++ = c0;
986                         *odata++ = c1;
987                         *odata++ = c2;
988                 }
989         }
990 #undef _C0
991 #undef _C1
992 #undef _C2
993 }
994
995 static void image_scale(const struct image *input, struct image *output,
996                         const struct params *params)
997 {
998         image_scale_bilinear(input, output);
999 }
1000
1001 /* -----------------------------------------------------------------------------
1002  * Image composing
1003  */
1004
1005 static void image_compose(const struct image *input, struct image *output,
1006                           unsigned int num_inputs)
1007 {
1008         const uint8_t *idata = input->data;
1009         uint8_t *odata = output->data;
1010         unsigned int offset = 50;
1011         unsigned int y;
1012         unsigned int i;
1013
1014         memset(odata, 0, output->size);
1015
1016         for (i = 0; i < num_inputs; ++i) {
1017                 unsigned int dst_offset = (offset * output->width + offset) * 3;
1018
1019                 if (offset >= output->width || offset >= output->height)
1020                         break;
1021
1022                 for (y = 0; y < output->height - offset; ++y)
1023                         memcpy(odata + y * output->width * 3 + dst_offset,
1024                                idata + y * output->width * 3,
1025                                (output->width - offset) * 3);
1026
1027                 offset += 50;
1028         }
1029 }
1030
1031 /* -----------------------------------------------------------------------------
1032  * Image rotation and flipping
1033  */
1034
1035 static void image_rotate(const struct image *input, struct image *output)
1036 {
1037         const uint8_t *idata = input->data;
1038         uint8_t *odata;
1039         unsigned int stride = output->width * 3;
1040         unsigned int x, y;
1041
1042         odata = output->data + stride - 3;
1043
1044         for (y = 0; y < input->height; ++y) {
1045                 for (x = 0; x < input->width; ++x) {
1046                         odata[x*stride+0] = *idata++;
1047                         odata[x*stride+1] = *idata++;
1048                         odata[x*stride+2] = *idata++;
1049                 }
1050
1051                 odata -= 3;
1052         }
1053 }
1054
1055 static void image_flip(const struct image *input, struct image *output,
1056                        bool hflip, bool vflip)
1057 {
1058         const uint8_t *idata = input->data;
1059         uint8_t *odata = output->data;
1060         unsigned int stride = output->width * 3;
1061         unsigned int x, y;
1062         int x_step, y_step;
1063
1064         if (!hflip) {
1065                 x_step = 3;
1066                 y_step = !vflip ? 0 : -2 * stride;
1067                 odata += !vflip ? 0 : stride * (output->height - 1);
1068         } else {
1069                 x_step = -3;
1070                 y_step = !vflip ? 2 * stride : 0;
1071                 odata += !vflip ? stride - 3 : stride * output->height - 3;
1072         }
1073
1074         for (y = 0; y < output->height; ++y) {
1075                 for (x = 0; x < output->width; ++x) {
1076                         odata[0] = *idata++;
1077                         odata[1] = *idata++;
1078                         odata[2] = *idata++;
1079
1080                         odata += x_step;
1081                 }
1082
1083                 odata += y_step;
1084         }
1085 }
1086
1087 /* -----------------------------------------------------------------------------
1088  * Image Cropping
1089  */
1090
1091 static void image_crop(const struct image *input, const struct image *output,
1092                        const struct image_rect *crop)
1093 {
1094         unsigned int offset = (crop->top * input->width + crop->left) * 3;
1095         const uint8_t *idata = input->data + offset;
1096         uint8_t *odata = output->data;
1097         unsigned int y;
1098
1099         for (y = 0; y < output->height; ++y) {
1100                 memcpy(odata, idata, output->width * 3);
1101                 odata += output->width * 3;
1102                 idata += input->width * 3;
1103         }
1104 }
1105
1106 /* -----------------------------------------------------------------------------
1107  * Look Up Table
1108  */
1109
1110 static int image_lut_1d(const struct image *input, struct image *output,
1111                         const char *filename)
1112 {
1113         const uint8_t *idata = input->data;
1114         uint8_t *odata = output->data;
1115         unsigned int comp_map[3];
1116         uint8_t c0, c1, c2;
1117         unsigned int x, y;
1118         uint8_t lut[1024];
1119         int ret;
1120         int fd;
1121
1122         fd = open(filename, O_RDONLY);
1123         if (fd < 0) {
1124                 printf("Unable to open LUT file %s: %s (%d)\n", filename,
1125                        strerror(errno), errno);
1126                 return -errno;
1127         }
1128
1129         ret = file_read(fd, lut, sizeof(lut));
1130         close(fd);
1131         if (ret < 0) {
1132                 printf("Unable to read 1D LUT file: %s (%d)\n", strerror(-ret),
1133                        ret);
1134                 return ret;
1135         }
1136         if ((size_t)ret != sizeof(lut)) {
1137                 printf("Invalid 1D LUT file: file too short\n");
1138                 return -ENODATA;
1139         }
1140
1141         if (input->format->type == FORMAT_YUV)
1142                 memcpy(comp_map, (unsigned int[3]){ 1, 0, 2 },
1143                        sizeof(comp_map));
1144         else
1145                 memcpy(comp_map, (unsigned int[3]){ 2, 1, 0 },
1146                        sizeof(comp_map));
1147
1148         for (y = 0; y < input->height; ++y) {
1149                 for (x = 0; x < input->width; ++x) {
1150                         c0 = *idata++;
1151                         c1 = *idata++;
1152                         c2 = *idata++;
1153
1154                         *odata++ = lut[c0*4 + comp_map[0]];
1155                         *odata++ = lut[c1*4 + comp_map[1]];
1156                         *odata++ = lut[c2*4 + comp_map[2]];
1157                 }
1158         }
1159
1160         return 0;
1161 }
1162
1163 static int image_lut_3d(const struct image *input, struct image *output,
1164                         const char *filename)
1165 {
1166         const uint8_t *idata = input->data;
1167         uint8_t *odata = output->data;
1168         unsigned int comp_map[3];
1169         unsigned int x, y;
1170         uint32_t lut[17*17*17];
1171         int ret;
1172         int fd;
1173
1174         fd = open(filename, O_RDONLY);
1175         if (fd < 0) {
1176                 printf("Unable to open 3D LUT file %s: %s (%d)\n", filename,
1177                        strerror(errno), errno);
1178                 return -errno;
1179         }
1180
1181         ret = file_read(fd, lut, sizeof(lut));
1182         close(fd);
1183         if (ret < 0) {
1184                 printf("Unable to read 3D LUT file: %s (%d)\n", strerror(-ret),
1185                        ret);
1186                 return ret;
1187         }
1188         if ((size_t)ret != sizeof(lut)) {
1189                 printf("Invalid 3D LUT file: file too short\n");
1190                 return -ENODATA;
1191         }
1192
1193         if (input->format->type == FORMAT_YUV)
1194                 memcpy(comp_map, (unsigned int[3]){ 2, 0, 1 },
1195                        sizeof(comp_map));
1196         else
1197                 memcpy(comp_map, (unsigned int[3]){ 0, 1, 2 },
1198                        sizeof(comp_map));
1199
1200         for (y = 0; y < input->height; ++y) {
1201                 for (x = 0; x < input->width; ++x) {
1202                         double a1_ratio, a2_ratio, a3_ratio;
1203                         unsigned int a1, a2, a3;
1204                         double c0, c1, c2;
1205                         uint8_t c[3];
1206
1207                         c[0] = idata[comp_map[0]];
1208                         c[1] = idata[comp_map[1]];
1209                         c[2] = idata[comp_map[2]];
1210
1211                         a1 = c[0] >> 4;
1212                         a2 = c[1] >> 4;
1213                         a3 = c[2] >> 4;
1214
1215                         /*
1216                          * Implement the hardware MVS (Max Value Stretch)
1217                          * behaviour: move the point by one step towards the
1218                          * upper limit of the grid if we're closer than 0.5 to
1219                          * that limit.
1220                          */
1221                         a1_ratio = ((c[0] & 0xf) + (c[0] >= 0xf8 ? 1 : 0)) / 16.;
1222                         a2_ratio = ((c[1] & 0xf) + (c[1] >= 0xf8 ? 1 : 0)) / 16.;
1223                         a3_ratio = ((c[2] & 0xf) + (c[2] >= 0xf8 ? 1 : 0)) / 16.;
1224
1225 #define _LUT(a1, a2, a3, offset)        ((lut[(a1)+(a2)*17+(a3)*17*17] >> (offset)) & 0xff)
1226                         c0 = _LUT(a1,   a2,   a3,   16) * (1 - a1_ratio) * (1 - a2_ratio) * (1 - a3_ratio)
1227                            + _LUT(a1,   a2,   a3+1, 16) * (1 - a1_ratio) * (1 - a2_ratio) * a3_ratio
1228                            + _LUT(a1,   a2+1, a3,   16) * (1 - a1_ratio) * a2_ratio       * (1 - a3_ratio)
1229                            + _LUT(a1,   a2+1, a3+1, 16) * (1 - a1_ratio) * a2_ratio       * a3_ratio
1230                            + _LUT(a1+1, a2,   a3,   16) * a1_ratio       * (1 - a2_ratio) * (1 - a3_ratio)
1231                            + _LUT(a1+1, a2,   a3+1, 16) * a1_ratio       * (1 - a2_ratio) * a3_ratio
1232                            + _LUT(a1+1, a2+1, a3,   16) * a1_ratio       * a2_ratio       * (1 - a3_ratio)
1233                            + _LUT(a1+1, a2+1, a3+1, 16) * a1_ratio       * a2_ratio       * a3_ratio;
1234                         c1 = _LUT(a1,   a2,   a3,    8) * (1 - a1_ratio) * (1 - a2_ratio) * (1 - a3_ratio)
1235                            + _LUT(a1,   a2,   a3+1,  8) * (1 - a1_ratio) * (1 - a2_ratio) * a3_ratio
1236                            + _LUT(a1,   a2+1, a3,    8) * (1 - a1_ratio) * a2_ratio       * (1 - a3_ratio)
1237                            + _LUT(a1,   a2+1, a3+1,  8) * (1 - a1_ratio) * a2_ratio       * a3_ratio
1238                            + _LUT(a1+1, a2,   a3,    8) * a1_ratio       * (1 - a2_ratio) * (1 - a3_ratio)
1239                            + _LUT(a1+1, a2,   a3+1,  8) * a1_ratio       * (1 - a2_ratio) * a3_ratio
1240                            + _LUT(a1+1, a2+1, a3,    8) * a1_ratio       * a2_ratio       * (1 - a3_ratio)
1241                            + _LUT(a1+1, a2+1, a3+1,  8) * a1_ratio       * a2_ratio       * a3_ratio;
1242                         c2 = _LUT(a1,   a2,   a3,    0) * (1 - a1_ratio) * (1 - a2_ratio) * (1 - a3_ratio)
1243                            + _LUT(a1,   a2,   a3+1,  0) * (1 - a1_ratio) * (1 - a2_ratio) * a3_ratio
1244                            + _LUT(a1,   a2+1, a3,    0) * (1 - a1_ratio) * a2_ratio       * (1 - a3_ratio)
1245                            + _LUT(a1,   a2+1, a3+1,  0) * (1 - a1_ratio) * a2_ratio       * a3_ratio
1246                            + _LUT(a1+1, a2,   a3,    0) * a1_ratio       * (1 - a2_ratio) * (1 - a3_ratio)
1247                            + _LUT(a1+1, a2,   a3+1,  0) * a1_ratio       * (1 - a2_ratio) * a3_ratio
1248                            + _LUT(a1+1, a2+1, a3,    0) * a1_ratio       * a2_ratio       * (1 - a3_ratio)
1249                            + _LUT(a1+1, a2+1, a3+1,  0) * a1_ratio       * a2_ratio       * a3_ratio;
1250 #undef _LUT
1251
1252                         odata[comp_map[0]] = round(c0);
1253                         odata[comp_map[1]] = round(c1);
1254                         odata[comp_map[2]] = round(c2);
1255
1256                         idata += 3;
1257                         odata += 3;
1258                 }
1259         }
1260
1261         return 0;
1262 }
1263
1264 /* -----------------------------------------------------------------------------
1265  * Histogram
1266  */
1267
1268 static void histogram_compute(const struct image *image, void *histo)
1269 {
1270         const uint8_t *data = image->data;
1271         uint8_t comp_min[3] = { 255, 255, 255 };
1272         uint8_t comp_max[3] = { 0, 0, 0 };
1273         uint32_t comp_sums[3] = { 0, 0, 0 };
1274         uint32_t comp_bins[3][64];
1275         unsigned int comp_map[3];
1276         unsigned int x, y;
1277         unsigned int i, j;
1278
1279         if (image->format->type == FORMAT_YUV)
1280                 memcpy(comp_map, (unsigned int[3]){ 2, 0, 1 }, sizeof(comp_map));
1281         else
1282                 memcpy(comp_map, (unsigned int[3]){ 0, 1, 2 }, sizeof(comp_map));
1283
1284         memset(comp_bins, 0, sizeof(comp_bins));
1285
1286         for (y = 0; y < image->height; ++y) {
1287                 for (x = 0; x < image->width; ++x) {
1288                         for (i = 0; i < 3; ++i) {
1289                                 comp_min[i] = min(*data, comp_min[i]);
1290                                 comp_max[i] = max(*data, comp_max[i]);
1291                                 comp_sums[i] += *data;
1292                                 comp_bins[i][*data >> 2]++;
1293                                 data++;
1294                         }
1295                 }
1296         }
1297
1298         for (i = 0; i < ARRAY_SIZE(comp_min); ++i) {
1299                 *(uint8_t *)histo++ = comp_min[comp_map[i]];
1300                 *(uint8_t *)histo++ = 0;
1301                 *(uint8_t *)histo++ = comp_max[comp_map[i]];
1302                 *(uint8_t *)histo++ = 0;
1303         }
1304
1305         for (i = 0; i < ARRAY_SIZE(comp_sums); ++i) {
1306                 *(uint32_t *)histo = comp_sums[comp_map[i]];
1307                 histo += 4;
1308         }
1309
1310         for (i = 0; i < ARRAY_SIZE(comp_bins); ++i) {
1311                 for (j = 0; j < ARRAY_SIZE(comp_bins[i]); ++j) {
1312                         *(uint32_t *)histo = comp_bins[comp_map[i]][j];
1313                         histo += 4;
1314                 }
1315         }
1316 }
1317
1318 static int histogram(const struct image *image, const char *filename)
1319 {
1320         uint8_t data[3*4 + 3*4 + 3*64*4];
1321         int ret;
1322         int fd;
1323
1324         histogram_compute(image, data);
1325
1326         fd = open(filename, O_WRONLY | O_CREAT,
1327                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1328         if (fd < 0) {
1329                 printf("Unable to open histogram file %s: %s (%d)\n", filename,
1330                        strerror(errno), errno);
1331                 return -errno;
1332         }
1333
1334         ret = file_write(fd, data, sizeof(data));
1335         if (ret < 0)
1336                 printf("Unable to write histogram: %s (%d)\n",
1337                        strerror(-ret), ret);
1338         else
1339                 ftruncate(fd, sizeof(data));
1340
1341         close(fd);
1342         return ret;
1343 }
1344
1345 /* -----------------------------------------------------------------------------
1346  * Processing pipeline
1347  */
1348
1349 static int process(const struct options *options)
1350 {
1351         struct image *input = NULL;
1352         struct image *output = NULL;
1353         unsigned int output_width;
1354         unsigned int output_height;
1355         int ret = 0;
1356
1357         /* Read the input image */
1358         input = image_read(options->input_filename);
1359         if (!input) {
1360                 ret = -EINVAL;
1361                 goto done;
1362         }
1363
1364         /* Convert colorspace */
1365         if (options->input_format->type == FORMAT_YUV) {
1366                 struct image *yuv;
1367
1368                 yuv = image_new(format_by_name("YUV24"), input->width,
1369                                 input->height);
1370                 if (!yuv) {
1371                         ret = -ENOMEM;
1372                         goto done;
1373                 }
1374
1375                 image_colorspace_rgb_to_yuv(input, yuv, options->input_format,
1376                                             &options->params);
1377                 image_delete(input);
1378                 input = yuv;
1379         } else if (options->input_format->rgb.bpp < 24) {
1380                 struct image *rgb;
1381
1382                 rgb = image_new(format_by_name("RGB24"), input->width,
1383                                 input->height);
1384                 if (!rgb) {
1385                         ret = -ENOMEM;
1386                         goto done;
1387                 }
1388
1389                 image_convert_rgb_to_rgb(input, rgb, options->input_format);
1390                 image_delete(input);
1391                 input = rgb;
1392         }
1393
1394         /* Crop */
1395         if (options->crop) {
1396                 struct image *cropped;
1397
1398                 cropped = image_new(input->format, options->inputcrop.width,
1399                                 options->inputcrop.height);
1400                 if (!cropped) {
1401                         ret = -ENOMEM;
1402                         goto done;
1403                 }
1404
1405                 image_crop(input, cropped, &options->inputcrop);
1406                 image_delete(input);
1407                 input = cropped;
1408         }
1409
1410         /* Scale */
1411         if (options->output_width && options->output_height) {
1412                 output_width = options->output_width;
1413                 output_height = options->output_height;
1414         } else {
1415                 output_width = input->width;
1416                 output_height = input->height;
1417         }
1418
1419         if (options->rotate)
1420                 swap(output_width, output_height);
1421
1422         if (input->width != output_width ||
1423             input->height != output_height) {
1424                 struct image *scaled;
1425
1426                 scaled = image_new(input->format, output_width, output_height);
1427                 if (!scaled) {
1428                         ret = -ENOMEM;
1429                         goto done;
1430                 }
1431
1432                 image_scale(input, scaled, &options->params);
1433                 image_delete(input);
1434                 input = scaled;
1435         }
1436
1437         /* Compose */
1438         if (options->compose) {
1439                 struct image *composed;
1440
1441                 composed = image_new(input->format, input->width, input->height);
1442                 if (!composed) {
1443                         ret = -ENOMEM;
1444                         goto done;
1445                 }
1446
1447                 image_compose(input, composed, options->compose);
1448                 image_delete(input);
1449                 input = composed;
1450         }
1451
1452         /* Look-up tables */
1453         if (options->lut_filename) {
1454                 struct image *lut;
1455
1456                 lut = image_new(input->format, input->width, input->height);
1457                 if (!lut) {
1458                         ret = -ENOMEM;
1459                         goto done;
1460                 }
1461
1462                 image_lut_1d(input, lut, options->lut_filename);
1463                 image_delete(input);
1464                 input = lut;
1465         }
1466
1467         if (options->clu_filename) {
1468                 struct image *clu;
1469
1470                 clu = image_new(input->format, input->width, input->height);
1471                 if (!clu) {
1472                         ret = -ENOMEM;
1473                         goto done;
1474                 }
1475
1476                 image_lut_3d(input, clu, options->clu_filename);
1477                 image_delete(input);
1478                 input = clu;
1479         }
1480
1481         /* Compute the histogram */
1482         if (options->histo_filename) {
1483                 ret = histogram(input, options->histo_filename);
1484                 if (ret)
1485                         goto done;
1486         }
1487
1488         /* Rotation and flipping */
1489         if (options->rotate) {
1490                 struct image *rotated;
1491
1492                 rotated = image_new(input->format, input->height, input->width);
1493                 if (!rotated) {
1494                         ret = -ENOMEM;
1495                         goto done;
1496                 }
1497
1498                 image_rotate(input, rotated);
1499                 image_delete(input);
1500                 input = rotated;
1501         }
1502
1503         if (options->hflip || options->vflip) {
1504                 struct image *flipped;
1505
1506                 flipped = image_new(input->format, input->width, input->height);
1507                 if (!flipped) {
1508                         ret = -ENOMEM;
1509                         goto done;
1510                 }
1511
1512                 image_flip(input, flipped, options->hflip, options->vflip);
1513                 image_delete(input);
1514                 input = flipped;
1515         }
1516
1517         /* Format the output */
1518         if (input->format->type != options->output_format->type &&
1519             input->format->type != FORMAT_RGB) {
1520                 printf("Format conversion with non-RGB input not supported\n");
1521                 ret = -EINVAL;
1522                 goto done;
1523         }
1524
1525         if (input->format->type != options->output_format->type) {
1526                 const struct format_info *format;
1527                 struct image *converted;
1528
1529                 if (options->output_format->type == FORMAT_YUV)
1530                         format = format_by_name("YUV24");
1531                 else
1532                         format = format_by_name("HSV24");
1533
1534                 converted = image_new(format, input->width, input->height);
1535                 if (!converted) {
1536                         ret = -ENOMEM;
1537                         goto done;
1538                 }
1539
1540                 if (options->output_format->type == FORMAT_YUV)
1541                         image_colorspace_rgb_to_yuv(input, converted, format,
1542                                                     &options->params);
1543                 else
1544                         image_rgb_to_hsv(input, converted, &options->params);
1545
1546                 image_delete(input);
1547                 input = converted;
1548         }
1549
1550         output = image_new(options->output_format, input->width, input->height);
1551         if (!output) {
1552                 ret = -ENOMEM;
1553                 goto done;
1554         }
1555
1556         switch (output->format->type) {
1557         case FORMAT_RGB:
1558                 switch (output->format->rgb.bpp) {
1559                 case 8:
1560                         image_format_rgb8(input, output, &options->params);
1561                         break;
1562                 case 16:
1563                         image_format_rgb16(input, output, &options->params);
1564                         break;
1565                 case 24:
1566                         image_format_rgb24(input, output, &options->params);
1567                         break;
1568                 case 32:
1569                         image_format_rgb32(input, output, &options->params);
1570                         break;
1571                 default:
1572                         ret = -EINVAL;
1573                         break;
1574                 }
1575                 break;
1576
1577         case FORMAT_HSV:
1578                 switch (output->format->hsv.bpp) {
1579                 case 24:
1580                         image_format_hsv24(input, output, &options->params);
1581                         break;
1582                 case 32:
1583                         image_format_hsv32(input, output, &options->params);
1584                         break;
1585                 default:
1586                         ret = -EINVAL;
1587                         break;
1588                 }
1589                 break;
1590
1591         case FORMAT_YUV:
1592                 switch (output->format->yuv.num_planes) {
1593                 case 1:
1594                         image_format_yuv_packed(input, output, &options->params);
1595                         break;
1596                 case 2:
1597                 case 3:
1598                         image_format_yuv_planar(input, output, &options->params);
1599                         break;
1600                 default:
1601                         ret = -EINVAL;
1602                         break;
1603                 }
1604                 break;
1605         }
1606
1607         if (ret < 0) {
1608                 printf("Output formatting failed\n");
1609                 goto done;
1610         }
1611
1612         /* Write the output image */
1613         if (options->output_filename) {
1614                 ret = image_write(output, options->output_filename);
1615                 if (ret)
1616                         goto done;
1617         }
1618
1619         ret = 0;
1620
1621 done:
1622         image_delete(input);
1623         image_delete(output);
1624         return ret;
1625 }
1626
1627 /* -----------------------------------------------------------------------------
1628  * Usage, argument parsing and main
1629  */
1630
1631 static void usage(const char *argv0)
1632 {
1633         printf("Usage: %s [options] <infile.pnm>\n\n", argv0);
1634         printf("Convert the input image stored in <infile> in PNM format to\n");
1635         printf("the target format and resolution and store the resulting\n");
1636         printf("image in raw binary form\n\n");
1637         printf("Supported options:\n");
1638         printf("-a, --alpha value       Set the alpha value. Valid syntaxes are floating\n");
1639         printf("                        point values ([0.0 - 1.0]), fixed point values ([0-255])\n");
1640         printf("                        or percentages ([0%% - 100%%]). Defaults to 1.0\n");
1641         printf("-c, --compose n         Compose n copies of the image offset by (50,50) over a black background\n");
1642         printf("-C, --no-chroma-average Disable chroma averaging for odd pixels on output\n");
1643         printf("    --crop (X,Y)/WxH    Crop the input image\n");
1644         printf("-e, --encoding enc      Set the YCbCr encoding method. Valid values are\n");
1645         printf("                        BT.601, REC.709, BT.2020 and SMPTE240M\n");
1646         printf("-f, --format format     Set the output image format\n");
1647         printf("                        Defaults to RGB24 if not specified\n");
1648         printf("                        Use -f help to list the supported formats\n");
1649         printf("-h, --help              Show this help screen\n");
1650         printf("    --hflip             Flip the image horizontally\n");
1651         printf("-H, --histogram file    Compute histogram on the output image and store it to file\n");
1652         printf("-i, --in-format format  Set the input image format\n");
1653         printf("                        Defaults to RGB24 if not specified\n");
1654         printf("                        Use -i help to list the supported formats\n");
1655         printf("-l, --lut file          Apply 1D Look Up Table from file\n");
1656         printf("-L, --clu file          Apply 3D Look Up Table from file\n");
1657         printf("-o, --output file       Store the output image to file\n");
1658         printf("-q, --quantization q    Set the quantization method. Valid values are\n");
1659         printf("                        limited or full\n");
1660         printf("-r, --rotate            Rotate the image clockwise by 90°\n");
1661         printf("-s, --size WxH          Set the output image size\n");
1662         printf("                        Defaults to the input size if not specified\n");
1663         printf("    --vflip             Flip the image vertically\n");
1664 }
1665
1666 static void list_formats(void)
1667 {
1668         unsigned int i;
1669
1670         for (i = 0; i < ARRAY_SIZE(format_info); i++)
1671                 printf("%s\n", format_info[i].name);
1672 }
1673
1674 #define OPT_HFLIP       256
1675 #define OPT_VFLIP       257
1676 #define OPT_CROP        258
1677
1678 static struct option opts[] = {
1679         {"alpha", 1, 0, 'a'},
1680         {"clu", 1, 0, 'L'},
1681         {"compose", 1, 0, 'c'},
1682         {"crop", 1, 0, OPT_CROP},
1683         {"encoding", 1, 0, 'e'},
1684         {"format", 1, 0, 'f'},
1685         {"help", 0, 0, 'h'},
1686         {"hflip", 0, 0, OPT_HFLIP},
1687         {"histogram", 1, 0, 'H'},
1688         {"in-format", 1, 0, 'i'},
1689         {"lut", 1, 0, 'l'},
1690         {"no-chroma-average", 1, 0, 'C'},
1691         {"output", 1, 0, 'o'},
1692         {"quantization", 1, 0, 'q'},
1693         {"rotate", 0, 0, 'r'},
1694         {"size", 1, 0, 's'},
1695         {"vflip", 0, 0, OPT_VFLIP},
1696         {0, 0, 0, 0}
1697 };
1698
1699 static void parser_print_error(const char *p, const char *end)
1700 {
1701         int pos;
1702
1703         pos = end - p + 1;
1704
1705         if (pos < 0)
1706                 pos = 0;
1707         if (pos > (int) strlen(p) + 1)
1708                 pos = strlen(p) + 1;
1709
1710         printf("\n");
1711         printf(" %s\n", p);
1712         printf(" %*s\n", pos, "^");
1713 }
1714
1715 static int parse_crop(struct image_rect *crop, const char *string)
1716 {
1717         /* (X,Y)/WxH */
1718         const char *p = string;
1719         char *endptr;
1720         int value;
1721
1722         if (*p != '(') {
1723                 printf("Invalid crop format, expected '('\n");
1724                 goto error;
1725         }
1726
1727         p++;
1728         crop->left = strtol(p, &endptr, 10);
1729         if (p == endptr) {
1730                 printf("Invalid crop format, expected x coordinate\n");
1731                 goto error;
1732         }
1733
1734         p = endptr;
1735         if (*p != ',') {
1736                 printf("Invalid crop format, expected ','\n");
1737                 goto error;
1738         }
1739
1740         p++;
1741         crop->top = strtol(p, &endptr, 10);
1742         if (p == endptr) {
1743                 printf("Invalid crop format, expected y coordinate\n");
1744                 goto error;
1745         }
1746
1747         p = endptr;
1748         if (*p != ')') {
1749                 printf("Invalid crop format, expected ')'\n");
1750                 goto error;
1751         }
1752
1753         p++;
1754         if (*p != '/') {
1755                 printf("Invalid crop format, expected '/'\n");
1756                 goto error;
1757         }
1758
1759         p++;
1760         value = strtol(p, &endptr, 10);
1761         if (p == endptr) {
1762                 printf("Invalid crop format, expected width\n");
1763                 goto error;
1764         }
1765
1766         if (value < 0) {
1767                 printf("width must be positive\n");
1768                 goto error;
1769         }
1770
1771         crop->width = value;
1772
1773         p = endptr;
1774         if (*p != 'x') {
1775                 printf("Invalid crop format, expected 'x'\n");
1776                 goto error;
1777         }
1778
1779         p++;
1780         value = strtol(p, &endptr, 10);
1781         if (p == endptr) {
1782                 printf("Invalid crop format, expected height\n");
1783                 goto error;
1784         }
1785
1786         if (value < 0) {
1787                 printf("height must be positive\n");
1788                 goto error;
1789         }
1790
1791         crop->height = value;
1792
1793         p = endptr;
1794         if (*p != 0) {
1795                 printf("Invalid crop format, garbage at end of input\n");
1796                 goto error;
1797         }
1798
1799         return 0;
1800
1801 error:
1802         parser_print_error(string, p);
1803         return 1;
1804 }
1805
1806 static int parse_args(struct options *options, int argc, char *argv[])
1807 {
1808         char *endptr;
1809         int c;
1810
1811         if (argc < 3) {
1812                 usage(argv[0]);
1813                 return 1;
1814         }
1815
1816         memset(options, 0, sizeof(*options));
1817         options->input_format = format_by_name("RGB24");
1818         options->output_format = format_by_name("RGB24");
1819         options->params.alpha = 255;
1820         options->params.encoding = V4L2_YCBCR_ENC_601;
1821         options->params.quantization = V4L2_QUANTIZATION_LIM_RANGE;
1822
1823         opterr = 0;
1824         while ((c = getopt_long(argc, argv, "a:c:Ce:f:hH:i:l:L:o:q:rs:", opts, NULL)) != -1) {
1825
1826                 switch (c) {
1827                 case 'a': {
1828                         int alpha;
1829
1830                         if (strchr(optarg, '.')) {
1831                                 alpha = strtod(optarg, &endptr) * 255;
1832                                 if (*endptr != 0)
1833                                         alpha = -1;
1834                         } else {
1835                                 alpha = strtoul(optarg, &endptr, 10);
1836                                 if (*endptr == '%')
1837                                         alpha = alpha * 255 / 100;
1838                                 else if (*endptr != 0)
1839                                         alpha = -1;
1840                         }
1841
1842                         if (alpha < 0 || alpha > 255) {
1843                                 printf("Invalid alpha value '%s'\n", optarg);
1844                                 return 1;
1845                         }
1846
1847                         options->params.alpha = alpha;
1848                         break;
1849                 }
1850
1851                 case 'c':
1852                           options->compose = strtoul(optarg, &endptr, 10);
1853                           if (*endptr != 0) {
1854                                 printf("Invalid compose value '%s'\n", optarg);
1855                                 return 1;
1856                           }
1857                           break;
1858
1859                 case 'C':
1860                           options->params.no_chroma_average = true;
1861                           break;
1862
1863                 case 'e':
1864                         if (!strcmp(optarg, "BT.601")) {
1865                                 options->params.encoding = V4L2_YCBCR_ENC_601;
1866                         } else if (!strcmp(optarg, "REC.709")) {
1867                                 options->params.encoding = V4L2_YCBCR_ENC_709;
1868                         } else if (!strcmp(optarg, "BT.2020")) {
1869                                 options->params.encoding = V4L2_YCBCR_ENC_BT2020;
1870                         } else if (!strcmp(optarg, "SMPTE240M")) {
1871                                 options->params.encoding = V4L2_YCBCR_ENC_SMPTE240M;
1872                         } else {
1873                                 printf("Invalid encoding value '%s'\n", optarg);
1874                                 return 1;
1875                         }
1876                         break;
1877
1878                 case 'f':
1879                         if (!strcmp("help", optarg)) {
1880                                 list_formats();
1881                                 return 1;
1882                         }
1883
1884                         options->output_format = format_by_name(optarg);
1885                         if (!options->output_format) {
1886                                 printf("Unsupported output format '%s'\n", optarg);
1887                                 return 1;
1888                         }
1889
1890                         break;
1891
1892                 case 'h':
1893                         usage(argv[0]);
1894                         exit(0);
1895                         break;
1896
1897                 case 'H':
1898                         options->histo_filename = optarg;
1899                         break;
1900
1901                 case 'i':
1902                         if (!strcmp("help", optarg)) {
1903                                 list_formats();
1904                                 return 1;
1905                         }
1906
1907                         options->input_format = format_by_name(optarg);
1908                         if (!options->input_format) {
1909                                 printf("Unsupported input format '%s'\n", optarg);
1910                                 return 1;
1911                         }
1912
1913                         break;
1914
1915                 case 'l':
1916                         options->lut_filename = optarg;
1917                         break;
1918
1919                 case 'L':
1920                         options->clu_filename = optarg;
1921                         break;
1922
1923                 case 'o':
1924                         options->output_filename = optarg;
1925                         break;
1926
1927                 case 'q':
1928                         if (!strcmp(optarg, "limited")) {
1929                                 options->params.quantization = V4L2_QUANTIZATION_LIM_RANGE;
1930                         } else if (!strcmp(optarg, "full")) {
1931                                 options->params.quantization = V4L2_QUANTIZATION_FULL_RANGE;
1932                         } else {
1933                                 printf("Invalid quantization value '%s'\n", optarg);
1934                                 return 1;
1935                         }
1936                         break;
1937
1938                         break;
1939
1940                 case 'r':
1941                         options->rotate = true;
1942                         break;
1943
1944                 case 's':
1945                         options->output_width = strtol(optarg, &endptr, 10);
1946                         if (*endptr != 'x' || endptr == optarg) {
1947                                 printf("Invalid size '%s'\n", optarg);
1948                                 return 1;
1949                         }
1950
1951                         options->output_height = strtol(endptr + 1, &endptr, 10);
1952                         if (*endptr != 0) {
1953                                 printf("Invalid size '%s'\n", optarg);
1954                                 return 1;
1955                         }
1956                         break;
1957
1958                 case OPT_HFLIP:
1959                         options->hflip = true;
1960                         break;
1961
1962                 case OPT_VFLIP:
1963                         options->vflip = true;
1964                         break;
1965
1966                 case OPT_CROP:
1967                         if (parse_crop(&options->inputcrop, optarg))
1968                                 return 1;
1969
1970                         if (options->inputcrop.left < 0 || options->inputcrop.top < 0) {
1971                                 printf("Invalid crop rectangle '%s': coordinates must be positive\n",
1972                                        optarg);
1973                                 return 1;
1974                         }
1975
1976                         options->crop = true;
1977                         break;
1978
1979                 default:
1980                         printf("Invalid option -%c\n", c);
1981                         printf("Run %s -h for help.\n", argv[0]);
1982                         return 1;
1983                 }
1984         }
1985
1986         if (optind != argc - 1) {
1987                 usage(argv[0]);
1988                 return 1;
1989         }
1990
1991         options->input_filename = argv[optind];
1992
1993         return 0;
1994 }
1995
1996 int main(int argc, char *argv[])
1997 {
1998         struct options options;
1999         int ret;
2000
2001         ret = parse_args(&options, argc, argv);
2002         if (ret)
2003                 return ret;
2004
2005         ret = process(&options);
2006         if (ret)
2007                 return 1;
2008
2009         return 0;
2010 }