blind

suckless command-line video editing utility
git clone git://git.suckless.org/blind
Log | Files | Refs | README | LICENSE

blind-arithm.c (3393B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include "common.h"
      3 
      4 USAGE("[-axyz] operation right-hand-stream ...")
      5 
      6 static int skip_ch[4] = {0, 0, 0, 0};
      7 
      8 /* Because the syntax for a function returning a function pointer is disgusting. */
      9 typedef void (*process_func)(struct stream *streams, size_t n_streams, size_t n);
     10 
     11 #define LIST_OPERATORS(PIXFMT, TYPE)\
     12 	X(add, 0, *lh += rh,                  PIXFMT, TYPE)\
     13 	X(sub, 0, *lh -= rh,                  PIXFMT, TYPE)\
     14 	X(mul, 0, *lh *= rh,                  PIXFMT, TYPE)\
     15 	X(div, 0, *lh /= rh,                  PIXFMT, TYPE)\
     16 	X(mod, 0, *lh = posmod(*lh, rh),      PIXFMT, TYPE)\
     17 	X(exp, 1, *lh = pow(*lh, rh),         PIXFMT, TYPE)\
     18 	X(log, 0, *lh = log2(*lh) / log2(rh), PIXFMT, TYPE)\
     19 	X(min, 0, *lh = MIN(*lh, rh),         PIXFMT, TYPE)\
     20 	X(max, 0, *lh = MAX(*lh, rh),         PIXFMT, TYPE)\
     21 	X(abs, 0, *lh = abs(*lh - rh) + rh,   PIXFMT, TYPE)
     22 
     23 #define P(L, R, ALGO, TYPE)\
     24 	(lh = (TYPE *)(streams[L].buf + k),\
     25 	 rh = *((TYPE *)(streams[R].buf + k)),\
     26 	 (ALGO))
     27 
     28 #define X(NAME, RTL, ALGO, PIXFMT, TYPE)\
     29 	static void\
     30 	process_##PIXFMT##_##NAME(struct stream *streams, size_t n_streams, size_t n)\
     31 	{\
     32 		size_t i, j, k;\
     33 		TYPE *lh, rh;\
     34 		if (RTL) {\
     35 			for (i = 0; i < streams->n_chan; i++)\
     36 				if (!skip_ch[i])\
     37 					for (j = n_streams; --j;)\
     38 						for (k = i * sizeof(TYPE); k < n; k += 4 * sizeof(TYPE))\
     39 							P(j - 1, j, ALGO, TYPE);\
     40 		} else {\
     41 			for (i = 0; i < streams->n_chan; i++)\
     42 				if (!skip_ch[i])\
     43 					for (j = 1; j < n_streams; j++)\
     44 						for (k = i * sizeof(TYPE); k < n; k += 4 * sizeof(TYPE))\
     45 							P(0, j, ALGO, TYPE);\
     46 		}\
     47 	}
     48 LIST_OPERATORS(lf, double)
     49 LIST_OPERATORS(f, float)
     50 #undef X
     51 
     52 static process_func
     53 get_process_lf(const char *operation)
     54 {
     55 #define X(NAME, _RTL, _ALGO, PIXFMT, _TYPE)\
     56 	if (!strcmp(operation, #NAME)) return process_##PIXFMT##_##NAME;
     57 	LIST_OPERATORS(lf, double)
     58 #undef X
     59 	eprintf("algorithm not recognised: %s\n", operation);
     60 	return NULL;
     61 }
     62 
     63 static process_func
     64 get_process_f(const char *operation)
     65 {
     66 #define X(NAME, _RTL, _ALGO, PIXFMT, _TYPE)\
     67 	if (!strcmp(operation, #NAME)) return process_##PIXFMT##_##NAME;
     68 	LIST_OPERATORS(f, float)
     69 #undef X
     70 	eprintf("algorithm not recognised: %s\n", operation);
     71 	return NULL;
     72 }
     73 
     74 int
     75 main(int argc, char *argv[])
     76 {
     77 	struct stream *streams;
     78 	process_func process;
     79 	const char *operation;
     80 	size_t frames = SIZE_MAX, tmp;
     81 	int i;
     82 
     83 	ARGBEGIN {
     84 	case 'a':
     85 		skip_ch[3] = 1;
     86 		break;
     87 	case 'x':
     88 	case 'y':
     89 	case 'z':
     90 		skip_ch[ARGC() - 'x'] = 1;
     91 		break;
     92 	default:
     93 		usage();
     94 	} ARGEND;
     95 
     96 	if (argc < 2)
     97 		usage();
     98 
     99 	operation = *argv;
    100 	streams = alloca((size_t)argc * sizeof(*streams));
    101 	*argv = NULL;
    102 	for (i = 0; i < argc; i++) {
    103 		eopen_stream(streams + i, argv[i]);
    104 		if (streams[i].frames && streams[i].frames < frames)
    105 			frames = streams[i].frames;
    106 	}
    107 
    108 	if (streams->alpha)
    109 		CHECK_ALPHA(streams);
    110 	CHECK_N_CHAN(streams, 1, 3 + !!streams->alpha);
    111 	if (streams->encoding == DOUBLE)
    112 		process = get_process_lf(operation);
    113 	else if (streams->encoding == FLOAT)
    114 		process = get_process_f(operation);
    115 	else
    116 		eprintf("pixel format %s is not supported, try xyza\n", streams->pixfmt);
    117 
    118 	tmp = streams->frames, streams->frames = frames;
    119 	fprint_stream_head(stdout, streams);
    120 	efflush(stdout, "<stdout>");
    121 	streams->frames = tmp;
    122 	process_multiple_streams(streams, (size_t)argc, STDOUT_FILENO, "<stdout>", 1, process);
    123 	return 0;
    124 }