[MPlayer-dev-eng] [PATCH] new odml patch version 8 (was: Re: [PATCH] OpenDML AVI2.0 read support)

Tilmann Bitterberg transcode at tibit.org
Mon Mar 1 11:52:46 CET 2004


On 24.02.04, Tobias Diedrich wrote:

>Tilmann Bitterberg wrote:
>
>> +	    // find first non keyframe
>> +	    if (!((idx->dwFlags&0xffff) & AVIIF_KEYFRAME) && idx->ckid == db) break;
>[...]
>> +		    if (!((idx->dwFlags&0xffff) & AVIIF_KEYFRAME) && idx->ckid == db)
>[...]
>> -    if(!(idx->dwFlags&AVIIF_KEYFRAME)) flags=0;
>> +    if(!((idx->dwFlags&0xffff)&AVIIF_KEYFRAME)) flags=0;
>[...]
>> -    if(!(idx->dwFlags&AVIIF_KEYFRAME)) flags=0;
>> +    if(!((idx->dwFlags&0xffff)&AVIIF_KEYFRAME)) flags=0;
>
>AVIIF_KEYFRAME is defined as 0x00000010L, so masking with 0xffff is
>not necessary.
>
>Also, please apply the following patch on top of yours, it fixes some
>"Broken chunk" messages, when running mplayer -v -v.

Thanks, incorporated.

Here is a new (and probably final) version of my odml patch. The
xbmc people tested the patch and kindly provided me with
regression test files.

o respect -idx/-forceidx switches
o respect -loadidx/-saveidx switches
o deal with files where audio is 00wb and video 01db (I can
  provide a sample if wanted)
o endian clean; tested on MacOS X
o better interleaving algorithm from the odml indices into
  mplayers index

I won't do more revisions of this patch until someone
complains or it gets applied and bugs turn up.

Please apply.

Tilmann
-- 
Sometimes transcode changes or   |    http://www.transcoding.org/
adds new features while you      |      Searchable ML-archives
are encoding.                    |  http://itdp.de/transcode-users/
            -- ThOe              |         IRCnet #transcode
-------------- next part --------------
diff -Nur -X ../dontdiff orig/libmpdemux/aviheader.c main/libmpdemux/aviheader.c
--- orig/libmpdemux/aviheader.c	2003-10-22 19:01:37.000000000 +0000
+++ main/libmpdemux/aviheader.c	2004-03-01 09:53:02.977213320 +0000
@@ -26,6 +26,48 @@
 extern void print_video_header(BITMAPINFOHEADER *h);
 extern void print_index(AVIINDEXENTRY *idx,int idx_size);
 
+void print_avistdindex_chunk(avistdindex_chunk *h){
+    mp_msg (MSGT_HEADER, MSGL_V, "====== AVI Standard Index Header ========\n");
+    mp_msg (MSGT_HEADER, MSGL_V, "  FCC (%.4s) dwSize (%d) wLongsPerEntry(%d)\n", h->fcc, h->dwSize, h->wLongsPerEntry);
+    mp_msg (MSGT_HEADER, MSGL_V, "  bIndexSubType (%d) bIndexType (%d)\n", h->bIndexSubType, h->bIndexType);
+    mp_msg (MSGT_HEADER, MSGL_V, "  nEntriesInUse (%d) dwChunkId (%.4s)\n", h->nEntriesInUse, h->dwChunkId);
+    mp_msg (MSGT_HEADER, MSGL_V, "  qwBaseOffset (0x%llX) dwReserved3 (%d)\n", h->qwBaseOffset, h->dwReserved3);
+    mp_msg (MSGT_HEADER, MSGL_V, "===========================\n");
+}
+void print_avisuperindex_chunk(avisuperindex_chunk *h){
+    mp_msg (MSGT_HEADER, MSGL_V, "====== AVI Super Index Header ========\n");
+    mp_msg (MSGT_HEADER, MSGL_V, "  FCC (%.4s) dwSize (%d) wLongsPerEntry(%d)\n", h->fcc, h->dwSize, h->wLongsPerEntry);
+    mp_msg (MSGT_HEADER, MSGL_V, "  bIndexSubType (%d) bIndexType (%d)\n", h->bIndexSubType, h->bIndexType);
+    mp_msg (MSGT_HEADER, MSGL_V, "  nEntriesInUse (%d) dwChunkId (%.4s)\n", h->nEntriesInUse, h->dwChunkId);
+    mp_msg (MSGT_HEADER, MSGL_V, "  dwReserved[0] (%d) dwReserved[1] (%d) dwReserved[2] (%d)\n", 
+	    h->dwReserved[0], h->dwReserved[1], h->dwReserved[2]);
+    mp_msg (MSGT_HEADER, MSGL_V, "===========================\n");
+}
+
+int odml_get_vstream_id(int id, unsigned char res[])
+{
+    unsigned char *p = (unsigned char *)&id;
+
+#if WORDS_BIGENDIAN
+    if (p[1] == 'd') {
+	if (res) {
+	    res[0] = p[3];
+	    res[1] = p[2];
+	}
+	return 1;
+    }
+#else
+    if (p[2] == 'd') {
+	if (res) {
+	    res[0] = p[0];
+	    res[1] = p[1];
+	}
+	return 1;
+    }
+#endif
+    return 0;
+}
+
 void read_avi_header(demuxer_t *demuxer,int index_mode){
 sh_audio_t *sh_audio=NULL;
 sh_video_t *sh_video=NULL;
@@ -179,6 +221,47 @@
       last_fccType=h.fccType;
       if(verbose>=1) print_strh(&h);
       break; }
+    case mmioFOURCC('i', 'n', 'd', 'x'): {
+      DWORD i;
+      unsigned msize = 0;
+      avisuperindex_chunk *s;
+      priv->suidx_size++;
+      priv->suidx = realloc(priv->suidx, priv->suidx_size * sizeof (avisuperindex_chunk));
+      s = &priv->suidx[priv->suidx_size-1];
+
+      chunksize-=24;
+      memcpy(s->fcc, "indx", 4);
+      s->dwSize = size2;
+      s->wLongsPerEntry = stream_read_word_le(demuxer->stream);
+      s->bIndexSubType = stream_read_char(demuxer->stream);
+      s->bIndexType = stream_read_char(demuxer->stream);
+      s->nEntriesInUse = stream_read_dword_le(demuxer->stream);
+      *(uint32_t *)s->dwChunkId = stream_read_dword_le(demuxer->stream);
+      stream_read(demuxer->stream, (char *)s->dwReserved, 3*4);
+      memset(s->dwReserved, 0, 3*4);
+	  
+      print_avisuperindex_chunk(s);
+
+      msize = sizeof (uint32_t) * s->wLongsPerEntry * s->nEntriesInUse;
+      s->aIndex = malloc(msize);
+      memset (s->aIndex, 0, msize);
+      s->stdidx = malloc (s->nEntriesInUse * sizeof (avistdindex_chunk));
+      memset (s->stdidx, 0, s->nEntriesInUse * sizeof (avistdindex_chunk));
+
+      // now the real index of indices
+      for (i=0; i<s->nEntriesInUse; i++) {
+	  chunksize-=16;
+	  s->aIndex[i].qwOffset = stream_read_dword_le(demuxer->stream) & 0xffffffff;
+	  s->aIndex[i].qwOffset |= ((uint64_t)stream_read_dword_le(demuxer->stream) & 0xffffffff)<<32;
+	  s->aIndex[i].dwSize = stream_read_dword_le(demuxer->stream);
+	  s->aIndex[i].dwDuration = stream_read_dword_le(demuxer->stream);
+	  mp_msg (MSGT_HEADER, MSGL_V, "ODML (%.4s): [%d] 0x%016llx 0x%04lx %ld\n", 
+		  (s->dwChunkId), i,
+		  (uint64_t)s->aIndex[i].qwOffset, s->aIndex[i].dwSize, s->aIndex[i].dwDuration);
+      }
+      priv->isodml++;
+
+      break; }
     case ckidSTREAMFORMAT: {      // read 'strf'
       if(last_fccType==streamtypeVIDEO){
         sh_video->bih=calloc((chunksize<sizeof(BITMAPINFOHEADER))?sizeof(BITMAPINFOHEADER):chunksize,1);
@@ -246,10 +329,18 @@
       }
       break;
     }
+    case mmioFOURCC('d', 'm', 'l', 'h'): {
+	// dmlh 00 00 00 04 frms
+	unsigned int total_frames = stream_read_dword_le(demuxer->stream);
+	mp_msg(MSGT_HEADER,MSGL_V,"AVI: dmlh found (size=%d) (total_frames=%d)\n", chunksize, total_frames);
+	stream_skip(demuxer->stream, chunksize-4);
+	chunksize = 0;
+    }
+    break;
     case ckidAVINEWINDEX:
     if(demuxer->movi_end>stream_tell(demuxer->stream))
 	demuxer->movi_end=stream_tell(demuxer->stream); // fixup movi-end
-    if(index_mode){
+    if(index_mode && !priv->isodml){
       int i;
       priv->idx_size=size2>>4;
       mp_msg(MSGT_HEADER,MSGL_V,"Reading INDEX block, %d chunks for %ld frames (fpos=%p)\n",
@@ -261,8 +352,8 @@
 	le2me_AVIINDEXENTRY((AVIINDEXENTRY*)priv->idx + i);
       chunksize-=priv->idx_size<<4;
       if(verbose>=2) print_index(priv->idx,priv->idx_size);
-      break;
     }
+    break;
     /* added May 2002 */
     case mmioFOURCC('R','I','F','F'): {
 	char riff_type[4];
@@ -275,6 +366,29 @@
 	chunksize = 0;
 	list_end = 0; /* a new list will follow */
 	break; }
+    case mmioFOURCC('A', 'T', 'T', 'R'): {
+	unsigned int nrinfo;
+	char *data=malloc(chunksize), *c;
+	nrinfo = stream_read_dword_le(demuxer->stream);
+	mp_msg(MSGT_HEADER, MSGL_V, "[BTV] Beyond TV metainfo found with %d entries\n", nrinfo);
+	memset (data, '\0', chunksize);
+	stream_read (demuxer->stream, data, chunksize-4);
+	c = data;
+	while (nrinfo--) {
+	    mp_msg(MSGT_HEADER, MSGL_V, "[BTV] %s: ", c);
+	    c += strlen(c)+1;
+	    if (strchr(c, '\n')) *strchr(c, '\n') = ' ';
+	    if (!*c) mp_msg(MSGT_HEADER, MSGL_V, "not set\n");
+	    else mp_msg(MSGT_HEADER, MSGL_V, "%s\n", c);
+	    c += strlen(c)+1;
+	}
+	chunksize = 0;
+	}
+       break;
+    case ckidAVIPADDING:
+	stream_skip(demuxer->stream, chunksize);
+	chunksize = 0;
+	break;
   }
   if(hdr){
     mp_msg(MSGT_HEADER,MSGL_V,"hdr=%s  size=%u\n",hdr,size2);
@@ -293,6 +407,8 @@
   mp_msg(MSGT_HEADER,MSGL_DBG2,"list_end=0x%X  pos=0x%X  chunksize=0x%X  next=0x%X\n",
       (int)list_end, (int)stream_tell(demuxer->stream),
       chunksize, (int)chunksize+stream_tell(demuxer->stream));
+  if(list_end>0 &&
+     chunksize+stream_tell(demuxer->stream) == list_end) list_end=0;
   if(list_end>0 && chunksize+stream_tell(demuxer->stream)>list_end){
       mp_msg(MSGT_HEADER,MSGL_V,"Broken chunk?  chunksize=%d  (id=%.4s)\n",chunksize,(char *) &id);
       stream_seek(demuxer->stream,list_end);
@@ -303,6 +419,242 @@
   
 }
 
+if (priv->isodml && (index_mode==-1 || index_mode==0)) {
+    int i, j, k;
+    int safety=1000;
+    int nroffsets;
+
+    avisuperindex_chunk *cx;
+    AVIINDEXENTRY *idx;
+
+
+    if (priv->idx_size) free(priv->idx);
+    priv->offsets_size=0;
+    priv->idx_size = 0;
+    priv->idx_offset = 0;
+    priv->idx = NULL;
+
+    mp_msg(MSGT_HEADER, MSGL_INFO, 
+	    "AVI: ODML: Building odml index (%d superindexchunks)\n", priv->suidx_size);
+
+    //  count number of stdindex entries in all superindices
+    nroffsets=0; cx = &priv->suidx[0];
+    do nroffsets+=cx->nEntriesInUse;
+    while (cx++ != &priv->suidx[priv->suidx_size-1]);
+
+    priv->offsets = malloc(sizeof(uint64_t) * (nroffsets+1));
+
+    // read the standard indices
+    for (cx = &priv->suidx[0], i=0; i<priv->suidx_size; cx++, i++) {
+	stream_reset(demuxer->stream);
+	for (j=0; j<cx->nEntriesInUse; j++) {
+	    int ret1, ret2;
+	    memset(&cx->stdidx[j], 0, 32);
+	    ret1 = stream_seek(demuxer->stream, (off_t)cx->aIndex[j].qwOffset);
+	    ret2 = stream_read(demuxer->stream, (char *)&cx->stdidx[j], 32);
+	    if (ret1 != 1 || ret2 != 32 || cx->stdidx[j].nEntriesInUse==0) {
+		// this is a broken file (probably incomplete) let the standard
+		// gen_index routine handle this
+		priv->isodml = 0;
+		priv->idx_size = 0;
+		memset(priv->offsets, 0, (nroffsets+1)*sizeof(uint64_t));
+		priv->offsets_size = 0;
+		mp_msg(MSGT_HEADER, MSGL_WARN,
+			"AVI: ODML: Broken (incomplete?) file detected. Will use traditional index\n");
+		goto freeout;
+	    }
+
+	    le2me_AVISTDIDXCHUNK(&cx->stdidx[j]);
+	    print_avistdindex_chunk(&cx->stdidx[j]);
+	    priv->idx_size += cx->stdidx[j].nEntriesInUse;
+	    priv->offsets[priv->offsets_size] = (off_t)(cx->stdidx[j].qwBaseOffset - 8);
+	    priv->offsets_size++;
+	    cx->stdidx[j].aIndex = malloc(cx->stdidx[j].nEntriesInUse*sizeof(avistdindex_entry));
+	    stream_read(demuxer->stream, (char *)cx->stdidx[j].aIndex, 
+		    cx->stdidx[j].nEntriesInUse*sizeof(avistdindex_entry));
+	    for (k=0;k<cx->stdidx[j].nEntriesInUse; k++)
+		le2me_AVISTDIDXENTRY(&cx->stdidx[j].aIndex[k]);
+
+	    cx->stdidx[j].dwReserved3 = 0;
+
+	}
+    }
+
+    // put the number of frames per superindex into dwReserved[0]
+    cx = &priv->suidx[0];
+    do for (j=0;j<cx->nEntriesInUse;j++)
+	    cx->dwReserved[0] += cx->stdidx[j].nEntriesInUse;
+    while (cx++ != &priv->suidx[priv->suidx_size-1]);
+
+    /* 
+       priv->
+       suidx[0] ----- stdidx[0] ----- aIndex[0]
+               \                `---- aIndex[1]
+                `---- stdidx[1] --...
+       suidx[1] ---...
+
+       This code is not nice but has to done. It copies the stdindex entries
+       into the standard index structure mplayer wants. It has to interleave
+       them while doing this. The algorithm does so by looking at how many
+       packets from one stream already went into the index and choosing the
+       stream which has the least percent of packets in the idx1.
+                                     --tibit
+
+       We "recycle" the dwReserved variables as counters
+       cx->dwReserved[0] = number of total frames per superindex
+       cx->dwReserved[2] = number of used frames per superindex
+       cx->stdidx[n].dwReserved3 = number of used frames in this stdindex
+     */
+
+
+    priv->idx = malloc(priv->idx_size * sizeof (AVIINDEXENTRY));
+    idx = &((AVIINDEXENTRY *)priv->idx)[0];
+
+    cx = &priv->suidx[0];
+
+    safety = 1000;
+
+    // Interleave. Could be done smarter I guess
+    for (i=0; i<priv->idx_size; i++) {
+	avistdindex_entry *e;
+	int widx;
+	int id=0;
+
+	j = 1;
+	widx=cx->stdidx[0].nEntriesInUse;
+	while (cx->dwReserved[2] >= widx) {
+	    if (j==cx->nEntriesInUse) { i--; safety--; goto tryagain; }
+	    widx += cx->stdidx[j].nEntriesInUse;
+	    j++;
+	}
+	j--;
+
+	e = &cx->stdidx[j].aIndex[cx->stdidx[j].dwReserved3];
+	memcpy(&idx->ckid, cx->stdidx[j].dwChunkId, 4);
+	id = idx->ckid;
+	idx->dwChunkOffset = e->dwOffset;
+	idx->dwFlags = idx->dwChunkLength = e->dwSize;
+	idx->dwChunkLength &= 0x7fffffff;
+	idx->dwFlags = (idx->dwFlags&0x80000000)?0x0:AVIIF_KEYFRAME; // first bit denotes !keyframe
+	k = 0;
+	while (priv->offsets[k]+8 != cx->stdidx[j].qwBaseOffset) {
+	    k++;
+	    if (k==priv->offsets_size)
+		    mp_msg(MSGT_HEADER,MSGL_ERR, 
+			    "AVI: ODML: Internal error. Can't find offset in array\n");
+	}
+	// We now put the index chunk where this is in into the upper 16 bits
+	idx->dwFlags |= (k<<16)&0xffff0000;
+
+	cx->dwReserved[2]++;
+	cx->stdidx[j].dwReserved3++;
+
+	// completely empty chunk, whats the purpose of that? Just delete it.
+	if (idx->dwChunkOffset==0 && idx->dwChunkLength==0) {
+	    mp_msg(MSGT_HEADER, MSGL_V,
+		    "AVI: ODML: Skipping emtpy chunk nr %d fcc %.4s\n", i, (char *)&idx->ckid);
+	    idx--;
+	    priv->idx_size--;
+	    i--;
+	}
+	idx++;
+	safety = 1000;
+tryagain:
+	{
+	    avisuperindex_chunk *mincx;
+	    float percent, old_percent=1000.0;
+	    float audio_bonus = 0.0;
+
+	    // the audio_bonus ensures that audio chunks gets added
+	    // into idx prior to video chunks. mplayer likes this better.
+	    if (id && odml_get_vstream_id(id, NULL)==0)
+		audio_bonus = 5.0;
+
+	    // find the cx with the least percentage written
+	    cx = &priv->suidx[0];
+	    do {
+		percent = (cx->dwReserved[2]+audio_bonus)*1000.0/cx->dwReserved[0];
+		if (percent < old_percent) {
+		    old_percent = percent;
+		    mincx = cx;
+		}
+
+	    } while (cx++ != &priv->suidx[priv->suidx_size-1]);
+
+	    cx = mincx;
+	    if (safety <= 0) { 
+		mp_msg(MSGT_HEADER, MSGL_ERR,
+		    "AVI: ODML: Internal error. Endless loop. Please bugreport\n");
+		mp_msg(MSGT_HEADER, MSGL_ERR, 
+			"cx->id = %.4s perc=%f %d / %d\n", cx->dwChunkId, percent,
+			cx->dwReserved[2], cx->dwReserved[0]);
+		sleep(10);
+		return;
+	    }
+	}
+    }
+
+    /* 
+       Hack to work around a "wrong" index in some divx odml files
+       (processor_burning.avi as an example)
+       They have ##dc on non keyframes but the ix00 tells us they are ##db.
+       Read the fcc of a non-keyframe vid frame and check it.
+     */
+
+    {
+	uint32_t id;
+	uint32_t db = 0;
+	stream_reset (demuxer->stream);
+
+	// find out the video stream id. I have seen files with 01db.
+	for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++){
+	    unsigned char res[2];
+	    if (odml_get_vstream_id(idx->ckid, res)) {
+		db = mmioFOURCC(res[0], res[1], 'd', 'b');
+		break;
+	    }
+	}
+
+	// find first non keyframe
+	for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++){
+	    if (!(idx->dwFlags & AVIIF_KEYFRAME) && idx->ckid == db) break;
+	}
+	if (i<priv->idx_size && db) {
+	    stream_seek(demuxer->stream, idx->dwChunkOffset+priv->offsets[idx->dwFlags>>16&0xffff]);
+	    id = stream_read_dword_le(demuxer->stream);
+	    if (id && id != db) // index fcc and real fcc differ? fix it.
+		for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++){
+		    if (!(idx->dwFlags & AVIIF_KEYFRAME) && idx->ckid == db)
+			idx->ckid = id;
+	    }
+	}
+    }
+
+    if (verbose>=2) // dump the constructed index
+	for (idx = &((AVIINDEXENTRY *)priv->idx)[0], i=0; i<priv->idx_size; i++, idx++)
+	    // chunknr fcc offset length flags base_offset
+	    mp_msg(MSGT_HEADER, MSGL_DBG2, 
+		"ODML %6d: %.4s %08x %08x %02x %016llx\n", i, (char *)&idx->ckid, 
+		idx->dwChunkOffset, idx->dwChunkLength, idx->dwFlags&0xffff, 
+		priv->offsets[(idx->dwFlags>>16)&0xffff]);
+
+
+    demuxer->movi_end=demuxer->stream->end_pos;
+
+freeout:
+
+    // free unneeded stuff
+    cx = &priv->suidx[0];
+    do {
+	for (j=0;j<cx->nEntriesInUse;j++)
+	    if (cx->stdidx[j].nEntriesInUse) free(cx->stdidx[j].aIndex);
+	free(cx->stdidx);
+
+    } while (cx++ != &priv->suidx[priv->suidx_size-1]);
+    free(priv->suidx);
+
+}
+
 /* Read a saved index file */
 if (index_file_load) {
   FILE *fp;
diff -Nur -X ../dontdiff orig/libmpdemux/aviheader.h main/libmpdemux/aviheader.h
--- orig/libmpdemux/aviheader.h	2002-11-16 03:42:14.000000000 +0000
+++ main/libmpdemux/aviheader.h	2004-03-01 08:15:19.680569896 +0000
@@ -4,6 +4,48 @@
 //#include "config.h"	/* get correct definition WORDS_BIGENDIAN */
 #include "bswap.h"
 
+typedef struct _avisuperindex_entry {
+    uint64_t qwOffset;           // absolute file offset
+    uint32_t dwSize;             // size of index chunk at this offset
+    uint32_t dwDuration;         // time span in stream ticks
+} avisuperindex_entry;
+
+typedef struct _avistdindex_entry {
+    uint32_t dwOffset;           // qwBaseOffset + this is absolute file offset
+    uint32_t dwSize;             // bit 31 is set if this is NOT a keyframe
+} avistdindex_entry;
+
+// Standard index 
+typedef struct _avistdindex_chunk {
+    char           fcc[4];       // ix##
+    uint32_t  dwSize;            // size of this chunk
+    uint16_t wLongsPerEntry;     // must be sizeof(aIndex[0])/sizeof(DWORD)
+    uint8_t  bIndexSubType;      // must be 0
+    uint8_t  bIndexType;         // must be AVI_INDEX_OF_CHUNKS
+    uint32_t  nEntriesInUse;     // first unused entry
+    char           dwChunkId[4]; // '##dc' or '##db' or '##wb' etc..
+    uint64_t qwBaseOffset;       // all dwOffsets in aIndex array are relative to this
+    uint32_t  dwReserved3;       // must be 0
+    avistdindex_entry *aIndex;   // the actual frames
+} avistdindex_chunk;
+    
+
+// Base Index Form 'indx'
+typedef struct _avisuperindex_chunk {
+    char           fcc[4];
+    uint32_t  dwSize;                // size of this chunk
+    uint16_t wLongsPerEntry;         // size of each entry in aIndex array (must be 4*4 for us)
+    uint8_t  bIndexSubType;          // future use. must be 0
+    uint8_t  bIndexType;             // one of AVI_INDEX_* codes
+    uint32_t  nEntriesInUse;         // index of first unused member in aIndex array
+    char       dwChunkId[4];         // fcc of what is indexed
+    uint32_t  dwReserved[3];         // meaning differs for each index type/subtype.
+                                     // 0 if unused
+    avisuperindex_entry *aIndex;     // position of ix## chunks
+    avistdindex_chunk *stdidx;       // the actual std indices
+} avisuperindex_chunk;
+
+
 /*
  * Some macros to swap little endian structures read from an AVI file
  * into machine endian format
@@ -72,6 +114,23 @@
     (h)->dwChunkOffset = le2me_32((h)->dwChunkOffset);			\
     (h)->dwChunkLength = le2me_32((h)->dwChunkLength);			\
 }
+#define le2me_AVISTDIDXCHUNK(h) {\
+    char c; \
+    c = (h)->fcc[0]; (h)->fcc[0] = (h)->fcc[3]; (h)->fcc[3] = c;  \
+    c = (h)->fcc[1]; (h)->fcc[1] = (h)->fcc[2]; (h)->fcc[2] = c;  \
+    (h)->dwSize = le2me_32((h)->dwSize);  \
+    (h)->wLongsPerEntry = le2me_16((h)->wLongsPerEntry);  \
+    (h)->nEntriesInUse = le2me_32((h)->nEntriesInUse);  \
+    c = (h)->dwChunkId[0]; (h)->dwChunkId[0] = (h)->dwChunkId[3]; (h)->dwChunkId[3] = c;  \
+    c = (h)->dwChunkId[1]; (h)->dwChunkId[1] = (h)->dwChunkId[2]; (h)->dwChunkId[2] = c;  \
+    (h)->qwBaseOffset = le2me_64((h)->qwBaseOffset);  \
+    (h)->dwReserved3 = le2me_32((h)->dwReserved3);  \
+}
+#define le2me_AVISTDIDXENTRY(h)  {\
+    (h)->dwOffset = le2me_32((h)->dwOffset);  \
+    (h)->dwSize = le2me_32((h)->dwSize);  \
+}
+
 #else
 #define	le2me_MainAVIHeader(h)	    /**/
 #define le2me_AVIStreamHeader(h)    /**/
@@ -79,6 +138,8 @@
 #define le2me_BITMAPINFOHEADER(h)   /**/
 #define le2me_WAVEFORMATEX(h)	    /**/
 #define le2me_AVIINDEXENTRY(h)	    /**/
+#define le2me_AVISTDIDXCHUNK(h)     /**/
+#define le2me_AVISTDIDXENTRY(h)     /**/
 #endif
 
 
@@ -107,6 +168,11 @@
   unsigned char pts_corrected;
   unsigned char pts_has_video;
   unsigned int numberofframes;
+  avisuperindex_chunk *suidx;
+  int suidx_size;
+  uint64_t *offsets;
+  int offsets_size;
+  int isodml;
 } avi_priv_t;
 
 #define AVI_PRIV ((avi_priv_t*)(demuxer->priv))
diff -Nur -X ../dontdiff orig/libmpdemux/demux_avi.c main/libmpdemux/demux_avi.c
--- orig/libmpdemux/demux_avi.c	2004-02-24 17:39:19.000000000 +0000
+++ main/libmpdemux/demux_avi.c	2004-03-01 08:15:19.681569744 +0000
@@ -170,6 +170,13 @@
   return ds?1:0;
 }
 
+
+inline static off_t demux_avi_dml_offset(demuxer_t *demux, AVIINDEXENTRY *idx)
+{
+    avi_priv_t *priv = demux->priv;
+    return (off_t)(priv->offsets?priv->offsets[(idx->dwFlags>>16)&0xffff]:0);
+}
+
 // return value:
 //     0 = EOF or no stream found
 //     1 = successfully read a packet
@@ -213,7 +220,7 @@
       continue; // skip this chunk
     }
 
-    pos = priv->idx_offset + (unsigned long)idx->dwChunkOffset;
+    pos = (off_t)priv->idx_offset + (off_t)idx->dwChunkOffset + demux_avi_dml_offset(demux, idx);
     if((pos<demux->movi_start || pos>=demux->movi_end) && (demux->movi_end>demux->movi_start) && (demux->stream->flags & STREAM_SEEK)){
       mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range!   idx=0x%X  \n",pos);
       continue;
@@ -446,6 +453,12 @@
   priv->video_pack_no=0;
   priv->audio_block_no=0;
   priv->audio_block_size=0;
+  priv->isodml = 0;
+  priv->offsets_size = 0;
+  priv->offsets = NULL;
+  priv->suidx_size = 0;
+  priv->suidx = NULL;
+
   demuxer->priv=(void*)priv;
 
   //---- AVI header:
@@ -468,8 +481,8 @@
   if(priv->idx_size>1){
     // decide index format:
 #if 1
-    if((unsigned long)((AVIINDEXENTRY *)priv->idx)[0].dwChunkOffset<demuxer->movi_start ||
-       (unsigned long)((AVIINDEXENTRY *)priv->idx)[1].dwChunkOffset<demuxer->movi_start)
+    if(((unsigned long)((AVIINDEXENTRY *)priv->idx)[0].dwChunkOffset<demuxer->movi_start ||
+        (unsigned long)((AVIINDEXENTRY *)priv->idx)[1].dwChunkOffset<demuxer->movi_start )&& !priv->isodml)
       priv->idx_offset=demuxer->movi_start-4;
     else
       priv->idx_offset=0;


More information about the MPlayer-dev-eng mailing list