blind

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

blind-translate.c (4130B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include "common.h"
      3 
      4 USAGE("[-wp] translation-stream")
      5 
      6 static int invtrans = 0;
      7 static char zeroes[BUFSIZ];
      8 
      9 static void*
     10 next_pixel(struct stream *stream, size_t *ptr)
     11 {
     12 	void *ret;
     13 	if (*ptr + stream->pixel_size >= stream->ptr) {
     14 		memmove(stream->buf, stream->buf + *ptr, stream->ptr -= *ptr);
     15 		*ptr = 0;
     16 		while (stream->ptr < stream->pixel_size)
     17 			if (!eread_stream(stream, SIZE_MAX))
     18 				return NULL;
     19 	}
     20 	ret = stream->buf + *ptr;
     21 	*ptr += stream->pixel_size;
     22 	return ret;
     23 }
     24 
     25 static int
     26 process_frame(struct stream *stream, char *buf, size_t above, size_t below, size_t left, size_t right)
     27 {
     28 #define ZEROES(N) ewritezeroes(STDOUT_FILENO, zeroes, sizeof(zeroes), N, "<stdout>")
     29 
     30 	size_t i, w = stream->row_size - left - right;
     31 	int first = 1;
     32 
     33 	if (!eread_row(stream, buf))
     34 		return 0;
     35 
     36 	for (i = 0; i < above; i++)
     37 		ZEROES(stream->row_size);
     38 	for (i = 0; i < below; i++, first = 0)
     39 		if (!first && !eread_row(stream, buf))
     40 			goto eof;
     41 
     42 	for (i = above + below; i < stream->height; i++, first = 0) {
     43 		if (!first && !eread_row(stream, buf))
     44 			goto eof;
     45 		ZEROES((size_t)left);
     46 		ewriteall(STDOUT_FILENO, buf + right, w, "<stdout>");
     47 		ZEROES((size_t)right);
     48 	}
     49 
     50 	for (i = 0; i < below; i++)
     51 		ZEROES(stream->row_size);
     52 	for (i = 0; i < above; i++, first = 0)
     53 		if (!first && !eread_row(stream, buf))
     54 			goto eof;
     55 
     56 	return 1;
     57 eof:
     58 	eprintf("%s: file is shorter than expected\n", stream->file);
     59 }
     60 
     61 static void
     62 process(struct stream *stream, struct stream *trstream)
     63 {
     64 	char *buf;
     65 	size_t p = 0;
     66 	double *trans, tmp;
     67 	ssize_t trx = 0, try = 0;
     68 	size_t above = 0, below = 0, left = 0, right = 0;
     69 
     70 	memset(zeroes, 0, sizeof(zeroes));
     71 
     72 	echeck_dimensions(stream, WIDTH, NULL);
     73 	buf = emalloc(stream->row_size);
     74 
     75 	do {
     76 		if ((trans = next_pixel(trstream, &p))) {
     77 			trx = (ssize_t)(tmp = round(invtrans ? -trans[0] : trans[0]));
     78 			try = (ssize_t)(tmp = round(invtrans ? -trans[1] : trans[1]));
     79 
     80 			above =  try > 0 ? (size_t)try  : 0;
     81 			below =  try < 0 ? (size_t)-try : 0;
     82 			left  = (trx > 0 ? (size_t)trx  : 0) * stream->pixel_size;
     83 			right = (trx < 0 ? (size_t)-trx : 0) * stream->pixel_size;
     84 
     85 			above = MIN(above, stream->height);
     86 			below = MIN(below, stream->height);
     87 			left  = MIN(left,  stream->row_size);
     88 			right = MIN(right, stream->row_size);
     89 		}
     90 	} while (process_frame(stream, buf, above, below, left, right));
     91 
     92 	free(buf);
     93 }
     94 
     95 static void
     96 process_wrap(struct stream *stream, struct stream *trstream)
     97 {
     98 	char *buf, *row;
     99 	size_t p = 0;
    100 	double *trans, tmp;
    101 	ssize_t trx = 0, try = 0, py;
    102 	size_t off = 0, y;
    103 
    104 	echeck_dimensions(stream, WIDTH | HEIGHT, NULL);
    105 	buf = emalloc(stream->frame_size);
    106 
    107 	while (eread_frame(stream, buf)) {
    108 		if ((trans = next_pixel(trstream, &p))) {
    109 			trx = (ssize_t)(tmp = round(invtrans ? -trans[0] : trans[0]));
    110 			try = (ssize_t)(tmp = round(invtrans ? -trans[1] : trans[1]));
    111 			trx %= (ssize_t)stream->width;
    112 			if (trx < 0)
    113 				trx += (ssize_t)stream->width;
    114 			off = (stream->width - (size_t)trx) % stream->width;
    115 			off = off * stream->pixel_size;
    116 		}
    117 
    118 		for (y = 0; y < stream->height; y++) {
    119 			py = ((ssize_t)y - try) % (ssize_t)stream->height;
    120 			if (py < 0)
    121 				py += (ssize_t)stream->height;
    122 			row = buf + (size_t)py * stream->row_size;
    123 			ewriteall(STDOUT_FILENO, row + off, stream->row_size - off, "<stdout>");
    124 			ewriteall(STDOUT_FILENO, row, off, "<stdout>");
    125 		}
    126 	}
    127 
    128 	free(buf);
    129 }
    130 
    131 int
    132 main(int argc, char *argv[])
    133 {
    134 	struct stream stream;
    135 	struct stream trstream;
    136 	int wrap = 0;
    137 
    138 	ARGBEGIN {
    139 	case 'w':
    140 		wrap = 1;
    141 		break;
    142 	case 'p':
    143 		invtrans = 1;
    144 		break;
    145 	default:
    146 		usage();
    147 	} ARGEND;
    148 
    149 	if (argc != 1)
    150 		usage();
    151 
    152 	eopen_stream(&stream, NULL);
    153 	eopen_stream(&trstream, argv[0]);
    154 
    155 	if (trstream.width != 1 || trstream.height != 1)
    156 		eprintf("translation-stream does not have 1x1 geometry\n");
    157 
    158 	if (strcmp(trstream.pixfmt, "xyza"))
    159 		eprintf("pixel format of translation-stream %s "
    160 			"is not supported, try xyza\n", trstream.pixfmt);
    161 
    162 	fprint_stream_head(stdout, &stream);
    163 	efflush(stdout, "<stdout>");
    164 
    165 	(wrap ? process_wrap : process)(&stream, &trstream);
    166 	close(trstream.fd);
    167 	return 0;
    168 }