Mercurial > mplayer.hg
comparison vobsub.c @ 4080:47bcafe1442e
Add vobsub support.
author | kmkaplan |
---|---|
date | Thu, 10 Jan 2002 17:20:27 +0000 |
parents | |
children | dc0a91965b97 |
comparison
equal
deleted
inserted
replaced
4079:ae78dd1d8daf | 4080:47bcafe1442e |
---|---|
1 /* | |
2 * Some code freely inspired from VobSub <URL:http://vobsub.edensrising.com>, | |
3 * with kind permission from Gabest <gabest@freemail.hu> | |
4 */ | |
5 /* #define HAVE_GETLINE */ | |
6 #include <ctype.h> | |
7 #include <errno.h> | |
8 #include <stdio.h> | |
9 #include <stdlib.h> | |
10 #include <string.h> | |
11 #include <fcntl.h> | |
12 #include <unistd.h> | |
13 #include <sys/stat.h> | |
14 #include <sys/types.h> | |
15 | |
16 #include "config.h" | |
17 | |
18 #include "stream.h" | |
19 #include "vobsub.h" | |
20 #include "spudec.h" | |
21 #include "mp_msg.h" | |
22 | |
23 extern int vobsub_id; | |
24 | |
25 extern int verbose; | |
26 | |
27 #ifdef HAVE_GETLINE | |
28 extern ssize_t getline(char **, size_t *, FILE *); | |
29 #else | |
30 /* FIXME This should go into a general purpose library or even a | |
31 separate file. */ | |
32 static ssize_t | |
33 getline (char **lineptr, size_t *n, FILE *stream) | |
34 { | |
35 size_t res = 0; | |
36 int c; | |
37 if (*lineptr == NULL) { | |
38 *lineptr = malloc(4096); | |
39 if (*lineptr) | |
40 *n = 4096; | |
41 } | |
42 else if (*n == 0) { | |
43 char *tmp = realloc(*lineptr, 4096); | |
44 if (tmp) { | |
45 *lineptr = tmp; | |
46 *n = 4096; | |
47 } | |
48 } | |
49 if (*lineptr == NULL || *n == 0) | |
50 return -1; | |
51 | |
52 for (c = fgetc(stream); c != EOF; c = fgetc(stream)) { | |
53 if (res + 1 >= *n) { | |
54 char *tmp = realloc(*lineptr, *n * 2); | |
55 if (tmp == NULL) | |
56 return -1; | |
57 *lineptr = tmp; | |
58 *n *= 2; | |
59 } | |
60 (*lineptr)[res++] = c; | |
61 if (c == '\n') { | |
62 (*lineptr)[res] = 0; | |
63 return res; | |
64 } | |
65 } | |
66 if (res == 0) | |
67 return -1; | |
68 (*lineptr)[res] = 0; | |
69 return res; | |
70 } | |
71 #endif | |
72 | |
73 /********************************************************************** | |
74 * MPEG parsing | |
75 **********************************************************************/ | |
76 | |
77 typedef struct { | |
78 stream_t *stream; | |
79 unsigned int pts; | |
80 int aid; | |
81 unsigned char *packet; | |
82 unsigned int packet_reserve; | |
83 unsigned int packet_size; | |
84 } mpeg_t; | |
85 | |
86 static mpeg_t * | |
87 mpeg_open(const char *filename) | |
88 { | |
89 mpeg_t *res = malloc(sizeof(mpeg_t)); | |
90 int err = res == NULL; | |
91 if (!err) { | |
92 int fd; | |
93 res->pts = 0; | |
94 res->aid = -1; | |
95 res->packet = NULL; | |
96 res->packet_size = 0; | |
97 res->packet_reserve = 0; | |
98 fd = open(filename, O_RDONLY); | |
99 err = fd < 0; | |
100 if (!err) { | |
101 res->stream = new_stream(fd, STREAMTYPE_FILE); | |
102 err = res->stream == NULL; | |
103 if (err) | |
104 close(fd); | |
105 } | |
106 if (err) | |
107 free(res); | |
108 } | |
109 return err ? NULL : res; | |
110 } | |
111 | |
112 static void | |
113 mpeg_free(mpeg_t *mpeg) | |
114 { | |
115 int fd; | |
116 if (mpeg->packet) | |
117 free(mpeg->packet); | |
118 fd = mpeg->stream->fd; | |
119 free_stream(mpeg->stream); | |
120 close(fd); | |
121 free(mpeg); | |
122 } | |
123 | |
124 static int | |
125 mpeg_eof(mpeg_t *mpeg) | |
126 { | |
127 return stream_eof(mpeg->stream); | |
128 } | |
129 | |
130 static off_t | |
131 mpeg_tell(mpeg_t *mpeg) | |
132 { | |
133 return stream_tell(mpeg->stream); | |
134 } | |
135 | |
136 static int | |
137 mpeg_run(mpeg_t *mpeg) | |
138 { | |
139 unsigned int len, idx, version; | |
140 int c; | |
141 /* Goto start of a packet, it starts with 0x000001?? */ | |
142 const unsigned char wanted[] = { 0, 0, 1 }; | |
143 unsigned char buf[5]; | |
144 | |
145 mpeg->aid = -1; | |
146 mpeg->packet_size = 0; | |
147 if (stream_read(mpeg->stream, buf, 4) != 4) | |
148 return -1; | |
149 while (memcmp(buf, wanted, sizeof(wanted)) != 0) { | |
150 c = stream_read_char(mpeg->stream); | |
151 if (c < 0) | |
152 return -1; | |
153 memmove(buf, buf + 1, 3); | |
154 buf[3] = c; | |
155 } | |
156 switch (buf[3]) { | |
157 case 0xb9: /* System End Code */ | |
158 break; | |
159 case 0xba: /* Packet start code */ | |
160 c = stream_read_char(mpeg->stream); | |
161 if (c < 0) | |
162 return -1; | |
163 if ((c & 0xc0) == 0x40) | |
164 version = 4; | |
165 else if ((c & 0xf0) == 0x20) | |
166 version = 2; | |
167 else { | |
168 fprintf(stderr, "Unsupported MPEG version: 0x%02x", c); | |
169 return -1; | |
170 } | |
171 if (version == 4) { | |
172 if (!stream_skip(mpeg->stream, 9)) | |
173 return -1; | |
174 } | |
175 else if (version == 2) { | |
176 if (!stream_skip(mpeg->stream, 7)) | |
177 return -1; | |
178 } | |
179 else | |
180 abort(); | |
181 break; | |
182 case 0xbd: /* packet */ | |
183 if (stream_read(mpeg->stream, buf, 2) != 2) | |
184 return -1; | |
185 len = buf[0] << 8 | buf[1]; | |
186 idx = mpeg_tell(mpeg); | |
187 c = stream_read_char(mpeg->stream); | |
188 if (c < 0) | |
189 return -1; | |
190 if ((c & 0xC0) == 0x40) { /* skip STD scale & size */ | |
191 if (stream_read_char(mpeg->stream) < 0) | |
192 return -1; | |
193 c = stream_read_char(mpeg->stream); | |
194 if (c < 0) | |
195 return -1; | |
196 } | |
197 if ((c & 0xf0) == 0x20) { /* System-1 stream timestamp */ | |
198 /* Do we need this? */ | |
199 abort(); | |
200 } | |
201 else if ((c & 0xf0) == 0x30) { | |
202 /* Do we need this? */ | |
203 abort(); | |
204 } | |
205 else if ((c & 0xc0) == 0x80) { /* System-2 (.VOB) stream */ | |
206 unsigned int pts_flags, hdrlen, dataidx; | |
207 c = stream_read_char(mpeg->stream); | |
208 if (c < 0) | |
209 return -1; | |
210 pts_flags = c; | |
211 c = stream_read_char(mpeg->stream); | |
212 if (c < 0) | |
213 return -1; | |
214 hdrlen = c; | |
215 dataidx = mpeg_tell(mpeg) + hdrlen; | |
216 if (dataidx > idx + len) { | |
217 fprintf(stderr, "Invalid header length: %d (total length: %d, idx: %d, dataidx: %d)\n", | |
218 hdrlen, len, idx, dataidx); | |
219 return -1; | |
220 } | |
221 if ((pts_flags & 0xc0) == 0x80) { | |
222 if (stream_read(mpeg->stream, buf, 5) != 5) | |
223 return -1; | |
224 if (!(((buf[0] & 0xf0) == 0x20) && (buf[0] & 1) && (buf[2] & 1) && (buf[4] & 1))) { | |
225 fprintf(stderr, "vobsub PTS error: 0x%02x %02x%02x %02x%02x \n", | |
226 buf[0], buf[1], buf[2], buf[3], buf[4]); | |
227 mpeg->pts = 0; | |
228 } | |
229 else | |
230 mpeg->pts = ((buf[0] & 0x0e) << 29 | buf[1] << 22 | (buf[2] & 0xfe) << 14 | |
231 | buf[3] << 7 | (buf[4] >> 1)) / 900; | |
232 } | |
233 else /* if ((pts_flags & 0xc0) == 0xc0) */ { | |
234 /* what's this? */ | |
235 /* abort(); */ | |
236 } | |
237 stream_seek(mpeg->stream, dataidx); | |
238 mpeg->aid = stream_read_char(mpeg->stream); | |
239 if (mpeg->aid < 0) { | |
240 fprintf(stderr, "Bogus aid %d\n", mpeg->aid); | |
241 return -1; | |
242 } | |
243 mpeg->packet_size = len - ((unsigned int) mpeg_tell(mpeg) - idx); | |
244 if (mpeg->packet_reserve < mpeg->packet_size) { | |
245 if (mpeg->packet) | |
246 free(mpeg->packet); | |
247 mpeg->packet = malloc(mpeg->packet_size); | |
248 if (mpeg->packet) | |
249 mpeg->packet_reserve = mpeg->packet_size; | |
250 } | |
251 if (mpeg->packet == NULL) { | |
252 perror("malloc failure"); | |
253 mpeg->packet_reserve = 0; | |
254 mpeg->packet_size = 0; | |
255 return -1; | |
256 } | |
257 if (stream_read(mpeg->stream, mpeg->packet, mpeg->packet_size) != mpeg->packet_size) { | |
258 perror("stream_read failure"); | |
259 mpeg->packet_size = 0; | |
260 return -1; | |
261 } | |
262 idx = len; | |
263 } | |
264 break; | |
265 case 0xbe: /* Padding */ | |
266 if (stream_read(mpeg->stream, buf, 2) != 2) | |
267 return -1; | |
268 len = buf[0] << 8 | buf[1]; | |
269 if (len > 0 && !stream_skip(mpeg->stream, len)) | |
270 return -1; | |
271 break; | |
272 default: | |
273 return -1; | |
274 } | |
275 return 0; | |
276 } | |
277 | |
278 /********************************************************************** | |
279 * Packet queue | |
280 **********************************************************************/ | |
281 | |
282 typedef struct { | |
283 unsigned int pts100; | |
284 off_t filepos; | |
285 unsigned int size; | |
286 unsigned char *data; | |
287 } packet_t; | |
288 | |
289 typedef struct { | |
290 char *id; | |
291 packet_t *packets; | |
292 unsigned int packets_reserve; | |
293 unsigned int packets_size; | |
294 unsigned int current_index; | |
295 } packet_queue_t; | |
296 | |
297 static void | |
298 packet_construct(packet_t *pkt) | |
299 { | |
300 pkt->pts100 = 0; | |
301 pkt->filepos = 0; | |
302 pkt->size = 0; | |
303 pkt->data = NULL; | |
304 } | |
305 | |
306 static void | |
307 packet_destroy(packet_t *pkt) | |
308 { | |
309 if (pkt->data) | |
310 free(pkt->data); | |
311 } | |
312 | |
313 static void | |
314 packet_queue_construct(packet_queue_t *queue) | |
315 { | |
316 queue->id = NULL; | |
317 queue->packets = NULL; | |
318 queue->packets_reserve = 0; | |
319 queue->packets_size = 0; | |
320 queue->current_index = 0; | |
321 } | |
322 | |
323 static void | |
324 packet_queue_destroy(packet_queue_t *queue) | |
325 { | |
326 if (queue->packets) { | |
327 while (queue->packets_size--) | |
328 packet_destroy(queue->packets + queue->packets_size); | |
329 free(queue->packets); | |
330 } | |
331 return; | |
332 } | |
333 | |
334 /* Make sure there is enough room for needed_size packets in the | |
335 packet queue. */ | |
336 static int | |
337 packet_queue_ensure(packet_queue_t *queue, unsigned int needed_size) | |
338 { | |
339 if (queue->packets_reserve < needed_size) { | |
340 if (queue->packets) { | |
341 packet_t *tmp = realloc(queue->packets, 2 * queue->packets_reserve * sizeof(packet_t)); | |
342 if (tmp == NULL) { | |
343 perror("realloc failure"); | |
344 return -1; | |
345 } | |
346 queue->packets = tmp; | |
347 queue->packets_reserve *= 2; | |
348 } | |
349 else { | |
350 queue->packets = malloc(sizeof(packet_t)); | |
351 if (queue->packets == NULL) { | |
352 perror("malloc failure"); | |
353 return -1; | |
354 } | |
355 queue->packets_reserve = 1; | |
356 } | |
357 } | |
358 return 0; | |
359 } | |
360 | |
361 /* add one more packet */ | |
362 static int | |
363 packet_queue_grow(packet_queue_t *queue) | |
364 { | |
365 if (packet_queue_ensure(queue, queue->packets_size + 1) < 0) | |
366 return -1; | |
367 packet_construct(queue->packets + queue->packets_size); | |
368 ++queue->packets_size; | |
369 return 0; | |
370 } | |
371 | |
372 /* insert a new packet, duplicating pts from the current one */ | |
373 static int | |
374 packet_queue_insert(packet_queue_t *queue) | |
375 { | |
376 packet_t *pkts; | |
377 if (packet_queue_ensure(queue, queue->packets_size + 1) < 0) | |
378 return -1; | |
379 /* XXX packet_size does not reflect the real thing here, it will be updated a bit later */ | |
380 memmove(queue->packets + queue->current_index + 2, | |
381 queue->packets + queue->current_index + 1, | |
382 sizeof(packet_t) * (queue->packets_size - queue->current_index)); | |
383 pkts = queue->packets + queue->current_index; | |
384 ++queue->packets_size; | |
385 ++queue->current_index; | |
386 packet_construct(pkts + 1); | |
387 pkts[1].pts100 = pkts[0].pts100; | |
388 pkts[1].filepos = pkts[0].filepos; | |
389 return 0; | |
390 } | |
391 | |
392 /********************************************************************** | |
393 * Vosub | |
394 **********************************************************************/ | |
395 | |
396 typedef struct { | |
397 void *spudec; | |
398 unsigned int palette[16]; | |
399 /* index */ | |
400 packet_queue_t *spu_streams; | |
401 unsigned int spu_streams_size; | |
402 unsigned int spu_streams_current; | |
403 } vobsub_t; | |
404 | |
405 static int | |
406 vobsub_add_id(vobsub_t *vob, const char *id, size_t idlen, const unsigned int index) | |
407 { | |
408 if (index >= vob->spu_streams_size) { | |
409 /* This is a new stream */ | |
410 if (vob->spu_streams) { | |
411 packet_queue_t *tmp = realloc(vob->spu_streams, (index + 1) * sizeof(packet_queue_t)); | |
412 if (tmp == NULL) { | |
413 perror("vobsub_add_id: realloc failure"); | |
414 return -1; | |
415 } | |
416 vob->spu_streams = tmp; | |
417 } | |
418 else { | |
419 vob->spu_streams = malloc((index + 1) * sizeof(packet_queue_t)); | |
420 if (vob->spu_streams == NULL) { | |
421 perror("vobsub_add_id: malloc failure"); | |
422 return -1; | |
423 } | |
424 } | |
425 while (vob->spu_streams_size <= index) { | |
426 packet_queue_construct(vob->spu_streams + vob->spu_streams_size); | |
427 ++vob->spu_streams_size; | |
428 } | |
429 } | |
430 if (id && idlen) { | |
431 if (vob->spu_streams[index].id) | |
432 free(vob->spu_streams[index].id); | |
433 vob->spu_streams[index].id = malloc(idlen + 1); | |
434 if (vob->spu_streams[index].id == NULL) { | |
435 perror("vobsub_add_id: malloc failure"); | |
436 return -1; | |
437 } | |
438 vob->spu_streams[index].id[idlen] = 0; | |
439 memcpy(vob->spu_streams[index].id, id, idlen); | |
440 } | |
441 vob->spu_streams_current = index; | |
442 if (verbose) | |
443 fprintf(stderr, "[vobsub] subtitle (vobsubid): %d language %s\n", | |
444 index, vob->spu_streams[index].id); | |
445 return 0; | |
446 } | |
447 | |
448 static int | |
449 vobsub_add_timestamp(vobsub_t *vob, off_t filepos, unsigned int ms) | |
450 { | |
451 packet_queue_t *queue; | |
452 packet_t *pkt; | |
453 if (vob->spu_streams == 0) { | |
454 fprintf(stderr, "[vobsub] warning, binning some index entries. Check your index file\n"); | |
455 return -1; | |
456 } | |
457 queue = vob->spu_streams + vob->spu_streams_current; | |
458 if (packet_queue_grow(queue) >= 0) { | |
459 pkt = queue->packets + (queue->packets_size - 1); | |
460 pkt->filepos = filepos; | |
461 pkt->pts100 = ms / 10; | |
462 return 0; | |
463 } | |
464 return -1; | |
465 } | |
466 | |
467 static int | |
468 vobsub_parse_id(vobsub_t *vob, const char *line) | |
469 { | |
470 // id: xx, index: n | |
471 size_t idlen; | |
472 const char *p, *q; | |
473 p = line; | |
474 while (isspace(*p)) | |
475 ++p; | |
476 q = p; | |
477 while (isalpha(*q)) | |
478 ++q; | |
479 idlen = q - p; | |
480 if (idlen == 0) | |
481 return -1; | |
482 ++q; | |
483 while (isspace(*q)) | |
484 ++q; | |
485 if (strncmp("index:", q, 6)) | |
486 return -1; | |
487 q += 6; | |
488 while (isspace(*q)) | |
489 ++q; | |
490 if (!isdigit(*q)) | |
491 return -1; | |
492 return vobsub_add_id(vob, p, idlen, atoi(q)); | |
493 } | |
494 | |
495 static int | |
496 vobsub_parse_timestamp(vobsub_t *vob, const char *line) | |
497 { | |
498 // timestamp: HH:MM:SS.mmm, filepos: 0nnnnnnnnn | |
499 const char *p; | |
500 int h, m, s, ms; | |
501 off_t filepos; | |
502 while (isspace(*line)) | |
503 ++line; | |
504 p = line; | |
505 while (isdigit(*p)) | |
506 ++p; | |
507 if (p - line != 2) | |
508 return -1; | |
509 h = atoi(line); | |
510 if (*p != ':') | |
511 return -1; | |
512 line = ++p; | |
513 while (isdigit(*p)) | |
514 ++p; | |
515 if (p - line != 2) | |
516 return -1; | |
517 m = atoi(line); | |
518 if (*p != ':') | |
519 return -1; | |
520 line = ++p; | |
521 while (isdigit(*p)) | |
522 ++p; | |
523 if (p - line != 2) | |
524 return -1; | |
525 s = atoi(line); | |
526 if (*p != ':') | |
527 return -1; | |
528 line = ++p; | |
529 while (isdigit(*p)) | |
530 ++p; | |
531 if (p - line != 3) | |
532 return -1; | |
533 ms = atoi(line); | |
534 if (*p != ',') | |
535 return -1; | |
536 line = p + 1; | |
537 while (isspace(*line)) | |
538 ++line; | |
539 if (strncmp("filepos:", line, 8)) | |
540 return -1; | |
541 line += 8; | |
542 while (isspace(*line)) | |
543 ++line; | |
544 if (! isxdigit(*line)) | |
545 return -1; | |
546 filepos = strtol(line, NULL, 16); | |
547 return vobsub_add_timestamp(vob, filepos, ms + 1000 * (s + 60 * (m + 60 * h))); | |
548 } | |
549 | |
550 static int | |
551 vobsub_parse_one_line(vobsub_t *vob, FILE *fd) | |
552 { | |
553 ssize_t line_size; | |
554 int res = -1; | |
555 do { | |
556 int line_reserve = 0; | |
557 char *line = NULL; | |
558 line_size = getline(&line, &line_reserve, fd); | |
559 if (line_size < 0) { | |
560 if (line) | |
561 free(line); | |
562 break; | |
563 } | |
564 if (*line == 0 || *line == '\r' || *line == '\n' || *line == '#') | |
565 continue; | |
566 else if (strncmp("id:", line, 3) == 0) | |
567 res = vobsub_parse_id(vob, line + 3); | |
568 else if (strncmp("timestamp:", line, 10) == 0) | |
569 res = vobsub_parse_timestamp(vob, line + 10); | |
570 else { | |
571 if (verbose) | |
572 fprintf(stderr, "vobsub: ignoring %s", line); | |
573 continue; | |
574 } | |
575 if (res < 0) | |
576 fprintf(stderr, "ERROR in %s", line); | |
577 break; | |
578 } while (1); | |
579 return res; | |
580 } | |
581 | |
582 void * | |
583 vobsub_open(const char *const name) | |
584 { | |
585 vobsub_t *vob = malloc(sizeof(vobsub_t)); | |
586 if (vob) { | |
587 char *buf; | |
588 vob->spudec = NULL; | |
589 vob->spu_streams = NULL; | |
590 vob->spu_streams_size = 0; | |
591 vob->spu_streams_current = 0; | |
592 buf = malloc((strlen(name) + 5) * sizeof(char)); | |
593 if (buf) { | |
594 FILE *fd; | |
595 mpeg_t *mpg; | |
596 strcpy(buf, name); | |
597 strcat(buf, ".ifo"); | |
598 fd = fopen(buf, "rb"); | |
599 if (fd == NULL) | |
600 perror("Can't open IFO file"); | |
601 else { | |
602 // parse IFO header | |
603 unsigned char block[0x800]; | |
604 const char *const ifo_magic = "DVDVIDEO-VTS"; | |
605 if (fread(block, sizeof(block), 1, fd) != 1) | |
606 perror("Can't read IFO header"); | |
607 else if (memcmp(block, ifo_magic, strlen(ifo_magic) + 1)) | |
608 fprintf(stderr, "Bad magic in IFO header\n"); | |
609 else { | |
610 unsigned long pgci_sector = block[0xcc] << 24 | block[0xcd] << 16 | |
611 | block[0xce] << 8 | block[0xcf]; | |
612 int standard = (block[0x200] & 0x30) >> 4; | |
613 int resolution = (block[0x201] & 0x0c) >> 2; | |
614 unsigned int orig_frame_y = standard ? 576 : 480; | |
615 unsigned int orig_frame_x = 0; | |
616 switch (resolution) { | |
617 case 0x0: | |
618 orig_frame_x = 720; | |
619 break; | |
620 case 0x1: | |
621 orig_frame_x = 704; | |
622 break; | |
623 case 0x2: | |
624 orig_frame_x = 352; | |
625 break; | |
626 case 0x3: | |
627 orig_frame_x = 352; | |
628 orig_frame_y /= 2; | |
629 break; | |
630 default: | |
631 fprintf(stderr, "Unknown resolution %d \n", resolution); | |
632 } | |
633 if (fseek(fd, pgci_sector * sizeof(block), SEEK_SET) | |
634 || fread(block, sizeof(block), 1, fd) != 1) | |
635 perror("Can't read IFO PGCI"); | |
636 else { | |
637 unsigned long idx; | |
638 unsigned long pgc_offset = block[0xc] << 24 | block[0xd] << 16 | |
639 | block[0xe] << 8 | block[0xf]; | |
640 for (idx = 0; idx < 16; ++idx) { | |
641 unsigned char *p = block + pgc_offset + 0xa4 + 4 * idx; | |
642 vob->palette[idx] = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3]; | |
643 } | |
644 } | |
645 vob->spudec = spudec_new_scaled(vob->palette, orig_frame_x, orig_frame_y); | |
646 } | |
647 fclose(fd); | |
648 } | |
649 | |
650 /* read in the index */ | |
651 strcpy(buf, name); | |
652 strcat(buf, ".idx"); | |
653 fd = fopen(buf, "rb"); | |
654 if (fd == NULL) | |
655 perror("Can't open IDX file"); | |
656 else { | |
657 while (vobsub_parse_one_line(vob, fd) >= 0) | |
658 /* NOOP */ ; | |
659 fclose(fd); | |
660 } | |
661 | |
662 /* read the indexed mpeg_stream */ | |
663 strcpy(buf, name); | |
664 strcat(buf, ".sub"); | |
665 mpg = mpeg_open(buf); | |
666 if (mpg == NULL) | |
667 perror("Can't open SUB file"); | |
668 else { | |
669 long last_pts_diff = 0; | |
670 if (vob->spu_streams == NULL) | |
671 abort(); | |
672 while (!mpeg_eof(mpg)) { | |
673 off_t pos = mpeg_tell(mpg); | |
674 if (mpeg_run(mpg) < 0) { | |
675 if (!mpeg_eof(mpg)) | |
676 perror("mpeg_run error"); | |
677 break; | |
678 } | |
679 if (mpg->packet_size) { | |
680 if ((mpg->aid & 0xe0) == 0x20) { | |
681 unsigned int sid = mpg->aid & 0x1f; | |
682 if (vob->spu_streams_size > sid) { | |
683 packet_queue_t *queue = vob->spu_streams + sid; | |
684 /* get the packet to fill */ | |
685 while (queue->current_index + 1 < queue->packets_size | |
686 && queue->packets[queue->current_index + 1].filepos <= pos) | |
687 ++queue->current_index; | |
688 if (queue->current_index < queue->packets_size) { | |
689 packet_t *pkt; | |
690 if (queue->packets[queue->current_index].data) { | |
691 /* insert a new packet and fix the PTS ! */ | |
692 packet_queue_insert(queue); | |
693 queue->packets[queue->current_index].pts100 = | |
694 mpg->pts + last_pts_diff; | |
695 } | |
696 pkt = queue->packets + queue->current_index; | |
697 last_pts_diff = pkt->pts100 - mpg->pts; | |
698 /* FIXME: should not use mpg_sub internal informations, make a copy */ | |
699 pkt->data = mpg->packet; | |
700 pkt->size = mpg->packet_size; | |
701 mpg->packet = NULL; | |
702 mpg->packet_reserve = 0; | |
703 mpg->packet_size = 0; | |
704 } | |
705 } | |
706 else | |
707 fprintf(stderr, "don't know what to do with subtitle #%u\n", sid); | |
708 } | |
709 } | |
710 } | |
711 vob->spu_streams_current = vob->spu_streams_size; | |
712 while (vob->spu_streams_current-- > 0) | |
713 vob->spu_streams[vob->spu_streams_current].current_index = 0; | |
714 mpeg_free(mpg); | |
715 } | |
716 free(buf); | |
717 } | |
718 } | |
719 return vob; | |
720 } | |
721 | |
722 void | |
723 vobsub_close(void *this) | |
724 { | |
725 vobsub_t *vob = (vobsub_t *)this; | |
726 if (vob->spudec) | |
727 spudec_free(vob->spudec); | |
728 if (vob->spu_streams) { | |
729 while (vob->spu_streams_size--) | |
730 packet_queue_destroy(vob->spu_streams + vob->spu_streams_size); | |
731 free(vob->spu_streams); | |
732 } | |
733 free(vob); | |
734 } | |
735 | |
736 void vobsub_draw(void *this, int dxs, int dys, void (*draw_alpha)(int x0,int y0, int w,int h, unsigned char* src, unsigned char *srca, int stride)) | |
737 { | |
738 vobsub_t *vob = (vobsub_t *)this; | |
739 if (vob->spudec) | |
740 spudec_draw_scaled(vob->spudec, dxs, dys, draw_alpha); | |
741 } | |
742 | |
743 void | |
744 vobsub_process(void *vobhandle, float pts) | |
745 { | |
746 vobsub_t *vob = (vobsub_t *)vobhandle; | |
747 unsigned int pts100 = 100 * pts; | |
748 if (vob->spudec) | |
749 spudec_heartbeat(vob->spudec, pts100); | |
750 if (vob->spu_streams && 0 <= vobsub_id && (unsigned) vobsub_id < vob->spu_streams_size) { | |
751 packet_queue_t *queue = vob->spu_streams + vobsub_id; | |
752 while (queue->current_index < queue->packets_size) { | |
753 packet_t *pkt = queue->packets + queue->current_index; | |
754 if (pkt->pts100 <= pts100) { | |
755 spudec_assemble(vob->spudec, pkt->data, pkt->size, pkt->pts100); | |
756 ++queue->current_index; | |
757 } | |
758 else | |
759 break; | |
760 } | |
761 } | |
762 } | |
763 | |
764 void | |
765 vobsub_reset(void *vobhandle) | |
766 { | |
767 vobsub_t *vob = (vobsub_t *)vobhandle; | |
768 if (vob->spu_streams) { | |
769 unsigned int n = vob->spu_streams_size; | |
770 while (n-- > 0) | |
771 vob->spu_streams[n].current_index = 0; | |
772 } | |
773 if (vob->spudec) | |
774 spudec_reset(vob->spudec); | |
775 } |