changeset 6706:e1428c2c971f

Lots of compatibility fixes for Windows' Vobsub reader.
author kmkaplan
date Thu, 11 Jul 2002 18:49:18 +0000
parents 68506f182491
children 3f0c724dac75
files vobsub.c
diffstat 1 files changed, 110 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/vobsub.c	Thu Jul 11 18:48:43 2002 +0000
+++ b/vobsub.c	Thu Jul 11 18:49:18 2002 +0000
@@ -1012,7 +1012,7 @@
 {
     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 @@
 	    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 @@
 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 @@
 	    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;
+	    }
 	}
-	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
+	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;
+	}
+	*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);
     }
 }
-