30 typedef enum {
false = 0,
true = 1 }
bool;
39 #include <sys/types.h>
51 typedef int8_t
ei8;
typedef uint8_t
eu8;
55 typedef int_least8_t
li8;
typedef uint_least8_t
lu8;
56 typedef int_least16_t
li16;
typedef uint_least16_t
lu16;
57 typedef int_least32_t
li32;
typedef uint_least32_t
lu32;
59 typedef int_fast8_t
fi8;
typedef uint_fast8_t
fu8;
60 typedef int_fast16_t
fi16;
typedef uint_fast16_t
fu16;
61 typedef int_fast32_t
fi32;
typedef uint_fast32_t
fu32;
66 #define GCCATTR_PRINTF(m, n) __attribute__ ((format (printf, m, n)))
67 #define GCCATTR_UNUSED __attribute ((unused))
68 #define GCCATTR_NORETURN __attribute ((noreturn))
69 #define GCCATTR_CONST __attribute ((const))
71 #define GCCATTR_PRINTF(m, n)
72 #define GCCATTR_UNUSED
73 #define GCCATTR_NORETURN
78 #define CUS (const unsigned char *)
86 int sup2dast(
const char *supfile,
const char *ifofile,
int delay_ms);
103 #define exc_try do { struct exc__state exc_s; int exc_type GCCATTR_UNUSED; \
104 exc_s.prev = EXC.last; EXC.last = &exc_s; if ((exc_type = setjmp(exc_s.env)) == 0)
106 #define exc_ftry do { struct exc__state exc_s, *exc_p = EXC.last; \
107 int exc_type GCCATTR_UNUSED; exc_s.prev = EXC.last; \
108 EXC.last = &exc_s; if ((exc_type = setjmp(exc_s.env)) == 0)
110 #define exc_catch(t) else if (t == exc_type)
112 #define exc_end else __exc_throw(exc_type); EXC.last = exc_s.prev; } while (0)
114 #define exc_return for (EXC.last = exc_p;;) return
116 #define exc_fthrow for (EXC.last = exc_p;;) ex_throw
118 #define exc_catchall else
119 #define exc_endall EXC.last = exc_s.prev; } while (0)
125 EXC.last =
EXC.last->prev;
126 longjmp(exc_s->
env, type);
138 va_start(ap, format);
139 len = vsnprintf(
EXC.msgbuf,
sizeof EXC.msgbuf, format, ap);
142 if (len >=
sizeof EXC.msgbuf)
144 len =
sizeof EXC.msgbuf - 1;
149 if (format[strlen(format) - 1] ==
':')
151 int l = snprintf(&
EXC.msgbuf[len],
sizeof EXC.msgbuf - len,
152 " %s.", strerror(err));
153 if (l + len >=
sizeof EXC.msgbuf)
155 len =
sizeof EXC.msgbuf - 1;
166 EXC.msgbuf[0] =
'\0';
178 size_t n = fread(ptr, size, 1, stream);
189 size_t n = fwrite(ptr, size, 1, stream);
198 #define xxfwriteCS(f, s) xxfwrite(f, CUS s, sizeof s - 1)
206 lr = (500 + 1164 * (y - 16) + 1596 * (cr - 128) ) /1000;
207 lg = (500 + 1164 * (y - 16) - 813 * (cr - 128) - 391 * (cb - 128)) / 1000;
208 lb = (500 + 1164 * (y - 16) + 2018 * (cb - 128)) / 1000;
210 *r = (lr < 0)? 0: (lr > 255)? 255: (
eu8)lr;
211 *g = (lg < 0)? 0: (lg > 255)? 255: (
eu8)lg;
212 *b = (lb < 0)? 0: (lb > 255)? 255: (
eu8)lb;
221 *y = ( 257 * r + 504 * g + 98 * b + 16500) / 1000;
222 *cr = ( 439 * r - 368 * g - 71 * b + 128500) / 1000;
223 *cb = (-148 * r - 291 * g + 439 * b + 128500) / 1000;
245 FILE * fh = fopen(filename, mode);
253 if (fseek(stream, offset, SEEK_SET) < 0)
259 if (mkdir(path, mode) < 0)
268 if (stat(filename, &st) == 0 && S_ISREG(st.st_mode))
277 if (stat(filename, &st) == 0 && S_ISDIR(st.st_mode))
285 return (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3];
290 return (bytes[0] << 8) + bytes[1];
295 return (bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0];
300 return (bytes[1] << 8) + bytes[0]; }
306 ptr[0] = value>>24; ptr[1] = value>>16; ptr[2] = value>>8; ptr[3] =value;
311 ptr[0] = value>>8; ptr[1] = value; }
314 ptr[3] = value>>24; ptr[2] = value>>16; ptr[1] = value>>8; ptr[0] =value; }
319 ptr[1] = value>>8; ptr[0] =value;
330 eu8 yuvpalette[16][3],
eu8 rgbpalette[16][3])
337 fh =
xfopen(filename,
"rb");
338 if (memcmp(
xxfread(fh, buf, 12),
"DVDVIDEO-VTS", 12) != 0)
340 "(IFO) file %s not of type DVDVIDEO-VTS.", filename);
344 xfseek0(fh, offset * 0x800 + 12);
350 for (i = 0; i < 16; i++)
352 eu8 *
p = buf + i * 4 + 1;
353 yuvpalette[i][0] =p[0]; yuvpalette[i][1] =p[1]; yuvpalette[i][2] =p[2];
354 yuv2rgb(p[0], p[1], p[2], &r, &g, &b);
355 rgbpalette[i][0] =
r; rgbpalette[i][1] =
g; rgbpalette[i][2] =
b;
364 r = value >> 16; g = value >> 8; b = value;
365 rgbpalpart[0] =
r, rgbpalpart[1] =
g, rgbpalpart[2] =
b;
366 rgb2yuv(r, g, b, &y, &cr, &cb);
367 yuvpalpart[0] =
y, yuvpalpart[1] = cr, yuvpalpart[2] = cb;
372 eu8 yuvpalette[16][3],
eu8 rgbpalette[16][3])
376 if (strlen(arg) != 20 || arg[6] !=
',' || arg[13] !=
',')
379 for (i = 0; i < 16; i++)
380 set2palettes(i * 0x111111, yuvpalette[i], rgbpalette[i]);
382 sscanf(arg,
"%x", &i);
384 sscanf(arg + 7,
"%x", &i);
386 sscanf(arg + 14,
"%x", &i);
408 memcpy(self->palettechunk,
"\0\0\0\x0c" "PLTE", 8);
409 memcpy(self->palettechunk + 8, palette, 12);
411 self->crc =
crc32(self->crc, self->palettechunk + 4, 16);
419 self->fh =
xfopen(filename,
"wb");
421 self->hleft = height;
424 xxfwrite(self->fh, CUS
"\x89PNG\r\n\x1a\n" "\0\0\0\x0d", 12);
426 memcpy(self->buffer,
"IHDR", 4);
429 memcpy(self->buffer + 12,
"\004\003\0\0\0", 5);
431 crc =
crc32(0, self->buffer, 17);
433 xxfwrite(self->fh, self->buffer, 21);
435 xxfwrite(self->fh, self->palettechunk,
sizeof self->palettechunk);
438 xxfwriteCS(self->fh,
"\0\0\0\001" "tRNS" "\0" "\x40\xe6\xd8\x66");
440 xxfwrite(self->fh, CUS
"\0\0\0\0IDAT" "\x78\001", 10);
441 self->buffer[0] =
'\0';
442 self->buffer[5] =
'\0';
445 self->crc =
crc32(0, CUS
"IDAT" "\x78\001", 6);
451 int l =
self->bufpos - 5;
452 self->chunklen +=
self->bufpos;
455 xxfwrite(self->fh, self->buffer, self->bufpos);
456 self->crc =
crc32(self->crc, self->buffer, self->bufpos);
457 self->adler = adler32(self->adler, self->buffer + 5, self->bufpos - 5);
458 self->buffer[0] =
'\0';
464 if (self->nibble < 0)
465 self->nibble = (pixel << 4);
468 self->buffer[
self->bufpos++] =
self->nibble |
pixel;
470 if (self->bufpos ==
sizeof self->buffer - 4)
477 if (self->nibble >= 0)
479 self->buffer[
self->bufpos++] =
self->nibble;
485 self->buffer[
self->bufpos++] =
'\0';
491 self->buffer[0] = 0x01;
502 self->crc =
crc32(self->crc, adlerbuf, 4);
504 xxfwriteCS(self->fh,
"\0\0\0\0" "IEND" "\xae\x42\x60\x82");
515 eu8 rv = *nibble & 0x0f;
520 *nibble = *(*data)++;
535 if ((bits & 0xc) != 0)
538 number = (bits & 0xc) >> 2;
539 cindex = bits & 0x3; }
542 bits = (bits << 4) |
getnibble(data, &nibble);
543 if ((bits & 0xf0) != 0)
546 number = (bits & 0x3c) >> 2;
551 bits = (bits << 4) |
getnibble(data, &nibble);
552 if ((bits & 0xfc0) != 0)
555 number = (bits & 0xfc) >> 2;
561 bits = (bits << 4) |
getnibble(data, &nibble);
562 number = (bits & 0x3fc) >> 2;
572 for (; number > 0 && col <
width; number--, col++)
586 eu8 * top_ibuf = data + top;
587 eu8 * bot_ibuf = data + bot;
593 for (i = 0; i < h / 2; i++)
603 static char *
pts2ts(
fu32 pts,
char * rvbuf,
bool is_png_filename)
605 int h = pts / (3600 * 90000);
606 int m = pts / (60 * 90000) % 60;
607 int s = pts / 90000 % 60;
608 int hs = (pts + 450) / 900 % 100;
611 sprintf(rvbuf,
"%02d+%02d+%02d.%02d.png", h, m, s, hs);
613 sprintf(rvbuf,
"%02d:%02d:%02d.%02d", h, m, s, hs);
647 bool createpics,
int delay_ms,
648 char * fnbuf,
char * fnbuf_fp)
658 if (memcmp(
xxfread(sfh, data, 2),
"SP", 2) != 0)
682 ctrl = data + pack - 4;
683 xxfread(sfh, ctrl, size - pack);
687 if (memcmp(
xxfread(sfh, (
unsigned char *)junk, 2),
697 int x1 = -1,
x2 = -1, y1 = -1, y2 = -1;
698 int top_field = -1, bot_field = -1;
699 int start = 0, end = 0;
701 eu8 this_palette[4][3];
727 for (n = 0; n < 4; n++) {
728 i = (xpalette >> (n * 4) & 0x0f);
729 this_palette[
n][0] = palette[i][0];
730 this_palette[
n][1] = palette[i][1];
731 this_palette[
n][2] = palette[i][2];
739 x1 = (p[0] << 4) + (p[1] >> 4);
740 x2 = ((p[1] & 0xf) << 8) + p[2];
741 y1 = (p[3] << 4) + (p[4] >> 4);
742 y2 = ((p[4] & 0xf) << 8) + p[5];
766 tmppts += delay_ms * 90;
772 endpts = tmppts + end * 1000;
774 if (tmppts <= lastendpts)
776 if (lastendpts < endpts)
778 pts = lastendpts + 2 * (1000 / 30) * 90;
781 tmppts += delay_ms * 90;
782 printf(
"Fixed overlapping subtitle!\n");
786 printf(
"Dropping overlapping subtitle\n");
793 pts2ts(pts, fnbuf_fp,
true);
794 pts2ts(tmppts, sptsstr + 1,
false);
800 size_t len =
write(1, sptsstr, strlen(sptsstr));
801 if (len != strlen(sptsstr))
802 printf(
"ERROR: write failed");
805 fprintf(ofh,
" <spu start=\"%s\" end=\"%s\" image=\"%s\""
806 " xoffset=\"%d\" yoffset=\"%d\" />\n",
807 sptsstr + 1,
pts2ts(endpts, junk,
false),
811 makebitmap(data,
x2 - x1 + 1, y2 - y1 + 1, top_field - 4,
812 bot_field - 4, fnbuf, this_palette);
820 size_t len =
write(1, sptsstr, strlen(sptsstr));
821 if (len != strlen(sptsstr))
822 printf(
"ERROR: write failed");
832 "Usage: %s [--delay ms] <supfile> <ifofile>|<palette>" "\n"
836 "\t ProjectX decoded recording.sup and recording.sup.IFO" "\n"
838 "\t\t$ pxsup2dast recording.sup*" "\n"
840 "\t Having test.sup and map.ifo" "\n"
842 "\t\t$ pxsup2dast test.sup map.ifo" "\n"
844 "\t No .IFO, so giving 3 colors (rgb components in hex)" "\n"
846 "\t\t$ pxsup2dast titles.sup ff0000,00ff00,0000ff" "\n"
848 "\t Trying to fix sync in recording" "\n"
850 "\t\t$ pxsup2dast --delay 750 recording.sup*" "\n"
864 fh =
xfopen(filename,
"rb");
865 for (i = 0; i < 16; i++)
867 if (fscanf(fh,
"%02x%02x%02x\n", &r, &g, &b) != 3 ||
868 r != palette[i][0] || g != palette[i][1] || b != palette[i][2])
878 int sup2dast(
const char *supfile,
const char *ifofile ,
int delay_ms)
883 eu8 yuvpalette[16][3], rgbpalette[16][3];
890 memset(yuvpalette, 0,
sizeof(yuvpalette));
891 memset(rgbpalette, 0,
sizeof(rgbpalette));
893 if (
write(1,
"\n", 1) != 1)
894 printf(
"ERROR: write failed");
896 if (
sizeof (
char) != 1 ||
sizeof (
int) < 2)
899 if ((p = strrchr(supfile,
'.')) != NULL)
905 "not manage filenames longer than 950 characters.");
906 memcpy(fnbuf, supfile, i);
919 strcpy(p,
"palette.ycrcb");
923 printf(
"Found palette.yuv having our palette information...\n");
924 printf(
"...Skipping image files, Writing spumux.tmp.\n");
929 printf(
"Writing image files and spumux.tmp.\n");
932 strcpy(p,
"spumux.tmp");
935 xxfwriteCS(fh,
"<subpictures>\n <stream>\n");
936 pxsubtitle(supfile, fh, rgbpalette, createpics, delay_ms, fnbuf, p);
938 if (
write(1,
"\n", 1) != 1)
939 printf(
"ERROR: write failed");
941 xxfwriteCS(fh,
" </stream>\n</subpictures>\n");
946 FILE * yuvfh, *rgbfh;
947 printf(
"Writing palette.ycrcb and palette.rgb.\n");
948 strcpy(p,
"palette.ycrcb");
949 yuvfh =
xfopen(fnbuf,
"wb");
950 strcpy(p,
"palette.rgb");
951 rgbfh =
xfopen(fnbuf,
"wb");
952 for (i = 0; i < 16; i++)
954 fprintf(yuvfh,
"%02x%02x%02x\n",
955 yuvpalette[i][0], yuvpalette[i][1], yuvpalette[i][2]);
956 fprintf(rgbfh,
"%02x%02x%02x\n",
957 rgbpalette[i][0], rgbpalette[i][1], rgbpalette[i][2]);
965 printf(
"Renaming spumux.tmp to spumux.xml.\n");
966 strcpy(p,
"spumux.tmp");
968 memcpy(buf, fnbuf, i);
969 strcpy(&buf[i - 3],
"xml");
975 printf(
"Output files reside in %s\n", fnbuf);
976 printf(
"All done.\n");
982 printf(
"ERROR: write failed");
984 if (
write(2,
"\n", 1) != 1)
985 printf(
"ERROR: write failed");