blind-temporal-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-temporal-mean.c (5440B)
       ---
            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, void *buffer, void *image, size_t frame);
            9 
           10 /*
           11  * X-parameter 1: method enum value
           12  * X-parameter 2: identifier-friendly name
           13  * X-parameter 3: images
           14  * X-parameter 4: action for first frame
           15  * X-parameter 5: pre-process assignments
           16  * X-parameter 6: subcell processing
           17  * X-parameter 7: pre-finalise assignments
           18  * X-parameter 8: subcell finalisation
           19  */
           20 #define LIST_MEANS(TYPE)\
           21         /* [default] arithmetic mean */\
           22         X(ARITHMETIC, arithmetic, 1, COPY_FRAME,, *img += *buf,\
           23           a = (TYPE)1 / (TYPE)frame, *img *= a)\
           24         /* standard deviation */\
           25         X(STANDARD_DEVIATION, sd, 2, ZERO_AND_PROCESS_FRAME,, (*img += *buf * *buf, *aux += *buf),\
           26           a = (TYPE)1 / (TYPE)frame, *img = nnpow((*img - *aux * *aux * a) * a, (TYPE)0.5))\
           27         /* geometric mean */\
           28         X(GEOMETRIC, geometric, 1, COPY_FRAME,, *img *= *buf,\
           29           a = (TYPE)1 / (TYPE)frame, *img = nnpow(*img, a))\
           30         /* harmonic mean */\
           31         X(HARMONIC, harmonic, 1, ZERO_AND_PROCESS_FRAME,, *img += (TYPE)1 / *buf,\
           32           a = (TYPE)frame, *img = a / *img)\
           33         /* Lehmer mean */\
           34         X(LEHMER, lehmer, 2, ZERO_AND_PROCESS_FRAME,,\
           35           (*img += nnpow(*buf, *pows), *aux += nnpow(*buf, *pows - (TYPE)1)),, *img /= *aux)\
           36         /* power mean (Hölder mean) (m = 2 for root square mean; m = 3 for cubic mean) */\
           37         X(POWER, power, 1, ZERO_AND_PROCESS_FRAME,, *img += nnpow(*buf, *pows),\
           38           a = (TYPE)1 / (TYPE)frame, *img = a * nnpow(*img, (TYPE)1 / *pows))\
           39         /* variance */\
           40         X(VARIANCE, variance, 2, ZERO_AND_PROCESS_FRAME,, (*img += *buf * *buf, *aux += *buf),\
           41           a = (TYPE)1 / (TYPE)frame, *img = (*img - *aux * *aux * a) * a)
           42 
           43 enum first_frame_action {
           44         COPY_FRAME,
           45         PROCESS_FRAME,
           46         ZERO_AND_PROCESS_FRAME,
           47 };
           48 
           49 #define X(V, ...) V,
           50 enum method { LIST_MEANS() };
           51 #undef X
           52 
           53 static void *powerbuf = NULL;
           54 
           55 #define MAKE_PROCESS(PIXFMT, TYPE,\
           56                      _1, NAME, _3, _4, PRE_PROCESS, PROCESS_SUBCELL, PRE_FINALISE, FINALISE_SUBCELL)\
           57         static void\
           58         process_##PIXFMT##_##NAME(struct stream *stream, void *buffer, void *image, size_t frame)\
           59         {\
           60                 TYPE *buf = buffer, *img = image, a, *pows = powerbuf;\
           61                 TYPE *aux = (TYPE *)(((char *)image) + stream->frame_size);\
           62                 size_t x, y, z;\
           63                 if (!buf) {\
           64                         PRE_FINALISE;\
           65                         for (z = 0; z < stream->n_chan; z++)\
           66                                 for (y = 0; y < stream->height; y++)\
           67                                         for (x = 0; x < stream->width; x++, img++, aux++, pows++)\
           68                                                 FINALISE_SUBCELL;\
           69                 } else {\
           70                         PRE_PROCESS;\
           71                         for (z = 0; z < stream->n_chan; z++)\
           72                                 for (y = 0; y < stream->height; y++)\
           73                                         for (x = 0; x < stream->width; x++, img++, aux++, pows++, buf++) { \
           74                                                 PROCESS_SUBCELL;\
           75                                         }\
           76                 }\
           77                 (void) aux, (void) a, (void) pows, (void) frame;\
           78         }
           79 #define X(...) MAKE_PROCESS(lf, double, __VA_ARGS__)
           80 LIST_MEANS(double)
           81 #undef X
           82 #define X(...) MAKE_PROCESS(f, float, __VA_ARGS__)
           83 LIST_MEANS(float)
           84 #undef X
           85 #undef MAKE_PROCESS
           86 
           87 #define X(ID, NAME, ...) [ID] = process_lf_##NAME,
           88 static const process_func process_functions_lf[] = { LIST_MEANS() };
           89 #undef X
           90 
           91 #define X(ID, NAME, ...) [ID] = process_f_##NAME,
           92 static const process_func process_functions_f[] = { LIST_MEANS() };
           93 #undef X
           94 
           95 int
           96 main(int argc, char *argv[])
           97 {
           98         struct stream stream, power;
           99         void *buf, *img;
          100         process_func process;
          101         size_t frames, images;
          102         enum method method = ARITHMETIC;
          103         enum first_frame_action first_frame_action;
          104         const char *power_file = NULL;
          105 
          106         ARGBEGIN {
          107         case 'd':
          108                 method = STANDARD_DEVIATION;
          109                 break;
          110         case 'g':
          111                 method = GEOMETRIC;
          112                 break;
          113         case 'h':
          114                 method = HARMONIC;
          115                 break;
          116         case 'l':
          117                 method = LEHMER;
          118                 power_file = UARGF();
          119                 break;
          120         case 'p':
          121                 method = POWER;
          122                 power_file = UARGF();
          123                 break;
          124         case 'v':
          125                 method = VARIANCE;
          126                 break;
          127         default:
          128                 usage();
          129         } ARGEND;
          130 
          131         if (argc)
          132                 usage();
          133 
          134 #define X(ID, _2, IMAGES, FIRST_FRAME_ACTION, ...)\
          135         case ID:\
          136                 images = IMAGES;\
          137                 first_frame_action = FIRST_FRAME_ACTION;\
          138                 break;
          139         switch (method) {
          140         LIST_MEANS()
          141         default:
          142                 abort();
          143         }
          144 #undef X
          145 
          146         eopen_stream(&stream, NULL);
          147         if (power_file != NULL) {
          148                 eopen_stream(&power, power_file);
          149                 echeck_compat(&stream, &power);
          150                 powerbuf = emalloc(power.frame_size);
          151                 if (!eread_frame(&power, powerbuf))
          152                         eprintf("%s is no frames\n", power_file);
          153         }
          154 
          155         if (stream.encoding == DOUBLE)
          156                 process = process_functions_lf[method];
          157         else if (stream.encoding == FLOAT)
          158                 process = process_functions_f[method];
          159         else
          160                 eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt);
          161 
          162         stream.frames = 1;
          163         echeck_dimensions(&stream, WIDTH | HEIGHT, NULL);
          164         fprint_stream_head(stdout, &stream);
          165         efflush(stdout, "<stdout>");
          166         buf = emalloc(stream.frame_size);
          167         if (first_frame_action == ZERO_AND_PROCESS_FRAME)
          168                 img = ecalloc(images, stream.frame_size);
          169         else
          170                 img = emalloc2(images, stream.frame_size);
          171 
          172         frames = 0;
          173         if (first_frame_action == COPY_FRAME) {
          174                 if (!eread_frame(&stream, img))
          175                         eprintf("video is no frames\n");
          176                 frames++;
          177         }
          178         for (; eread_frame(&stream, buf); frames++)
          179                 process(&stream, buf, img, frames);
          180         if (!frames)
          181                 eprintf("video has no frames\n");
          182         process(&stream, NULL, img, frames);
          183 
          184         ewriteall(STDOUT_FILENO, img, stream.frame_size, "<stdout>");
          185         free(buf);
          186         free(img);
          187         free(powerbuf);
          188         return 0;
          189 }