blind-rewrite-head.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-rewrite-head.c (3241B)
---
1 /* See LICENSE file for copyright and license details. */
2 #include "common.h"
3
4 USAGE("[-h] file [(frames | 'auto') [(width | 'same') (height | 'same') [format | 'same']]]")
5
6 static void
7 rewrite(struct stream *stream, int frames_auto)
8 {
9 char head[STREAM_HEAD_MAX];
10 ssize_t headlen;
11 size_t frame_count, length;
12 struct stat st;
13 char *data;
14
15 echeck_dimensions(stream, WIDTH | HEIGHT, NULL);
16
17 if (fstat(stream->fd, &st))
18 eprintf("fstat %s:", stream->file);
19 if (!S_ISREG(st.st_mode))
20 eprintf("%s: not a regular file\n", stream->file);
21
22 frame_count = (size_t)(st.st_size) / stream->frame_size;
23 if (frame_count * stream->frame_size != (size_t)(st.st_size) - stream->headlen)
24 eprintf("%s: given the select width and height, "
25 "the file has an incomplete frame\n", stream->file);
26 if (frames_auto)
27 stream->frames = frame_count;
28 else if (stream->frames != frame_count)
29 eprintf("%s: frame count mismatch\n", stream->file);
30
31 SPRINTF_HEAD_ZN(head, stream->frames, stream->width, stream->height, stream->pixfmt, &headlen);
32
33 length = stream->frames * stream->frame_size;
34 if (length > (size_t)SSIZE_MAX || (size_t)headlen > (size_t)SSIZE_MAX - length)
35 eprintf("%s: video is too long\n", stream->file);
36
37 if ((size_t)headlen > stream->headlen)
38 if (ftruncate(stream->fd, (off_t)length + (off_t)headlen))
39 eprintf("ftruncate %s:", stream->file);
40
41 data = mmap(0, length + (size_t)headlen, PROT_READ | PROT_WRITE, MAP_SHARED, stream->fd, 0);
42 if (data == MAP_FAILED)
43 eprintf("mmap %s:", stream->file);
44 if ((size_t)headlen != stream->headlen)
45 memmove(data + headlen, data + stream->headlen, length);
46 memcpy(data, head, (size_t)headlen);
47 munmap(data, length + (size_t)headlen);
48
49 if ((size_t)headlen < stream->headlen)
50 if (ftruncate(stream->fd, (off_t)length + (off_t)headlen))
51 eprintf("ftruncate %s:", stream->file);
52 }
53
54 int
55 main(int argc, char *argv[])
56 {
57 struct stream stream;
58 int headless = 0, frames_auto = 0;
59
60 ARGBEGIN {
61 case 'h':
62 headless = 1;
63 break;
64 default:
65 usage();
66 } ARGEND;
67
68 if (headless) {
69 if (argc != 5)
70 eprintf("all positional arguments are mandatory unless -h is used\n");
71 } else if (argc != 1 && argc != 2 && argc != 4 && argc != 5) {
72 usage();
73 }
74
75 memset(&stream, 0, sizeof(stream));
76 stream.file = argv[0];
77 stream.fd = eopen(stream.file, O_RDWR);
78 if (!headless)
79 einit_stream(&stream);
80
81 if (argc < 2 || !strcmp(argv[1], "auto"))
82 frames_auto = 1;
83 else
84 stream.frames = etozu_arg("the frame count", argv[1], 0, SIZE_MAX);
85
86 if (argc < 4);
87 else if (strcmp(argv[2], "same"))
88 stream.width = etozu_arg("the width", argv[2], 1, SIZE_MAX);
89 else if (headless)
90 eprintf("cannot use both 'same' and -h\n");
91
92 if (argc < 4);
93 else if (strcmp(argv[3], "same"))
94 stream.height = etozu_arg("the height", argv[3], 1, SIZE_MAX);
95 else if (headless)
96 eprintf("cannot use both 'same' and -h\n");
97
98 if (argc < 5);
99 else if (strcmp(argv[4], "same")) {
100 if (strlen(argv[4]) >= sizeof(stream.pixfmt))
101 eprintf("choosen pixel format is unsupported\n");
102 if (set_pixel_format(&stream, argv[5]))
103 eprintf("choosen pixel format is unsupported\n");
104 } else if (headless) {
105 eprintf("cannot use both 'same' and -h\n");
106 }
107
108 rewrite(&stream, frames_auto);
109 close(stream.fd);
110 return 0;
111 }