blind-spatial-mean.c - blind - suckless command-line video editing utility
 (HTM) git clone git://git.suckless.org/blind
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       blind-spatial-mean.c (4867B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include "common.h"
            3 
            4 USAGE("[-d | -g | -h | -l power-stream | -p power-stream | -v]")
            5 /* TODO add [-w weight-stream] for [-ghlpv] */
            6 
            7 /* Because the syntax for a function returning a function pointer is disgusting. */
            8 typedef void (*process_func)(struct stream *stream);
            9 
           10 #define C (j & 3)
           11 /*
           12  * X-parameter 1: method enum value
           13  * X-parameter 2: identifier-friendly name
           14  * X-parameter 3: initial assignments
           15  * X-parameter 4: initial value
           16  * X-parameter 5: subcell processing
           17  * X-parameter 6: subcell finalisation
           18  */
           19 #define LIST_MEANS(TYPE)\
           20         /* [default] arithmetic mean */\
           21         X(ARITHMETIC, arithmetic,, 0, img[C] += *buf, img[C] /= pixels)\
           22         /* standard deviation */\
           23         X(STANDARD_DEVIATION, sd,, 0, (img[C] += *buf * *buf, aux[C] += *buf),\
           24           img[C] = nnpow((img[C] - aux[C] * aux[C] / pixels) / pixels, (TYPE)0.5)) \
           25         /* geometric mean */\
           26         X(GEOMETRIC, geometric,, 1, img[C] *= *buf, img[C] = nnpow(img[C], 1 / pixels))\
           27         /* harmonic mean */\
           28         X(HARMONIC, harmonic,, 0, img[C] += (TYPE)1 / *buf, img[C] = pixels / img[C])\
           29         /* Lehmer mean */\
           30         X(LEHMER, lehmer, (a[0] = powers[0] - (TYPE)1, a[1] = powers[1] - (TYPE)1,\
           31                            a[2] = powers[2] - (TYPE)1, a[3] = powers[3] - (TYPE)1), 0,\
           32           (img[C] += nnpow(*buf, powers[C]), aux[C] += nnpow(*buf, a[C])), img[C] /= aux[C])\
           33         /* power mean (Hölder mean) (m = 2 for root square mean; m = 3 for cubic mean) */\
           34         X(POWER, power,, 0, img[C] += nnpow(*buf, powers[C]),\
           35           img[C] = nnpow(img[C], (TYPE)1 / powers[C]) / pixels)\
           36         /* variance */\
           37         X(VARIANCE, variance,, 0, (img[C] += *buf * *buf, aux[C] += *buf),\
           38           img[C] = (img[C] - aux[C] * aux[C] / pixels) / pixels)
           39 
           40 #define X(V, ...) V,
           41 enum method { LIST_MEANS() };
           42 #undef X
           43 
           44 static struct stream power;
           45 static const char *power_file = NULL;
           46 
           47 #define MAKE_PROCESS(PIXFMT, TYPE,\
           48                      _1, NAME, INIT, INITIAL, PROCESS_SUBCELL, FINALISE_SUBCELL)\
           49         static void\
           50         process_##PIXFMT##_##NAME(struct stream *stream)\
           51         {\
           52                 TYPE img[4], aux[4], *buf, a[4], powers[4];\
           53                 TYPE pixels = (TYPE)(stream->frame_size / sizeof(img));\
           54                 size_t i, n, j = 0, m = stream->frame_size / sizeof(*img);\
           55                 int first = 1;\
           56                 do {\
           57                         n = stream->ptr / stream->pixel_size * stream->n_chan;\
           58                         buf = (TYPE *)(stream->buf);\
           59                         for (i = 0; i < n; i++, buf++, j++, j %= m) {\
           60                                 if (!j) {\
           61                                         if (!first) {\
           62                                                 for (j = 0; j < ELEMENTSOF(img); j++)\
           63                                                         FINALISE_SUBCELL;\
           64                                                 j = 0;\
           65                                                 ewriteall(STDOUT_FILENO, img, sizeof(img), "<stdout>");\
           66                                         }\
           67                                         first = 0;\
           68                                         if (power_file && !eread_frame(&power, powers))\
           69                                                 return;\
           70                                         INIT;\
           71                                         img[0] = aux[0] = INITIAL;\
           72                                         img[1] = aux[1] = INITIAL;\
           73                                         img[2] = aux[2] = INITIAL;\
           74                                         img[3] = aux[3] = INITIAL;\
           75                                 }\
           76                                 PROCESS_SUBCELL;\
           77                         }\
           78                         n *= sizeof(TYPE);\
           79                         memmove(stream->buf, stream->buf + n, stream->ptr -= n);\
           80                 } while (eread_stream(stream, SIZE_MAX));\
           81                 if (!first) {\
           82                         for (j = 0; j < ELEMENTSOF(img); j++)\
           83                                 FINALISE_SUBCELL;\
           84                         ewriteall(STDOUT_FILENO, img, sizeof(img), "<stdout>");\
           85                 }\
           86                 (void) aux, (void) a, (void) powers, (void) pixels;\
           87         }
           88 #define X(...) MAKE_PROCESS(lf, double, __VA_ARGS__)
           89 LIST_MEANS(double)
           90 #undef X
           91 #define X(...) MAKE_PROCESS(f, float, __VA_ARGS__)
           92 LIST_MEANS(float)
           93 #undef X
           94 #undef MAKE_PROCESS
           95 #undef C
           96 
           97 #define X(ID, NAME, ...) [ID] = process_lf_##NAME,
           98 static const process_func process_functions_lf[] = { LIST_MEANS() };
           99 #undef X
          100 
          101 #define X(ID, NAME, ...) [ID] = process_f_##NAME,
          102 static const process_func process_functions_f[] = { LIST_MEANS() };
          103 #undef X
          104 
          105 int
          106 main(int argc, char *argv[])
          107 {
          108         struct stream stream;
          109         process_func process;
          110         enum method method = ARITHMETIC;
          111 
          112         ARGBEGIN {
          113         case 'd':
          114                 method = STANDARD_DEVIATION;
          115                 break;
          116         case 'g':
          117                 method = GEOMETRIC;
          118                 break;
          119         case 'h':
          120                 method = HARMONIC;
          121                 break;
          122         case 'l':
          123                 method = LEHMER;
          124                 power_file = UARGF();
          125                 break;
          126         case 'p':
          127                 method = POWER;
          128                 power_file = UARGF();
          129                 break;
          130         case 'v':
          131                 method = VARIANCE;
          132                 break;
          133         default:
          134                 usage();
          135         } ARGEND;
          136 
          137         if (argc)
          138                 usage();
          139 
          140         eopen_stream(&stream, NULL);
          141         if (power_file != NULL) {
          142                 eopen_stream(&power, power_file);
          143                 if (power.width != 1 || power.height != 1)
          144                         eprintf("%s: videos do not have the 1x1 geometry\n", power_file);
          145                 if (strcmp(power.pixfmt, stream.pixfmt))
          146                         eprintf("videos use incompatible pixel formats\n");
          147         }
          148 
          149         CHECK_N_CHAN(&stream, 4, 4);
          150         if (stream.encoding == DOUBLE)
          151                 process = process_functions_lf[method];
          152         else if (stream.encoding == FLOAT)
          153                 process = process_functions_f[method];
          154         else
          155                 eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt);
          156 
          157         if (DPRINTF_HEAD(STDOUT_FILENO, stream.frames, 1, 1, stream.pixfmt) < 0)
          158                 eprintf("dprintf:");
          159         process(&stream);
          160         if (stream.ptr)
          161                 eprintf("%s: incomplete frame\n", stream.file);
          162         return 0;
          163 }