|
MythTV
0.26-pre
|
00001 /* 00002 # 00003 # pxsup2dast.c version YYYY-MM-DD (take from most recent change below). 00004 # 00005 # Project X sup to dvdauthor subtitle xml file. 00006 # too ät iki piste fi 00007 # 00008 # ------------------------------------------------- 00009 # 00010 # This is currently wery picky what this expects of ProjectX .sup to contain. 00011 # Update: 2005/07/02 Not so picky anymore, but control sequence parsing is 00012 # not perfect (yet!?) 00013 # 00014 # Change 2010-08-29: Initial handling of 0x07 control code (from 00015 # Simon Liddicott). Currently just ignores contents but doesn't choke on 00016 # it anymore... 00017 # 00018 # Change 2009-08-09: Renamed getline() as getpixelline() (to avoid function 00019 # name collision. Fixed GPL version to 2 (only). Thanks Ville Skyttä. 00020 # 00021 # Change 2009-01-10: Added subtitle indexing change (fix) from patch 00022 # sent by Ian Stewart. 00023 # 00024 # This program is released under GNU GPL version 2. Check 00025 # http://www.fsf.org/licenses/licenses.html 00026 # to get your own copy of the GPL v2 license. 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 /* this is all speed, not so much portability -- using C99 features... */ 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 /* use this only to cast quoted strings in function calls */ 00078 #define CUS (const unsigned char *) 00079 00080 /* forward declarations */ 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 /****** Poor man's exception code ... (heavily inspired by cexcept). ******/ 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 /* = { 0 }*/ ; 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) /* protoadd GCCATTR_NORETURN */ 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 /* protoadd GCCATTR_NORETURN */ 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 /****** end exception code block ******/ 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 /* from dvdauthor... */ 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 /* int ly, lcr, lcb; */ 00219 00220 /* from dvdauthor... */ 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 /* the code above matches nicely with http://www.fourcc.org/fccyvrgb.php 00227 00228 * RGB to YUV Conversion 00229 00230 * Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16 00231 * Cr = V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128 00232 * Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128 00233 00234 * YUV to RGB Conversion 00235 00236 * B = 1.164(Y - 16) + 2.018(U - 128) 00237 * G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128) 00238 * R = 1.164(Y - 16) + 1.596(V - 128) 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 /* protoline */ 00299 static fu32 get_uint16_le(const eu8 * bytes) { 00300 return (bytes[1] << 8) + bytes[0]; } 00301 #endif /* protoline */ 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 /* protoline */ 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 /* protoline */ 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 /* seek to palette */ 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); /* "%x," ? */ 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 /* typedef struct _Png4File Png4File; */ 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 /*crc32(0, Z_NULL, 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 /* XXX quick hack, first color transparent. */ 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; /* 78 01, zlib header */ 00445 self->crc = crc32(0, CUS "IDAT" "\x78\001", 6); 00446 self->adler = 1 /* adler32(0, Z_NULL, 0) */; 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 /* adler*/); 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 /* else */ 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 /* Originally from gtkspu - this from the python implementation of this */ 00531 00532 while (1) 00533 { 00534 int bits = getnibble(data, &nibble); 00535 if ((bits & 0xc) != 0) 00536 { 00537 /* have 4-bit code */ 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 /* have 8-bit code */ 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 /* have 12-bit code */ 00555 number = (bits & 0xfc) >> 2; 00556 cindex = bits & 0x3; 00557 } 00558 else 00559 { 00560 /* have 16-bit code */ 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 /* printf("%d %d %d %d\n", number, col, width, cindex); */ 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); /* not bottleneck even re-doing this every time */ 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 /*char transparent[8]; */ 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 /*sprintf(transparent, 00664 "%02x%02x%02x", palette[0][0], palette[0][1], palette[0][2]); */ 00665 00666 exc_try 00667 { 00668 eu32 lastendpts = 0; 00669 00670 while (1) 00671 { 00672 /* X.java reads 5 bytes of pts, SubPicture.java writes 4. With 00673 * 4 bytes 47721 seconds (13.25 hours) can be handled. 00674 * Later, bytes 1,2,3,4 (instead of 0,1,2,3) could be used. 00675 * 256/90000 = 1/351 sec -- way better than required resolution. 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: /* force display: */ 00718 continue; 00719 case 0x01: /* start date (read above) */ 00720 start = date; 00721 continue; 00722 case 0x02: /* stop date (read above) */ 00723 end = date; 00724 continue; 00725 case 0x03: /* palette */ 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: /* alpha channel */ 00735 /*alpha =*/ boundstr_read(&bs, 2); 00736 continue; 00737 case 0x05: /* coordinates */ 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: /* rle offsets */ 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) /* end command */ 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 /* check for overlapping subtitles */ 00764 eu32 tmppts = pts; 00765 if (delay_ms) 00766 tmppts += delay_ms * 90; 00767 00768 /* hack to fix projectx bug adding wrong end times around a cut point*/ 00769 if (end > 500) 00770 end = 500; 00771 00772 endpts = tmppts + end * 1000; /* ProjectX ! (other: 900, 1024) */ 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) /* protoadd GCCATTR_NORETURN */ 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) /* very unlikely */ 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 }
1.7.6.1