]> git.sesse.net Git - vlc/blobdiff - plugins/avi/avi.c
* ALL: new module API. Makes a few things a lot simpler, and we gain
[vlc] / plugins / avi / avi.c
index 51b1d9d8204086e6715f5e2b4d52aeb85c494fc8..ed5bd7ee3945b821e3ebe373865e2a4c2f8a24c7 100644 (file)
@@ -2,7 +2,7 @@
  * avi.c : AVI file Stream input module for vlc
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: avi.c,v 1.10 2002/05/02 10:54:34 fenrir Exp $
+ * $Id: avi.c,v 1.33 2002/07/31 20:56:50 sam Exp $
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  * 
  * This program is free software; you can redistribute it and/or modify
 #include <errno.h>
 #include <sys/types.h>
 
-#include <videolan/vlc.h>
-
-#include "stream_control.h"
-#include "input_ext-intf.h"
-#include "input_ext-dec.h"
-#include "input_ext-plugins.h"
+#include <vlc/vlc.h>
+#include <vlc/input.h>
 
 #include "video.h"
 
-/*****************************************************************************
- * Constants
- *****************************************************************************/
+#include "libioRIFF.h"
+#include "avi.h"
 
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static void input_getfunctions( function_list_t * p_function_list );
-static int  AVIDemux         ( struct input_thread_s * );
-static int  AVIInit          ( struct input_thread_s * );
-static void AVIEnd           ( struct input_thread_s * );
-
-/*****************************************************************************
- * Build configuration tree.
- *****************************************************************************/
-MODULE_CONFIG_START
-MODULE_CONFIG_STOP
-
-MODULE_INIT_START
-    SET_DESCRIPTION( "RIFF-AVI Stream input" )
-    ADD_CAPABILITY( DEMUX, 150 )
-    ADD_SHORTCUT( "avi" )
-MODULE_INIT_STOP
+static int    AVIInit   ( vlc_object_t * );
+static void __AVIEnd    ( vlc_object_t * );
+static int    AVIDemux  ( input_thread_t * );
 
-MODULE_ACTIVATE_START
-    input_getfunctions( &p_module->p_functions->demux );
-MODULE_ACTIVATE_STOP
-
-MODULE_DEACTIVATE_START
-MODULE_DEACTIVATE_STOP
+#define AVIEnd(a) __AVIEnd(VLC_OBJECT(a))
 
 /*****************************************************************************
- * Definition of structures and libraries for this plugins 
+ * Module descriptor
  *****************************************************************************/
-#include "libLE.c"
-#include "libioRIFF.c"
-#include "avi.h"
+vlc_module_begin();
+    set_description( "RIFF-AVI demuxer" );
+    set_capability( "demux", 150 );
+    set_callbacks( AVIInit, __AVIEnd );
+vlc_module_end();
 
 /*****************************************************************************
- * Functions exported as capabilities. They are declared as static so that
- * we don't pollute the namespace too much.
+ * Some usefull functions to manipulate memory 
  *****************************************************************************/
-static void input_getfunctions( function_list_t * p_function_list )
+static u16 GetWLE( byte_t *p_buff )
 {
-#define input p_function_list->functions.demux
-    input.pf_init             = AVIInit;
-    input.pf_end              = AVIEnd;
-    input.pf_demux            = AVIDemux;
-    input.pf_rewind           = NULL;
-#undef input
+    u16 i;
+    i = (*p_buff) + ( *(p_buff + 1) <<8 );
+    return ( i );
 }
-
-/********************************************************************/
-
-
-static void __AVIFreeDemuxData( input_thread_t *p_input )
+static u32 GetDWLE( byte_t *p_buff )
 {
-    int i;
-    demux_data_avi_file_t *p_avi_demux;
-    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_avi_demux->p_riff );
-    if( p_avi_demux->p_hdrl != NULL ) 
-            RIFF_DeleteChunk( p_input, p_avi_demux->p_hdrl );
-    if( p_avi_demux->p_movi != NULL ) 
-            RIFF_DeleteChunk( p_input, p_avi_demux->p_movi );
-    if( p_avi_demux->p_idx1 != NULL ) 
-            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]
-                
-                if( p_info->p_index != NULL )
-                {
-                      free( p_info->p_index );
-                }
-                free( p_info ); 
-#undef  p_info
-            }
-        }
-         free( p_avi_demux->pp_info );
-    }
+    u32 i;
+    i = (*p_buff) + ( *(p_buff + 1) <<8 ) + 
+            ( *(p_buff + 2) <<16 ) + ( *(p_buff + 3) <<24 );
+    return ( i );
 }
-
-static void __AVI_Parse_avih( MainAVIHeader_t *p_avih, byte_t *p_buff )
+static u32 GetDWBE( byte_t *p_buff )
 {
-    p_avih->i_microsecperframe = __GetDoubleWordLittleEndianFromBuff( p_buff );
-    p_avih->i_maxbytespersec = __GetDoubleWordLittleEndianFromBuff( p_buff + 4);
-    p_avih->i_reserved1 = __GetDoubleWordLittleEndianFromBuff( p_buff + 8);
-    p_avih->i_flags = __GetDoubleWordLittleEndianFromBuff( p_buff + 12);
-    p_avih->i_totalframes = __GetDoubleWordLittleEndianFromBuff( p_buff + 16);
-    p_avih->i_initialframes = __GetDoubleWordLittleEndianFromBuff( p_buff + 20);
-    p_avih->i_streams = __GetDoubleWordLittleEndianFromBuff( p_buff + 24);
-    p_avih->i_suggestedbuffersize = 
-                        __GetDoubleWordLittleEndianFromBuff( p_buff + 28);
-    p_avih->i_width = __GetDoubleWordLittleEndianFromBuff( p_buff + 32 );
-    p_avih->i_height = __GetDoubleWordLittleEndianFromBuff( p_buff + 36 );
-    p_avih->i_scale = __GetDoubleWordLittleEndianFromBuff( p_buff + 40 );
-    p_avih->i_rate = __GetDoubleWordLittleEndianFromBuff( p_buff + 44 );
-    p_avih->i_start = __GetDoubleWordLittleEndianFromBuff( p_buff + 48);
-    p_avih->i_length = __GetDoubleWordLittleEndianFromBuff( p_buff + 52);
+    u32 i;
+    i = ((*p_buff)<<24) + ( *(p_buff + 1) <<16 ) + 
+            ( *(p_buff + 2) <<8 ) + ( *(p_buff + 3) );
+    return ( i );
 }
-
-static void __AVI_Parse_Header( AVIStreamHeader_t *p_strh, byte_t *p_buff )
+static inline off_t __EVEN( off_t i )
 {
-    p_strh->i_type = __GetDoubleWordLittleEndianFromBuff( p_buff );
-    p_strh->i_handler = __GetDoubleWordLittleEndianFromBuff( p_buff + 4 );
-    p_strh->i_flags = __GetDoubleWordLittleEndianFromBuff( p_buff + 8 );
-    p_strh->i_reserved1 = __GetDoubleWordLittleEndianFromBuff( p_buff + 12);
-    p_strh->i_initialframes = __GetDoubleWordLittleEndianFromBuff( p_buff + 16);
-    p_strh->i_scale = __GetDoubleWordLittleEndianFromBuff( p_buff + 20);
-    p_strh->i_rate = __GetDoubleWordLittleEndianFromBuff( p_buff + 24);
-    p_strh->i_start = __GetDoubleWordLittleEndianFromBuff( p_buff + 28);
-    p_strh->i_length = __GetDoubleWordLittleEndianFromBuff( p_buff + 32);
-    p_strh->i_suggestedbuffersize = 
-                        __GetDoubleWordLittleEndianFromBuff( p_buff + 36);
-    p_strh->i_quality = __GetDoubleWordLittleEndianFromBuff( p_buff + 40);
-    p_strh->i_samplesize = __GetDoubleWordLittleEndianFromBuff( p_buff + 44);
+    return( (i & 1) ? i+1 : i );
 }
 
-int avi_ParseBitMapInfoHeader( bitmapinfoheader_t *h, byte_t *p_data )
+
+/*****************************************************************************
+ * Functions for parsing the headers in an avi file
+ *****************************************************************************/
+static void AVI_Parse_avih( MainAVIHeader_t *p_avih, byte_t *p_buff )
 {
-    h->i_size          = __GetDoubleWordLittleEndianFromBuff( p_data );
-    h->i_width         = __GetDoubleWordLittleEndianFromBuff( p_data + 4 );
-    h->i_height        = __GetDoubleWordLittleEndianFromBuff( p_data + 8 );
-    h->i_planes        = __GetWordLittleEndianFromBuff( p_data + 12 );
-    h->i_bitcount      = __GetWordLittleEndianFromBuff( p_data + 14 );
-    h->i_compression   = __GetDoubleWordLittleEndianFromBuff( p_data + 16 );
-    h->i_sizeimage     = __GetDoubleWordLittleEndianFromBuff( p_data + 20 );
-    h->i_xpelspermeter = __GetDoubleWordLittleEndianFromBuff( p_data + 24 );
-    h->i_ypelspermeter = __GetDoubleWordLittleEndianFromBuff( p_data + 28 );
-    h->i_clrused       = __GetDoubleWordLittleEndianFromBuff( p_data + 32 );
-    h->i_clrimportant  = __GetDoubleWordLittleEndianFromBuff( p_data + 36 );
-    return( 0 );
+    p_avih->i_microsecperframe = GetDWLE( p_buff );
+    p_avih->i_maxbytespersec   = GetDWLE( p_buff + 4);
+    p_avih->i_reserved1        = GetDWLE( p_buff + 8);
+    p_avih->i_flags            = GetDWLE( p_buff + 12);
+    p_avih->i_totalframes      = GetDWLE( p_buff + 16);
+    p_avih->i_initialframes    = GetDWLE( p_buff + 20);
+    p_avih->i_streams          = GetDWLE( p_buff + 24);
+    p_avih->i_suggestedbuffersize = GetDWLE( p_buff + 28);
+    p_avih->i_width            = GetDWLE( p_buff + 32 );
+    p_avih->i_height           = GetDWLE( p_buff + 36 );
+    p_avih->i_scale            = GetDWLE( p_buff + 40 );
+    p_avih->i_rate             = GetDWLE( p_buff + 44 );
+    p_avih->i_start            = GetDWLE( p_buff + 48);
+    p_avih->i_length           = GetDWLE( p_buff + 52);
 }
-
-int avi_ParseWaveFormatEx( waveformatex_t *h, byte_t *p_data )
+static void AVI_Parse_Header( AVIStreamHeader_t *p_strh, byte_t *p_buff )
 {
-    h->i_formattag     = __GetWordLittleEndianFromBuff( p_data );
-    h->i_channels      = __GetWordLittleEndianFromBuff( p_data + 2 );
-    h->i_samplespersec = __GetDoubleWordLittleEndianFromBuff( p_data + 4 );
-    h->i_avgbytespersec= __GetDoubleWordLittleEndianFromBuff( p_data + 8 );
-    h->i_blockalign    = __GetWordLittleEndianFromBuff( p_data + 12 );
-    h->i_bitspersample = __GetWordLittleEndianFromBuff( p_data + 14 );
-    h->i_size          = __GetWordLittleEndianFromBuff( p_data + 16 );
-    return( 0 );
+    p_strh->i_type      = GetDWLE( p_buff );
+    p_strh->i_handler   = GetDWLE( p_buff + 4 );
+    p_strh->i_flags     = GetDWLE( p_buff + 8 );
+    p_strh->i_reserved1 = GetDWLE( p_buff + 12);
+    p_strh->i_initialframes = GetDWLE( p_buff + 16);
+    p_strh->i_scale     = GetDWLE( p_buff + 20);
+    p_strh->i_rate      = GetDWLE( p_buff + 24);
+    p_strh->i_start     = GetDWLE( p_buff + 28);
+    p_strh->i_length    = GetDWLE( p_buff + 32);
+    p_strh->i_suggestedbuffersize = GetDWLE( p_buff + 36);
+    p_strh->i_quality   = GetDWLE( p_buff + 40);
+    p_strh->i_samplesize = GetDWLE( p_buff + 44);
+}
+static void AVI_Parse_BitMapInfoHeader( bitmapinfoheader_t *h, byte_t *p_data )
+{
+    h->i_size          = GetDWLE( p_data );
+    h->i_width         = GetDWLE( p_data + 4 );
+    h->i_height        = GetDWLE( p_data + 8 );
+    h->i_planes        = GetWLE( p_data + 12 );
+    h->i_bitcount      = GetWLE( p_data + 14 );
+    h->i_compression   = GetDWLE( p_data + 16 );
+    h->i_sizeimage     = GetDWLE( p_data + 20 );
+    h->i_xpelspermeter = GetDWLE( p_data + 24 );
+    h->i_ypelspermeter = GetDWLE( p_data + 28 );
+    h->i_clrused       = GetDWLE( p_data + 32 );
+    h->i_clrimportant  = GetDWLE( p_data + 36 );
+}
+static void AVI_Parse_WaveFormatEx( waveformatex_t *h, byte_t *p_data )
+{
+    h->i_formattag     = GetWLE( p_data );
+    h->i_channels      = GetWLE( p_data + 2 );
+    h->i_samplespersec = GetDWLE( p_data + 4 );
+    h->i_avgbytespersec= GetDWLE( p_data + 8 );
+    h->i_blockalign    = GetWLE( p_data + 12 );
+    h->i_bitspersample = GetWLE( p_data + 14 );
+    h->i_size          = GetWLE( p_data + 16 );
 }
 
-static __inline__ int __AVIGetESTypeFromTwoCC( u16 i_type )
+static inline int AVI_GetESTypeFromTwoCC( u16 i_type )
 {
     switch( i_type )
     {
@@ -199,28 +152,236 @@ static __inline__ int __AVIGetESTypeFromTwoCC( u16 i_type )
          case( TWOCC_dc ):
          case( TWOCC_db ):
             return( VIDEO_ES );
+         default:
+            return( UNKNOWN_ES );
+    }
+}
+
+static vlc_fourcc_t AVI_AudioGetType( u32 i_type )
+{
+    switch( i_type )
+    {
+/*        case( WAVE_FORMAT_PCM ):
+            return VLC_FOURCC('l','p','c','m'); */
+        case( WAVE_FORMAT_AC3 ):
+            return VLC_FOURCC('a','5','2',' ');
+        case( WAVE_FORMAT_MPEG):
+        case( WAVE_FORMAT_MPEGLAYER3):
+            return VLC_FOURCC('m','p','g','a'); /* for mpeg2 layer 1 2 ou 3 */
+        default:
+            return 0;
+    }
+}
+
+/* Test if it seems that it's a key frame */
+static int AVI_GetKeyFlag( vlc_fourcc_t i_fourcc, u8 *p_byte )
+{
+    switch( i_fourcc )
+    {
+        case FOURCC_DIV1:
+        case FOURCC_div1:
+        case FOURCC_MPG4:
+        case FOURCC_mpg4:
+            if( GetDWBE( p_byte ) != 0x00000100 ) 
+            /* startcode perhaps swapped, I haven't tested */
+            {
+            /* it's seems it's not an msmpegv1 stream 
+               but perhaps I'm wrong so return yes */
+                return( AVIIF_KEYFRAME );
+            }
+            else
+            {
+                return( (*(p_byte+4))&0x06 ? 0 : AVIIF_KEYFRAME);
+            }
+        case FOURCC_DIV2:
+        case FOURCC_div2:
+        case FOURCC_MP42:
+        case FOURCC_mp42:
+        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:
+//            printf( "\n Is a Key Frame %s", (*p_byte)&0xC0 ? "no" : "yes!!" );
+            return( (*p_byte)&0xC0 ? 0 : AVIIF_KEYFRAME );
+        case FOURCC_DIVX:
+        case FOURCC_divx:
+        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:
+            if( GetDWBE( p_byte ) != 0x000001b6 )
+            {
+                /* not true , need to find the first VOP header
+                    but, I'm lazy */
+                return( AVIIF_KEYFRAME );
+            }
+            else
+            {
+//                printf( "\n Is a Key Frame %s", (*(p_byte+4))&0xC0 ? "no" : 
+//                                                                   "yes!!" );
+                return( (*(p_byte+4))&0xC0 ? 0 : AVIIF_KEYFRAME );
+            }
+        default:
+            /* I can't do it, so said yes */
+            return( AVIIF_KEYFRAME );
+    }
+
+}
+/*****************************************************************************
+ * Data and functions to manipulate pes buffer
+ *****************************************************************************/
+#define BUFFER_MAXTOTALSIZE   512*1024 /* 1/2 Mo */
+#define BUFFER_MAXSPESSIZE 1024*200
+static int  AVI_PESBuffer_IsFull( AVIStreamInfo_t *p_info )
+{
+    return( p_info->i_pes_totalsize > BUFFER_MAXTOTALSIZE ? 1 : 0);
+}
+static void AVI_PESBuffer_Add( input_buffers_t *p_method_data,
+                               AVIStreamInfo_t *p_info,
+                               pes_packet_t *p_pes,
+                               int i_posc,
+                               int i_posb )
+{
+    AVIESBuffer_t   *p_buffer_pes;
+
+    if( p_info->i_pes_totalsize > BUFFER_MAXTOTALSIZE )
+    {
+        input_DeletePES( p_method_data, p_pes );
+        return;
+    }
+    
+    if( !( p_buffer_pes = malloc( sizeof( AVIESBuffer_t ) ) ) )
+    {
+        input_DeletePES( p_method_data, p_pes );
+        return;
+    }
+    p_buffer_pes->p_next = NULL;
+    p_buffer_pes->p_pes = p_pes;
+    p_buffer_pes->i_posc = i_posc;
+    p_buffer_pes->i_posb = i_posb;
+
+    if( p_info->p_pes_last ) 
+    {
+        p_info->p_pes_last->p_next = p_buffer_pes;
     }
-    return( UNKNOWN_ES );
+    p_info->p_pes_last = p_buffer_pes;
+    if( !p_info->p_pes_first )
+    {
+        p_info->p_pes_first = p_buffer_pes;
+    }
+    p_info->i_pes_count++;
+    p_info->i_pes_totalsize += p_pes->i_pes_size;
 }
+static pes_packet_t *AVI_PESBuffer_Get( AVIStreamInfo_t *p_info )
+{
+    AVIESBuffer_t   *p_buffer_pes;
+    pes_packet_t    *p_pes;
+    if( p_info->p_pes_first )
+    {
+        p_buffer_pes = p_info->p_pes_first;
+        p_info->p_pes_first = p_buffer_pes->p_next;
+        if( !p_info->p_pes_first )
+        {
+            p_info->p_pes_last = NULL;
+        }
+        p_pes = p_buffer_pes->p_pes;
 
+        free( p_buffer_pes );
+        p_info->i_pes_count--;
+        p_info->i_pes_totalsize -= p_pes->i_pes_size;
+        return( p_pes );
+    }
+    else
+    {
+        return( NULL );
+    }
+}
+static int AVI_PESBuffer_Drop( input_buffers_t *p_method_data,
+                                AVIStreamInfo_t *p_info )
+{
+    pes_packet_t *p_pes = AVI_PESBuffer_Get( p_info );
+    if( p_pes )
+    {
+        input_DeletePES( p_method_data, p_pes );
+        return( 1 );
+    }
+    else
+    {
+        return( 0 );
+    }
+}
+static void AVI_PESBuffer_Flush( input_buffers_t *p_method_data,
+                                 AVIStreamInfo_t *p_info )
+{
+    while( p_info->p_pes_first )
+    {
+        AVI_PESBuffer_Drop( p_method_data, p_info );
+    }
+}
 
-static int __AVI_ParseStreamHeader( u32 i_id, int *i_number, u16 *i_type )
+static void AVI_ParseStreamHeader( u32 i_id, int *i_number, int *i_type )
 {
-    int c1,c2,c3,c4;
+    int c1,c2;
 
     c1 = ( i_id ) & 0xFF;
     c2 = ( i_id >>  8 ) & 0xFF;
-    c3 = ( i_id >> 16 ) & 0xFF;
-    c4 = ( i_id >> 24 ) & 0xFF;
 
     if( c1 < '0' || c1 > '9' || c2 < '0' || c2 > '9' )
     {
-        return( -1 );
+        *i_number = 100; /* > max stream number */
+        *i_type = 0;
     }
-    *i_number = (c1 - '0') * 10 + (c2 - '0' );
-    *i_type = ( c4 << 8) + c3;
-    return( 0 );
-}   
+    else
+    {
+        *i_number = (c1 - '0') * 10 + (c2 - '0' );
+        *i_type = ( i_id >> 16 ) & 0xFFFF;
+    }
+}
+
+/* Function to manipulate stream easily */
+static off_t AVI_TellAbsolute( input_thread_t *p_input )
+{
+    off_t i_pos;
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    i_pos= p_input->stream.p_selected_area->i_tell -
+            ( p_input->p_last_data - p_input->p_current_data  );
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+    return( i_pos );
+}
+                            
+static int AVI_SeekAbsolute( input_thread_t *p_input,
+                             off_t i_pos)
+{
+    off_t i_filepos;
+    /* FIXME add support for not seekable stream */
+
+    i_filepos = AVI_TellAbsolute( p_input );
+    if( i_pos != i_filepos )
+    {
+//        msg_Err( p_input, "Seek --> delta %d", i_pos - i_filepos );
+        p_input->pf_seek( p_input, i_pos );
+        input_AccessReinit( p_input );
+    }
+    return( 1 );
+}
+
 
 static void __AVI_AddEntryIndex( AVIStreamInfo_t *p_info,
                                  AVIIndexEntry_t *p_index)
@@ -240,7 +401,7 @@ static void __AVI_AddEntryIndex( AVIStreamInfo_t *p_info,
         p_tmp = realloc( (void*)p_info->p_index,
                            p_info->i_idxmax * 
                            sizeof( AVIIndexEntry_t ) );
-        if( p_tmp == NULL ) 
+        if( !p_tmp ) 
         { 
             p_info->i_idxmax -= 16384;
             return; 
@@ -264,195 +425,162 @@ 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;
     int             i_read;
     int             i;
     int             i_number;
-    u16             i_type;
+    int             i_type;
     int             i_totalentry = 0;
-    
-    p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data  ;    
+    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, 
                                    &p_idx1, 
                                    FOURCC_idx1)!=0 )
     {
-        intf_WarnMsg( 1, "input init: cannot find index" );
+        msg_Warn( p_input, "cannot find index" );
         RIFF_GoToChunk( p_input, p_avi_demux->p_hdrl );        
         return;
     }
     p_avi_demux->p_idx1 = p_idx1;
-    intf_WarnMsg( 1, "input init: loading index" ); 
+    msg_Dbg( p_input, "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 ) )
         {
-            intf_WarnMsg( 1,"input info: read %d idx chunk", i_totalentry );
+            msg_Dbg( p_input, "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_length = __GetDoubleWordLittleEndianFromBuff(p_peek+12);
+            index.i_id      = GetDWLE( p_peek );
+            index.i_flags   = GetDWLE( p_peek+4)&(~AVIIF_FIXKEYFRAME);
+            index.i_pos     = GetDWLE( p_peek+8);
+            index.i_length  = GetDWLE(p_peek+12);
+            AVI_ParseStreamHeader( index.i_id, &i_number, &i_type );
             
-            if( (__AVI_ParseStreamHeader( index.i_id, &i_number, &i_type ) != 0)
-             ||(i_number > p_avi_demux->i_streams)) 
+            if( ( i_number <  p_avi_demux->i_streams )
+               &&(p_avi_demux->pp_info[i_number]->i_cat == 
+                     AVI_GetESTypeFromTwoCC( 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 );
     }
 
 }
-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_idxposc < p_info->i_idxnb) )
-    {
-        off_t i_pos;
-        i_pos = (off_t)p_info->p_index[p_info->i_idxposc].i_offset +
-                    p_info->i_idxoffset;
-
-        p_input->pf_seek( p_input, i_pos );
-        input_AccessReinit( p_input );
-        return( 0 );
-    }
-    /* no index can't arrive but ...*/
-    intf_WarnMsg( 1, "input error: can't seek");
-    return( -1 );
-}
-
 
 /* XXX call after get p_movi */
-static void __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++ )
-    {
-#define p_info p_avi_demux->pp_info[i]
-        if( p_info->p_index == NULL ) 
+    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 file 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 ))
         {
-            intf_WarnMsg( 1, "input demux: can't find offset for stream %d",i);
-            continue;
+            b_start = 0;
+            break;
         }
-        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) )
+    }
+    if( !b_start )
+    {
+        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;
-}
-
-static int __AVI_AudioGetType( u32 i_type )
-{
-    switch( i_type )
-    {
-/*        case( WAVE_FORMAT_PCM ):
-            return( WAVE_AUDIO_ES ); */
-        case( WAVE_FORMAT_AC3 ):
-            return( AC3_AUDIO_ES );
-        case( WAVE_FORMAT_MPEG):
-        case( WAVE_FORMAT_MPEGLAYER3):
-            return( MPEG2_AUDIO_ES ); /* 2 for mpeg-2 layer 1 2 ou 3 */
-        default:
-            return( 0 );
     }
+#undef p_info
 }
 
-static int __AVI_VideoGetType( u32 i_type )
-{
-    switch( i_type )
+/*****************************************************************************
+ * AVIEnd: frees unused data
+ *****************************************************************************/
+static void __AVIEnd ( vlc_object_t * p_this )
+{   
+    input_thread_t *    p_input = (input_thread_t *)p_this;
+    int i;
+    demux_data_avi_file_t *p_avi_demux;
+    p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data  ; 
+    
+    if( p_avi_demux->p_riff ) 
+            RIFF_DeleteChunk( p_input, p_avi_demux->p_riff );
+    if( p_avi_demux->p_hdrl ) 
+            RIFF_DeleteChunk( p_input, p_avi_demux->p_hdrl );
+    if( p_avi_demux->p_movi ) 
+            RIFF_DeleteChunk( p_input, p_avi_demux->p_movi );
+    if( p_avi_demux->p_idx1 ) 
+            RIFF_DeleteChunk( p_input, p_avi_demux->p_idx1 );
+    if( p_avi_demux->pp_info )
     {
-        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 ):
-            return( MPEG4_VIDEO_ES );
-
-        default:
-            return( 0 );
+        for( i = 0; i < p_avi_demux->i_streams; i++ )
+        {
+            if( p_avi_demux->pp_info[i] ) 
+            {
+                if( p_avi_demux->pp_info[i]->p_index )
+                {
+                      free( p_avi_demux->pp_info[i]->p_index );
+                      AVI_PESBuffer_Flush( p_input->p_method_data, 
+                                           p_avi_demux->pp_info[i] );
+                }
+                free( p_avi_demux->pp_info[i] ); 
+            }
+        }
+         free( p_avi_demux->pp_info );
     }
 }
 
 /*****************************************************************************
  * AVIInit: check file and initializes AVI structures
  *****************************************************************************/
-static int AVIInit( input_thread_t *p_input )
-{
+static int AVIInit( vlc_object_t * p_this )
+{   
+    input_thread_t *    p_input = (input_thread_t *)p_this;
     riffchunk_t *p_riff,*p_hdrl,*p_movi;
     riffchunk_t *p_avih;
     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 */
-
     int i;
 
-    /* we need to seek to be able to readcorrectly */
-    if( !p_input->stream.b_seekable ) 
-    {
-        intf_ErrMsg( "input error: need the ability to seek in stream" );
-        return( -1 );
-    }
+    p_input->pf_demux = AVIDemux;
 
-    p_input->p_demux_data = 
-                p_avi_demux = malloc( sizeof(demux_data_avi_file_t) );
-    if( p_avi_demux == NULL )
+    if( !( p_input->p_demux_data = 
+                    p_avi_demux = malloc( sizeof(demux_data_avi_file_t) ) ) )
     {
-        intf_ErrMsg( "input error: not enough memory" );
+        msg_Err( p_input, "out of memory" );
         return( -1 );
     }
     memset( p_avi_demux, 0, sizeof( demux_data_avi_file_t ) );
+    p_avi_demux->i_rate = DEFAULT_RATE;
+    p_avi_demux->b_seekable = ( ( p_input->stream.b_seekable )
+                        &&( p_input->stream.i_method == INPUT_METHOD_FILE ) );
 
-    /* FIXME I don't know what it's do, copied from ESInit */
     /* Initialize access plug-in structures. */
     if( p_input->i_mtu == 0 )
     {
@@ -462,71 +590,70 @@ 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)" );
+        AVIEnd( p_input );
+        msg_Warn( p_input, "RIFF-AVI module discarded" );
         return( -1 );
     }
     p_avi_demux->p_riff = p_riff;
 
     if ( RIFF_DescendChunk(p_input) != 0 )
     {
-        __AVIFreeDemuxData( p_input );
-        intf_ErrMsg( "input error: cannot look for subchunk (avi_file)" );
+        AVIEnd( p_input );
+        msg_Err( p_input, "cannot look for subchunk" );
         return ( -1 );
     }
 
     /* it's a riff-avi file, so search for LIST-hdrl */
     if( RIFF_FindListChunk(p_input ,&p_hdrl,p_riff, FOURCC_hdrl) != 0 )
     {
-        __AVIFreeDemuxData( p_input );
-        intf_ErrMsg( "input error: cannot find \"LIST-hdrl\" (avi_file)" );
+        AVIEnd( p_input );
+        msg_Err( p_input, "cannot find \"LIST-hdrl\"" );
         return( -1 );
     }
     p_avi_demux->p_hdrl = p_hdrl;
 
     if( RIFF_DescendChunk(p_input) != 0 )
     {
-        __AVIFreeDemuxData( p_input );
-        intf_ErrMsg( "input error: cannot look for subchunk (avi_file)" );
+        AVIEnd( p_input );
+        msg_Err( p_input, "cannot look for subchunk" );
         return ( -1 );
     }
     /* in  LIST-hdrl search avih */
     if( RIFF_FindAndLoadChunk( p_input, p_hdrl, 
                                     &p_avih, FOURCC_avih ) != 0 )
     {
-        __AVIFreeDemuxData( p_input );
-        intf_ErrMsg( "input error: cannot find \"avih\" chunk (avi_file)" );
+        AVIEnd( p_input );
+        msg_Err( p_input, "cannot find \"avih\" chunk" );
         return( -1 );
     }
-    __AVI_Parse_avih( &p_avi_demux->avih, p_avih->p_data->p_payload_start );
+    AVI_Parse_avih( &p_avi_demux->avih, p_avih->p_data->p_payload_start );
     RIFF_DeleteChunk( p_input, p_avih );
     
     if( p_avi_demux->avih.i_streams == 0 )  
     /* no stream found, perhaps it would be cool to find it */
     {
-        __AVIFreeDemuxData( p_input );
-        intf_ErrMsg( "input error: no defined stream !" );
+        AVIEnd( p_input );
+        msg_Err( p_input, "no stream defined!" );
         return( -1 );
     }
 
     /*  create one program */
-    vlc_mutex_lock( &p_input->stream.stream_lock ); 
+    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" );
+        AVIEnd( p_input );
+        msg_Err( p_input, "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" );
+        AVIEnd( p_input );
+        msg_Err( p_input, "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 ); 
 
@@ -535,8 +662,9 @@ static int AVIInit( input_thread_t *p_input )
     
     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 );
+    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++ )
     {
@@ -548,8 +676,8 @@ static int AVIInit( input_thread_t *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)" );
+            AVIEnd( p_input );
+            msg_Err( p_input, "cannot find \"LIST-strl\"" );
             return( -1 );
         }
         
@@ -558,12 +686,12 @@ static int AVIInit( input_thread_t *p_input )
                                 &p_strh, FOURCC_strh ) != 0 )
         {
             RIFF_DeleteChunk( p_input, p_strl );
-            __AVIFreeDemuxData( p_input );
-            intf_ErrMsg( "input error: cannot find \"strh\" (avi_file)" );
+            AVIEnd( p_input );
+            msg_Err( p_input, "cannot find \"strh\"" );
             return( -1 );
         }
-        __AVI_Parse_Header( &p_info->header,
-                        p_strh->p_data->p_payload_start);
+        AVI_Parse_Header( &p_info->header,
+                            p_strh->p_data->p_payload_start);
         RIFF_DeleteChunk( p_input, p_strh );      
 
         /* in  LIST-strl search strf */
@@ -571,8 +699,8 @@ static int AVIInit( input_thread_t *p_input )
                                 &p_strf, FOURCC_strf ) != 0 )
         {
             RIFF_DeleteChunk( p_input, p_strl );
-            __AVIFreeDemuxData( p_input );
-            intf_ErrMsg( "input error: cannot find \"strf\" (avi_file)" );
+            AVIEnd( p_input );
+            msg_Err( p_input, "cannot find \"strf\"" );
             return( -1 );
         }
         /* we don't get strd, it's useless for divx,opendivx,mepgaudio */ 
@@ -580,8 +708,8 @@ static int AVIInit( input_thread_t *p_input )
         {
             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)" );
+            AVIEnd( p_input );
+            msg_Err( p_input, "cannot go out (\"strl\")" );
             return( -1 );
         }
 
@@ -597,38 +725,24 @@ static int AVIInit( input_thread_t *p_input )
         {
             case( FOURCC_auds ):
                 p_es->i_cat = AUDIO_ES;
-                avi_ParseWaveFormatEx( &p_info->audio_format,
+                AVI_Parse_WaveFormatEx( &p_info->audio_format,
                                    p_strf->p_data->p_payload_start ); 
-                p_es->b_audio = 1;
-                p_es->i_type = 
-                    __AVI_AudioGetType( p_info->audio_format.i_formattag );
-                if( p_es->i_type == 0 )
-                {
-                    intf_ErrMsg( "input error: stream(%d,0x%x) not supported",
-                                    i,
-                                    p_info->audio_format.i_formattag );
-                    p_es->i_cat = UNKNOWN_ES;
-                }
+                p_es->i_fourcc = AVI_AudioGetType(
+                                     p_info->audio_format.i_formattag );
                 break;
                 
             case( FOURCC_vids ):
                 p_es->i_cat = VIDEO_ES;
-                avi_ParseBitMapInfoHeader( &p_info->video_format,
+                AVI_Parse_BitMapInfoHeader( &p_info->video_format,
                                    p_strf->p_data->p_payload_start ); 
-                p_es->b_audio = 0;
-                p_es->i_type = 
-                    __AVI_VideoGetType( p_info->video_format.i_compression );
-                if( p_es->i_type == 0 )
-                {
-                    intf_ErrMsg( "input error: stream(%d,%4.4s) not supported",
-                               i,
-                               (char*)&p_info->video_format.i_compression);
-                    p_es->i_cat = UNKNOWN_ES;
-                }
+
+                /* XXX quick hack for playing ffmpeg video, I don't know 
+                    who is doing something wrong */
+                p_info->header.i_samplesize = 0;
+                p_es->i_fourcc = p_info->video_format.i_compression;
                 break;
             default:
-                intf_ErrMsg( "input error: unknown stream(%d) type",
-                            i );
+                msg_Err( p_input, "unknown stream(%d) type", i );
                 p_es->i_cat = UNKNOWN_ES;
                 break;
         }
@@ -648,109 +762,50 @@ static int AVIInit( input_thread_t *p_input )
     /* 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)" );
+        AVIEnd( p_input );
+        msg_Err( p_input, "cannot go out (\"hdrl\")" );
         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 );
+        msg_Err( p_input, "cannot find \"LIST-movi\"" );
+        AVIEnd( 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 )
+    if( p_avi_demux->b_seekable )
     {
         /* get index */
         __AVI_GetIndex( p_input ); 
         /* try to get i_idxoffset for each stream  */
-        __AVI_GetIndexOffset( p_input );
+        __AVI_UpdateIndexOffset( p_input );
+        /* to make sure to go the begining unless demux will see a seek */
+        RIFF_GoToChunk( p_input, p_avi_demux->p_movi );
+
     }
     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 )
-        {
-            intf_WarnMsg( 3, "input init: add index entry for stream %d", i ); 
-            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 ):
-                    p_info->i_idxoffset = 0;  /* ref: begining of file */
-                    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 ):
-                    p_info->i_idxoffset = 0;
-                    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_offset = p_chunk->i_pos;
-                index.i_length = p_chunk->i_size;
-                __AVI_AddEntryIndex( p_info, &index );
-            }
-        }
-#undef p_info
+        msg_Warn( p_input, "no index!" );
     }
 
-    /* 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)" );
+        AVIEnd( p_input );
+        msg_Err( p_input, "cannot go in (\"movi\")" );
         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":"" );
+    msg_Dbg( p_input, "AVIH: %d stream, flags %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":"" );
 
     for( i = 0; i < p_avi_demux->i_streams; i++ )
     {
@@ -758,534 +813,825 @@ static int AVIInit( input_thread_t *p_input )
         switch( p_info->p_es->i_cat )
         {
             case( VIDEO_ES ):
-                intf_Msg("input init: video(%4.4s) %dx%d %dbpp %ffps (size %d)",
-                        (char*)&p_info->video_format.i_compression,
-                        p_info->video_format.i_width,
-                        p_info->video_format.i_height,
-                        p_info->video_format.i_bitcount,
-                        (float)p_info->header.i_rate /
-                            (float)p_info->header.i_scale,
-                        p_info->header.i_samplesize );
+
+                msg_Dbg( p_input, "video(%4.4s) %dx%d %dbpp %ffps",
+                         (char*)&p_info->video_format.i_compression,
+                         p_info->video_format.i_width,
+                         p_info->video_format.i_height,
+                         p_info->video_format.i_bitcount,
+                         (float)p_info->header.i_rate /
+                             (float)p_info->header.i_scale );
                 if( (p_avi_demux->p_info_video == NULL) ) 
                 {
                     p_avi_demux->p_info_video = p_info;
-               }
+                    /* TODO add test to see if a decoder has been found */
+                    vlc_mutex_lock( &p_input->stream.stream_lock );
+                    input_SelectES( p_input, p_info->p_es );
+                    vlc_mutex_unlock( &p_input->stream.stream_lock );
+                }
                 break;
 
             case( AUDIO_ES ):
-                intf_Msg( "input init: audio(0x%x) %d channels %dHz %dbits %ffps (size %d)",
-                        p_info->audio_format.i_formattag,
-                        p_info->audio_format.i_channels,
-                        p_info->audio_format.i_samplespersec,
-                        p_info->audio_format.i_bitspersample,
-                        (float)p_info->header.i_rate /
-                            (float)p_info->header.i_scale,
-                        p_info->header.i_samplesize );
+                msg_Dbg( p_input, "audio(0x%x) %d channels %dHz %dbits",
+                         p_info->audio_format.i_formattag,
+                         p_info->audio_format.i_channels,
+                         p_info->audio_format.i_samplespersec,
+                         p_info->audio_format.i_bitspersample );
                 if( (p_avi_demux->p_info_audio == NULL) ) 
                 {
                     p_avi_demux->p_info_audio = p_info;
+                    vlc_mutex_lock( &p_input->stream.stream_lock );
+                    input_SelectES( p_input, p_info->p_es );
+                    vlc_mutex_unlock( &p_input->stream.stream_lock );
                 }
                 break;
-            case( UNKNOWN_ES ):
-                intf_Msg( "input init: unhanled stream %d", i );
+            default:
+                break;
         }
 #undef p_info    
     }
 
+
     /* we select the first audio and video ES */
     vlc_mutex_lock( &p_input->stream.stream_lock );
-    if( p_avi_demux->p_info_video != NULL ) 
-    {
-        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
-    {
-        /* TODO: if there is more than 1 video stream */
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
-        intf_ErrMsg( "input error: no video stream found !" );
-        return( -1 );
-    }
-    if( p_avi_demux->p_info_audio != NULL ) 
+    if( !p_avi_demux->p_info_video ) 
     {
-        input_SelectES( p_input, p_avi_demux->p_info_audio->p_es );
+        msg_Warn( p_input, "no video stream found" );
     }
-    else
+    if( !p_avi_demux->p_info_audio )
     {
-        intf_Msg( "input init: no audio stream found !" );
+        msg_Warn( p_input, "no audio stream found!" );
     }
     p_input->stream.p_selected_program->b_is_ok = 1;
     vlc_mutex_unlock( &p_input->stream.stream_lock );
 
-
     return( 0 );
 }
 
 
+
+
+
+
 /*****************************************************************************
- * AVIEnd: frees unused data
+ * Function to convert pts to chunk or byte
  *****************************************************************************/
-static void AVIEnd( input_thread_t *p_input )
-{   
-    __AVIFreeDemuxData( p_input ); 
-    return;
-}
-
 
-static mtime_t __AVI_GetPTS( AVIStreamInfo_t *p_info )
+static inline mtime_t AVI_PTSToChunk( AVIStreamInfo_t *p_info, 
+                                        mtime_t i_pts )
 {
-    /* XXX you need to add p_info->i_date to have correct pts */
-    /* p_info->p_index[p_info->i_idxposc] need to be valid !! */
-    mtime_t i_pts;
+    return( (mtime_t)((s64)i_pts *
+                      (s64)p_info->header.i_rate /
+                      (s64)p_info->header.i_scale /
+                      (s64)1000000 ) );
+}
+static inline mtime_t AVI_PTSToByte( AVIStreamInfo_t *p_info,
+                                       mtime_t i_pts )
+{
+    return( (mtime_t)((s64)i_pts * 
+                      (s64)p_info->header.i_samplesize *
+                      (s64)p_info->header.i_rate /
+                      (s64)p_info->header.i_scale /
+                      (s64)1000000 ) );
 
-    /* be careful to  *1000000 before round  ! */
-    if( p_info->header.i_samplesize != 0 )
+}
+static mtime_t AVI_GetPTS( AVIStreamInfo_t *p_info )
+{
+    
+    if( p_info->header.i_samplesize )
     {
-        i_pts = (mtime_t)( (double)1000000.0 *
-                   ((double)p_info->p_index[p_info->i_idxposc].i_lengthtotal +
-                    (double)p_info->i_idxposb ) *
-                    (double)p_info->header.i_scale /
-                    (double)p_info->header.i_rate /
-                    (double)p_info->header.i_samplesize );
+        /* we need a valid entry we will emulate one */
+        int i_len;
+        if( p_info->i_idxposc == p_info->i_idxnb )
+        {
+            if( p_info->i_idxposc )
+            {
+                /* use the last entry */
+                i_len = p_info->p_index[p_info->i_idxnb - 1].i_lengthtotal
+                            + p_info->p_index[p_info->i_idxnb - 1].i_length
+                            + p_info->i_idxposb; /* should be 0 */
+            }
+            else
+            {
+                i_len = p_info->i_idxposb; 
+                /* no valid entry use only offset*/
+            }
+        }
+        else
+        {
+            i_len = p_info->p_index[p_info->i_idxposc].i_lengthtotal
+                                + p_info->i_idxposb;
+        }
+        return( (mtime_t)( (s64)1000000 *
+                   (s64)i_len *
+                    (s64)p_info->header.i_scale /
+                    (s64)p_info->header.i_rate /
+                    (s64)p_info->header.i_samplesize ) );
     }
     else
     {
-        i_pts = (mtime_t)( (double)1000000.0 *
-                    (double)p_info->i_idxposc *
-                    (double)p_info->header.i_scale /
-                    (double)p_info->header.i_rate);
+        /* even if p_info->i_idxposc isn't valid, there isn't any probllem */
+        return( (mtime_t)( (s64)1000000 *
+                    (s64)(p_info->i_idxposc ) *
+                    (s64)p_info->header.i_scale /
+                    (s64)p_info->header.i_rate) );
     }
-    return( i_pts );
 }
 
 
+/*****************************************************************************
+ * Functions to acces streams data 
+ * Uses it, because i plane to read unseekable stream
+ * Don't work for the moment for unseekable stream 
+ * XXX NEVER set directly i_idxposc and i_idxposb unless you know what you do 
+ *****************************************************************************/
 
-static int __AVI_NextIndexEntry( input_thread_t *p_input, 
-                                  AVIStreamInfo_t *p_info )
+/* FIXME FIXME change b_pad to number of bytes to skipp after reading */
+static int __AVI_GetDataInPES( input_thread_t *p_input,
+                               pes_packet_t   **pp_pes,
+                               int i_size,
+                               int b_pad )
 {
-    AVIIndexEntry_t index;
-    riffchunk_t     *p_chunk;
-    demux_data_avi_file_t *p_avi_demux;
-    AVIStreamInfo_t *p_info_tmp;
-    int             i;
-    int             i_idxposc;
-    int             b_inc = 0;
-    p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
 
-    p_info->i_idxposc++;
+    int i_read;
+    data_packet_t *p_data;
 
-    if( p_info->i_idxposc < p_info->i_idxnb )
+    
+    if( !(*pp_pes = input_NewPES( p_input->p_method_data ) ) )
     {
         return( 0 );
     }
-    p_info->i_idxposc--;
-    /* create entry on the fly */
-    /* TODO: when parsing for a stream take care of the other to not do 
-       the same things two time */
-    /* search for the less advance stream and parse from it for all streams*/
-    p_info_tmp = p_info;
+
     
-    for( i = 0; i < p_avi_demux->i_streams; i++ )
+    if( !i_size )
     {
-#define p_info_i p_avi_demux->pp_info[i]
-        if( p_info_i->p_index[p_info_i->i_idxnb - 1].i_offset + 
-                        p_info_i->i_idxoffset < 
-            p_info_tmp->p_index[p_info_tmp->i_idxnb - 1].i_offset +
-                        p_info_tmp->i_idxoffset )
-        {
-            p_info_tmp = p_info_i;
-        }
-#undef  p_info_i
+        p_data = input_NewPacket( p_input->p_method_data, 0 );
+        (*pp_pes)->p_first = (*pp_pes)->p_last  = p_data;
+        (*pp_pes)->i_nb_data = 1;
+        (*pp_pes)->i_pes_size = 0;
+        return( 0 );
     }
-    /* 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 )
+    
+    if( ( i_size&1 )&&( b_pad ) )
     {
-        __AVI_SeekToChunk( p_input, p_info );
-        return( -1 );
+        b_pad = 1;
+        i_size++;
+    }
+    else
+    {
+        b_pad = 0;
     }
-    /* 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++)
+
+    do
     {
-        int i_number;
-        u16 i_type;
-        if( (p_chunk = RIFF_ReadChunk( p_input )) == NULL )
+        i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size - 
+                                                              (*pp_pes)->i_pes_size, 1024 ) );
+        if( i_read < 0 )
         {
-            if( b_inc )
-            {
-                return( 0 );
-            }
-            else
-            {
-                return( -1 );
-            }
+            return( (*pp_pes)->i_pes_size );
         }
-
-        index.i_id = p_chunk->i_id;
-        index.i_flags = AVIIF_KEYFRAME;
-        index.i_offset = 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->i_idxnb - 1].i_offset + 
-                     p_info_i->p_index[p_info_i->i_idxnb - 1].i_length + 8<= 
-                        index.i_offset ) 
-             &&( __AVIGetESTypeFromTwoCC( i_type ) == p_info_i->i_cat ) )
+        if( !(*pp_pes)->p_first )
         {
-            __AVI_AddEntryIndex( p_info_i, &index );
-            if( (p_info_i == p_info)&&(!b_inc) )
-            {
-                p_info->i_idxposc++;
-                b_inc = 1;
-            }
+            (*pp_pes)->p_first = 
+                    (*pp_pes)->p_last  = p_data;
+            (*pp_pes)->i_nb_data = 1;
+            (*pp_pes)->i_pes_size = i_read;
         }
-#undef  p_info_i
-        if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+        else
         {
-            if( b_inc )
-            {
-                return( 0 );
-            }
-            else
-            {
-                return( -1 );
-            }
+            (*pp_pes)->p_last->p_next = 
+                    (*pp_pes)->p_last = p_data;
+            (*pp_pes)->i_nb_data++;
+            (*pp_pes)->i_pes_size += i_read;
         }
-    } 
-    return( 0 );
+    } while( ((*pp_pes)->i_pes_size < i_size)&&( i_read ) );
+
+    if( b_pad )
+    {
+        (*pp_pes)->i_pes_size--;
+        (*pp_pes)->p_last->p_payload_end--;
+        i_size--;
+    }
+
+       return( i_size );
 }
 
-/*****************************************************************************
- * Functions to acces streams data 
- * Uses it, because i plane to read unseekable stream
- * Don't work for the moment for unseekable stream 
- *****************************************************************************/
+static int __AVI_SeekAndGetChunk( input_thread_t  *p_input,
+                                  AVIStreamInfo_t *p_info )
+{
+    pes_packet_t *p_pes;
+    int i_length, i_ret;
+    
+    i_length = __MIN( p_info->p_index[p_info->i_idxposc].i_length 
+                        - p_info->i_idxposb,
+                            BUFFER_MAXSPESSIZE );
+
+    AVI_SeekAbsolute( p_input, 
+                      (off_t)p_info->p_index[p_info->i_idxposc].i_pos + 
+                            p_info->i_idxposb + 8);
 
-/*      __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
+    i_ret = __AVI_GetDataInPES( p_input, &p_pes, i_length , 0);
+
+    if( i_ret != i_length )
+    {
+        return( 0 );
+    }
+    /*  TODO test key frame if i_idxposb == 0*/
+    AVI_PESBuffer_Add( p_input->p_method_data,
+                       p_info,
+                       p_pes,
+                       p_info->i_idxposc,
+                       p_info->i_idxposb );
+    return( 1 );
+}
+/* TODO check if it's correct (humm...) and optimisation ... */
+/* return 0 if we choose to get only the ck we want 
+ *        1 if index is invalid
+ *        2 if there is a ck_other before ck_info and the last proced ck_info*/
+/* XXX XXX XXX avi file is some BIG shit, and sometime index give 
+ * a refenrence to the same chunk BUT with a different size ( usually 0 )
  */
 
-static int __AVI_GoToStreamChunk( input_thread_t    *p_input, 
-                                  AVIStreamInfo_t   *p_info,
-                                  int   i_chunk )
+static inline int __AVI_GetChunkMethod( input_thread_t  *p_input,
+                                 AVIStreamInfo_t *p_info,
+                                 AVIStreamInfo_t *p_other )
 {
-    demux_data_avi_file_t *p_avi_demux;
-    u32   u32_pos;
-    off_t i_pos;
+    int i_info_pos;
+    int i_other_pos;
+    
+    int i_info_pos_last;
+    int i_other_pos_last;
 
-    p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
+    /*If we don't have a valid entry we need to parse from last 
+        defined chunk and it's the only way that we return 1*/
+    if( p_info->i_idxposc >= p_info->i_idxnb )
+    {
+        return( 1 );
+    }
+
+    /* KNOW we have a valid entry for p_info */
+    /* we return 0 if we haven't an valid entry for p_other */ 
+    if( ( !p_other )||( p_other->i_idxposc >= p_other->i_idxnb ) )
+    {
+        return( 0 );
+    }
+
+    /* KNOW there are 2 streams with valid entry */
+   
+    /* we return 0 if for one of the two streams we will not read 
+       chunk-aligned */
+    if( ( p_info->i_idxposb )||( p_other->i_idxposb ) )
+    { 
+        return( 0 );
+    }
+    
+    /* KNOW we have a valid entry for the 2 streams
+         and for the 2 we want an aligned chunk (given by i_idxposc )*/
+        /* if in stream, the next chunk is back than the one we 
+           have just read, it's useless to parse */
+    i_info_pos  = p_info->p_index[p_info->i_idxposc].i_pos;
+    i_other_pos = p_other->p_index[p_other->i_idxposc].i_pos ;
+
+    i_info_pos_last  = p_info->i_idxposc ? 
+                            p_info->p_index[p_info->i_idxposc - 1].i_pos : 0;
+    i_other_pos_last = p_other->i_idxposc ?
+                            p_other->p_index[p_other->i_idxposc - 1].i_pos : 0 ;
+   
     
-    if( !p_input->stream.b_seekable )
+    if( ( ( p_info->i_idxposc )&&( i_info_pos <= i_info_pos_last ) ) ||
+        ( ( p_other->i_idxposc )&&( i_other_pos <= i_other_pos_last ) ) )
     {
-        intf_ErrMsg( "input error: need the ability to seek in stream" );
-        return( -1 );
+        return( 0 );
+    }
+
+    /* KNOW for the 2 streams, the ck we want are after the last read 
+           or it's the first */
+
+    /* if the first ck_other we want isn't between ck_info_last 
+       and ck_info, don't parse */
+    /* TODO fix this, use also number in buffered PES */
+    if( ( i_other_pos > i_info_pos) /* ck_other too far */
+        ||( i_other_pos < i_info_pos_last ) ) /* it's too late for ck_other */
+    {
+        return( 0 );
+    } 
+   
+    /* we Know we will find ck_other, and before ck_info 
+        "if ck_info is too far" will be handle after */
+    return( 2 );
+}
+
+                         
+static inline int __AVI_ChooseSize( int l1, int l2 )
+{
+    /* XXX l2 is prefered if 0 otherwise min not equal to 0 */
+    if( !l2 )
+    { 
+        return( 0 );
+    }
+    return( !l1 ? l2 : __MIN( l1,l2 ) );
+}
+
+/* We know we will read chunk align */
+static int __AVI_GetAndPutChunkInBuffer( input_thread_t  *p_input,
+                                  AVIStreamInfo_t *p_info,
+                                  int i_size,
+                                  int i_ck )
+{
+
+    pes_packet_t    *p_pes;
+    int i_length; 
+
+    i_length = __MIN( i_size, BUFFER_MAXSPESSIZE );
+
+    /* Skip chunk header */
+
+    if( __AVI_GetDataInPES( p_input, &p_pes, i_length + 8,1 ) != i_length +8 )
+    {
+        return( 0 );
+    }
+    p_pes->p_first->p_payload_start += 8;
+    p_pes->i_pes_size -= 8;
+
+    i_size = GetDWLE( p_pes->p_first->p_demux_start + 4);
+
+    AVI_PESBuffer_Add( p_input->p_method_data,
+                       p_info,
+                       p_pes,
+                       i_ck,
+                       0 );
+    /* skip unwanted bytes */
+    if( i_length != i_size)
+    {
+        msg_Err( p_input, "Chunk Size mismatch" );
+        AVI_SeekAbsolute( p_input,
+                          __EVEN( AVI_TellAbsolute( p_input ) + 
+                                  i_size - i_length ) );
+    }
+    return( 1 );
+}
+
+/* XXX Don't use this function directly ! XXX */
+static int __AVI_GetChunk( input_thread_t  *p_input,
+                           AVIStreamInfo_t *p_info,
+                           int b_load )
+{
+    demux_data_avi_file_t *p_avi_demux =
+                        (demux_data_avi_file_t*)p_input->p_demux_data;
+    AVIStreamInfo_t *p_other;
+    int i_method;
+    off_t i_posmax;
+    int i;
+   
+#define p_info_i p_avi_demux->pp_info[i]
+    while( p_info->p_pes_first )
+    {
+        if( ( p_info->p_pes_first->i_posc == p_info->i_idxposc ) 
+             &&( p_info->i_idxposb >= p_info->p_pes_first->i_posb )
+             &&( p_info->i_idxposb < p_info->p_pes_first->i_posb + 
+                     p_info->p_pes_first->p_pes->i_pes_size ) )
+  
+        {
+            return( 1 ); /* we have it in buffer */
+        }
+        else
+        {
+            AVI_PESBuffer_Drop( p_input->p_method_data, p_info );
+        }
     }
+    /* up to now we handle only one audio and video streams at the same time */
+    p_other = (p_info == p_avi_demux->p_info_video ) ?
+                     p_avi_demux->p_info_audio : p_avi_demux->p_info_video ;
 
-    if( p_info->p_index != NULL )
+    i_method = __AVI_GetChunkMethod( p_input, p_info, p_other );
+
+    if( !i_method )
+    {
+        /* get directly the good chunk */
+        return( b_load ? __AVI_SeekAndGetChunk( p_input, p_info ) : 1 );
+    }
+    /* We will parse
+        * because invalid index
+        * or will find ck_other before ck_info 
+    */
+//    msg_Warn( p_input, "method %d", i_method ); 
+    /* we will calculate the better position we have to reach */
+    if( i_method == 1 )
     {
-        if( i_chunk >= p_info->i_idxnb )
+        /* invalid index */
+    /*  the position max we have already reached */
+        /* FIXME this isn't the better because sometime will fail to
+            put in buffer p_other since it could be too far */
+        AVIStreamInfo_t *p_info_max = p_info;
+        
+        for( i = 0; i < p_avi_demux->i_streams; i++ )
         {
-            p_info->i_idxposc = p_info->i_idxnb-1;
-            while( p_info->i_idxposc < i_chunk )
+            if( p_info_i->i_idxnb )
             {
-                if( __AVI_NextIndexEntry( p_input, p_info ) != 0)
+                if( p_info_max->i_idxnb )
                 {
-                    return( -1 );
+                    if( p_info_i->p_index[p_info_i->i_idxnb -1 ].i_pos >
+                            p_info_max->p_index[p_info_max->i_idxnb -1 ].i_pos )
+                    {
+                        p_info_max = p_info_i;
+                    }
+                }
+                else
+                {
+                    p_info_max = p_info_i;
                 }
             }
         }
-        else
+        if( p_info_max->i_idxnb )
         {
-            p_info->i_idxposc = i_chunk;
+            /* be carefull that size between index and ck can sometime be 
+              different without any error (and other time it's an error) */
+           i_posmax = p_info_max->p_index[p_info_max->i_idxnb -1 ].i_pos; 
+           /* so choose this, and I know that we have already reach it */
         }
-
-        /* 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_offset +
-                     p_info->i_idxoffset;
-        if( i_pos != u32_pos )
+        else
         {
-            p_input->pf_seek( p_input, i_pos );
-            input_AccessReinit( p_input );
+            i_posmax = p_avi_demux->p_movi->i_pos + 12;
         }
-        p_info->i_idxposb = 0;
-        return( 0 );
     }
     else
     {
-        return( -1 );
-    }
-}
-
-static int __AVI_GoToStreamBytes( input_thread_t    *p_input, 
-                                  AVIStreamInfo_t   *p_info,
-                                  int   i_byte )
-{
-    demux_data_avi_file_t *p_avi_demux;
-    u32   u32_pos;
-    off_t i_pos;
-    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 );
+        if( !b_load )
+        {
+            return( 1 ); /* all is ok */
+        }
+        /* valid index */
+        /* we know that the entry and the last one are valid for the 2 stream */
+        /* and ck_other will come *before* index so go directly to it*/
+        i_posmax = p_other->p_index[p_other->i_idxposc].i_pos;
     }
 
-    /* now do we have valid index for the chunk */
-    if( p_info->p_index != NULL )
+    AVI_SeekAbsolute( p_input, i_posmax );
+    /* the first chunk we will see is :
+            * the last chunk that we have already seen for broken index 
+            * the first ck for other with good index */ 
+    for( ; ; ) /* infinite parsing until the ck we want */
     {
-        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)
+        riffchunk_t  *p_ck;
+        int i_type;
+        
+        /* Get the actual chunk in the stream */
+        if( !(p_ck = RIFF_ReadChunk( p_input )) )
+        {
+            return( 0 );
+        }
+//        msg_Dbg( p_input, "ck: %4.4s len %d", &p_ck->i_id, p_ck->i_size );
+        /* special case for LIST-rec chunk */
+        if( ( p_ck->i_id == FOURCC_LIST )&&( p_ck->i_type == FOURCC_rec ) )
+        {
+            RIFF_DescendChunk( p_input );
+            RIFF_DeleteChunk( p_input, p_ck );
+            continue;
+        }
+        AVI_ParseStreamHeader( p_ck->i_id, &i, &i_type );
+        /* littles checks but not too much if you want to read all file */ 
+        if( i >= p_avi_demux->i_streams )
+        /* (AVI_GetESTypeFromTwoCC(i_type) != p_info_i->i_cat) perhaps add it*/
+            
         {
-            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)
+            RIFF_DeleteChunk( p_input, p_ck );
+            if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
             {
-                if( __AVI_NextIndexEntry( p_input, p_info ) != 0)
-                {
-                    return( -1 );
-                }
+                return( 0 );
             }
         }
         else
         {
-            /* 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( ;; )
+            int i_size;
+
+            /* have we found a new entry (not present in index)? */
+            if( ( !p_info_i->i_idxnb )
+                ||(p_info_i->p_index[p_info_i->i_idxnb-1].i_pos < p_ck->i_pos))
             {
-                if( p_info->p_index[i_idxposc].i_lengthtotal > i_byte )
+                AVIIndexEntry_t index;
+
+                index.i_id = p_ck->i_id;
+                index.i_flags = AVI_GetKeyFlag( p_info_i->p_es->i_fourcc,
+                                                (u8*)&p_ck->i_8bytes);
+                index.i_pos = p_ck->i_pos;
+                index.i_length = p_ck->i_size;
+                __AVI_AddEntryIndex( p_info_i, &index );   
+            }
+
+
+            /* TODO check if p_other is full and then if is possible 
+                go directly to the good chunk */
+            if( ( p_info_i == p_other )
+                &&( !AVI_PESBuffer_IsFull( p_other ) )
+                &&( ( !p_other->p_pes_last )||
+                    ( p_other->p_pes_last->p_pes->i_pes_size != 
+                                                    BUFFER_MAXSPESSIZE ) ) )
+            {
+                int i_ck = p_other->p_pes_last ? 
+                        p_other->p_pes_last->i_posc + 1 : p_other->i_idxposc;
+                i_size = __AVI_ChooseSize( p_ck->i_size,
+                                           p_other->p_index[i_ck].i_length);
+               
+                if( p_other->p_index[i_ck].i_pos == p_ck->i_pos )
                 {
-                    i_idxmax  = i_idxposc ;
-                    i_idxposc = ( i_idxmin + i_idxposc ) / 2 ;
+                    if( !__AVI_GetAndPutChunkInBuffer( p_input, p_other, 
+                                                       i_size, i_ck ) )
+                    {
+                        RIFF_DeleteChunk( p_input, p_ck );
+                        return( 0 );
+                    }
                 }
                 else
                 {
-                    if( p_info->p_index[i_idxposc].i_lengthtotal + 
-                            p_info->p_index[i_idxposc].i_length <= i_byte)
+                    if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
                     {
-                        i_idxmin  = i_idxposc ;
-                        i_idxposc = (i_idxmax + i_idxposc ) / 2 ;
+                        RIFF_DeleteChunk( p_input, p_ck );
+
+                        return( 0 );
                     }
-                    else
-                    {
-                        p_info->i_idxposc = i_idxposc;
-                       break;
-                   }
+
+                }
+                        
+                RIFF_DeleteChunk( p_input, p_ck );
+            }
+            else
+            if( ( p_info_i == p_info)
+                &&( p_info->i_idxposc < p_info->i_idxnb ) )
+            {
+                /* the first ck_info is ok otherwise it should be 
+                        loaded without parsing */
+                i_size = __AVI_ChooseSize( p_ck->i_size,
+                                 p_info->p_index[p_info->i_idxposc].i_length);
+
+
+                RIFF_DeleteChunk( p_input, p_ck );
+                
+                return( b_load ? __AVI_GetAndPutChunkInBuffer( p_input,
+                                                               p_info,
+                                                               i_size,
+                                                     p_info->i_idxposc ) : 1 );
+            }
+            else
+            {
+                /* skip it */
+                RIFF_DeleteChunk( p_input, p_ck );
+                if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+                {
+                    return( 0 );
                 }
             }
         }
 
-        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_offset +
-                     p_info->i_idxoffset + p_info->i_idxposb + 8;
-        __RIFF_TellPos( p_input, &u32_pos );
-        if( u32_pos != i_pos )
+    
+    }
+    
+#undef p_info_i
+}
+
+/* be sure that i_ck will be a valid index entry */
+static int AVI_SetStreamChunk( input_thread_t    *p_input,
+                               AVIStreamInfo_t   *p_info,
+                               int   i_ck )
+{
+
+    p_info->i_idxposc = i_ck;
+    p_info->i_idxposb = 0;
+
+    if(  i_ck < p_info->i_idxnb )
+    {
+        return( 1 );
+    }
+    else
+    {
+        p_info->i_idxposc = p_info->i_idxnb - 1;
+        do
         {
-            p_input->pf_seek( p_input, i_pos );
-            input_AccessReinit( p_input );
+            p_info->i_idxposc++;
+            if( !__AVI_GetChunk( p_input, p_info, 0 ) )
+            {
+                return( 0 );
+            }
+        } while( p_info->i_idxposc < i_ck );
+
+        return( 1 );
+    }
+}
+
+
+/* XXX FIXME up to now, we assume that all chunk are one after one */
+static int AVI_SetStreamBytes( input_thread_t    *p_input, 
+                               AVIStreamInfo_t   *p_info,
+                               off_t   i_byte )
+{
+    if( ( p_info->i_idxnb > 0 )
+        &&( i_byte < p_info->p_index[p_info->i_idxnb - 1].i_lengthtotal + 
+                p_info->p_index[p_info->i_idxnb - 1].i_length ) )
+    {
+        /* index is valid to find the ck */
+        /* uses dichototmie to be fast enougth */
+        int i_idxposc = __MIN( p_info->i_idxposc, p_info->i_idxnb - 1 );
+        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;
+                    p_info->i_idxposb = i_byte - 
+                            p_info->p_index[i_idxposc].i_lengthtotal;
+                    return( 1 );
+                }
+            }
         }
-        return( 0 );
+        
     }
     else
     {
-        return( -1 );
+        p_info->i_idxposc = p_info->i_idxnb - 1;
+        p_info->i_idxposb = 0;
+        do
+        {
+            p_info->i_idxposc++;
+            if( !__AVI_GetChunk( p_input, p_info, 0 ) )
+            {
+                return( 0 );
+            }
+        } while( p_info->p_index[p_info->i_idxposc].i_lengthtotal +
+                    p_info->p_index[p_info->i_idxposc].i_length <= i_byte );
+
+        p_info->i_idxposb = i_byte -
+                       p_info->p_index[p_info->i_idxposc].i_lengthtotal;
+        return( 1 );
     }
 }
 
-static pes_packet_t *__AVI_ReadStreamChunkInPES(  input_thread_t    *p_input,
-                                                AVIStreamInfo_t   *p_info )
+static pes_packet_t *AVI_ReadStreamChunkInPES(  input_thread_t  *p_input,
+                                                AVIStreamInfo_t *p_info )
+
 {
-    pes_packet_t    *p_pes;
-    if( ( __AVI_GoToStreamChunk( p_input, p_info, p_info->i_idxposc ) != 0 )
-         ||( RIFF_LoadChunkDataInPES( p_input, &p_pes) != 0 ) )
+    if( p_info->i_idxposc > p_info->i_idxnb )
     {
         return( NULL );
     }
-    else
+
+    /* we want chunk (p_info->i_idxposc,0) */
+    p_info->i_idxposb = 0;
+    if( !__AVI_GetChunk( p_input, p_info, 1) )
     {
-      __AVI_NextIndexEntry( p_input, p_info);
-      p_info->i_idxposb = 0;
-      return( p_pes );
+        msg_Err( p_input, "Got one chunk : failed" );
+        return( NULL );
     }
+    p_info->i_idxposc++;
+    return( AVI_PESBuffer_Get( p_info ) );
 }
 
-static pes_packet_t *__AVI_ReadStreamBytesInPES(  input_thread_t    *p_input,
-                                                  AVIStreamInfo_t   *p_info,
-                                                  int i_byte )
+static pes_packet_t *AVI_ReadStreamBytesInPES(  input_thread_t  *p_input,
+                                                AVIStreamInfo_t *p_info,
+                                                int i_byte )
 {
     pes_packet_t    *p_pes;
     data_packet_t   *p_data;
+    int             i_count = 0;
     int             i_read;
-    /* make one pes with one data_packet with all the data */
-    if( ( p_pes = input_NewPES( p_input->p_method_data ) ) == NULL )
+
+        
+    if( !( p_pes = input_NewPES( p_input->p_method_data ) ) )
     {
         return( NULL );
     }
-    p_pes->i_nb_data = 1;
-    if( (p_pes->p_first =
-            p_pes->p_last = 
-                input_NewPacket( p_input->p_method_data, i_byte ) ) ==NULL )
+fprintf(stderr, "blah ibyte %i\n", i_byte);
+    if( !( p_data = input_NewPacket( p_input->p_method_data, i_byte ) ) )
     {
         input_DeletePES( p_input->p_method_data, p_pes );
         return( NULL );
     }
-    
-    do
+
+    p_pes->p_first =
+            p_pes->p_last = p_data;
+    p_pes->i_nb_data = 1;
+    p_pes->i_pes_size = i_byte;
+
+    while( i_byte > 0 )
     {
-        if( __AVI_GoToStreamBytes( p_input, p_info, 
-                       p_info->p_index[p_info->i_idxposc].i_lengthtotal + 
-                        p_info->i_idxposb ) != 0 )
+        if( !__AVI_GetChunk( p_input, p_info, 1) )
         {
-            input_DeletePacket( p_input->p_method_data, p_pes->p_first );
+         msg_Err( p_input, "Got one chunk : failed" );
+           
             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 )
-        {
-           p_pes->p_first->p_demux_start = p_pes->p_first->p_payload_start;
-           p_pes->i_pes_size = p_pes->p_first->p_payload_end
-                                - p_pes->p_first->p_payload_start;
-           return( p_pes );
-        }
-        FAST_MEMCPY( p_pes->p_first->p_demux_start, 
-                     p_data->p_demux_start,
-                     i_read );
-        i_byte -= i_read;
+
+        i_read = __MIN( p_info->p_pes_first->p_pes->i_pes_size - 
+                            ( p_info->i_idxposb - p_info->p_pes_first->i_posb ),
+                        i_byte);
+        /* FIXME FIXME FIXME follow all data packet */
+        memcpy( p_data->p_payload_start + i_count, 
+                p_info->p_pes_first->p_pes->p_first->p_payload_start + 
+                    p_info->i_idxposb - p_info->p_pes_first->i_posb,
+                i_read );
+
+        AVI_PESBuffer_Drop( p_input->p_method_data, p_info );
+        i_byte  -= i_read;
+        i_count += i_read;
+
         p_info->i_idxposb += i_read;
-        p_pes->p_first->p_demux_start += i_read;
-        if( p_info->i_idxposb >= p_info->p_index[p_info->i_idxposc].i_length )
+        if( p_info->p_index[p_info->i_idxposc].i_length <= p_info->i_idxposb )
         {
-            p_info->i_idxposb = 0;
-            __AVI_NextIndexEntry( p_input, p_info);
+            p_info->i_idxposb -= p_info->p_index[p_info->i_idxposc].i_length;
+            p_info->i_idxposc++;
         }
-        input_DeletePacket( p_input->p_method_data, p_data );
-    } while( i_byte > 0 );
-   p_pes->p_first->p_demux_start = p_pes->p_first->p_payload_start;
-   p_pes->i_pes_size = p_pes->p_first->p_payload_end
-                        - p_pes->p_first->p_payload_start;
+    }
    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)((mtime_t)i_pts *
-                      (mtime_t)p_info->header.i_rate /
-                      (mtime_t)p_info->header.i_scale /
-                      (mtime_t)1000000.0 ) );
-}
-
-static __inline__ mtime_t __AVI_PTSToByte( AVIStreamInfo_t *p_info,
-                                   mtime_t i_pts )
-{
-    return( (mtime_t)((mtime_t)i_pts * 
-                      (mtime_t)p_info->header.i_samplesize *
-                      (mtime_t)p_info->header.i_rate /
-                      (mtime_t)p_info->header.i_scale /
-                      (mtime_t)1000000.0 ) );
-
-}
 
 /* try to realign after a seek */
-static int __AVI_ReAlign( input_thread_t *p_input )
+static int AVI_ReAlign( input_thread_t *p_input,
+                        AVIStreamInfo_t *p_info )
 {
-    u32     u32_pos;
+    int i;
     off_t   i_pos;
     int     b_after = 0;
-    demux_data_avi_file_t *p_avi_demux;
-    AVIStreamInfo_t *p_info;
+    demux_data_avi_file_t *p_avi_demux =
+                        (demux_data_avi_file_t*)p_input->p_demux_data;
 
-    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 - (off_t)p_info->i_idxoffset;
-    
-    if( i_pos <= p_info->p_index[0].i_offset )
-    {
-        /*  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 );
-    }
 
-    if( (p_info->p_index[p_info->i_idxposc].i_offset <= i_pos)
-        && ( i_pos < p_info->p_index[p_info->i_idxposc].i_offset +
-                p_info->p_index[p_info->i_idxposc].i_length ) )
-    {
-        /* don't do anything we are in the current chunk  */
-        return( 0 );
-    }
-    if( i_pos < p_info->p_index[p_info->i_idxposc].i_offset )
+    for( i = 0; i < p_avi_demux->i_streams; i++ )
     {
-        b_after = 0;
+        AVI_PESBuffer_Flush( p_input->p_method_data, p_avi_demux->pp_info[i] );
     }
-    else
+    /* Reinit clock
+       TODO use input_ClockInit instead but need to be exported 
+    p_input->stream.p_selected_program->last_cr = 0;
+    p_input->stream.p_selected_program->last_syscr = 0;
+    p_input->stream.p_selected_program->cr_ref = 0;
+    p_input->stream.p_selected_program->sysdate_ref = 0;
+    p_input->stream.p_selected_program->delta_cr = 0;
+    p_input->stream.p_selected_program->c_average_count = 0; */
+       
+    i_pos = AVI_TellAbsolute( p_input );
+
+    p_info->i_idxposc--; /* in fact  p_info->i_idxposc is for ck to be read */
+    
+
+    if( ( p_info->i_idxposc <= 0)
+        ||( i_pos <= p_info->p_index[0].i_pos ) )
     {
-        b_after = 1;
+        /*  before beginning of stream  */
+        return( p_info->header.i_samplesize ?
+                    AVI_SetStreamBytes( p_input, p_info, 0 ) :
+                        AVI_SetStreamChunk( p_input, p_info, 0 ) );
     }
+    
+    b_after = ( i_pos >= p_info->p_index[p_info->i_idxposc].i_pos );
     /* now find in what chunk we are */
-    while( ( i_pos < p_info->p_index[p_info->i_idxposc].i_offset )
+    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--;
+
+        if( !AVI_SetStreamChunk( p_input, p_info, p_info->i_idxposc - 1 ) )
+        {
+            return( 0 );   
+        }
     }
     
-    while( i_pos >= p_info->p_index[p_info->i_idxposc].i_offset +
-               p_info->p_index[p_info->i_idxposc].i_length )
+    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 )
+
+        if( !AVI_SetStreamChunk( p_input, p_info, p_info->i_idxposc + 1 ) )
         {
-            return( -1 );
+            return( 0 );
         }
     }
-    /* search nearest key frame */
-    if( ( !p_info->header.i_samplesize ) && ( p_info->i_cat == VIDEO_ES ) )
+
+    /* search nearest key frame, only for video */
+    if( 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 )
+                if( !AVI_SetStreamChunk( p_input, p_info, 
+                                         p_info->i_idxposc + 1 ) )
                 {
-                    break;
+                    return( 0 );
                 }
             }
         }
@@ -1294,103 +1640,82 @@ static int __AVI_ReAlign( input_thread_t *p_input )
             while( ( p_info->i_idxposc > 0 ) &&
               (!(p_info->p_index[p_info->i_idxposc].i_flags&AVIIF_KEYFRAME)) )
             {
-                p_info->i_idxposc--;
+
+                if( !AVI_SetStreamChunk( p_input, p_info, 
+                                        p_info->i_idxposc - 1 ) )
+                {
+
+                    return( 0 );
+                }
             }
         }
-        __AVI_GoToStreamChunk( p_input, p_info, p_info->i_idxposc );
     } 
-    
-    return( 0 );
+    return( 1 );
 }
 
-/* update i_date and */
 /* make difference between audio and video pts as little as possible */
-static void __AVI_SynchroReInit( input_thread_t *p_input )
+static void AVI_SynchroReInit( input_thread_t *p_input )
 {
-    demux_data_avi_file_t *p_avi_demux;
-
-    p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
-    p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK;
-
-    if( p_avi_demux->p_info_video == NULL )
+    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_audio )||( !p_info_video ) )
     {
-        p_avi_demux->i_date = mdate() + DEFAULT_PTS_DELAY
-                - __AVI_GetPTS( p_avi_demux->p_info_audio );
         return;
     }
+    /* now resynch audio video video */
+    /*don't care of AVIF_KEYFRAME */
+    if( !p_info_audio->header.i_samplesize )
+    {
+        AVI_SetStreamChunk( p_input, 
+                            p_info_audio, 
+                            AVI_PTSToChunk( p_info_audio,
+                                            AVI_GetPTS( p_info_video ) ) );
+    }
     else
     {
-        p_avi_demux->i_date = mdate() + DEFAULT_PTS_DELAY
-                - __AVI_GetPTS( p_avi_demux->p_info_video );
-        /* now resynch audio video video */
-        /*don't care of AVIF_KEYFRAME */
-        if( p_avi_demux->p_info_audio != NULL )
-        {
-            if( p_avi_demux->p_info_audio->header.i_samplesize == 0 )
-            {
-                int i_chunk = __AVI_PTSToChunk( p_avi_demux->p_info_audio, 
-                                    __AVI_GetPTS( p_avi_demux->p_info_video ));
-                if( i_chunk < 0 )
-                {
-                    i_chunk = 0;
-                }
-                __AVI_GoToStreamChunk( p_input, 
-                                       p_avi_demux->p_info_audio, 
-                                       i_chunk );            
-            }
-            else
-            {
-                int i_byte = __AVI_PTSToByte( p_avi_demux->p_info_audio, 
-                                    __AVI_GetPTS( p_avi_demux->p_info_video ) );
-                if( i_byte < 0 )
-                {
-                    i_byte = 0;
-                }
-                __AVI_GoToStreamBytes( p_input, 
-                                       p_avi_demux->p_info_audio,
-                                       i_byte );
-            }
-        }
-   }
-            
+        AVI_SetStreamBytes( p_input,
+                            p_info_audio,
+                            AVI_PTSToByte( p_info_audio,
+                                            AVI_GetPTS( p_info_video ) ) ); 
+    }
+#undef p_info_video
+#undef p_info_audio
 } 
 
-static pes_packet_t *__AVI_GetFrameInPES( input_thread_t *p_input,
-                                          AVIStreamInfo_t *p_info,
-                                          mtime_t i_dpts)
+/*****************************************************************************
+ * 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;
-    demux_data_avi_file_t *p_avi_demux;
-    
-    p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
-    
-    if( ( !p_info)||(i_dpts < 0 ) ) 
+
+    if( i_dpts < 1000 ) 
     { 
         return( NULL ) ; 
     }
-    /* if i_pts is too small use 100 ms */
-    if( i_dpts <= 100000)
-    {
-        i_dpts = 100000; /* 100 ms by default */
-    }
 
     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 */
-        i_chunk = __MIN( 20, i_chunk ); /* but no more than 20 */
-        /* read them */
+        int i_chunk = __MAX( AVI_PTSToChunk( p_info, i_dpts), 1 );
         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 );
+            i_pts = AVI_GetPTS( p_info ); 
+            p_pes_tmp = AVI_ReadStreamChunkInPES( p_input, p_info );
+
             if( !p_pes_tmp )
             {
                 return( p_pes_first );
@@ -1411,68 +1736,416 @@ static pes_packet_t *__AVI_GetFrameInPES( input_thread_t *p_input,
     else
     {
         /* stream is byte based */
-        int i_byte = __MAX( __AVI_PTSToByte( p_info, i_dpts), 1024 );
-         /* at least one Kbyte */
-        i_byte = __MIN( 1024*1000, i_byte ); /* but no more than 1000ko */
-        i_pts = __AVI_GetPTS( p_info );
+        int i_byte = AVI_PTSToByte( p_info, i_dpts);
+        if( i_byte < 50 ) /* to avoid some problem with audio */
+        {
+            return( NULL );
+        }
+        i_pts = AVI_GetPTS( p_info );  /* ok even with broken index */
+        p_pes = AVI_ReadStreamBytesInPES( p_input, p_info, i_byte);
 
-        p_pes = __AVI_ReadStreamBytesInPES( p_input, p_info, i_byte);
-        if( p_pes != NULL )
+        if( p_pes )
         {
             p_pes->i_pts = i_pts;
         }
         return( p_pes );
     }
 }
-
-static void __AVI_DecodePES( AVIStreamInfo_t *p_info,
-                             pes_packet_t *p_pes,
-                             mtime_t    i_date,
-                             int        i_rate )
+/*****************************************************************************
+ * AVI_DecodePES : send a pes to decoder 
+ *****************************************************************************
+ * Handle multiple pes, and update 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;
-    if( ( !p_info )||( !p_pes ) )
-    {
-        return;
-    }
-    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 )
-    {
-        vlc_cond_wait( &p_info->p_es->p_decoder_fifo->data_wait,
-                       &p_info->p_es->p_decoder_fifo->data_lock );
-    }
-    vlc_mutex_unlock( &p_info->p_es->p_decoder_fifo->data_lock );
+    pes_packet_t    *p_pes_next;
     /* input_decode want only one pes, but AVI_GetFrameInPES give
           multiple pes so send one by one */
-    do
+    while( p_pes )
     {
         p_pes_next = p_pes->p_next;
         p_pes->p_next = NULL;
-        p_pes->i_pts = i_date + p_pes->i_pts * (mtime_t)i_rate /
-                                               (mtime_t)DEFAULT_RATE;
+        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;
-    } while( p_pes != NULL );
+    }
   
 }
 
+/*****************************************************************************
+ * AVIDemux_Seekable: reads and demuxes data packets for stream seekable
+ *****************************************************************************
+ * Called by AVIDemux, that make common work
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
+static int AVIDemux_Seekable( input_thread_t *p_input,
+                              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;
+
+    pes_packet_t *p_pes_master;
+    pes_packet_t *p_pes_slave;
+
+    /* 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, p_info_master ) )
+        {
+            return( 0 ); /* assume EOF */
+        }
+        AVI_SynchroReInit( p_input ); 
+    }
+
+    /* 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 /*- DEFAULT_PTS_DELAY / 2 */); 
+    /* 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_master = AVI_GetFrameInPES( p_input,
+                                      p_info_master,
+                                      100000 ); /* 100 ms */
+    AVI_DecodePES( p_input,
+                   p_info_master,
+                   p_pes_master);
+
+
+    if( p_info_slave )
+    {
+        p_pes_slave = 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_slave );
+    }
+
+
+    /* at the end ? */
+    return( p_pes_master ? 1 : 0 );
+
+}
+
+/*****************************************************************************
+ * AVIDemux_NotSeekable: reads and demuxes data packets for stream seekable
+ *****************************************************************************
+ * Called by AVIDemux, that makes common work
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
+
+/* 0 if can be load/updated, 1 if skip, 2 if descend into, 3 if exit, 4 if error and need recover */
+static int __AVIDemux_ChunkAction( int i_streams_max,
+                                   riffchunk_t *p_ck )
+{
+    int i_stream;
+    int i_type;
+
+    AVI_ParseStreamHeader( p_ck->i_id, &i_stream, &i_type );
+    if( i_stream < i_streams_max )
+    {
+        return( 0 ); /* read and/or update stream info */
+    }
+
+    if( i_stream <= 99 )
+    {
+        /* should not happen but ... */
+        return( 1 );
+    }
+
+    /* now we know that it's not a stream */
+
+    switch( p_ck->i_id )
+    {
+        case( FOURCC_JUNK ):
+            return( 1 );
+        case( FOURCC_idx1 ):
+            return( 3 );
+        case( FOURCC_LIST ):
+            if( p_ck->i_type == FOURCC_rec )
+            {
+                return( 2 );
+            }
+            else
+            {
+                return( 1 );
+            }
+        default:
+            break;
+    } 
+    /* test for ix?? */
+
+    if( ( p_ck->i_id & 0xFFFF ) == VLC_TWOCC( 'i','x' ) )
+    {
+        return( 1 );
+    }
+
+    return( 4 );
+}
+
+static int AVI_NotSeekableRecover( input_thread_t *p_input )
+{
+    byte_t *p_id;
+    u32 i_id;
+    int i_number, i_type;
+    data_packet_t *p_pack;
+
+    for( ; ; )
+    {
+        if( input_Peek( p_input, &p_id, 4 ) < 4 )
+        {
+            return( 0 ); /* Failed */
+        }
+        i_id = GetDWLE( p_id );
+        switch( i_id )
+        {
+            case( FOURCC_idx1 ):
+            case( FOURCC_JUNK ):
+            case( FOURCC_LIST ):
+                return( 1 );
+            default:
+                AVI_ParseStreamHeader( i_id, &i_number, &i_type );
+                if( i_number <= 99 )
+                {
+                    switch( i_type )
+                    {
+                        case( TWOCC_wb ):
+                        case( TWOCC_db ):
+                        case( TWOCC_dc ):
+                        case( TWOCC_pc ):
+                            return( 1 );
+                    }
+                }
+                else
+                {
+
+                }
+        }
+        /* Read 1 byte VERY unoptimised */
+        if( input_SplitBuffer( p_input, &p_pack, 1) < 1 )
+        {
+            return( 0 );
+        }
+        input_DeletePacket( p_input->p_method_data, p_pack);
+    }
+
+}
+
+static int AVIDemux_NotSeekable( input_thread_t *p_input,
+                                 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;
+    int i_loop;
+    int i_stream;
+    int i_type;
+    
+    riffchunk_t *p_ck;
+    pes_packet_t *p_pes;
+   
+/*
+    i_filepos = AVI_TellAbsolute( p_input );
+    p_input->pf_seek( p_input, i_filepos ); 
+    input_AccessReinit( p_input );
+*/
+    
+#define p_info p_avi_demux->pp_info[i_stream]
+
+    /* The managment is very basic, we will read packets, caclulate pts 
+    and send it to decoder, synchro made on video, and audio is very less
+    important */
+    
+    /* wait the good time */
+    input_ClockManageRef( p_input,
+                          p_input->stream.p_selected_program,
+                          p_avi_demux->i_pcr /*- DEFAULT_PTS_DELAY / 2 */); 
+    /* TODO be smart, seeing if we can wait for min( audio, video )
+        or there is a too big deep */
+    if( !p_info_slave )
+    {
+        p_avi_demux->i_pcr =  AVI_GetPTS( p_info_master ) * 9/100;
+    }
+    else
+    {
+        p_avi_demux->i_pcr =  __MIN( AVI_GetPTS( p_info_master ),
+                                 AVI_GetPTS( p_info_slave ) ) * 9/100;
+        p_avi_demux->i_pcr =  AVI_GetPTS( p_info_master ) * 9/100;
+    }
+    
+    for( i_loop = 0; i_loop < 10; i_loop++ )
+    {
+        int b_load =0;
+        
+        /* first find a ck for master or slave */
+        do
+        {
+
+            if( !(p_ck = RIFF_ReadChunk( p_input ) ) )
+            {
+                msg_Err( p_input, "Badd" );
+                return( 0 ); /* assume EOF */
+            }
+            //msg_Err( p_input,"Looking ck: %4.4s %d",&p_ck->i_id, p_ck->i_size );
+
+            switch( __AVIDemux_ChunkAction( p_avi_demux->i_streams, p_ck ) )
+            {
+                case( 0 ): /* load it if possible */
+                    b_load = 1;
+                    break;
+                case( 1 ): /* skip it */
+                    RIFF_DeleteChunk( p_input, p_ck );
+                    if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+                    {
+                        return( 0 );
+                    }
+                    b_load = 0;
+                    break;
+                case( 2 ): /* descend into */
+                    RIFF_DeleteChunk( p_input, p_ck );
+                    RIFF_DescendChunk( p_input );
+                    b_load = 0;
+                    break;
+                case( 3 ): /* exit */
+                    RIFF_DeleteChunk( p_input, p_ck );
+                    return( 0 );
+                case( 4 ): /* Error */
+                    RIFF_DeleteChunk( p_input, p_ck );
+                    msg_Warn( p_input, "unknown chunk id 0x%8.8x, trying to recover", p_ck->i_id );
+                    if( !AVI_NotSeekableRecover( p_input ) )
+                    {
+                        msg_Err( p_input, "cannot recover, dying" );
+                        return( -1 );
+                    }
+                    else
+                    {
+                        msg_Warn( p_input, "recovered sucessfully" );
+                    }
+                    b_load = 0;
+                    break;
+            }
+
+        } while( !b_load );
+
+        AVI_ParseStreamHeader( p_ck->i_id, &i_stream, &i_type );
+        /* now check if we really have to load it */
+        if( ( p_info != p_info_master )&&( p_info != p_info_slave ) )
+        {
+            b_load = 0;
+        }
+        else
+        {
+            if( p_info == p_info_master )
+            {
+                b_load = 1;
+            }
+            else
+            {
+                mtime_t i_dpts;
+                i_dpts = AVI_GetPTS( p_info_slave ) - 
+                            AVI_GetPTS( p_info_master );
+                if( i_dpts < 0 ) {i_dpts = - i_dpts; }
+                if( i_dpts < 600000 )
+                {
+                    b_load = 1;
+                } 
+                else
+                {
+                    b_load = 0;
+                }
+            }
+
+        }
+
+        /* now do we can load this chunk ? */ 
+        if( b_load )
+        {
+
+            if( __AVI_GetDataInPES( p_input, &p_pes, p_ck->i_size + 8, 1) != p_ck->i_size + 8)
+            {
+                return( 0 );
+            }
+            p_pes->p_first->p_payload_start += 8;
+            p_pes->i_pes_size -= 8;
+            /* get PTS */
+            p_pes->i_pts = AVI_GetPTS( p_info );
+            AVI_DecodePES( p_input, p_info, p_pes );
+        }
+        else
+        {
+
+            if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+            {
+                RIFF_DeleteChunk( p_input, p_ck );
+                return( 0 );
+            }
+        } 
+        
+        /* finaly update stream information */
+        if( p_info->header.i_samplesize )
+        {
+            p_info->i_idxposb += p_ck->i_size;
+        }
+        else
+        {
+            p_info->i_idxposc++;
+        }
+        
+        RIFF_DeleteChunk( p_input, p_ck );
+    }
+
+    return( 1 );
+#undef p_info
+}
 /*****************************************************************************
  * AVIDemux: reads and demuxes data packets
  *****************************************************************************
  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ * TODO add support for unstreable file, just read a chunk and send it 
+ *      to the right decoder, very easy
  *****************************************************************************/
+
 static int AVIDemux( input_thread_t *p_input )
 {
     int i;
-    pes_packet_t *p_pes_audio;
-    pes_packet_t *p_pes_video;
-    demux_data_avi_file_t *p_avi_demux;
+    AVIStreamInfo_t *p_info_master;
+    AVIStreamInfo_t *p_info_slave;    
 
-/*     try to use this to read data packet at the good time
- *     input_ClockManageRef( p_input,
-                            p_input->stream.p_selected_program,
-                            (mtime_t)pcr );  ??? what is supposed to do */
-    p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
+    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*/
@@ -1483,7 +2156,7 @@ static int AVIDemux( input_thread_t *p_input )
         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->pp_info[i]->p_es->p_decoder_fifo ) )
             {
                 p_avi_demux->p_info_video = p_avi_demux->pp_info[i];
                 p_avi_demux->p_info_video->b_selected = 1;
@@ -1498,7 +2171,7 @@ static int AVIDemux( input_thread_t *p_input )
         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->pp_info[i]->p_es->p_decoder_fifo ) )
             {
                 p_avi_demux->p_info_audio = p_avi_demux->pp_info[i];
                 p_avi_demux->p_info_audio->b_selected = 1;
@@ -1506,102 +2179,54 @@ static int AVIDemux( input_thread_t *p_input )
             }
         }
     }
-    /* for now, we need at least one video stream */
-    if( !p_avi_demux->p_info_video ) 
+    /* by default video is master for resync audio (after a seek .. ) */
+    if( p_avi_demux->p_info_video )
     {
-        intf_ErrMsg( "input error: no video ouput selected" );
-        return( -1 );
+        p_info_master = p_avi_demux->p_info_video;
+        p_info_slave  = p_avi_demux->p_info_audio;
     }
-
-    /* check for signal from interface */
-    if( (input_ClockManageControl( p_input, p_input->stream.p_selected_program,
-                            (mtime_t)0) == PAUSE_S) )
-    {   
-        __AVI_SynchroReInit( p_input ); /* resynchro, and make pts audio 
-                                            and video egual */
-        p_avi_demux->i_rate = DEFAULT_RATE;
+    else
+    {
+        p_info_master = p_avi_demux->p_info_audio;
+        p_info_slave  = NULL;
     }
-
-    if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
-    { 
-        msleep( 200000 ); /* 200ms delay to have empty audio and video buffer*/
-      /*realign audio and video stream to the good pts*/
-        if( __AVI_ReAlign( p_input ) != 0 )
-        {
-            return( 0 ); /* assume EOF */
-        }
-        __AVI_SynchroReInit( p_input ); /* resynchro, and make pts audio 
-                                            and video egual */
-        p_avi_demux->i_rate = DEFAULT_RATE;
+    
+    if( !p_info_master ) 
+    {
+        msg_Err( p_input, "no stream selected" );
+        return( -1 );
     }
 
-    
+    /* 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 )
     {
-        msleep( 200000 );
-        p_avi_demux->i_rate = p_input->stream.control.i_rate;
-        p_avi_demux->i_date = mdate()  + DEFAULT_PTS_DELAY
-                        - __AVI_GetPTS( p_avi_demux->p_info_video ) *
-                                (mtime_t)p_avi_demux->i_rate  /
-                                (mtime_t)DEFAULT_RATE ;
-        if( p_avi_demux->i_rate == DEFAULT_RATE )
+        if( p_avi_demux->p_info_audio)
         {
-            if( p_avi_demux->p_info_audio )
-            {
-                p_avi_demux->p_info_audio->b_selected = 1;
-            }
+             p_avi_demux->p_info_audio->b_selected = 1;
         }
-    }
-    if( p_avi_demux->i_rate != DEFAULT_RATE )
-    {
-        p_avi_demux->p_info_audio = NULL;
+        p_avi_demux->i_rate = p_input->stream.control.i_rate;
     }
     vlc_mutex_unlock( &p_input->stream.stream_lock );    
-    
-    /* take care of newly selected audio ES */
-    if( (p_avi_demux->p_info_audio != NULL)
-                    &&(p_avi_demux->p_info_audio->b_selected ))
+    p_avi_demux->i_rate = DEFAULT_RATE;
+    if( p_avi_demux->i_rate != DEFAULT_RATE )
     {
-        p_avi_demux->p_info_audio->b_selected = 0 ;
-        __AVI_SynchroReInit( p_input ); /* resynchro, and make pts audio
-                                            and video egual */
+        p_info_slave = NULL;
     }
-    /* get audio and video frame */
-    if( p_avi_demux->p_info_video != NULL )
+
+    if( p_avi_demux->b_seekable )
     {
-       p_pes_video = __AVI_GetFrameInPES( p_input,
-                                           p_avi_demux->p_info_video,
-                                           100000 ); /* 100 ms */
-        if( p_avi_demux->p_info_audio != NULL )
-        {
-           p_pes_audio = __AVI_GetFrameInPES( p_input,
-                                               p_avi_demux->p_info_audio,
-                                   __AVI_GetPTS( p_avi_demux->p_info_video) -
-                                   __AVI_GetPTS( p_avi_demux->p_info_audio) );
-        }
-        else
-        {
-           p_pes_audio = NULL;
-        }
+        return( AVIDemux_Seekable( p_input,
+                                   p_info_master,
+                                   p_info_slave) );
     }
     else
     {
-        p_pes_video = NULL;
-        p_pes_audio = __AVI_GetFrameInPES( p_input,
-                                           p_avi_demux->p_info_audio,
-                                           100000 ); /* 100 ms */
-    }
-    /* send them to decoder */
-    __AVI_DecodePES( p_avi_demux->p_info_audio, p_pes_audio,
-                     p_avi_demux->i_date, p_avi_demux->i_rate );
-    __AVI_DecodePES( p_avi_demux->p_info_video, p_pes_video,
-                     p_avi_demux->i_date, p_avi_demux->i_rate );
-   
-    if( !p_pes_video )  /* no more video */
-    {                          /* currently i need a video stream */
-       return( 0 );
+        return( AVIDemux_NotSeekable( p_input,
+                                      p_info_master,
+                                      p_info_slave ) );
     }
-    
-    return( 1 );
 }
+
+
+