9e8d32cd0dc81adc135c5d7287d8874126ea18ab
[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 struct format_color_component {
50         unsigned char length;
51         unsigned char offset;
52 };
53
54 struct format_rgb_info {
55         unsigned int bpp;
56         struct format_color_component red;
57         struct format_color_component green;
58         struct format_color_component blue;
59         struct format_color_component alpha;
60 };
61
62 enum format_yuv_order {
63         YUV_YCbCr = 1,
64         YUV_YCrCb = 2,
65         YUV_YC = 4,
66         YUV_CY = 8,
67 };
68
69 struct format_yuv_info {
70         unsigned int num_planes;
71         enum format_yuv_order order;
72         unsigned int xsub;
73         unsigned int ysub;
74 };
75
76 struct format_info {
77         const char *name;
78         bool is_yuv;
79         struct format_rgb_info rgb;
80         struct format_yuv_info yuv;
81 };
82
83 struct image {
84         const struct format_info *format;
85         unsigned int width;
86         unsigned int height;
87         unsigned int size;
88         void *data;
89 };
90
91 struct params {
92         unsigned int alpha;
93         enum v4l2_ycbcr_encoding encoding;
94         enum v4l2_quantization quantization;
95 };
96
97 struct options {
98         const char *input_filename;
99         const char *output_filename;
100         const char *histo_filename;
101         const char *clu_filename;
102         const char *lut_filename;
103
104         const struct format_info *output_format;
105         unsigned int output_height;
106         unsigned int output_width;
107
108         bool process_yuv;
109         bool hflip;
110         bool vflip;
111         bool rotate;
112         unsigned int compose;
113         struct params params;
114 };
115
116 /* -----------------------------------------------------------------------------
117  * Format information
118  */
119
120 #define MAKE_RGB_INFO(rl, ro, gl, go, bl, bo, al, ao) \
121         .red = { (rl), (ro) }, .green = { (gl), (go) }, \
122         .blue = { (bl), (bo) }, .alpha = { (al), (ao) }
123
124 static const struct format_info format_info[] = {
125         /*
126          * The alpha channel maps to the X (don't care) bits for the XRGB
127          * formats.
128          */
129         { "RGB332",     false, .rgb = { 8,  MAKE_RGB_INFO(3, 5, 3, 2, 2, 0, 0, 0) } },
130         { "ARGB444",    false, .rgb = { 16, MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 4, 12) } },
131         { "XRGB444",    false, .rgb = { 16, MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 4, 12) } },
132         { "ARGB555",    false, .rgb = { 16, MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 1, 15) } },
133         { "XRGB555",    false, .rgb = { 16, MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 1, 15) } },
134         { "RGB565",     false, .rgb = { 16, MAKE_RGB_INFO(5, 11, 6, 5, 5, 0, 0, 0) } },
135         { "BGR24",      false, .rgb = { 24, MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) } },
136         { "RGB24",      false, .rgb = { 24, MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) } },
137         { "ABGR32",     false, .rgb = { 32, MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 8, 24) } },
138         { "XBGR32",     false, .rgb = { 32, MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 8, 24) } },
139         { "ARGB32",     false, .rgb = { 32, MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 8, 0) } },
140         { "XRGB32",     false, .rgb = { 32, MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 8, 0) } },
141         { "UYVY",       true,  .yuv = { 1, YUV_YCbCr | YUV_CY, 2, 1 } },
142         { "VYUY",       true,  .yuv = { 1, YUV_YCrCb | YUV_CY, 2, 1 } },
143         { "YUYV",       true,  .yuv = { 1, YUV_YCbCr | YUV_YC, 2, 1 } },
144         { "YVYU",       true,  .yuv = { 1, YUV_YCrCb | YUV_YC, 2, 1 } },
145         { "NV12M",      true,  .yuv = { 2, YUV_YCbCr, 2, 2 } },
146         { "NV21M",      true,  .yuv = { 2, YUV_YCrCb, 2, 2 } },
147         { "NV16M",      true,  .yuv = { 2, YUV_YCbCr, 2, 1 } },
148         { "NV61M",      true,  .yuv = { 2, YUV_YCrCb, 2, 1 } },
149         { "YUV420M",    true,  .yuv = { 3, YUV_YCbCr, 2, 2 } },
150         { "YVU420M",    true,  .yuv = { 3, YUV_YCrCb, 2, 2 } },
151         { "YUV422M",    true,  .yuv = { 3, YUV_YCbCr, 2, 1 } },
152         { "YVU422M",    true,  .yuv = { 3, YUV_YCrCb, 2, 1 } },
153         { "YUV444M",    true,  .yuv = { 3, YUV_YCbCr, 1, 1 } },
154         { "YVU444M",    true,  .yuv = { 3, YUV_YCrCb, 1, 1 } },
155         { "YUV24",      true,  .yuv = { 1, YUV_YCbCr | YUV_YC, 1, 1 } },
156 };
157
158 static const struct format_info *format_by_name(const char *name)
159 {
160         unsigned int i;
161
162         for (i = 0; i < ARRAY_SIZE(format_info); i++) {
163                 if (!strcmp(name, format_info[i].name))
164                         return &format_info[i];
165         }
166
167         return NULL;
168 }
169
170 /* -----------------------------------------------------------------------------
171  * File I/O
172  */
173
174 static int file_read(int fd, void *buffer, size_t size)
175 {
176         unsigned int offset = 0;
177
178         while (offset < size) {
179                 ssize_t nbytes;
180
181                 nbytes = read(fd, buffer + offset, size - offset);
182                 if (nbytes < 0) {
183                         if (errno == EINTR)
184                                 continue;
185
186                         return -errno;
187                 }
188
189                 if (nbytes == 0)
190                         return offset;
191
192                 offset += nbytes;
193         }
194
195         return size;
196 }
197
198 static int file_write(int fd, const void *buffer, size_t size)
199 {
200         unsigned int offset = 0;
201
202         while (offset < size) {
203                 ssize_t nbytes;
204
205                 nbytes = write(fd, buffer + offset, size - offset);
206                 if (nbytes < 0) {
207                         if (errno == EINTR)
208                                 continue;
209
210                         return -errno;
211                 }
212
213                 offset += nbytes;
214         }
215
216         return 0;
217 }
218
219 /* -----------------------------------------------------------------------------
220  * Image initialization
221  */
222
223 static struct image *image_new(const struct format_info *format,
224                                unsigned int width, unsigned int height)
225 {
226         struct image *image;
227
228         image = malloc(sizeof(*image));
229         if (!image)
230                 return NULL;
231
232         memset(image, 0, sizeof(*image));
233         image->format = format;
234         image->width = width;
235         image->height = height;
236
237         if (format->is_yuv)
238                 image->size = image->width * image->height
239                              * (8 + 2 * 8 / format->yuv.xsub / format->yuv.ysub)
240                              / 8;
241         else
242                 image->size = image->width * image->height
243                              * format->rgb.bpp / 8;
244
245         image->data = malloc(image->size);
246         if (!image->data) {
247                 printf("Not enough memory for image data\n");
248                 free(image);
249                 return NULL;
250         }
251
252         return image;
253 }
254
255 static void image_delete(struct image *image)
256 {
257         if (!image)
258                 return;
259
260         free(image->data);
261         free(image);
262 }
263
264 /* -----------------------------------------------------------------------------
265  * Image read and write
266  */
267
268 static int pnm_read_bytes(int fd, char *buffer, size_t size)
269 {
270         int ret;
271
272         ret = file_read(fd, buffer, size);
273         if (ret < 0) {
274                 printf("Unable to read PNM file: %s (%d)\n", strerror(-ret),
275                        ret);
276                 return ret;
277         }
278         if ((size_t)ret != size) {
279                 printf("Invalid PNM file: file too short\n");
280                 return -ENODATA;
281         }
282
283         return 0;
284 }
285
286 static int pnm_read_integer(int fd)
287 {
288         unsigned int value = 0;
289         int ret;
290         char c;
291
292         do {
293                 ret = pnm_read_bytes(fd, &c, 1);
294         } while (!ret && isspace(c));
295
296         if (ret)
297                 return ret;
298
299         while (!ret && isdigit(c)) {
300                 value = value * 10 + c - '0';
301                 ret = pnm_read_bytes(fd, &c, 1);
302         }
303
304         if (ret)
305                 return ret;
306
307         if (!isspace(c))
308                 return -EINVAL;
309
310         return value;
311 }
312
313 static struct image *pnm_read(const char *filename)
314 {
315         struct image *image;
316         unsigned int width;
317         unsigned int height;
318         char buffer[2];
319         int ret;
320         int fd;
321
322         fd = open(filename, O_RDONLY);
323         if (fd < 0) {
324                 printf("Unable to open PNM file %s: %s (%d)\n", filename,
325                        strerror(errno), errno);
326                 return NULL;
327         }
328
329         /* Read and validate the header. */
330         ret = pnm_read_bytes(fd, buffer, 2);
331         if (ret < 0)
332                 goto done;
333
334         if (buffer[0] != 'P' || buffer[1] != '6') {
335                 printf("Invalid PNM file: invalid signature\n");
336                 ret = -EINVAL;
337                 goto done;
338         }
339
340         /* Read the width, height and depth. */
341         ret = pnm_read_integer(fd);
342         if (ret < 0) {
343                 printf("Invalid PNM file: invalid width\n");
344                 goto done;
345         }
346
347         width = ret;
348
349         ret = pnm_read_integer(fd);
350         if (ret < 0) {
351                 printf("Invalid PNM file: invalid height\n");
352                 goto done;
353         }
354
355         height = ret;
356
357         ret = pnm_read_integer(fd);
358         if (ret < 0) {
359                 printf("Invalid PNM file: invalid depth\n");
360                 goto done;
361         }
362
363         if (ret != 255) {
364                 printf("Invalid PNM file: unsupported depth %u\n", ret);
365                 ret = -EINVAL;
366                 goto done;
367         }
368
369         /* Allocate the image and read the data. */
370         image = image_new(format_by_name("RGB24"), width, height);
371         if (!image)
372                 goto done;
373
374         ret = pnm_read_bytes(fd, image->data, image->size);
375         if (ret < 0) {
376                 image_delete(image);
377                 image = NULL;
378         }
379
380 done:
381         close(fd);
382
383         return ret ? NULL : image;
384 }
385
386 static struct image *image_read(const char *filename)
387 {
388         return pnm_read(filename);
389 }
390
391 static int image_write(const struct image *image, const char *filename)
392 {
393         int ret;
394         int fd;
395
396         fd = open(filename, O_WRONLY | O_CREAT,
397                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
398         if (fd < 0) {
399                 printf("Unable to open output file %s: %s (%d)\n", filename,
400                        strerror(errno), errno);
401                 return -errno;
402         }
403
404         ret = file_write(fd, image->data, image->size);
405         if (ret < 0)
406                 printf("Unable to write output image: %s (%d)\n",
407                        strerror(-ret), ret);
408         else
409                 ftruncate(fd, image->size);
410
411         close(fd);
412         return ret;
413 }
414
415 /* -----------------------------------------------------------------------------
416  * Image formatting
417  */
418
419 static void image_format_rgb8(const struct image *input, struct image *output,
420                               const struct params *params)
421 {
422         const uint8_t *idata = input->data;
423         uint8_t *odata = output->data;
424         uint8_t r, g, b;
425         unsigned int x, y;
426
427         idata = input->data;
428         odata = output->data;
429
430         for (y = 0; y < input->height; ++y) {
431                 for (x = 0; x < input->width; ++x) {
432                         /* There's only one RGB8 variant supported, hardcode it. */
433                         r = *idata++ >> 5;
434                         g = *idata++ >> 5;
435                         b = *idata++ >> 6;
436
437                         *odata++ = (r << 5) | (g << 2) | b;
438                 }
439         }
440 }
441
442 static void image_format_rgb16(const struct image *input, struct image *output,
443                                const struct params *params)
444 {
445         const struct format_info *format = output->format;
446         const uint8_t *idata = input->data;
447         uint16_t *odata = output->data;
448         uint8_t r, g, b, a;
449         unsigned int x, y;
450
451         for (y = 0; y < input->height; ++y) {
452                 for (x = 0; x < input->width; ++x) {
453                         r = *idata++ >> (8 - format->rgb.red.length);
454                         g = *idata++ >> (8 - format->rgb.green.length);
455                         b = *idata++ >> (8 - format->rgb.blue.length);
456                         a = params->alpha >> (8 - format->rgb.alpha.length);
457
458                         *odata++ = (r << format->rgb.red.offset)
459                                  | (g << format->rgb.green.offset)
460                                  | (b << format->rgb.blue.offset)
461                                  | (a << format->rgb.alpha.offset);
462                 }
463         }
464 }
465
466 static void image_format_rgb24(const struct image *input, struct image *output,
467                                const struct params *params)
468 {
469         struct color_rgb24 {
470                 unsigned int value:24;
471         } __attribute__((__packed__));
472
473         const struct format_info *format = output->format;
474         const uint8_t *idata = input->data;
475         struct color_rgb24 *odata = output->data;
476         uint8_t r, g, b, a;
477         unsigned int x, y;
478
479         idata = input->data;
480         odata = output->data;
481
482         for (y = 0; y < input->height; ++y) {
483                 for (x = 0; x < input->width; ++x) {
484                         r = *idata++ >> (8 - format->rgb.red.length);
485                         g = *idata++ >> (8 - format->rgb.green.length);
486                         b = *idata++ >> (8 - format->rgb.blue.length);
487                         a = params->alpha >> (8 - format->rgb.alpha.length);
488
489                         *odata++ = (struct color_rgb24){ .value =
490                                         (r << format->rgb.red.offset) |
491                                         (g << format->rgb.green.offset) |
492                                         (b << format->rgb.blue.offset) |
493                                         (a << format->rgb.alpha.offset) };
494                 }
495         }
496 }
497
498 static void image_format_rgb32(const struct image *input, struct image *output,
499                                const struct params *params)
500 {
501         const struct format_info *format = output->format;
502         const uint8_t *idata = input->data;
503         uint32_t *odata = output->data;
504         uint8_t r, g, b, a;
505         unsigned int x, y;
506
507         for (y = 0; y < input->height; ++y) {
508                 for (x = 0; x < input->width; ++x) {
509                         r = *idata++ >> (8 - format->rgb.red.length);
510                         g = *idata++ >> (8 - format->rgb.green.length);
511                         b = *idata++ >> (8 - format->rgb.blue.length);
512                         a = params->alpha >> (8 - format->rgb.alpha.length);
513
514                         *odata++ = (r << format->rgb.red.offset)
515                                  | (g << format->rgb.green.offset)
516                                  | (b << format->rgb.blue.offset)
517                                  | (a << format->rgb.alpha.offset);
518                 }
519         }
520 }
521
522 /*
523  * In YUV packed and planar formats, when subsampling horizontally average the
524  * chroma components of the two pixels to match the hardware behaviour.
525  */
526 static void image_format_yuv_packed(const struct image *input, struct image *output,
527                                     const struct params *params)
528 {
529         const struct format_info *format = output->format;
530         const uint8_t *idata = input->data;
531         uint8_t *o_y = output->data + ((format->yuv.order & YUV_YC) ? 0 : 1);
532         uint8_t *o_c = output->data + ((format->yuv.order & YUV_CY) ? 0 : 1);
533         unsigned int u_offset = (format->yuv.order & YUV_YCrCb) ? 2 : 0;
534         unsigned int v_offset = (format->yuv.order & YUV_YCbCr) ? 2 : 0;
535         unsigned int x;
536         unsigned int y;
537
538         for (y = 0; y < output->height; ++y) {
539                 for (x = 0; x < output->width; x += 2) {
540                         o_y[2*x] = idata[3*x];
541                         o_y[2*x + 2] = idata[3*x + 3];
542                         o_c[2*x + u_offset] = (idata[3*x + 1] + idata[3*x + 4]) / 2;
543                         o_c[2*x + v_offset] = (idata[3*x + 2] + idata[3*x + 5]) / 2;
544                 }
545
546                 o_y += input->width * 2;
547                 o_c += input->width * 2;
548                 idata += input->width * 3;
549         }
550 }
551
552 static void image_format_yuv_planar(const struct image *input, struct image *output,
553                                     const struct params *params)
554 {
555         const struct format_info *format = output->format;
556         const uint8_t *idata;
557         uint8_t *o_y = output->data;
558         uint8_t *o_c = o_y + output->width * output->height;
559         uint8_t *o_u;
560         uint8_t *o_v;
561         unsigned int xsub = format->yuv.xsub;
562         unsigned int ysub = format->yuv.ysub;
563         unsigned int c_stride;
564         unsigned int x;
565         unsigned int y;
566
567         if (format->yuv.num_planes == 2) {
568                 o_u = (format->yuv.order & YUV_YCbCr) ? o_c : o_c + 1;
569                 o_v = (format->yuv.order & YUV_YCrCb) ? o_c : o_c + 1;
570                 c_stride = 2;
571         } else {
572                 unsigned int c_size = output->width * output->height
573                                     / xsub / ysub;
574
575                 o_u = (format->yuv.order & YUV_YCbCr) ? o_c : o_c + c_size;
576                 o_v = (format->yuv.order & YUV_YCrCb) ? o_c : o_c + c_size;
577                 c_stride = 1;
578         }
579
580         idata = input->data;
581         for (y = 0; y < output->height; ++y) {
582                 for (x = 0; x < output->width; ++x)
583                         *o_y++ = idata[3*x];
584
585                 idata += input->width * 3;
586         }
587
588         idata = input->data;
589         for (y = 0; y < output->height / ysub; ++y) {
590                 if (xsub == 1) {
591                         for (x = 0; x < output->width; x += xsub) {
592                                 o_u[x*c_stride/xsub] = idata[3*x + 1];
593                                 o_v[x*c_stride/xsub] = idata[3*x + 2];
594                         }
595                 } else {
596                         for (x = 0; x < output->width; x += xsub) {
597                                 o_u[x*c_stride/xsub] = (idata[3*x + 1] + idata[3*x + 4]) / 2;
598                                 o_v[x*c_stride/xsub] = (idata[3*x + 2] + idata[3*x + 5]) / 2;
599                         }
600                 }
601
602                 o_u += output->width * c_stride / xsub;
603                 o_v += output->width * c_stride / xsub;
604                 idata += input->width * 3 * ysub;
605         }
606 }
607
608 /* -----------------------------------------------------------------------------
609  * Colorspace handling
610  *
611  * The code is inspired by the v4l2-tpg Linux kernel driver.
612  */
613
614 static void colorspace_matrix(enum v4l2_ycbcr_encoding encoding,
615                               enum v4l2_quantization quantization,
616                               int (*matrix)[3][3])
617 {
618 #define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
619
620         static const int bt601[3][3] = {
621                 { COEFF(0.299, 219),  COEFF(0.587, 219),  COEFF(0.114, 219)  },
622                 { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224)    },
623                 { COEFF(0.5, 224),    COEFF(-0.419, 224), COEFF(-0.081, 224) },
624         };
625         static const int bt601_full[3][3] = {
626                 { COEFF(0.299, 255),  COEFF(0.587, 255),  COEFF(0.114, 255)  },
627                 { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255)    },
628                 { COEFF(0.5, 255),    COEFF(-0.419, 255), COEFF(-0.081, 255) },
629         };
630         static const int rec709[3][3] = {
631                 { COEFF(0.2126, 219),  COEFF(0.7152, 219),  COEFF(0.0722, 219)  },
632                 { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224)     },
633                 { COEFF(0.5, 224),     COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
634         };
635         static const int rec709_full[3][3] = {
636                 { COEFF(0.2126, 255),  COEFF(0.7152, 255),  COEFF(0.0722, 255)  },
637                 { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255)     },
638                 { COEFF(0.5, 255),     COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
639         };
640         static const int smpte240m[3][3] = {
641                 { COEFF(0.212, 219),  COEFF(0.701, 219),  COEFF(0.087, 219)  },
642                 { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224)    },
643                 { COEFF(0.5, 224),    COEFF(-0.445, 224), COEFF(-0.055, 224) },
644         };
645         static const int smpte240m_full[3][3] = {
646                 { COEFF(0.212, 255),  COEFF(0.701, 255),  COEFF(0.087, 255)  },
647                 { COEFF(-0.116, 255), COEFF(-0.384, 255), COEFF(0.5, 255)    },
648                 { COEFF(0.5, 255),    COEFF(-0.445, 255), COEFF(-0.055, 255) },
649         };
650         static const int bt2020[3][3] = {
651                 { COEFF(0.2627, 219),  COEFF(0.6780, 219),  COEFF(0.0593, 219)  },
652                 { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224)     },
653                 { COEFF(0.5, 224),     COEFF(-0.4598, 224), COEFF(-0.0402, 224) },
654         };
655         static const int bt2020_full[3][3] = {
656                 { COEFF(0.2627, 255),  COEFF(0.6780, 255),  COEFF(0.0593, 255)  },
657                 { COEFF(-0.1396, 255), COEFF(-0.3604, 255), COEFF(0.5, 255)     },
658                 { COEFF(0.5, 255),     COEFF(-0.4698, 255), COEFF(-0.0402, 255) },
659         };
660
661         bool full = quantization == V4L2_QUANTIZATION_FULL_RANGE;
662         unsigned int i;
663         const int (*m)[3][3];
664
665         switch (encoding) {
666         case V4L2_YCBCR_ENC_601:
667         default:
668                 m = full ? &bt601_full : &bt601;
669                 break;
670         case V4L2_YCBCR_ENC_709:
671                 m = full ? &rec709_full : &rec709;
672                 break;
673         case V4L2_YCBCR_ENC_BT2020:
674                 m = full ? &bt2020_full : &bt2020;
675                 break;
676         case V4L2_YCBCR_ENC_SMPTE240M:
677                 m = full ? &smpte240m_full : &smpte240m;
678                 break;
679         }
680
681         for (i = 0; i < ARRAY_SIZE(*m); ++i)
682                 memcpy((*matrix)[i], (*m)[i], sizeof((*m)[i]));
683 }
684
685 static void colorspace_rgb2ycbcr(int m[3][3],
686                                  enum v4l2_quantization quantization,
687                                  const uint8_t rgb[3], uint8_t ycbcr[3])
688 {
689         bool full = quantization == V4L2_QUANTIZATION_FULL_RANGE;
690         unsigned int y_offset = full ? 0 : 16;
691         int r, g, b;
692         int y, cb, cr;
693         int div;
694
695         r = rgb[0] << 4;
696         g = rgb[1] << 4;
697         b = rgb[2] << 4;
698
699         div = (1 << (8 + 4)) * 255;
700         y  = (m[0][0] * r + m[0][1] * g + m[0][2] * b + y_offset * div) / div;
701         cb = (m[1][0] * r + m[1][1] * g + m[1][2] * b + 128 * div) / div;
702         cr = (m[2][0] * r + m[2][1] * g + m[2][2] * b + 128 * div) / div;
703
704         ycbcr[0] = y;
705         ycbcr[1] = cb;
706         ycbcr[2] = cr;
707 }
708
709 static void image_colorspace_rgb_to_yuv(const struct image *input,
710                                         struct image *output,
711                                         const struct params *params)
712 {
713         int matrix[3][3];
714         const uint8_t *idata = input->data;
715         uint8_t *odata = output->data;
716         unsigned int x;
717         unsigned int y;
718
719         colorspace_matrix(params->encoding, params->quantization, &matrix);
720
721         for (y = 0; y < output->height; ++y) {
722                 for (x = 0; x < output->width; ++x) {
723                         colorspace_rgb2ycbcr(matrix, params->quantization, idata, odata);
724                         idata += 3;
725                         odata += 3;
726                 }
727         }
728 }
729
730 /* -----------------------------------------------------------------------------
731  * Image scaling
732  */
733
734 static void image_scale_bilinear(const struct image *input, struct image *output)
735 {
736 #define _C0(x, y)       (idata[0][((y)*input->width+(x)) * 3])
737 #define _C1(x, y)       (idata[1][((y)*input->width+(x)) * 3])
738 #define _C2(x, y)       (idata[2][((y)*input->width+(x)) * 3])
739         const uint8_t *idata[3] = { input->data, input->data + 1, input->data + 2 };
740         uint8_t *odata = output->data;
741         uint8_t c0, c1, c2;
742         unsigned int u, v;
743
744         for (v = 0; v < output->height; ++v) {
745                 double v_input = (double)v / (output->height - 1) * (input->height - 1);
746                 unsigned int y = floor(v_input);
747                 double v_ratio = v_input - y;
748
749                 for (u = 0; u < output->width; ++u) {
750                         double u_input = (double)u / (output->width - 1) * (input->width - 1);
751                         unsigned int x = floor(u_input);
752                         double u_ratio = u_input - x;
753
754                         c0 = (_C0(x, y)   * (1 - u_ratio) + _C0(x+1, y)   * u_ratio) * (1 - v_ratio)
755                            + (_C0(x, y+1) * (1 - u_ratio) + _C0(x+1, y+1) * u_ratio) * v_ratio;
756                         c1 = (_C1(x, y)   * (1 - u_ratio) + _C1(x+1, y)   * u_ratio) * (1 - v_ratio)
757                            + (_C1(x, y+1) * (1 - u_ratio) + _C1(x+1, y+1) * u_ratio) * v_ratio;
758                         c2 = (_C2(x, y)   * (1 - u_ratio) + _C2(x+1, y)   * u_ratio) * (1 - v_ratio)
759                            + (_C2(x, y+1) * (1 - u_ratio) + _C2(x+1, y+1) * u_ratio) * v_ratio;
760
761                         *odata++ = c0;
762                         *odata++ = c1;
763                         *odata++ = c2;
764                 }
765         }
766 #undef _C0
767 #undef _C1
768 #undef _C2
769 }
770
771 static void image_scale(const struct image *input, struct image *output,
772                         const struct params *params)
773 {
774         image_scale_bilinear(input, output);
775 }
776
777 /* -----------------------------------------------------------------------------
778  * Image composing
779  */
780
781 static void image_compose(const struct image *input, struct image *output,
782                           unsigned int num_inputs)
783 {
784         const uint8_t *idata = input->data;
785         uint8_t *odata = output->data;
786         unsigned int offset = 50;
787         unsigned int y;
788         unsigned int i;
789
790         memset(odata, 0, output->size);
791
792         for (i = 0; i < num_inputs; ++i) {
793                 unsigned int dst_offset = (offset * output->width + offset) * 3;
794
795                 if (offset >= output->width || offset >= output->height)
796                         break;
797
798                 for (y = 0; y < output->height - offset; ++y)
799                         memcpy(odata + y * output->width * 3 + dst_offset,
800                                idata + y * output->width * 3,
801                                (output->width - offset) * 3);
802
803                 offset += 50;
804         }
805 }
806
807 /* -----------------------------------------------------------------------------
808  * Image rotation and flipping
809  */
810
811 static void image_rotate(const struct image *input, struct image *output)
812 {
813         const uint8_t *idata = input->data;
814         uint8_t *odata;
815         unsigned int stride = output->width * 3;
816         unsigned int x, y;
817
818         odata = output->data + stride - 3;
819
820         for (y = 0; y < input->height; ++y) {
821                 for (x = 0; x < input->width; ++x) {
822                         odata[x*stride+0] = *idata++;
823                         odata[x*stride+1] = *idata++;
824                         odata[x*stride+2] = *idata++;
825                 }
826
827                 odata -= 3;
828         }
829 }
830
831 static void image_flip(const struct image *input, struct image *output,
832                        bool hflip, bool vflip)
833 {
834         const uint8_t *idata = input->data;
835         uint8_t *odata = output->data;
836         unsigned int stride = output->width * 3;
837         unsigned int x, y;
838         int x_step, y_step;
839
840         if (!hflip) {
841                 x_step = 3;
842                 y_step = !vflip ? 0 : -2 * stride;
843                 odata += !vflip ? 0 : stride * (output->height - 1);
844         } else {
845                 x_step = -3;
846                 y_step = !vflip ? 2 * stride : 0;
847                 odata += !vflip ? stride - 3 : stride * output->height - 3;
848         }
849
850         for (y = 0; y < output->height; ++y) {
851                 for (x = 0; x < output->width; ++x) {
852                         odata[0] = *idata++;
853                         odata[1] = *idata++;
854                         odata[2] = *idata++;
855
856                         odata += x_step;
857                 }
858
859                 odata += y_step;
860         }
861 }
862
863 /* -----------------------------------------------------------------------------
864  * Look Up Table
865  */
866
867 static int image_lut_1d(const struct image *input, struct image *output,
868                         const char *filename)
869 {
870         const uint8_t *idata = input->data;
871         uint8_t *odata = output->data;
872         unsigned int comp_map[3];
873         uint8_t c0, c1, c2;
874         unsigned int x, y;
875         uint8_t lut[1024];
876         int ret;
877         int fd;
878
879         fd = open(filename, O_RDONLY);
880         if (fd < 0) {
881                 printf("Unable to open LUT file %s: %s (%d)\n", filename,
882                        strerror(errno), errno);
883                 return -errno;
884         }
885
886         ret = file_read(fd, lut, sizeof(lut));
887         close(fd);
888         if (ret < 0) {
889                 printf("Unable to read 1D LUT file: %s (%d)\n", strerror(-ret),
890                        ret);
891                 return ret;
892         }
893         if ((size_t)ret != sizeof(lut)) {
894                 printf("Invalid 1D LUT file: file too short\n");
895                 return -ENODATA;
896         }
897
898         if (input->format->is_yuv)
899                 memcpy(comp_map, (unsigned int[3]){ 1, 0, 2 },
900                        sizeof(comp_map));
901         else
902                 memcpy(comp_map, (unsigned int[3]){ 2, 1, 0 },
903                        sizeof(comp_map));
904
905         for (y = 0; y < input->height; ++y) {
906                 for (x = 0; x < input->width; ++x) {
907                         c0 = *idata++;
908                         c1 = *idata++;
909                         c2 = *idata++;
910
911                         *odata++ = lut[c0*4 + comp_map[0]];
912                         *odata++ = lut[c1*4 + comp_map[1]];
913                         *odata++ = lut[c2*4 + comp_map[2]];
914                 }
915         }
916
917         return 0;
918 }
919
920 static int image_lut_3d(const struct image *input, struct image *output,
921                         const char *filename)
922 {
923         const uint8_t *idata = input->data;
924         uint8_t *odata = output->data;
925         unsigned int comp_map[3];
926         unsigned int x, y;
927         uint32_t lut[17*17*17];
928         int ret;
929         int fd;
930
931         fd = open(filename, O_RDONLY);
932         if (fd < 0) {
933                 printf("Unable to open 3D LUT file %s: %s (%d)\n", filename,
934                        strerror(errno), errno);
935                 return -errno;
936         }
937
938         ret = file_read(fd, lut, sizeof(lut));
939         close(fd);
940         if (ret < 0) {
941                 printf("Unable to read 3D LUT file: %s (%d)\n", strerror(-ret),
942                        ret);
943                 return ret;
944         }
945         if ((size_t)ret != sizeof(lut)) {
946                 printf("Invalid 3D LUT file: file too short\n");
947                 return -ENODATA;
948         }
949
950         if (input->format->is_yuv)
951                 memcpy(comp_map, (unsigned int[3]){ 2, 0, 1 },
952                        sizeof(comp_map));
953         else
954                 memcpy(comp_map, (unsigned int[3]){ 0, 1, 2 },
955                        sizeof(comp_map));
956
957         for (y = 0; y < input->height; ++y) {
958                 for (x = 0; x < input->width; ++x) {
959                         double a1_ratio, a2_ratio, a3_ratio;
960                         unsigned int a1, a2, a3;
961                         double c0, c1, c2;
962                         uint8_t c[3];
963
964                         c[0] = idata[comp_map[0]];
965                         c[1] = idata[comp_map[1]];
966                         c[2] = idata[comp_map[2]];
967
968                         a1 = c[0] >> 4;
969                         a2 = c[1] >> 4;
970                         a3 = c[2] >> 4;
971
972                         /*
973                          * Implement the hardware MVS (Max Value Stretch)
974                          * behaviour: move the point by one step towards the
975                          * upper limit of the grid if we're closer than 0.5 to
976                          * that limit.
977                          */
978                         a1_ratio = ((c[0] & 0xf) + (c[0] >= 0xf8 ? 1 : 0)) / 16.;
979                         a2_ratio = ((c[1] & 0xf) + (c[1] >= 0xf8 ? 1 : 0)) / 16.;
980                         a3_ratio = ((c[2] & 0xf) + (c[2] >= 0xf8 ? 1 : 0)) / 16.;
981
982 #define _LUT(a1, a2, a3, offset)        ((lut[(a1)+(a2)*17+(a3)*17*17] >> (offset)) & 0xff)
983                         c0 = _LUT(a1,   a2,   a3,   16) * (1 - a1_ratio) * (1 - a2_ratio) * (1 - a3_ratio)
984                            + _LUT(a1,   a2,   a3+1, 16) * (1 - a1_ratio) * (1 - a2_ratio) * a3_ratio
985                            + _LUT(a1,   a2+1, a3,   16) * (1 - a1_ratio) * a2_ratio       * (1 - a3_ratio)
986                            + _LUT(a1,   a2+1, a3+1, 16) * (1 - a1_ratio) * a2_ratio       * a3_ratio
987                            + _LUT(a1+1, a2,   a3,   16) * a1_ratio       * (1 - a2_ratio) * (1 - a3_ratio)
988                            + _LUT(a1+1, a2,   a3+1, 16) * a1_ratio       * (1 - a2_ratio) * a3_ratio
989                            + _LUT(a1+1, a2+1, a3,   16) * a1_ratio       * a2_ratio       * (1 - a3_ratio)
990                            + _LUT(a1+1, a2+1, a3+1, 16) * a1_ratio       * a2_ratio       * a3_ratio;
991                         c1 = _LUT(a1,   a2,   a3,    8) * (1 - a1_ratio) * (1 - a2_ratio) * (1 - a3_ratio)
992                            + _LUT(a1,   a2,   a3+1,  8) * (1 - a1_ratio) * (1 - a2_ratio) * a3_ratio
993                            + _LUT(a1,   a2+1, a3,    8) * (1 - a1_ratio) * a2_ratio       * (1 - a3_ratio)
994                            + _LUT(a1,   a2+1, a3+1,  8) * (1 - a1_ratio) * a2_ratio       * a3_ratio
995                            + _LUT(a1+1, a2,   a3,    8) * a1_ratio       * (1 - a2_ratio) * (1 - a3_ratio)
996                            + _LUT(a1+1, a2,   a3+1,  8) * a1_ratio       * (1 - a2_ratio) * a3_ratio
997                            + _LUT(a1+1, a2+1, a3,    8) * a1_ratio       * a2_ratio       * (1 - a3_ratio)
998                            + _LUT(a1+1, a2+1, a3+1,  8) * a1_ratio       * a2_ratio       * a3_ratio;
999                         c2 = _LUT(a1,   a2,   a3,    0) * (1 - a1_ratio) * (1 - a2_ratio) * (1 - a3_ratio)
1000                            + _LUT(a1,   a2,   a3+1,  0) * (1 - a1_ratio) * (1 - a2_ratio) * a3_ratio
1001                            + _LUT(a1,   a2+1, a3,    0) * (1 - a1_ratio) * a2_ratio       * (1 - a3_ratio)
1002                            + _LUT(a1,   a2+1, a3+1,  0) * (1 - a1_ratio) * a2_ratio       * a3_ratio
1003                            + _LUT(a1+1, a2,   a3,    0) * a1_ratio       * (1 - a2_ratio) * (1 - a3_ratio)
1004                            + _LUT(a1+1, a2,   a3+1,  0) * a1_ratio       * (1 - a2_ratio) * a3_ratio
1005                            + _LUT(a1+1, a2+1, a3,    0) * a1_ratio       * a2_ratio       * (1 - a3_ratio)
1006                            + _LUT(a1+1, a2+1, a3+1,  0) * a1_ratio       * a2_ratio       * a3_ratio;
1007 #undef _LUT
1008
1009                         odata[comp_map[0]] = round(c0);
1010                         odata[comp_map[1]] = round(c1);
1011                         odata[comp_map[2]] = round(c2);
1012
1013                         idata += 3;
1014                         odata += 3;
1015                 }
1016         }
1017
1018         return 0;
1019 }
1020
1021 /* -----------------------------------------------------------------------------
1022  * Histogram
1023  */
1024
1025 static void histogram_compute(const struct image *image, void *histo)
1026 {
1027         const uint8_t *data = image->data;
1028         uint8_t comp_min[3] = { 255, 255, 255 };
1029         uint8_t comp_max[3] = { 0, 0, 0 };
1030         uint32_t comp_sums[3] = { 0, 0, 0 };
1031         uint32_t comp_bins[3][64];
1032         unsigned int comp_map[3];
1033         unsigned int x, y;
1034         unsigned int i, j;
1035
1036         if (image->format->is_yuv)
1037                 memcpy(comp_map, (unsigned int[3]){ 2, 0, 1 }, sizeof(comp_map));
1038         else
1039                 memcpy(comp_map, (unsigned int[3]){ 0, 1, 2 }, sizeof(comp_map));
1040
1041         memset(comp_bins, 0, sizeof(comp_bins));
1042
1043         for (y = 0; y < image->height; ++y) {
1044                 for (x = 0; x < image->width; ++x) {
1045                         for (i = 0; i < 3; ++i) {
1046                                 comp_min[i] = min(*data, comp_min[i]);
1047                                 comp_max[i] = max(*data, comp_max[i]);
1048                                 comp_sums[i] += *data;
1049                                 comp_bins[i][*data >> 2]++;
1050                                 data++;
1051                         }
1052                 }
1053         }
1054
1055         for (i = 0; i < ARRAY_SIZE(comp_min); ++i) {
1056                 *(uint8_t *)histo++ = comp_min[comp_map[i]];
1057                 *(uint8_t *)histo++ = 0;
1058                 *(uint8_t *)histo++ = comp_max[comp_map[i]];
1059                 *(uint8_t *)histo++ = 0;
1060         }
1061
1062         for (i = 0; i < ARRAY_SIZE(comp_sums); ++i) {
1063                 *(uint32_t *)histo = comp_sums[comp_map[i]];
1064                 histo += 4;
1065         }
1066
1067         for (i = 0; i < ARRAY_SIZE(comp_bins); ++i) {
1068                 for (j = 0; j < ARRAY_SIZE(comp_bins[i]); ++j) {
1069                         *(uint32_t *)histo = comp_bins[comp_map[i]][j];
1070                         histo += 4;
1071                 }
1072         }
1073 }
1074
1075 static int histogram(const struct image *image, const char *filename)
1076 {
1077         uint8_t data[3*4 + 3*4 + 3*64*4];
1078         int ret;
1079         int fd;
1080
1081         histogram_compute(image, data);
1082
1083         fd = open(filename, O_WRONLY | O_CREAT,
1084                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1085         if (fd < 0) {
1086                 printf("Unable to open histogram file %s: %s (%d)\n", filename,
1087                        strerror(errno), errno);
1088                 return -errno;
1089         }
1090
1091         ret = file_write(fd, data, sizeof(data));
1092         if (ret < 0)
1093                 printf("Unable to write histogram: %s (%d)\n",
1094                        strerror(-ret), ret);
1095         else
1096                 ftruncate(fd, sizeof(data));
1097
1098         close(fd);
1099         return ret;
1100 }
1101
1102 /* -----------------------------------------------------------------------------
1103  * Processing pipeline
1104  */
1105
1106 static int process(const struct options *options)
1107 {
1108         struct image *input = NULL;
1109         struct image *output = NULL;
1110         unsigned int output_width;
1111         unsigned int output_height;
1112         int ret = 0;
1113
1114         /* Read the input image */
1115         input = image_read(options->input_filename);
1116         if (!input) {
1117                 ret = -EINVAL;
1118                 goto done;
1119         }
1120
1121         /* Convert colorspace */
1122         if (options->process_yuv) {
1123                 struct image *yuv;
1124
1125                 yuv = image_new(format_by_name("YUV24"), input->width,
1126                                 input->height);
1127                 if (!yuv) {
1128                         ret = -ENOMEM;
1129                         goto done;
1130                 }
1131
1132                 image_colorspace_rgb_to_yuv(input, yuv, &options->params);
1133                 image_delete(input);
1134                 input = yuv;
1135         }
1136
1137         /* Scale */
1138         if (options->output_width && options->output_height) {
1139                 output_width = options->output_width;
1140                 output_height = options->output_height;
1141         } else {
1142                 output_width = input->width;
1143                 output_height = input->height;
1144         }
1145
1146         if (options->rotate)
1147                 swap(output_width, output_height);
1148
1149         if (input->width != output_width ||
1150             input->height != output_height) {
1151                 struct image *scaled;
1152
1153                 scaled = image_new(input->format, output_width, output_height);
1154                 if (!scaled) {
1155                         ret = -ENOMEM;
1156                         goto done;
1157                 }
1158
1159                 image_scale(input, scaled, &options->params);
1160                 image_delete(input);
1161                 input = scaled;
1162         }
1163
1164         /* Compose */
1165         if (options->compose) {
1166                 struct image *composed;
1167
1168                 composed = image_new(input->format, input->width, input->height);
1169                 if (!composed) {
1170                         ret = -ENOMEM;
1171                         goto done;
1172                 }
1173
1174                 image_compose(input, composed, options->compose);
1175                 image_delete(input);
1176                 input = composed;
1177         }
1178
1179         /* Look-up tables */
1180         if (options->lut_filename) {
1181                 struct image *lut;
1182
1183                 lut = image_new(input->format, input->width, input->height);
1184                 if (!lut) {
1185                         ret = -ENOMEM;
1186                         goto done;
1187                 }
1188
1189                 image_lut_1d(input, lut, options->lut_filename);
1190                 image_delete(input);
1191                 input = lut;
1192         }
1193
1194         if (options->clu_filename) {
1195                 struct image *clu;
1196
1197                 clu = image_new(input->format, input->width, input->height);
1198                 if (!clu) {
1199                         ret = -ENOMEM;
1200                         goto done;
1201                 }
1202
1203                 image_lut_3d(input, clu, options->clu_filename);
1204                 image_delete(input);
1205                 input = clu;
1206         }
1207
1208         /* Compute the histogram */
1209         if (options->histo_filename) {
1210                 ret = histogram(input, options->histo_filename);
1211                 if (ret)
1212                         goto done;
1213         }
1214
1215         /* Rotation and flipping */
1216         if (options->rotate) {
1217                 struct image *rotated;
1218
1219                 rotated = image_new(input->format, input->height, input->width);
1220                 if (!rotated) {
1221                         ret = -ENOMEM;
1222                         goto done;
1223                 }
1224
1225                 image_rotate(input, rotated);
1226                 image_delete(input);
1227                 input = rotated;
1228         }
1229
1230         if (options->hflip || options->vflip) {
1231                 struct image *flipped;
1232
1233                 flipped = image_new(input->format, input->width, input->height);
1234                 if (!flipped) {
1235                         ret = -ENOMEM;
1236                         goto done;
1237                 }
1238
1239                 image_flip(input, flipped, options->hflip, options->vflip);
1240                 image_delete(input);
1241                 input = flipped;
1242         }
1243
1244         /* Format the output */
1245         if (input->format->is_yuv && !options->output_format->is_yuv) {
1246                 printf("RGB output with YUV processing not supported\n");
1247                 ret = -EINVAL;
1248                 goto done;
1249         }
1250
1251         if (!input->format->is_yuv && options->output_format->is_yuv) {
1252                 const struct format_info *format = format_by_name("YUV24");
1253                 struct image *converted;
1254
1255                 converted = image_new(format, input->width, input->height);
1256                 if (!converted) {
1257                         ret = -ENOMEM;
1258                         goto done;
1259                 }
1260
1261                 image_colorspace_rgb_to_yuv(input, converted, &options->params);
1262                 image_delete(input);
1263                 input = converted;
1264         }
1265
1266         output = image_new(options->output_format, input->width, input->height);
1267         if (!output) {
1268                 ret = -ENOMEM;
1269                 goto done;
1270         }
1271
1272         if (output->format->is_yuv) {
1273                 switch (output->format->yuv.num_planes) {
1274                 case 1:
1275                         image_format_yuv_packed(input, output, &options->params);
1276                         break;
1277                 case 2:
1278                 case 3:
1279                         image_format_yuv_planar(input, output, &options->params);
1280                         break;
1281                 default:
1282                         ret = -EINVAL;
1283                         break;
1284                 }
1285         } else {
1286                 switch (output->format->rgb.bpp) {
1287                 case 8:
1288                         image_format_rgb8(input, output, &options->params);
1289                         break;
1290                 case 16:
1291                         image_format_rgb16(input, output, &options->params);
1292                         break;
1293                 case 24:
1294                         image_format_rgb24(input, output, &options->params);
1295                         break;
1296                 case 32:
1297                         image_format_rgb32(input, output, &options->params);
1298                         break;
1299                 default:
1300                         ret = -EINVAL;
1301                         break;
1302                 }
1303         }
1304
1305         if (ret < 0) {
1306                 printf("Output formatting failed\n");
1307                 goto done;
1308         }
1309
1310         /* Write the output image */
1311         if (options->output_filename) {
1312                 ret = image_write(output, options->output_filename);
1313                 if (ret)
1314                         goto done;
1315         }
1316
1317         ret = 0;
1318
1319 done:
1320         image_delete(input);
1321         image_delete(output);
1322         return ret;
1323 }
1324
1325 /* -----------------------------------------------------------------------------
1326  * Usage, argument parsing and main
1327  */
1328
1329 static void usage(const char *argv0)
1330 {
1331         printf("Usage: %s [options] <infile.pnm>\n\n", argv0);
1332         printf("Convert the input image stored in <infile> in PNM format to\n");
1333         printf("the target format and resolution and store the resulting\n");
1334         printf("image in raw binary form\n\n");
1335         printf("Supported options:\n");
1336         printf("-a, --alpha value       Set the alpha value. Valid syntaxes are floating\n");
1337         printf("                        point values ([0.0 - 1.0]), fixed point values ([0-255])\n");
1338         printf("                        or percentages ([0%% - 100%%]). Defaults to 1.0\n");
1339         printf("-c, --compose n         Compose n copies of the image offset by (50,50) over a black background\n");
1340         printf("-e, --encoding enc      Set the YCbCr encoding method. Valid values are\n");
1341         printf("                        BT.601, REC.709, BT.2020 and SMPTE240M\n");
1342         printf("-f, --format format     Set the output image format\n");
1343         printf("                        Defaults to RGB24 if not specified\n");
1344         printf("                        Use -f help to list the supported formats\n");
1345         printf("-h, --help              Show this help screen\n");
1346         printf("    --hflip             Flip the image horizontally\n");
1347         printf("-H, --histogram file    Compute histogram on the output image and store it to file\n");
1348         printf("-l, --lut file          Apply 1D Look Up Table from file\n");
1349         printf("-L, --clu file          Apply 3D Look Up Table from file\n");
1350         printf("-o, --output file       Store the output image to file\n");
1351         printf("-q, --quantization q    Set the quantization method. Valid values are\n");
1352         printf("                        limited or full\n");
1353         printf("-r, --rotate            Rotate the image clockwise by 90°\n");
1354         printf("-s, --size WxH          Set the output image size\n");
1355         printf("                        Defaults to the input size if not specified\n");
1356         printf("    --vflip             Flip the image vertically\n");
1357         printf("-y, --yuv               Perform all processing in YUV space\n");
1358 }
1359
1360 static void list_formats(void)
1361 {
1362         unsigned int i;
1363
1364         for (i = 0; i < ARRAY_SIZE(format_info); i++)
1365                 printf("%s\n", format_info[i].name);
1366 }
1367
1368 #define OPT_HFLIP       256
1369 #define OPT_VFLIP       257
1370
1371 static struct option opts[] = {
1372         {"alpha", 1, 0, 'a'},
1373         {"clu", 1, 0, 'L'},
1374         {"compose", 1, 0, 'c'},
1375         {"encoding", 1, 0, 'e'},
1376         {"format", 1, 0, 'f'},
1377         {"help", 0, 0, 'h'},
1378         {"hflip", 0, 0, OPT_HFLIP},
1379         {"histogram", 1, 0, 'H'},
1380         {"lut", 1, 0, 'l'},
1381         {"output", 1, 0, 'o'},
1382         {"quantization", 1, 0, 'q'},
1383         {"rotate", 0, 0, 'r'},
1384         {"size", 1, 0, 's'},
1385         {"vflip", 0, 0, OPT_VFLIP},
1386         {"yuv", 0, 0, 'y'},
1387         {0, 0, 0, 0}
1388 };
1389
1390 static int parse_args(struct options *options, int argc, char *argv[])
1391 {
1392         char *endptr;
1393         int c;
1394
1395         if (argc < 3) {
1396                 usage(argv[0]);
1397                 return 1;
1398         }
1399
1400         memset(options, 0, sizeof(*options));
1401         options->output_format = format_by_name("RGB24");
1402         options->params.alpha = 255;
1403         options->params.encoding = V4L2_YCBCR_ENC_601;
1404         options->params.quantization = V4L2_QUANTIZATION_LIM_RANGE;
1405
1406         opterr = 0;
1407         while ((c = getopt_long(argc, argv, "a:c:e:f:hH:l:L:o:q:rs:y", opts, NULL)) != -1) {
1408
1409                 switch (c) {
1410                 case 'a': {
1411                         int alpha;
1412
1413                         if (strchr(optarg, '.')) {
1414                                 alpha = strtod(optarg, &endptr) * 255;
1415                                 if (*endptr != 0)
1416                                         alpha = -1;
1417                         } else {
1418                                 alpha = strtoul(optarg, &endptr, 10);
1419                                 if (*endptr == '%')
1420                                         alpha = alpha * 255 / 100;
1421                                 else if (*endptr != 0)
1422                                         alpha = -1;
1423                         }
1424
1425                         if (alpha < 0 || alpha > 255) {
1426                                 printf("Invalid alpha value '%s'\n", optarg);
1427                                 return 1;
1428                         }
1429
1430                         options->params.alpha = alpha;
1431                         break;
1432                 }
1433
1434                 case 'c':
1435                           options->compose = strtoul(optarg, &endptr, 10);
1436                           if (*endptr != 0) {
1437                                 printf("Invalid compose value '%s'\n", optarg);
1438                                 return 1;
1439                           }
1440                           break;
1441
1442                 case 'e':
1443                         if (!strcmp(optarg, "BT.601")) {
1444                                 options->params.encoding = V4L2_YCBCR_ENC_601;
1445                         } else if (!strcmp(optarg, "REC.709")) {
1446                                 options->params.encoding = V4L2_YCBCR_ENC_709;
1447                         } else if (!strcmp(optarg, "BT.2020")) {
1448                                 options->params.encoding = V4L2_YCBCR_ENC_BT2020;
1449                         } else if (!strcmp(optarg, "SMPTE240M")) {
1450                                 options->params.encoding = V4L2_YCBCR_ENC_SMPTE240M;
1451                         } else {
1452                                 printf("Invalid encoding value '%s'\n", optarg);
1453                                 return 1;
1454                         }
1455                         break;
1456
1457                 case 'f':
1458                         if (!strcmp("help", optarg)) {
1459                                 list_formats();
1460                                 return 1;
1461                         }
1462
1463                         options->output_format = format_by_name(optarg);
1464                         if (!options->output_format) {
1465                                 printf("Unsupported output format '%s'\n", optarg);
1466                                 return 1;
1467                         }
1468
1469                         break;
1470
1471                 case 'h':
1472                         usage(argv[0]);
1473                         exit(0);
1474                         break;
1475
1476                 case 'H':
1477                         options->histo_filename = optarg;
1478                         break;
1479
1480                 case 'l':
1481                         options->lut_filename = optarg;
1482                         break;
1483
1484                 case 'L':
1485                         options->clu_filename = optarg;
1486                         break;
1487
1488                 case 'o':
1489                         options->output_filename = optarg;
1490                         break;
1491
1492                 case 'q':
1493                         if (!strcmp(optarg, "limited")) {
1494                                 options->params.quantization = V4L2_QUANTIZATION_LIM_RANGE;
1495                         } else if (!strcmp(optarg, "full")) {
1496                                 options->params.quantization = V4L2_QUANTIZATION_FULL_RANGE;
1497                         } else {
1498                                 printf("Invalid quantization value '%s'\n", optarg);
1499                                 return 1;
1500                         }
1501                         break;
1502
1503                         break;
1504
1505                 case 'r':
1506                         options->rotate = true;
1507                         break;
1508
1509                 case 's':
1510                         options->output_width = strtol(optarg, &endptr, 10);
1511                         if (*endptr != 'x' || endptr == optarg) {
1512                                 printf("Invalid size '%s'\n", optarg);
1513                                 return 1;
1514                         }
1515
1516                         options->output_height = strtol(endptr + 1, &endptr, 10);
1517                         if (*endptr != 0) {
1518                                 printf("Invalid size '%s'\n", optarg);
1519                                 return 1;
1520                         }
1521                         break;
1522
1523                 case 'y':
1524                         options->process_yuv = true;
1525                         break;
1526
1527                 case OPT_HFLIP:
1528                         options->hflip = true;
1529                         break;
1530
1531                 case OPT_VFLIP:
1532                         options->vflip = true;
1533                         break;
1534
1535                 default:
1536                         printf("Invalid option -%c\n", c);
1537                         printf("Run %s -h for help.\n", argv[0]);
1538                         return 1;
1539                 }
1540         }
1541
1542         if (optind != argc - 1) {
1543                 usage(argv[0]);
1544                 return 1;
1545         }
1546
1547         options->input_filename = argv[optind];
1548
1549         return 0;
1550 }
1551
1552 int main(int argc, char *argv[])
1553 {
1554         struct options options;
1555         int ret;
1556
1557         ret = parse_args(&options, argc, argv);
1558         if (ret)
1559                 return ret;
1560
1561         ret = process(&options);
1562         if (ret)
1563                 return 1;
1564
1565         return 0;
1566 }