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