blind-convert.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-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 }