blind

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

blind-invert-matrix.c (3905B)


      1 /* See LICENSE file for copyright and license details. */
      2 #ifndef TYPE
      3 #include "common.h"
      4 
      5 USAGE("[-aexyz]")
      6 
      7 static int equal = 0;
      8 static int skip_ch[] = {0, 0, 0, 0};
      9 static size_t first_included = 0;
     10 
     11 #define FILE "blind-invert-matrix.c"
     12 #include "define-functions.h"
     13 
     14 int
     15 main(int argc, char *argv[])
     16 {
     17 	struct stream stream;
     18 	size_t width, x, y, i, row_size;
     19 	char *buf, *one, *p, *q;
     20 	void (*process)(struct stream *stream, void *buf);
     21 
     22 	ARGBEGIN {
     23 	case 'a':
     24 		skip_ch[3] = 1;
     25 		break;
     26 	case 'e':
     27 		equal = 1;
     28 		break;
     29 	case 'x':
     30 		skip_ch[0] = 1;
     31 		break;
     32 	case 'y':
     33 		skip_ch[1] = 1;
     34 		break;
     35 	case 'z':
     36 		skip_ch[2] = 1;
     37 		break;
     38 	default:
     39 		usage();
     40 	} ARGEND;
     41 
     42 	if (argc)
     43 		usage();
     44 
     45 	while (first_included < ELEMENTSOF(skip_ch) && skip_ch[first_included])
     46 		first_included++;
     47 	if (first_included == ELEMENTSOF(skip_ch))
     48 		equal = 0;
     49 
     50 	eopen_stream(&stream, NULL);
     51 	echeck_dimensions(&stream, WIDTH | HEIGHT, NULL);
     52 	width = stream.width;
     53 	if (stream.width < stream.height)
     54 		eprintf("<stdin>: the video must be at least as wide as it is tall\n");
     55 	else if (stream.width > stream.height)
     56 		stream.width -= stream.height;
     57 	fprint_stream_head(stdout, &stream);
     58 	stream.width = width;
     59 	efflush(stdout, "<stdout>");
     60 
     61 	if (skip_ch[3] && stream.alpha_chan != -1)
     62 		CHECK_ALPHA_CHAN(&stream);
     63 	CHECK_N_CHAN(&stream, 1, 4);
     64 	one = alloca(stream.pixel_size);
     65 	if (stream.encoding == DOUBLE) {
     66 		*(double *)one = 1;
     67 		process = process_lf;
     68 	} else if (stream.encoding == FLOAT) {
     69 		*(float *)one = 1;
     70 		process = process_f;
     71 	} else {
     72 		eprintf("pixel format %s is not supported, try xyza\n", stream.pixfmt);
     73 	}
     74 
     75 	for (i = 1; i < stream.n_chan; i++)
     76 		memcpy(one + i * stream.chan_size, one, stream.chan_size);
     77 
     78 	width = stream.width > stream.height ? stream.width : 2 * stream.height;
     79 	buf = emalloc2(width, stream.col_size);
     80 	row_size = width * stream.pixel_size;
     81 
     82 	while (eread_frame(&stream, buf)) {
     83 		if (stream.width == stream.height) {
     84 			for (y = stream.height; y--;) {
     85 				memmove(buf + y * row_size, buf + y * stream.row_size, stream.row_size);
     86 				memset(buf + y * row_size + stream.row_size, 0, stream.row_size);
     87 				memcpy(buf + y * row_size + stream.row_size + y * stream.pixel_size, one, stream.pixel_size);
     88 			}
     89 		}
     90 		if (equal) {
     91 			process(&stream, buf + first_included * stream.chan_size);
     92 			for (y = 0; y < stream.height; y++) {
     93 				for (x = 0; x < stream.width; x++) {
     94 					p = buf + y * row_size + x * stream.pixel_size + stream.col_size;
     95 					q = p + first_included * stream.chan_size;
     96 					for (i = 0; i < stream.n_chan; i++, p += stream.chan_size)
     97 						if (i != first_included && !skip_ch[i])
     98 							memcpy(p, q, stream.chan_size);
     99 				}
    100 			}
    101 		} else {
    102 			for (i = 0; i < stream.n_chan; i++)
    103 				if (!skip_ch[i])
    104 					process(&stream, buf + i * stream.chan_size);
    105 		}
    106 		for (y = 0; y < stream.height; y++)
    107 			ewriteall(STDOUT_FILENO, buf + y * row_size + stream.col_size, row_size - stream.col_size, "<stdout>");
    108 	}
    109 
    110 	free(buf);
    111 	return 0;
    112 }
    113 
    114 #else
    115 
    116 #define SUB_ROWS()\
    117 	do {\
    118 		p2 = matrix + r2 * cn;\
    119 		t = p2[r1][0];\
    120 		for (c = 0; c < cn; c++)\
    121 			p2[c][0] -= p1[c][0] * t;\
    122 	} while (0)
    123 
    124 static void
    125 PROCESS(struct stream *stream, void *buf)
    126 {
    127 	typedef TYPE pixel_t[4];
    128 	size_t rn = stream->height, r1, r2, c;
    129 	size_t cn = stream->width > rn ? stream->width : 2 * rn;
    130 	pixel_t *matrix = buf, *p1, *p2;
    131 	TYPE t;
    132 
    133 	for (r1 = 0; r1 < rn; r1++) {
    134 		p1 = matrix + r1 * cn;
    135 		if (!p1[r1][0]) {
    136 			for (r2 = r1 + 1; r2 < rn; r2++) {
    137 				p2 = matrix + r2 * cn;
    138 				if (p2[r1][0])
    139 					break;
    140 			}
    141 			if (r2 >= rn)
    142 				eprintf("matrix is not invertable\n");
    143 			for (c = 0; c < cn; c++)
    144 				t = p1[c][0], p1[c][0] = p2[c][0], p2[c][0] = t;
    145 		}
    146 		t = 1 / p1[r1][0];
    147 		for (c = 0; c < cn; c++)
    148 			p1[c][0] *= t;
    149 		for (r2 = r1 + 1; r2 < rn; r2++)
    150 			SUB_ROWS();
    151 	}
    152 
    153 	for (r1 = rn; r1--;) {
    154 		p1 = matrix + r1 * cn;
    155 		for (r2 = r1; r2--;)
    156 			SUB_ROWS();
    157 	}
    158 }
    159 
    160 #undef SUB_ROWS
    161 #endif