00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030 typedef enum { false = 0, true = 1 } bool;
00031 typedef unsigned char bool8;
00032
00033
00034 #include <unistd.h>
00035 #include <stdio.h>
00036 #include <stdlib.h>
00037 #include <stdarg.h>
00038 #include <string.h>
00039 #include <sys/types.h>
00040 #include <sys/stat.h>
00041 #include <time.h>
00042 #include <errno.h>
00043 #include <ctype.h>
00044 #include <setjmp.h>
00045 #include <zlib.h>
00046
00047 #if 1
00048
00049 #include <stdint.h>
00050
00051 typedef int8_t ei8; typedef uint8_t eu8;
00052 typedef int16_t ei16; typedef uint16_t eu16;
00053 typedef int32_t ei32; typedef uint32_t eu32;
00054
00055 typedef int_least8_t li8; typedef uint_least8_t lu8;
00056 typedef int_least16_t li16; typedef uint_least16_t lu16;
00057 typedef int_least32_t li32; typedef uint_least32_t lu32;
00058
00059 typedef int_fast8_t fi8; typedef uint_fast8_t fu8;
00060 typedef int_fast16_t fi16; typedef uint_fast16_t fu16;
00061 typedef int_fast32_t fi32; typedef uint_fast32_t fu32;
00062 #endif
00063
00064
00065 #if (__GNUC__ >= 3)
00066 #define GCCATTR_PRINTF(m, n) __attribute__ ((format (printf, m, n)))
00067 #define GCCATTR_UNUSED __attribute ((unused))
00068 #define GCCATTR_NORETURN __attribute ((noreturn))
00069 #define GCCATTR_CONST __attribute ((const))
00070 #else
00071 #define GCCATTR_PRINTF(m, n)
00072 #define GCCATTR_UNUSED
00073 #define GCCATTR_NORETURN
00074 #define GCCATTR_CONST
00075 #endif
00076
00077
00078 #define CUS (const unsigned char *)
00079
00080
00081 typedef struct _Png4File Png4File;
00082 typedef struct _BoundStr BoundStr;
00083
00084 enum { MiscError = 1, EOFIndicator, IndexError };
00085
00086 int sup2dast(const char *supfile, const char *ifofile, int delay_ms);
00087
00088
00089
00090 struct exc__state
00091 {
00092 struct exc__state * prev;
00093 jmp_buf env;
00094 };
00095
00096 struct
00097 {
00098 struct exc__state * last;
00099 char msgbuf[1024];
00100 int buflen;
00101 } EXC ;
00102
00103 #define exc_try do { struct exc__state exc_s; int exc_type GCCATTR_UNUSED; \
00104 exc_s.prev = EXC.last; EXC.last = &exc_s; if ((exc_type = setjmp(exc_s.env)) == 0)
00105
00106 #define exc_ftry do { struct exc__state exc_s, *exc_p = EXC.last; \
00107 int exc_type GCCATTR_UNUSED; exc_s.prev = EXC.last; \
00108 EXC.last = &exc_s; if ((exc_type = setjmp(exc_s.env)) == 0)
00109
00110 #define exc_catch(t) else if (t == exc_type)
00111
00112 #define exc_end else __exc_throw(exc_type); EXC.last = exc_s.prev; } while (0)
00113
00114 #define exc_return for (EXC.last = exc_p;;) return
00115
00116 #define exc_fthrow for (EXC.last = exc_p;;) ex_throw
00117
00118 #define exc_catchall else
00119 #define exc_endall EXC.last = exc_s.prev; } while (0)
00120
00121 static void __exc_throw(int type)
00122 {
00123 struct exc__state * exc_s;
00124 exc_s = EXC.last;
00125 EXC.last = EXC.last->prev;
00126 longjmp(exc_s->env, type);
00127 }
00128
00129 static void exc_throw(int type, const char * format, ...)
00130
00131 {
00132 if (format != NULL)
00133 {
00134 va_list ap;
00135 unsigned int len;
00136 int err = errno;
00137
00138 va_start(ap, format);
00139 len = vsnprintf(EXC.msgbuf, sizeof EXC.msgbuf, format, ap);
00140 va_end(ap);
00141
00142 if (len >= sizeof EXC.msgbuf)
00143 {
00144 len = sizeof EXC.msgbuf - 1;
00145 EXC.msgbuf[len] = '\0';
00146 }
00147 else
00148 {
00149 if (format[strlen(format) - 1] == ':')
00150 {
00151 int l = snprintf(&EXC.msgbuf[len], sizeof EXC.msgbuf - len,
00152 " %s.", strerror(err));
00153 if (l + len >= sizeof EXC.msgbuf)
00154 {
00155 len = sizeof EXC.msgbuf - 1;
00156 EXC.msgbuf[len] = '\0';
00157 }
00158 else
00159 len += l;
00160 }
00161 }
00162 EXC.buflen = len;
00163 }
00164 else
00165 {
00166 EXC.msgbuf[0] = '\0';
00167 EXC.buflen = 0;
00168 }
00169
00170 __exc_throw(type);
00171 }
00172
00173
00174
00175
00176 static eu8 * xxfread(FILE * stream, eu8 * ptr, size_t size)
00177 {
00178 size_t n = fread(ptr, size, 1, stream);
00179 if (n == 0)
00180 {
00181 if (ferror(stream))
00182 exc_throw(MiscError, "fread failure:");
00183 exc_throw(EOFIndicator, NULL); }
00184 return ptr;
00185 }
00186
00187 static void xxfwrite(FILE * stream, const eu8 * ptr, size_t size)
00188 {
00189 size_t n = fwrite(ptr, size, 1, stream);
00190 if (n == 0)
00191 {
00192 if (ferror(stream))
00193 exc_throw(MiscError, "fwrite failure:");
00194 exc_throw(MiscError, "fwrite failure:");
00195 }
00196 }
00197
00198 #define xxfwriteCS(f, s) xxfwrite(f, CUS s, sizeof s - 1)
00199
00200 static void yuv2rgb(int y, int cr, int cb,
00201 eu8 * r, eu8 * g, eu8 * b)
00202 {
00203 int lr, lg, lb;
00204
00205
00206 lr = (500 + 1164 * (y - 16) + 1596 * (cr - 128) ) /1000;
00207 lg = (500 + 1164 * (y - 16) - 813 * (cr - 128) - 391 * (cb - 128)) / 1000;
00208 lb = (500 + 1164 * (y - 16) + 2018 * (cb - 128)) / 1000;
00209
00210 *r = (lr < 0)? 0: (lr > 255)? 255: (eu8)lr;
00211 *g = (lg < 0)? 0: (lg > 255)? 255: (eu8)lg;
00212 *b = (lb < 0)? 0: (lb > 255)? 255: (eu8)lb;
00213 }
00214
00215 static void rgb2yuv(eu8 r, eu8 g, eu8 b,
00216 eu8 * y, eu8 * cr, eu8 * cb)
00217 {
00218
00219
00220
00221 *y = ( 257 * r + 504 * g + 98 * b + 16500) / 1000;
00222 *cr = ( 439 * r - 368 * g - 71 * b + 128500) / 1000;
00223 *cb = (-148 * r - 291 * g + 439 * b + 128500) / 1000;
00224 }
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 static FILE * xfopen(const char * filename, const char * mode)
00244 {
00245 FILE * fh = fopen(filename, mode);
00246 if (fh == NULL)
00247 exc_throw(MiscError, "fopen(\"%s\", \"%s\") failure:", filename, mode);
00248 return fh;
00249 }
00250
00251 static void xfseek0(FILE * stream, long offset)
00252 {
00253 if (fseek(stream, offset, SEEK_SET) < 0)
00254 exc_throw(MiscError, "fseek(stream, %ld, SEEK_SET) failure:",offset);
00255 }
00256
00257 static void xmkdir(const char * path, int mode)
00258 {
00259 if (mkdir(path, mode) < 0)
00260 exc_throw(MiscError, "mkdir(%s, 0%o) failure:", path, mode);
00261 }
00262
00263
00264 static bool fexists(const char * filename)
00265 {
00266 struct stat st;
00267
00268 if (stat(filename, &st) == 0 && S_ISREG(st.st_mode))
00269 return true;
00270 return false;
00271 }
00272
00273 static bool dexists(const char * filename)
00274 {
00275 struct stat st;
00276
00277 if (stat(filename, &st) == 0 && S_ISDIR(st.st_mode))
00278 return true;
00279
00280 return false;
00281 }
00282
00283 static fu32 get_uint32_be(const eu8 * bytes)
00284 {
00285 return (bytes[0] << 24) + (bytes[1] << 16) + (bytes[2] << 8) + bytes[3];
00286 }
00287
00288 static fu16 get_uint16_be(const eu8 * bytes)
00289 {
00290 return (bytes[0] << 8) + bytes[1];
00291 }
00292
00293 static fu32 get_uint32_le(const eu8 * bytes)
00294 {
00295 return (bytes[3] << 24) + (bytes[2] << 16) + (bytes[1] << 8) + bytes[0];
00296 }
00297
00298 #if 0
00299 static fu32 get_uint16_le(const eu8 * bytes) {
00300 return (bytes[1] << 8) + bytes[0]; }
00301 #endif
00302
00303
00304 static void set_uint32_be(eu8 * ptr, eu32 value)
00305 {
00306 ptr[0] = value>>24; ptr[1] = value>>16; ptr[2] = value>>8; ptr[3] =value;
00307 }
00308
00309 #if 0
00310 static void set_uint16_be(eu8 * ptr, eu32 value) {
00311 ptr[0] = value>>8; ptr[1] = value; }
00312
00313 static void set_uint32_le(eu8 * ptr, eu32 value) {
00314 ptr[3] = value>>24; ptr[2] = value>>16; ptr[1] = value>>8; ptr[0] =value; }
00315 #endif
00316
00317 static void set_uint16_le(eu8 * ptr, eu16 value)
00318 {
00319 ptr[1] = value>>8; ptr[0] =value;
00320 }
00321
00322 static void xxfwrite_uint32_be(FILE * fh, eu32 value)
00323 {
00324 eu8 buf[4];
00325 set_uint32_be(buf, value);
00326 xxfwrite(fh, buf, 4);
00327 }
00328
00329 static void ifopalette(const char * filename,
00330 eu8 yuvpalette[16][3], eu8 rgbpalette[16][3])
00331 {
00332 eu8 buf[1024], r, g, b;
00333 fu32 offset, pgc;
00334 int i;
00335 FILE * fh;
00336
00337 fh = xfopen(filename, "rb");
00338 if (memcmp(xxfread(fh, buf, 12), "DVDVIDEO-VTS", 12) != 0)
00339 exc_throw(MiscError,
00340 "(IFO) file %s not of type DVDVIDEO-VTS.", filename);
00341
00342 xfseek0(fh, 0xcc);
00343 offset = get_uint32_be(xxfread(fh, buf, 4));
00344 xfseek0(fh, offset * 0x800 + 12);
00345 pgc = offset * 0x800 + get_uint32_be(xxfread(fh, buf, 4));
00346
00347 xfseek0(fh, pgc + 0xa4);
00348 xxfread(fh, buf, 16 * 4);
00349 fclose(fh);
00350 for (i = 0; i < 16; i++)
00351 {
00352 eu8 * p = buf + i * 4 + 1;
00353 yuvpalette[i][0] =p[0]; yuvpalette[i][1] =p[1]; yuvpalette[i][2] =p[2];
00354 yuv2rgb(p[0], p[1], p[2], &r, &g, &b);
00355 rgbpalette[i][0] = r; rgbpalette[i][1] = g; rgbpalette[i][2] = b;
00356 }
00357 }
00358
00359
00360 static void set2palettes(int value, eu8 * yuvpalpart, eu8 * rgbpalpart)
00361 {
00362 eu8 r, g, b, y, cr, cb;
00363
00364 r = value >> 16; g = value >> 8; b = value;
00365 rgbpalpart[0] = r, rgbpalpart[1] = g, rgbpalpart[2] = b;
00366 rgb2yuv(r, g, b, &y, &cr, &cb);
00367 yuvpalpart[0] = y, yuvpalpart[1] = cr, yuvpalpart[2] = cb;
00368 }
00369
00370
00371 static void argpalette(const char * arg,
00372 eu8 yuvpalette[16][3], eu8 rgbpalette[16][3])
00373 {
00374 unsigned int i;
00375
00376 if (strlen(arg) != 20 || arg[6] != ',' || arg[13] != ',')
00377 exc_throw(MiscError, "Palette arg %s invalid.\n", arg);
00378
00379 for (i = 0; i < 16; i++)
00380 set2palettes(i * 0x111111, yuvpalette[i], rgbpalette[i]);
00381
00382 sscanf(arg, "%x", &i);
00383 set2palettes(i, yuvpalette[1], rgbpalette[1]);
00384 sscanf(arg + 7, "%x", &i);
00385 set2palettes(i, yuvpalette[2], rgbpalette[2]);
00386 sscanf(arg + 14, "%x", &i);
00387 set2palettes(i, yuvpalette[3], rgbpalette[3]);
00388 }
00389
00390
00391
00392 struct _Png4File
00393 {
00394 FILE * fh;
00395 int width;
00396 int hleft;
00397 int nibble;
00398 int bufpos;
00399 int chunklen;
00400 eu32 crc;
00401 eu32 adler;
00402 eu8 palettechunk[24];
00403 eu8 buffer[65536];
00404 };
00405
00406 static void png4file_init(Png4File * self, eu8 palette[4][3])
00407 {
00408 memcpy(self->palettechunk, "\0\0\0\x0c" "PLTE", 8);
00409 memcpy(self->palettechunk + 8, palette, 12);
00410 self->crc = 0 ;
00411 self->crc = crc32(self->crc, self->palettechunk + 4, 16);
00412 set_uint32_be(self->palettechunk + 20, self->crc);
00413 }
00414
00415 static void png4file_open(Png4File * self,
00416 const char * filename, int height, int width)
00417 {
00418 eu32 crc;
00419 self->fh = xfopen(filename, "wb");
00420 self->width = width;
00421 self->hleft = height;
00422 self->nibble = -1;
00423
00424 xxfwrite(self->fh, CUS "\x89PNG\r\n\x1a\n" "\0\0\0\x0d", 12);
00425
00426 memcpy(self->buffer, "IHDR", 4);
00427 set_uint32_be(self->buffer + 4, width);
00428 set_uint32_be(self->buffer + 8, height);
00429 memcpy(self->buffer + 12, "\004\003\0\0\0", 5);
00430
00431 crc = crc32(0, self->buffer, 17);
00432 set_uint32_be(self->buffer + 17, crc);
00433 xxfwrite(self->fh, self->buffer, 21);
00434
00435 xxfwrite(self->fh, self->palettechunk, sizeof self->palettechunk);
00436
00437
00438 xxfwriteCS(self->fh, "\0\0\0\001" "tRNS" "\0" "\x40\xe6\xd8\x66");
00439
00440 xxfwrite(self->fh, CUS "\0\0\0\0IDAT" "\x78\001", 10);
00441 self->buffer[0] = '\0';
00442 self->buffer[5] = '\0';
00443 self->bufpos = 6;
00444 self->chunklen = 2;
00445 self->crc = crc32(0, CUS "IDAT" "\x78\001", 6);
00446 self->adler = 1 ;
00447 }
00448
00449 static void png4file_flush(Png4File * self)
00450 {
00451 int l = self->bufpos - 5;
00452 self->chunklen += self->bufpos;
00453 set_uint16_le(self->buffer + 1, l);
00454 set_uint16_le(self->buffer + 3, l ^ 0xffff);
00455 xxfwrite(self->fh, self->buffer, self->bufpos);
00456 self->crc = crc32(self->crc, self->buffer, self->bufpos);
00457 self->adler = adler32(self->adler, self->buffer + 5, self->bufpos - 5);
00458 self->buffer[0] = '\0';
00459 self->bufpos = 5;
00460 }
00461
00462 static void png4file_addpixel(Png4File * self, eu8 pixel)
00463 {
00464 if (self->nibble < 0)
00465 self->nibble = (pixel << 4);
00466 else
00467 {
00468 self->buffer[self->bufpos++] = self->nibble | pixel;
00469 self->nibble = -1;
00470 if (self->bufpos == sizeof self->buffer - 4)
00471 png4file_flush(self);
00472 }
00473 }
00474
00475 static void png4file_endrow(Png4File * self)
00476 {
00477 if (self->nibble >= 0)
00478 {
00479 self->buffer[self->bufpos++] = self->nibble;
00480 self->nibble = -1;
00481 }
00482
00483 self->hleft--;
00484 if (self->hleft)
00485 self->buffer[self->bufpos++] = '\0';
00486 }
00487
00488 static void png4file_close(Png4File * self)
00489 {
00490 eu8 adlerbuf[4];
00491 self->buffer[0] = 0x01;
00492 if (self->bufpos)
00493 png4file_flush(self);
00494 else
00495 {
00496 self->bufpos = 5;
00497 png4file_flush(self);
00498 }
00499
00500 set_uint32_be(adlerbuf, self->adler);
00501 xxfwrite(self->fh, adlerbuf, 4);
00502 self->crc = crc32(self->crc, adlerbuf, 4);
00503 xxfwrite_uint32_be(self->fh, self->crc);
00504 xxfwriteCS(self->fh, "\0\0\0\0" "IEND" "\xae\x42\x60\x82");
00505 xfseek0(self->fh, 70);
00506 xxfwrite_uint32_be(self->fh, self->chunklen + 4 );
00507 fclose(self->fh);
00508 self->fh = NULL;
00509 }
00510
00511 static eu8 getnibble(eu8 ** data, int * nibble)
00512 {
00513 if (*nibble >= 0)
00514 {
00515 eu8 rv = *nibble & 0x0f;
00516 *nibble = -1;
00517 return rv;
00518 }
00519
00520 *nibble = *(*data)++;
00521 return *nibble >> 4;
00522 }
00523
00524
00525 static void getpixelline(eu8 ** data, int width, Png4File * picfile)
00526 {
00527 int nibble = -1;
00528 int col = 0;
00529 int number, cindex;
00530
00531
00532 while (1)
00533 {
00534 int bits = getnibble(data, &nibble);
00535 if ((bits & 0xc) != 0)
00536 {
00537
00538 number = (bits & 0xc) >> 2;
00539 cindex = bits & 0x3; }
00540 else
00541 {
00542 bits = (bits << 4) | getnibble(data, &nibble);
00543 if ((bits & 0xf0) != 0)
00544 {
00545
00546 number = (bits & 0x3c) >> 2;
00547 cindex = bits & 0x3;
00548 }
00549 else
00550 {
00551 bits = (bits << 4) | getnibble(data, &nibble);
00552 if ((bits & 0xfc0) != 0)
00553 {
00554
00555 number = (bits & 0xfc) >> 2;
00556 cindex = bits & 0x3;
00557 }
00558 else
00559 {
00560
00561 bits = (bits << 4) | getnibble(data, &nibble);
00562 number = (bits & 0x3fc) >> 2;
00563 cindex = bits & 0x3;
00564
00565 if (number == 0)
00566 number = width;
00567 }
00568 }
00569 }
00570
00571
00572 for (; number > 0 && col < width; number--, col++)
00573 png4file_addpixel(picfile, cindex);
00574
00575 if (col == width)
00576 {
00577 png4file_endrow(picfile);
00578 return;
00579 }
00580 }
00581 }
00582
00583 static void makebitmap(eu8 * data, int w, int h, int top, int bot,
00584 char * filename, eu8 palette[4][3])
00585 {
00586 eu8 * top_ibuf = data + top;
00587 eu8 * bot_ibuf = data + bot;
00588 int i;
00589 Png4File picfile;
00590
00591 png4file_init(&picfile, palette);
00592 png4file_open(&picfile, filename, h, w);
00593 for (i = 0; i < h / 2; i++)
00594 {
00595 getpixelline(&top_ibuf, w, &picfile);
00596 getpixelline(&bot_ibuf, w, &picfile);
00597 }
00598
00599 png4file_close(&picfile);
00600 }
00601
00602
00603 static char * pts2ts(fu32 pts, char * rvbuf, bool is_png_filename)
00604 {
00605 int h = pts / (3600 * 90000);
00606 int m = pts / (60 * 90000) % 60;
00607 int s = pts / 90000 % 60;
00608 int hs = (pts + 450) / 900 % 100;
00609
00610 if (is_png_filename)
00611 sprintf(rvbuf, "%02d+%02d+%02d.%02d.png", h, m, s, hs);
00612 else
00613 sprintf(rvbuf, "%02d:%02d:%02d.%02d", h, m, s, hs);
00614
00615 return rvbuf;
00616 }
00617
00618
00619
00620 struct _BoundStr
00621 {
00622 eu8 * p;
00623 int l;
00624 };
00625
00626 static void boundstr_init(BoundStr * bs, eu8 * p, int l)
00627 {
00628 bs->p = p;
00629 bs->l = l;
00630 }
00631
00632 static eu8 * boundstr_read(BoundStr * bs, int l)
00633 {
00634 eu8 * rp;
00635 if (l > bs->l)
00636 exc_throw(IndexError, "XXX IndexError %p.", bs);
00637 rp = bs->p;
00638 bs->p += l;
00639 bs->l -= l;
00640 return rp;
00641 }
00642
00643
00644
00645
00646 static void pxsubtitle(const char * supfile, FILE * ofh, eu8 palette[16][3],
00647 bool createpics, int delay_ms,
00648 char * fnbuf, char * fnbuf_fp)
00649 {
00650 char junk[32];
00651 char sptsstr[32];
00652 eu8 data[65536];
00653 eu8 * ctrl;
00654 time_t pt = 0, ct;
00655 bool last = false;
00656
00657 FILE * sfh = xfopen(supfile, "rb");
00658 if (memcmp(xxfread(sfh, data, 2), "SP", 2) != 0)
00659 {
00660 exc_throw(MiscError, "Syncword missing. XXX bailing out.");
00661 }
00662
00663
00664
00665
00666 exc_try
00667 {
00668 eu32 lastendpts = 0;
00669
00670 while (1)
00671 {
00672
00673
00674
00675
00676
00677 eu32 pts = get_uint32_le(xxfread(sfh, data, 8));
00678 eu16 size = get_uint16_be(xxfread(sfh, data, 2));
00679 eu16 pack = get_uint16_be(xxfread(sfh, data, 2));
00680 eu32 endpts;
00681 xxfread(sfh, data, pack - 4);
00682 ctrl = data + pack - 4;
00683 xxfread(sfh, ctrl, size - pack);
00684
00685 exc_try
00686 {
00687 if (memcmp(xxfread(sfh, (unsigned char *)junk, 2),
00688 "SP", 2) != 0)
00689 exc_throw(MiscError, "Syncword missing. XXX bailing out.");
00690 }
00691 exc_catch (EOFIndicator)
00692 last = true;
00693 exc_end;
00694 {
00695 BoundStr bs;
00696 int prev;
00697 int x1 = -1, x2 = -1, y1 = -1, y2 = -1;
00698 int top_field = -1, bot_field = -1;
00699 int start = 0, end = 0;
00700 int colcon_length;
00701 eu8 this_palette[4][3];
00702 boundstr_init(&bs, ctrl, size - pack);
00703
00704 prev = 0;
00705 while (1)
00706 {
00707 int date = get_uint16_be(boundstr_read(&bs, 2));
00708 int next = get_uint16_be(boundstr_read(&bs, 2));
00709
00710 while (1)
00711 {
00712 eu8 * p;
00713 eu8 cmd = boundstr_read(&bs, 1)[0];
00714 int xpalette, i, n;
00715 switch (cmd)
00716 {
00717 case 0x00:
00718 continue;
00719 case 0x01:
00720 start = date;
00721 continue;
00722 case 0x02:
00723 end = date;
00724 continue;
00725 case 0x03:
00726 xpalette = get_uint16_be(boundstr_read(&bs, 2));
00727 for (n = 0; n < 4; n++) {
00728 i = (xpalette >> (n * 4) & 0x0f);
00729 this_palette[n][0] = palette[i][0];
00730 this_palette[n][1] = palette[i][1];
00731 this_palette[n][2] = palette[i][2];
00732 }
00733 continue;
00734 case 0x04:
00735 boundstr_read(&bs, 2);
00736 continue;
00737 case 0x05:
00738 p = boundstr_read(&bs, 6);
00739 x1 = (p[0] << 4) + (p[1] >> 4);
00740 x2 = ((p[1] & 0xf) << 8) + p[2];
00741 y1 = (p[3] << 4) + (p[4] >> 4);
00742 y2 = ((p[4] & 0xf) << 8) + p[5];
00743 continue;
00744 case 0x06:
00745 top_field = get_uint16_be(boundstr_read(&bs, 2));
00746 bot_field = get_uint16_be(boundstr_read(&bs, 2));
00747 continue;
00748 case 0x07:
00749 colcon_length = get_uint16_be(boundstr_read(&bs, 2)-2);
00750 boundstr_read(&bs, colcon_length);
00751 continue;
00752 }
00753 if (cmd == 0xff)
00754 break;
00755 exc_throw(MiscError, "%d: Unknown control sequence", cmd);
00756 }
00757
00758 if (prev == next)
00759 break;
00760 prev = next;
00761 }
00762
00763
00764 eu32 tmppts = pts;
00765 if (delay_ms)
00766 tmppts += delay_ms * 90;
00767
00768
00769 if (end > 500)
00770 end = 500;
00771
00772 endpts = tmppts + end * 1000;
00773
00774 if (tmppts <= lastendpts)
00775 {
00776 if (lastendpts < endpts)
00777 {
00778 pts = lastendpts + 2 * (1000 / 30) * 90;
00779 tmppts = pts;
00780 if (delay_ms)
00781 tmppts += delay_ms * 90;
00782 printf("Fixed overlapping subtitle!\n");
00783 }
00784 else
00785 {
00786 printf("Dropping overlapping subtitle\n");
00787 continue;
00788 }
00789 }
00790
00791 lastendpts = endpts;
00792
00793 pts2ts(pts, fnbuf_fp, true);
00794 pts2ts(tmppts, sptsstr + 1, false);
00795
00796 if (pt != time(&ct))
00797 {
00798 pt = ct;
00799 sptsstr[0] = '\r';
00800 size_t len = write(1, sptsstr, strlen(sptsstr));
00801 if (len != strlen(sptsstr))
00802 printf("ERROR: write failed");
00803 }
00804
00805 fprintf(ofh, " <spu start=\"%s\" end=\"%s\" image=\"%s\""
00806 " xoffset=\"%d\" yoffset=\"%d\" />\n",
00807 sptsstr + 1, pts2ts(endpts, junk, false),
00808 fnbuf, x1, y1);
00809
00810 if (createpics)
00811 makebitmap(data, x2 - x1 + 1, y2 - y1 + 1, top_field - 4,
00812 bot_field - 4, fnbuf, this_palette);
00813 if (last)
00814 exc_throw(EOFIndicator, NULL);
00815 }
00816 }
00817 }
00818 exc_catch (EOFIndicator)
00819 {
00820 size_t len = write(1, sptsstr, strlen(sptsstr));
00821 if (len != strlen(sptsstr))
00822 printf("ERROR: write failed");
00823 return;
00824 }
00825 exc_end;
00826 }
00827
00828 #if 0
00829 static void usage(const char * pn)
00830 {
00831 exc_throw(MiscError, "\n"
00832 "Usage: %s [--delay ms] <supfile> <ifofile>|<palette>" "\n"
00833 "\n"
00834 "\tExamples:" "\n"
00835 "\n"
00836 "\t ProjectX decoded recording.sup and recording.sup.IFO" "\n"
00837 "\n"
00838 "\t\t$ pxsup2dast recording.sup*" "\n"
00839 "\n"
00840 "\t Having test.sup and map.ifo" "\n"
00841 "\n"
00842 "\t\t$ pxsup2dast test.sup map.ifo" "\n"
00843 "\n"
00844 "\t No .IFO, so giving 3 colors (rgb components in hex)" "\n"
00845 "\n"
00846 "\t\t$ pxsup2dast titles.sup ff0000,00ff00,0000ff" "\n"
00847 "\n"
00848 "\t Trying to fix sync in recording" "\n"
00849 "\n"
00850 "\t\t$ pxsup2dast --delay 750 recording.sup*" "\n"
00851 , pn);
00852 }
00853 #endif
00854
00855 static bool samepalette(char * filename, eu8 palette[16][3])
00856 {
00857 FILE * fh;
00858 int i;
00859 unsigned int r,g,b;
00860
00861 if (!fexists(filename))
00862 return false;
00863
00864 fh = xfopen(filename, "rb");
00865 for (i = 0; i < 16; i++)
00866 {
00867 if (fscanf(fh, "%02x%02x%02x\n", &r, &g, &b) != 3 ||
00868 r != palette[i][0] || g != palette[i][1] || b != palette[i][2])
00869 {
00870 fclose(fh);
00871 return false;
00872 }
00873 }
00874 fclose(fh);
00875 return true;
00876 }
00877
00878 int sup2dast(const char *supfile, const char *ifofile ,int delay_ms)
00879 {
00880 exc_try
00881 {
00882 int jc, i;
00883 eu8 yuvpalette[16][3], rgbpalette[16][3];
00884 char fnbuf[1024];
00885 char * p;
00886
00887 bool createpics;
00888 FILE * fh;
00889
00890 memset(yuvpalette, 0, sizeof(yuvpalette));
00891 memset(rgbpalette, 0, sizeof(rgbpalette));
00892
00893 if (write(1, "\n", 1) != 1)
00894 printf("ERROR: write failed");
00895
00896 if (sizeof (char) != 1 || sizeof (int) < 2)
00897 exc_throw(MiscError, "Incompatible variable sizes.");
00898
00899 if ((p = strrchr(supfile, '.')) != NULL)
00900 i = p - supfile;
00901 else
00902 i = strlen(supfile);
00903 if (i > 950)
00904 exc_throw(MiscError, "Can "
00905 "not manage filenames longer than 950 characters.");
00906 memcpy(fnbuf, supfile, i);
00907 p = fnbuf + i;
00908 strcpy(p, ".d/");
00909 p += strlen(p);
00910
00911 if (!dexists(fnbuf))
00912 xmkdir(fnbuf, 0755);
00913
00914 if (fexists(ifofile))
00915 ifopalette(ifofile, yuvpalette, rgbpalette);
00916 else
00917 argpalette(ifofile, yuvpalette, rgbpalette);
00918
00919 strcpy(p, "palette.ycrcb");
00920 if (samepalette(fnbuf, yuvpalette))
00921 {
00922 createpics = false;
00923 printf("Found palette.yuv having our palette information...\n");
00924 printf("...Skipping image files, Writing spumux.tmp.\n");
00925 }
00926 else
00927 {
00928 createpics = true;
00929 printf("Writing image files and spumux.tmp.\n");
00930 }
00931
00932 strcpy(p, "spumux.tmp");
00933 fh = xfopen(fnbuf, "wb");
00934
00935 xxfwriteCS(fh, "<subpictures>\n <stream>\n");
00936 pxsubtitle(supfile, fh, rgbpalette, createpics, delay_ms, fnbuf, p);
00937
00938 if (write(1, "\n", 1) != 1)
00939 printf("ERROR: write failed");
00940
00941 xxfwriteCS(fh, " </stream>\n</subpictures>\n");
00942 fclose(fh);
00943
00944 if (createpics)
00945 {
00946 FILE * yuvfh, *rgbfh;
00947 printf("Writing palette.ycrcb and palette.rgb.\n");
00948 strcpy(p, "palette.ycrcb");
00949 yuvfh = xfopen(fnbuf, "wb");
00950 strcpy(p, "palette.rgb");
00951 rgbfh = xfopen(fnbuf, "wb");
00952 for (i = 0; i < 16; i++)
00953 {
00954 fprintf(yuvfh, "%02x%02x%02x\n",
00955 yuvpalette[i][0], yuvpalette[i][1], yuvpalette[i][2]);
00956 fprintf(rgbfh, "%02x%02x%02x\n",
00957 rgbpalette[i][0], rgbpalette[i][1], rgbpalette[i][2]);
00958 }
00959 fclose(yuvfh);
00960 fclose(rgbfh);
00961 }
00962
00963 {
00964 char buf[1024];
00965 printf("Renaming spumux.tmp to spumux.xml.\n");
00966 strcpy(p, "spumux.tmp");
00967 i = strlen(fnbuf);
00968 memcpy(buf, fnbuf, i);
00969 strcpy(&buf[i - 3], "xml");
00970 unlink(buf);
00971 rename(fnbuf, buf);
00972 jc = 0;
00973 }
00974 p[0] = '\0';
00975 printf("Output files reside in %s\n", fnbuf);
00976 printf("All done.\n");
00977 }
00978
00979 exc_catchall
00980 {
00981 if (write(2, EXC.msgbuf, EXC.buflen) != EXC.buflen)
00982 printf("ERROR: write failed");
00983
00984 if (write(2, "\n", 1) != 1)
00985 printf("ERROR: write failed");
00986
00987 return 1;
00988 }
00989 exc_endall;
00990
00991 return 0;
00992 }