blind

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

blind-stack.c (2685B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include "common.h"
      3 
      4 USAGE("[-bs] bottom-stream ... top-stream")
      5 
      6 #define PROCESS(TYPE, BLEND)\
      7 	do {\
      8 		TYPE x1, y1, z1, a1;\
      9 		TYPE x2, y2, z2, a2;\
     10 		size_t i, j;\
     11 		for (i = 0; i < n; i += streams->pixel_size) {\
     12 			x1 = ((TYPE *)(streams[0].buf + i))[0];\
     13 			y1 = ((TYPE *)(streams[0].buf + i))[1];\
     14 			z1 = ((TYPE *)(streams[0].buf + i))[2];\
     15 			a1 = ((TYPE *)(streams[0].buf + i))[3];\
     16 			for (j = 1; j < n_streams; j++) {\
     17 				x2 = ((TYPE *)(streams[j].buf + i))[0];\
     18 				y2 = ((TYPE *)(streams[j].buf + i))[1];\
     19 				z2 = ((TYPE *)(streams[j].buf + i))[2];\
     20 				a2 = ((TYPE *)(streams[j].buf + i))[3];\
     21 				if (BLEND)\
     22 					a2 /= (TYPE)(j + 1);\
     23 				a1 *= 1 - a2;\
     24 				x1 = x1 * a1 + x2 * a2;\
     25 				y1 = y1 * a1 + y2 * a2;\
     26 				z1 = z1 * a1 + z2 * a2;\
     27 				a1 += a2;\
     28 			}\
     29 			((TYPE *)(streams[0].buf + i))[0] = x1;\
     30 			((TYPE *)(streams[0].buf + i))[1] = y1;\
     31 			((TYPE *)(streams[0].buf + i))[2] = z1;\
     32 			((TYPE *)(streams[0].buf + i))[3] = a1;\
     33 		}\
     34 	} while (0)
     35 
     36 static void process_lf  (struct stream *streams, size_t n_streams, size_t n) { PROCESS(double, 0); }
     37 static void process_lf_b(struct stream *streams, size_t n_streams, size_t n) { PROCESS(double, 1); }
     38 static void process_f   (struct stream *streams, size_t n_streams, size_t n) { PROCESS(float, 0); }
     39 static void process_f_b (struct stream *streams, size_t n_streams, size_t n) { PROCESS(float, 1); }
     40 
     41 int
     42 main(int argc, char *argv[])
     43 {
     44 	struct stream *streams;
     45 	size_t n_streams, i, frames = 0, tmp;
     46 	int blend = 0, shortest = 0;
     47 	void (*process)(struct stream *streams, size_t n_streams, size_t n);
     48 
     49 	ARGBEGIN {
     50 	case 'b':
     51 		blend = 1;
     52 		break;
     53 	case 's':
     54 		shortest = 1;
     55 		frames = SIZE_MAX;
     56 		break;
     57 	default:
     58 		usage();
     59 	} ARGEND;
     60 
     61 	if (argc < 2)
     62 		usage();
     63 
     64 	n_streams = (size_t)argc;
     65 	streams = ecalloc(n_streams, sizeof(*streams));
     66 
     67 	for (i = 0; i < n_streams; i++) {
     68 		eopen_stream(streams + i, argv[i]);
     69 		if (shortest ?
     70 		    (streams[i].frames && streams[i].frames < frames) :
     71 		    (streams[i].frames || streams[i].frames > frames))
     72 			frames = streams[i].frames;
     73 	}
     74 
     75 	if (streams->encoding == DOUBLE)
     76 		process = blend ? process_lf_b :process_lf;
     77 	else if (streams->encoding == FLOAT)
     78 		process = blend ? process_f_b : process_f;
     79 	else
     80 		eprintf("pixel format %s is not supported, try xyza\n", streams->pixfmt);
     81 	CHECK_ALPHA_CHAN(streams);
     82 	CHECK_N_CHAN(streams, 4, 4);
     83 
     84 	tmp = streams->frames, streams->frames = frames;
     85 	fprint_stream_head(stdout, streams);
     86 	efflush(stdout, "<stdout>");
     87 	streams->frames = tmp;
     88 	process_multiple_streams(streams, n_streams, STDOUT_FILENO, "<stdout>", shortest, process);
     89 
     90 	free(streams);
     91 	return 0;
     92 }