summaryrefslogtreecommitdiffstats
path: root/vobsub.c
diff options
context:
space:
mode:
authorkmkaplan <kmkaplan@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-07-11 18:49:18 +0000
committerkmkaplan <kmkaplan@b3059339-0415-0410-9bf9-f77b7e298cf2>2002-07-11 18:49:18 +0000
commitf36c4b065b6b5ed5b79cbf423501a0a1d1a07078 (patch)
treebe2d23941734d75142115a461054fe87d176a7e9 /vobsub.c
parent25c6f96f6280f8151e20f5051e89e5c000ee6f61 (diff)
downloadmpv-f36c4b065b6b5ed5b79cbf423501a0a1d1a07078.tar.bz2
mpv-f36c4b065b6b5ed5b79cbf423501a0a1d1a07078.tar.xz
Lots of compatibility fixes for Windows' Vobsub reader.
git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@6707 b3059339-0415-0410-9bf9-f77b7e298cf2
Diffstat (limited to 'vobsub.c')
-rw-r--r--vobsub.c145
1 files changed, 110 insertions, 35 deletions
diff --git a/vobsub.c b/vobsub.c
index 15175d6ffa..19b19f5dfb 100644
--- a/vobsub.c
+++ b/vobsub.c
@@ -1012,7 +1012,7 @@ create_idx(vobsub_out_t *me, const unsigned int *palette, unsigned int orig_widt
{
int i;
fprintf(me->fidx,
- "# VobSub index file, v3 (do not modify this line!)\n"
+ "# VobSub index file, v7 (do not modify this line!)\n"
"#\n"
"# Generated by MPlayer " VERSION "\n"
"# See <URL:http://www.mplayerhq.hu/> for more information about MPlayer\n"
@@ -1055,10 +1055,11 @@ vobsub_out_open(const char *basename, const unsigned int *palette,
strcat(filename, ".idx");
result->fidx = fopen(filename, "a");
if (result->fidx) {
- setvbuf(result->fidx, NULL, _IOLBF, 0);
if (ftell(result->fidx) == 0)
create_idx(result, palette, orig_width, orig_height);
fprintf(result->fidx, "\nid: %s, index: %u\n", id ? id : "xx", index);
+ /* So that we can check the file now */
+ fflush(result->fidx);
}
else
perror("Error: vobsub_out_open index file open failed");
@@ -1082,10 +1083,18 @@ vobsub_out_close(void *me)
void
vobsub_out_output(void *me, const unsigned char *packet, int len, double pts)
{
+ static double last_pts;
+ static int last_pts_set = 0;
vobsub_out_t *vob = (vobsub_out_t*)me;
if (vob->fsub) {
+ /* Windows' Vobsub require that every packet is exactly 2kB long */
unsigned char buffer[2048];
- if (vob->fidx) {
+ unsigned char *p;
+ int remain = 2048;
+ /* Do not output twice a line with the same timestamp, this
+ breaks Windows' Vobsub */
+ if (vob->fidx && (!last_pts_set || last_pts != pts)) {
+ static unsigned int last_h = 9999, last_m = 9999, last_s = 9999, last_ms = 9999;
unsigned int h, m, ms;
double s;
s = pts;
@@ -1096,40 +1105,106 @@ vobsub_out_output(void *me, const unsigned char *packet, int len, double pts)
ms = (s - (unsigned int) s) * 1000;
if (ms >= 1000) /* prevent overfolws or bad float stuff */
ms = 0;
- fprintf(vob->fidx, "timestamp: %02u:%02u:%02u:%03u, filepos: %09lx\n",
- h, m, (unsigned int) s, ms, ftell(vob->fsub));
+ if (h != last_h || m != last_m || (unsigned int) s != last_s || ms != last_ms) {
+ fprintf(vob->fidx, "timestamp: %02u:%02u:%02u:%03u, filepos: %09lx\n",
+ h, m, (unsigned int) s, ms, ftell(vob->fsub));
+ last_h = h;
+ last_m = m;
+ last_s = (unsigned int) s;
+ last_ms = ms;
+ }
+ }
+ last_pts = pts;
+ last_pts_set = 1;
+
+ /* Packet start code: Windows' Vobsub needs this */
+ p = buffer;
+ *p++ = 0; /* 0x00 */
+ *p++ = 0;
+ *p++ = 1;
+ *p++ = 0xba;
+ *p++ = 0x40;
+ memset(p, 0, 9);
+ p += 9;
+ { /* Packet */
+ static unsigned char last_pts[5] = { 0, 0, 0, 0, 0};
+ unsigned char now_pts[5];
+ int pts_len, pad_len, datalen = len;
+ pts *= 90000;
+ now_pts[0] = 0x21 | (((unsigned long)pts >> 29) & 0x0e);
+ now_pts[1] = ((unsigned long)pts >> 22) & 0xff;
+ now_pts[2] = 0x01 | (((unsigned long)pts >> 14) & 0xfe);
+ now_pts[3] = ((unsigned long)pts >> 7) & 0xff;
+ now_pts[4] = 0x01 | (((unsigned long)pts << 1) & 0xfe);
+ pts_len = memcmp(last_pts, now_pts, sizeof(now_pts)) ? sizeof(now_pts) : 0;
+ memcpy(last_pts, now_pts, sizeof(now_pts));
+
+ datalen += 3; /* Version, PTS_flags, pts_len */
+ datalen += pts_len;
+ datalen += 1; /* AID */
+ pad_len = 2048 - (p - buffer) - 4 /* MPEG ID */ - 2 /* payload len */ - datalen;
+ /* XXX - Go figure what should go here! In any case the
+ packet has to be completly filled. If I can fill it
+ with padding (0x000001be) latter I'll do that. But if
+ there is only room for 6 bytes then I can not write a
+ padding packet. So I add some padding in the PTS
+ field. This looks like a dirty kludge. Oh well... */
+ if (pad_len < 0) {
+ /* Packet is too big. Let's try ommiting the PTS field */
+ datalen -= pts_len;
+ pts_len = 0;
+ pad_len = 0;
+ }
+ else if (pad_len > 6)
+ pad_len = 0;
+ datalen += pad_len;
+
+ *p++ = 0; /* 0x0e */
+ *p++ = 0;
+ *p++ = 1;
+ *p++ = 0xbd;
+
+ *p++ = (datalen >> 8) & 0xff; /* length of payload */
+ *p++ = datalen & 0xff;
+ *p++ = 0x80; /* System-2 (.VOB) stream */
+ *p++ = pts_len ? 0x80 : 0x00; /* pts_flags */
+ *p++ = pts_len + pad_len;
+ memcpy(p, now_pts, pts_len);
+ p += pts_len;
+ memset(p, 0, pad_len);
+ p += pad_len;
}
- buffer[0] = 0;
- buffer[1] = 0;
- buffer[2] = 1;
- buffer[3] = 0xbd;
- buffer[4] = ((9 + len) >> 8) & 0xff; /* length of payload */
- buffer[5] = (9 + len) & 0xff;
- buffer[6] = 0x80; /* System-2 (.VOB) stream */
- buffer[7] = 0x80; /* pts_flags */
- buffer[8] = 5; /* hdrlen */
- pts *= 90000;
- buffer[9] = 0x21 | (((unsigned long)pts >> 29) & 0x0e);
- buffer[10] = ((unsigned long)pts >> 22) & 0xff;
- buffer[11] = 0x01 | (((unsigned long)pts >> 14) & 0xfe);
- buffer[12] = ((unsigned long)pts >> 7) & 0xff;
- buffer[13] = 0x01 | (((unsigned long)pts << 1) & 0xfe);
- buffer[14] = 0x20 | vob->aid; /* aid */
- if (fwrite(buffer, 15, 1, vob->fsub) != 1
+ *p++ = 0x20 | vob->aid; /* aid */
+ if (fwrite(buffer, p - buffer, 1, vob->fsub) != 1
|| fwrite(packet, len, 1, vob->fsub) != 1)
perror("ERROR: vobsub write failed");
- /* padding */
- len = 2048 - 15 - len;
- buffer[0] = 0x00;
- buffer[1] = 0x00;
- buffer[2] = 0x01;
- buffer[3] = 0xbe;
- buffer[4] = (len - 6) >> 8;
- buffer[5] = (len - 6) & 0xff;
- /* for better compression, blank this */
- memset(buffer + 6, 0, len - 6);
- if (fwrite(buffer, len, 1, vob->fsub) != 1)
- perror("ERROR: vobsub padding write failed");
+ else
+ remain -= p - buffer + len;
+
+ /* Padding */
+ if (remain >= 6) {
+ p = buffer;
+ *p++ = 0x00;
+ *p++ = 0x00;
+ *p++ = 0x01;
+ *p++ = 0xbe;
+ *p++ = (remain - 6) >> 8;
+ *p++ = (remain - 6) & 0xff;
+ /* for better compression, blank this */
+ memset(buffer + 6, 0, remain - (p - buffer));
+ if (fwrite(buffer, remain, 1, vob->fsub) != 1)
+ perror("ERROR: vobsub padding write failed");
+ }
+ else if (remain > 0) {
+ /* I don't know what to output. But anyway the block
+ needs to be 2KB big */
+ memset(buffer, 0, remain);
+ if (fwrite(buffer, remain, 1, vob->fsub) != 1)
+ perror("ERROR: vobsub blank padding write failed");
+ }
+ else if (remain < 0)
+ fprintf(stderr,
+ "\nERROR: wrong thing happenned...\n"
+ " I wrote a %i data bytes spu packet and that's too long\n", len);
}
}
-