]> git.sesse.net Git - vlc/blobdiff - plugins/avi/avi.c
* ALL: changed __inline__ with inline (autoconf does the job for us anyway,
[vlc] / plugins / avi / avi.c
index c7e7ec2690037506da602e15712f321e71f41587..343584d4bcd30a06b23bebc6e0bab1eb4bb0b040 100644 (file)
@@ -2,7 +2,7 @@
  * avi.c : AVI file Stream input module for vlc
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: avi.c,v 1.2 2002/04/25 03:01:03 fenrir Exp $
+ * $Id: avi.c,v 1.19 2002/05/18 17:47:46 sam Exp $
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  * 
  * This program is free software; you can redistribute it and/or modify
@@ -35,6 +35,8 @@
 #include "input_ext-dec.h"
 #include "input_ext-plugins.h"
 
+#include "video.h"
+
 /*****************************************************************************
  * Constants
  *****************************************************************************/
@@ -69,7 +71,6 @@ MODULE_DEACTIVATE_STOP
 /*****************************************************************************
  * Definition of structures and libraries for this plugins 
  *****************************************************************************/
-#include "fourcc.h"
 #include "libLE.c"
 #include "libioRIFF.c"
 #include "avi.h"
@@ -98,45 +99,24 @@ static void __AVIFreeDemuxData( input_thread_t *p_input )
     p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data  ; 
     
     if( p_avi_demux->p_riff != NULL ) 
-            RIFF_DeleteChunk( p_input->p_demux_data, p_avi_demux->p_riff );
+            RIFF_DeleteChunk( p_input, p_avi_demux->p_riff );
     if( p_avi_demux->p_hdrl != NULL ) 
-            RIFF_DeleteChunk( p_input->p_demux_data, p_avi_demux->p_hdrl );
+            RIFF_DeleteChunk( p_input, p_avi_demux->p_hdrl );
     if( p_avi_demux->p_movi != NULL ) 
-            RIFF_DeleteChunk( p_input->p_demux_data, p_avi_demux->p_movi );
+            RIFF_DeleteChunk( p_input, p_avi_demux->p_movi );
     if( p_avi_demux->p_idx1 != NULL ) 
-            RIFF_DeleteChunk( p_input->p_demux_data, p_avi_demux->p_idx1 );
+            RIFF_DeleteChunk( p_input, p_avi_demux->p_idx1 );
     if( p_avi_demux->pp_info != NULL )
     {
         for( i = 0; i < p_avi_demux->i_streams; i++ )
         {
             if( p_avi_demux->pp_info[i] != NULL ) 
             {
-#define p_info p_avi_demux->pp_info[i]
-/* don't uses RIFF_DeleteChunk -> it will segfault here ( probably because of
-    data_packey already unallocated ? */
-                if( p_info->p_strl != NULL ) 
-                {
-                    free( p_info->p_strl );
-                }
-                if( p_info->p_strh != NULL )
-                {
-                   free( p_info->p_strh );
-                }
-                
-                if( p_info->p_strf != NULL ) 
-                {
-                    free( p_info->p_strf );
-                }
-                if( p_info->p_strd != NULL )
+                if( p_avi_demux->pp_info[i]->p_index != NULL )
                 {
-                   free( p_info->p_strd );
+                      free( p_avi_demux->pp_info[i]->p_index );
                 }
-                if( p_info->p_index != NULL )
-                {
-                      free( p_info->p_index );
-                }
-                free( p_info ); 
-#undef  p_info
+                free( p_avi_demux->pp_info[i] ); 
             }
         }
          free( p_avi_demux->pp_info );
@@ -207,6 +187,20 @@ int avi_ParseWaveFormatEx( waveformatex_t *h, byte_t *p_data )
     return( 0 );
 }
 
+static inline int __AVIGetESTypeFromTwoCC( u16 i_type )
+{
+    switch( i_type )
+    {
+        case( TWOCC_wb ):
+            return( AUDIO_ES );
+         case( TWOCC_dc ):
+         case( TWOCC_db ):
+            return( VIDEO_ES );
+    }
+    return( UNKNOWN_ES );
+}
+
+
 static int __AVI_ParseStreamHeader( u32 i_id, int *i_number, u16 *i_type )
 {
     int c1,c2,c3,c4;
@@ -221,53 +215,40 @@ static int __AVI_ParseStreamHeader( u32 i_id, int *i_number, u16 *i_type )
         return( -1 );
     }
     *i_number = (c1 - '0') * 10 + (c2 - '0' );
-    *i_type = ( c3 << 8) + c4;
+    *i_type = ( c4 << 8) + c3;
     return( 0 );
 }   
 
-static int __AVI_HeaderMoviValid( u32 i_header )
-{
-    switch( i_header&0xFFFF0000 )
-    {
-        case( TWOCC_wb ):
-        case( TWOCC_db ):
-        case( TWOCC_dc ):
-        case( TWOCC_pc ):
-            return( 1 );
-            break;
-    }
-    switch( i_header )
-    {
-        case( FOURCC_LIST ):
-        case( FOURCC_JUNK ):
-            return( 1 );
-            break;
-    }
-    return( 0 );
-}
-
 static void __AVI_AddEntryIndex( AVIStreamInfo_t *p_info,
                                  AVIIndexEntry_t *p_index)
 {
+    AVIIndexEntry_t *p_tmp;
     if( p_info->p_index == NULL )
     {
-        p_info->i_idxmax = 4096;
+        p_info->i_idxmax = 16384;
         p_info->i_idxnb = 0;
         p_info->p_index = calloc( p_info->i_idxmax, 
                                   sizeof( AVIIndexEntry_t ) );
+        if( p_info->p_index == NULL ) {return;}
     }
     if( p_info->i_idxnb >= p_info->i_idxmax )
     {
-        p_info->i_idxmax += 4096;
-        p_info->p_index = realloc( (void*)p_info->p_index,
-                                    p_info->i_idxmax * 
-                                    sizeof( AVIIndexEntry_t ) );
+        p_info->i_idxmax += 16384;
+        p_tmp = realloc( (void*)p_info->p_index,
+                           p_info->i_idxmax * 
+                           sizeof( AVIIndexEntry_t ) );
+        if( p_tmp == NULL ) 
+        { 
+            p_info->i_idxmax -= 16384;
+            return; 
+        }
+        p_info->p_index = p_tmp;
     }
     /* calculate cumulate length */
     if( p_info->i_idxnb > 0 )
     {
-        p_index->i_lengthtotal = p_index->i_length +
-            p_info->p_index[p_info->i_idxnb-1].i_lengthtotal;
+        p_index->i_lengthtotal = p_info->p_index[p_info->i_idxnb-1].i_length +
+                p_info->p_index[p_info->i_idxnb-1].i_lengthtotal;
     }
     else
     {
@@ -280,7 +261,6 @@ static void __AVI_AddEntryIndex( AVIStreamInfo_t *p_info,
 
 static void __AVI_GetIndex( input_thread_t *p_input )
 {
-    demux_data_avi_file_t *p_avi_demux;
     AVIIndexEntry_t index;
     byte_t          *p_buff;
     riffchunk_t     *p_idx1;
@@ -288,8 +268,9 @@ static void __AVI_GetIndex( input_thread_t *p_input )
     int             i;
     int             i_number;
     u16             i_type;
-    
-    p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data  ;    
+    int             i_totalentry = 0;
+    demux_data_avi_file_t *p_avi_demux =
+                        (demux_data_avi_file_t*)p_input->p_demux_data  ;    
 
     if( RIFF_FindAndGotoDataChunk( p_input,
                                    p_avi_demux->p_riff, 
@@ -304,32 +285,31 @@ static void __AVI_GetIndex( input_thread_t *p_input )
     intf_WarnMsg( 1, "input init: loading index" ); 
     for(;;)
     {
-        if( (i_read = input_Peek( p_input, &p_buff, 16*1024 )) < 16 )
+        i_read = __MIN( 16*1024, p_idx1->i_size - i_totalentry *16);
+        if( ((i_read = input_Peek( p_input, &p_buff, i_read )) < 16 )
+              ||( i_totalentry *16 >= p_idx1->i_size ) )
         {
-            for( i = 0, i_read = 0; i < p_avi_demux->i_streams; i++ )
-            {
-                i_read += p_avi_demux->pp_info[i]->i_idxnb;
-            }
-            intf_WarnMsg( 1,"input info: read %d idx chunk", i_read );
+            intf_WarnMsg( 1,"input info: read %d idx entries", i_totalentry );
             return;
         }
         i_read /= 16 ;
-        /* TODO try to verify if we are beyond end of p_idx1 */
         for( i = 0; i < i_read; i++ )
         {
             byte_t  *p_peek = p_buff + i * 16;
+            i_totalentry++;
             index.i_id = __GetDoubleWordLittleEndianFromBuff( p_peek );
             index.i_flags = __GetDoubleWordLittleEndianFromBuff( p_peek+4);
-            index.i_offset = __GetDoubleWordLittleEndianFromBuff( p_peek+8);
+            index.i_pos = __GetDoubleWordLittleEndianFromBuff( p_peek+8);
             index.i_length = __GetDoubleWordLittleEndianFromBuff(p_peek+12);
             
-            if( (__AVI_ParseStreamHeader( index.i_id, &i_number, &i_type ) != 0)
-             ||(i_number > p_avi_demux->i_streams)) 
+            if( (__AVI_ParseStreamHeader( index.i_id, &i_number, &i_type ) == 0)
+             &&(i_number <  p_avi_demux->i_streams )
+             &&(p_avi_demux->pp_info[i_number]->i_cat == 
+                     __AVIGetESTypeFromTwoCC( i_type ))) 
             {
-                continue;
+                __AVI_AddEntryIndex( p_avi_demux->pp_info[i_number],
+                                     &index );
             }
-            __AVI_AddEntryIndex( p_avi_demux->pp_info[i_number],
-                                 &index );
         }
         __RIFF_SkipBytes( p_input, 16 * i_read );
     }
@@ -337,61 +317,58 @@ static void __AVI_GetIndex( input_thread_t *p_input )
 }
 static int __AVI_SeekToChunk( input_thread_t *p_input, AVIStreamInfo_t *p_info )
 {
-    demux_data_avi_file_t *p_avi_demux;
-    p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
-    
-    if( (p_info->p_index != NULL)&&(p_info->i_idxpos < p_info->i_idxnb) )
+    if( (p_info->p_index )&&(p_info->i_idxposc < p_info->i_idxnb) )
     {
-        /* perfect */
-        off_t i_pos;
-        i_pos = (off_t)p_info->p_index[p_info->i_idxpos].i_offset +
-                    p_info->i_idxoffset;
-
-        p_input->pf_seek( p_input, i_pos );
+        p_input->pf_seek( p_input, 
+                          (off_t)p_info->p_index[p_info->i_idxposc].i_pos);
         input_AccessReinit( p_input );
         return( 0 );
     }
-    /* index are no longer valid */
-    if( p_info->p_index != NULL )
-    {
-        return( -1 );
-    }
-    /* no index */
+    /* no index can't arrive but ...*/
+    intf_WarnMsg( 1, "input error: can't seek");
     return( -1 );
 }
 
 
 /* XXX call after get p_movi */
-static int __AVI_GetIndexOffset( input_thread_t *p_input )
+static void __AVI_UpdateIndexOffset( input_thread_t *p_input )
 {
-    riffchunk_t *p_chunk;
-    demux_data_avi_file_t *p_avi_demux;
-    int i;
-
-    p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
-    for( i = 0; i < p_avi_demux->i_streams; i++ )
+    int i_stream;
+    int b_start = 1;/* if index pos is based on start of file or not (p_movi) */
+    demux_data_avi_file_t *p_avi_demux =
+                        (demux_data_avi_file_t*)p_input->p_demux_data;
+
+/* FIXME some work to do :
+        * test in the ile if it's true, if not do a RIFF_Find...
+*/
+#define p_info p_avi_demux->pp_info[i_stream]
+    for( i_stream = 0; i_stream < p_avi_demux->i_streams; i_stream++ )
+    {
+        if( ( p_info->p_index )
+           && ( p_info->p_index[0].i_pos < p_avi_demux->p_movi->i_pos + 8 ))
+        {
+            b_start = 0;
+            break;
+        }
+    }
+    if( !b_start )
     {
-#define p_info p_avi_demux->pp_info[i]
-        if( p_info->p_index == NULL ) {continue;}
-        p_info->i_idxoffset = 0;
-        __AVI_SeekToChunk( p_input, p_info );
-        p_chunk = RIFF_ReadChunk( p_input );
-        if( (p_chunk == NULL)||(p_chunk->i_id != p_info->p_index[0].i_id) )
+        for( i_stream = 0; i_stream < p_avi_demux->i_streams; i_stream++ )
         {
-            p_info->i_idxoffset = p_avi_demux->p_movi->i_pos + 8;
-            __AVI_SeekToChunk( p_input, p_info );
-            p_chunk = RIFF_ReadChunk( p_input );
-            if( (p_chunk == NULL)||(p_chunk->i_id != p_info->p_index[0].i_id) )
+            int i;
+            if( p_info->p_index )
             {
-                intf_WarnMsg( 1, "input demux: can't find offset for stream %d",
-                                i);
-                continue; /* TODO: search manually from p_movi */
+                for( i = 0; i < p_info->i_idxnb; i++ )
+                {
+                    p_info->p_index[i].i_pos += 
+                                                p_avi_demux->p_movi->i_pos + 8;
+                }
             }
         }
-#undef p_info
     }
-    return( 0 );
+#undef p_info
 }
+
 static int __AVI_AudioGetType( u32 i_type )
 {
     switch( i_type )
@@ -412,54 +389,82 @@ static int __AVI_VideoGetType( u32 i_type )
 {
     switch( i_type )
     {
-        case( FOURCC_DIV3 ):
-        case( FOURCC_div3 ):
-        case( FOURCC_DIV4 ):
-        case( FOURCC_div4 ):
-        case( FOURCC_DIV5 ):
-        case( FOURCC_div5 ):
-        case( FOURCC_DIV6 ):
-        case( FOURCC_div6 ):
-        case( FOURCC_3IV1 ):
-        case( FOURCC_AP41 ):
-        case( FOURCC_MP43 ):
-        case( FOURCC_mp43 ):
-            return( MSMPEG4_VIDEO_ES );
-
-        case( FOURCC_DIVX ):
-        case( FOURCC_divx ):
-        case( FOURCC_DX50 ):
-        case( FOURCC_MP4S ):
-        case( FOURCC_MPG4 ):
-        case( FOURCC_mpg4 ):
-        case( FOURCC_mp4v ):
+/* FIXME FIXME :  what are the correct tag for msmpeg4 v1 */
+        case(  FOURCC_MPG4  ):
+        case(  FOURCC_mpg4  ):
+        case(  FOURCC_DIV2  ):
+        case(  FOURCC_div2  ):
+        case(  FOURCC_MP42  ):
+        case(  FOURCC_mp42  ):
+             return( MSMPEG4v2_VIDEO_ES );
+           
+        case(  FOURCC_MPG3  ):
+        case(  FOURCC_mpg3  ):
+        case(  FOURCC_div3  ):
+        case(  FOURCC_MP43  ):
+        case(  FOURCC_mp43  ):
+        case(  FOURCC_DIV3  ):
+        case(  FOURCC_DIV4  ):
+        case(  FOURCC_div4  ):
+        case(  FOURCC_DIV5  ):
+        case(  FOURCC_div5  ):
+        case(  FOURCC_DIV6  ):
+        case(  FOURCC_div6  ):
+        case(  FOURCC_AP41  ):
+        case(  FOURCC_3IV1  ):
+            return( MSMPEG4v3_VIDEO_ES );
+
+
+        case(  FOURCC_DIVX  ):
+        case(  FOURCC_divx  ):
+        case(  FOURCC_DIV1  ):
+        case(  FOURCC_div1  ):
+        case(  FOURCC_MP4S  ):
+        case(  FOURCC_mp4s  ):
+        case(  FOURCC_M4S2  ):
+        case(  FOURCC_m4s2  ):
+        case(  FOURCC_xvid  ):
+        case(  FOURCC_XVID  ):
+        case(  FOURCC_XviD  ):
+        case(  FOURCC_DX50  ):
+        case(  FOURCC_mp4v  ):
+        case(  FOURCC_4     ):
             return( MPEG4_VIDEO_ES );
 
         default:
             return( 0 );
     }
 }
-/**************************************************************************/
 
-/* Tention: bcp de test à ajouter mais aussi beaucoup de MEMOIRE a DESALLOUER pas fait */
+/*****************************************************************************
+ * AVIInit: check file and initializes AVI structures
+ *****************************************************************************/
 static int AVIInit( input_thread_t *p_input )
 {
     riffchunk_t *p_riff,*p_hdrl,*p_movi;
     riffchunk_t *p_avih;
-    riffchunk_t *p_strl,*p_strh,*p_strf/* ,*p_strd */;
-    
+    riffchunk_t *p_strl,*p_strh,*p_strf;
     demux_data_avi_file_t *p_avi_demux;
     es_descriptor_t *p_es = NULL; /* for not warning */
-    es_descriptor_t *p_es_video = NULL; 
-    es_descriptor_t *p_es_audio = NULL;
 
     int i;
-    
-    p_avi_demux = malloc( sizeof(demux_data_avi_file_t) );
-    memset( p_avi_demux, 0, sizeof( demux_data_avi_file_t ) );
-    p_input->p_demux_data = p_avi_demux;
 
-    /* FIXME FIXME Je sais pas trop a quoi ca sert juste copié de ESInit */
+    /* we need to seek to be able to readcorrectly */
+    if( !p_input->stream.b_seekable ) 
+    {
+        intf_WarnMsg( 2,"input: RIFF-AVI plug-in discarded (no seekable)" );
+        return( -1 );
+    }
+    p_input->p_demux_data = 
+                p_avi_demux = malloc( sizeof(demux_data_avi_file_t) );
+    if( p_avi_demux == NULL )
+    {
+        intf_ErrMsg( "input error: not enough memory" );
+        return( -1 );
+    }
+    memset( p_avi_demux, 0, sizeof( demux_data_avi_file_t ) );
+    p_avi_demux->i_rate = DEFAULT_RATE;
+    /* FIXME I don't know what it's do, copied from ESInit */
     /* Initialize access plug-in structures. */
     if( p_input->i_mtu == 0 )
     {
@@ -470,7 +475,7 @@ static int AVIInit( input_thread_t *p_input )
     if( RIFF_TestFileHeader( p_input, &p_riff, FOURCC_AVI ) != 0 )    
     {
         __AVIFreeDemuxData( p_input );
-        intf_ErrMsg( "input: RIFF-AVI plug-in discarded (avi_file)" );
+        intf_WarnMsg( 2,"input: RIFF-AVI plug-in discarded (avi_file)" );
         return( -1 );
     }
     p_avi_demux->p_riff = p_riff;
@@ -497,7 +502,7 @@ static int AVIInit( input_thread_t *p_input )
         intf_ErrMsg( "input error: cannot look for subchunk (avi_file)" );
         return ( -1 );
     }
-    /* ds  LIST-hdrl cherche avih */
+    /* in  LIST-hdrl search avih */
     if( RIFF_FindAndLoadChunk( p_input, p_hdrl, 
                                     &p_avih, FOURCC_avih ) != 0 )
     {
@@ -509,161 +514,106 @@ static int AVIInit( input_thread_t *p_input )
     RIFF_DeleteChunk( p_input, p_avih );
     
     if( p_avi_demux->avih.i_streams == 0 )  
-            /* aucun flux defini, peut etre essayer de trouver ss connaitre */
-                                      /* le nombre serait pas mal, a voir */
+    /* no stream found, perhaps it would be cool to find it */
     {
         __AVIFreeDemuxData( p_input );
         intf_ErrMsg( "input error: no defined stream !" );
         return( -1 );
     }
-    
-    /* On creer les tableau pr les flux */
+
+    /*  create one program */
+    vlc_mutex_lock( &p_input->stream.stream_lock ); 
+    if( input_InitStream( p_input, 0 ) == -1)
+    {
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        __AVIFreeDemuxData( p_input );
+        intf_ErrMsg( "input error: cannot init stream" );
+        return( -1 );
+    }
+    if( input_AddProgram( p_input, 0, 0) == NULL )
+    {
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        __AVIFreeDemuxData( p_input );
+        intf_ErrMsg( "input error: cannot add program" );
+        return( -1 );
+    }
+    p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
+    p_input->stream.p_new_program = p_input->stream.pp_programs[0] ;
+    p_input->stream.i_mux_rate = p_avi_demux->avih.i_maxbytespersec / 50;
+    vlc_mutex_unlock( &p_input->stream.stream_lock ); 
+
+    /* now read info on each stream and create ES */
     p_avi_demux->i_streams = p_avi_demux->avih.i_streams;
     
     p_avi_demux->pp_info = calloc( p_avi_demux->i_streams, 
                                     sizeof( AVIStreamInfo_t* ) );
     memset( p_avi_demux->pp_info, 0, 
                         sizeof( AVIStreamInfo_t* ) * p_avi_demux->i_streams );
-    
+
     for( i = 0 ; i < p_avi_demux->i_streams; i++ )
     {
-        p_avi_demux->pp_info[i] = malloc( sizeof(AVIStreamInfo_t ) );
-        memset( p_avi_demux->pp_info[i], 0, sizeof( AVIStreamInfo_t ) );        
+#define p_info  p_avi_demux->pp_info[i]
+        p_info = malloc( sizeof(AVIStreamInfo_t ) );
+        memset( p_info, 0, sizeof( AVIStreamInfo_t ) );        
 
-        /* pour chaque flux on cherche ses infos */
-        if( RIFF_FindListChunk(p_input,
+        if( ( RIFF_FindListChunk(p_input,
                                 &p_strl,p_hdrl, FOURCC_strl) != 0 )
+                ||( RIFF_DescendChunk(p_input) != 0 ))
         {
             __AVIFreeDemuxData( p_input );
             intf_ErrMsg( "input error: cannot find \"LIST-strl\" (avi_file)" );
             return( -1 );
         }
-        p_avi_demux->pp_info[i]->p_strl = p_strl;
         
-        if( RIFF_DescendChunk(p_input) != 0 )
-        {
-            __AVIFreeDemuxData( p_input );
-            intf_ErrMsg( "input error: cannot look for subchunk (avi_file)" );
-            return ( -1 );
-        }
-        /* ds  LIST-strl cherche strh */
+        /* in  LIST-strl search strh */
         if( RIFF_FindAndLoadChunk( p_input, p_hdrl, 
                                 &p_strh, FOURCC_strh ) != 0 )
         {
+            RIFF_DeleteChunk( p_input, p_strl );
             __AVIFreeDemuxData( p_input );
             intf_ErrMsg( "input error: cannot find \"strh\" (avi_file)" );
             return( -1 );
         }
-        p_avi_demux->pp_info[i]->p_strh = p_strh;
-        
-        /* ds  LIST-strl cherche strf */
+        __AVI_Parse_Header( &p_info->header,
+                            p_strh->p_data->p_payload_start);
+        RIFF_DeleteChunk( p_input, p_strh );      
+
+        /* in  LIST-strl search strf */
         if( RIFF_FindAndLoadChunk( p_input, p_hdrl, 
                                 &p_strf, FOURCC_strf ) != 0 )
         {
+            RIFF_DeleteChunk( p_input, p_strl );
             __AVIFreeDemuxData( p_input );
             intf_ErrMsg( "input error: cannot find \"strf\" (avi_file)" );
             return( -1 );
         }
-         p_avi_demux->pp_info[i]->p_strf = p_strf;
-        /* FIXME faudrait cherche et charger strd */
-        /* mais a priori pas vraiment utile pr divx */
-
-         if( RIFF_AscendChunk(p_input, p_strl) != 0 )
+        /* we don't get strd, it's useless for divx,opendivx,mepgaudio */ 
+        if( RIFF_AscendChunk(p_input, p_strl) != 0 )
         {
+            RIFF_DeleteChunk( p_input, p_strf );
+            RIFF_DeleteChunk( p_input, p_strl );
             __AVIFreeDemuxData( p_input );
             intf_ErrMsg( "input error: cannot go out (\"strl\") (avi_file)" );
             return( -1 );
         }
-        
-    }
-    
-
-    if( RIFF_AscendChunk(p_input, p_hdrl) != 0)
-    {
-        __AVIFreeDemuxData( p_input );
-        intf_ErrMsg( "input error: cannot go out (\"hdrl\") (avi_file)" );
-        return( -1 );
-    }
-
-    intf_Msg( "input init: AVIH: %d stream, flags %s%s%s%s%s%s ", 
-            p_avi_demux->i_streams,
-            p_avi_demux->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
-            p_avi_demux->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
-            p_avi_demux->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
-            p_avi_demux->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"",
-            p_avi_demux->avih.i_flags&AVIF_WASCAPTUREFILE?" CAPTUREFILE":"",
-            p_avi_demux->avih.i_flags&AVIF_COPYRIGHTED?" COPYRIGHTED":"" );
-
-    /* go to movi chunk */
-    if( RIFF_FindListChunk(p_input ,&p_movi,p_riff, FOURCC_movi) != 0 )
-    {
-        intf_ErrMsg( "input error: cannot find \"LIST-movi\" (avi_file)" );
-        __AVIFreeDemuxData( p_input );
-        return( -1 );
-    }
-    p_avi_demux->p_movi = p_movi;
-    
-    /* get index */
-    if( (p_input->stream.b_seekable)
-         &&((p_avi_demux->avih.i_flags&AVIF_HASINDEX) != 0) )
-    {
-        __AVI_GetIndex( p_input );
-        /* try to get i_idxoffset with first stream*/
-        __AVI_GetIndexOffset( p_input );
-        RIFF_GoToChunk( p_input, p_avi_demux->p_movi );
-    }
-    else
-    {
-        intf_WarnMsg( 1, "input init: cannot get index" );
-    }
-
-    if( RIFF_DescendChunk( p_input ) != 0 )
-    {
-        __AVIFreeDemuxData( p_input );
-        intf_ErrMsg( "input error: cannot go in (\"movi\") (avi_file)" );
-        return( -1 );
-    }
-   /* TODO: check for index and read it if possible( seekable )*/
-
-   /** We have now finished with reading the file **/
-   /** we make the last initialisation  **/
-
-    if( input_InitStream( p_input, 0 ) == -1)
-    {
-        __AVIFreeDemuxData( p_input );
-        intf_ErrMsg( "input error: cannot init stream" );
-        return( -1 );
-    }
 
-    if( input_AddProgram( p_input, 0, 0) == NULL )
-    {
-        __AVIFreeDemuxData( p_input );
-        intf_ErrMsg( "input error: cannot add program" );
-        return( -1 );
-    }
-    p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
-    p_input->stream.p_new_program = p_input->stream.pp_programs[0] ;
-            
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-    for( i = 0; i < p_avi_demux->i_streams; i++ )
-    {
-#define p_info  p_avi_demux->pp_info[i]
-        __AVI_Parse_Header( &p_info->header,
-                        p_info->p_strh->p_data->p_payload_start);
+        /* add one ES */
+        vlc_mutex_lock( &p_input->stream.stream_lock );
+        p_es = input_AddES( p_input,
+                            p_input->stream.p_selected_program, 1+i,
+                            p_strf->i_size );
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        p_es->i_stream_id =i; /* XXX: i don't use it */ 
+       
         switch( p_info->header.i_type )
         {
             case( FOURCC_auds ):
-                /* pour l'id j'ai mis 12+i pr audio et 42+i pour video */
-                /* et le numero du flux(ici i) dans i_stream_id */
+                p_es->i_cat = AUDIO_ES;
                 avi_ParseWaveFormatEx( &p_info->audio_format,
-                                   p_info->p_strf->p_data->p_payload_start ); 
-                p_es = input_AddES( p_input, 
-                                p_input->stream.p_selected_program, 12+i, 
-                                    p_info->p_strf->i_size );
+                                   p_strf->p_data->p_payload_start ); 
                 p_es->b_audio = 1;
                 p_es->i_type = 
                     __AVI_AudioGetType( p_info->audio_format.i_formattag );
-                p_es->i_stream_id =i; /* FIXME */                
                 if( p_es->i_type == 0 )
                 {
                     intf_ErrMsg( "input error: stream(%d,0x%x) not supported",
@@ -671,24 +621,15 @@ static int AVIInit( input_thread_t *p_input )
                                     p_info->audio_format.i_formattag );
                     p_es->i_cat = UNKNOWN_ES;
                 }
-                else
-                {
-                    if( p_es_audio == NULL ) {p_es_audio = p_es;}
-                    p_es->i_cat = AUDIO_ES;
-                }
                 break;
                 
             case( FOURCC_vids ):
+                p_es->i_cat = VIDEO_ES;
                 avi_ParseBitMapInfoHeader( &p_info->video_format,
-                                   p_info->p_strf->p_data->p_payload_start ); 
-
-                p_es = input_AddES( p_input, 
-                                p_input->stream.p_selected_program, 42+i,
-                                    p_info->p_strf->i_size );
+                                   p_strf->p_data->p_payload_start ); 
                 p_es->b_audio = 0;
                 p_es->i_type = 
                     __AVI_VideoGetType( p_info->video_format.i_compression );
-                p_es->i_stream_id =i; /* FIXME */                
                 if( p_es->i_type == 0 )
                 {
                     intf_ErrMsg( "input error: stream(%d,%4.4s) not supported",
@@ -696,16 +637,8 @@ static int AVIInit( input_thread_t *p_input )
                                (char*)&p_info->video_format.i_compression);
                     p_es->i_cat = UNKNOWN_ES;
                 }
-                else
-                {
-                    if( p_es_video == NULL ) {p_es_video = p_es;}
-                    p_es->i_cat = VIDEO_ES;
-                }
                 break;
             default:
-                p_es = input_AddES( p_input, 
-                                p_input->stream.p_selected_program, 12, 
-                                    p_info->p_strf->i_size );
                 intf_ErrMsg( "input error: unknown stream(%d) type",
                             i );
                 p_es->i_cat = UNKNOWN_ES;
@@ -715,10 +648,127 @@ static int AVIInit( input_thread_t *p_input )
         p_info->i_cat = p_es->i_cat;
         /* We copy strf for decoder in p_es->p_demux_data */
         memcpy( p_es->p_demux_data, 
-                p_info->p_strf->p_data->p_payload_start,
-                p_info->p_strf->i_size );
-        /* print informations on stream */
-        switch( p_es->i_cat )
+                p_strf->p_data->p_payload_start,
+                p_strf->i_size );
+        RIFF_DeleteChunk( p_input, p_strf );
+        RIFF_DeleteChunk( p_input, p_strl );
+#undef p_info           
+    }
+
+
+
+    /* go out of p_hdrl */
+    if( RIFF_AscendChunk(p_input, p_hdrl) != 0)
+    {
+        __AVIFreeDemuxData( p_input );
+        intf_ErrMsg( "input error: cannot go out (\"hdrl\") (avi_file)" );
+        return( -1 );
+    }
+
+    /* go to movi chunk to get it*/
+    if( RIFF_FindListChunk(p_input ,&p_movi,p_riff, FOURCC_movi) != 0 )
+    {
+        intf_ErrMsg( "input error: cannot find \"LIST-movi\" (avi_file)" );
+        __AVIFreeDemuxData( p_input );
+        return( -1 );
+    }
+    p_avi_demux->p_movi = p_movi;
+    
+    /* get index  XXX need to have p_movi */
+    if( (p_avi_demux->avih.i_flags&AVIF_HASINDEX) != 0 )
+    {
+        /* get index */
+        __AVI_GetIndex( p_input ); 
+        /* try to get i_idxoffset for each stream  */
+        __AVI_UpdateIndexOffset( p_input );
+    }
+    else
+    {
+        intf_WarnMsg( 1, "input init: no index !" );
+    }
+
+    
+    /* we verify that each stream have at least one entry or create it */
+    for( i = 0; i < p_avi_demux->i_streams ; i++ )
+    {
+        AVIIndexEntry_t index;
+        riffchunk_t     *p_chunk;
+#define p_info  p_avi_demux->pp_info[i]
+        if( p_info->p_index == NULL )
+        {
+            RIFF_GoToChunk( p_input, p_avi_demux->p_movi );
+            if( RIFF_DescendChunk(p_input) != 0 ) { continue; }
+            p_chunk = NULL;
+            switch( p_info->i_cat ) 
+            {
+                case( AUDIO_ES ):
+                    if( RIFF_FindChunk( p_input, 
+                               MAKEFOURCC('0'+i/10, '0'+i%10,'w','b' ), 
+                                             p_movi ) == 0)
+                    {
+                       p_chunk = RIFF_ReadChunk( p_input );
+                    }
+                    break;
+                    
+                case( VIDEO_ES ):
+                    if( (RIFF_FindChunk( p_input, 
+                                    MAKEFOURCC('0'+i/10, '0'+i%10,'d','c' ),
+                                            p_movi ) == 0) )
+                    {
+                        p_chunk = RIFF_ReadChunk( p_input ); 
+                    }
+                    else
+                    {
+                        RIFF_GoToChunk( p_input, p_avi_demux->p_movi );
+                        if( RIFF_DescendChunk(p_input) != 0 ) { continue; }
+                        if( (RIFF_FindChunk( p_input,
+                                        MAKEFOURCC('0'+i/10, '0'+i%10,'d','b' ),
+                                            p_movi ) == 0) )
+                        {
+                            p_chunk = RIFF_ReadChunk( p_input );
+                        }
+                    }
+                    break;
+            }
+            if( p_chunk != NULL )
+            {
+                index.i_id = p_chunk->i_id;
+                index.i_flags = AVIIF_KEYFRAME;
+                index.i_pos = p_chunk->i_pos;
+                index.i_length = p_chunk->i_size;
+                __AVI_AddEntryIndex( p_info, &index );
+                intf_WarnMsg( 3, "input init: add index entry (%4.4s) (%d)", 
+                                 (char*)&p_chunk->i_id,
+                                 i); 
+               
+            }
+        }
+#undef p_info
+    }
+
+    /* to make sure to go the begining because unless demux will see a seek */
+    RIFF_GoToChunk( p_input, p_avi_demux->p_movi );
+    if( RIFF_DescendChunk( p_input ) != 0 )
+    {
+        __AVIFreeDemuxData( p_input );
+        intf_ErrMsg( "input error: cannot go in (\"movi\") (avi_file)" );
+        return( -1 );
+    }
+
+    /* print informations on streams */
+    intf_Msg( "input init: AVIH: %d stream, flags %s%s%s%s%s%s ", 
+            p_avi_demux->i_streams,
+            p_avi_demux->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
+            p_avi_demux->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
+            p_avi_demux->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
+            p_avi_demux->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"",
+            p_avi_demux->avih.i_flags&AVIF_WASCAPTUREFILE?" CAPTUREFILE":"",
+            p_avi_demux->avih.i_flags&AVIF_COPYRIGHTED?" COPYRIGHTED":"" );
+
+    for( i = 0; i < p_avi_demux->i_streams; i++ )
+    {
+#define p_info  p_avi_demux->pp_info[i]
+        switch( p_info->p_es->i_cat )
         {
             case( VIDEO_ES ):
                 intf_Msg("input init: video(%4.4s) %dx%d %dbpp %ffps (size %d)",
@@ -729,7 +779,12 @@ static int AVIInit( input_thread_t *p_input )
                         (float)p_info->header.i_rate /
                             (float)p_info->header.i_scale,
                         p_info->header.i_samplesize );
+                if( (p_avi_demux->p_info_video == NULL) ) 
+                {
+                    p_avi_demux->p_info_video = p_info;
+               }
                 break;
+
             case( AUDIO_ES ):
                 intf_Msg( "input init: audio(0x%x) %d channels %dHz %dbits %ffps (size %d)",
                         p_info->audio_format.i_formattag,
@@ -739,40 +794,47 @@ static int AVIInit( input_thread_t *p_input )
                         (float)p_info->header.i_rate /
                             (float)p_info->header.i_scale,
                         p_info->header.i_samplesize );
+                if( (p_avi_demux->p_info_audio == NULL) ) 
+                {
+                    p_avi_demux->p_info_audio = p_info;
+                }
                 break;
+            case( UNKNOWN_ES ):
+                intf_Msg( "input init: unhanled stream %d", i );
         }
-
 #undef p_info    
     }
 
     /* we select the first audio and video ES */
-    if( p_es_video != NULL ) 
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    if( p_avi_demux->p_info_video != NULL ) 
     {
-        input_SelectES( p_input, p_es_video );
+        input_SelectES( p_input, p_avi_demux->p_info_video->p_es );
+        /*  it seems that it's useless to select es because there are selected 
+         *  by the interface but i'm not sure of that */
     }
     else
     {
-        intf_ErrMsg( "input error: no video stream found !" );
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
-        return( -1 );
+        intf_Msg( "input error: no video stream found !" );
     }
-    if( p_es_audio != NULL ) 
+    if( p_avi_demux->p_info_audio != NULL ) 
     {
-        input_SelectES( p_input, p_es_audio );
+        input_SelectES( p_input, p_avi_demux->p_info_audio->p_es );
     }
     else
     {
         intf_Msg( "input init: no audio stream found !" );
     }
-
-   /* p_input->stream.p_selected_area->i_tell = 0; */
-    p_input->stream.i_mux_rate = p_avi_demux->avih.i_maxbytespersec / 50;
     p_input->stream.p_selected_program->b_is_ok = 1;
     vlc_mutex_unlock( &p_input->stream.stream_lock );
     
     return( 0 );
 }
 
+
+/*****************************************************************************
+ * AVIEnd: frees unused data
+ *****************************************************************************/
 static void AVIEnd( input_thread_t *p_input )
 {   
     __AVIFreeDemuxData( p_input ); 
@@ -780,266 +842,746 @@ static void AVIEnd( input_thread_t *p_input )
 }
 
 
-static mtime_t __AVI_GetPTS( AVIStreamInfo_t *p_info )
+static mtime_t AVI_GetPTS( AVIStreamInfo_t *p_info )
 {
-    /* XXX you need to had p_info->i_date to have correct pts */
-    /* p_info->p_index[p_info->i_idxpos] need to be valid !! */
-    mtime_t i_pts;
-
+    /* p_info->p_index[p_info->i_idxposc] need to be valid !! */
     /* be careful to  *1000000 before round  ! */
     if( p_info->header.i_samplesize != 0 )
     {
-        i_pts = (mtime_t)( (double)1000000.0 *
-                    (double)p_info->p_index[p_info->i_idxpos].i_lengthtotal *
+        return( (mtime_t)( (double)1000000.0 *
+                   (double)(p_info->p_index[p_info->i_idxposc].i_lengthtotal +
+                             p_info->i_idxposb )*
                     (double)p_info->header.i_scale /
                     (double)p_info->header.i_rate /
-                    (double)p_info->header.i_samplesize );
+                    (double)p_info->header.i_samplesize ) );
     }
     else
     {
-        i_pts = (mtime_t)( (double)1000000.0 *
-                    (double)p_info->i_idxpos *
+        return( (mtime_t)( (double)1000000.0 *
+                    (double)(p_info->i_idxposc ) *
                     (double)p_info->header.i_scale /
-                    (double)p_info->header.i_rate);
+                    (double)p_info->header.i_rate) );
     }
-    return( i_pts );
 }
 
 
 
-static void __AVI_NextIndexEntry( input_thread_t *p_input, 
+static int __AVI_NextIndexEntry( input_thread_t *p_input, 
                                   AVIStreamInfo_t *p_info )
 {
-   p_info->i_idxpos++;
-   if( p_info->i_idxpos >= p_info->i_idxnb )
-   {
-        /* we need to verify if we reach end of file
-            or if index is broken and search manually */
-        intf_WarnMsg( 1, "input demux: out of index" );
-   }
-}
+    AVIIndexEntry_t index;
+    riffchunk_t     *p_chunk;
+    AVIStreamInfo_t *p_info_tmp;
+    int             i;
+    int             i_idxposc;
+    int             b_inc = 0;
+    demux_data_avi_file_t *p_avi_demux =
+                        (demux_data_avi_file_t*)p_input->p_demux_data;
 
-static int __AVI_ReAlign( input_thread_t *p_input, 
-                            AVIStreamInfo_t  *p_info )
-{
-    u32     u32_pos;
-    off_t   i_pos;
-    
-    __RIFF_TellPos( p_input, &u32_pos );
-     i_pos = (off_t)u32_pos - (off_t)p_info->i_idxoffset;
-   
-    /* TODO verifier si on est dans p_movi */
-    
-    if( p_info->p_index[p_info->i_idxnb-1].i_offset <= i_pos )
+    p_info->i_idxposc++;
+
+    if( p_info->i_idxposc < p_info->i_idxnb )
     {
-        p_info->i_idxpos = p_info->i_idxnb-1;
-        return( 0 ); 
+        return( 0 );
     }
+    if( p_info->i_idxposc > p_info->i_idxnb )
+    {
+        return( -1 );
+    }
+    p_info->i_idxposc--;
     
-    if( i_pos <= p_info->p_index[0].i_offset )
+    /* create entry on the fly */
+    /* search for the more advance stream and parse from it for all streams*/
+    p_info_tmp = p_info;
+    for( i = 0; i < p_avi_demux->i_streams; i++ )
     {
-        p_info->i_idxpos = 0;
-        return( 0 );
+#define p_info_i p_avi_demux->pp_info[i]
+        if( ( p_info_i->p_index )
+            && ( p_info_i->p_index[p_info_i->i_idxnb - 1].i_pos >
+            p_info_tmp->p_index[p_info_tmp->i_idxnb - 1].i_pos ) )
+        {
+            p_info_tmp = p_info_i;
+        }
+#undef  p_info_i
     }
-    /* if we have seek in the current chunk then do nothing 
-        __AVI_SeekToChunk will correct */
-    if( (p_info->p_index[p_info->i_idxpos].i_offset <= i_pos)
-            && ( i_pos < p_info->p_index[p_info->i_idxpos].i_offset + 
-                    p_info->p_index[p_info->i_idxpos].i_length ) )
+       
+    /* go to last defined entry */
+    i_idxposc = p_info_tmp->i_idxposc; /* save p_info_tmp->i_idxposc */
+    p_info_tmp->i_idxposc = p_info_tmp->i_idxnb - 1;
+    __AVI_SeekToChunk( p_input, p_info_tmp );
+    p_info_tmp->i_idxposc = i_idxposc;
+
+    if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
     {
-        return( 0 );
+        p_info->i_idxposc++;
+        return( -1 );
     }
 
-    if( i_pos >= p_info->p_index[p_info->i_idxpos].i_offset )
+    /* save idxpos of p_info */
+    /* now parse for all stream and stop when reach next chunk for p_info */
+    for( i = 0; (i < 15)||(!b_inc); i++)
     {
-        /* search for a chunk after i_idxpos */
-        while( (p_info->p_index[p_info->i_idxpos].i_offset < i_pos)
-                &&( p_info->i_idxpos < p_info->i_idxnb - 1 ) )
+        int i_number;
+        u16 i_type;
+        if( (p_chunk = RIFF_ReadChunk( p_input )) == NULL )
+        {
+            p_info->i_idxposc++;
+            return( b_inc == 1 ? 0 : -1 );
+        }
+
+        index.i_id = p_chunk->i_id;
+        index.i_flags = AVIIF_KEYFRAME;
+        index.i_pos = p_chunk->i_pos;
+        index.i_length = p_chunk->i_size;
+        RIFF_DeleteChunk( p_input, p_chunk );
+#define p_info_i    p_avi_demux->pp_info[i_number]
+       if( (__AVI_ParseStreamHeader( index.i_id, &i_number, &i_type ) == 0)
+             &&( i_number < p_avi_demux->i_streams )
+             &&( p_info_i->p_index )
+             &&( p_info_i->p_index[p_info_i->i_idxnb - 1].i_pos + 
+                     p_info_i->p_index[p_info_i->i_idxnb - 1].i_length + 8<= 
+                        index.i_pos ) 
+             &&( __AVIGetESTypeFromTwoCC( i_type ) == p_info_i->i_cat ) )
         {
-            p_info->i_idxpos++;
+            __AVI_AddEntryIndex( p_info_i, &index );
+            if( (p_info_i == p_info)&&(!b_inc) )
+            {
+                b_inc = 1;
+            }
         }
-        while( ((p_info->p_index[p_info->i_idxpos].i_flags&AVIIF_KEYFRAME) == 0)
-                &&( p_info->i_idxpos < p_info->i_idxnb - 1 ) )
+#undef  p_info_i
+        if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
         {
-            p_info->i_idxpos++;
+            p_info->i_idxposc++;
+            return( b_inc == 1 ? 0 : -1 );
         }
+
+    } 
+
+    p_info->i_idxposc++;
+    return( 0 );
+}
+
+/*****************************************************************************
+ * Functions to acces streams data 
+ * Uses it, because i plane to read unseekable stream
+ * Don't work for the moment for unseekable stream 
+ *****************************************************************************/
+
+/*      __AVI_ReadStreamChunkInPES;   load an entire chunk 
+        __AVI_ReadStreamBytesInPES;   load bytes 
+        __AVI_GoToStreamChunk;        go to chunk
+        __AVI_GoToStreamBytes;        go to bytes in the all stream  
+ not seekable file is not yet supported
+ */
+
+static int __AVI_GoToStreamChunk( input_thread_t    *p_input, 
+                                  AVIStreamInfo_t   *p_info,
+                                  int   i_chunk )
+{
+    u32   u32_pos;
+    off_t i_pos;
+    
+    if( !p_input->stream.b_seekable )
+    {
+        intf_ErrMsg( "input error: need the ability to seek in stream" );
+        return( -1 );
     }
-    else
+
+    if( p_info->p_index != NULL )
     {
-        /* search for a chunk before i_idxpos */
-        while( (p_info->p_index[p_info->i_idxpos].i_offset + 
-                    p_info->p_index[p_info->i_idxpos].i_length >= i_pos)
-                        &&( p_info->i_idxpos > 0 ) )
+        if( i_chunk >= p_info->i_idxnb )
+        {
+            p_info->i_idxposc = p_info->i_idxnb-1;
+            while( p_info->i_idxposc < i_chunk )
+            {
+                if( __AVI_NextIndexEntry( p_input, p_info ) != 0)
+                {
+                    return( -1 );
+                }
+            }
+        }
+        else
         {
-            p_info->i_idxpos--;
+            p_info->i_idxposc = i_chunk;
         }
-        while( ((p_info->p_index[p_info->i_idxpos].i_flags&AVIIF_KEYFRAME) == 0)
-                &( p_info->i_idxpos > 0 ) )
+
+        /* now do we have valid index for the chunk */
+        __RIFF_TellPos( p_input, &u32_pos );
+
+        i_pos = (off_t)p_info->p_index[i_chunk].i_pos;
+        if( i_pos != u32_pos )
         {
-            p_info->i_idxpos--;
+            p_input->pf_seek( p_input, i_pos );
+            input_AccessReinit( p_input );
         }
+        p_info->i_idxposb = 0;
+        return( 0 );
+    }
+    else
+    {
+        return( -1 );
     }
-    
-    return( 0 );
 }
-static void __AVI_SynchroReInit( input_thread_t *p_input,
-                                 AVIStreamInfo_t *p_info_master,
-                                 AVIStreamInfo_t *p_info_slave )
-{
-    demux_data_avi_file_t *p_avi_demux;
-    p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
-    p_avi_demux->i_date = mdate() + DEFAULT_PTS_DELAY 
-                            - __AVI_GetPTS( p_info_master );
-    /* TODO: a optimiser */
-    p_info_slave->i_idxpos = 0; 
-    p_info_slave->b_unselected = 1; /* to correct audio */
-    p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK;
-} 
-/** -1 in case of error, 0 of EOF, 1 otherwise **/
-static int AVIDemux( input_thread_t *p_input )
+
+static int __AVI_GoToStreamBytes( input_thread_t    *p_input, 
+                                  AVIStreamInfo_t   *p_info,
+                                  int   i_byte )
 {
-    /* on cherche un block
-       plusieurs cas :
-        * encapsuler dans un chunk "rec "
-        * juste une succesion de 00dc 01wb ...
-        * pire tout audio puis tout video ou vice versa
-     */
-/* TODO :   * a better method to realign
-            * verify that we are reading in p_movi 
-            * XXX be sure to send audio before video to avoid click
-            * 
- */
-    riffchunk_t *p_chunk;
-    int i;
-    pes_packet_t *p_pes;
-    demux_data_avi_file_t *p_avi_demux;
+    u32   u32_pos;
+    off_t i_pos;
 
-    AVIStreamInfo_t *p_info_video;
-    AVIStreamInfo_t *p_info_audio;
-    AVIStreamInfo_t *p_info;
-    /* XXX arrive pas a avoir acces a cette fct° 
-    input_ClockManageRef( p_input,
-                            p_input->stream.p_selected_program,
-                            (mtime_t)0 ); */
-    p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
+    if( !p_input->stream.b_seekable )
+    {
+        intf_ErrMsg( "input error: need the ability to seek in stream" );
+        return( -1 );
+    }
 
-    /* search video and audio stream selected */
-    p_info_video = NULL;
-    p_info_audio = NULL;
-    
-    for( i = 0; i < p_avi_demux->i_streams; i++ )
+    /* now do we have valid index for the chunk */
+    if( p_info->p_index != NULL )
     {
-        if( p_avi_demux->pp_info[i]->p_es->p_decoder_fifo != NULL )
+        if( p_info->p_index[p_info->i_idxnb - 1].i_lengthtotal +
+            p_info->p_index[p_info->i_idxnb - 1].i_length <= i_byte)
         {
-            switch( p_avi_demux->pp_info[i]->p_es->i_cat )
+            p_info->i_idxposc = p_info->i_idxnb - 1;
+            while( p_info->p_index[p_info->i_idxposc].i_lengthtotal +
+                        p_info->p_index[p_info->i_idxposc].i_length <= i_byte)
             {
-                case( VIDEO_ES ):
-                    p_info_video = p_avi_demux->pp_info[i];
-                    break;
-                case( AUDIO_ES ):
-                    p_info_audio = p_avi_demux->pp_info[i];
-                    break;
+                if( __AVI_NextIndexEntry( p_input, p_info ) != 0)
+                {
+                    return( -1 );
+                }
             }
         }
         else
         {
-            p_avi_demux->pp_info[i]->b_unselected = 1;
+            /* uses dichototmie to be fast enougth */
+            int i_idxposc = p_info->i_idxposc;
+            int i_idxmax  = p_info->i_idxnb;
+            int i_idxmin  = 0;
+            for( ;; )
+            {
+                if( p_info->p_index[i_idxposc].i_lengthtotal > i_byte )
+                {
+                    i_idxmax  = i_idxposc ;
+                    i_idxposc = ( i_idxmin + i_idxposc ) / 2 ;
+                }
+                else
+                {
+                    if( p_info->p_index[i_idxposc].i_lengthtotal + 
+                            p_info->p_index[i_idxposc].i_length <= i_byte)
+                    {
+                        i_idxmin  = i_idxposc ;
+                        i_idxposc = (i_idxmax + i_idxposc ) / 2 ;
+                    }
+                    else
+                    {
+                        p_info->i_idxposc = i_idxposc;
+                       break;
+                   }
+                }
+            }
+        }
+
+        p_info->i_idxposb = i_byte - 
+                       p_info->p_index[p_info->i_idxposc].i_lengthtotal;
+        
+        i_pos = (off_t)p_info->p_index[p_info->i_idxposc].i_pos +
+                      p_info->i_idxposb + 8;
+        __RIFF_TellPos( p_input, &u32_pos );
+        if( u32_pos != i_pos )
+        {
+            p_input->pf_seek( p_input, i_pos );
+            input_AccessReinit( p_input );
         }
+        return( 0 );
     }
-    if( p_info_video == NULL )
+    else
     {
-        intf_ErrMsg( "input error: no video ouput selected" );
         return( -1 );
     }
-    if( input_ClockManageControl( p_input, p_input->stream.p_selected_program,
-                            (mtime_t)0) == PAUSE_S )
-    {   
-        __AVI_SynchroReInit( p_input, p_info_video, p_info_audio );
+}
+
+static pes_packet_t *__AVI_ReadStreamChunkInPES(  input_thread_t    *p_input,
+                                                  AVIStreamInfo_t   *p_info )
+{
+    pes_packet_t    *p_pes;
+    if( p_info->i_idxposc >= p_info->i_idxnb )
+    {
+        return( NULL );
     }
 
-    /* after updated p_avi_demux->pp_info[i]->b_unselected  !! */
-    if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
-    { 
-        /* TODO check if we have seek */
-        __AVI_ReAlign( p_input, p_info_video ); /*on se realigne pr la video */
-        __AVI_SynchroReInit( p_input, p_info_video, p_info_audio );
+    if( ( __AVI_GoToStreamChunk( p_input, p_info, p_info->i_idxposc ) != 0 )
+         ||( RIFF_LoadChunkDataInPES( p_input, &p_pes) != 0 ) )
+    {
+        return( NULL );
+    }
+    else
+    {
+      __AVI_NextIndexEntry( p_input, p_info);
+      p_info->i_idxposb = 0;
+      return( p_pes );
     }
+}
+
+static pes_packet_t *__AVI_ReadStreamBytesInPES(  input_thread_t    *p_input,
+                                                  AVIStreamInfo_t   *p_info,
+                                                  int i_byte )
+{
+    pes_packet_t    *p_pes = NULL;
+    data_packet_t   *p_data;
+    int             i_read;
 
-     /* update i_date if previously unselected ES (ex: 2 channels audio ) */
-    if( (p_info_audio != NULL)&&(p_info_audio->b_unselected ))
+    if( ( p_pes = input_NewPES( p_input->p_method_data ) ) == NULL )
     {
-        /* we have to go to the good pts */
-        /* we will reach p_info_ok pts */
-        while( __AVI_GetPTS( p_info_audio) < __AVI_GetPTS( p_info_video) )
+        return( NULL );
+    }
+    
+    while( i_byte > 0 )
+    {
+        if( p_info->i_idxposc >= p_info->i_idxnb )
+        {
+            input_DeletePES( p_input->p_method_data, p_pes );
+            return( NULL );
+        }
+        if( __AVI_GoToStreamBytes( p_input, p_info, 
+                       p_info->p_index[p_info->i_idxposc].i_lengthtotal + 
+                        p_info->i_idxposb ) != 0 )
+        {
+            input_DeletePES( p_input->p_method_data, p_pes );
+            return( NULL );
+        }
+
+        i_read = input_SplitBuffer(p_input, &p_data,
+                                 __MIN( i_byte, 
+                                 p_info->p_index[p_info->i_idxposc].i_length 
+                                    - p_info->i_idxposb ) );
+        if( i_read <= 0 )
+        {
+            input_DeletePES( p_input->p_method_data, p_pes );
+            return( NULL );
+        }
+        p_pes->i_nb_data++;
+        if( !p_pes->p_first )
+        {
+            p_pes->p_first = p_data;
+        }
+        else
         {
-            __AVI_NextIndexEntry( p_input, p_info_audio );
+            p_pes->p_last->p_next = p_data;
         }
-       p_info_audio->b_unselected = 0 ;
+        p_pes->p_last = p_data;
+        p_pes->i_pes_size += i_read;
+
+        i_byte -= i_read;
+        p_info->i_idxposb += i_read;
+
+        if( p_info->i_idxposb >= p_info->p_index[p_info->i_idxposc].i_length )
+        {
+            p_info->i_idxposb = 0;
+            if( __AVI_NextIndexEntry( p_input, p_info) != 0 )
+            {
+                input_DeletePES( p_input->p_method_data, p_pes );
+                return( NULL );
+            }
+        }
+    };
+   return( p_pes );
+}
+        
+/*****************************************************************************
+ * Function to convert pts to chunk or byte
+ *****************************************************************************/
+
+static inline mtime_t __AVI_PTSToChunk( AVIStreamInfo_t *p_info, 
+                                        mtime_t i_pts )
+{
+    return( (mtime_t)((double)i_pts *
+                      (double)p_info->header.i_rate /
+                      (double)p_info->header.i_scale /
+                      (double)1000000.0 ) );
+}
+
+static inline mtime_t __AVI_PTSToByte( AVIStreamInfo_t *p_info,
+                                       mtime_t i_pts )
+{
+    return( (mtime_t)((double)i_pts * 
+                      (double)p_info->header.i_samplesize *
+                      (double)p_info->header.i_rate /
+                      (double)p_info->header.i_scale /
+                      (double)1000000.0 ) );
+
+}
+
+/* try to realign after a seek */
+static int AVI_ReAlign( input_thread_t *p_input )
+{
+    u32     u32_pos;
+    off_t   i_pos;
+    int     b_after = 0;
+    AVIStreamInfo_t *p_info;
+    demux_data_avi_file_t *p_avi_demux =
+                        (demux_data_avi_file_t*)p_input->p_demux_data;
+
+    p_info = (p_avi_demux->p_info_video != NULL ) ? 
+                    p_avi_demux->p_info_video :
+                    p_avi_demux->p_info_audio;
+    
+    __RIFF_TellPos( p_input, &u32_pos );
+    
+    i_pos = (off_t)u32_pos;
+    
+    if( i_pos <= p_info->p_index[0].i_pos )
+    {
+        /*  before beginning of stream  */
+        if( !p_info->header.i_samplesize )
+        {
+            __AVI_GoToStreamChunk( p_input, 
+                                   p_info,
+                                   0 );
+        } 
+        else
+        {
+            __AVI_GoToStreamBytes( p_input, 
+                                   p_info, 
+                                   0);
+        }
+        return( 0 );
     }
-  
-    /* what stream we should read in first */
-    if( p_info_audio == NULL )
+
+    if( (p_info->p_index[p_info->i_idxposc].i_pos <= i_pos)
+        && ( i_pos < p_info->p_index[p_info->i_idxposc].i_pos +
+                p_info->p_index[p_info->i_idxposc].i_length ) )
+    {
+        /* FIXME if master == audio and samplesize != 0 */
+        /* don't work with big chunk */
+        /* don't do anything we are in the current chunk  */
+        return( 0 );
+    }
+    if( i_pos < p_info->p_index[p_info->i_idxposc].i_pos )
     {
-        p_info = p_info_video;
+        b_after = 0;
     }
     else
     {
-        if( __AVI_GetPTS( p_info_audio ) <= 
-                        __AVI_GetPTS( p_info_video ) )
+        b_after = 1;
+    }
+    /* now find in what chunk we are */
+    while( ( i_pos < p_info->p_index[p_info->i_idxposc].i_pos )
+           &&( p_info->i_idxposc > 0 ) )
+    {
+        /* search before i_idxposc */
+        p_info->i_idxposc--;
+    }
+    
+    while( i_pos >= p_info->p_index[p_info->i_idxposc].i_pos +
+               p_info->p_index[p_info->i_idxposc].i_length + 8 )
+    {
+        /* search after i_idxposc */
+        if( __AVI_NextIndexEntry( p_input, p_info ) != 0 )
+        {
+            return( -1 );
+        }
+    }
+    /* search nearest key frame */
+    if( ( !p_info->header.i_samplesize ) && ( p_info->i_cat == VIDEO_ES ) )
+    {
+        /* only for chunk stream */
+        if( b_after )
+        {
+            while(!(p_info->p_index[p_info->i_idxposc].i_flags&AVIIF_KEYFRAME) )
+            {
+                if( __AVI_NextIndexEntry( p_input, p_info ) != 0 )
+                {
+                    break;
+                }
+            }
+        }
+        else
+        { 
+            while( ( p_info->i_idxposc > 0 ) &&
+              (!(p_info->p_index[p_info->i_idxposc].i_flags&AVIIF_KEYFRAME)) )
+            {
+                p_info->i_idxposc--;
+            }
+        }
+    } 
+    __AVI_GoToStreamChunk( p_input, p_info, p_info->i_idxposc );
+   
+    return( 0 );
+}
+
+/* make difference between audio and video pts as little as possible */
+static void AVI_SynchroReInit( input_thread_t *p_input )
+{
+    demux_data_avi_file_t *p_avi_demux =
+                        (demux_data_avi_file_t*)p_input->p_demux_data;
+#define p_info_video p_avi_demux->p_info_video
+#define p_info_audio p_avi_demux->p_info_audio
+    if( ( p_info_video )&&( p_info_audio ) )
+    {
+        /* now resynch audio video video */
+        /*don't care of AVIF_KEYFRAME */
+        if( !p_info_audio->header.i_samplesize )
         {
-            p_info = p_info_audio;
+            int i_chunk = __AVI_PTSToChunk( p_info_audio, 
+                                            AVI_GetPTS( p_info_video ));
+            __AVI_GoToStreamChunk( p_input, 
+                                   p_info_audio, 
+                                   i_chunk );
         }
         else
         {
-            p_info = p_info_video;
+            int i_byte = __AVI_PTSToByte( p_info_audio, 
+                                          AVI_GetPTS( p_info_video ) ) ;
+            __AVI_GoToStreamBytes( p_input,
+                                   p_info_audio,
+                                   i_byte );
         }
+   }
+#undef p_info_video
+#undef p_info_audio
+} 
+
+/*****************************************************************************
+ * AVI_GetFrameInPES : get dpts length(µs) in pes from stream
+ *****************************************************************************
+ * Handle multiple pes, and set pts to the good value 
+ *****************************************************************************/
+static pes_packet_t *AVI_GetFrameInPES( input_thread_t *p_input,
+                                        AVIStreamInfo_t *p_info,
+                                        mtime_t i_dpts)
+{
+    int i;
+    pes_packet_t *p_pes = NULL;
+    pes_packet_t *p_pes_tmp = NULL;
+    pes_packet_t *p_pes_first = NULL;
+    mtime_t i_pts;
+
+    /* we now that p_info != NULL */
+    if( i_dpts < 1000 ) 
+    { 
+        return( NULL ) ; 
     }
 
-    /* go to the good chunk to read */
+    if( !p_info->header.i_samplesize )
+    {
+        /* stream is chunk based , easy */
+        int i_chunk = __MAX( __AVI_PTSToChunk( p_info, i_dpts), 1 );
+        /* at least one frame */
+        /* read them */
+        p_pes_first = NULL;
+        for( i = 0; i < i_chunk; i++ )
+        {
+            /* get pts while is valid */
+            i_pts = AVI_GetPTS( p_info );
+            p_pes_tmp = __AVI_ReadStreamChunkInPES( p_input, p_info );
 
-    __AVI_SeekToChunk( p_input, p_info );
-    
-    /* now we just need to read a chunk */
-    if( (p_chunk = RIFF_ReadChunk( p_input )) == NULL )
-    {   
-        intf_ErrMsg( "input demux: cannot read chunk" );
-        return( -1 );
+            if( !p_pes_tmp )
+            {
+                return( p_pes_first );
+            }
+            p_pes_tmp->i_pts = i_pts;
+            if( !p_pes_first )
+            {
+                p_pes_first = p_pes_tmp;
+            }
+            else
+            {
+                p_pes->p_next = p_pes_tmp;
+            }
+            p_pes = p_pes_tmp;
+        }
+        return( p_pes_first );
     }
+    else
+    {
+        /* stream is byte based */
+        int i_byte = __AVI_PTSToByte( p_info, i_dpts);
+        if( !i_byte )
+        {
+            return( NULL );
+        }
+        /* at least one Kbyte */
+        /*i_byte = __MIN( 1024*1000, i_byte ); *//* but no more than 1000ko */
+        i_pts = AVI_GetPTS( p_info );
 
-    if( (p_chunk->i_id&0xFFFF0000) != 
-                    (p_info->p_index[p_info->i_idxpos].i_id&0xFFFF0000) )
+        p_pes = __AVI_ReadStreamBytesInPES( p_input, p_info, i_byte);
+        
+        if( p_pes != NULL )
+        {
+            p_pes->i_pts = i_pts;
+        }
+        return( p_pes );
+    }
+}
+/*****************************************************************************
+ * AVI_DecodePES : send a pes to decoder 
+ *****************************************************************************
+ * Handle multiple pes, and set pts to the good value 
+ *****************************************************************************/
+static inline void AVI_DecodePES( input_thread_t *p_input,
+                                  AVIStreamInfo_t *p_info,
+                                  pes_packet_t *p_pes )
+{
+    pes_packet_t    *p_pes_next;
+    /* input_decode want only one pes, but AVI_GetFrameInPES give
+          multiple pes so send one by one */
+    /* we now that p_info != NULL */
+    while( p_pes )
+    {
+        p_pes_next = p_pes->p_next;
+        p_pes->p_next = NULL;
+        p_pes->i_pts = input_ClockGetTS( p_input, 
+                                         p_input->stream.p_selected_program, 
+                                         p_pes->i_pts * 9/100);
+        input_DecodePES( p_info->p_es->p_decoder_fifo, p_pes );
+        p_pes = p_pes_next;
+    };
+  
+}
+
+/*****************************************************************************
+ * AVIDemux: reads and demuxes data packets
+ *****************************************************************************
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
+static int AVIDemux( input_thread_t *p_input )
+{
+    int i;
+    pes_packet_t *p_pes;
+    AVIStreamInfo_t *p_info_master;
+    AVIStreamInfo_t *p_info_slave;    
+
+    demux_data_avi_file_t *p_avi_demux = 
+                (demux_data_avi_file_t*)p_input->p_demux_data;
+
+    /* search new video and audio stream selected 
+          if current have been unselected*/
+    if( ( !p_avi_demux->p_info_video )
+            || ( !p_avi_demux->p_info_video->p_es->p_decoder_fifo ) )
     {
-        intf_WarnMsg( 2, "input demux: bad index entry" );
-        __AVI_NextIndexEntry( p_input, p_info );
-        return( 1 );
+        p_avi_demux->p_info_video = NULL;
+        for( i = 0; i < p_avi_demux->i_streams; i++ )
+        {
+            if( ( p_avi_demux->pp_info[i]->i_cat == VIDEO_ES )
+                  &&( p_avi_demux->pp_info[i]->p_es->p_decoder_fifo != NULL ) )
+            {
+                p_avi_demux->p_info_video = p_avi_demux->pp_info[i];
+                p_avi_demux->p_info_video->b_selected = 1;
+                break;
+            }
+        }
     }
-    
-    intf_WarnMsg( 6, "input demux: read %4.4s chunk %d bytes",
-                    (char*)&p_chunk->i_id,
-                    p_chunk->i_size);
-                    
-    if( RIFF_LoadChunkDataInPES(p_input, p_chunk, &p_pes) != 0 )
+    if( ( !p_avi_demux->p_info_audio )
+            ||( !p_avi_demux->p_info_audio->p_es->p_decoder_fifo ) )
     {
-        intf_ErrMsg( "input error: cannot read data" );
+        p_avi_demux->p_info_audio = NULL;
+        for( i = 0; i < p_avi_demux->i_streams; i++ )
+        {
+            if( ( p_avi_demux->pp_info[i]->i_cat == AUDIO_ES )
+                  &&( p_avi_demux->pp_info[i]->p_es->p_decoder_fifo != NULL ) )
+            {
+                p_avi_demux->p_info_audio = p_avi_demux->pp_info[i];
+                p_avi_demux->p_info_audio->b_selected = 1;
+                break;
+            }
+        }
+    }
+    /* by default video is master for resync audio (after a seek .. ) */
+    if( p_avi_demux->p_info_video )
+    {
+        p_info_master = p_avi_demux->p_info_video;
+        p_info_slave  = p_avi_demux->p_info_audio;
+    }
+    else
+    {
+        p_info_master = p_avi_demux->p_info_audio;
+        p_info_slave  = NULL;
+    }
+
+    if( !p_info_master ) 
+    {
+        intf_ErrMsg( "input error: no stream selected" );
         return( -1 );
     }
 
-    p_pes->i_rate = p_input->stream.control.i_rate; 
-    p_pes->i_pts = p_avi_demux->i_date + __AVI_GetPTS( p_info );
-    p_pes->i_dts = 0;
-    
-    __AVI_NextIndexEntry( p_input, p_info );
-    /* send to decoder */
-    vlc_mutex_lock( &p_info->p_es->p_decoder_fifo->data_lock );
-    if( p_info->p_es->p_decoder_fifo->i_depth >= MAX_PACKETS_IN_FIFO )
+    /* check for signal from interface */
+    if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
+    { 
+        /* we can supposed that is a seek */
+        /* first wait for empty buffer, arbitrary time */
+        msleep( DEFAULT_PTS_DELAY );
+        /* then try to realign in stream */
+        if( AVI_ReAlign( p_input ) != 0 )
+        {
+            return( 0 ); /* assume EOF */
+        }
+        AVI_SynchroReInit( p_input ); 
+    }
+    /* manage rate, if not default: skeep audio */
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    if( p_input->stream.control.i_rate != p_avi_demux->i_rate )
     {
-        /* Wait for the decoder. */
-        vlc_cond_wait( &p_info->p_es->p_decoder_fifo->data_wait, 
-                        &p_info->p_es->p_decoder_fifo->data_lock );
+        if( p_avi_demux->p_info_audio)
+        {
+             p_avi_demux->p_info_audio->b_selected = 1;
+        }
+        p_avi_demux->i_rate = p_input->stream.control.i_rate;
     }
-    vlc_mutex_unlock( &p_info->p_es->p_decoder_fifo->data_lock );
-    input_DecodePES( p_info->p_es->p_decoder_fifo, p_pes );
+    vlc_mutex_unlock( &p_input->stream.stream_lock );    
+    if( p_avi_demux->i_rate != DEFAULT_RATE )
+    {
+        p_info_slave = NULL;
+    }
+    /* take care of newly selected audio ES */
+    if( p_info_master->b_selected )
+    {
+        p_info_master->b_selected = 0;
+        AVI_SynchroReInit( p_input ); 
+    }
+    if( ( p_info_slave )&&( p_info_slave->b_selected ) )
+    {
+        p_info_slave->b_selected = 0;
+        AVI_SynchroReInit( p_input );
+    }
+
+    /* wait for the good time */
+    input_ClockManageRef( p_input,
+                          p_input->stream.p_selected_program,
+                          p_avi_demux->i_pcr ); 
+    /* calculate pcr, time when we must read the next data */
+    /* 9/100 kludge ->need to convert to 1/1000000 clock unit to 1/90000 */
+    if( p_info_slave )
+    {
+        p_avi_demux->i_pcr =  __MIN( AVI_GetPTS( p_info_master ),
+                                     AVI_GetPTS( p_info_slave ) ) * 9/100;
+    }
+    else
+    {
+        p_avi_demux->i_pcr =  AVI_GetPTS( p_info_master ) * 9/100;
+    }
+
+    /* get video and audio frames */
+    p_pes = AVI_GetFrameInPES( p_input,
+                               p_info_master,
+                               100000 ); /* 100 ms */
 
-    return( 1 );
+    AVI_DecodePES( p_input,
+                   p_info_master,
+                   p_pes);
 
+    if( p_info_slave )
+    {
+        p_pes = AVI_GetFrameInPES( p_input,
+                                   p_info_slave,
+                                   AVI_GetPTS( p_info_master ) -
+                                       AVI_GetPTS( p_info_slave));
+        AVI_DecodePES( p_input,
+                       p_info_slave,
+                       p_pes );
+    }
+    /* at the end ? */
+    return( p_info_master->i_idxposc >= p_info_master->i_idxnb ? 0 : 1 );
 }