[MPlayer-dev-eng] [PATCH] let -idx generate usable index for >4GB AVI files

Wolfram Gloger wmglo at dent.med.uni-muenchen.de
Thu May 1 00:52:36 CEST 2003


About a year ago I added support for files >2GB to demux_avi.c.  Now I
have generated a .avi file >4GB with mencoder and found that mplayer
-idx cannot create a meaningful index for it (to be expected of
course).

The patch below lets mplayer/mencoder create a usable index for .avi
files >4GB, such that seeking works in such files.  Due to the use of
a private AVIextINDEXENTRY struct it also gets rid of a lot of casts
and hence makes the code a bit cleaner IMHO.  I haven't yet adapted
print_index() to the new structure (any index read from the file is
printed just like before) but could of course do so.

Regards,
Wolfram.

--- libmpdemux/aviheader.h.orig	Sat Nov 16 04:42:14 2002
+++ libmpdemux/aviheader.h	Tue Apr 29 18:25:31 2003
@@ -84,10 +84,25 @@
 
 #endif
 
+/* extended index entry, for files >4GB */
+typedef struct
+{
+    DWORD		ckid;
+    DWORD		dwFlags;
+    off_t		ChunkOffset; // Position of chunk
+    off_t		ChunkLength; // Length of chunk
+} AVIextINDEXENTRY;
+
+#define extend_AVIINDEXENTRY(h, exth) do { \
+    (exth)->ckid = (h)->ckid; \
+    (exth)->dwFlags = (h)->dwFlags; \
+    (exth)->ChunkOffset = (h)->dwChunkOffset; \
+    (exth)->ChunkLength = (h)->dwChunkLength; \
+} while (0)
 
 typedef struct {
   // index stuff:
-  void* idx;
+  AVIextINDEXENTRY* idx;
   int idx_size;
   off_t idx_pos;
   off_t idx_pos_a;
--- libmpdemux/aviheader.c.orig	Fri Nov  1 18:46:43 2002
+++ libmpdemux/aviheader.c	Tue Apr 29 18:30:59 2003
@@ -247,16 +247,23 @@
 	demuxer->movi_end=stream_tell(demuxer->stream); // fixup movi-end
     if(index_mode){
       int i;
+      AVIINDEXENTRY* idx_vec;
+
       priv->idx_size=size2>>4;
       mp_msg(MSGT_HEADER,MSGL_V,"Reading INDEX block, %d chunks for %ld frames (fpos=%p)\n",
         priv->idx_size,avih.dwTotalFrames, stream_tell(demuxer->stream));
-      priv->idx=malloc(priv->idx_size<<4);
-//      printf("\nindex to %p !!!!! (priv=%p)\n",priv->idx,priv);
-      stream_read(demuxer->stream,(char*)priv->idx,priv->idx_size<<4);
+      idx_vec=malloc(priv->idx_size<<4);
+//      printf("\nindex to %p !!!!! (priv=%p)\n",idx_vec,priv);
+      stream_read(demuxer->stream,(char*)idx_vec,priv->idx_size<<4);
       for (i = 0; i < priv->idx_size; i++)	// swap index to machine endian
-	le2me_AVIINDEXENTRY((AVIINDEXENTRY*)priv->idx + i);
+	le2me_AVIINDEXENTRY(idx_vec + i);
       chunksize-=priv->idx_size<<4;
-      if(verbose>=2) print_index(priv->idx,priv->idx_size);
+      if(verbose>=2) print_index(idx_vec, priv->idx_size);
+      priv->idx = malloc(priv->idx_size * sizeof(*priv->idx));
+      for (i=0; i<priv->idx_size; ++i) {
+	  extend_AVIINDEXENTRY(idx_vec + i, priv->idx + i);
+      }
+      free(idx_vec);
       break;
     }
     /* added May 2002 */
@@ -312,7 +319,7 @@
     int id;
     unsigned len;
     off_t skip;
-    AVIINDEXENTRY* idx;
+    AVIextINDEXENTRY* idx;
     unsigned int c;
     demuxer->filepos=stream_tell(demuxer->stream);
     if(demuxer->filepos>=demuxer->movi_end && demuxer->movi_start<demuxer->movi_end) break;
@@ -328,14 +335,14 @@
     if(priv->idx_pos>=priv->idx_size){
 //      priv->idx_size+=32;
       priv->idx_size+=1024; // +16kB
-      priv->idx=realloc(priv->idx,priv->idx_size*sizeof(AVIINDEXENTRY));
+      priv->idx=realloc(priv->idx,priv->idx_size*sizeof(*priv->idx));
       if(!priv->idx){priv->idx_pos=0; break;} // error!
     }
-    idx=&((AVIINDEXENTRY *)priv->idx)[priv->idx_pos++];
+    idx=&(priv->idx)[priv->idx_pos++];
     idx->ckid=id;
     idx->dwFlags=AVIIF_KEYFRAME; // FIXME
-    idx->dwChunkOffset=(unsigned long)demuxer->filepos;
-    idx->dwChunkLength=len;
+    idx->ChunkOffset=demuxer->filepos;
+    idx->ChunkLength=len;
     
     c=stream_read_dword(demuxer->stream);
 
@@ -380,11 +387,9 @@
   }
   priv->idx_size=priv->idx_pos;
   mp_msg(MSGT_HEADER,MSGL_INFO,"AVI: Generated index table for %d chunks!\n",priv->idx_size);
-  if(verbose>=2) print_index(priv->idx,priv->idx_size);
+  //if(verbose>=2) print_index(priv->idx,priv->idx_size);
 }
 
 }
 
 #undef MIN
-
-
--- libmpdemux/demux_avi.c.orig	Sun Feb  2 22:32:05 2003
+++ libmpdemux/demux_avi.c	Tue Apr 29 18:35:18 2003
@@ -183,7 +183,7 @@
 
 do{
   int flags=1;
-  AVIINDEXENTRY *idx=NULL;
+  AVIextINDEXENTRY *idx=NULL;
 #if 0
   demux->filepos=stream_tell(demux->stream);
   if(demux->filepos>=demux->movi_end){
@@ -197,13 +197,13 @@
     
     //if(priv->idx_pos<0) printf("Fatal! idx_pos=%d\n",priv->idx_pos);
     
-    idx=&((AVIINDEXENTRY *)priv->idx)[priv->idx_pos++];
+    idx=&(priv->idx)[priv->idx_pos++];
     
     //printf("[%d]",priv->idx_pos);fflush(stdout);
     
-    //stream_seek(demux->stream,idx.dwChunkOffset);
+    //stream_seek(demux->stream,idx.ChunkOffset);
     //printf("IDX  pos=%X  idx.pos=%X  idx.size=%X  idx.flags=%X\n",demux->filepos,
-    //  pos-4,idx->dwChunkLength,idx->dwFlags);
+    //  pos-4,idx->ChunkLength,idx->dwFlags);
     if(idx->dwFlags&AVIIF_LIST){
       // LIST
       continue;
@@ -213,7 +213,7 @@
       continue; // skip this chunk
     }
 
-    pos = priv->idx_offset + (unsigned long)idx->dwChunkOffset;
+    pos = priv->idx_offset + idx->ChunkOffset;
     if((pos<demux->movi_start || pos>=demux->movi_end) && (demux->movi_end>demux->movi_start) && (demux->stream->type!=STREAMTYPE_STREAM)){
       mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range!   idx=0x%X  \n",pos);
       continue;
@@ -236,12 +236,12 @@
           if(!valid_fourcc(id)) continue; // drop chunk if both id and idx bad
     }
     len=stream_read_dword_le(demux->stream);
-//    if((len&(~1))!=(idx->dwChunkLength&(~1))){
-//    if((len)!=(idx->dwChunkLength)){
-    if((len!=idx->dwChunkLength)&&((len+1)!=idx->dwChunkLength)){
-      mp_msg(MSGT_DEMUX,MSGL_V,"ChunkSize mismatch! raw=%d idx=%ld  \n",len,idx->dwChunkLength);
-      if(len>0x200000 && idx->dwChunkLength>0x200000) continue; // both values bad :(
-      len=choose_chunk_len(idx->dwChunkLength,len);
+//    if((len&(~1))!=(idx->ChunkLength&(~1))){
+//    if((len)!=(idx->ChunkLength)){
+    if((len!=idx->ChunkLength)&&((len+1)!=idx->ChunkLength)){
+      mp_msg(MSGT_DEMUX,MSGL_V,"ChunkSize mismatch! raw=%d idx=%ld  \n",len,(long)idx->ChunkLength);
+      if(len>0x200000 && idx->ChunkLength>0x200000) continue; // both values bad :(
+      len=choose_chunk_len(idx->ChunkLength,len);
     }
     if(!(idx->dwFlags&AVIIF_KEYFRAME)) flags=0;
   } else {
@@ -303,7 +303,7 @@
 
 do{
   int flags=1;
-  AVIINDEXENTRY *idx=NULL;
+  AVIextINDEXENTRY *idx=NULL;
   int idx_pos=0;
   demux->filepos=stream_tell(demux->stream);
   
@@ -313,7 +313,7 @@
   
   if(priv->idx_size>0 && idx_pos<priv->idx_size){
     off_t pos;
-    idx=&((AVIINDEXENTRY *)priv->idx)[idx_pos];
+    idx=&(priv->idx)[idx_pos];
 //    idx=&priv->idx[idx_pos];
     
     if(idx->dwFlags&AVIIF_LIST){
@@ -325,7 +325,7 @@
       continue; // skip this chunk
     }
 
-    pos = priv->idx_offset+(unsigned long)idx->dwChunkOffset;
+    pos = priv->idx_offset+idx->ChunkOffset;
     if((pos<demux->movi_start || pos>=demux->movi_end) && (demux->movi_end>demux->movi_start)){
       mp_msg(MSGT_DEMUX,MSGL_V,"ChunkOffset out of range!  current=0x%X  idx=0x%X  \n",demux->filepos,pos);
       continue;
@@ -349,10 +349,10 @@
           if(!valid_fourcc(id)) continue; // drop chunk if both id and idx bad
     }
     len=stream_read_dword_le(demux->stream);
-    if((len!=idx->dwChunkLength)&&((len+1)!=idx->dwChunkLength)){
-      mp_msg(MSGT_DEMUX,MSGL_V,"ChunkSize mismatch! raw=%d idx=%ld  \n",len,idx->dwChunkLength);
-      if(len>0x200000 && idx->dwChunkLength>0x200000) continue; // both values bad :(
-      len=choose_chunk_len(idx->dwChunkLength,len);
+    if((len!=idx->ChunkLength)&&((len+1)!=idx->ChunkLength)){
+      mp_msg(MSGT_DEMUX,MSGL_V,"ChunkSize mismatch! raw=%d idx=%ld  \n",len,(long)idx->ChunkLength);
+      if(len>0x200000 && idx->ChunkLength>0x200000) continue; // both values bad :(
+      len=choose_chunk_len(idx->ChunkLength,len);
     }
     if(!(idx->dwFlags&AVIIF_KEYFRAME)) flags=0;
   } else return 0;
@@ -467,21 +467,21 @@
   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((priv->idx)[0].ChunkOffset<demuxer->movi_start ||
+       (priv->idx)[1].ChunkOffset<demuxer->movi_start)
       priv->idx_offset=demuxer->movi_start-4;
     else
       priv->idx_offset=0;
 #else
-    if((unsigned long)((AVIINDEXENTRY *)priv->idx)[0].dwChunkOffset<demuxer->movi_start)
+    if((priv->idx)[0].ChunkOffset<demuxer->movi_start)
       priv->idx_offset=demuxer->movi_start-4;
     else
       priv->idx_offset=0;
 #endif
     mp_msg(MSGT_DEMUX,MSGL_V,"AVI index offset: 0x%X (movi=0x%X idx0=0x%X idx1=0x%X)\n",
 	    (int)priv->idx_offset,(int)demuxer->movi_start,
-	    (int)((AVIINDEXENTRY *)priv->idx)[0].dwChunkOffset,
-	    (int)((AVIINDEXENTRY *)priv->idx)[1].dwChunkOffset);
+	    (int)(priv->idx)[0].ChunkOffset,
+	    (int)(priv->idx)[1].ChunkOffset);
   }
 //  demuxer->endpos=avi_header.movi_end;
   
@@ -491,9 +491,9 @@
       off_t a_pos=-1;
       off_t v_pos=-1;
       for(i=0;i<priv->idx_size;i++){
-        AVIINDEXENTRY* idx=&((AVIINDEXENTRY *)priv->idx)[i];
+        AVIextINDEXENTRY* idx=&(priv->idx)[i];
         demux_stream_t* ds=demux_avi_select_stream(demuxer,idx->ckid);
-        off_t pos = priv->idx_offset + (unsigned long)idx->dwChunkOffset;
+        off_t pos = priv->idx_offset + idx->ChunkOffset;
         if(a_pos==-1 && ds==demuxer->audio){
           a_pos=pos;
           if(v_pos!=-1) break;
@@ -556,8 +556,8 @@
     size_t asamples=0;
     int i;
     for(i=0;i<priv->idx_size;i++){ 
-      int id=avi_stream_id(((AVIINDEXENTRY *)priv->idx)[i].ckid);
-      int len=((AVIINDEXENTRY *)priv->idx)[i].dwChunkLength;
+      int id=avi_stream_id((priv->idx)[i].ckid);
+      off_t len=(priv->idx)[i].ChunkLength;
       if(sh_video->ds->id == id) {
         vsize+=len;
         ++vsamples;
@@ -622,11 +622,10 @@
     sh_video_t *sh_video=d_video->sh;
     float skip_audio_secs=0;
 
-  //FIXME: OFF_T - Didn't check AVI case yet (avi files can't be >2G anyway?)
   //================= seek in AVI ==========================
     int rel_seek_frames=rel_seek_secs*sh_video->fps;
-    int video_chunk_pos=d_video->pos;
-    int i;
+    off_t video_chunk_pos=d_video->pos;
+    off_t i;
 
       if(flags&1){
 	// seek absolute
@@ -645,18 +644,18 @@
       if(rel_seek_frames>0){
         // seek forward
         while(video_chunk_pos<priv->idx_size-1){
-          int id=((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].ckid;
+          int id=(priv->idx)[video_chunk_pos].ckid;
           if(avi_stream_id(id)==d_video->id){  // video frame
-            if((--rel_seek_frames)<0 && ((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break;
+            if((--rel_seek_frames)<0 && (priv->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break;
           }
           ++video_chunk_pos;
         }
       } else {
         // seek backward
         while(video_chunk_pos>0){
-          int id=((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].ckid;
+          int id=(priv->idx)[video_chunk_pos].ckid;
           if(avi_stream_id(id)==d_video->id){  // video frame
-            if((++rel_seek_frames)>0 && ((AVIINDEXENTRY *)priv->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break;
+            if((++rel_seek_frames)>0 && (priv->idx)[video_chunk_pos].dwFlags&AVIIF_KEYFRAME) break;
           }
           --video_chunk_pos;
         }
@@ -666,7 +665,7 @@
       // re-calc video pts:
       d_video->pack_no=0;
       for(i=0;i<video_chunk_pos;i++){
-          int id=((AVIINDEXENTRY *)priv->idx)[i].ckid;
+          int id=(priv->idx)[i].ckid;
           if(avi_stream_id(id)==d_video->id) ++d_video->pack_no;
       }
       priv->video_pack_no=
@@ -684,12 +683,12 @@
       d_audio->dpos=0;
 
       if(sh_audio){
-        int i;
-        int len=0;
-	int skip_audio_bytes=0;
-	int curr_audio_pos=-1;
-	int audio_chunk_pos=-1;
-	int chunk_max=(demuxer->type==DEMUXER_TYPE_AVI)?video_chunk_pos:priv->idx_size;
+        off_t i;
+        off_t len=0;
+	off_t skip_audio_bytes=0;
+	off_t curr_audio_pos=-1;
+	off_t audio_chunk_pos=-1;
+	off_t chunk_max=(demuxer->type==DEMUXER_TYPE_AVI)?video_chunk_pos:priv->idx_size;
 	
 	if(sh_audio->audio.dwSampleSize){
 	    // constant rate audio stream
@@ -709,9 +708,9 @@
 
         // find audio chunk pos:
           for(i=0;i<chunk_max;i++){
-            int id=((AVIINDEXENTRY *)priv->idx)[i].ckid;
+            int id=(priv->idx)[i].ckid;
             if(avi_stream_id(id)==d_audio->id){
-                len=((AVIINDEXENTRY *)priv->idx)[i].dwChunkLength;
+                len=(priv->idx)[i].ChunkLength;
                 if(d_audio->dpos<=curr_audio_pos && curr_audio_pos<(d_audio->dpos+len)){
                   break;
                 }
@@ -725,7 +724,7 @@
 	  skip_audio_bytes=curr_audio_pos-d_audio->dpos;
 
           mp_msg(MSGT_SEEK,MSGL_V,"SEEK: i=%d (max:%d) dpos=%d (wanted:%d)  \n",
-	      i,chunk_max,(int)d_audio->dpos,curr_audio_pos);
+	      (int)i,(int)chunk_max,(int)d_audio->dpos,(int)curr_audio_pos);
 	      
 	} else {
 	    // VBR audio
@@ -734,9 +733,9 @@
 	    
         // find audio chunk pos:
           for(i=0;i<priv->idx_size && chunks>0;i++){
-            int id=((AVIINDEXENTRY *)priv->idx)[i].ckid;
+            int id=(priv->idx)[i].ckid;
             if(avi_stream_id(id)==d_audio->id){
-                len=((AVIINDEXENTRY *)priv->idx)[i].dwChunkLength;
+                len=(priv->idx)[i].ChunkLength;
 		if(i>chunk_max){
 		  skip_audio_bytes+=len;
 		} else {
@@ -775,7 +774,7 @@
 	  if(audio_chunk_pos<video_chunk_pos){
             // calc priv->skip_video_frames & adjust video pts counter:
 	    for(i=audio_chunk_pos;i<video_chunk_pos;i++){
-              int id=((AVIINDEXENTRY *)priv->idx)[i].ckid;
+              int id=(priv->idx)[i].ckid;
               if(avi_stream_id(id)==d_video->id) ++priv->skip_video_frames;
             }
             // requires for correct audio pts calculation (demuxer):
@@ -794,8 +793,8 @@
 
 
           mp_msg(MSGT_SEEK,MSGL_V,"SEEK: idx=%d  (a:%d v:%d)  v.skip=%d  a.skip=%d/%4.3f  \n",
-            (int)priv->idx_pos,audio_chunk_pos,video_chunk_pos,
-            (int)priv->skip_video_frames,skip_audio_bytes,skip_audio_secs);
+            (int)priv->idx_pos,(int)audio_chunk_pos,(int)video_chunk_pos,
+            (int)priv->skip_video_frames,(int)skip_audio_bytes,skip_audio_secs);
 
           if(skip_audio_bytes){
             demux_read_data(d_audio,NULL,skip_audio_bytes);



More information about the MPlayer-dev-eng mailing list