File:dvdauthor-0.6.14-ivtv-patch.txt

From IVTV

Jump to: navigation, search

Contents

What's this?

The following is a patch file that describes a number of changes to the source code for version 0.6.14 of dvdauthor, that enable it successfully to accept direct input from suitably-formatted MPEG-2 streams encoded by IVTV (see my howto).

A patch against an old version of dvdauthor (0.6.11) is available here, but I recommend using the newer version if at all possible.

How do I use it?

  1. Download and extract the source tarball for dvdauthor version 0.6.14;
  2. Copy the content of the section below to a local file called dvdauthor-0.6.14-ivtv-patch-0.2.txt;
  3. Go to the dvdauthor-0.6.14 directory and do patch -p0 < dvdauthor-0.6.14-ivtv-patch-0.2.txt;
  4. Configure, build and install the application as required.


IVTV patch for dvdauthor version 0.6.14

note: this patch has been passed to the dvdauthor developers, for consideration as a possible inclusion in their next release


--- src/dvdvob.c.dist	2008-06-06 13:16:57.000000000 +0100
+++ src/dvdvob.c	2008-06-06 13:29:47.000000000 +0100
@@ -16,8 +16,31 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
  * USA
  */
 
+/* NOTE TO THOSE UNFAMILIAR WITH MPEG FORMAT
+ *       This code contains many 'magic numbers' related to analysing and
+ *       and parsing MPEG data. MPEG content consists of a series of
+ *       2048 byte 'packs'. Each pack begins with a pack header that is
+ *       identified by the byte sequence 00 00 01 BA. The rest of the pack
+ *       contains other headers (each identified by their own start code),
+ *       plus payload data and optional stuffing bytes. The headers contain
+ *       data fields describing different aspect of the payload, timing etc.
+ *       Frequently encountered types of header include:
+ *		00 00 01 BA : pack header;
+ *		00 00 01 BB : system header;
+ *		00 00 01 B3 : sequence header;
+ *		00 00 01 B5 : extension header;
+ *		00 00 01 B8 : group-of-pictures (GOP) header;
+ *		00 00 01 E0 : programme-elementary-stream (PES) header for first video channel
+ *		etc...
+ *       A useful quick reference for identifying and decoding MPEG headers
+ *       is available at http://dvd.sourceforge.net/dvdinfo/mpeghdrs.html
+ *       For detailed information try chapter 10 (p230) of 'digital video
+ *       introduction to mpeg2' (Haskell, Puri and Netravali), which you can
+ *       read online at http://books.google.com
+ */
+
 #include "config.h"
 
 #include "compat.h"
 
@@ -233,8 +254,10 @@
 }
 
 static void transpose_ts(unsigned char *buf,pts_t tsoffs)
 {
+    int shift;
+
     // pack scr
     if( buf[0] == 0 &&
         buf[1] == 0 &&
         buf[2] == 1 &&
@@ -243,23 +266,51 @@
         writescr(buf+4,readscr(buf+4)+tsoffs);
 
         // video/audio?
         // pts?
-        if( buf[14] == 0 &&
-            buf[15] == 0 &&
-            buf[16] == 1 &&
-            (buf[17]==0xbd || (buf[17]>=0xc0 && buf[17]<=0xef)) &&
-            (buf[21] & 128))
+	// allow for optional system header before the PES header
+	shift = (buf[17] == 0xbb) ? 24 : 0;
+        if( buf[14+shift] == 0 &&
+            buf[15+shift] == 0 &&
+            buf[16+shift] == 1 &&
+            (buf[17+shift]==0xbd || (buf[17+shift]>=0xc0 && buf[17+shift]<=0xef)) &&
+            (buf[21+shift] & 128))
         {
-            writepts(buf+23,readpts(buf+23)+tsoffs);
+            writepts(buf+23+shift,readpts(buf+23+shift)+tsoffs);
             // dts?
-            if( buf[21] & 64 ) {
-                writepts(buf+28,readpts(buf+28)+tsoffs);
+            if( buf[21+shift] & 64 ) {
+                writepts(buf+28+shift,readpts(buf+28+shift)+tsoffs);
             }
         }
     }
 }
 
+int find_gop(unsigned char *buf)
+{
+    // if the pack has a system header and a video PES header, then check whether there is a GOP header
+    if (buf[14] == 0 &&
+        buf[15] == 0 &&
+        buf[16] == 1 &&
+        buf[17] == 0xbb &&
+        buf[38] == 0 &&
+        buf[39] == 0 &&
+        buf[40] == 1 &&
+        buf[41] == 0xe0)
+    {
+        int i = 42;
+        while (i < 1024)
+        {
+            if (buf[i] == 0 &&
+                buf[i+1] == 0 &&
+                buf[i+2] == 1 &&
+                buf[i+3] == 0xb8)
+                return 1;
+            i += 4;
+        }
+    }
+    return 0;
+}
+
 static int mpa_valid(unsigned char *b)
 {
     unsigned int v=(b[0]<<24)|(b[1]<<16)|(b[2]<<8)|b[3];
     int t;
@@ -823,10 +874,12 @@
 
 int FindVobus(char *fbase,struct vobgroup *va,int ismenu)
 {
     unsigned char *buf;
+    unsigned char *buf_copy = (unsigned char*) malloc(2048);
     int cursect=0,fsect=-1,vnum,outnum=-ismenu+1;
     int vobid=0;
+    int shift;
     struct mp2info {
         int hdrptr;
         unsigned char buf[6];
     } mp2hdr[8];
@@ -836,8 +889,9 @@
     for( vnum=0; vnum<va->numvobs; vnum++ ) {
         int i,j;
         int hadfirstvobu=0;
         pts_t backoffs=0, lastscr=0;
+        int generate_vobu=0,copy_packet=0,tsoffs=0;
         struct vob *s=va->vobs[vnum];
         int prevvidsect=-1;
         struct vscani vsi;
         struct vfile vf;
@@ -868,10 +922,11 @@
                 fsect=-1;
             }
             buf=writegrabbuf();
 
-            i=fread(buf,1,2048,vf.h);
-            if( i!=2048 ) {
+            if (copy_packet == 1 ) {
+                memcpy( buf, buf_copy, 2048);
+            } else if( 2048 != (i=fread(buf,1,2048,vf.h)) ) {
                 if( i==-1 ) {
                     fprintf(stderr,"\nERR:  Error while reading: %s\n",strerror(errno));
                     exit(1);
                 } else if( i>0 )
@@ -985,8 +1040,44 @@
 
                 writeundo();
                 continue;
             }
+
+            if( fsect == -1 ) {
+                char newname[200];
+                fsect=0;
+                if( fbase ) {
+                    if( outnum>=0 )
+                        sprintf(newname,"%s_%d.VOB",fbase,outnum);
+                    else
+                        strcpy(newname,fbase);
+                    writeopen(newname);
+                }
+            }
+
+            // we should get a VOBU before a video with GOP
+            if( (generate_vobu == 1 || hadfirstvobu == 0) &&
+                copy_packet == 0 && find_gop(buf) )
+            {
+                // create VOBU
+		//fprintf(stderr,"INFO: found video GOP without a preceding VOBU - creating VOBU\n");
+                generate_vobu = 1;
+                copy_packet = 1;
+                memcpy( buf_copy, buf, 2048);
+
+                buf[41] = 0xbf;
+                buf[42] = 0x03;
+                buf[43] = 0xd4;
+                buf[44] = 0x81;
+                memset( buf+45, 0, 2048-45);
+                buf[1026] = 1;
+                buf[1027] = 0xbf;
+                buf[1028] = 0x03;
+                buf[1029] = 0xfa;
+                buf[1030] = 0x81;
+            } else if (copy_packet == 1)
+                copy_packet = 0;
+
             if( buf[0]==0 && buf[1]==0 && buf[2]==1 && buf[3]==0xba ) {
                 pts_t newscr=readscr(buf+4);
                 if( newscr < lastscr ) {
                     fprintf(stderr,"ERR:  SCR moves backwards, remultiplex input.\n");
@@ -996,18 +1087,19 @@
                 if( !hadfirstvobu )
                     backoffs=newscr;
             }
             transpose_ts(buf,-backoffs);
-            if( fsect == -1 ) {
-                char newname[200];
-                fsect=0;
-                if( fbase ) {
-                    if( outnum>=0 )
-                        sprintf(newname,"%s_%d.VOB",fbase,outnum);
-                    else
-                        strcpy(newname,fbase);
-                    writeopen(newname);
-                }
+
+            if( !hadfirstvobu && buf[0]==0 && buf[1]==0 && buf[2]==1 && buf[3]==0xba )
+            {
+                // allow for optional system header before the PES header
+                shift = (buf[17] == 0xbb) ? 24 : 0;
+                if( buf[14+shift] == 0 &&
+                    buf[15+shift] == 0 &&
+                    buf[16+shift] == 1 &&
+                    (buf[17+shift]==0xbd || (buf[17+shift]>=0xc0 && buf[17+shift]<=0xef)) &&
+                    (buf[21+shift] & 128))
+	                    tsoffs = readpts(buf+23+shift);
             }
             if( buf[14] == 0 &&
                 buf[15] == 0 &&
                 buf[16] == 1 &&
@@ -1050,9 +1142,9 @@
                     if( !(s->numvobus&15) )
                         printvobustatus(va,cursect);
                     vsi.lastrefsect=0;
                     vsi.firstgop=1;
-                } else {
+                } else if (generate_vobu == 0 || copy_packet == 1) {
                     fprintf(stderr,"WARN: System header found, but PCI/DSI information is not where expected\n\t(make sure your system header is 18 bytes!)\n");
                 }
             }
             if( !hadfirstvobu ) {
@@ -1077,36 +1169,40 @@
                 }
                 break;
             }
 
+            // allow for optional system header before the PES header
+            shift = (buf[17] == 0xbb) ? 24 : 0;
             if( buf[0] == 0 &&
                 buf[1] == 0 &&
                 buf[2] == 1 &&
                 buf[3] == 0xba &&
-                buf[14] == 0 &&
-                buf[15] == 0 &&
-                buf[16] == 1 &&
-                buf[17] == 0xe0 ) { // video
+                buf[14+shift] == 0 &&
+                buf[15+shift] == 0 &&
+                buf[16+shift] == 1 &&
+                buf[17+shift] == 0xe0 ) { // video
                 struct vobuinfo *vi=&s->vi[s->numvobus-1];
                 vi->hasvideo=1;
-                scanvideoframe(va,buf,vi,cursect,prevvidsect,&vsi);
-                if( (buf[21] & 128) && vi->firstvideopts==-1 ) { // check whether there's a pts
-                    vi->firstvideopts=readpts(buf+23);
+                scanvideoframe(va,buf+shift,vi,cursect,prevvidsect,&vsi);
+                if( (buf[21+shift] & 128) && vi->firstvideopts==-1 ) { // check whether there's a pts
+                    vi->firstvideopts=readpts(buf+23+shift);
                 }
                 prevvidsect=cursect;
             }
+ 
+            shift = (buf[17] == 0xbb) ? 24 : 0;
             if( buf[0] == 0 &&
                 buf[1] == 0 &&
                 buf[2] == 1 &&
                 buf[3] == 0xba &&
-                buf[14] == 0 &&
-                buf[15] == 0 &&
-                buf[16] == 1 &&
-                ((buf[17] & 0xf8) == 0xc0 || buf[17]==0xbd)) {
+                buf[14+shift] == 0 &&
+                buf[15+shift] == 0 &&
+                buf[16+shift] == 1 &&
+                ((buf[17+shift] & 0xf8) == 0xc0 || buf[17+shift]==0xbd)) {
                 pts_t pts0=0,pts1=0,backpts1=0;
-                int dptr=buf[22]+23,endop=read2(buf+18)+20;
-                int audch,haspts=(buf[21]&128);
-                if( buf[17]==0xbd ) {
+                int dptr=buf[22+shift]+23,endop=read2(buf+shift+18)+20;	// NB: indices based on dptr should be correct - do not adjust them
+                int audch,haspts=(buf[21+shift]&128);
+                if( buf[17+shift]==0xbd ) {
                     int sid=buf[dptr],offs=read2(buf+dptr+2);
 
                     switch(sid&0xf8) {
                     case 0x20:                          // subpicture
@@ -1130,9 +1226,9 @@
                     default:   audch=-1; break;         // unknown
                     }
                 } else {
                     int len=endop-dptr;
-                    int index=buf[17]&7;
+                    int index=buf[17+shift]&7;
                     audch=8|index;                      // mp2
                     memcpy(mp2hdr[index].buf+3,buf+dptr,3);
                     while(mp2hdr[index].hdrptr+4<=len) {
                         unsigned char *h;
@@ -1156,9 +1252,9 @@
                     memcpy(mp2hdr[index].buf,buf+dptr+len-3,3);
                     audiodesc_set_audio_attr(&s->audch[audch].ad,&s->audch[audch].adwarn,AUDIO_SAMPLERATE,"48khz");
                 }
                 if( haspts ) {
-                    pts0=readpts(buf+23);
+                    pts0=readpts(buf+23+shift);
                     pts1+=pts0;
                 } else if( pts1>0 ) {
                     fprintf(stderr,"WARN: Audio channel %d contains sync headers but has no PTS.\n",audch);
                 }
@@ -1214,17 +1310,18 @@
                 }
             }
             // the following code scans subtitle code in order to
             // remap the colors and update the end pts
+            shift = (buf[17] == 0xbb) ? 24 : 0;
             if( buf[0] == 0 &&
                 buf[1] == 0 &&
                 buf[2] == 1 &&
                 buf[3] == 0xba &&
-                buf[14] == 0 &&
-                buf[15] == 0 &&
-                buf[16] == 1 &&
-                buf[17] == 0xbd) {
-                int dptr=buf[22]+23,ml=read2(buf+18)+20;
+                buf[14+shift] == 0 &&
+                buf[15+shift] == 0 &&
+                buf[16+shift] == 1 &&
+                buf[17+shift] == 0xbd) {
+                int dptr=buf[22+shift]+23,ml=read2(buf+18+shift)+20;
                 int st=buf[dptr];
                 dptr++;
                 if( (st&0xf8)==0x20 ) { // subtitle
                     procremap(&crs[st&31],buf+dptr,ml-dptr,&s->audch[st].audpts[s->audch[st].numaudpts-1].pts[1]);
@@ -1368,8 +1465,9 @@
             fprintf(stderr,"\n");
         }
     }
     writeclose();
+    free(buf_copy);
     printvobustatus(va,cursect);
     fprintf(stderr,"\n");
     free(crs);
     return 1;

previous version of the IVTV patch for dvdauthor version 0.6.14


--- src/dvdvob.c	2008-05-30 22:07:22.000000000 +0100
+++ src/dvdvob.c	2008-05-30 22:09:43.000000000 +0100
@@ -240,25 +240,51 @@
         buf[2] == 1 &&
         buf[3] == 0xba )
     {
+	int offs = (buf[17] == 0xbb) ? 24 : 0;
         writescr(buf+4,readscr(buf+4)+tsoffs);
 
         // video/audio?
         // pts?
-        if( buf[14] == 0 &&
-            buf[15] == 0 &&
-            buf[16] == 1 &&
-            (buf[17]==0xbd || (buf[17]>=0xc0 && buf[17]<=0xef)) &&
-            (buf[21] & 128))
+        if( buf[offs+14] == 0 &&
+            buf[offs+15] == 0 &&
+            buf[offs+16] == 1 &&
+            (buf[offs+17]==0xbd || (buf[offs+17]>=0xc0 && buf[offs+17]<=0xef)) &&
+            (buf[offs+21] & 128))
         {
-            writepts(buf+23,readpts(buf+23)+tsoffs);
+            writepts(buf+offs+23,readpts(buf+offs+23)+tsoffs);
             // dts?
-            if( buf[21] & 64 ) {
-                writepts(buf+28,readpts(buf+28)+tsoffs);
+            if( buf[offs+21] & 64 ) {
+                writepts(buf+offs+28,readpts(buf+offs+28)+tsoffs);
             }
         }
     }
 }
 
+int find_gop(unsigned char *buf)
+{
+    if (buf[14] == 0 &&
+        buf[15] == 0 &&
+        buf[16] == 1 &&
+        buf[17] == 0xbb &&
+        buf[38] == 0 &&
+        buf[39] == 0 &&
+        buf[40] == 1 &&
+        buf[41] == 0xe0)
+    {
+        int i = 42;
+        while (i < 1024)
+        {
+            if (buf[i] == 0 &&
+                buf[i+1] == 0 &&
+                buf[i+2] == 1 &&
+                buf[i+3] == 0xb8)
+                return 1;
+            i += 4;
+        }
+    }
+    return 0;
+}
+
 static int mpa_valid(unsigned char *b)
 {
     unsigned int v=(b[0]<<24)|(b[1]<<16)|(b[2]<<8)|b[3];
@@ -548,7 +574,7 @@
             scanvideoptr(va,buf+i,thisvi,cursect,vsi);
     }
     if( !va->vd.vmpeg )
-        vobgroup_set_video_attr(va,VIDEO_MPEG,"mpeg1");
+        vobgroup_set_video_attr(va,VIDEO_MPEG,"mpeg2");
     // if the mpeg version changed, then rerun scanvideoframe, because
     // scanvideoptr updates the aspect ratio in the sequence header
     if( mpf != va->vd.vmpeg ) {
@@ -824,6 +850,7 @@
 int FindVobus(char *fbase,struct vobgroup *va,int ismenu)
 {
     unsigned char *buf;
+    unsigned char *buf_copy = (unsigned char*) malloc(2048);
     int cursect=0,fsect=-1,vnum,outnum=-ismenu+1;
     int vobid=0;
     struct mp2info {
@@ -837,6 +864,7 @@
         int i,j;
         int hadfirstvobu=0;
         pts_t backoffs=0, lastscr=0;
+        int generate_vobu=0,copy_packet=0,tsoffs=0;
         struct vob *s=va->vobs[vnum];
         int prevvidsect=-1;
         struct vscani vsi;
@@ -869,8 +897,9 @@
             }
             buf=writegrabbuf();
 
-            i=fread(buf,1,2048,vf.h);
-            if( i!=2048 ) {
+            if (copy_packet == 1 ) {
+                memcpy( buf, buf_copy, 2048);
+            } else if( 2048 != (i=fread(buf,1,2048,vf.h)) ) {
                 if( i==-1 ) {
                     fprintf(stderr,"\nERR:  Error while reading: %s\n",strerror(errno));
                     exit(1);
@@ -986,6 +1015,38 @@
                 writeundo();
                 continue;
             }
+
+            if( fsect == -1 ) {
+                char newname[200];
+                fsect=0;
+	        if( outnum >= 0)
+                	sprintf(newname, "%s_%d.VOB", fbase,outnum);
+                else
+	               	strcpy(newname,fbase);
+		writeopen(newname);
+            }
+
+            // we should get a VOBU before a video with GOP
+            if( (generate_vobu == 1 || hadfirstvobu == 0) &&
+                copy_packet == 0 && find_gop(buf) )
+            {
+                // create VOBU
+                generate_vobu = 1;
+                copy_packet = 1;
+                memcpy( buf_copy, buf, 2048);
+
+                buf[41] = 0xbf;
+                buf[42] = 0x03;
+                buf[43] = 0xd4;
+                buf[44] = 0x81;
+                memset( buf+45, 0, 2048-45);
+                buf[1026] = 1;
+                buf[1027] = 0xbf;
+                buf[1028] = 0x03;
+                buf[1029] = 0xfa;
+                buf[1030] = 0x81;
+            } else if (copy_packet == 1)
+                copy_packet = 0;
             if( buf[0]==0 && buf[1]==0 && buf[2]==1 && buf[3]==0xba ) {
                 pts_t newscr=readscr(buf+4);
                 if( newscr < lastscr ) {
@@ -997,16 +1058,15 @@
                     backoffs=newscr;
             }
             transpose_ts(buf,-backoffs);
-            if( fsect == -1 ) {
-                char newname[200];
-                fsect=0;
-                if( fbase ) {
-                    if( outnum>=0 )
-                        sprintf(newname,"%s_%d.VOB",fbase,outnum);
-                    else
-                        strcpy(newname,fbase);
-                    writeopen(newname);
-                }
+            if( !hadfirstvobu && buf[0]==0 && buf[1]==0 && buf[2]==1 && buf[3]==0xba )
+            {
+                int offs = (buf[17] == 0xbb) ? 24 : 0;
+                if( buf[offs+14] == 0 &&
+                    buf[offs+15] == 0 &&
+                    buf[offs+16] == 1 &&
+                    (buf[offs+17]==0xbd || (buf[offs+17]>=0xc0 && buf[offs+17]<=0xef)) &&
+                    (buf[offs+21] & 128))
+	                    tsoffs = readpts(buf+offs+23);
             }
             if( buf[14] == 0 &&
                 buf[15] == 0 &&
@@ -1051,7 +1111,7 @@
                         printvobustatus(va,cursect);
                     vsi.lastrefsect=0;
                     vsi.firstgop=1;
-                } else {
+                } else if (generate_vobu == 0 || copy_packet == 1) {
                     fprintf(stderr,"WARN: System header found, but PCI/DSI information is not where expected\n\t(make sure your system header is 18 bytes!)\n");
                 }
             }
@@ -1369,6 +1429,7 @@
         }
     }
     writeclose();
+    free(buf_copy);
     printvobustatus(va,cursect);
     fprintf(stderr,"\n");
     free(crs);

development