gen-image: Add input format configuration
[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 *input_format;
105         const struct format_info *output_format;
106         unsigned int output_height;
107         unsigned int output_width;
108
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 static void image_convert_rgb_to_rgb(const struct image *input,
731                                      struct image *output,
732                                      const struct format_info *format)
733 {
734         const uint8_t *idata = input->data;
735         uint8_t *odata = output->data;
736         unsigned int x;
737         unsigned int y;
738         uint8_t r, g, b;
739
740         for (y = 0; y < output->height; ++y) {
741                 for (x = 0; x < output->width; ++x) {
742                         r = *idata++ & (0xff << (8 - format->rgb.red.length));
743                         g = *idata++ & (0xff << (8 - format->rgb.green.length));
744                         b = *idata++ & (0xff << (8 - format->rgb.blue.length));
745                         *odata++ = r;
746                         *odata++ = g;
747                         *odata++ = b;
748                 }
749         }
750 }
751
752 /* -----------------------------------------------------------------------------
753  * Image scaling
754  */
755
756 static void image_scale_bilinear(const struct image *input, struct image *output)
757 {
758 #define _C0(x, y)       (idata[0][((y)*input->width+(x)) * 3])
759 #define _C1(x, y)       (idata[1][((y)*input->width+(x)) * 3])
760 #define _C2(x, y)       (idata[2][((y)*input->width+(x)) * 3])
761         const uint8_t *idata[3] = { input->data, input->data + 1, input->data + 2 };
762         uint8_t *odata = output->data;
763         uint8_t c0, c1, c2;
764         unsigned int u, v;
765
766         for (v = 0; v < output->height; ++v) {
767                 double v_input = (double)v / (output->height - 1) * (input->height - 1);
768                 unsigned int y = floor(v_input);
769                 double v_ratio = v_input - y;
770
771                 for (u = 0; u < output->width; ++u) {
772                         double u_input = (double)u / (output->width - 1) * (input->width - 1);
773                         unsigned int x = floor(u_input);
774                         double u_ratio = u_input - x;
775
776                         c0 = (_C0(x, y)   * (1 - u_ratio) + _C0(x+1, y)   * u_ratio) * (1 - v_ratio)
777                            + (_C0(x, y+1) * (1 - u_ratio) + _C0(x+1, y+1) * u_ratio) * v_ratio;
778                         c1 = (_C1(x, y)   * (1 - u_ratio) + _C1(x+1, y)   * u_ratio) * (1 - v_ratio)
779                            + (_C1(x, y+1) * (1 - u_ratio) + _C1(x+1, y+1) * u_ratio) * v_ratio;
780                         c2 = (_C2(x, y)   * (1 - u_ratio) + _C2(x+1, y)   * u_ratio) * (1 - v_ratio)
781                            + (_C2(x, y+1) * (1 - u_ratio) + _C2(x+1, y+1) * u_ratio) * v_ratio;
782
783                         *odata++ = c0;
784                         *odata++ = c1;
785                         *odata++ = c2;
786                 }
787         }
788 #undef _C0
789 #undef _C1
790 #undef _C2
791 }
792
793 static void image_scale(const struct image *input, struct image *output,
794                         const struct params *params)
795 {
796         image_scale_bilinear(input, output);
797 }
798
799 /* -----------------------------------------------------------------------------
800  * Image composing
801  */
802
803 static void image_compose(const struct image *input, struct image *output,
804                           unsigned int num_inputs)
805 {
806         const uint8_t *idata = input->data;
807         uint8_t *odata = output->data;
808         unsigned int offset = 50;
809         unsigned int y;
810         unsigned int i;
811
812         memset(odata, 0, output->size);
813
814         for (i = 0; i < num_inputs; ++i) {
815                 unsigned int dst_offset = (offset * output->width + offset) * 3;
816
817                 if (offset >= output->width || offset >= output->height)
818                         break;
819
820                 for (y = 0; y < output->height - offset; ++y)
821                         memcpy(odata + y * output->width * 3 + dst_offset,
822                                idata + y * output->width * 3,
823                                (output->width - offset) * 3);
824
825                 offset += 50;
826         }
827 }
828
829 /* -----------------------------------------------------------------------------
830  * Image rotation and flipping
831  */
832
833 static void image_rotate(const struct image *input, struct image *output)
834 {
835         const uint8_t *idata = input->data;
836         uint8_t *odata;
837         unsigned int stride = output->width * 3;
838         unsigned int x, y;
839
840         odata = output->data + stride - 3;
841
842         for (y = 0; y < input->height; ++y) {
843                 for (x = 0; x < input->width; ++x) {
844                         odata[x*stride+0] = *idata++;
845                         odata[x*stride+1] = *idata++;
846                         odata[x*stride+2] = *idata++;
847                 }
848
849                 odata -= 3;
850         }
851 }
852
853 static void image_flip(const struct image *input, struct image *output,
854                        bool hflip, bool vflip)
855 {
856         const uint8_t *idata = input->data;
857         uint8_t *odata = output->data;
858         unsigned int stride = output->width * 3;
859         unsigned int x, y;
860         int x_step, y_step;
861
862         if (!hflip) {
863                 x_step = 3;
864                 y_step = !vflip ? 0 : -2 * stride;
865                 odata += !vflip ? 0 : stride * (output->height - 1);
866         } else {
867                 x_step = -3;
868                 y_step = !vflip ? 2 * stride : 0;
869                 odata += !vflip ? stride - 3 : stride * output->height - 3;
870         }
871
872         for (y = 0; y < output->height; ++y) {
873                 for (x = 0; x < output->width; ++x) {
874                         odata[0] = *idata++;
875                         odata[1] = *idata++;
876                         odata[2] = *idata++;
877
878                         odata += x_step;
879                 }
880
881                 odata += y_step;
882         }
883 }
884
885 /* -----------------------------------------------------------------------------
886  * Look Up Table
887  */
888
889 static int image_lut_1d(const struct image *input, struct image *output,
890                         const char *filename)
891 {
892         const uint8_t *idata = input->data;
893         uint8_t *odata = output->data;
894         unsigned int comp_map[3];
895         uint8_t c0, c1, c2;
896         unsigned int x, y;
897         uint8_t lut[1024];
898         int ret;
899         int fd;
900
901         fd = open(filename, O_RDONLY);
902         if (fd < 0) {
903                 printf("Unable to open LUT file %s: %s (%d)\n", filename,
904                        strerror(errno), errno);
905                 return -errno;
906         }
907
908         ret = file_read(fd, lut, sizeof(lut));
909         close(fd);
910         if (ret < 0) {
911                 printf("Unable to read 1D LUT file: %s (%d)\n", strerror(-ret),
912                        ret);
913                 return ret;
914         }
915         if ((size_t)ret != sizeof(lut)) {
916                 printf("Invalid 1D LUT file: file too short\n");
917                 return -ENODATA;
918         }
919
920         if (input->format->is_yuv)
921                 memcpy(comp_map, (unsigned int[3]){ 1, 0, 2 },
922                        sizeof(comp_map));
923         else
924                 memcpy(comp_map, (unsigned int[3]){ 2, 1, 0 },
925                        sizeof(comp_map));
926
927         for (y = 0; y < input->height; ++y) {
928                 for (x = 0; x < input->width; ++x) {
929                         c0 = *idata++;
930                         c1 = *idata++;
931                         c2 = *idata++;
932
933                         *odata++ = lut[c0*4 + comp_map[0]];
934                         *odata++ = lut[c1*4 + comp_map[1]];
935                         *odata++ = lut[c2*4 + comp_map[2]];
936                 }
937         }
938
939         return 0;
940 }
941
942 static int image_lut_3d(const struct image *input, struct image *output,
943                         const char *filename)
944 {
945         const uint8_t *idata = input->data;
946         uint8_t *odata = output->data;
947         unsigned int comp_map[3];
948         unsigned int x, y;
949         uint32_t lut[17*17*17];
950         int ret;
951         int fd;
952
953         fd = open(filename, O_RDONLY);
954         if (fd < 0) {
955                 printf("Unable to open 3D LUT file %s: %s (%d)\n", filename,
956                        strerror(errno), errno);
957                 return -errno;
958         }
959
960         ret = file_read(fd, lut, sizeof(lut));
961         close(fd);
962         if (ret < 0) {
963                 printf("Unable to read 3D LUT file: %s (%d)\n", strerror(-ret),
964                        ret);
965                 return ret;
966         }
967         if ((size_t)ret != sizeof(lut)) {
968                 printf("Invalid 3D LUT file: file too short\n");
969                 return -ENODATA;
970         }
971
972         if (input->format->is_yuv)
973                 memcpy(comp_map, (unsigned int[3]){ 2, 0, 1 },
974                        sizeof(comp_map));
975         else
976                 memcpy(comp_map, (unsigned int[3]){ 0, 1, 2 },
977                        sizeof(comp_map));
978
979         for (y = 0; y < input->height; ++y) {
980                 for (x = 0; x < input->width; ++x) {
981                         double a1_ratio, a2_ratio, a3_ratio;
982                         unsigned int a1, a2, a3;
983                         double c0, c1, c2;
984                         uint8_t c[3];
985
986                         c[0] = idata[comp_map[0]];
987                         c[1] = idata[comp_map[1]];
988                         c[2] = idata[comp_map[2]];
989
990                         a1 = c[0] >> 4;
991                         a2 = c[1] >> 4;
992                         a3 = c[2] >> 4;
993
994                         /*
995                          * Implement the hardware MVS (Max Value Stretch)
996                          * behaviour: move the point by one step towards the
997                          * upper limit of the grid if we're closer than 0.5 to
998                          * that limit.
999                          */
1000                         a1_ratio = ((c[0] & 0xf) + (c[0] >= 0xf8 ? 1 : 0)) / 16.;
1001                         a2_ratio = ((c[1] & 0xf) + (c[1] >= 0xf8 ? 1 : 0)) / 16.;
1002                         a3_ratio = ((c[2] & 0xf) + (c[2] >= 0xf8 ? 1 : 0)) / 16.;
1003
1004 #define _LUT(a1, a2, a3, offset)        ((lut[(a1)+(a2)*17+(a3)*17*17] >> (offset)) & 0xff)
1005                         c0 = _LUT(a1,   a2,   a3,   16) * (1 - a1_ratio) * (1 - a2_ratio) * (1 - a3_ratio)
1006                            + _LUT(a1,   a2,   a3+1, 16) * (1 - a1_ratio) * (1 - a2_ratio) * a3_ratio
1007                            + _LUT(a1,   a2+1, a3,   16) * (1 - a1_ratio) * a2_ratio       * (1 - a3_ratio)
1008                            + _LUT(a1,   a2+1, a3+1, 16) * (1 - a1_ratio) * a2_ratio       * a3_ratio
1009                            + _LUT(a1+1, a2,   a3,   16) * a1_ratio       * (1 - a2_ratio) * (1 - a3_ratio)
1010                            + _LUT(a1+1, a2,   a3+1, 16) * a1_ratio       * (1 - a2_ratio) * a3_ratio
1011                            + _LUT(a1+1, a2+1, a3,   16) * a1_ratio       * a2_ratio       * (1 - a3_ratio)
1012                            + _LUT(a1+1, a2+1, a3+1, 16) * a1_ratio       * a2_ratio       * a3_ratio;
1013                         c1 = _LUT(a1,   a2,   a3,    8) * (1 - a1_ratio) * (1 - a2_ratio) * (1 - a3_ratio)
1014                            + _LUT(a1,   a2,   a3+1,  8) * (1 - a1_ratio) * (1 - a2_ratio) * a3_ratio
1015                            + _LUT(a1,   a2+1, a3,    8) * (1 - a1_ratio) * a2_ratio       * (1 - a3_ratio)
1016                            + _LUT(a1,   a2+1, a3+1,  8) * (1 - a1_ratio) * a2_ratio       * a3_ratio
1017                            + _LUT(a1+1, a2,   a3,    8) * a1_ratio       * (1 - a2_ratio) * (1 - a3_ratio)
1018                            + _LUT(a1+1, a2,   a3+1,  8) * a1_ratio       * (1 - a2_ratio) * a3_ratio
1019                            + _LUT(a1+1, a2+1, a3,    8) * a1_ratio       * a2_ratio       * (1 - a3_ratio)
1020                            + _LUT(a1+1, a2+1, a3+1,  8) * a1_ratio       * a2_ratio       * a3_ratio;
1021                         c2 = _LUT(a1,   a2,   a3,    0) * (1 - a1_ratio) * (1 - a2_ratio) * (1 - a3_ratio)
1022                            + _LUT(a1,   a2,   a3+1,  0) * (1 - a1_ratio) * (1 - a2_ratio) * a3_ratio
1023                            + _LUT(a1,   a2+1, a3,    0) * (1 - a1_ratio) * a2_ratio       * (1 - a3_ratio)
1024                            + _LUT(a1,   a2+1, a3+1,  0) * (1 - a1_ratio) * a2_ratio       * a3_ratio
1025                            + _LUT(a1+1, a2,   a3,    0) * a1_ratio       * (1 - a2_ratio) * (1 - a3_ratio)
1026                            + _LUT(a1+1, a2,   a3+1,  0) * a1_ratio       * (1 - a2_ratio) * a3_ratio
1027                            + _LUT(a1+1, a2+1, a3,    0) * a1_ratio       * a2_ratio       * (1 - a3_ratio)
1028                            + _LUT(a1+1, a2+1, a3+1,  0) * a1_ratio       * a2_ratio       * a3_ratio;
1029 #undef _LUT
1030
1031                         odata[comp_map[0]] = round(c0);
1032                         odata[comp_map[1]] = round(c1);
1033                         odata[comp_map[2]] = round(c2);
1034
1035                         idata += 3;
1036                         odata += 3;
1037                 }
1038         }
1039
1040         return 0;
1041 }
1042
1043 /* -----------------------------------------------------------------------------
1044  * Histogram
1045  */
1046
1047 static void histogram_compute(const struct image *image, void *histo)
1048 {
1049         const uint8_t *data = image->data;
1050         uint8_t comp_min[3] = { 255, 255, 255 };
1051         uint8_t comp_max[3] = { 0, 0, 0 };
1052         uint32_t comp_sums[3] = { 0, 0, 0 };
1053         uint32_t comp_bins[3][64];
1054         unsigned int comp_map[3];
1055         unsigned int x, y;
1056         unsigned int i, j;
1057
1058         if (image->format->is_yuv)
1059                 memcpy(comp_map, (unsigned int[3]){ 2, 0, 1 }, sizeof(comp_map));
1060         else
1061                 memcpy(comp_map, (unsigned int[3]){ 0, 1, 2 }, sizeof(comp_map));
1062
1063         memset(comp_bins, 0, sizeof(comp_bins));
1064
1065         for (y = 0; y < image->height; ++y) {
1066                 for (x = 0; x < image->width; ++x) {
1067                         for (i = 0; i < 3; ++i) {
1068                                 comp_min[i] = min(*data, comp_min[i]);
1069                                 comp_max[i] = max(*data, comp_max[i]);
1070                                 comp_sums[i] += *data;
1071                                 comp_bins[i][*data >> 2]++;
1072                                 data++;
1073                         }
1074                 }
1075         }
1076
1077         for (i = 0; i < ARRAY_SIZE(comp_min); ++i) {
1078                 *(uint8_t *)histo++ = comp_min[comp_map[i]];
1079                 *(uint8_t *)histo++ = 0;
1080                 *(uint8_t *)histo++ = comp_max[comp_map[i]];
1081                 *(uint8_t *)histo++ = 0;
1082         }
1083
1084         for (i = 0; i < ARRAY_SIZE(comp_sums); ++i) {
1085                 *(uint32_t *)histo = comp_sums[comp_map[i]];
1086                 histo += 4;
1087         }
1088
1089         for (i = 0; i < ARRAY_SIZE(comp_bins); ++i) {
1090                 for (j = 0; j < ARRAY_SIZE(comp_bins[i]); ++j) {
1091                         *(uint32_t *)histo = comp_bins[comp_map[i]][j];
1092                         histo += 4;
1093                 }
1094         }
1095 }
1096
1097 static int histogram(const struct image *image, const char *filename)
1098 {
1099         uint8_t data[3*4 + 3*4 + 3*64*4];
1100         int ret;
1101         int fd;
1102
1103         histogram_compute(image, data);
1104
1105         fd = open(filename, O_WRONLY | O_CREAT,
1106                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
1107         if (fd < 0) {
1108                 printf("Unable to open histogram file %s: %s (%d)\n", filename,
1109                        strerror(errno), errno);
1110                 return -errno;
1111         }
1112
1113         ret = file_write(fd, data, sizeof(data));
1114         if (ret < 0)
1115                 printf("Unable to write histogram: %s (%d)\n",
1116                        strerror(-ret), ret);
1117         else
1118                 ftruncate(fd, sizeof(data));
1119
1120         close(fd);
1121         return ret;
1122 }
1123
1124 /* -----------------------------------------------------------------------------
1125  * Processing pipeline
1126  */
1127
1128 static int process(const struct options *options)
1129 {
1130         struct image *input = NULL;
1131         struct image *output = NULL;
1132         unsigned int output_width;
1133         unsigned int output_height;
1134         int ret = 0;
1135
1136         /* Read the input image */
1137         input = image_read(options->input_filename);
1138         if (!input) {
1139                 ret = -EINVAL;
1140                 goto done;
1141         }
1142
1143         /* Convert colorspace */
1144         if (options->input_format->is_yuv) {
1145                 struct image *yuv;
1146
1147                 yuv = image_new(format_by_name("YUV24"), input->width,
1148                                 input->height);
1149                 if (!yuv) {
1150                         ret = -ENOMEM;
1151                         goto done;
1152                 }
1153
1154                 image_colorspace_rgb_to_yuv(input, yuv, &options->params);
1155                 image_delete(input);
1156                 input = yuv;
1157         } else if (options->input_format->rgb.bpp < 24) {
1158                 struct image *rgb;
1159
1160                 rgb = image_new(format_by_name("RGB24"), input->width,
1161                                 input->height);
1162                 if (!rgb) {
1163                         ret = -ENOMEM;
1164                         goto done;
1165                 }
1166
1167                 image_convert_rgb_to_rgb(input, rgb, options->input_format);
1168                 image_delete(input);
1169                 input = rgb;
1170         }
1171
1172         /* Scale */
1173         if (options->output_width && options->output_height) {
1174                 output_width = options->output_width;
1175                 output_height = options->output_height;
1176         } else {
1177                 output_width = input->width;
1178                 output_height = input->height;
1179         }
1180
1181         if (options->rotate)
1182                 swap(output_width, output_height);
1183
1184         if (input->width != output_width ||
1185             input->height != output_height) {
1186                 struct image *scaled;
1187
1188                 scaled = image_new(input->format, output_width, output_height);
1189                 if (!scaled) {
1190                         ret = -ENOMEM;
1191                         goto done;
1192                 }
1193
1194                 image_scale(input, scaled, &options->params);
1195                 image_delete(input);
1196                 input = scaled;
1197         }
1198
1199         /* Compose */
1200         if (options->compose) {
1201                 struct image *composed;
1202
1203                 composed = image_new(input->format, input->width, input->height);
1204                 if (!composed) {
1205                         ret = -ENOMEM;
1206                         goto done;
1207                 }
1208
1209                 image_compose(input, composed, options->compose);
1210                 image_delete(input);
1211                 input = composed;
1212         }
1213
1214         /* Look-up tables */
1215         if (options->lut_filename) {
1216                 struct image *lut;
1217
1218                 lut = image_new(input->format, input->width, input->height);
1219                 if (!lut) {
1220                         ret = -ENOMEM;
1221                         goto done;
1222                 }
1223
1224                 image_lut_1d(input, lut, options->lut_filename);
1225                 image_delete(input);
1226                 input = lut;
1227         }
1228
1229         if (options->clu_filename) {
1230                 struct image *clu;
1231
1232                 clu = image_new(input->format, input->width, input->height);
1233                 if (!clu) {
1234                         ret = -ENOMEM;
1235                         goto done;
1236                 }
1237
1238                 image_lut_3d(input, clu, options->clu_filename);
1239                 image_delete(input);
1240                 input = clu;
1241         }
1242
1243         /* Compute the histogram */
1244         if (options->histo_filename) {
1245                 ret = histogram(input, options->histo_filename);
1246                 if (ret)
1247                         goto done;
1248         }
1249
1250         /* Rotation and flipping */
1251         if (options->rotate) {
1252                 struct image *rotated;
1253
1254                 rotated = image_new(input->format, input->height, input->width);
1255                 if (!rotated) {
1256                         ret = -ENOMEM;
1257                         goto done;
1258                 }
1259
1260                 image_rotate(input, rotated);
1261                 image_delete(input);
1262                 input = rotated;
1263         }
1264
1265         if (options->hflip || options->vflip) {
1266                 struct image *flipped;
1267
1268                 flipped = image_new(input->format, input->width, input->height);
1269                 if (!flipped) {
1270                         ret = -ENOMEM;
1271                         goto done;
1272                 }
1273
1274                 image_flip(input, flipped, options->hflip, options->vflip);
1275                 image_delete(input);
1276                 input = flipped;
1277         }
1278
1279         /* Format the output */
1280         if (input->format->is_yuv && !options->output_format->is_yuv) {
1281                 printf("RGB output with YUV processing not supported\n");
1282                 ret = -EINVAL;
1283                 goto done;
1284         }
1285
1286         if (!input->format->is_yuv && options->output_format->is_yuv) {
1287                 const struct format_info *format = format_by_name("YUV24");
1288                 struct image *converted;
1289
1290                 converted = image_new(format, input->width, input->height);
1291                 if (!converted) {
1292                         ret = -ENOMEM;
1293                         goto done;
1294                 }
1295
1296                 image_colorspace_rgb_to_yuv(input, converted, &options->params);
1297                 image_delete(input);
1298                 input = converted;
1299         }
1300
1301         output = image_new(options->output_format, input->width, input->height);
1302         if (!output) {
1303                 ret = -ENOMEM;
1304                 goto done;
1305         }
1306
1307         if (output->format->is_yuv) {
1308                 switch (output->format->yuv.num_planes) {
1309                 case 1:
1310                         image_format_yuv_packed(input, output, &options->params);
1311                         break;
1312                 case 2:
1313                 case 3:
1314                         image_format_yuv_planar(input, output, &options->params);
1315                         break;
1316                 default:
1317                         ret = -EINVAL;
1318                         break;
1319                 }
1320         } else {
1321                 switch (output->format->rgb.bpp) {
1322                 case 8:
1323                         image_format_rgb8(input, output, &options->params);
1324                         break;
1325                 case 16:
1326                         image_format_rgb16(input, output, &options->params);
1327                         break;
1328                 case 24:
1329                         image_format_rgb24(input, output, &options->params);
1330                         break;
1331                 case 32:
1332                         image_format_rgb32(input, output, &options->params);
1333                         break;
1334                 default:
1335                         ret = -EINVAL;
1336                         break;
1337                 }
1338         }
1339
1340         if (ret < 0) {
1341                 printf("Output formatting failed\n");
1342                 goto done;
1343         }
1344
1345         /* Write the output image */
1346         if (options->output_filename) {
1347                 ret = image_write(output, options->output_filename);
1348                 if (ret)
1349                         goto done;
1350         }
1351
1352         ret = 0;
1353
1354 done:
1355         image_delete(input);
1356         image_delete(output);
1357         return ret;
1358 }
1359
1360 /* -----------------------------------------------------------------------------
1361  * Usage, argument parsing and main
1362  */
1363
1364 static void usage(const char *argv0)
1365 {
1366         printf("Usage: %s [options] <infile.pnm>\n\n", argv0);
1367         printf("Convert the input image stored in <infile> in PNM format to\n");
1368         printf("the target format and resolution and store the resulting\n");
1369         printf("image in raw binary form\n\n");
1370         printf("Supported options:\n");
1371         printf("-a, --alpha value       Set the alpha value. Valid syntaxes are floating\n");
1372         printf("                        point values ([0.0 - 1.0]), fixed point values ([0-255])\n");
1373         printf("                        or percentages ([0%% - 100%%]). Defaults to 1.0\n");
1374         printf("-c, --compose n         Compose n copies of the image offset by (50,50) over a black background\n");
1375         printf("-e, --encoding enc      Set the YCbCr encoding method. Valid values are\n");
1376         printf("                        BT.601, REC.709, BT.2020 and SMPTE240M\n");
1377         printf("-f, --format format     Set the output image format\n");
1378         printf("                        Defaults to RGB24 if not specified\n");
1379         printf("                        Use -f help to list the supported formats\n");
1380         printf("-h, --help              Show this help screen\n");
1381         printf("    --hflip             Flip the image horizontally\n");
1382         printf("-H, --histogram file    Compute histogram on the output image and store it to file\n");
1383         printf("-i, --in-format format  Set the input image format\n");
1384         printf("                        Defaults to RGB24 if not specified\n");
1385         printf("                        Use -i help to list the supported formats\n");
1386         printf("-l, --lut file          Apply 1D Look Up Table from file\n");
1387         printf("-L, --clu file          Apply 3D Look Up Table from file\n");
1388         printf("-o, --output file       Store the output image to file\n");
1389         printf("-q, --quantization q    Set the quantization method. Valid values are\n");
1390         printf("                        limited or full\n");
1391         printf("-r, --rotate            Rotate the image clockwise by 90°\n");
1392         printf("-s, --size WxH          Set the output image size\n");
1393         printf("                        Defaults to the input size if not specified\n");
1394         printf("    --vflip             Flip the image vertically\n");
1395 }
1396
1397 static void list_formats(void)
1398 {
1399         unsigned int i;
1400
1401         for (i = 0; i < ARRAY_SIZE(format_info); i++)
1402                 printf("%s\n", format_info[i].name);
1403 }
1404
1405 #define OPT_HFLIP       256
1406 #define OPT_VFLIP       257
1407
1408 static struct option opts[] = {
1409         {"alpha", 1, 0, 'a'},
1410         {"clu", 1, 0, 'L'},
1411         {"compose", 1, 0, 'c'},
1412         {"encoding", 1, 0, 'e'},
1413         {"format", 1, 0, 'f'},
1414         {"help", 0, 0, 'h'},
1415         {"hflip", 0, 0, OPT_HFLIP},
1416         {"histogram", 1, 0, 'H'},
1417         {"in-format", 1, 0, 'i'},
1418         {"lut", 1, 0, 'l'},
1419         {"output", 1, 0, 'o'},
1420         {"quantization", 1, 0, 'q'},
1421         {"rotate", 0, 0, 'r'},
1422         {"size", 1, 0, 's'},
1423         {"vflip", 0, 0, OPT_VFLIP},
1424         {0, 0, 0, 0}
1425 };
1426
1427 static int parse_args(struct options *options, int argc, char *argv[])
1428 {
1429         char *endptr;
1430         int c;
1431
1432         if (argc < 3) {
1433                 usage(argv[0]);
1434                 return 1;
1435         }
1436
1437         memset(options, 0, sizeof(*options));
1438         options->input_format = format_by_name("RGB24");
1439         options->output_format = format_by_name("RGB24");
1440         options->params.alpha = 255;
1441         options->params.encoding = V4L2_YCBCR_ENC_601;
1442         options->params.quantization = V4L2_QUANTIZATION_LIM_RANGE;
1443
1444         opterr = 0;
1445         while ((c = getopt_long(argc, argv, "a:c:e:f:hH:i:l:L:o:q:rs:", opts, NULL)) != -1) {
1446
1447                 switch (c) {
1448                 case 'a': {
1449                         int alpha;
1450
1451                         if (strchr(optarg, '.')) {
1452                                 alpha = strtod(optarg, &endptr) * 255;
1453                                 if (*endptr != 0)
1454                                         alpha = -1;
1455                         } else {
1456                                 alpha = strtoul(optarg, &endptr, 10);
1457                                 if (*endptr == '%')
1458                                         alpha = alpha * 255 / 100;
1459                                 else if (*endptr != 0)
1460                                         alpha = -1;
1461                         }
1462
1463                         if (alpha < 0 || alpha > 255) {
1464                                 printf("Invalid alpha value '%s'\n", optarg);
1465                                 return 1;
1466                         }
1467
1468                         options->params.alpha = alpha;
1469                         break;
1470                 }
1471
1472                 case 'c':
1473                           options->compose = strtoul(optarg, &endptr, 10);
1474                           if (*endptr != 0) {
1475                                 printf("Invalid compose value '%s'\n", optarg);
1476                                 return 1;
1477                           }
1478                           break;
1479
1480                 case 'e':
1481                         if (!strcmp(optarg, "BT.601")) {
1482                                 options->params.encoding = V4L2_YCBCR_ENC_601;
1483                         } else if (!strcmp(optarg, "REC.709")) {
1484                                 options->params.encoding = V4L2_YCBCR_ENC_709;
1485                         } else if (!strcmp(optarg, "BT.2020")) {
1486                                 options->params.encoding = V4L2_YCBCR_ENC_BT2020;
1487                         } else if (!strcmp(optarg, "SMPTE240M")) {
1488                                 options->params.encoding = V4L2_YCBCR_ENC_SMPTE240M;
1489                         } else {
1490                                 printf("Invalid encoding value '%s'\n", optarg);
1491                                 return 1;
1492                         }
1493                         break;
1494
1495                 case 'f':
1496                         if (!strcmp("help", optarg)) {
1497                                 list_formats();
1498                                 return 1;
1499                         }
1500
1501                         options->output_format = format_by_name(optarg);
1502                         if (!options->output_format) {
1503                                 printf("Unsupported output format '%s'\n", optarg);
1504                                 return 1;
1505                         }
1506
1507                         break;
1508
1509                 case 'h':
1510                         usage(argv[0]);
1511                         exit(0);
1512                         break;
1513
1514                 case 'H':
1515                         options->histo_filename = optarg;
1516                         break;
1517
1518                 case 'i':
1519                         if (!strcmp("help", optarg)) {
1520                                 list_formats();
1521                                 return 1;
1522                         }
1523
1524                         options->input_format = format_by_name(optarg);
1525                         if (!options->input_format) {
1526                                 printf("Unsupported input format '%s'\n", optarg);
1527                                 return 1;
1528                         }
1529
1530                         break;
1531
1532                 case 'l':
1533                         options->lut_filename = optarg;
1534                         break;
1535
1536                 case 'L':
1537                         options->clu_filename = optarg;
1538                         break;
1539
1540                 case 'o':
1541                         options->output_filename = optarg;
1542                         break;
1543
1544                 case 'q':
1545                         if (!strcmp(optarg, "limited")) {
1546                                 options->params.quantization = V4L2_QUANTIZATION_LIM_RANGE;
1547                         } else if (!strcmp(optarg, "full")) {
1548                                 options->params.quantization = V4L2_QUANTIZATION_FULL_RANGE;
1549                         } else {
1550                                 printf("Invalid quantization value '%s'\n", optarg);
1551                                 return 1;
1552                         }
1553                         break;
1554
1555                         break;
1556
1557                 case 'r':
1558                         options->rotate = true;
1559                         break;
1560
1561                 case 's':
1562                         options->output_width = strtol(optarg, &endptr, 10);
1563                         if (*endptr != 'x' || endptr == optarg) {
1564                                 printf("Invalid size '%s'\n", optarg);
1565                                 return 1;
1566                         }
1567
1568                         options->output_height = strtol(endptr + 1, &endptr, 10);
1569                         if (*endptr != 0) {
1570                                 printf("Invalid size '%s'\n", optarg);
1571                                 return 1;
1572                         }
1573                         break;
1574
1575                 case OPT_HFLIP:
1576                         options->hflip = true;
1577                         break;
1578
1579                 case OPT_VFLIP:
1580                         options->vflip = true;
1581                         break;
1582
1583                 default:
1584                         printf("Invalid option -%c\n", c);
1585                         printf("Run %s -h for help.\n", argv[0]);
1586                         return 1;
1587                 }
1588         }
1589
1590         if (optind != argc - 1) {
1591                 usage(argv[0]);
1592                 return 1;
1593         }
1594
1595         options->input_filename = argv[optind];
1596
1597         return 0;
1598 }
1599
1600 int main(int argc, char *argv[])
1601 {
1602         struct options options;
1603         int ret;
1604
1605         ret = parse_args(&options, argc, argv);
1606         if (ret)
1607                 return ret;
1608
1609         ret = process(&options);
1610         if (ret)
1611                 return 1;
1612
1613         return 0;
1614 }