blind-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-mean.c (5615B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include "common.h"
            3 
            4 USAGE("[-d | -g | -h | -H | -i | -l power-stream | -L | -p power-stream | -s power-stream | -v | -z power] stream-1 stream-2 ...")
            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 *streams, size_t n_streams, size_t n);
            9 
           10 /*
           11  * X-parameter 1: method enum value
           12  * X-parameter 2: identifier-friendly name
           13  * X-parameter 3: initial assignments
           14  * X-parameter 4: initial value
           15  * X-parameter 5: subcell processing
           16  * X-parameter 6: subcell finalisation
           17  */
           18 #define LIST_MEANS(TYPE)\
           19         /* [default] arithmetic mean */\
           20         X(ARITHMETIC, arithmetic, sn = (TYPE)1 / sn, 0, img += val, img *= sn) \
           21         /* standard deviation */\
           22         X(STANDARD_DEVIATION, sd, sn = (TYPE)1 / sn, 0, (img += val * val, aux += val),\
           23           img = nnpow((img - aux * aux * sn) * sn, (TYPE)0.5))\
           24         /* geometric mean */\
           25         X(GEOMETRIC, geometric, sn = (TYPE)1 / sn, 1, img *= val, img = nnpow(img, sn))\
           26         /* harmonic mean */\
           27         X(HARMONIC, harmonic,, 0, img += (TYPE)1 / val, img = sn / img)\
           28         /* Heronian mean */\
           29         X(HERONIAN, heronian,, 0, auxs[j] = val,\
           30           img = (auxs[0] + sqrt(auxs[0] * auxs[1]) + auxs[1]) / (TYPE)3)\
           31         /* identric mean */\
           32         X(IDENTRIC, identric, a = (TYPE)(1. / M_E), 0, auxs[j] = val,\
           33           img = auxs[0] == auxs[1] ? auxs[0] :\
           34                 nnpow(nnpow(auxs[0], auxs[0]) / nnpow(auxs[1], auxs[1]), auxs[0] - auxs[1]) * a)\
           35         /* Lehmer mean */\
           36         X(LEHMER, lehmer,, 0, (img += nnpow(val, *pows), aux += nnpow(val, *pows - (TYPE)1)), img /= aux)\
           37         /* logarithmic mean */\
           38         X(LOGARITHMIC, logarithmic,, 0, auxs[j] = val,\
           39           img = auxs[0] == auxs[1] ? auxs[0] : (!auxs[0] || !auxs[1]) ? (TYPE)0 :\
           40                 (auxs[1] - auxs[0]) / log(auxs[1] / auxs[0]))\
           41         /* power mean (Hölder mean) (m = 2 for root square mean; m = 3 for cubic mean) */\
           42         X(POWER, power, sn = (TYPE)1 / sn, 0,\
           43           img += nnpow(val, *pows), img = nnpow(img, (TYPE)1 / *pows) * sn)\
           44         /* Stolarsky mean */\
           45         X(STOLARSKY, stolarsky,, 0, auxs[j] = val,\
           46           img = auxs[0] == auxs[1] ? auxs[0] :\
           47                 nnpow((nnpow(auxs[0], *pows) - nnpow(auxs[1], *pows)) /\
           48                       (*pows * (auxs[0] - auxs[1])), (TYPE)1 / (*pows - (TYPE)1)))\
           49         /* variance */\
           50         X(VARIANCE, variance, sn = (TYPE)1 / sn, 0, (img += val * val, aux += val),\
           51           img = (img - aux * aux * sn) * sn)\
           52         /* Heinz mean */\
           53         X(HEINZ, heinz,, 0, auxs[j] = val,\
           54           img = (nnpow(auxs[0], *pows) * nnpow(auxs[1], (TYPE)1 - *pows) +\
           55                  nnpow(auxs[0], (TYPE)1 - *pows) * nnpow(auxs[1], *pows)) / (TYPE)2)
           56 
           57 #define X(V, ...) V,
           58 enum method { LIST_MEANS() };
           59 #undef X
           60 
           61 static const char *power_file = NULL;
           62 
           63 #define aux (*auxs)
           64 #define MAKE_PROCESS(PIXFMT, TYPE,\
           65           _1, NAME, INIT, INITIAL, PROCESS_SUBCELL, FINALISE_SUBCELL)\
           66         static void\
           67         process_##PIXFMT##_##NAME(struct stream *streams, size_t n_streams, size_t n)\
           68         {\
           69                 size_t i, j;\
           70                 TYPE img, auxs[2], val, a, sn;\
           71                 TYPE *pows = power_file ? (TYPE *)(streams[n_streams - 1].buf) : NULL;\
           72                 n_streams -= (size_t)!!power_file;\
           73                 sn = (TYPE)n_streams;\
           74                 INIT;\
           75                 for (i = 0; i < n; i += sizeof(TYPE), pows++) {\
           76                         img = auxs[0] = auxs[1] = INITIAL;\
           77                         for (j = 0; j < n_streams; j++) {\
           78                                 val = *(TYPE *)(streams[j].buf + i);\
           79                                 PROCESS_SUBCELL;\
           80                         }\
           81                         FINALISE_SUBCELL;\
           82                         *(TYPE *)(streams->buf + i) = img;\
           83                 }\
           84                 (void) aux, (void) a, (void) pows, (void) sn;\
           85         }
           86 #define X(...) MAKE_PROCESS(lf, double, __VA_ARGS__)
           87 LIST_MEANS(double)
           88 #undef X
           89 #define X(...) MAKE_PROCESS(f, float, __VA_ARGS__)
           90 LIST_MEANS(float)
           91 #undef X
           92 #undef MAKE_PROCESS
           93 #undef aux
           94 
           95 #define X(ID, NAME, ...) [ID] = process_lf_##NAME,
           96 static const process_func process_functions_lf[] = { LIST_MEANS() };
           97 #undef X
           98 
           99 #define X(ID, NAME, ...) [ID] = process_f_##NAME,
          100 static const process_func process_functions_f[] = { LIST_MEANS() };
          101 #undef X
          102 
          103 int
          104 main(int argc, char *argv[])
          105 {
          106         struct stream *streams;
          107         process_func process;
          108         size_t frames = SIZE_MAX, tmp;
          109         enum method method = ARITHMETIC;
          110         int i, two = 0;
          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 'H':
          123                 method = HERONIAN;
          124                 two = 1;
          125                 break;
          126         case 'i':
          127                 method = IDENTRIC;
          128                 two = 1;
          129                 break;
          130         case 'l':
          131                 method = LEHMER;
          132                 power_file = UARGF();
          133                 break;
          134         case 'L':
          135                 method = LOGARITHMIC;
          136                 two = 1;
          137                 break;
          138         case 'p':
          139                 method = POWER;
          140                 power_file = UARGF();
          141                 break;
          142         case 's':
          143                 method = STOLARSKY;
          144                 two = 1;
          145                 power_file = UARGF();
          146                 break;
          147         case 'v':
          148                 method = VARIANCE;
          149                 break;
          150         case 'z':
          151                 method = HEINZ;
          152                 two = 1;
          153                 power_file = UARGF();
          154                 break;
          155         default:
          156                 usage();
          157         } ARGEND;
          158 
          159         if (argc < 2 || (argc > 2 && two))
          160                 usage();
          161 
          162         streams = alloca((size_t)(argc + !!power_file) * sizeof(*streams));
          163         for (i = 0; i < argc; i++) {
          164                 eopen_stream(streams + i, argv[i]);
          165                 if (streams[i].frames && streams[i].frames < frames)
          166                         frames = streams[i].frames;
          167         }
          168         if (power_file != NULL)
          169                 eopen_stream(streams + argc, power_file);
          170 
          171         if (streams->encoding == DOUBLE)
          172                 process = process_functions_lf[method];
          173         else if (streams->encoding == FLOAT)
          174                 process = process_functions_f[method];
          175         else
          176                 eprintf("pixel format %s is not supported, try xyza\n", streams->pixfmt);
          177 
          178         tmp = streams->frames, streams->frames = frames;
          179         fprint_stream_head(stdout, streams);
          180         efflush(stdout, "<stdout>");
          181         streams->frames = tmp;
          182         process_multiple_streams(streams, (size_t)(argc + !!power_file),
          183                                  STDOUT_FILENO, "<stdout>", 1, process);
          184         return 0;
          185 }