Introduction
Introduction Statistics Contact Development Disclaimer Help
blind-from-video.c - blind - suckless command-line video editing utility
git clone git://git.suckless.org/blind
Log
Files
Refs
README
LICENSE
---
blind-from-video.c (7228B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include "common.h"
3
4 USAGE("[-F pixel-format] [-r frame-rate] [-w width -h height] [-dL] inpu…
5
6 static int draft = 0;
7 static void (*convert_segment)(char *buf, size_t n, int fd, const char *…
8
9 static void
10 read_metadata(FILE *fp, char *fname, size_t *width, size_t *height)
11 {
12 char *line = NULL;
13 size_t size = 0;
14 ssize_t len;
15 char *p;
16
17 while ((len = getline(&line, &size, fp)) != -1) {
18 if (len && line[len - 1])
19 line[--len] = '\0';
20 p = strchr(line, '=') + 1;
21 if (strstr(line, "width=") == line) {
22 if (tozu(p, 1, SIZE_MAX, width))
23 eprintf("invalid width: %s\n", p);
24 } else if (strstr(line, "height=") == line) {
25 if (tozu(p, 1, SIZE_MAX, height))
26 eprintf("invalid height: %s\n", p);
27 }
28 }
29
30 if (ferror(fp))
31 eprintf("getline %s:", fname);
32 free(line);
33
34 if (!*width || !*height)
35 eprintf("could not get all required metadata\n");
36 }
37
38 static void
39 get_metadata(char *file, size_t *width, size_t *height)
40 {
41 FILE *fp;
42 int fd, pipe_rw[2];
43 pid_t pid;
44 int status;
45
46 epipe(pipe_rw);
47 pid = efork();
48
49 if (!pid) {
50 pdeath(SIGKILL);
51 fd = eopen(file, O_RDONLY);
52 edup2(fd, STDIN_FILENO);
53 close(fd);
54 close(pipe_rw[0]);
55 edup2(pipe_rw[1], STDOUT_FILENO);
56 close(pipe_rw[1]);
57 eexeclp("ffprobe", "ffprobe", "-v", "quiet", "-show_stre…
58 "-select_streams", "v", "-", NULL);
59 }
60
61 close(pipe_rw[1]);
62 fp = fdopen(pipe_rw[0], "rb");
63 if (!fp)
64 eprintf("fdopen <subprocess>:");
65 read_metadata(fp, file, width, height);
66 fclose(fp);
67 close(pipe_rw[0]);
68
69 ewaitpid(pid, &status, 0);
70 if (status)
71 exit(1);
72 }
73
74 #define CONVERT_SEGMENT(TYPE)\
75 do {\
76 typedef TYPE pixel_t[4];\
77 size_t i, ptr;\
78 TYPE y, u, v, max = (TYPE)0xFF00L, ymax = (TYPE)0xDAF4L;\
79 TYPE r, g, b;\
80 pixel_t pixels[1024];\
81 uint16_t *pix;\
82 if (draft) {\
83 for (ptr = i = 0; ptr < n; ptr += 8) {\
84 pix = (uint16_t *)(buf + ptr);\
85 pixels[i][3] = 1;\
86 y = (TYPE)((long int)(le16toh(pix[1])) -…
87 u = (TYPE)((long int)(le16toh(pix[2])) -…
88 v = (TYPE)((long int)(le16toh(pix[3])) -…
89 scaled_yuv_to_ciexyz(y, u, v, pixels[i] …
90 pixels[i] + 1, pixe…
91 if (++i == 1024) {\
92 i = 0;\
93 ewriteall(fd, pixels, sizeof(pix…
94 }\
95 }\
96 } else {\
97 for (ptr = i = 0; ptr < n; ptr += 8) {\
98 pix = (uint16_t *)(buf + ptr);\
99 pixels[i][3] = le16toh(pix[0]) / max;\
100 pixels[i][3] = CLIP(0, pixels[i][3], 1);\
101 y = (TYPE)((long int)le16toh(pix[1]) - 0…
102 u = (TYPE)((long int)le16toh(pix[2]) - 0…
103 v = (TYPE)((long int)le16toh(pix[3]) - 0…
104 yuv_to_srgb(y, u, v, &r, &g, &b);\
105 r = srgb_decode(r);\
106 g = srgb_decode(g);\
107 b = srgb_decode(b);\
108 srgb_to_ciexyz(r, g, b, pixels[i] + 0, p…
109 if (++i == 1024) {\
110 i = 0;\
111 ewriteall(fd, pixels, sizeof(pix…
112 }\
113 }\
114 }\
115 if (i)\
116 ewriteall(fd, pixels, i * sizeof(*pixels), file)…
117 } while (0)
118
119 static void convert_segment_xyza (char *buf, size_t n, int fd, const cha…
120 static void convert_segment_xyzaf(char *buf, size_t n, int fd, const cha…
121
122 static void
123 convert(const char *infile, int outfd, const char *outfile, size_t width…
124 {
125 char geometry[2 * INTSTRLEN(size_t) + 2], buf[BUFSIZ];
126 const char *cmd[13];
127 int status, pipe_rw[2];
128 size_t i = 0, n, ptr;
129 pid_t pid;
130
131 cmd[i++] = "ffmpeg";
132 cmd[i++] = "-i", cmd[i++] = infile;
133 cmd[i++] = "-f", cmd[i++] = "rawvideo";
134 cmd[i++] = "-pix_fmt", cmd[i++] = "ayuv64le";
135 if (width && height) {
136 sprintf(geometry, "%zux%zu", width, height);
137 cmd[i++] = "-s:v", cmd[i++] = geometry;
138 }
139 if (frame_rate)
140 cmd[i++] = "-r", cmd[i++] = frame_rate;
141 cmd[i++] = "-";
142 cmd[i++] = NULL;
143
144 epipe(pipe_rw);
145 pid = efork();
146
147 if (!pid) {
148 pdeath(SIGKILL);
149 close(pipe_rw[0]);
150 edup2(pipe_rw[1], STDOUT_FILENO);
151 close(pipe_rw[1]);
152 eexecvp("ffmpeg", (char **)(void *)cmd);
153 }
154
155 close(pipe_rw[1]);
156
157 if (convert_segment) {
158 for (ptr = 0;;) {
159 if (!(n = eread(pipe_rw[0], buf + ptr, sizeof(bu…
160 break;
161 ptr += n;
162 n = ptr - (ptr % 8);
163 convert_segment(buf, n, outfd, outfile);
164 memmove(buf, buf + n, ptr -= n);
165 }
166 if (ptr)
167 eprintf("<subprocess>: incomplete frame\n");
168 } else {
169 while ((n = eread(pipe_rw[0], buf, sizeof(buf), "<subpro…
170 ewriteall(outfd, buf, (size_t)n, outfile);
171 }
172
173 close(pipe_rw[0]);
174 ewaitpid(pid, &status, 0);
175 if (status)
176 exit(1);
177 }
178
179 int
180 main(int argc, char *argv[])
181 {
182 size_t width = 0, height = 0, frames;
183 char head[STREAM_HEAD_MAX];
184 char *frame_rate = NULL;
185 char *infile;
186 const char *outfile;
187 char *data;
188 const char *pixfmt = "xyza";
189 ssize_t headlen;
190 size_t length, frame_size, pixel_size;
191 int outfd, skip_length = 0;
192 struct stat st;
193
194 ARGBEGIN {
195 case 'd':
196 draft = 1;
197 break;
198 case 'L':
199 skip_length = 1;
200 break;
201 case 'F':
202 pixfmt = UARGF();
203 break;
204 case 'r':
205 frame_rate = UARGF();
206 break;
207 case 'w':
208 width = etozu_flag('w', UARGF(), 1, SIZE_MAX);
209 break;
210 case 'h':
211 height = etozu_flag('h', UARGF(), 1, SIZE_MAX);
212 break;
213 default:
214 usage();
215 } ARGEND;
216
217 if (argc < 1 || argc > 2 || !width != !height)
218 usage();
219
220 infile = argv[0];
221 outfile = argv[1] ? argv[1] : "-";
222
223 pixfmt = get_pixel_format(pixfmt, "xyza");
224 if (!strcmp(pixfmt, "xyza")) {
225 convert_segment = convert_segment_xyza;
226 pixel_size = 4 * sizeof(double);
227 } else if (!strcmp(pixfmt, "xyza f")) {
228 convert_segment = convert_segment_xyzaf;
229 pixel_size = 4 * sizeof(float);
230 } else if (!strcmp(pixfmt, "raw0")) {
231 convert_segment = NULL;
232 pixel_size = 4 * sizeof(uint16_t);
233 } else {
234 eprintf("pixel format %s is not supported, try xyza or r…
235 }
236
237 if (!width)
238 get_metadata(infile, &width, &height);
239 if (width > SIZE_MAX / height)
240 eprintf("video frame too large\n");
241 frame_size = width * height;
242 if (pixel_size > SIZE_MAX / frame_size)
243 eprintf("video frame too large\n");
244 frame_size *= pixel_size;
245
246 if (!strcmp(outfile, "-")) {
247 outfile = "<stdout>";
248 outfd = STDOUT_FILENO;
249 if (!skip_length)
250 eprintf("standard out as output file is only all…
251 } else {
252 outfd = eopen(outfile, O_RDWR | O_CREAT | O_TRUNC, 0666);
253 }
254
255 if (skip_length) {
256 SPRINTF_HEAD_ZN(head, 0, width, height, pixfmt, &headlen…
257 ewriteall(outfd, head, (size_t)headlen, outfile);
258 }
259
260 convert(infile, outfd, outfile, width, height, frame_rate);
261
262 if (outfd == STDOUT_FILENO)
263 return 0;
264
265 if (fstat(outfd, &st))
266 eprintf("fstat %s:", outfile);
267 length = (size_t)(st.st_size);
268
269 if (skip_length)
270 length -= (size_t)headlen;
271 if (length % frame_size)
272 eprintf("<subprocess>: incomplete frame\n");
273 frames = length / frame_size;
274
275 if (!skip_length) {
276 SPRINTF_HEAD_ZN(head, frames, width, height, pixfmt, &he…
277 ewriteall(outfd, head, (size_t)headlen, outfile);
278 data = mmap(0, length + (size_t)headlen, PROT_READ | PRO…
279 memmove(data + headlen, data, length);
280 memcpy(data, head, (size_t)headlen);
281 munmap(data, length + (size_t)headlen);
282 }
283
284 close(outfd);
285 return 0;
286 }
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.