blind-multiply-matrices.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-multiply-matrices.c (3451B)
---
1 /* See LICENSE file for copyright and license details. */
2 #ifndef TYPE
3 #include "common.h"
4
5 USAGE("[-en] leftmost-stream ... rightmost-stream")
6
7 static int equal = 0;
8 static size_t max_frame_size;
9
10 #define FILE "blind-multiply-matrices.c"
11 #include "define-functions.h"
12
13 int
14 main(int argc, char *argv[])
15 {
16 struct stream *streams;
17 size_t n_streams, i, frames = 0;
18 int natural = 0, j;
19 char **rev_argv;
20 size_t max_width = 0, max_height = 0;
21 size_t width = 0, height = 0, w, h;
22 void (*process)(struct stream *streams, size_t n_streams);
23
24 ARGBEGIN {
25 case 'e':
26 equal = 1;
27 break;
28 case 'n':
29 natural = 1;
30 break;
31 default:
32 usage();
33 } ARGEND;
34
35 if (argc < 2)
36 usage();
37
38 if (natural) {
39 rev_argv = alloca((size_t)argc * sizeof(*rev_argv));
40 for (j = 0; j < argc; j++)
41 rev_argv[j] = argv[argc - 1 - j];
42 argv = rev_argv;
43 }
44
45 n_streams = (size_t)argc;
46 streams = ecalloc(n_streams, sizeof(*streams));
47
48 for (i = 0; i < n_streams; i++) {
49 eopen_stream(streams + i, argv[i]);
50 if (streams[i].frames && streams[i].frames < frames)
51 frames = streams[i].frames;
52 if (streams->width > max_width)
53 max_width = streams->width;
54 if (streams->height > max_height)
55 max_height = streams->height;
56 }
57 for (i = 1; i < n_streams; i++)
58 if (strcmp(streams->pixfmt, streams[i].pixfmt))
59 eprintf("videos use incompatible pixel formats\n");
60
61 width = streams[n_streams - 1].width;
62 height = streams[n_streams - 1].height;
63 for (i = n_streams - 1; i--;) {
64 if (streams[i].width != height)
65 eprintf("videos do not have the compatible geometry\n");
66 height = streams[i].height;
67 }
68
69 SELECT_PROCESS_FUNCTION(streams);
70 CHECK_N_CHAN(streams, 1, 4);
71
72 w = streams->width, streams->width = max_width;
73 h = streams->height, streams->height = max_height;
74 echeck_dimensions(streams, WIDTH | HEIGHT, NULL);
75 streams->width = width;
76 streams->height = height;
77 streams->frames = frames;
78 fprint_stream_head(stdout, streams);
79 streams->width = w;
80 streams->height = h;
81 efflush(stdout, "<stdout>");
82 max_frame_size = max_width * max_height * streams->pixel_size;
83
84 process(streams, n_streams);
85
86 free(streams);
87 return 0;
88 }
89
90 #else
91
92 static void
93 PROCESS(struct stream *streams, size_t n_streams)
94 {
95 typedef TYPE pixel_t[4];
96 pixel_t *res, *left, *right, *tmp;
97 size_t i, j, w, h, h2, x, y, k, r;
98 res = emalloc(max_frame_size);
99 left = emalloc(max_frame_size);
100 right = emalloc(max_frame_size);
101
102 while (eread_frame(streams + (n_streams - 1), res)) {
103 w = streams[n_streams - 1].width;
104 h = streams[n_streams - 1].height;
105 for (i = n_streams - 1; i--;) {
106 tmp = res, res = right, right = tmp;
107 if (!eread_frame(streams + i, left))
108 goto done;
109 h2 = streams[i].height;
110 memset(res, 0, w * h2 * streams->pixel_size);
111
112 /* XXX Is there any significant performance to be gained by transposing `right`? */
113 if (equal) {
114 for (y = r = 0; y < h2; y++) {
115 for (x = 0; x < w; x++, r++) {
116 for (k = 0; k < h; k++)
117 res[r][0] += left[y * h + k][0] * right[k * w + x][0];
118 for (j = 1; j < streams->n_chan; j++)
119 res[r][j] = res[r][0];
120 }
121 }
122 } else {
123 for (y = r = 0; y < h2; y++)
124 for (x = 0; x < w; x++, r++)
125 for (k = 0; k < h; k++)
126 for (j = 0; j < streams->n_chan; j++)
127 res[r][j] += left[y * h + k][j] * right[k * w + x][j];
128 }
129
130 h = h2;
131 }
132 ewriteall(STDOUT_FILENO, res, streams->frame_size, "<stdout>");
133 }
134
135 done:
136 free(res);
137 free(left);
138 free(right);
139 }
140
141 #endif