blind

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

blind-convert.c (12962B)


      1 /* See LICENSE file for copyright and license details. */
      2 #include "common.h"
      3 
      4 USAGE("pixel-format ...")
      5 
      6 static int in_level = INT_MAX;
      7 static int out_level = INT_MAX;
      8 
      9 static void
     10 lf_to_f(double *in, float *out, size_t n)
     11 {
     12 	size_t i;
     13 	for (i = 0; i < n; i++)
     14 		out[i] = (float)(in[i]);
     15 }
     16 
     17 static void
     18 f_to_lf(double *in, float *out, size_t n)
     19 {
     20 	size_t i;
     21 	for (i = 0; i < n; i++)
     22 		out[i] = (double)(in[i]);
     23 }
     24 
     25 #if !defined(HOST_ENDIAN_IS_LITTLE_ENDIAN_16)
     26 static void
     27 le_to_h_16(uint16_t *buf, size_t n)
     28 {
     29 	size_t i;
     30 	for (i = 0; i < n; i++)
     31 		buf[i] = letoh(buf[i]);
     32 }
     33 
     34 static void
     35 h_to_le_16(uint16_t *buf, size_t n)
     36 {
     37 	size_t i;
     38 	for (i = 0; i < n; i++)
     39 		buf[i] = htole(buf[i]);
     40 }
     41 #else
     42 # define le_to_h_16(buf, n) ((void) buf, (void) n)
     43 # define h_to_le_16(buf, n) ((void) buf, (void) n)
     44 #endif
     45 
     46 static size_t
     47 remove_alpha_u16(uint16_t *buf, size_t n)
     48 {
     49 	size_t i, j;
     50 	long int a, max = (long int)0xFF00L, ymax = 0xDAF4L;
     51 	for (i = j = 0; i < n; i += 4, j += 3) {
     52 		a = (long int)(buf[i + 3]);
     53 		buf[j + 0] = (uint16_t)(((long int)(buf[i + 0]) - 0x1001L) * a / ymax + 0x1001L);
     54 		buf[j + 1] = (uint16_t)(((long int)(buf[i + 1]) - 0x8000L) * a /  max + 0x8000L);
     55 		buf[j + 2] = (uint16_t)(((long int)(buf[i + 2]) - 0x8000L) * a /  max + 0x8000L);
     56 	}
     57 	return j;
     58 }
     59 
     60 #define REMOVE_ALPHA()\
     61 	do {\
     62 		size_t i, j;\
     63 		for (i = j = 0; i < n; i += 4, j += 3) {\
     64 			buf[j + 0] = buf[i + 0] * buf[i + 3];\
     65 			buf[j + 1] = buf[i + 1] * buf[i + 3];\
     66 			buf[j + 2] = buf[i + 2] * buf[i + 3];\
     67 		}\
     68 		return j;\
     69 	} while (0)
     70 
     71 static size_t remove_alpha_lf(double *buf, size_t n) { REMOVE_ALPHA(); }
     72 static size_t remove_alpha_f (float  *buf, size_t n) { REMOVE_ALPHA(); }
     73 
     74 #define ADD_ALPHA(TYPE, MAX)\
     75 	do {\
     76 		size_t i = n, j = n + n / 3;\
     77 		for (; i; i -= 3, j -= 4) {\
     78 			out[j - 1] = (TYPE)(MAX);\
     79 			out[j - 2] = in[i - 1];\
     80 			out[j - 3] = in[i - 2];\
     81 			out[j - 4] = in[i - 3];\
     82 		}\
     83 		return n + n / 3;\
     84 	} while (0)
     85 
     86 static size_t add_alpha_u16(uint16_t *in, uint16_t *out, size_t n) { ADD_ALPHA(uint16_t, UINT16_MAX); }
     87 static size_t add_alpha_lf (double   *in, double   *out, size_t n) { ADD_ALPHA(double,   1); }
     88 static size_t add_alpha_f  (float    *in, float    *out, size_t n) { ADD_ALPHA(float,    1); }
     89 
     90 static void
     91 raw0_to_raw1(uint16_t *buf, size_t n)
     92 {
     93 	size_t i;
     94 	uint16_t t;
     95 	for (i = 0; i < n; i += 4, buf += 4)
     96 		t = buf[0], buf[0] = buf[1], buf[1] = buf[2], buf[2] = buf[3], buf[3] = t;
     97 }
     98 
     99 static void
    100 raw1_to_raw0(uint16_t *buf, size_t n)
    101 {
    102 	size_t i;
    103 	uint16_t t;
    104 	for (i = 0; i < n; i += 4, buf += 4)
    105 		t = buf[3], buf[3] = buf[2], buf[2] = buf[1], buf[1] = buf[0], buf[0] = t;
    106 }
    107 
    108 #define RAW2_TO_RAW3(TYPE, WITH_ALPHA)\
    109 	do {\
    110 		size_t i;\
    111 		TYPE max = (TYPE)0xFF00L, ymax = (TYPE)0xDAF4L;\
    112 		if (sizeof(*in) > sizeof(*out)) {\
    113 			for (i = 0; i < n; i += 3 + WITH_ALPHA) {\
    114 				out[i + 0] = (TYPE)((long int)(in[i + 0]) - 0x1001L) / ymax;\
    115 				out[i + 1] = (TYPE)((long int)(in[i + 1]) - 0x8000L) /  max;\
    116 				out[i + 2] = (TYPE)((long int)(in[i + 2]) - 0x8000L) /  max;\
    117 				if (WITH_ALPHA) {\
    118 					out[i + 3] = (TYPE)(in[i + 3]) / max;\
    119 					out[i + 3] = CLIP(0, out[i + 3], 1);\
    120 				}\
    121 			}\
    122 		} else {\
    123 			for (i = n; i; i -= 3 + WITH_ALPHA) {\
    124 				if (WITH_ALPHA) {\
    125 					out[i - 1] = (TYPE)(in[i - 1]) / max;\
    126 					out[i - 1] = CLIP(0, out[i - 1], 1);\
    127 				}\
    128 				out[i - 1 - WITH_ALPHA] = (TYPE)((long int)(in[i - 1 - WITH_ALPHA]) - 0x8000L) /  max;\
    129 				out[i - 2 - WITH_ALPHA] = (TYPE)((long int)(in[i - 2 - WITH_ALPHA]) - 0x8000L) /  max;\
    130 				out[i - 3 - WITH_ALPHA] = (TYPE)((long int)(in[i - 3 - WITH_ALPHA]) - 0x1001L) / ymax;\
    131 			}\
    132 		}\
    133 	} while (0)
    134 
    135 static void raw2_to_raw3_lf  (uint16_t *in, double *out, size_t n) { RAW2_TO_RAW3(double, 0); }
    136 static void raw2_to_raw3_f   (uint16_t *in, float  *out, size_t n) { RAW2_TO_RAW3(float,  0); }
    137 static void raw2a_to_raw3a_lf(uint16_t *in, double *out, size_t n) { RAW2_TO_RAW3(double, 1); }
    138 static void raw2a_to_raw3a_f (uint16_t *in, float  *out, size_t n) { RAW2_TO_RAW3(float,  1); }
    139 
    140 #define RAW3_TO_RAW2(TYPE, WITH_ALPHA)\
    141 	do {\
    142 		size_t i;\
    143 		TYPE max = (TYPE)0xFF00L, ymax = (TYPE)0xDAF4L;\
    144 		long int y, u, v;\
    145 		if (sizeof(*in) > sizeof(*out)) {\
    146 			for (i = 0; i < n; i += 3 + WITH_ALPHA) {\
    147 				y = (long int)(in[i + 0] * ymax) + 0x1001L;\
    148 				u = (long int)(in[i + 1] *  max) + 0x8000L;\
    149 				v = (long int)(in[i + 2] *  max) + 0x8000L;\
    150 				out[i + 0] = (uint16_t)CLIP(0, y, 0xFFFFL);\
    151 				out[i + 1] = (uint16_t)CLIP(0, u, 0xFFFFL);\
    152 				out[i + 2] = (uint16_t)CLIP(0, v, 0xFFFFL);\
    153 				if (WITH_ALPHA) {\
    154 					v = (long int)(in[i + 3] * max);\
    155 					out[i + 3] = (uint16_t)CLIP(0, v, 0xFFFFL);\
    156 				}\
    157 			}\
    158 		} else {\
    159 			for (i = n; i; i -= 3 + WITH_ALPHA) {\
    160 				if (WITH_ALPHA) {\
    161 					v = (long int)(in[i - 1] * max);\
    162 					out[i - 1] = (uint16_t)CLIP(0, v, 0xFFFFL); \
    163 				}\
    164 				v = (long int)(in[i - 1 - WITH_ALPHA] *  max) + 0x8000L;\
    165 				u = (long int)(in[i - 2 - WITH_ALPHA] *  max) + 0x8000L;\
    166 				y = (long int)(in[i - 3 - WITH_ALPHA] * ymax) + 0x1001L;\
    167 				out[i - 1 - WITH_ALPHA] = (uint16_t)CLIP(0, v, 0xFFFFL);\
    168 				out[i - 2 - WITH_ALPHA] = (uint16_t)CLIP(0, u, 0xFFFFL);\
    169 				out[i - 3 - WITH_ALPHA] = (uint16_t)CLIP(0, y, 0xFFFFL);\
    170 			}\
    171 		}\
    172 	} while (0)
    173 
    174 static void raw3_to_raw2_lf  (double *in, uint16_t *out, size_t n) { RAW3_TO_RAW2(double, 0); }
    175 static void raw3_to_raw2_f   (float  *in, uint16_t *out, size_t n) { RAW3_TO_RAW2(float,  0); }
    176 static void raw3a_to_raw2a_lf(double *in, uint16_t *out, size_t n) { RAW3_TO_RAW2(double, 1); }
    177 static void raw3a_to_raw2a_f (float  *in, uint16_t *out, size_t n) { RAW3_TO_RAW2(float,  1); }
    178 
    179 #define CONVERT_COLOUR_SPACE(TYPE, CONV)\
    180 	do {\
    181 		size_t i, s = 3 + (size_t)a;\
    182 		for (i = 0; i < n; i += s)\
    183 			CONV(buf[i + 0], buf[i + 1], buf[i + 2], buf + i + 0, buf + i + 1, buf + i + 2);\
    184 	} while (0)
    185 
    186 static void conv_yuv_to_srgb_lf(double *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(double, yuv_to_srgb); }
    187 static void conv_yuv_to_srgb_f (float  *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(float,  yuv_to_srgb); }
    188 static void conv_srgb_to_yuv_lf(double *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(double, srgb_to_yuv); }
    189 static void conv_srgb_to_yuv_f (float  *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(float,  srgb_to_yuv); }
    190 static void conv_xyz_to_srgb_lf(double *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(double, ciexyz_to_srgb); }
    191 static void conv_xyz_to_srgb_f (float  *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(float,  ciexyz_to_srgb); }
    192 static void conv_srgb_to_xyz_lf(double *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(double, srgb_to_ciexyz); }
    193 static void conv_srgb_to_xyz_f (float  *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(float,  srgb_to_ciexyz); }
    194 
    195 #define CHANGE_TRANSFER(TYPE, CONV)\
    196 	do {\
    197 		size_t i, s = 3 + (size_t)a;\
    198 		for (i = 0; i < n; i += s) {\
    199 			buf[i + 0] = CONV(buf[i + 0]);\
    200 			buf[i + 1] = CONV(buf[i + 1]);\
    201 			buf[i + 2] = CONV(buf[i + 2]);\
    202 		}\
    203 	} while (0)
    204 
    205 static void conv_srgbt_to_srgb_lf(double *buf, size_t n, int a) { CHANGE_TRANSFER(double, srgb_decode); }
    206 static void conv_srgbt_to_srgb_f (float  *buf, size_t n, int a) { CHANGE_TRANSFER(float,  srgb_decode); }
    207 static void conv_srgb_to_srgbt_lf(double *buf, size_t n, int a) { CHANGE_TRANSFER(double, srgb_encode); }
    208 static void conv_srgb_to_srgbt_f (float  *buf, size_t n, int a) { CHANGE_TRANSFER(float,  srgb_encode); }
    209 
    210 #define CONVERT_COLOUR_SPACE_AUTO(CONV)\
    211 	static void\
    212 	conv_##CONV(enum encoding encoding, int with_alpha, void *buf, size_t n)\
    213 	{\
    214 		if (encoding == DOUBLE)\
    215 			conv_##CONV##_lf(buf, n, !!with_alpha);\
    216 		else\
    217 			conv_##CONV##_f(buf, n, !!with_alpha);\
    218 	}
    219 CONVERT_COLOUR_SPACE_AUTO(yuv_to_srgb)
    220 CONVERT_COLOUR_SPACE_AUTO(srgb_to_yuv)
    221 CONVERT_COLOUR_SPACE_AUTO(xyz_to_srgb)
    222 CONVERT_COLOUR_SPACE_AUTO(srgb_to_xyz)
    223 CONVERT_COLOUR_SPACE_AUTO(srgbt_to_srgb)
    224 CONVERT_COLOUR_SPACE_AUTO(srgb_to_srgbt)
    225 
    226 static void
    227 convert(struct stream *stream, struct stream *out, void *buf, size_t n)
    228 {
    229 	enum encoding encoding = stream->encoding;
    230 
    231 	if (in_level <= 0 && out_level > 0)
    232 		raw0_to_raw1(buf, n);
    233 
    234 	if (in_level <= 1 && out_level > 1)
    235 		le_to_h_16(buf, n);
    236 
    237 	if (in_level <= 2 && out_level > 2) {
    238 		if (out->encoding == DOUBLE && stream->alpha)
    239 			raw2a_to_raw3a_lf(buf, buf, n);
    240 		else if (out->encoding == FLOAT && stream->alpha)
    241 			raw2a_to_raw3a_f(buf, buf, n);
    242 		else if (out->encoding == DOUBLE)
    243 			raw2_to_raw3_lf(buf, buf, n);
    244 		else if (out->encoding == FLOAT)
    245 			raw2_to_raw3_f(buf, buf, n);
    246 		encoding = out->encoding;
    247 	} else if (stream->encoding == FLOAT && out->encoding == DOUBLE) {
    248 		f_to_lf(buf, buf, n);
    249 		encoding = out->encoding;
    250 	} else if (stream->encoding == DOUBLE && out->encoding == FLOAT) {
    251 		lf_to_f(buf, buf, n);
    252 		encoding = out->encoding;
    253 	}
    254 
    255 	if (stream->alpha && !out->alpha) {
    256 		if (encoding == DOUBLE)
    257 			n = remove_alpha_lf(buf, n);
    258 		else if (encoding == FLOAT)
    259 			n = remove_alpha_f(buf, n);
    260 		else
    261 			n = remove_alpha_u16(buf, n);
    262 	} else if (!stream->alpha && out->alpha) {
    263 		if (encoding == DOUBLE)
    264 			n = add_alpha_lf(buf, buf, n);
    265 		else if (encoding == FLOAT)
    266 			n = add_alpha_f(buf, buf, n);
    267 		else
    268 			n = add_alpha_u16(buf, buf, n);
    269 	}
    270 
    271 	if (stream->space == CIEXYZ && out->space == YUV_NONLINEAR) {
    272 		conv_xyz_to_srgb(encoding, out->alpha, buf, n);
    273 		conv_srgb_to_srgbt(encoding, out->alpha, buf, n);
    274 		conv_srgb_to_yuv(encoding, out->alpha, buf, n);
    275 	} else if (stream->space == CIEXYZ && out->space == SRGB_NONLINEAR) {
    276 		conv_xyz_to_srgb(encoding, out->alpha, buf, n);
    277 		conv_srgb_to_srgbt(encoding, out->alpha, buf, n);
    278 	} else if (stream->space == CIEXYZ && out->space == SRGB) {
    279 		conv_xyz_to_srgb(encoding, out->alpha, buf, n);
    280 	} else if (stream->space == YUV_NONLINEAR && out->space == CIEXYZ) {
    281 		conv_yuv_to_srgb(encoding, out->alpha, buf, n);
    282 		conv_srgbt_to_srgb(encoding, out->alpha, buf, n);
    283 		conv_srgb_to_xyz(encoding, out->alpha, buf, n);
    284 	} else if (stream->space == YUV_NONLINEAR && out->space == SRGB_NONLINEAR) {
    285 		conv_yuv_to_srgb(encoding, out->alpha, buf, n);
    286 	} else if (stream->space == YUV_NONLINEAR && out->space == SRGB) {
    287 		conv_yuv_to_srgb(encoding, out->alpha, buf, n);
    288 		conv_srgbt_to_srgb(encoding, out->alpha, buf, n);
    289 	} else if (stream->space == SRGB_NONLINEAR && out->space == CIEXYZ) {
    290 		conv_srgbt_to_srgb(encoding, out->alpha, buf, n);
    291 		conv_srgb_to_xyz(encoding, out->alpha, buf, n);
    292 	} else if (stream->space == SRGB_NONLINEAR && out->space == YUV_NONLINEAR) {
    293 		conv_srgb_to_yuv(encoding, out->alpha, buf, n);
    294 	} else if (stream->space == SRGB_NONLINEAR && out->space == SRGB) {
    295 		conv_srgbt_to_srgb(encoding, out->alpha, buf, n);
    296 	} else if (stream->space == SRGB && out->space == CIEXYZ) {
    297 		conv_srgb_to_xyz(encoding, out->alpha, buf, n);
    298 	} else if (stream->space == SRGB && out->space == YUV_NONLINEAR) {
    299 		conv_srgb_to_srgbt(encoding, out->alpha, buf, n);
    300 		conv_srgb_to_yuv(encoding, out->alpha, buf, n);
    301 	} else if (stream->space == SRGB && out->space == SRGB_NONLINEAR) {
    302 		conv_srgb_to_srgbt(encoding, out->alpha, buf, n);
    303 	}
    304 
    305 	if (out_level <= 2 && in_level > 2) {
    306 		if (encoding == DOUBLE && out->alpha)
    307 			raw3a_to_raw2a_lf(buf, buf, n);
    308 		else if (encoding == FLOAT && out->alpha)
    309 			raw3a_to_raw2a_f(buf, buf, n);
    310 		else if (encoding == DOUBLE)
    311 			raw3_to_raw2_lf(buf, buf, n);
    312 		else if (encoding == FLOAT)
    313 			raw3_to_raw2_f(buf, buf, n);
    314 	}
    315 
    316 	if (out_level <= 1 && in_level > 1)
    317 		h_to_le_16(buf, n);
    318 
    319 	if (out_level <= 0 && in_level > 0)
    320 		raw1_to_raw0(buf, n);
    321 
    322 	ewriteall(STDOUT_FILENO, buf, n * out->chan_size, "<stdout>");
    323 }
    324 
    325 int
    326 main(int argc, char *argv[])
    327 {
    328 	struct stream stream, out;
    329 	const char *pixfmt;
    330 	void *buf = NULL;
    331 	size_t n;
    332 
    333 	UNOFLAGS(!argc);
    334 
    335 	eopen_stream(&stream, NULL);
    336 
    337 	memcpy(&out, &stream, sizeof(out));
    338 	pixfmt = stream.pixfmt;
    339 	while (*argv)
    340 		pixfmt = get_pixel_format(*argv++, pixfmt);
    341 	strcpy(out.pixfmt, pixfmt);
    342 	if (set_pixel_format(&out, NULL))
    343 		eprintf("output pixel format %s is not supported\n", pixfmt);
    344 
    345 	fprint_stream_head(stdout, &out);
    346 	efflush(stdout, "<stdout>");
    347 
    348 	if (!strcmp(stream.pixfmt, out.pixfmt)) {
    349 		esend_stream(&stream, STDOUT_FILENO, "<stdout>");
    350 		return 0;
    351 	}
    352 
    353 	if (stream.alpha_chan == 0)
    354 		in_level = 0;
    355 	else if (stream.endian == LITTLE)
    356 		in_level = 1;
    357 	else if (stream.encoding == UINT16)
    358 		in_level = 2;
    359 	if (out.alpha_chan == 0)
    360 		out_level = 0;
    361 	else if (out.endian == LITTLE)
    362 		out_level = 1;
    363 	else if (out.encoding == UINT16)
    364 		out_level = 2;
    365 
    366 	if (out.encoding == UINT16)
    367 		out.encoding = stream.encoding;
    368 
    369 	n = MAX(stream.chan_size, out.chan_size) * MAX(stream.n_chan, out.n_chan);
    370 	if (n > stream.pixel_size)
    371 		buf = emalloc(sizeof(stream.buf) / stream.chan_size * n);
    372 
    373 	do {
    374 		n = stream.ptr / stream.pixel_size * stream.n_chan;
    375 		if (buf)
    376 			memcpy(buf, stream.buf, n * stream.chan_size);
    377 		convert(&stream, &out, buf ? buf : stream.buf, n);
    378 		n *= stream.chan_size;
    379 		memmove(stream.buf, stream.buf + n, stream.ptr -= n);
    380 	} while (eread_stream(&stream, SIZE_MAX));
    381 	if (stream.ptr)
    382 		eprintf("%s: incomplete frame\n", stream.file);
    383 
    384 	free(buf);
    385 	return 0;
    386 }