Introduction
Introduction Statistics Contact Development Disclaimer Help
blind-concat.c - blind - suckless command-line video editing utility
git clone git://git.suckless.org/blind
Log
Files
Refs
README
LICENSE
---
blind-concat.c (5171B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include "common.h"
3
4 USAGE("[-o output-file [-j jobs]] first-stream ... last-stream")
5
6 static void
7 concat_to_stdout(int argc, char *argv[], const char *fname)
8 {
9 struct stream *streams;
10 size_t frames = 0;
11 int i;
12
13 streams = emalloc2((size_t)argc, sizeof(*streams));
14
15 for (i = 0; i < argc; i++) {
16 eopen_stream(streams + i, argv[i]);
17 if (i)
18 echeck_compat(streams + i, streams);
19 if (streams[i].frames > SIZE_MAX - frames)
20 eprintf("resulting video is too long\n");
21 frames += streams[i].frames;
22 }
23
24 streams->frames = frames;
25 fprint_stream_head(stdout, streams);
26 efflush(stdout, fname);
27
28 for (i = 0; i < argc; i++) {
29 esend_stream(streams + i, STDOUT_FILENO, fname);
30 close(streams[i].fd);
31 }
32
33 free(streams);
34 }
35
36 static void
37 concat_to_file(int argc, char *argv[], char *output_file)
38 {
39 struct stream stream, refstream;
40 int first = 1;
41 int fd = eopen(output_file, O_RDWR | O_CREAT | O_TRUNC, 0666);
42 char head[STREAM_HEAD_MAX];
43 ssize_t headlen;
44 size_t size;
45 off_t pos;
46 char *data;
47
48 for (; argc--; argv++) {
49 eopen_stream(&stream, *argv);
50
51 if (first) {
52 refstream = stream;
53 first = 1;
54 } else {
55 if (refstream.frames > SIZE_MAX - stream.frames)
56 eprintf("resulting video is too long\n");
57 refstream.frames += stream.frames;
58 echeck_compat(&stream, &refstream);
59 }
60
61 esend_stream(&stream, fd, output_file);
62 close(stream.fd);
63 }
64
65 SPRINTF_HEAD_ZN(head, stream.frames, stream.width, stream.height…
66 ewriteall(fd, head, (size_t)headlen, output_file);
67
68 size = (size_t)(pos = elseek(fd, 0, SEEK_CUR, output_file));
69 if ((uintmax_t)pos > SIZE_MAX)
70 eprintf("%s\n", strerror(EFBIG));
71
72 data = mmap(0, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
73 if (data == MAP_FAILED)
74 eprintf("mmap %s:", output_file);
75 memmove(data + headlen, data, size - (size_t)headlen);
76 memcpy(data, head, (size_t)headlen);
77 munmap(data, size);
78
79 close(fd);
80 }
81
82 static void
83 concat_to_file_parallel(int argc, char *argv[], char *output_file, size_…
84 {
85 #if !defined(HAVE_EPOLL)
86 int fd = eopen(output_file, O_WRONLY | O_CREAT | O_TRUNC, 0666);
87 if (fd != STDOUT_FILENO)
88 edup2(fd, STDOUT_FILENO);
89 concat_to_stdout(argc, argv, output_file);
90 #else
91 struct epoll_event *events;
92 struct stream *streams;
93 off_t *ptrs, ptr;
94 char head[STREAM_HEAD_MAX];
95 size_t frames = 0, next = 0, j;
96 ssize_t headlen;
97 int fd, i, n, pollfd;
98
99 if (jobs > (size_t)argc)
100 jobs = (size_t)argc;
101
102 fd = eopen(output_file, O_RDWR | O_CREAT | O_TRUNC, 0666);
103 events = emalloc2(jobs, sizeof(*events));
104 streams = emalloc2((size_t)argc, sizeof(*streams));
105 ptrs = emalloc2((size_t)argc, sizeof(*ptrs));
106
107 for (i = 0; i < argc; i++) {
108 eopen_stream(streams + i, argv[i]);
109 if (i)
110 echeck_compat(streams + i, streams);
111 if (streams[i].frames > SIZE_MAX - frames)
112 eprintf("resulting video is too long\n");
113 frames += streams[i].frames;
114 }
115
116 SPRINTF_HEAD_ZN(head, frames, streams->width, streams->height, s…
117
118 echeck_dimensions(streams, WIDTH | HEIGHT, NULL);
119 ptr = (off_t)headlen;
120 for (i = 0; i < argc; i++) {
121 ptrs[i] = ptr;
122 ptr += (off_t)streams->frames * (off_t)streams->frame_si…
123 }
124 if (ftruncate(fd, (off_t)ptr))
125 eprintf("ftruncate %s:", output_file);
126 fadvise_random(fd, (off_t)headlen, 0);
127
128 pollfd = epoll_create1(0);
129 if (pollfd == -1)
130 eprintf("epoll_create1:");
131
132 epwriteall(fd, head, (size_t)headlen, 0, output_file);
133 for (i = 0; i < argc; i++) {
134 epwriteall(fd, streams[i].buf, streams[i].ptr, ptrs[i], …
135 ptrs[i] += (off_t)(streams[i].ptr);
136 streams[i].ptr = 0;
137 }
138
139 for (j = 0; j < jobs; j++, next++) {
140 events->events = EPOLLIN;
141 events->data.u64 = next;
142 if (epoll_ctl(pollfd, EPOLL_CTL_ADD, streams[next].fd, e…
143 if ((errno == ENOMEM || errno == ENOSPC) && j)
144 break;
145 eprintf("epoll_ctl:");
146 }
147 }
148 jobs = j;
149
150 while (jobs) {
151 n = epoll_wait(pollfd, events, (int)jobs, -1);
152 if (n < 0)
153 eprintf("epoll_wait:");
154 for (i = 0; i < n; i++) {
155 j = events[i].data.u64;
156 if (streams[j].ptr || eread_stream(streams + j, …
157 epwriteall(fd, streams[j].buf, streams[j…
158 ptrs[j] += (off_t)(streams[j].ptr);
159 streams[j].ptr = 0;
160 continue;
161 }
162
163 close(streams[j].fd);
164 if (next < (size_t)argc) {
165 events->events = EPOLLIN;
166 events->data.u64 = next;
167 if (epoll_ctl(pollfd, EPOLL_CTL_ADD, str…
168 if ((errno == ENOMEM || errno ==…
169 break;
170 eprintf("epoll_ctl:");
171 }
172 next++;
173 } else {
174 jobs--;
175 }
176 }
177 }
178
179 close(pollfd);
180 free(events);
181 free(streams);
182 free(ptrs);
183 #endif
184 }
185
186 int
187 main(int argc, char *argv[])
188 {
189 char *output_file = NULL;
190 size_t jobs = 0;
191
192 ARGBEGIN {
193 case 'o':
194 output_file = UARGF();
195 break;
196 case 'j':
197 jobs = etozu_flag('j', UARGF(), 1, SHRT_MAX);
198 break;
199 default:
200 usage();
201 } ARGEND;
202
203 if (argc < 2 || (jobs && !output_file))
204 usage();
205
206 if (jobs)
207 concat_to_file_parallel(argc, argv, output_file, jobs);
208 else if (output_file)
209 concat_to_file(argc, argv, output_file);
210 else
211 concat_to_stdout(argc, argv, "<stdout>");
212
213 return 0;
214 }
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.