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 }