diff --git a/src/output/p_vobsub.cpp b/src/output/p_vobsub.cpp index 0dd17e7cb..b8b22799d 100644 --- a/src/output/p_vobsub.cpp +++ b/src/output/p_vobsub.cpp @@ -72,12 +72,73 @@ void vobsub_packetizer_c::set_headers() { track_entry->EnableLacing(false); } +int vobsub_packetizer_c::extract_duration(unsigned char *data, int buf_size) { + const int lengths[7] = {0, 0, 0, 2, 2, 6, 4}; + int i, next_ctrlblk, packet_size, data_size, t, len; + + packet_size = (data[0] << 8) | data[1]; + data_size = (data[2] << 8) | data[3]; + next_ctrlblk = data_size; + + do { + i = next_ctrlblk; + t = (data[i] << 8) | data[i + 1]; + i += 2; + next_ctrlblk = (data[i] << 8) | data[i + 1]; + i += 2; + + if((next_ctrlblk > packet_size) || (next_ctrlblk < data_size)) + mxerror(PFX "Inconsistent data in the SPU packets (next_ctrlblk: %d, " + "packet_size: %d, data_size: %d)\n", next_ctrlblk, packet_size, + data_size); + + if (data[i] <= 0x06) + len = lengths[data[i]]; + else + len = 0; + + if ((i + len) > packet_size) { + mxwarn(PFX "Warning: Wrong subpicture parameter blockending (i: %d, " + "len: %d, packet_size: %d)\n", i, len, packet_size); + break; + } + if (data[i] == 0x02) + return 1024 * t / 90; + i++; + } + while ((i <= next_ctrlblk) && (i < packet_size)); + + return -1; +} + +#define deliver() deliver_packet(dst_buf, dst_size, timecode, duration); +int vobsub_packetizer_c::deliver_packet(unsigned char *buf, int size, + int64_t timecode, + int64_t default_duration) { + int64_t duration; + + if ((buf == NULL) || (size == 0)) { + safefree(buf); + return -1; + } + + duration = extract_duration(buf, size); + if (duration == -1) { + mxwarn(PFX "Could not extract the duration for a SPU packet.\n"); + duration = default_duration; + } + add_packet(buf, size, timecode, duration, true); + safefree(buf); + + return -1; +} + // Adopted from mplayer's vobsub.c int vobsub_packetizer_c::process(unsigned char *srcbuf, int size, int64_t timecode, int64_t duration, int64_t, int64_t) { - unsigned char *data; - uint32_t len, idx, version, packet_size; + unsigned char *dst_buf; + uint32_t len, idx, version, packet_size, dst_size; int c, aid; float pts; /* Goto start of a packet, it starts with 0x000001?? */ @@ -89,26 +150,28 @@ int vobsub_packetizer_c::process(unsigned char *srcbuf, int size, if (extract_from_mpeg) { mm_mem_io_c in(srcbuf, size); + dst_buf = NULL; + dst_size = 0; packet_size = 0; while (1) { if (in.read(buf, 4) != 4) - return -1; + return deliver(); while (memcmp(buf, wanted, sizeof(wanted)) != 0) { c = in.getch(); if (c < 0) - return -1; + return deliver(); memmove(buf, buf + 1, 3); buf[3] = c; } switch (buf[3]) { case 0xb9: /* System End Code */ - return 0; + return deliver(); break; case 0xba: /* Packet start code */ c = in.getch(); if (c < 0) - return -1; + return deliver(); if ((c & 0xc0) == 0x40) version = 4; else if ((c & 0xf0) == 0x20) @@ -116,33 +179,33 @@ int vobsub_packetizer_c::process(unsigned char *srcbuf, int size, else { mxwarn(PFX "Unsupported MPEG version: 0x%02x in packet %lld\n", c, packet_num); - return -1; + return deliver(); } if (version == 4) { if (!in.setFilePointer2(9, seek_current)) - return -1; + return deliver(); } else if (version == 2) { if (!in.setFilePointer2(7, seek_current)) - return -1; + return deliver(); } else abort(); break; case 0xbd: /* packet */ if (in.read(buf, 2) != 2) - return -1; + return deliver(); len = buf[0] << 8 | buf[1]; idx = in.getFilePointer(); c = in.getch(); if (c < 0) - return -1; + return deliver(); if ((c & 0xC0) == 0x40) { /* skip STD scale & size */ if (in.getch() < 0) - return -1; + return deliver(); c = in.getch(); if (c < 0) - return -1; + return deliver(); } if ((c & 0xf0) == 0x20) { /* System-1 stream timestamp */ /* Do we need this? */ @@ -154,21 +217,21 @@ int vobsub_packetizer_c::process(unsigned char *srcbuf, int size, uint32_t pts_flags, hdrlen, dataidx; c = in.getch(); if (c < 0) - return -1; + return deliver(); pts_flags = c; c = in.getch(); if (c < 0) - return -1; + return deliver(); hdrlen = c; dataidx = in.getFilePointer() + hdrlen; if (dataidx > idx + len) { mxwarn(PFX "Invalid header length: %d (total length: %d, " "idx: %d, dataidx: %d)\n", hdrlen, len, idx, dataidx); - return -1; + return deliver(); } if ((pts_flags & 0xc0) == 0x80) { if (in.read(buf, 5) != 5) - return -1; + return deliver(); if (!(((buf[0] & 0xf0) == 0x20) && (buf[0] & 1) && (buf[2] & 1) && (buf[4] & 1))) { mxwarn(PFX "PTS error: 0x%02x %02x%02x %02x%02x \n", @@ -185,20 +248,18 @@ int vobsub_packetizer_c::process(unsigned char *srcbuf, int size, aid = in.getch(); if (aid < 0) { mxwarn(PFX "Bogus aid %d\n", aid); - return -1; + return deliver(); } packet_size = len - ((unsigned int)in.getFilePointer() - idx); - data = (unsigned char *)safemalloc(packet_size); - if (in.read(data, packet_size) != packet_size) { + dst_buf = (unsigned char *)saferealloc(dst_buf, dst_size + + packet_size); + if (in.read(&dst_buf[dst_size], packet_size) != packet_size) { mxwarn(PFX "in.read failure"); - safefree(data); - return -1; + return deliver(); } - + dst_size += packet_size; spu_size += packet_size; overhead += size - packet_size; - add_packet(data, packet_size, timecode, duration, true); - safefree(data); idx = len; } @@ -206,34 +267,34 @@ int vobsub_packetizer_c::process(unsigned char *srcbuf, int size, case 0xbe: /* Padding */ if (in.read(buf, 2) != 2) - return -1; + return deliver(); len = buf[0] << 8 | buf[1]; if ((len > 0) && !in.setFilePointer2(len, seek_current)) - return -1; + return deliver(); break; default: if ((0xc0 <= buf[3]) && (buf[3] < 0xf0)) { /* MPEG audio or video */ if (in.read(buf, 2) != 2) - return -1; + return deliver(); len = (buf[0] << 8) | buf[1]; if ((len > 0) && !in.setFilePointer2(len, seek_current)) - return -1; + return deliver(); } else { mxwarn(PFX "unknown header 0x%02X%02X%02X%02X\n", buf[0], buf[1], buf[2], buf[3]); - return -1; + return deliver(); } } } - return EMOREDATA; + return deliver(); } spu_size += size; - add_packet(buf, size, timecode, duration, true); + add_packet(srcbuf, size, timecode, duration, true); return EMOREDATA; } diff --git a/src/output/p_vobsub.h b/src/output/p_vobsub.h index e7764548f..d088e5e37 100644 --- a/src/output/p_vobsub.h +++ b/src/output/p_vobsub.h @@ -47,6 +47,11 @@ public: virtual void set_headers(); virtual void dump_debug_info(); + +protected: + virtual int extract_duration(unsigned char *data, int buf_size); + virtual int deliver_packet(unsigned char *buf, int size, int64_t timecode, + int64_t default_duration); }; #endif // __P_VOBSUB_H