MythTV master
pxsup2dast.c
Go to the documentation of this file.
1/*
2 #
3 # pxsup2dast.c version YYYY-MM-DD (take from most recent change below).
4 #
5 # Project X sup to dvdauthor subtitle xml file.
6 # too ät iki piste fi
7 #
8 # -------------------------------------------------
9 #
10 # This is currently wery picky what this expects of ProjectX .sup to contain.
11 # Update: 2005/07/02 Not so picky anymore, but control sequence parsing is
12 # not perfect (yet!?)
13 #
14 # Change 2010-08-29: Initial handling of 0x07 control code (from
15 # Simon Liddicott). Currently just ignores contents but doesn't choke on
16 # it anymore...
17 #
18 # Change 2009-08-09: Renamed getline() as getpixelline() (to avoid function
19 # name collision. Fixed GPL version to 2 (only). Thanks Ville Skyttä.
20 #
21 # Change 2009-01-10: Added subtitle indexing change (fix) from patch
22 # sent by Ian Stewart.
23 #
24 # This program is released under GNU GPL version 2. Check
25 # http://www.fsf.org/licenses/licenses.html
26 # to get your own copy of the GPL v2 license.
27 #
28 */
29
30#include <unistd.h>
31#include <stdbool.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <stdarg.h>
35#include <stddef.h>
36#include <string.h>
37#include <sys/types.h>
38#include <sys/stat.h>
39#include <time.h>
40#include <errno.h>
41#include <ctype.h>
42#include <setjmp.h>
43#include <zlib.h>
44#ifdef _WIN32
45#include <dirent.h>
46#endif
47
48#if 1
49/* this is all speed, not so much portability -- using C99 features... */
50#include <stdint.h>
51
52typedef int8_t ei8; typedef uint8_t eu8;
53typedef int16_t ei16; typedef uint16_t eu16;
54typedef int32_t ei32; typedef uint32_t eu32;
55
56typedef int_least8_t li8; typedef uint_least8_t lu8;
57typedef int_least16_t li16; typedef uint_least16_t lu16;
58typedef int_least32_t li32; typedef uint_least32_t lu32;
59
60typedef int_fast8_t fi8; typedef uint_fast8_t fu8;
61typedef int_fast16_t fi16; typedef uint_fast16_t fu16;
62typedef int_fast32_t fi32; typedef uint_fast32_t fu32;
63#endif
64
65
66#define GCCATTR_PRINTF(m, n) __attribute__ ((format (printf, m, n)))
67#define GCCATTR_UNUSED __attribute ((unused))
68#define GCCATTR_NORETURN __attribute ((noreturn))
69#define GCCATTR_CONST __attribute ((const))
70
71/* use this only to cast quoted strings in function calls */
72#define CUS (const unsigned char *)
73
75
76int sup2dast(const char *supfile, const char *ifofile, int delay_ms);
77
78/****** Poor man's exception code ... (heavily inspired by cexcept). ******/
79
81{
83 jmp_buf m_env;
84};
85
86struct
87{
89 char m_msgbuf[1024];
91} EXC /* = { 0 }*/ ;
92
93// These macros now all take a parameter 'x' to specify a recursion
94// level. This will then generate unique variable names for each
95// level of recursion, preventing the compiler from complaining about
96// shadowed variables.
97#define exc_try(x) do { struct exc__state exc_s##x; int exc_type##x GCCATTR_UNUSED; \
98 exc_s##x.m_prev = EXC.m_last; \
99 EXC.m_last = &exc_s##x; \
100 exc_type##x = setjmp(exc_s##x.m_env); \
101 if (exc_type##x == 0)
102
103#define exc_ftry(x) do { struct exc__state exc_s##x, *exc_p##x = EXC.m_last; \
104 int exc_type##x GCCATTR_UNUSED; \
105 exc_s##x.prev = EXC.m_last; \
106 EXC.m_last = &exc_s##x; \
107 exc_type##x = setjmp(exc_s##x.env); \
108 if (exc_type##x == 0)
109
110#define exc_catch(x,t) else if ((t) == exc_type##x)
111
112#define exc_end(x) else __exc_throw(exc_type##x); EXC.m_last = exc_s##x.m_prev; } while (0)
113
114#define exc_return(x) for (EXC.m_last = exc_p##x;) return
115
116#define exc_fthrow(x) for (EXC.m_last = exc_p##x;) ex_throw
117
118#define exc_catchall else
119#define exc_endall(x) EXC.m_last = exc_s##x.m_prev; } while (0)
120
121#define exc_cleanup() EXC.m_last = NULL;
122
124{
125 struct exc__state * exc_s = EXC.m_last;
126 EXC.m_last = EXC.m_last->m_prev;
127 longjmp(exc_s->m_env, type);
128}
129
130GCCATTR_NORETURN static void exc_throw(int type, const char * format, ...)
131{
132 if (format != NULL)
133 {
134 va_list ap;
135 int err = errno;
136
137 va_start(ap, format);
138 unsigned int len = vsnprintf(EXC.m_msgbuf, sizeof EXC.m_msgbuf, format, ap);
139 va_end(ap);
140
141 if (len >= sizeof EXC.m_msgbuf)
142 {
143 len = sizeof EXC.m_msgbuf - 1;
144 EXC.m_msgbuf[len] = '\0';
145 }
146 else
147 {
148 if (format[strlen(format) - 1] == ':')
149 {
150 int l = snprintf(&EXC.m_msgbuf[len], sizeof EXC.m_msgbuf - len,
151 " %s.", strerror(err));
152 if (l + len >= sizeof EXC.m_msgbuf)
153 {
154 len = sizeof EXC.m_msgbuf - 1;
155 EXC.m_msgbuf[len] = '\0';
156 }
157 else
158 {
159 len += l;
160 }
161 }
162 }
163 EXC.m_buflen = len;
164 }
165 else
166 {
167 EXC.m_msgbuf[0] = '\0';
168 EXC.m_buflen = 0;
169 }
170
172}
173
174/****** end exception code block ******/
175
176
177static eu8 * xxfread(FILE * stream, eu8 * ptr, size_t size)
178{
179 size_t n = fread(ptr, size, 1, stream);
180 if (n == 0)
181 {
182 if (ferror(stream))
183 exc_throw(MiscError, "fread failure:");
184 exc_throw(EOFIndicator, NULL); }
185 return ptr;
186}
187
188static void xxfwrite(FILE * stream, const eu8 * ptr, size_t size)
189{
190 size_t n = fwrite(ptr, size, 1, stream);
191 if (n == 0)
192 {
193 if (ferror(stream))
194 exc_throw(MiscError, "fwrite failure:");
195 exc_throw(MiscError, "fwrite failure:");
196 }
197}
198
199#define xxfwriteCS(f, s) xxfwrite(f, CUS s, sizeof (s) - 1)
200
201static inline eu8 clamp (eu8 value, eu8 low, eu8 high)
202{
203 if (value < low)
204 return low;
205 if (value > high)
206 return high;
207 return value;
208}
209
210static void yuv2rgb(int y, int cr, int cb,
211 eu8 * r, eu8 * g, eu8 * b)
212{
213 /* from dvdauthor... */
214 int lr = (500 + 1164 * (y - 16) + 1596 * (cr - 128) ) /1000;
215 int lg = (500 + 1164 * (y - 16) - 813 * (cr - 128) - 391 * (cb - 128)) / 1000;
216 int lb = (500 + 1164 * (y - 16) + 2018 * (cb - 128)) / 1000;
217
218 *r = clamp(lr, 0, 255);
219 *g = clamp(lg, 0, 255);
220 *b = clamp(lb, 0, 255);
221}
222
223static void rgb2yuv(eu8 r, eu8 g, eu8 b,
224 eu8 * y, eu8 * cr, eu8 * cb)
225{
226 /* int ly, lcr, lcb; */
227
228 /* from dvdauthor... */
229 *y = ( 257 * r + 504 * g + 98 * b + 16500) / 1000;
230 *cr = ( 439 * r - 368 * g - 71 * b + 128500) / 1000;
231 *cb = (-148 * r - 291 * g + 439 * b + 128500) / 1000;
232}
233
234/* the code above matches nicely with http://www.fourcc.org/fccyvrgb.php
235
236 * RGB to YUV Conversion
237
238 * Y = (0.257 * R) + (0.504 * G) + (0.098 * B) + 16
239 * Cr = V = (0.439 * R) - (0.368 * G) - (0.071 * B) + 128
240 * Cb = U = -(0.148 * R) - (0.291 * G) + (0.439 * B) + 128
241
242 * YUV to RGB Conversion
243
244 * B = 1.164(Y - 16) + 2.018(U - 128)
245 * G = 1.164(Y - 16) - 0.813(V - 128) - 0.391(U - 128)
246 * R = 1.164(Y - 16) + 1.596(V - 128)
247
248*/
249
250
251static FILE * xfopen(const char * filename, const char * mode)
252{
253 FILE * fh = fopen(filename, mode);
254 if (fh == NULL)
255 exc_throw(MiscError, "fopen(\"%s\", \"%s\") failure:", filename, mode);
256 return fh;
257}
258
259static void xfseek0(FILE * stream, long offset)
260{
261 if (fseek(stream, offset, SEEK_SET) < 0)
262 exc_throw(MiscError, "fseek(stream, %ld, SEEK_SET) failure:",offset);
263}
264
265static void xmkdir(const char * path, int mode)
266{
267#ifdef _WIN32
268 (void)mode;
269 if (mkdir(path) < 0)
270 exc_throw(MiscError, "mkdir(%s%o) failure:", path);
271#else
272 if (mkdir(path, mode) < 0)
273 exc_throw(MiscError, "mkdir(%s, 0%o) failure:", path, mode);
274#endif
275}
276
277
278static bool fexists(const char * filename)
279{
280 struct stat st;
281
282 if (stat(filename, &st) == 0 && S_ISREG(st.st_mode))
283 return true;
284 return false;
285}
286
287static bool dexists(const char * filename)
288{
289 struct stat st;
290
291 if (stat(filename, &st) == 0 && S_ISDIR(st.st_mode))
292 return true;
293
294 return false;
295}
296
297static fu32 get_uint32_be(const eu8 * bytes)
298{
299 return ((fu32)(bytes[0]) << 24) +
300 ((fu32)(bytes[1]) << 16) +
301 ((fu32)(bytes[2]) << 8) +
302 (fu32)(bytes[3]);
303}
304
306{
307 return ((fu16)(bytes[0]) << 8) +
308 (fu16)(bytes[1]);
309}
310
311static fu32 get_uint32_le(const eu8 * bytes)
312{
313 return ((fu32)(bytes[3]) << 24) +
314 ((fu32)(bytes[2]) << 16) +
315 ((fu32)(bytes[1]) << 8) +
316 (fu32)(bytes[0]);
317}
318
319#if 0 /* protoline */
320static fu32 get_uint16_le(const eu8 * bytes) {
321 return ((fu16)(bytes[1]) << 8) +
322 (fu16)(bytes[0]); }
323#endif /* protoline */
324
325
326static void set_uint32_be(eu8 * ptr, eu32 value)
327{
328 ptr[0] = value>>24; ptr[1] = value>>16; ptr[2] = value>>8; ptr[3] =value;
329}
330
331#if 0 /* protoline */
332static void set_uint16_be(eu8 * ptr, eu32 value) {
333 ptr[0] = value>>8; ptr[1] = value; }
334
335static void set_uint32_le(eu8 * ptr, eu32 value) {
336 ptr[3] = value>>24; ptr[2] = value>>16; ptr[1] = value>>8; ptr[0] =value; }
337#endif /* protoline */
338
339static void set_uint16_le(eu8 * ptr, eu16 value)
340{
341 ptr[1] = value>>8; ptr[0] =value;
342}
343
344static void xxfwrite_uint32_be(FILE * fh, eu32 value)
345{
346 eu8 buf[4];
347 set_uint32_be(buf, value);
348 xxfwrite(fh, buf, 4);
349}
350
351static void ifopalette(const char * filename,
352 eu8 yuvpalette[16][3], eu8 rgbpalette[16][3])
353{
354 eu8 buf[1024];
355
356 FILE *fh = xfopen(filename, "rb");
357 if (memcmp(xxfread(fh, buf, 12), "DVDVIDEO-VTS", 12) != 0)
359 "(IFO) file %s not of type DVDVIDEO-VTS.", filename);
360
361 xfseek0(fh, 0xcc);
362 fu32 offset = get_uint32_be(xxfread(fh, buf, 4));
363 xfseek0(fh, (offset * 0x800) + 12);
364 fu32 pgc = (offset * 0x800) + get_uint32_be(xxfread(fh, buf, 4));
365 /* seek to palette */
366 xfseek0(fh, pgc + 0xa4);
367 xxfread(fh, buf, (size_t)(16 * 4));
368 fclose(fh);
369 for (int i = 0; i < 16; i++)
370 {
371 eu8 r = 0;
372 eu8 g = 0;
373 eu8 b = 0;
374 eu8 * p = buf + ((ptrdiff_t)(i) * 4) + 1;
375 yuvpalette[i][0] =p[0]; yuvpalette[i][1] =p[1]; yuvpalette[i][2] =p[2];
376 yuv2rgb(p[0], p[1], p[2], &r, &g, &b);
377 rgbpalette[i][0] = r; rgbpalette[i][1] = g; rgbpalette[i][2] = b;
378 }
379}
380
381
382static void set2palettes(int value, eu8 * yuvpalpart, eu8 * rgbpalpart)
383{
384 eu8 y = 0;
385 eu8 cr = 0;
386 eu8 cb = 0;
387 eu8 r = value >> 16;
388 eu8 g = value >> 8;
389 eu8 b = value;
390 rgbpalpart[0] = r, rgbpalpart[1] = g, rgbpalpart[2] = b;
391 rgb2yuv(r, g, b, &y, &cr, &cb);
392 yuvpalpart[0] = y, yuvpalpart[1] = cr, yuvpalpart[2] = cb;
393}
394
395
396static void argpalette(const char * arg,
397 eu8 yuvpalette[16][3], eu8 rgbpalette[16][3])
398{
399 unsigned int i = 0;
400
401 if (strlen(arg) != 20 || arg[6] != ',' || arg[13] != ',')
402 exc_throw(MiscError, "Palette arg %s invalid.\n", arg);
403
404 for (i = 0; i < 16; i++)
405 set2palettes(i * 0x111111, yuvpalette[i], rgbpalette[i]);
406
407 sscanf(arg, "%x", &i); /* "%x," ? */
408 set2palettes(i, yuvpalette[1], rgbpalette[1]);
409 sscanf(arg + 7, "%x", &i);
410 set2palettes(i, yuvpalette[2], rgbpalette[2]);
411 sscanf(arg + 14, "%x", &i);
412 set2palettes(i, yuvpalette[3], rgbpalette[3]);
413}
414
415
416typedef struct Png4File
417{
427 eu8 m_buffer[65536];
429
430static void png4file_init(Png4File * self, eu8 palette[4][3])
431{
432 memcpy(self->m_paletteChunk, "\0\0\0\x0c" "PLTE", 8);
433 memcpy(self->m_paletteChunk + 8, palette, 12);
434 self->m_crc = 0 /*crc32(0, Z_NULL, 0)*/;
435 self->m_crc = crc32(self->m_crc, self->m_paletteChunk + 4, 16);
436 set_uint32_be(self->m_paletteChunk + 20, self->m_crc);
437}
438
439static void png4file_open(Png4File * self,
440 const char * filename, int height, int width)
441{
442 self->m_fh = xfopen(filename, "wb");
443 self->m_width = width;
444 self->m_hleft = height;
445 self->m_nibble = -1;
446
447 xxfwrite(self->m_fh, CUS "\x89PNG\r\n\x1a\n" "\0\0\0\x0d", 12);
448
449 memcpy(self->m_buffer, "IHDR", 4);
450 set_uint32_be(self->m_buffer + 4, width);
451 set_uint32_be(self->m_buffer + 8, height);
452 memcpy(self->m_buffer + 12, "\004\003\0\0\0", 5);
453
454 eu32 crc = crc32(0, self->m_buffer, 17);
455 set_uint32_be(self->m_buffer + 17, crc);
456 xxfwrite(self->m_fh, self->m_buffer, 21);
457
458 xxfwrite(self->m_fh, self->m_paletteChunk, sizeof self->m_paletteChunk);
459
460 /* XXX quick hack, first color transparent. */
461 xxfwriteCS(self->m_fh, "\0\0\0\001" "tRNS" "\0" "\x40\xe6\xd8\x66");
462
463 xxfwrite(self->m_fh, CUS "\0\0\0\0IDAT" "\x78\001", 10);
464 self->m_buffer[0] = '\0';
465 self->m_buffer[5] = '\0';
466 self->m_bufPos = 6;
467 self->m_chunkLen = 2; /* 78 01, zlib header */
468 self->m_crc = crc32(0, CUS "IDAT" "\x78\001", 6);
469 self->m_adler = 1 /* adler32(0, Z_NULL, 0) */;
470}
471
472static void png4file_flush(Png4File * self)
473{
474 int l = self->m_bufPos - 5;
475 self->m_chunkLen += self->m_bufPos;
476 set_uint16_le(self->m_buffer + 1, l);
477 set_uint16_le(self->m_buffer + 3, l ^ 0xffff);
478 xxfwrite(self->m_fh, self->m_buffer, self->m_bufPos);
479 self->m_crc = crc32(self->m_crc, self->m_buffer, self->m_bufPos);
480 self->m_adler = adler32(self->m_adler, self->m_buffer + 5, self->m_bufPos - 5);
481 self->m_buffer[0] = '\0';
482 self->m_bufPos = 5;
483}
484
485static void png4file_addpixel(Png4File * self, eu8 pixel)
486{
487 if (self->m_nibble < 0)
488 self->m_nibble = (pixel << 4);
489 else
490 {
491 self->m_buffer[self->m_bufPos++] = self->m_nibble | pixel;
492 self->m_nibble = -1;
493 if (self->m_bufPos == sizeof self->m_buffer - 4)
494 png4file_flush(self);
495 }
496}
497
498static void png4file_endrow(Png4File * self)
499{
500 if (self->m_nibble >= 0)
501 {
502 self->m_buffer[self->m_bufPos++] = self->m_nibble;
503 self->m_nibble = -1;
504 }
505
506 self->m_hleft--;
507 if (self->m_hleft)
508 self->m_buffer[self->m_bufPos++] = '\0';
509}
510
511static void png4file_close(Png4File * self)
512{
513 eu8 adlerbuf[4];
514 self->m_buffer[0] = 0x01;
515 if (self->m_bufPos)
516 png4file_flush(self);
517 else
518 {
519 self->m_bufPos = 5;
520 png4file_flush(self);
521 }
522
523 set_uint32_be(adlerbuf, self->m_adler);
524 xxfwrite(self->m_fh, adlerbuf, 4);
525 self->m_crc = crc32(self->m_crc, adlerbuf, 4);
526 xxfwrite_uint32_be(self->m_fh, self->m_crc);
527 xxfwriteCS(self->m_fh, "\0\0\0\0" "IEND" "\xae\x42\x60\x82");
528 xfseek0(self->m_fh, 70);
529 xxfwrite_uint32_be(self->m_fh, self->m_chunkLen + 4 /* adler*/);
530 fclose(self->m_fh);
531 self->m_fh = NULL;
532}
533
534static eu8 getnibble(eu8 ** data, int * nibble)
535{
536 if (*nibble >= 0)
537 {
538 eu8 rv = *nibble & 0x0f;
539 *nibble = -1;
540 return rv;
541 }
542 /* else */
543 *nibble = *(*data)++;
544 return *nibble >> 4;
545}
546
547
548static void getpixelline(eu8 ** data, int width, Png4File * picfile)
549{
550 int nibble = -1;
551 int col = 0;
552 int number = 0;
553 int cindex = 0;
554 /* Originally from gtkspu - this from the python implementation of this */
555
556 while (1)
557 {
558 int bits = getnibble(data, &nibble);
559 if ((bits & 0xc) != 0)
560 {
561 /* have 4-bit code */
562 number = (bits & 0xc) >> 2;
563 cindex = bits & 0x3; }
564 else
565 {
566 bits = (bits << 4) | getnibble(data, &nibble);
567 if ((bits & 0xf0) != 0)
568 {
569 /* have 8-bit code */
570 number = (bits & 0x3c) >> 2;
571 cindex = bits & 0x3;
572 }
573 else
574 {
575 bits = (bits << 4) | getnibble(data, &nibble);
576 if ((bits & 0xfc0) != 0)
577 {
578 /* have 12-bit code */
579 number = (bits & 0xfc) >> 2;
580 cindex = bits & 0x3;
581 }
582 else
583 {
584 /* have 16-bit code */
585 bits = (bits << 4) | getnibble(data, &nibble);
586 number = (bits & 0x3fc) >> 2;
587 cindex = bits & 0x3;
588
589 if (number == 0)
590 number = width;
591 }
592 }
593 }
594
595 /* printf("%d %d %d %d\n", number, col, width, cindex); */
596 for (; number > 0 && col < width; number--, col++)
597 png4file_addpixel(picfile, cindex);
598
599 if (col == width)
600 {
601 png4file_endrow(picfile);
602 return;
603 }
604 }
605}
606
607static void makebitmap(eu8 * data, int w, int h, int top, int bot,
608 char * filename, eu8 palette[4][3])
609{
610 if (top < 0 || bot < 0)
611 {
612 printf("ERROR: invalid arguments to makebitmap");
613 return;
614 }
615 eu8 * top_ibuf = data + top;
616 eu8 * bot_ibuf = data + bot;
617 Png4File picfile;
618
619 png4file_init(&picfile, palette); /* not bottleneck even re-doing this every time */
620 png4file_open(&picfile, filename, h, w);
621 for (int i = 0; i < h / 2; i++)
622 {
623 getpixelline(&top_ibuf, w, &picfile);
624 getpixelline(&bot_ibuf, w, &picfile);
625 }
626
627 png4file_close(&picfile);
628}
629
630
631static char * pts2ts(fu32 pts, char * rvbuf, bool is_png_filename)
632{
633 uint32_t h = pts / (3600 * 90000UL);
634 uint32_t m = pts / (60 * 90000UL) % 60;
635 uint32_t s = pts / 90000 % 60;
636 uint32_t hs = (pts + 450) / 900 % 100;
637
638 if (is_png_filename)
639 sprintf(rvbuf, "%02d+%02d+%02d.%02d.png", h, m, s, hs);
640 else
641 sprintf(rvbuf, "%02d:%02d:%02d.%02d", h, m, s, hs);
642
643 return rvbuf;
644}
645
646/* *********** */
647
648typedef struct BoundStr
649{
651 int m_l;
653
654static void boundstr_init(BoundStr * bs, eu8 * p, int l)
655{
656 bs->m_p = p;
657 bs->m_l = l;
658}
659
660static eu8 * boundstr_read(BoundStr * bs, int l)
661{
662 if (l > bs->m_l)
663 exc_throw(IndexError, "XXX IndexError %p.", bs);
664 eu8 * rp = bs->m_p;
665 bs->m_p += l;
666 bs->m_l -= l;
667 return rp;
668}
669
670/* *********** */
671
672
673static void pxsubtitle(const char * supfile, FILE * ofh, eu8 palette[16][3],
674 bool createpics, int delay_ms,
675 char * fnbuf, char * fnbuf_fp)
676{
677 char junk[32];
678 char sptsstr[32];
679 eu8 data[65536];
680 time_t volatile pt = 0;
681 bool volatile last = false;
682 /*char transparent[8]; */
683 FILE * sfh = xfopen(supfile, "rb");
684 if (memcmp(xxfread(sfh, data, 2), "SP", 2) != 0)
685 {
686 exc_throw(MiscError, "Syncword missing. XXX bailing out.");
687 }
688
689 /*sprintf(transparent,
690 "%02x%02x%02x", palette[0][0], palette[0][1], palette[0][2]); */
691
692 exc_try(1)
693 {
694 eu32 volatile lastendpts = 0;
695
696 while (1)
697 {
698 /* X.java reads 5 bytes of pts, SubPicture.java writes 4. With
699 * 4 bytes 47721 seconds (13.25 hours) can be handled.
700 * Later, bytes 1,2,3,4 (instead of 0,1,2,3) could be used.
701 * 256/90000 = 1/351 sec -- way better than required resolution.
702 */
703 eu32 volatile pts = get_uint32_le(xxfread(sfh, data, 8));
704 eu16 size = get_uint16_be(xxfread(sfh, data, 2));
705 eu16 pack = get_uint16_be(xxfread(sfh, data, 2));
706 xxfread(sfh, data, pack - 4);
707 eu8 * ctrl = data + pack - 4;
708 xxfread(sfh, ctrl, size - pack);
709
710 exc_try(2)
711 {
712 if (memcmp(xxfread(sfh, (unsigned char *)junk, 2),
713 "SP", 2) != 0)
714 exc_throw(MiscError, "Syncword missing. XXX bailing out.");
715 }
717 last = true;
718 exc_end(2);
719 {
720 BoundStr bs;
721 int x1 = -1;
722 int x2 = -1;
723 int y1 = -1;
724 int y2 = -1;
725 int top_field = -1;
726 int bot_field = -1;
727 int end = 0;
728 eu8 this_palette[4][3];
729 boundstr_init(&bs, ctrl, size - pack);
730
731 int prev = 0;
732 while (1)
733 {
734 int date = get_uint16_be(boundstr_read(&bs, 2));
735 int next = get_uint16_be(boundstr_read(&bs, 2));
736
737 while (1)
738 {
739 eu8 * p = 0;
740 eu8 cmd = boundstr_read(&bs, 1)[0];//NOLINT(clang-analyzer-security.ArrayBound)
741 int xpalette = 0;
742 int colcon_length = 0;
743 switch (cmd)
744 {
745 case 0x00: /* force display: */
746 case 0x01: /* start date (read above) */
747 continue;
748 case 0x02: /* stop date (read above) */
749 end = date;
750 continue;
751 case 0x03: /* palette */
752 xpalette = get_uint16_be(boundstr_read(&bs, 2));
753 for (int n = 0; n < 4; n++) {
754 int i = (xpalette >> (n * 4) & 0x0f);
755 this_palette[n][0] = palette[i][0];
756 this_palette[n][1] = palette[i][1];
757 this_palette[n][2] = palette[i][2];
758 }
759 continue;
760 case 0x04: /* alpha channel */
761 /*alpha =*/ boundstr_read(&bs, 2);
762 continue;
763 case 0x05: /* coordinates */
764 p = boundstr_read(&bs, 6);
765 x1 = (p[0] << 4) + (p[1] >> 4);
766 x2 = ((p[1] & 0xf) << 8) + p[2];
767 y1 = (p[3] << 4) + (p[4] >> 4);
768 y2 = ((p[4] & 0xf) << 8) + p[5];
769 continue;
770 case 0x06: /* rle offsets */
771 top_field = get_uint16_be(boundstr_read(&bs, 2));
772 bot_field = get_uint16_be(boundstr_read(&bs, 2));
773 continue;
774 case 0x07: /* */
775 colcon_length = get_uint16_be(boundstr_read(&bs, 2)-2);
776 boundstr_read(&bs, colcon_length);
777 continue;
778 }
779 if (cmd == 0xff) /* end command */
780 break;
781 exc_throw(MiscError, "%d: Unknown control sequence", cmd);
782 }
783
784 if (prev == next)
785 break;
786 prev = next;
787 }
788
789 /* check for overlapping subtitles */
790 eu32 tmppts = pts;
791 if (delay_ms)
792 tmppts += delay_ms * 90;
793
794 /* hack to fix projectx bug adding wrong end times around a cut point*/
795 if (end > 500)
796 end = 500;
797
798 eu32 endpts = tmppts + (end * 1000); /* ProjectX ! (other: 900, 1024) */
799
800 if (tmppts <= lastendpts)
801 {
802 if (lastendpts < endpts)
803 {
804 pts = lastendpts + (2 * (1000 / 30) * 90);/*??? */
805 tmppts = pts;
806 if (delay_ms)
807 tmppts += delay_ms * 90;
808 printf("Fixed overlapping subtitle!\n");
809 }
810 else
811 {
812 printf("Dropping overlapping subtitle\n");
813 continue;
814 }
815 }
816
817 lastendpts = endpts;
818
819 pts2ts(pts, fnbuf_fp, true);
820 pts2ts(tmppts, sptsstr + 1, false);
821
822 time_t ct = 0;
823 if (pt != time(&ct))
824 {
825 pt = ct;
826 sptsstr[0] = '\r';
827 size_t len = write(1, sptsstr, strlen(sptsstr));
828 if (len != strlen(sptsstr))
829 printf("ERROR: write failed");
830 }
831
832 fprintf(ofh, " <spu start=\"%s\" end=\"%s\" image=\"%s\""
833 " xoffset=\"%d\" yoffset=\"%d\" />\n",
834 sptsstr + 1, pts2ts(endpts, junk, false),
835 fnbuf, x1, y1);
836
837 if (createpics)
838 makebitmap(data, x2 - x1 + 1, y2 - y1 + 1, top_field - 4,
839 bot_field - 4, fnbuf, this_palette);
840 if (last)
841 exc_throw(EOFIndicator, NULL);
842 }
843 }
844 }
846 {
847 size_t len = write(1, sptsstr, strlen(sptsstr));
848 if (len != strlen(sptsstr))
849 printf("ERROR: write failed");
850 exc_cleanup();
851 fclose(sfh);
852 return;
853 }
854 exc_end(1);
855}
856
857#if 0
858GCCATTR_NORETURN static void usage(const char * pn)
859{
860 exc_throw(MiscError, "\n"
861 "Usage: %s [--delay ms] <supfile> <ifofile>|<palette>" "\n"
862 "\n"
863 "\tExamples:" "\n"
864 "\n"
865 "\t ProjectX decoded recording.sup and recording.sup.IFO" "\n"
866 "\n"
867 "\t\t$ pxsup2dast recording.sup*" "\n"
868 "\n"
869 "\t Having test.sup and map.ifo" "\n"
870 "\n"
871 "\t\t$ pxsup2dast test.sup map.ifo" "\n"
872 "\n"
873 "\t No .IFO, so giving 3 colors (rgb components in hex)" "\n"
874 "\n"
875 "\t\t$ pxsup2dast titles.sup ff0000,00ff00,0000ff" "\n"
876 "\n"
877 "\t Trying to fix sync in recording" "\n"
878 "\n"
879 "\t\t$ pxsup2dast --delay 750 recording.sup*" "\n"
880 , pn);
881}
882#endif
883
884static bool samepalette(char * filename, eu8 palette[16][3])
885{
886 if (!fexists(filename))
887 return false;
888
889 FILE *fh = xfopen(filename, "rb");
890 for (int i = 0; i < 16; i++)
891 {
892 unsigned int r=0;
893 unsigned int g=0;
894 unsigned int b=0;
895 if (fscanf(fh, "%02x%02x%02x\n", &r, &g, &b) != 3 ||
896 r != palette[i][0] || g != palette[i][1] || b != palette[i][2])
897 {
898 fclose(fh);
899 return false;
900 }
901 }
902 fclose(fh);
903 return true;
904}
905
906int sup2dast(const char *supfile, const char *ifofile ,int delay_ms)
907{
908 exc_try(1)
909 {
910 int i = 0;
911 eu8 yuvpalette[16][3];
912 eu8 rgbpalette[16][3];
913 char fnbuf[1024];
914 char * p = NULL;
915
916 bool createpics = false;
917
918 memset(yuvpalette, 0, sizeof(yuvpalette));
919 memset(rgbpalette, 0, sizeof(rgbpalette));
920
921 if (write(1, "\n", 1) != 1)
922 printf("ERROR: write failed");
923
924 if (sizeof (char) != 1 || sizeof (int) < 2) /* very unlikely */
925 exc_throw(MiscError, "Incompatible variable sizes.");
926
927 p = strrchr(supfile, '.');
928 if (p != NULL)
929 i = p - supfile;
930 else
931 i = strlen(supfile);
932 if (i > 950)
933 exc_throw(MiscError, "Can "
934 "not manage filenames longer than 950 characters.");
935 memcpy(fnbuf, supfile, i);
936 p = fnbuf + i;
937 strcpy(p, ".d/");
938 p += strlen(p);
939
940 if (!dexists(fnbuf))
941 xmkdir(fnbuf, 0755);
942
943 if (fexists(ifofile))
944 ifopalette(ifofile, yuvpalette, rgbpalette);
945 else
946 argpalette(ifofile, yuvpalette, rgbpalette);
947
948 strcpy(p, "palette.ycrcb");
949 if (samepalette(fnbuf, yuvpalette))
950 {
951 createpics = false;
952 printf("Found palette.yuv having our palette information...\n");
953 printf("...Skipping image files, Writing spumux.tmp.\n");
954 }
955 else
956 {
957 createpics = true;
958 printf("Writing image files and spumux.tmp.\n");
959 }
960
961 strcpy(p, "spumux.tmp");
962 FILE *fh = xfopen(fnbuf, "wb");
963
964 xxfwriteCS(fh, "<subpictures>\n <stream>\n");
965 pxsubtitle(supfile, fh, rgbpalette, createpics, delay_ms, fnbuf, p);
966
967 if (write(1, "\n", 1) != 1)
968 printf("ERROR: write failed");
969
970 xxfwriteCS(fh, " </stream>\n</subpictures>\n");
971 fclose(fh);
972
973 if (createpics)
974 {
975 printf("Writing palette.ycrcb and palette.rgb.\n");
976 strcpy(p, "palette.ycrcb");
977 FILE *yuvfh = xfopen(fnbuf, "wb");
978 strcpy(p, "palette.rgb");
979 FILE *rgbfh = xfopen(fnbuf, "wb");
980 for (i = 0; i < 16; i++)
981 {
982 fprintf(yuvfh, "%02x%02x%02x\n",
983 yuvpalette[i][0], yuvpalette[i][1], yuvpalette[i][2]);
984 fprintf(rgbfh, "%02x%02x%02x\n",
985 rgbpalette[i][0], rgbpalette[i][1], rgbpalette[i][2]);
986 }
987 fclose(yuvfh);
988 fclose(rgbfh);
989 }
990
991 {
992 char buf[1024];
993 printf("Renaming spumux.tmp to spumux.xml.\n");
994 strcpy(p, "spumux.tmp");
995 i = strlen(fnbuf);
996 memcpy(buf, fnbuf, i);
997 strcpy(&buf[i - 3], "xml");
998 unlink(buf);
999 rename(fnbuf, buf);
1000 }
1001 p[0] = '\0';
1002 printf("Output files reside in %s\n", fnbuf);
1003 printf("All done.\n");
1004 }
1005
1007 {
1008 if (write(2, EXC.m_msgbuf, EXC.m_buflen) != EXC.m_buflen)
1009 printf("ERROR: write failed");
1010
1011 if (write(2, "\n", 1) != 1)
1012 printf("ERROR: write failed");
1013
1014 exc_cleanup();
1015 return 1;
1016 }
1017 exc_endall(1);
1018
1019 return 0;
1020}
static uint32_t crc32(const unsigned char *data, int len)
Definition: dsmcc.cpp:616
static std::vector< uint32_t > pixel
--------------------------------------------------—**
Definition: goom_core.cpp:26
unsigned short uint16_t
Definition: iso6937tables.h:3
static int x1
Definition: mythsocket.cpp:54
static int x2
Definition: mythsocket.cpp:55
std::chrono::duration< CHRONO_TYPE, std::ratio< 1, 90000 > > pts
Definition: mythchrono.h:44
def write(text, progress=True)
Definition: mythburn.py:306
int FILE
Definition: mythburn.py:137
static void set_uint32_be(eu8 *ptr, eu32 value)
Definition: pxsup2dast.c:326
static char * pts2ts(fu32 pts, char *rvbuf, bool is_png_filename)
Definition: pxsup2dast.c:631
int16_t ei16
Definition: pxsup2dast.c:53
static bool fexists(const char *filename)
Definition: pxsup2dast.c:278
static fu32 get_uint32_le(const eu8 *bytes)
Definition: pxsup2dast.c:311
@ EOFIndicator
Definition: pxsup2dast.c:74
@ MiscError
Definition: pxsup2dast.c:74
@ IndexError
Definition: pxsup2dast.c:74
uint_fast32_t fu32
Definition: pxsup2dast.c:62
int_least32_t li32
Definition: pxsup2dast.c:58
int_fast16_t fi16
Definition: pxsup2dast.c:61
uint8_t eu8
Definition: pxsup2dast.c:52
static GCCATTR_NORETURN void __exc_throw(int type)
Definition: pxsup2dast.c:123
int_fast32_t fi32
Definition: pxsup2dast.c:62
struct @79 EXC
int_least16_t li16
Definition: pxsup2dast.c:57
static eu8 * boundstr_read(BoundStr *bs, int l)
Definition: pxsup2dast.c:660
static void png4file_close(Png4File *self)
Definition: pxsup2dast.c:511
#define xxfwriteCS(f, s)
Definition: pxsup2dast.c:199
int_least8_t li8
Definition: pxsup2dast.c:56
struct BoundStr BoundStr
struct Png4File Png4File
struct exc__state * m_last
Definition: pxsup2dast.c:88
static bool samepalette(char *filename, eu8 palette[16][3])
Definition: pxsup2dast.c:884
#define exc_end(x)
Definition: pxsup2dast.c:112
static void yuv2rgb(int y, int cr, int cb, eu8 *r, eu8 *g, eu8 *b)
Definition: pxsup2dast.c:210
static void xxfwrite(FILE *stream, const eu8 *ptr, size_t size)
Definition: pxsup2dast.c:188
#define exc_catch(x, t)
Definition: pxsup2dast.c:110
#define CUS
Definition: pxsup2dast.c:72
static void png4file_init(Png4File *self, eu8 palette[4][3])
Definition: pxsup2dast.c:430
#define exc_try(x)
Definition: pxsup2dast.c:97
static void ifopalette(const char *filename, eu8 yuvpalette[16][3], eu8 rgbpalette[16][3])
Definition: pxsup2dast.c:351
int_fast8_t fi8
Definition: pxsup2dast.c:60
static void png4file_open(Png4File *self, const char *filename, int height, int width)
Definition: pxsup2dast.c:439
static void boundstr_init(BoundStr *bs, eu8 *p, int l)
Definition: pxsup2dast.c:654
uint_least32_t lu32
Definition: pxsup2dast.c:58
static fu32 get_uint32_be(const eu8 *bytes)
Definition: pxsup2dast.c:297
static void rgb2yuv(eu8 r, eu8 g, eu8 b, eu8 *y, eu8 *cr, eu8 *cb)
Definition: pxsup2dast.c:223
static bool dexists(const char *filename)
Definition: pxsup2dast.c:287
uint_least8_t lu8
Definition: pxsup2dast.c:56
static void set2palettes(int value, eu8 *yuvpalpart, eu8 *rgbpalpart)
Definition: pxsup2dast.c:382
static void argpalette(const char *arg, eu8 yuvpalette[16][3], eu8 rgbpalette[16][3])
Definition: pxsup2dast.c:396
static eu8 getnibble(eu8 **data, int *nibble)
Definition: pxsup2dast.c:534
static void pxsubtitle(const char *supfile, FILE *ofh, eu8 palette[16][3], bool createpics, int delay_ms, char *fnbuf, char *fnbuf_fp)
Definition: pxsup2dast.c:673
static void xfseek0(FILE *stream, long offset)
Definition: pxsup2dast.c:259
uint_least16_t lu16
Definition: pxsup2dast.c:57
static GCCATTR_NORETURN void exc_throw(int type, const char *format,...)
Definition: pxsup2dast.c:130
static void png4file_flush(Png4File *self)
Definition: pxsup2dast.c:472
static void makebitmap(eu8 *data, int w, int h, int top, int bot, char *filename, eu8 palette[4][3])
Definition: pxsup2dast.c:607
static void xmkdir(const char *path, int mode)
Definition: pxsup2dast.c:265
#define exc_cleanup()
Definition: pxsup2dast.c:121
#define exc_catchall
Definition: pxsup2dast.c:118
uint32_t eu32
Definition: pxsup2dast.c:54
uint16_t eu16
Definition: pxsup2dast.c:53
int m_buflen
Definition: pxsup2dast.c:90
int sup2dast(const char *supfile, const char *ifofile, int delay_ms)
Definition: pxsup2dast.c:906
#define GCCATTR_NORETURN
Definition: pxsup2dast.c:68
static void png4file_endrow(Png4File *self)
Definition: pxsup2dast.c:498
#define exc_endall(x)
Definition: pxsup2dast.c:119
static eu8 * xxfread(FILE *stream, eu8 *ptr, size_t size)
Definition: pxsup2dast.c:177
static FILE * xfopen(const char *filename, const char *mode)
Definition: pxsup2dast.c:251
static void xxfwrite_uint32_be(FILE *fh, eu32 value)
Definition: pxsup2dast.c:344
char m_msgbuf[1024]
Definition: pxsup2dast.c:89
int8_t ei8
Definition: pxsup2dast.c:52
uint_fast16_t fu16
Definition: pxsup2dast.c:61
static void getpixelline(eu8 **data, int width, Png4File *picfile)
Definition: pxsup2dast.c:548
static void set_uint16_le(eu8 *ptr, eu16 value)
Definition: pxsup2dast.c:339
static fu16 get_uint16_be(const eu8 *bytes)
Definition: pxsup2dast.c:305
static eu8 clamp(eu8 value, eu8 low, eu8 high)
Definition: pxsup2dast.c:201
int32_t ei32
Definition: pxsup2dast.c:54
uint_fast8_t fu8
Definition: pxsup2dast.c:60
static void png4file_addpixel(Png4File *self, eu8 pixel)
Definition: pxsup2dast.c:485
static void usage(char *progname)
Definition: replex.cpp:2413
eu8 * m_p
Definition: pxsup2dast.c:650
int m_nibble
Definition: pxsup2dast.c:421
eu8 m_paletteChunk[24]
Definition: pxsup2dast.c:426
FILE * m_fh
Definition: pxsup2dast.c:418
int m_chunkLen
Definition: pxsup2dast.c:423
eu32 m_adler
Definition: pxsup2dast.c:425
int m_hleft
Definition: pxsup2dast.c:420
eu32 m_crc
Definition: pxsup2dast.c:424
eu8 m_buffer[65536]
Definition: pxsup2dast.c:427
int m_bufPos
Definition: pxsup2dast.c:422
int m_width
Definition: pxsup2dast.c:419
struct exc__state * m_prev
Definition: pxsup2dast.c:82
jmp_buf m_env
Definition: pxsup2dast.c:83