File:dvdauthor-0.6.14-ivtv-patch.txt
From IVTV
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?
- Download and extract the source tarball for dvdauthor version 0.6.14;
- Copy the content of the section below to a local file called dvdauthor-0.6.14-ivtv-patch-0.2.txt;
- Go to the dvdauthor-0.6.14 directory and do patch -p0 < dvdauthor-0.6.14-ivtv-patch-0.2.txt;
- 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);
