MythTV  0.26-pre
pxsup2dast.c
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends