From f36c4b065b6b5ed5b79cbf423501a0a1d1a07078 Mon Sep 17 00:00:00 2001 From: kmkaplan Date: Thu, 11 Jul 2002 18:49:18 +0000 Subject: Lots of compatibility fixes for Windows' Vobsub reader. git-svn-id: svn://svn.mplayerhq.hu/mplayer/trunk@6707 b3059339-0415-0410-9bf9-f77b7e298cf2 --- vobsub.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 110 insertions(+), 35 deletions(-) (limited to 'vobsub.c') 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 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); } } - -- cgit v1.2.3