Bug Summary

File:spuunmux.c
Location:line 402, column 17
Description:Potential leak of memory pointed to by 'newspu'

Annotated Source Code

1/*
2 spuunmux mainline
3*/
4/*
5 * Copyright (C) 2002, 2003 Jan Panteltje <panteltje@yahoo.com>,
6 *
7 * Modified by Zachary Brewster-Geisz, 2003, to work on big-endian
8 * machines.
9 *
10 * Modified by Henry Mason, 2003, to use both PNG and BMP, and to use
11 * the dvdauthor submux format.
12 *
13 * Modified and copy right Jan Panteltje 2002
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or (at
17 * your option) any later version.
18 *
19 * With many changes by Scott Smith (trckjunky@users.sourceforge.net)
20 *
21 * Svcd decoding by Giacomo Comes <encode2mpeg@users.sourceforge.net>
22 *
23 * This program is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
31 * MA 02110-1301 USA.
32 */
33
34#include "config.h"
35#include "compat.h"
36
37#include <fcntl.h>
38#include <errno(*__errno_location ()).h>
39
40#include <netinet/in.h>
41
42#include <png.h>
43#include <zlib.h>
44
45#include "rgb.h"
46#include "common.h"
47#include "conffile.h"
48
49#define CBUFSIZE65536 65536 /* big enough for any MPEG packet */
50#define PSBUFSIZE10 10
51
52static unsigned int add_offset;
53
54static int debug = 0;
55
56static int video_format = VF_NONE;
57static bool_Bool full_size = false0;
58static unsigned int pts, spts, subi, subs, subno;
59static int ofs, ofs1;
60 /* offsets from beginning of SPU to bottom and top field data set by last SPU_SET_DSPXA command */
61static unsigned char sub[65536];
62static unsigned char next_bits;
63static const char *base_name;
64static unsigned int have_bits;
65static FILE *fdo;
66static unsigned char svcd_adjust;
67
68static colorspec
69 current_palette[16]; /* current PGC colour table, alpha unused */
70
71struct spu /* data for one subpicture unit (SPU) */
72 {
73 unsigned char *img; /* image data */
74 unsigned int x0, y0, xd, yd; /* display bounds */
75 unsigned int pts[2]; /* start time, end time */
76 unsigned int subno; /* index used for generating unique filenames */
77 unsigned int force_display;
78 unsigned int nummap; /* length of map array */
79 struct colormap *map;
80 /* array where entry 0 is for colours as specified in SPU, other entries
81 are for button colours as specified in PGC, so if they overlap, the
82 last entry takes precedence */
83 struct spu *next; /* linked list */
84 };
85
86static struct spu
87 *pending_spus = 0;
88
89struct button /* information about a button */
90 {
91 char *name;
92 bool_Bool autoaction;
93 int x1, y1, x2, y2;
94 char *up, *down, *left, *right; /* names of neighbouring buttons */
95 int grp; /* which group button belongs to */
96 };
97
98struct dispdetails /* information about button grouping */
99 {
100 int pts[2]; /* start time, end time */
101 int numpal; /* nr used entries in palette */
102 uint32_t palette[16]; /* RGB colours */
103 int numcoli; /* nr of SL_COLI entries present, not checked! */
104 uint32_t coli[6]; /* up to 3 8-byte SL_COLI entries */
105 int numbuttons; /* length of buttons array */
106 struct button *buttons; /* array */
107 struct dispdetails *next; /* linked list */
108 };
109
110static struct dispdetails
111 *pending_buttons = 0;
112
113struct colormap /* for determining which colours take precedence in overlapping areas */
114 {
115 uint16_t color; /* four 4-bit colour indexes */
116 uint16_t contrast; /* four 4-bit contrast (transparency) values */
117 int x1, y1, x2, y2; /* bounds of area over which entries are valid */
118 };
119
120static unsigned int read4(const unsigned char *p)
121 /* decodes 4 bytes as a big-endian integer starting at p. */
122 {
123 return
124 p[0] << 24
125 |
126 p[1] << 16
127 |
128 p[2] << 8
129 |
130 p[3];
131 } /*read4*/
132
133static unsigned int read2(const unsigned char *p)
134 /* decodes 2 bytes as a big-endian integer starting at p. */
135 {
136 return
137 p[0] << 8
138 |
139 p[1];
140 } /*read2*/
141
142static char *readpstr(const unsigned char *b, int *i)
143 /* extracts a null-terminated string beginning at b[*i], advances *i past it and returns
144 a copy of the string. */
145 {
146 char * const s = strdup((const char *)b + i[0])(__extension__ (__builtin_constant_p ((const char *)b + i[0])
&& ((size_t)(const void *)(((const char *)b + i[0]) +
1) - (size_t)(const void *)((const char *)b + i[0]) == 1) ? (
((const char *) ((const char *)b + i[0]))[0] == '\0' ? (char *
) calloc ((size_t) 1, (size_t) 1) : ({ size_t __len = strlen (
(const char *)b + i[0]) + 1; char *__retval = (char *) malloc
(__len); if (__retval != ((void*)0)) __retval = (char *) memcpy
(__retval, (const char *)b + i[0], __len); __retval; })) : __strdup
((const char *)b + i[0])))
;
147 i[0] += strlen(s) + 1;
148 return s;
149 } /*readpstr*/
150
151static unsigned char get_next_bits()
152 /* returns next nibble from sub at offset ofs. */
153 {
154 if (!have_bits)
155 {
156 next_bits = sub[ofs++];
157 have_bits = true1;
158 return next_bits >> 4;
159 } /*if*/
160 have_bits = false0;
161 return next_bits & 15;
162 } /*get_next_bits*/
163
164static unsigned char get_next_svcdbits()
165 /* returns next two bits from sub at offset ofs. */
166 {
167 switch (have_bits)
168 {
169 case 0:
170 ++have_bits;
171 return sub[++ofs] >> 6;
172 break;
173 case 1:
174 ++have_bits;
175 return (sub[ofs] & 0x30) >> 4;
176 break;
177 case 2:
178 ++have_bits;
179 return (sub[ofs] & 0x0c) >> 2;
180 break;
181 default:
182 have_bits = 0;
183 return sub[ofs] & 0x03;
184 break;
185 } /*switch*/
186 } /*get_next_svcdbits*/
187
188static unsigned int getpts(const unsigned char *buf)
189 /* decodes a presentation time stamp (PTS) beginning at location buf. */
190 {
191 if
192 (
193 !(buf[1] & 0xc0)
194 ||
195 buf[2] < 4
196 ||
197 (buf[3] & 0xe1) != 0x21
198 ||
199 (buf[5] & 1) != 1
200 ||
201 (buf[7] & 1) != 1
202 )
203 return -1; /* doesn't look like a proper PTS */
204 return
205 (buf[7] >> 1)
206 +
207 ((unsigned int)buf[6] << 7)
208 +
209 (((unsigned int)buf[5] & 254) << 14)
210 +
211 ((unsigned int)buf[4] << 22)
212 +
213 (((unsigned int)buf[3] & 14) << 29);
214 } /*getpts*/
215
216static void addspu(struct spu *s)
217 /* appends s onto pending_spus. */
218 {
219 struct spu **f = &pending_spus;
220 while (*f)
221 f = &f[0]->next;
222 *f = s;
223 } /*addspu*/
224
225static void add_pending_buttons(struct dispdetails *d)
226 /* appends d onto pending_buttons. */
227 {
228 struct dispdetails **dp = &pending_buttons;
229 while (*dp)
230 dp = &dp[0]->next;
231 *dp = d;
232 } /*add_pending_buttons*/
233
234static int dvddecode()
235 /* decodes DVD-Video subpicture data from sub and appends a new entry containing
236 the results onto pending_spus. */
237 {
238 unsigned int io;
239 uint16_t total_spu_size, dsize, thiscmdoffset, nextcmdoffset, i, x, y, t;
240 unsigned char c;
241 struct spu *newspu;
242 total_spu_size = read2(sub); /* SPDSZ = size of SPU */
243 dsize = read2(sub + 2); /* SP_DCSQTA = offset to SP_DCSQT */
244 ofs = -1;
245 if (debug > 1)
1
Assuming 'debug' is <= 1
2
Taking false branch
246 fprintf(stderrstderr, "packet: %d bytes, first block offset=%d\n", total_spu_size, dsize);
247 newspu = malloc(sizeof(struct spu));
3
Memory is allocated
248 memset(newspu, 0, sizeof(struct spu));
249 newspu->subno = subno++;
250 newspu->pts[0] = newspu->pts[1] = -1;
251 newspu->nummap = 1;
252 newspu->map = malloc(sizeof(struct colormap));
253 memset(newspu->map, 0, sizeof(struct colormap));
254 newspu->map[0].x2 = 0x7fffffff;
255 newspu->map[0].y2 = 0x7fffffff;
256 i = dsize + 4; /* start of commands */
257 thiscmdoffset = dsize;
258 nextcmdoffset = read2(sub + thiscmdoffset + 2);
259 if (nextcmdoffset < dsize)
4
Taking false branch
260 {
261 if (debug > 0)
262 {
263 fprintf
264 (
265 stderrstderr,
266 "invalid control header nextcommand=%d dsize=%d!\n",
267 nextcmdoffset,
268 dsize
269 );
270 } /*if*/
271 nextcmdoffset = thiscmdoffset;
272 } /*if*/
273 t = read2(sub + dsize); /* SP_DCSQ_STM = delay in 90kHz units / 1024 before executing commands */
274 if (debug > 2)
5
Taking false branch
275 fprintf
276 (
277 stderrstderr,
278 "\tBLK(%5d): time offset: %d; next: %d\n",
279 dsize, t, read2(sub + dsize + 2)
280 );
281 /* decode the commands, including finding out where the image data is */
282 while (i < total_spu_size)
6
Loop condition is true. Entering loop body
283 {
284 c = sub[i]; /* get next command */
285 switch (c)
7
Control jumps to the 'default' case at line 401
286 {
287 case SPU_FSTA_DSP:
288 if (debug > 4)
289 fprintf(stderrstderr, "\tcmd(%5d): force start display\n", i);
290 newspu->force_display = true1;
291 // fall through
292 case SPU_STA_DSP:
293 if (debug > 4 && c == SPU_STA_DSP)
294 fprintf(stderrstderr, "\tcmd(%5d): start display\n", i);
295 i++;
296 newspu->pts[0] = t * 1024 + spts;
297 break;
298
299 case SPU_STP_DSP:
300 if (debug > 4)
301 fprintf(stderrstderr, "\tcmd(%5d): end display\n", i);
302 newspu->pts[1] = t * 1024 + spts;
303 i++;
304 break;
305
306 case SPU_SET_COLOR:
307 if (debug > 4)
308 fprintf(stderrstderr, "\tcmd(%5d): palette=%02x%02x\n", i, sub[i + 1], sub[i + 2]);
309 newspu->map[0].color = read2(sub + i + 1);
310 i += 3;
311 break;
312
313 case SPU_SET_CONTR:
314 if (debug > 4)
315 fprintf(stderrstderr, "\tcmd(%5d): transparency=%02x%02x\n", i, sub[i + 1], sub[i + 2]);
316 newspu->map[0].contrast = read2(sub + i + 1);
317 i += 3;
318 break;
319
320 case SPU_SET_DAREA:
321 newspu->x0 = ((((unsigned int)sub[i + 1]) << 4) + (sub[i + 2] >> 4));
322 newspu->xd = (((sub[i + 2] & 0x0f) << 8) + sub[i + 3]) - newspu->x0 + 1;
323 newspu->y0 = ((((unsigned int)sub[i + 4]) << 4) + (sub[i + 5] >> 4));
324 newspu->yd = (((sub[i + 5] & 0x0f) << 8) + sub[i + 6]) - newspu->y0 + 1;
325 if (debug > 4)
326 fprintf
327 (
328 stderrstderr,
329 "\tcmd(%5d): image corner=%d,%d, size=%d,%d\n",
330 i, newspu->x0, newspu->y0, newspu->xd, newspu->yd
331 );
332 i += 7;
333 break;
334
335 case SPU_SET_DSPXA:
336 if (ofs >= 0)
337 fprintf(stderrstderr, "WARN: image pointer already supplied for this subpicture\n");
338 /* not necessarily wrong, it's just I can't handle it */
339 ofs = read2(sub + i + 1); /* offset to top field data */
340 ofs1 = read2(sub + i + 3); /* offset to bottom field data */
341 if (debug > 4)
342 fprintf(stderrstderr, "\tcmd(%5d): image offsets=%d,%d\n", i, ofs, ofs1);
343 i += 5;
344 break;
345
346 case SPU_CMD_END:
347 if (thiscmdoffset == nextcmdoffset) /* no next SP_DCSQ */
348 {
349 if (debug > 4)
350 {
351 fprintf(stderrstderr, "cmd: last end command\n");
352 if (i + 1 < total_spu_size)
353 {
354 fprintf
355 (
356 stderrstderr,
357 "data present after last command (%d bytes, size=%d)\n",
358 total_spu_size - (i + 1),
359 total_spu_size
360 );
361 } /*if*/
362 } /*if*/
363 i = total_spu_size; /* indicate I'm finished */
364 break;
365 } /*if*/
366 if (debug > 4)
367 fprintf(stderrstderr, "\tcmd(%5d): end cmd\n", i);
368 /* another SP_DCSQT follows */
369 thiscmdoffset = nextcmdoffset;
370 nextcmdoffset = read2(sub + thiscmdoffset + 2);
371 if (nextcmdoffset < dsize)
372 {
373 if (debug > 0)
374 {
375 fprintf
376 (
377 stderrstderr,
378 "invalid control header nextcommand=%d dsize=%d!\n",
379 nextcmdoffset,
380 dsize
381 );
382 } /*if*/
383 nextcmdoffset = thiscmdoffset;
384 i = total_spu_size; /* force an end to all this */
385 break;
386 } /*if*/
387 t = read2(sub + thiscmdoffset); /* SP_DCSQ_STM = delay in 90kHz units / 1024 before executing commands */
388 if (debug > 4)
389 {
390 fprintf(stderrstderr, "\tcmd(%5d): end cmd\n", i);
391 fprintf(stderrstderr, "\tBLK(%5d): time offset: %d; next: %d\n", i + 1, t, read2(sub + i + 3));
392 } /*if*/
393 if (debug > 4 && i + 1 < thiscmdoffset)
394 {
395 fprintf(stderrstderr, "next packet jump: %d bytes\n", thiscmdoffset - (i + 1));
396 } /*if*/
397 i = thiscmdoffset + 4; /* start of next lot of commands */
398 break;
399
400 /* case SPU_CHG_COLCON: */ /* fixme: not handled */
401 default:
402 if (debug > 4)
8
Potential leak of memory pointed to by 'newspu'
403 fprintf(stderrstderr, "\tcmd(%5d): 0x%x\n", i, c);
404 if (debug > 0)
405 fprintf(stderrstderr, "invalid sequence in control header (%02x)!\n", c);
406 return -1;
407 } /*switch*/
408 } /*while*/
409
410 /* now to decode the actual image data */
411 have_bits = false0;
412 x = y = 0;
413 io = 0;
414 newspu->img = malloc(newspu->xd * newspu->yd);
415 if (ofs < 0 && y < newspu->yd)
416 {
417 fprintf(stderrstderr, "WARN: No image data supplied for this subtitle\n");
418 }
419 else
420 {
421 /* decode image data */
422 while (ofs < dsize && y < newspu->yd)
423 {
424 i = get_next_bits();
425 if (i < 4)
426 {
427 i = (i << 4) + get_next_bits();
428 if (i < 16)
429 {
430 i = (i << 4) + get_next_bits();
431 if (i < 0x40)
432 {
433 i = (i << 4) + get_next_bits();
434 if (i < 4)
435 {
436 i = i + (newspu->xd - x) * 4; /* run ends at end of line */
437 } /*if*/
438 } /*if*/
439 } /*if*/
440 } /*if*/
441 c = i & 3; /* pixel value */
442 i = i >> 2; /* count */
443 while (i--)
444 {
445 newspu->img[io++] = c;
446 if (++x == newspu->xd)
447 {
448 /* end of scanline */
449 y += 2;
450 x = 0;
451 if (y >= newspu->yd && !(y & 1))
452 {
453 /* end of top (odd) field, now do bottom (even) field */
454 y = 1;
455 io = newspu->xd;
456 ofs = ofs1;
457 }
458 else
459 io += newspu->xd; /* next scanline */
460 have_bits = false0;
461 } /*if*/
462 } /*while*/
463 } /*while*/
464 } /*if*/
465 if (newspu->pts[0] == -1)
466 return 0; /* fixme: free newspu or report error? */
467 newspu->pts[0] += add_offset;
468 if (newspu->pts[1] != -1)
469 newspu->pts[1] += add_offset;
470 addspu(newspu);
471 return 0;
472 } /*dvddecode*/
473
474 /*
475 * from Y -> R
476 * from V -> G
477 * from U -> B
478 */
479
480static void ycrcb_to_rgb(int *Y, int *Cr, int *Cb)
481{
482 int R, G, B;
483 R = YCrCb2R(*Y,*Cr,*Cb);
484 G = YCrCb2G(*Y,*Cr,*Cb);
485 B = YCrCb2B(*Y,*Cr,*Cb);
486 *Y = R;
487 *Cr = G;
488 *Cb = B;
489}
490
491static void absorb_palette(const struct dispdetails *d)
492 /* extracts the colour palette from d and puts it in RGB format into current_palette. */
493 {
494 int i;
495 for (i = 0; i < d->numpal; i++)
496 {
497 int Y, Cr, Cb;
498 Y = d->palette[i] >> 16 & 255;
499 Cr = d->palette[i] >> 8 & 255;
500 Cb = d->palette[i] & 255;
501 current_palette[i].r = YCrCb2R(Y, Cr, Cb);
502 current_palette[i].g = YCrCb2G(Y, Cr, Cb);
503 current_palette[i].b = YCrCb2B(Y, Cr, Cb);
504 } /*for*/
505 } /*absorb_palette*/
506
507static void pluck_pending_buttons()
508 /* removes the head of pending_buttons, copies its palette into current_palette,
509 and gets rid of it. */
510 {
511 struct dispdetails * const d = pending_buttons;
512 int i;
513 pending_buttons = d->next;
514 absorb_palette(d);
515 for (i = 0; i < d->numbuttons; i++)
516 {
517 free(d->buttons[i].name);
518 free(d->buttons[i].up);
519 free(d->buttons[i].down);
520 free(d->buttons[i].left);
521 free(d->buttons[i].right);
522 } /*for*/
523 free(d->buttons);
524 free(d);
525 } /*pluck_pending_buttons*/
526
527static unsigned char cmap_find
528 (
529 int x,
530 int y,
531 const struct colormap *map, /* array */
532 int nummap, /* length of map array */
533 int ci /* pixel value */
534 )
535 /* returns the colour index (low nibble) and contrast (high nibble) of the
536 specified pixel, as determined from the highest-numbered entry of map that
537 covers its coordinates. Returns 0 if no entry is found. */
538 {
539 int i;
540 unsigned char cix = 0;
541 for (i = 0; i < nummap; i++)
542 /* fixme: why not just start from the other end and terminate when a match is found? */
543 if
544 (
545 x >= map[i].x1
546 &&
547 y >= map[i].y1
548 &&
549 x <= map[i].x2
550 &&
551 y <= map[i].y2
552 )
553 cix =
554 (map[i].contrast >> ci * 4 & 15) << 4
555 |
556 map[i].color >> ci * 4 & 15;
557 return cix;
558 } /*cmap_find*/
559
560static int write_png
561 (
562 const char *file_name,
563 const struct spu *s,
564 const struct colormap *map, /* array of entries for assigning colours to overlapping areas */
565 int nummap /* length of map array */
566 )
567 /* outputs the contents of s as a PNG file, converting pixels to colours
568 according to map. */
569 {
570 int status = -1; /* to begin with */
571 unsigned char *out_buf = NULL((void*)0);
572 FILE *fp = NULL((void*)0);
573 png_structp png_ptr = NULL((void*)0);
574 png_infop info_ptr = NULL((void*)0);
575 const unsigned short subwidth = svcd_adjust ? 704 : 720;
576 const unsigned short subheight = video_format == VF_NTSC ? 480 : 576;
577 do /*once*/
578 {
579 out_buf = malloc(s->xd * s->yd * 4);
580 if (out_buf == NULL((void*)0))
581 {
582 fprintf(stderrstderr, "ERR: unable allocate %d-byte PNG buffer\n", s->xd * s->yd * 4);
583 break;
584 } /*if*/
585 {
586 unsigned char *temp = out_buf;
587 bool_Bool nonzero = false0;
588 unsigned int x, y;
589 for (y = 0; y < s->yd; y++)
590 {
591 for (x = 0; x < s->xd; x++)
592 {
593 const unsigned char cix =
594 cmap_find(x + s->x0, y + s->y0, map, nummap, s->img[y * s->xd + x]);
595 *temp++ = current_palette[cix & 15].r;
596 *temp++ = current_palette[cix & 15].g;
597 *temp++ = current_palette[cix & 15].b;
598 *temp++ = (cix >> 4) * 17;
599 if (cix & 0xf0)
600 nonzero = true1;
601 } /*for*/
602 } /*for*/
603 if (!nonzero)
604 {
605 /* all transparent, don't bother writing any image */
606 status = 1;
607 break;
608 } /*if*/
609 }
610 fp = fopen(file_name, "wb");
611 if (fp == NULL((void*)0))
612 {
613 fprintf(stderrstderr, "ERR: error %s trying to open/create file: %s\n", strerror(errno(*__errno_location ())), file_name);
614 break;
615 } /*if*/
616 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING"1.6.8", NULL((void*)0), NULL((void*)0), NULL((void*)0));
617 if (png_ptr == NULL((void*)0))
618 break;
619 info_ptr = png_create_info_struct(png_ptr);
620 if (info_ptr == NULL((void*)0))
621 break;
622 if (setjmp(png_jmpbuf(png_ptr))_setjmp ((*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf
)))))
)
623 break;
624 png_init_io(png_ptr, fp);
625 png_set_filter(png_ptr, 0, PNG_FILTER_NONE0x08);
626 png_set_compression_level(png_ptr, Z_BEST_COMPRESSION9);
627 png_set_compression_mem_level(png_ptr, 8);
628 png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY0);
629 png_set_compression_window_bits(png_ptr, 15);
630 png_set_compression_method(png_ptr, 8);
631 if (full_size)
632 {
633 png_set_IHDR
634 (
635 /*png_ptr =*/ png_ptr,
636 /*info_ptr =*/ info_ptr,
637 /*width =*/ subwidth,
638 /*height =*/ subheight,
639 /*bit_depth =*/ 8,
640 /*color_type =*/ PNG_COLOR_TYPE_RGB_ALPHA(2 | 4),
641 /*interlace_method =*/ PNG_INTERLACE_NONE0,
642 /*compression_method =*/ PNG_COMPRESSION_TYPE_DEFAULT0,
643 /*filter_method =*/ PNG_FILTER_TYPE_DEFAULT0
644 );
645 }
646 else
647 {
648 png_set_IHDR
649 (
650 /*png_ptr =*/ png_ptr,
651 /*info_ptr =*/ info_ptr,
652 /*width =*/ s->xd,
653 /*height =*/ s->yd,
654 /*bit_depth =*/ 8,
655 /*color_type =*/ PNG_COLOR_TYPE_RGB_ALPHA(2 | 4),
656 /*interlace_method =*/ PNG_INTERLACE_NONE0,
657 /*compression_method =*/ PNG_COMPRESSION_TYPE_DEFAULT0,
658 /*filter_method =*/ PNG_FILTER_TYPE_DEFAULT0
659 );
660 } /*if*/
661 png_write_info(png_ptr, info_ptr);
662 png_set_packing(png_ptr);
663 {
664 unsigned int xd = s->xd, yd = s->yd;
665 png_byte *row_pointers[576]; /* big enough for both PAL and NTSC */
666 unsigned int a, x, y;
667 if (full_size)
668 {
669 unsigned char *image;
670 const unsigned char *temp = out_buf;
671 image = malloc(subwidth * subheight * 4);
672 memset(image, 0, subwidth * subheight * 4); // fill image full transparent
673 // insert image on the correct position
674 for (y = s->y0; y < s->y0 + s->yd; y++)
675 {
676 unsigned char *to = &image[y * subwidth * 4 + s->x0 * 4];
677 if (y >= subheight)
678 {
679 fprintf(stderrstderr, "WARN: subtitle %s truncated\n", file_name);
680 break;
681 } /*if*/
682 for (x = 0; x < s->xd; x++)
683 {
684 *to++ = *temp++;
685 *to++ = *temp++;
686 *to++ = *temp++;
687 *to++ = *temp++;
688 } /*for*/
689 } /*for*/
690 yd = subheight;
691 xd = subwidth;
692 free(out_buf);
693 out_buf = image;
694 } /*if*/
695 for (a = 0; a < yd; a++)
696 {
697 row_pointers[a] = out_buf + a * (xd * 4);
698 } /*for*/
699 png_write_image(png_ptr, row_pointers);
700 }
701 png_write_end(png_ptr, info_ptr);
702 /* all successfully done */
703 status = 0;
704 }
705 while (false0);
706 if (png_ptr != NULL((void*)0))
707 {
708 png_destroy_write_struct(&png_ptr, &info_ptr);
709 } /*if*/
710 if (fp != NULL((void*)0))
711 {
712 fclose(fp);
713 } /*if*/
714 free(out_buf);
715 return
716 status;
717 } /*write_png*/
718
719static void write_pts(const char *preamble, int pts)
720 /* outputs a formatted representation of a timestamp to fdo. */
721 {
722 fprintf
723 (
724 fdo,
725 " %s=\"%02d:%02d:%02d.%02d\"",
726 preamble,
727 (pts / (60 * 60 * 90000)) % 24,
728 (pts / (60 * 90000)) % 60,
729 (pts / 90000) % 60,
730 (pts / 900) % 100
731 );
732 } /*write_pts*/
733
734/*
735 copy the content of buf to expbuf converting '&' '<' '>' '"'
736 expbuf must be big enough to contain the expanded buffer
737*/
738static void xml_buf
739 (
740 unsigned char *expbuf,
741 const unsigned char *buf
742 )
743 {
744 const unsigned char *p;
745 do
746 {
747 switch (*buf)
748 {
749 case '&':
750 p = (const unsigned char *)"&amp;";
751 break;
752 case '<':
753 p = (const unsigned char *)"&lt;";
754 break;
755 case '>':
756 p = (const unsigned char *)"&gt;";
757 break;
758 case '"':
759 p = (const unsigned char *)"&quot;";
760 break;
761 default:
762 p = NULL((void*)0);
763 break;
764 } /*switch*/
765 if (p)
766 {
767 while ((*expbuf++ = *p++))
768 /* copy the representation */;
769 --expbuf;
770 }
771 else
772 *expbuf++ = *buf; /* copy as is */
773 }
774 while (*buf++);
775 } /*xml_buf*/
776
777static void write_menu_image
778 (
779 const struct spu *s,
780 const struct dispdetails *d,
781 const char *type, /* name of attribute to fill in with name of generated file */
782 int offset /* 0 => highlighted, 1 => selected */
783 )
784 /* outputs the subpicture image with the buttons in the highlighted or selected state. */
785 {
786 unsigned char nbuf[256];
787 int nummap = d->numbuttons + 1, i;
788 struct colormap *map = malloc(sizeof(struct colormap) * nummap);
789 memset(map, 0, sizeof(struct colormap)); // set the first one blank
790 map[0].x2 = 0x7fffffff;
791 map[0].y2 = 0x7fffffff;
792 for (i = 0; i < d->numbuttons; i++)
793 {
794 const uint32_t cc = d->coli[2 * d->buttons[i].grp - 2 + offset];
795 map[i + 1].x1 = d->buttons[i].x1;
796 map[i + 1].y1 = d->buttons[i].y1;
797 map[i + 1].x2 = d->buttons[i].x2;
798 map[i + 1].y2 = d->buttons[i].y2;
799 map[i + 1].color = cc >> 16;
800 map[i + 1].contrast = cc;
801 } /*for*/
802 sprintf((char *)nbuf, "%s%05d%c.png", base_name, s->subno, type[0]);
803 if (!write_png((char *)nbuf, s, map, nummap))
804 {
805 unsigned char ebuf[sizeof nbuf * 6];
806 xml_buf(ebuf, nbuf);
807 fprintf(fdo," %s=\"%s\"", type, ebuf);
808 } /*if*/
809 free(map);
810 } /*write_menu_image*/
811
812static void write_spu
813 (
814 const struct spu * curspu,
815 const struct dispdetails * buttons /* applicable button highlight info, if any */
816 )
817 /* writes out all information about a subpicture unit as an <spu> tag. */
818 {
819 unsigned char nbuf[256];
820 int i;
821 if (buttons)
822 absorb_palette(buttons);
823 fprintf(fdo, "\t\t<spu");
824 sprintf((char *)nbuf, "%s%05d.png", base_name, curspu->subno);
825 if (!write_png((char *)nbuf, curspu, curspu->map, curspu->nummap))
826 {
827 unsigned char ebuf[sizeof nbuf * 6];
828 xml_buf(ebuf, nbuf);
829 fprintf(fdo, " image=\"%s\"", ebuf);
830 } /*if*/
831 if (buttons && buttons->numbuttons)
832 {
833 write_menu_image(curspu, buttons, "highlight", 0);
834 write_menu_image(curspu, buttons, "select", 1);
835 } /*if*/
836 write_pts("start", curspu->pts[0]);
837 if (curspu->pts[1] != -1)
838 write_pts("end", curspu->pts[1]);
839 if (curspu->x0 || curspu->y0)
840 fprintf(fdo, " xoffset=\"%d\" yoffset=\"%d\"", curspu->x0, curspu->y0);
841 if (curspu->force_display)
842 fprintf(fdo, " force=\"yes\"");
843 if (buttons && buttons->numbuttons)
844 {
845 fprintf(fdo, ">\n");
846 for (i = 0; i < buttons->numbuttons; i++)
847 {
848 const struct button * const b = buttons->buttons + i;
849 fprintf
850 (
851 fdo,
852 "\t\t\t<%s name=\"%s\" x0=\"%d\" y0=\"%d\" x1=\"%d\" y1=\"%d\""
853 " up=\"%s\" down=\"%s\" left=\"%s\" right=\"%s\" />\n",
854 b->autoaction ? "action" : "button", b->name,
855 b->x1, b->y1, b->x2, b->y2,
856 b->up, b->down, b->left, b->right
857 );
858 } /*for*/
859 fprintf(fdo, "\t\t</spu>\n");
860 }
861 else
862 fprintf(fdo, " />\n");
863 } /*write_spu*/
864
865static void flushspus(unsigned int lasttime)
866 /* pops and outputs elements from pending_spus and pending_buttons that start
867 prior to lasttime. */
868 {
869 while (pending_spus)
870 {
871 const struct spu * const curspu = pending_spus;
872 if (curspu->pts[0] >= lasttime)
873 return; /* next entry not yet due */
874 pending_spus = pending_spus->next;
875 while
876 (
877 pending_buttons
878 &&
879 pending_buttons->pts[1] < curspu->pts[0]
880 &&
881 pending_buttons->pts[1] != -1
882 )
883 /* merge colours from expired entries into colour table, but otherwise ignore them */
884 pluck_pending_buttons();
885 if
886 (
887 pending_buttons
888 &&
889 (pending_buttons->pts[0] < curspu->pts[1] || curspu->pts[1] == -1)
890 &&
891 (pending_buttons->pts[1] > curspu->pts[0] || pending_buttons->pts[1] == -1)
892 )
893 /* head of pending_buttons overlaps duration of curspu */
894 write_spu(curspu, pending_buttons);
895 else
896 write_spu(curspu, 0);
897 free(curspu->img);
898 free(curspu->map);
899 free((void *)curspu);
900 } /*while*/
901 } /*flushspus*/
902
903#define bps(n,R,G,B)do { current_palette[n].r = R; current_palette[n].g = G; current_palette
[n].b = B; } while (0)
do { current_palette[n].r = R; current_palette[n].g = G; current_palette[n].b = B; } while (false0)
904
905static int svcddecode()
906 {
907 unsigned int io;
908 unsigned short int size, i, x, y;
909 unsigned char c;
910 struct spu *s;
911 int n;
912 size = read2(sub);
913 if (debug > 1)
914 fprintf(stderrstderr, "packet: 0x%x bytes\n", size);
915 s = malloc(sizeof(struct spu));
916 memset(s, 0, sizeof(struct spu));
917 s->subno = subno++;
918 s->pts[0] = spts;
919 s->pts[1] = -1;
920 s->nummap = 1;
921 s->map = malloc(sizeof(struct colormap));
922 memset(s->map, 0, sizeof(struct colormap));
923 s->map[0].x2 = 0x7ffffff; /* single colour map covers entire picture */
924 s->map[0].y2 = 0x7ffffff;
925 i = 2;
926 if (sub[i] & 0x08) /* timestamp present */
927 {
928 s->pts[1] = spts + read4(sub + i + 2);
929 i += 4;
930 } /*if*/
931 i += 2;
932 s->x0 = read2(sub + i);
933 s->y0 = read2(sub + i + 2);
934 s->xd = read2(sub + i + 4);
935 s->yd = read2(sub + i + 6);
936 i += 8;
937 if (debug > 4)
938 fprintf(stderrstderr, "img ofs: %d,%d size: %d,%d\n", s->x0, s->y0, s->xd, s->yd);
939 for (n = 0; n < 4; n++)
940 {
941 /* collect colour table */
942 int r, g, b;
943 r = sub[i + 0 + n * 4];
944 g = sub[i + 1 + n * 4];
945 b = sub[i + 2 + n * 4];
946 ycrcb_to_rgb(&r, &g, &b);
947 bps(n, r, g, b)do { current_palette[n].r = r; current_palette[n].g = g; current_palette
[n].b = b; } while (0)
;
948 if (debug > 4)
949 {
950 fprintf
951 (
952 stderrstderr,
953 "palette: %d => 0x%02x 0x%02x 0x%02x 0x%02x => (%d, %d, %d)\n",
954 n,
955 sub[i + 0 + n * 4],
956 sub[i + 1 + n * 4],
957 sub[i + 2 + n * 4],
958 sub[i + 3 + n * 4],
959 r,
960 g,
961 b
962 );
963 } /*if*/
964 } /*for*/
965 s->map[0].color = 0x3210;
966 s->map[0].contrast =
967 (sub[i + 3] >> 4)
968 +
969 (sub[i + 7] & 0xf0)
970 +
971 ((sub[i + 11] & 0xf0) << 4)
972 +
973 ((sub[i + 15] & 0xf0) << 8);
974 if (debug > 4)
975 fprintf(stderrstderr, "tpalette: %04x\n", s->map[0].contrast);
976 i += 16;
977 if (sub[i++] >> 6)
978 {
979 if (debug > 4)
980 {
981 fprintf
982 (
983 stderrstderr,
984 "cmd: shift (unsupported), direction=%d time=%f\n",
985 sub[i - 1] >> 4 & 0x3,
986 read4(sub) / 90000.0
987 );
988 } /*if*/
989 i += 4;
990 } /*if*/
991 ofs = i + 2 - 1; // get_next_svcdbits will increment ofs by 1
992 ofs1 = ofs + read2(sub + i);
993 /* i += 2; */ /* not further used */
994 if (debug > 4)
995 fprintf(stderrstderr, "cmd: image offsets 0x%x 0x%x\n", ofs, ofs1);
996 have_bits = 0;
997 x = y = 0;
998 io = 0;
999 s->img = malloc(s->xd * s->yd);
1000 memset(s->img, 0, s->xd * s->yd);
1001 /* decode the pixels */
1002 while (ofs < size && y < s->yd)
1003 {
1004 if ((c = get_next_svcdbits()) != 0)
1005 {
1006 s->img[io++] = c;
1007 ++x;
1008 }
1009 else
1010 {
1011 c = get_next_svcdbits() + 1;
1012 x += c;
1013 io += c;
1014 } /*if*/
1015 if (x >= s->xd)
1016 {
1017 y += 2;
1018 x = 0;
1019 if (y >= s->yd && !(y & 1))
1020 {
1021 y = 1;
1022 ofs = ofs1;
1023 } /*if*/
1024 io = s->xd * y;
1025 have_bits = 0;
1026 } /*if*/
1027 } /*while*/
1028 s->pts[0] += add_offset;
1029 if (s->pts[1] != -1)
1030 s->pts[1] += add_offset;
1031 addspu(s);
1032 if (debug > 2)
1033 fprintf(stderrstderr, "ofs: 0x%x y: %d\n", ofs, y);
1034 return 0;
1035 } /*svcddecode*/
1036
1037static void usage(void)
1038 {
1039 fprintf(stderrstderr,
1040 "\nUse: %s [options] [input file] [input file] ...\n\n",
1041 "spuunmux");
1042 fprintf(stderrstderr, "options:\n");
1043 fprintf(stderrstderr,
1044 "-o <name> base name for script and images [sub]\n");
1045 fprintf(stderrstderr,
1046 "-v <level> verbosity level [0]\n");
1047 fprintf(stderrstderr,
1048 "-f resize images to full size [720x576 or 720x480]\n");
1049 fprintf(stderrstderr,
1050 "-F <format> specify video format, NTSC or PAL\n");
1051 fprintf(stderrstderr,
1052 "-s <stream> number of the substream to extract [0]\n");
1053 fprintf(stderrstderr,
1054 "-p <file> name of file with dvd palette [none]\n");
1055 fprintf(stderrstderr, " if palette file ends with .rgb\n");
1056 fprintf(stderrstderr, " treated as a RGB\n");
1057 fprintf(stderrstderr, " else as a YCbCr color\n");
1058 fprintf(stderrstderr, "-h print this help\n");
1059 fprintf(stderrstderr, "-V print version number\n");
1060 fprintf(stderrstderr, "\n");
1061 } /*usage*/
1062
1063int main(int argc, char **argv)
1064 {
1065 int option, n;
1066 int firstvideo = -1;
1067 unsigned int pid, next_word, stream_number, fileindex, nrinfiles;
1068 unsigned char cbuf[CBUFSIZE65536];
1069 unsigned char psbuf[PSBUFSIZE10];
1070 char *palet_file;
1071 char *iname[256]; /* names of input files -- fixme: no range checking */
1072 unsigned int last_system_time = -1;
1073
1074 video_format = get_video_format();
1075 fputs(PACKAGE_HEADER("spuunmux")"DVDAuthor" "::" "spuunmux" ", version " "0.7.1+" ".\nBuild options:"
" gnugetopt" " graphicsmagick" " iconv" " freetype" " fribidi"
" fontconfig" "\nSend bug reports to <" "dvdauthor-users@lists.sourceforge.net"
">\n\n"
, stderrstderr);
1076 if (video_format != VF_NONE)
1077 {
1078 fprintf
1079 (
1080 stderrstderr,
1081 "INFO: default video format is %s\n",
1082 video_format == VF_PAL ? "PAL" : "NTSC"
1083 );
1084 }
1085 else
1086 {
1087#if defined(DEFAULT_VIDEO_FORMAT1)
1088# if DEFAULT_VIDEO_FORMAT1 == 1
1089 fprintf(stderrstderr, "INFO: default video format is NTSC\n");
1090 video_format = VF_NTSC;
1091# elif DEFAULT_VIDEO_FORMAT1 == 2
1092 fprintf(stderrstderr, "INFO: default video format is PAL\n");
1093 video_format = VF_PAL;
1094# endif
1095#else
1096 fprintf(stderrstderr, "INFO: no default video format, must explicitly specify NTSC or PAL\n");
1097#endif
1098 } /*if*/
1099 base_name = "sub";
1100 stream_number = 0;
1101 palet_file = 0;
1102 while ((option = getopt(argc, argv, "o:v:fF:s:p:Vh")) != -1)
1103 {
1104 switch (option)
1105 {
1106 case 'o':
1107 base_name = optarg;
1108 break;
1109 case 'v':
1110 debug = strtounsigned(optarg, "verbosity");
1111 break;
1112 case 'f':
1113 full_size = true1;
1114 break;
1115 case 'F':
1116 if (!strcasecmp(optarg, "ntsc"))
1117 {
1118 video_format = VF_NTSC;
1119 }
1120 else if (!strcasecmp(optarg, "pal"))
1121 {
1122 video_format = VF_PAL;
1123 }
1124 else
1125 {
1126 fprintf(stderrstderr, "ERR: Unrecognized video format \"%s\"\n", optarg);
1127 exit(-1);
1128 } /*if*/
1129 break;
1130 case 's':
1131 stream_number = strtounsigned(optarg, "stream number");
1132 break;
1133 case 'p':
1134 palet_file = optarg;
1135 break;
1136 case 'V':
1137 exit(-1);
1138
1139 case 'h':
1140 default:
1141 usage();
1142 return -1;
1143 } /*switch*/
1144 } /*while*/
1145
1146 if (optind < argc)
1147 {
1148 /* remaining args are input filenames */
1149 int n, i;
1150 for (i = 0, n = optind; n < argc; n++, i++)
1151 iname[i] = argv[n];
1152 nrinfiles = i;
1153 }
1154 else
1155 {
1156 usage();
1157 return -1;
1158 } /*if*/
1159 if (full_size && video_format == VF_NONE)
1160 {
1161 fprintf(stderrstderr, "ERR: cannot determine meaning of full size without knowing if it's NTSC or PAL\n");
1162 exit(-1);
1163 } /*if*/
1164
1165 /* initialize current_palette to default palette */
1166 bps(0, 0, 0, 0)do { current_palette[0].r = 0; current_palette[0].g = 0; current_palette
[0].b = 0; } while (0)
;
1167 bps(1, 127, 0, 0)do { current_palette[1].r = 127; current_palette[1].g = 0; current_palette
[1].b = 0; } while (0)
;
1168 bps(2, 0, 127, 0)do { current_palette[2].r = 0; current_palette[2].g = 127; current_palette
[2].b = 0; } while (0)
;
1169 bps(3, 127, 127, 0)do { current_palette[3].r = 127; current_palette[3].g = 127; current_palette
[3].b = 0; } while (0)
;
1170 bps(4, 0, 0, 127)do { current_palette[4].r = 0; current_palette[4].g = 0; current_palette
[4].b = 127; } while (0)
;
1171 bps(5, 127, 0, 127)do { current_palette[5].r = 127; current_palette[5].g = 0; current_palette
[5].b = 127; } while (0)
;
1172 bps(6, 0, 127, 127)do { current_palette[6].r = 0; current_palette[6].g = 127; current_palette
[6].b = 127; } while (0)
;
1173 bps(7, 127, 127, 127)do { current_palette[7].r = 127; current_palette[7].g = 127; current_palette
[7].b = 127; } while (0)
;
1174 bps(8, 192, 192, 192)do { current_palette[8].r = 192; current_palette[8].g = 192; current_palette
[8].b = 192; } while (0)
;
1175 bps(9, 128, 0, 0)do { current_palette[9].r = 128; current_palette[9].g = 0; current_palette
[9].b = 0; } while (0)
;
1176 bps(10, 0, 128, 0)do { current_palette[10].r = 0; current_palette[10].g = 128; current_palette
[10].b = 0; } while (0)
;
1177 bps(11, 128, 128, 0)do { current_palette[11].r = 128; current_palette[11].g = 128
; current_palette[11].b = 0; } while (0)
;
1178 bps(12, 0, 0, 128)do { current_palette[12].r = 0; current_palette[12].g = 0; current_palette
[12].b = 128; } while (0)
;
1179 bps(13, 128, 0, 128)do { current_palette[13].r = 128; current_palette[13].g = 0; current_palette
[13].b = 128; } while (0)
;
1180 bps(14, 0, 128, 128)do { current_palette[14].r = 0; current_palette[14].g = 128; current_palette
[14].b = 128; } while (0)
;
1181 bps(15, 128, 128, 128)do { current_palette[15].r = 128; current_palette[15].g = 128
; current_palette[15].b = 128; } while (0)
;
1182
1183 if (palet_file)
1184 {
1185 bool_Bool rgb = false0;
1186 char * const temp = strrchr(palet_file, '.');
1187 if (temp != NULL((void*)0))
1188 {
1189 if (strcmp(temp, ".rgb")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
(temp) && __builtin_constant_p (".rgb") && (
__s1_len = strlen (temp), __s2_len = strlen (".rgb"), (!((size_t
)(const void *)((temp) + 1) - (size_t)(const void *)(temp) ==
1) || __s1_len >= 4) && (!((size_t)(const void *)
((".rgb") + 1) - (size_t)(const void *)(".rgb") == 1) || __s2_len
>= 4)) ? __builtin_strcmp (temp, ".rgb") : (__builtin_constant_p
(temp) && ((size_t)(const void *)((temp) + 1) - (size_t
)(const void *)(temp) == 1) && (__s1_len = strlen (temp
), __s1_len < 4) ? (__builtin_constant_p (".rgb") &&
((size_t)(const void *)((".rgb") + 1) - (size_t)(const void *
)(".rgb") == 1) ? __builtin_strcmp (temp, ".rgb") : (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (".rgb"); int __result = (((const unsigned char *) (
const char *) (temp))[0] - __s2[0]); if (__s1_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (temp))[1] - __s2[1]); if (__s1_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (temp))[2] - __s2[2]); if (__s1_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (temp))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p
(".rgb") && ((size_t)(const void *)((".rgb") + 1) - (
size_t)(const void *)(".rgb") == 1) && (__s2_len = strlen
(".rgb"), __s2_len < 4) ? (__builtin_constant_p (temp) &&
((size_t)(const void *)((temp) + 1) - (size_t)(const void *)
(temp) == 1) ? __builtin_strcmp (temp, ".rgb") : (- (__extension__
({ const unsigned char *__s2 = (const unsigned char *) (const
char *) (temp); int __result = (((const unsigned char *) (const
char *) (".rgb"))[0] - __s2[0]); if (__s2_len > 0 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (".rgb"))[1] - __s2[1]); if (__s2_len > 1 &&
__result == 0) { __result = (((const unsigned char *) (const
char *) (".rgb"))[2] - __s2[2]); if (__s2_len > 2 &&
__result == 0) __result = (((const unsigned char *) (const char
*) (".rgb"))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp
(temp, ".rgb")))); })
== 0)
1190 rgb = true1;
1191 } /*if*/
1192 fdo = fopen(palet_file, "r");
1193 if (fdo != NULL((void*)0))
1194 {
1195 for (n = 0; n < 16; n++)
1196 {
1197 int r, g, b;
1198 fscanf(fdo, "%02x%02x%02x", &r, &g, &b);
1199 if (!rgb)
1200 ycrcb_to_rgb(&r, &g, &b);
1201 current_palette[n].r = r;
1202 current_palette[n].g = g;
1203 current_palette[n].b = b;
1204 if (debug > 3)
1205 fprintf
1206 (
1207 stderrstderr,
1208 "pal: %d #%02x%02x%02x\n",
1209 n, current_palette[n].r, current_palette[n].g, current_palette[n].b
1210 );
1211 } /*for*/
1212 fclose(fdo);
1213 }
1214 else
1215 {
1216 fprintf(stderrstderr, "unable to open %s, using defaults\n", palet_file);
1217 } /*if*/
1218 } /*if*/
1219 if (strlen(base_name) > 246)
1220 {
1221 fprintf(stderrstderr,
1222 "error: max length of base for filename creation is 246 characters\n");
1223 return -1;
1224 } /*if*/
1225 {
1226 char nbuf[256];
1227 sprintf(nbuf, "%s.xml", base_name);
1228 fdo = fopen(nbuf, "w+");
1229 }
1230 fprintf(fdo, "<subpictures>\n\t<stream>\n");
1231 pts = 0;
1232 subno = 0;
1233 subi = 0;
1234 add_offset = 450; // for rounding purposes
1235 fileindex = 0;
1236 while (fileindex < nrinfiles)
1237 {
1238 struct vfile fd = varied_open(iname[fileindex], O_RDONLY00, "input file");
1239 if (debug > 0)
1240 fprintf(stderrstderr, "file: %s\n", iname[fileindex]);
1241 fileindex++;
1242 while (fread(&pid, 1, 4, fd.h) == 4)
1243 {
1244 pid = ntohl(pid)(__extension__ ({ unsigned int __v, __x = (pid); if (__builtin_constant_p
(__x)) __v = ((((__x) & 0xff000000) >> 24) | (((__x
) & 0x00ff0000) >> 8) | (((__x) & 0x0000ff00) <<
8) | (((__x) & 0x000000ff) << 24)); else __asm__ (
"bswap %0" : "=r" (__v) : "0" (__x)); __v; }))
;
1245 if (pid == 0x00000100 + MPID_PACK)
1246 { // start PS (Program stream)
1247 unsigned int new_system_time, stuffcount;
1248l_01ba:
1249 if (debug > 5)
1250 fprintf(stderrstderr, "pack_start_code\n");
1251 if (fread(psbuf, 1, PSBUFSIZE10, fd.h) < 1)
1252 break;
1253 if ((psbuf[0] & 0xc0) != 0x40)
1254 {
1255 if (debug > 1)
1256 fprintf(stderrstderr, "not a MPEG-2 file, skipping.\n");
1257 break;
1258 } /*if*/
1259 new_system_time =
1260 (psbuf[4] >> 3)
1261 +
1262 psbuf[3] * 32
1263 +
1264 (psbuf[2] & 3) * 32 * 256
1265 +
1266 (psbuf[2] & 0xf8) * 32 * 128
1267 +
1268 psbuf[1] * 1024 * 1024
1269 +
1270 (psbuf[0] & 3) * 1024 * 1024 * 256
1271 +
1272 (psbuf[0] & 0x38) * 1024 * 1024 * 128;
1273 if (new_system_time < last_system_time)
1274 {
1275 if (last_system_time != -1)
1276 {
1277 if (debug > 0)
1278 fprintf
1279 (
1280 stderrstderr,
1281 "Time changed in stream header, use old time as offset for"
1282 " timecode in subtitle stream\n"
1283 );
1284 add_offset += last_system_time;
1285 } /*if*/
1286 } /*if*/
1287 last_system_time = new_system_time;
1288 flushspus(last_system_time);
1289 if (debug > 5)
1290 {
1291 fprintf(stderrstderr, "system time: %u\n", new_system_time);
1292 } /*if*/
1293 stuffcount = psbuf[9] & 7;
1294 if (stuffcount != 0)
1295 {
1296 char stuff[7];
1297 if (debug > 5)
1298 fprintf(stderrstderr, "found %d stuffing bytes\n", stuffcount);
1299 if (fread(stuff, 1, stuffcount, fd.h) < stuffcount)
1300 break;
1301 } /*if*/
1302 }
1303 else if (pid == 0x100 + MPID_PROGRAM_END)
1304 {
1305 if (debug > 5)
1306 fprintf(stderrstderr, "end packet\n");
1307 }
1308 else /* packet with a length field */
1309 {
1310 unsigned short int package_length;
1311 fread(&package_length, 1, 2, fd.h);
1312 package_length = ntohs(package_length)(__extension__ ({ unsigned short int __v, __x = (unsigned short
int) (package_length); if (__builtin_constant_p (__x)) __v =
((unsigned short int) ((((__x) >> 8) & 0xff) | (((
__x) & 0xff) << 8))); else __asm__ ("rorw $8, %w0" :
"=r" (__v) : "0" (__x) : "cc"); __v; }))
;
1313 if (package_length != 0)
1314 {
1315 switch (pid)
1316 {
1317 case 0x0100 + MPID_SYSTEM:
1318 if (debug > 5)
1319 fprintf(stderrstderr, "system header\n");
1320 break;
1321 case 0x0100 + MPID_PRIVATE2: /* PCI & DSI packets, not my problem */
1322 if (debug > 5)
1323 fprintf(stderrstderr, "private stream 2\n");
1324 break;
1325 case 0x0100 + MPID_PRIVATE1: /* subpicture or audio stream */
1326 if (debug > 5)
1327 fprintf(stderrstderr, "private stream 1\n");
1328 fread(cbuf, 1, package_length, fd.h);
1329 next_word = getpts(cbuf);
1330 if (next_word != -1)
1331 {
1332 pts = next_word;
1333 } /*if*/
1334 next_word = cbuf[2] /* additional data length */ + 3 /* length of fixed part of MPEG-2 extension */;
1335 if (debug > 5)
1336 {
1337 /* dump PES header + extension */
1338 int c;
1339 for (c = 0; c < next_word; c++)
1340 fprintf(stderrstderr, "0x%02x ", cbuf[c]);
1341 } /*if*/
1342 if (debug > 5)
1343 fprintf(stderrstderr, "tid: %d\n", pts);
1344 if
1345 (
1346 cbuf[next_word] == stream_number + 32 /* DVD-Video stream nr */
1347 ||
1348 cbuf[next_word] == 0x70 && cbuf[next_word + 1] == stream_number
1349 /* SVCD stream nr */
1350 )
1351 {
1352 /* this is the subpicture stream the user wants dumped */
1353 svcd_adjust = cbuf[next_word] == 0x70 ? 4 : 0;
1354 if (/*debug < 6 &&*/ debug > 1)
1355 {
1356 fprintf(stderrstderr,
1357 "id: 0x%x 0x%x %d tid: %d\n",
1358 cbuf[next_word], package_length,
1359 next_word, pts);
1360 } /*if*/
1361 if (!subi)
1362 {
1363 /* starting a new SPU */
1364 subs =
1365 ((unsigned int)cbuf[next_word + 1 + svcd_adjust] << 8)
1366 +
1367 cbuf[next_word + 2 + svcd_adjust];
1368 /* SPDSZ, size of total subpicture data */
1369 spts = pts;
1370 } /*if*/
1371 memcpy
1372 (
1373 /*dest =*/ sub + subi,
1374 /*src =*/ cbuf + next_word + 1 + svcd_adjust,
1375 /*n =*/ package_length - next_word - 1 - svcd_adjust
1376 );
1377 /* collect the subpicture data */
1378 if (debug > 1)
1379 {
1380 fprintf(stderrstderr, "found %d bytes of data\n",
1381 package_length - next_word - 1 - svcd_adjust);
1382 } /*if*/
1383 subi += package_length - next_word - 1 - svcd_adjust;
1384 /* how much I just collected */
1385 if (debug > 2)
1386 {
1387 fprintf(stderrstderr,
1388 "subi: %d (0x%x) subs: %d (0x%x) b-a-1: %d (0x%x)\n",
1389 subi, subi, subs, subs,
1390 package_length - next_word - 1 - svcd_adjust,
1391 package_length - next_word - 1 - svcd_adjust);
1392 } /*if*/
1393 if (svcd_adjust)
1394 {
1395 if (cbuf[next_word + 2] & 0x80)
1396 {
1397 subi = 0;
1398 next_word = svcddecode();
1399 if (next_word)
1400 {
1401 fprintf
1402 (
1403 stderrstderr,
1404 "found unreadable subtitle at %.2fs, skipping\n",
1405 (double) spts / 90000
1406 );
1407 continue;
1408 } /*if*/
1409 } /*if*/
1410 }
1411 else if (subs == subi)
1412 {
1413 /* got a complete SPU */
1414 subi = 0;
1415 if (dvddecode())
1416 {
1417 fprintf(stderrstderr,
1418 "found unreadable subtitle at %.2fs, skipping\n",
1419 (double) spts / 90000);
1420 continue;
1421 } /*if*/
1422 } /*if*/
1423 } /*if dump the stream*/
1424 package_length = 0;
1425 break;
1426 case 0x0100 + MPID_VIDEO_FIRST:
1427 if (firstvideo == -1)
1428 {
1429 fread(cbuf, 1, package_length, fd.h);
1430 firstvideo = getpts(cbuf);
1431 add_offset -= firstvideo;
1432 package_length = 0;
1433 } /*if*/
1434 if (debug > 5)
1435 fprintf(stderrstderr, "video stream 0\n");
1436 break;
1437 case 0x01e1:
1438 case 0x01e2:
1439 case 0x01e3:
1440 case 0x01e4:
1441 case 0x01e5:
1442 case 0x01e6:
1443 case 0x01e7:
1444 case 0x01e8:
1445 case 0x01e9:
1446 case 0x01ea:
1447 case 0x01eb:
1448 case 0x01ec:
1449 case 0x01ed:
1450 case 0x01ee:
1451 case 0x01ef:
1452 if (debug > 5)
1453 fprintf(stderrstderr, "video stream %d\n", pid - 0x100 - MPID_VIDEO_FIRST);
1454 break;
1455 case 0x0100 + MPID_PAD:
1456 if (debug > 5)
1457 fprintf(stderrstderr, "padding stream %d bytes\n", package_length);
1458 fread(cbuf, 1, package_length, fd.h);
1459 if (package_length > 30)
1460 {
1461 int i;
1462 package_length = 0;
1463 i = 0;
1464 if (strcmp((const char *)cbuf + i, "dvdauthor-data")__extension__ ({ size_t __s1_len, __s2_len; (__builtin_constant_p
((const char *)cbuf + i) && __builtin_constant_p ("dvdauthor-data"
) && (__s1_len = strlen ((const char *)cbuf + i), __s2_len
= strlen ("dvdauthor-data"), (!((size_t)(const void *)(((const
char *)cbuf + i) + 1) - (size_t)(const void *)((const char *
)cbuf + i) == 1) || __s1_len >= 4) && (!((size_t)(
const void *)(("dvdauthor-data") + 1) - (size_t)(const void *
)("dvdauthor-data") == 1) || __s2_len >= 4)) ? __builtin_strcmp
((const char *)cbuf + i, "dvdauthor-data") : (__builtin_constant_p
((const char *)cbuf + i) && ((size_t)(const void *)(
((const char *)cbuf + i) + 1) - (size_t)(const void *)((const
char *)cbuf + i) == 1) && (__s1_len = strlen ((const
char *)cbuf + i), __s1_len < 4) ? (__builtin_constant_p (
"dvdauthor-data") && ((size_t)(const void *)(("dvdauthor-data"
) + 1) - (size_t)(const void *)("dvdauthor-data") == 1) ? __builtin_strcmp
((const char *)cbuf + i, "dvdauthor-data") : (__extension__ (
{ const unsigned char *__s2 = (const unsigned char *) (const char
*) ("dvdauthor-data"); int __result = (((const unsigned char
*) (const char *) ((const char *)cbuf + i))[0] - __s2[0]); if
(__s1_len > 0 && __result == 0) { __result = (((const
unsigned char *) (const char *) ((const char *)cbuf + i))[1]
- __s2[1]); if (__s1_len > 1 && __result == 0) { __result
= (((const unsigned char *) (const char *) ((const char *)cbuf
+ i))[2] - __s2[2]); if (__s1_len > 2 && __result
== 0) __result = (((const unsigned char *) (const char *) ((
const char *)cbuf + i))[3] - __s2[3]); } } __result; }))) : (
__builtin_constant_p ("dvdauthor-data") && ((size_t)(
const void *)(("dvdauthor-data") + 1) - (size_t)(const void *
)("dvdauthor-data") == 1) && (__s2_len = strlen ("dvdauthor-data"
), __s2_len < 4) ? (__builtin_constant_p ((const char *)cbuf
+ i) && ((size_t)(const void *)(((const char *)cbuf +
i) + 1) - (size_t)(const void *)((const char *)cbuf + i) == 1
) ? __builtin_strcmp ((const char *)cbuf + i, "dvdauthor-data"
) : (- (__extension__ ({ const unsigned char *__s2 = (const unsigned
char *) (const char *) ((const char *)cbuf + i); int __result
= (((const unsigned char *) (const char *) ("dvdauthor-data"
))[0] - __s2[0]); if (__s2_len > 0 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("dvdauthor-data"
))[1] - __s2[1]); if (__s2_len > 1 && __result == 0
) { __result = (((const unsigned char *) (const char *) ("dvdauthor-data"
))[2] - __s2[2]); if (__s2_len > 2 && __result == 0
) __result = (((const unsigned char *) (const char *) ("dvdauthor-data"
))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp ((const
char *)cbuf + i, "dvdauthor-data")))); })
)
1465 break;
1466 /* pad packet contains DVDAuthor private data */
1467 i = 15;
1468 if (cbuf[i] != 2)
1469 break;
1470 switch(cbuf[i + 1])
1471 {
1472 case 1: // subtitle/menu color and button information
1473 {
1474 // int st = cbuf[i + 2] & 31; // we ignore which subtitle stream for now
1475 struct dispdetails *buttons;
1476 i += 3;
1477 buttons = malloc(sizeof(struct dispdetails));
1478 memset(buttons, 0, sizeof(struct dispdetails));
1479 buttons->pts[0] = read4(cbuf + i);
1480 buttons->pts[1] = read4(cbuf + i + 4);
1481 i += 8;
1482 while(cbuf[i] != 0xff)
1483 {
1484 switch(cbuf[i])
1485 {
1486 case 1: /* colour table */
1487 {
1488 int j;
1489 buttons->numpal = 0;
1490 for (j = 0; j < cbuf[i + 1]; j++)
1491 {
1492 const int c = read4(cbuf + i + 1 + 3 * j) & 0xffffff;
1493 buttons->palette[j] = c;
1494 buttons->numpal++;
1495 } /*for*/
1496 i += 2 + 3 * buttons->numpal;
1497 }
1498 break;
1499 case 2: /* button groups */
1500 {
1501 int j;
1502 buttons->numcoli = cbuf[i + 1];
1503 for (j = 0; j < 2 * buttons->numcoli; j++)
1504 buttons->coli[j] = read4(cbuf + i + 2 + j * 4);
1505 i += 2 + 8 * buttons->numcoli;
1506 }
1507 break;
1508 case 3: /* button placement */
1509 {
1510 int j;
1511 buttons->numbuttons = cbuf[i + 1];
1512 buttons->buttons = malloc(buttons->numbuttons * sizeof(struct button));
1513 i += 2;
1514 for (j = 0; j < buttons->numbuttons; j++)
1515 {
1516 struct button *b = &buttons->buttons[j];
1517 b->name = readpstr(cbuf, &i);
1518 i += 2;
1519 b->autoaction = cbuf[i++] != 0;
1520 b->grp = cbuf[i];
1521 b->x1 = read2(cbuf + i + 1);
1522 b->y1 = read2(cbuf + i + 3);
1523 b->x2 = read2(cbuf + i + 5);
1524 b->y2 = read2(cbuf + i + 7);
1525 i += 9;
1526 // up down left right
1527 b->up = readpstr(cbuf, &i);
1528 b->down = readpstr(cbuf, &i);
1529 b->left = readpstr(cbuf, &i);
1530 b->right = readpstr(cbuf, &i);
1531 } /*for*/
1532 }
1533 break;
1534 default:
1535 fprintf(stderrstderr,"ERR: unknown dvd info packet command: %d, offset %d\n",cbuf[i], i);
1536 exit(1);
1537 } /*switch*/
1538 } /*while*/
1539 add_pending_buttons(buttons);
1540 } /*case 1*/
1541 break;
1542 } /*switch*/
1543 } /*if*/
1544 package_length = 0;
1545 break;
1546 case 0x01c0:
1547 case 0x01c1:
1548 case 0x01c2:
1549 case 0x01c3:
1550 case 0x01c4:
1551 case 0x01c5:
1552 case 0x01c6:
1553 case 0x01c7:
1554 case 0x01c8:
1555 case 0x01c9:
1556 case 0x01ca:
1557 case 0x01cb:
1558 case 0x01cc:
1559 case 0x01cd:
1560 case 0x01ce:
1561 case 0x01cf:
1562 case 0x01d0:
1563 case 0x01d1:
1564 case 0x01d2:
1565 case 0x01d3:
1566 case 0x01d4:
1567 case 0x01d5:
1568 case 0x01d6:
1569 case 0x01d7:
1570 case 0x01d8:
1571 case 0x01d9:
1572 case 0x01da:
1573 case 0x01db:
1574 case 0x01dc:
1575 case 0x01dd:
1576 case 0x01de:
1577 case 0x01df:
1578 if (debug > 5)
1579 fprintf(stderrstderr, "audio stream %d\n", pid - 0x100 - MPID_AUDIO_FIRST);
1580 break;
1581 default:
1582 if (debug > 0)
1583 fprintf(stderrstderr, "unknown header %x\n", pid);
1584 next_word = pid << 16 | package_length;
1585 package_length = 2;
1586 while (next_word != 0x100 + MPID_PACK)
1587 {
1588 next_word = next_word << 8;
1589 if (fread(&next_word, 1, 1, fd.h) < 1)
1590 break;
1591 package_length++;
1592 } /*while*/
1593 if (debug > 0)
1594 fprintf(stderrstderr, "skipped %d bytes of garbage\n", package_length);
1595 goto l_01ba;
1596 } /*switch*/
1597 fread(cbuf, 1, package_length, fd.h);
1598 } /*if*/
1599 } /*if*/
1600 } /*while read next packet header*/
1601 varied_close(fd);
1602 } /*while fileindex < nrinfiles*/
1603 flushspus(0x7fffffff); /* ensure all remaining spus elements are output */
1604 fprintf(fdo, "\t</stream>\n</subpictures>\n");
1605 fclose(fdo);
1606 return 0;
1607 } /*main*/