diff options
| author | Mattias Andrée <maandree@kth.se> | 2017-08-06 02:52:29 +0200 |
|---|---|---|
| committer | Mattias Andrée <maandree@kth.se> | 2017-08-06 02:52:29 +0200 |
| commit | b640dfad6fd5c0ae3a9bfdd9b4bd54e387b0cc51 (patch) | |
| tree | 8d1614209eeb045d071349cc2808958647509110 /src/blind-convert.c | |
| parent | Update todo (diff) | |
| download | blind-b640dfad6fd5c0ae3a9bfdd9b4bd54e387b0cc51.tar.gz blind-b640dfad6fd5c0ae3a9bfdd9b4bd54e387b0cc51.tar.bz2 blind-b640dfad6fd5c0ae3a9bfdd9b4bd54e387b0cc51.tar.xz | |
Update blind-convert to support unconverted output from ffmpeg and partially converted output
Signed-off-by: Mattias Andrée <maandree@kth.se>
Diffstat (limited to 'src/blind-convert.c')
| -rw-r--r-- | src/blind-convert.c | 398 |
1 files changed, 349 insertions, 49 deletions
diff --git a/src/blind-convert.c b/src/blind-convert.c index e0ffc0f..8f14367 100644 --- a/src/blind-convert.c +++ b/src/blind-convert.c @@ -3,80 +3,380 @@ USAGE("pixel-format ...") -static void (*outconv)(double *xyzas, size_t n); +static int in_level = INT_MAX; +static int out_level = INT_MAX; -#define INCONV(TYPE)\ +static void +lf_to_f(double *in, float *out, size_t n) +{ + size_t i; + for (i = 0; i < n; i++) + out[i] = (float)(in[i]); +} + +static void +f_to_lf(double *in, float *out, size_t n) +{ + size_t i; + for (i = 0; i < n; i++) + out[i] = (double)(in[i]); +} + +#if !defined(HOST_ENDIAN_IS_LITTLE_ENDIAN_16) +static void +le_to_h_16(uint16_t *buf, size_t n) +{ + size_t i; + for (i = 0; i < n; i++) + buf[i] = letoh(buf[i]); +} + +static void +h_to_le_16(uint16_t *buf, size_t n) +{ + size_t i; + for (i = 0; i < n; i++) + buf[i] = htole(buf[i]); +} +#else +# define le_to_h_16(buf, n) ((void) buf, (void) n) +# define h_to_le_16(buf, n) ((void) buf, (void) n) +#endif + +static size_t +remove_alpha_u16(uint16_t *buf, size_t n) +{ + size_t i, j; + long int a, max = (long int)UINT16_MAX; + for (i = j = 0; i < n; i += 4, j += 3) { + a = (long int)(buf[i + 3]); + buf[j + 0] = (uint16_t)(((long int)(buf[i + 0]) - 16L * 256L) * a / max + 16L * 256L); + buf[j + 1] = (uint16_t)(((long int)(buf[i + 1]) - 128L * 256L) * a / max + 128L * 256L); + buf[j + 2] = (uint16_t)(((long int)(buf[i + 2]) - 128L * 256L) * a / max + 128L * 256L); + } + return j; +} + +#define REMOVE_ALPHA()\ + do {\ + size_t i, j;\ + for (i = j = 0; i < n; i += 4, j += 3) {\ + buf[j + 0] = buf[i + 0] * buf[i + 3];\ + buf[j + 1] = buf[i + 1] * buf[i + 3];\ + buf[j + 2] = buf[i + 2] * buf[i + 3];\ + }\ + return j;\ + } while (0) + +static size_t remove_alpha_lf(double *buf, size_t n) { REMOVE_ALPHA(); } +static size_t remove_alpha_f (float *buf, size_t n) { REMOVE_ALPHA(); } + +#define ADD_ALPHA(TYPE, MAX)\ + do {\ + size_t i = n, j = n + n / 3;\ + for (; i; i -= 3, j -= 4) {\ + out[j - 1] = (TYPE)(MAX);\ + out[j - 2] = in[i - 1];\ + out[j - 3] = in[i - 2];\ + out[j - 4] = in[i - 3];\ + }\ + return n + n / 3;\ + } while (0) + +static size_t add_alpha_u16(uint16_t *in, uint16_t *out, size_t n) { ADD_ALPHA(uint16_t, UINT16_MAX); } +static size_t add_alpha_lf (double *in, double *out, size_t n) { ADD_ALPHA(double, 1); } +static size_t add_alpha_f (float *in, float *out, size_t n) { ADD_ALPHA(float, 1); } + +static void +raw0_to_raw1(uint16_t *buf, size_t n) +{ + size_t i; + uint16_t t; + for (i = 0; i < n; i += 4, buf += 4) + t = buf[0], buf[0] = buf[1], buf[1] = buf[2], buf[2] = buf[3], buf[3] = t; +} + +static void +raw1_to_raw0(uint16_t *buf, size_t n) +{ + size_t i; + uint16_t t; + for (i = 0; i < n; i += 4, buf += 4) + t = buf[3], buf[3] = buf[2], buf[2] = buf[1], buf[1] = buf[0], buf[0] = t; +} + +#define RAW2_TO_RAW3(TYPE, WITH_ALPHA)\ + do {\ + size_t i;\ + TYPE max = (TYPE)UINT16_MAX;\ + if (sizeof(*in) > sizeof(*out)) {\ + for (i = 0; i < n; i += 3 + WITH_ALPHA) {\ + out[i + 0] = (TYPE)((long int)(in[i + 0]) - 16L * 256L) / max;\ + out[i + 1] = (TYPE)((long int)(in[i + 1]) - 128L * 256L) / max;\ + out[i + 2] = (TYPE)((long int)(in[i + 2]) - 128L * 256L) / max;\ + if (WITH_ALPHA)\ + out[i + 3] = (TYPE)(in[i + 3]) / max;\ + }\ + } else {\ + for (i = n; i; i -= 3 + WITH_ALPHA) {\ + if (WITH_ALPHA)\ + out[i - 1] = (TYPE)(in[i - 1]) / max;\ + out[i - 1 - WITH_ALPHA] = (TYPE)((long int)(in[i - 1 - WITH_ALPHA]) - 128L * 256L) / max;\ + out[i - 2 - WITH_ALPHA] = (TYPE)((long int)(in[i - 2 - WITH_ALPHA]) - 128L * 256L) / max;\ + out[i - 3 - WITH_ALPHA] = (TYPE)((long int)(in[i - 3 - WITH_ALPHA]) - 16L * 256L) / max;\ + }\ + }\ + } while (0) + +static void raw2_to_raw3_lf (uint16_t *in, double *out, size_t n) { RAW2_TO_RAW3(double, 0); } +static void raw2_to_raw3_f (uint16_t *in, float *out, size_t n) { RAW2_TO_RAW3(float, 0); } +static void raw2a_to_raw3a_lf(uint16_t *in, double *out, size_t n) { RAW2_TO_RAW3(double, 1); } +static void raw2a_to_raw3a_f (uint16_t *in, float *out, size_t n) { RAW2_TO_RAW3(float, 1); } + +#define RAW3_TO_RAW2(TYPE, WITH_ALPHA)\ do {\ - double buf[sizeof(stream->buf) / (4 * sizeof(TYPE)) * 4];\ - double *interm;\ - TYPE *in;\ - size_t n, m;\ - do {\ - in = (TYPE *)stream->buf;\ - interm = buf;\ - n = stream->ptr / stream->pixel_size;\ - for (m = n; m--; in += 4, interm += 4) { \ - interm[0] = (double)(in[0]);\ - interm[1] = (double)(in[1]);\ - interm[2] = (double)(in[2]);\ - interm[3] = (double)(in[3]);\ + size_t i;\ + TYPE max = (TYPE)UINT16_MAX;\ + long int y, u, v;\ + if (sizeof(*in) > sizeof(*out)) {\ + for (i = 0; i < n; i += 3 + WITH_ALPHA) {\ + y = (long int)(in[i + 0] * max) + 16L * 256L;\ + u = (long int)(in[i + 1] * max) + 128L * 256L;\ + v = (long int)(in[i + 2] * max) + 128L * 256L;\ + out[i + 0] = (uint16_t)CLIP(0, y, 0xFFFFL);\ + out[i + 1] = (uint16_t)CLIP(0, u, 0xFFFFL);\ + out[i + 2] = (uint16_t)CLIP(0, v, 0xFFFFL);\ + if (WITH_ALPHA) {\ + v = (long int)(in[i + 3] * max);\ + out[i + 3] = (uint16_t)CLIP(0, v, 0xFFFFL);\ + }\ + }\ + } else {\ + for (i = n; i; i -= 3 + WITH_ALPHA) {\ + if (WITH_ALPHA) {\ + v = (long int)(in[i - 1] * max);\ + out[i - 1] = (uint16_t)CLIP(0, v, 0xFFFFL); \ + }\ + v = (long int)(in[i - 1 - WITH_ALPHA] * max) + 128L * 256L;\ + u = (long int)(in[i - 2 - WITH_ALPHA] * max) + 128L * 256L;\ + y = (long int)(in[i - 3 - WITH_ALPHA] * max) + 16L * 256L;\ + out[i - 1 - WITH_ALPHA] = (uint16_t)CLIP(0, v, 0xFFFFL);\ + out[i - 2 - WITH_ALPHA] = (uint16_t)CLIP(0, u, 0xFFFFL);\ + out[i - 3 - WITH_ALPHA] = (uint16_t)CLIP(0, y, 0xFFFFL);\ }\ - outconv(buf, n);\ - n *= stream->pixel_size;\ - memmove(stream->buf, stream->buf + n, stream->ptr -= n);\ - } while (eread_stream(stream, SIZE_MAX));\ - if (stream->ptr)\ - eprintf("%s: incomplete frame\n", stream->file);\ + }\ } while (0) -#define OUTCONV(TYPE)\ +static void raw3_to_raw2_lf (double *in, uint16_t *out, size_t n) { RAW3_TO_RAW2(double, 0); } +static void raw3_to_raw2_f (float *in, uint16_t *out, size_t n) { RAW3_TO_RAW2(float, 0); } +static void raw3a_to_raw2a_lf(double *in, uint16_t *out, size_t n) { RAW3_TO_RAW2(double, 1); } +static void raw3a_to_raw2a_f (float *in, uint16_t *out, size_t n) { RAW3_TO_RAW2(float, 1); } + +#define CONVERT_COLOUR_SPACE(TYPE, CONV)\ do {\ - TYPE *out = alloca(n * 4 * sizeof(TYPE));\ - size_t i, m = n * 4;\ - for (i = 0; i < m; i++)\ - out[i] = (TYPE)(xyzas[i]);\ - ewriteall(STDOUT_FILENO, out, n * 4 * sizeof(TYPE), "<stdout>");\ + size_t i, s = 3 + (size_t)a;\ + for (i = 0; i < n; i += s)\ + CONV(buf[i + 0], buf[i + 1], buf[i + 2], buf + i + 0, buf + i + 1, buf + i + 2);\ } while (0) -static void inconv_xyza (struct stream *stream) {INCONV(double);} -static void inconv_xyzaf(struct stream *stream) {INCONV(float);} +static void conv_yuv_to_srgb_lf(double *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(double, yuv_to_srgb); } +static void conv_yuv_to_srgb_f (float *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(float, yuv_to_srgb); } +static void conv_srgb_to_yuv_lf(double *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(double, srgb_to_yuv); } +static void conv_srgb_to_yuv_f (float *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(float, srgb_to_yuv); } +static void conv_xyz_to_srgb_lf(double *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(double, ciexyz_to_srgb); } +static void conv_xyz_to_srgb_f (float *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(float, ciexyz_to_srgb); } +static void conv_srgb_to_xyz_lf(double *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(double, srgb_to_ciexyz); } +static void conv_srgb_to_xyz_f (float *buf, size_t n, int a) { CONVERT_COLOUR_SPACE(float, srgb_to_ciexyz); } + +#define CHANGE_TRANSFER(TYPE, CONV)\ + do {\ + size_t i, s = 3 + (size_t)a;\ + for (i = 0; i < n; i += s) {\ + buf[i + 0] = CONV(buf[i + 0]);\ + buf[i + 1] = CONV(buf[i + 1]);\ + buf[i + 2] = CONV(buf[i + 2]);\ + }\ + } while (0) + +static void conv_srgbt_to_srgb_lf(double *buf, size_t n, int a) { CHANGE_TRANSFER(double, srgb_decode); } +static void conv_srgbt_to_srgb_f (float *buf, size_t n, int a) { CHANGE_TRANSFER(float, srgb_decode); } +static void conv_srgb_to_srgbt_lf(double *buf, size_t n, int a) { CHANGE_TRANSFER(double, srgb_encode); } +static void conv_srgb_to_srgbt_f (float *buf, size_t n, int a) { CHANGE_TRANSFER(float, srgb_encode); } + +#define CONVERT_COLOUR_SPACE_AUTO(CONV)\ + static void\ + conv_##CONV(enum encoding encoding, int with_alpha, void *buf, size_t n)\ + {\ + if (encoding == DOUBLE)\ + conv_##CONV##_lf(buf, n, !!with_alpha);\ + else\ + conv_##CONV##_f(buf, n, !!with_alpha);\ + } +CONVERT_COLOUR_SPACE_AUTO(yuv_to_srgb) +CONVERT_COLOUR_SPACE_AUTO(srgb_to_yuv) +CONVERT_COLOUR_SPACE_AUTO(xyz_to_srgb) +CONVERT_COLOUR_SPACE_AUTO(srgb_to_xyz) +CONVERT_COLOUR_SPACE_AUTO(srgbt_to_srgb) +CONVERT_COLOUR_SPACE_AUTO(srgb_to_srgbt) + +static void +convert(struct stream *stream, struct stream *out, void *buf, size_t n) +{ + enum encoding encoding = stream->encoding; + + if (in_level <= 0 && out_level > 0) + raw0_to_raw1(buf, n); -static void outconv_xyza (double *xyzas, size_t n) {OUTCONV(double);} -static void outconv_xyzaf(double *xyzas, size_t n) {OUTCONV(float);} + if (in_level <= 1 && out_level > 1) + le_to_h_16(buf, n); + + if (in_level <= 2 && out_level > 2) { + if (out->encoding == DOUBLE && stream->alpha) + raw2a_to_raw3a_lf(buf, buf, n); + else if (out->encoding == FLOAT && stream->alpha) + raw2a_to_raw3a_f(buf, buf, n); + else if (out->encoding == DOUBLE) + raw2_to_raw3_lf(buf, buf, n); + else if (out->encoding == FLOAT) + raw2_to_raw3_f(buf, buf, n); + encoding = out->encoding; + } else if (stream->encoding == FLOAT && out->encoding == DOUBLE) { + f_to_lf(buf, buf, n); + encoding = out->encoding; + } else if (stream->encoding == DOUBLE && out->encoding == FLOAT) { + lf_to_f(buf, buf, n); + encoding = out->encoding; + } + + if (stream->alpha && !out->alpha) { + if (encoding == DOUBLE) + n = remove_alpha_lf(buf, n); + else if (encoding == FLOAT) + n = remove_alpha_f(buf, n); + else + n = remove_alpha_u16(buf, n); + } else if (!stream->alpha && out->alpha) { + if (encoding == DOUBLE) + n = add_alpha_lf(buf, buf, n); + else if (encoding == FLOAT) + n = add_alpha_f(buf, buf, n); + else + n = add_alpha_u16(buf, buf, n); + } + + if (stream->space == CIEXYZ && out->space == YUV_NONLINEAR) { + conv_xyz_to_srgb(encoding, out->alpha, buf, n); + conv_srgb_to_srgbt(encoding, out->alpha, buf, n); + conv_srgb_to_yuv(encoding, out->alpha, buf, n); + } else if (stream->space == CIEXYZ && out->space == SRGB_NONLINEAR) { + conv_xyz_to_srgb(encoding, out->alpha, buf, n); + conv_srgb_to_srgbt(encoding, out->alpha, buf, n); + } else if (stream->space == CIEXYZ && out->space == SRGB) { + conv_xyz_to_srgb(encoding, out->alpha, buf, n); + } else if (stream->space == YUV_NONLINEAR && out->space == CIEXYZ) { + conv_yuv_to_srgb(encoding, out->alpha, buf, n); + conv_srgbt_to_srgb(encoding, out->alpha, buf, n); + conv_srgb_to_xyz(encoding, out->alpha, buf, n); + } else if (stream->space == YUV_NONLINEAR && out->space == SRGB_NONLINEAR) { + conv_yuv_to_srgb(encoding, out->alpha, buf, n); + } else if (stream->space == YUV_NONLINEAR && out->space == SRGB) { + conv_yuv_to_srgb(encoding, out->alpha, buf, n); + conv_srgbt_to_srgb(encoding, out->alpha, buf, n); + } else if (stream->space == SRGB_NONLINEAR && out->space == CIEXYZ) { + conv_srgbt_to_srgb(encoding, out->alpha, buf, n); + conv_srgb_to_xyz(encoding, out->alpha, buf, n); + } else if (stream->space == SRGB_NONLINEAR && out->space == YUV_NONLINEAR) { + conv_srgb_to_yuv(encoding, out->alpha, buf, n); + } else if (stream->space == SRGB_NONLINEAR && out->space == SRGB) { + conv_srgbt_to_srgb(encoding, out->alpha, buf, n); + } else if (stream->space == SRGB && out->space == CIEXYZ) { + conv_srgb_to_xyz(encoding, out->alpha, buf, n); + } else if (stream->space == SRGB && out->space == YUV_NONLINEAR) { + conv_srgb_to_srgbt(encoding, out->alpha, buf, n); + conv_srgb_to_yuv(encoding, out->alpha, buf, n); + } else if (stream->space == SRGB && out->space == SRGB_NONLINEAR) { + conv_srgb_to_srgbt(encoding, out->alpha, buf, n); + } + + if (out_level <= 2 && in_level > 2) { + if (encoding == DOUBLE && out->alpha) + raw3a_to_raw2a_lf(buf, buf, n); + else if (encoding == FLOAT && out->alpha) + raw3a_to_raw2a_f(buf, buf, n); + else if (encoding == DOUBLE) + raw3_to_raw2_lf(buf, buf, n); + else if (encoding == FLOAT) + raw3_to_raw2_f(buf, buf, n); + } + + if (out_level <= 1 && in_level > 1) + h_to_le_16(buf, n); + + if (out_level <= 0 && in_level > 0) + raw1_to_raw0(buf, n); + + ewriteall(STDOUT_FILENO, buf, n * out->chan_size, "<stdout>"); +} int main(int argc, char *argv[]) { - struct stream stream; + struct stream stream, out; const char *pixfmt; - void (*inconv)(struct stream *stream); + void *buf = NULL; + size_t n; UNOFLAGS(!argc); eopen_stream(&stream, NULL); - if (!strcmp(stream.pixfmt, "xyza")) - inconv = inconv_xyza; - else if (!strcmp(stream.pixfmt, "xyza f")) - inconv = inconv_xyzaf; - else - eprintf("input pixel format %s is not supported\n", stream.pixfmt); - + memcpy(&out, &stream, sizeof(out)); pixfmt = stream.pixfmt; while (*argv) pixfmt = get_pixel_format(*argv++, pixfmt); - - if (!strcmp(pixfmt, "xyza")) - outconv = outconv_xyza; - else if (!strcmp(pixfmt, "xyza f")) - outconv = outconv_xyzaf; - else + strcpy(out.pixfmt, pixfmt); + if (set_pixel_format(&out, NULL)) eprintf("output pixel format %s is not supported\n", pixfmt); - strcpy(stream.pixfmt, pixfmt); - fprint_stream_head(stdout, &stream); + fprint_stream_head(stdout, &out); efflush(stdout, "<stdout>"); - inconv(&stream); + if (!strcmp(stream.pixfmt, out.pixfmt)) { + esend_stream(&stream, STDOUT_FILENO, "<stdout>"); + return 0; + } + + if (stream.alpha_chan == 0) + in_level = 0; + else if (stream.endian == LITTLE) + in_level = 1; + else if (stream.encoding == UINT16) + in_level = 2; + if (out.alpha_chan == 0) + out_level = 0; + else if (out.endian == LITTLE) + out_level = 1; + else if (out.encoding == UINT16) + out_level = 2; + + if (out.encoding == UINT16) + out.encoding = stream.encoding; + + n = MAX(stream.chan_size, out.chan_size) * MAX(stream.n_chan, out.n_chan); + if (n > stream.pixel_size) + buf = emalloc(sizeof(stream.buf) / stream.chan_size * n); + + do { + n = stream.ptr / stream.pixel_size * stream.n_chan; + if (buf) + memcpy(buf, stream.buf, n * stream.chan_size); + convert(&stream, &out, buf ? buf : stream.buf, n); + n *= stream.chan_size; + memmove(stream.buf, stream.buf + n, stream.ptr -= n); + } while (eread_stream(&stream, SIZE_MAX)); + if (stream.ptr) + eprintf("%s: incomplete frame\n", stream.file); + + free(buf); return 0; } |
