]> git.sesse.net Git - vlc/blobdiff - modules/demux/avi/avi.c
* ALL: i18n updates and fixes.
[vlc] / modules / demux / avi / avi.c
index 6c67e71668d8d674a220d9303687fd3caec84986..5b5c931d7a502f0595e64e9bb687e8078e63b517 100644 (file)
@@ -2,14 +2,14 @@
  * avi.c : AVI file Stream input module for vlc
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: avi.c,v 1.1 2002/08/04 17:23:42 sam Exp $
+ * $Id: avi.c,v 1.36 2003/02/27 13:19:43 gbazin Exp $
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
- * 
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
- * 
+ *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
 #include "video.h"
 
-#include "libioRIFF.h"
+#include "libavi.h"
+
+#define __AVI_SUBTITLE__ 1
+
+#ifdef __AVI_SUBTITLE__
+#   include "../util/sub.h"
+#endif
 #include "avi.h"
 
 /*****************************************************************************
  *****************************************************************************/
 static int    AVIInit   ( vlc_object_t * );
 static void __AVIEnd    ( vlc_object_t * );
-static int    AVIDemux  ( input_thread_t * );
+static int    AVISeek   ( input_thread_t *, mtime_t, int );
+static int    AVIDemux_Seekable  ( input_thread_t * );
+static int    AVIDemux_UnSeekable( input_thread_t *p_input );
 
 #define AVIEnd(a) __AVIEnd(VLC_OBJECT(a))
-
+#define FREE( p ) if( p ) { free( p ); (p) = NULL; }
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
 vlc_module_begin();
-    set_description( "RIFF-AVI demuxer" );
-    set_capability( "demux", 150 );
+    add_category_hint( N_("avi-demuxer"), NULL, VLC_TRUE );
+        add_bool( "avi-interleaved", 0, NULL,
+                  _("force interleaved method"),
+                  _("force interleaved method"), VLC_TRUE );
+        add_bool( "avi-index", 0, NULL,
+                  _("force index creation"),
+                  _("force index creation"), VLC_TRUE );
+
+    set_description( _("avi demuxer") );
+    set_capability( "demux", 212 );
     set_callbacks( AVIInit, __AVIEnd );
 vlc_module_end();
 
 /*****************************************************************************
- * Some usefull functions to manipulate memory 
+ * Some useful functions to manipulate memory
  *****************************************************************************/
-static u16 GetWLE( byte_t *p_buff )
-{
-    u16 i;
-    i = (*p_buff) + ( *(p_buff + 1) <<8 );
-    return ( i );
-}
-static u32 GetDWLE( byte_t *p_buff )
-{
-    u32 i;
-    i = (*p_buff) + ( *(p_buff + 1) <<8 ) + 
-            ( *(p_buff + 2) <<16 ) + ( *(p_buff + 3) <<24 );
-    return ( i );
-}
-static u32 GetDWBE( byte_t *p_buff )
-{
-    u32 i;
-    i = ((*p_buff)<<24) + ( *(p_buff + 1) <<16 ) + 
-            ( *(p_buff + 2) <<8 ) + ( *(p_buff + 3) );
-    return ( i );
-}
-static inline off_t __EVEN( off_t i )
+
+static uint16_t GetWLE( uint8_t *p_buff )
 {
-    return( (i & 1) ? i+1 : i );
+    return (uint16_t)p_buff[0] | ( ((uint16_t)p_buff[1]) << 8 );
 }
 
-
-/*****************************************************************************
- * Functions for parsing the headers in an avi file
- *****************************************************************************/
-static void AVI_Parse_avih( MainAVIHeader_t *p_avih, byte_t *p_buff )
+static uint32_t GetDWLE( uint8_t *p_buff )
 {
-    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);
+    return (uint32_t)p_buff[0] | ( ((uint32_t)p_buff[1]) << 8 ) |
+            ( ((uint32_t)p_buff[2]) << 16 ) | ( ((uint32_t)p_buff[3]) << 24 );
 }
-static void AVI_Parse_Header( AVIStreamHeader_t *p_strh, byte_t *p_buff )
+
+static uint32_t GetDWBE( uint8_t *p_buff )
 {
-    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);
+    return (uint32_t)p_buff[3] | ( ((uint32_t)p_buff[2]) << 8 ) |
+            ( ((uint32_t)p_buff[1]) << 16 ) | ( ((uint32_t)p_buff[0]) << 24 );
 }
-static void AVI_Parse_BitMapInfoHeader( bitmapinfoheader_t *h, byte_t *p_data )
+static vlc_fourcc_t GetFOURCC( byte_t *p_buff )
 {
-    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 );
+    return VLC_FOURCC( p_buff[0], p_buff[1], p_buff[2], p_buff[3] );
 }
-static void AVI_Parse_WaveFormatEx( waveformatex_t *h, byte_t *p_data )
+
+static inline off_t __EVEN( off_t i )
 {
-    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 );
+    return (i & 1) ? i + 1 : i;
 }
 
-static inline int AVI_GetESTypeFromTwoCC( u16 i_type )
+#define __ABS( x ) ( (x) < 0 ? (-(x)) : (x) )
+
+/* read data in a pes */
+static int input_ReadInPES( input_thread_t *p_input,
+                            pes_packet_t **pp_pes,
+                            size_t i_size )
 {
-    switch( i_type )
+    pes_packet_t *p_pes;
+    data_packet_t *p_data;
+
+
+    if( !(p_pes = input_NewPES( p_input->p_method_data ) ) )
     {
-        case( TWOCC_wb ):
-            return( AUDIO_ES );
-         case( TWOCC_dc ):
-         case( TWOCC_db ):
-            return( VIDEO_ES );
-         default:
-            return( UNKNOWN_ES );
+        pp_pes = NULL;
+        return -1;
     }
-}
 
-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_A52 ):
-            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;
+    *pp_pes = p_pes;
+
+    if( !i_size )
+    {
+        p_pes->p_first =
+            p_pes->p_last  =
+                input_NewPacket( p_input->p_method_data, 0 );
+        p_pes->i_nb_data = 1;
+        p_pes->i_pes_size = 0;
+        return 0;
+    }
+
+    p_pes->i_nb_data = 0;
+    p_pes->i_pes_size = 0;
+
+    while( p_pes->i_pes_size < i_size )
+    {
+        int i_read;
+
+        i_read = input_SplitBuffer(p_input,
+                                   &p_data,
+                                   __MIN( i_size -
+                                          p_pes->i_pes_size, 2048 ) );
+        if( i_read <= 0 )
+        {
+            /* should occur only with EOF and max allocation reached 
+             * it safer to  return an error */
+            /* free pes */
+            input_DeletePES( p_input->p_method_data, p_pes );
+            return -1;
+        }
+
+        if( !p_pes->p_first )
+        {
+            p_pes->p_first = p_data;
+        }
+        else
+        {
+            p_pes->p_last->p_next = p_data;
+        }
+        p_pes->p_last = p_data;
+        p_pes->i_nb_data++;
+        p_pes->i_pes_size += i_read;
     }
+
+
+    return p_pes->i_pes_size;
 }
 
 /* Test if it seems that it's a key frame */
-static int AVI_GetKeyFlag( vlc_fourcc_t i_fourcc, u8 *p_byte )
+static int AVI_GetKeyFlag( vlc_fourcc_t i_fourcc, uint8_t *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 */
+            /* we have:
+             *  startcode:      0x00000100   32bits
+             *  framenumber     ?             5bits
+             *  piture type     0(I),1(P)     2bits
+             */
+            if( GetDWBE( p_byte ) != 0x00000100 )
             {
-            /* it's seems it's not an msmpegv1 stream 
-               but perhaps I'm wrong so return yes */
-                return( AVIIF_KEYFRAME );
+                /* it's not an msmpegv1 stream, strange...*/
+                return AVIIF_KEYFRAME;
             }
             else
             {
-                return( (*(p_byte+4))&0x06 ? 0 : AVIIF_KEYFRAME);
+                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:
-            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_DIV3:   // wmv1 also
+            /* we have
+             *  picture type    0(I),1(P)     2bits
+             */
+            return p_byte[0] & 0xC0 ? 0 : AVIIF_KEYFRAME;
         case FOURCC_mp4v:
-        case FOURCC_4:
+            /* we should find first occurence of 0x000001b6 (32bits)
+             *  startcode:      0x000001b6   32bits
+             *  piture type     0(I),1(P)     2bits
+             */
             if( GetDWBE( p_byte ) != 0x000001b6 )
             {
-                /* not true , need to find the first VOP header
-                    but, I'm lazy */
-                return( AVIIF_KEYFRAME );
+                /* not true , need to find the first VOP header */
+                return AVIIF_KEYFRAME;
             }
             else
             {
-                return( (*(p_byte+4))&0xC0 ? 0 : AVIIF_KEYFRAME );
+                return p_byte[4] & 0xC0 ? 0 : AVIIF_KEYFRAME;
             }
         default:
-            /* I can't do it, so said yes */
-            return( AVIIF_KEYFRAME );
+            /* I can't do it, so say 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 )
+
+vlc_fourcc_t AVI_FourccGetCodec( unsigned int i_cat, vlc_fourcc_t i_codec )
 {
-    return( p_info->i_pes_totalsize > BUFFER_MAXTOTALSIZE ? 1 : 0);
+    switch( i_cat )
+    {
+        case AUDIO_ES:
+            switch( i_codec )
+            {
+                case WAVE_FORMAT_PCM:
+                    return VLC_FOURCC( 'a', 'r', 'a', 'w' );
+                case WAVE_FORMAT_MPEG:
+                case WAVE_FORMAT_MPEGLAYER3:
+                    return VLC_FOURCC( 'm', 'p', 'g', 'a' );
+                case WAVE_FORMAT_A52:
+                    return VLC_FOURCC( 'a', '5', '2', ' ' );
+                case WAVE_FORMAT_WMA1:
+                    return VLC_FOURCC( 'w', 'm', 'a', '1' );
+                case WAVE_FORMAT_WMA2:
+                    return VLC_FOURCC( 'w', 'm', 'a', '2' );
+                default:
+                    return VLC_FOURCC( 'm', 's',
+                                       ( i_codec >> 8 )&0xff, i_codec&0xff );
+            }
+        case VIDEO_ES:
+            // XXX DIV1 <- msmpeg4v1, DIV2 <- msmpeg4v2, DIV3 <- msmpeg4v3, mp4v for mpeg4
+            switch( i_codec )
+            {
+                case FOURCC_DIV1:
+                case FOURCC_div1:
+                case FOURCC_MPG4:
+                case FOURCC_mpg4:
+                    return FOURCC_DIV1;
+                case FOURCC_DIV2:
+                case FOURCC_div2:
+                case FOURCC_MP42:
+                case FOURCC_mp42:
+                case FOURCC_MPG3:
+                case FOURCC_mpg3:
+                    return FOURCC_DIV2;
+                case FOURCC_div3:
+                case FOURCC_MP43:
+                case FOURCC_mp43:
+                case FOURCC_DIV3:
+                case FOURCC_DIV4:
+                case FOURCC_div4:
+                case FOURCC_DIV5:
+                case FOURCC_div5:
+                case FOURCC_DIV6:
+                case FOURCC_div6:
+                case FOURCC_AP41:
+                case FOURCC_3IV1:
+                    return FOURCC_DIV3;
+                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:
+                    return FOURCC_mp4v;
+            }
+        default:
+            return VLC_FOURCC( 'u', 'n', 'd', 'f' );
+    }
 }
-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 )
+
+static void AVI_ParseStreamHeader( vlc_fourcc_t i_id,
+                                   int *pi_number, int *pi_type )
 {
-    AVIESBuffer_t   *p_buffer_pes;
+#define SET_PTR( p, v ) if( p ) *(p) = (v);
+    int c1, c2;
 
-    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;
+    c1 = ((uint8_t *)&i_id)[0];
+    c2 = ((uint8_t *)&i_id)[1];
 
-    if( p_info->p_pes_last ) 
+    if( c1 < '0' || c1 > '9' || c2 < '0' || c2 > '9' )
     {
-        p_info->p_pes_last->p_next = p_buffer_pes;
+        SET_PTR( pi_number, 100 ); /* > max stream number */
+        SET_PTR( pi_type, UNKNOWN_ES );
     }
-    p_info->p_pes_last = p_buffer_pes;
-    if( !p_info->p_pes_first )
+    else
     {
-        p_info->p_pes_first = p_buffer_pes;
+        SET_PTR( pi_number, (c1 - '0') * 10 + (c2 - '0' ) );
+        switch( VLC_TWOCC( ((uint8_t *)&i_id)[2], ((uint8_t *)&i_id)[3] ) )
+        {
+            case AVITWOCC_wb:
+                SET_PTR( pi_type, AUDIO_ES );
+                break;
+            case AVITWOCC_dc:
+            case AVITWOCC_db:
+                SET_PTR( pi_type, VIDEO_ES );
+                break;
+            default:
+                SET_PTR( pi_type, UNKNOWN_ES );
+                break;
+        }
     }
-    p_info->i_pes_count++;
-    p_info->i_pes_totalsize += p_pes->i_pes_size;
+#undef SET_PTR
 }
-static pes_packet_t *AVI_PESBuffer_Get( AVIStreamInfo_t *p_info )
+
+static int AVI_PacketGetHeader( input_thread_t *p_input, avi_packet_t *p_pk )
 {
-    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;
+    uint8_t  *p_peek;
 
-        free( p_buffer_pes );
-        p_info->i_pes_count--;
-        p_info->i_pes_totalsize -= p_pes->i_pes_size;
-        return( p_pes );
+    if( input_Peek( p_input, &p_peek, 16 ) < 16 )
+    {
+        return VLC_EGENERIC;
+    }
+    p_pk->i_fourcc  = GetFOURCC( p_peek );
+    p_pk->i_size    = GetDWLE( p_peek + 4 );
+    p_pk->i_pos     = AVI_TellAbsolute( p_input );
+    if( p_pk->i_fourcc == AVIFOURCC_LIST )
+    {
+        p_pk->i_type = GetFOURCC( p_peek + 8 );
     }
     else
     {
-        return( NULL );
+        p_pk->i_type = 0;
     }
+
+    memcpy( p_pk->i_peek, p_peek + 8, 8 );
+
+    AVI_ParseStreamHeader( p_pk->i_fourcc, &p_pk->i_stream, &p_pk->i_cat );
+    return VLC_SUCCESS;
 }
-static int AVI_PESBuffer_Drop( input_buffers_t *p_method_data,
-                                AVIStreamInfo_t *p_info )
+
+static int AVI_PacketNext( input_thread_t *p_input )
 {
-    pes_packet_t *p_pes = AVI_PESBuffer_Get( p_info );
-    if( p_pes )
+    avi_packet_t    avi_ck;
+
+    if( AVI_PacketGetHeader( p_input, &avi_ck ) )
     {
-        input_DeletePES( p_method_data, p_pes );
-        return( 1 );
+        return VLC_EGENERIC;
     }
-    else
+    if( avi_ck.i_fourcc == AVIFOURCC_LIST && avi_ck.i_type == AVIFOURCC_rec )
     {
-        return( 0 );
+        return AVI_SkipBytes( p_input, 12 );
     }
-}
-static void AVI_PESBuffer_Flush( input_buffers_t *p_method_data,
-                                 AVIStreamInfo_t *p_info )
-{
-    while( p_info->p_pes_first )
+    else
     {
-        AVI_PESBuffer_Drop( p_method_data, p_info );
+        return AVI_SkipBytes( p_input, __EVEN( avi_ck.i_size ) + 8 );
     }
 }
-
-static void AVI_ParseStreamHeader( u32 i_id, int *i_number, int *i_type )
+static int AVI_PacketRead( input_thread_t   *p_input,
+                           avi_packet_t     *p_pk,
+                           pes_packet_t     **pp_pes )
 {
-    int c1,c2;
+    size_t i_size;
+    vlc_bool_t b_pad;
 
-    c1 = ( i_id ) & 0xFF;
-    c2 = ( i_id >>  8 ) & 0xFF;
+    i_size = __EVEN( p_pk->i_size + 8 );
+    b_pad  = ( i_size != p_pk->i_size + 8 );
 
-    if( c1 < '0' || c1 > '9' || c2 < '0' || c2 > '9' )
+    if( input_ReadInPES( p_input, pp_pes, i_size ) != (ssize_t)i_size )
     {
-        *i_number = 100; /* > max stream number */
-        *i_type = 0;
+        return VLC_EGENERIC;
     }
-    else
+    (*pp_pes)->p_first->p_payload_start += 8;
+    (*pp_pes)->i_pes_size -= 8;
+
+    if( b_pad )
     {
-        *i_number = (c1 - '0') * 10 + (c2 - '0' );
-        *i_type = ( i_id >> 16 ) & 0xFFFF;
+        (*pp_pes)->p_last->p_payload_end--;
+        (*pp_pes)->i_pes_size--;
     }
-}
-
-/* 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 );
+    return VLC_SUCCESS;
 }
-                            
-static int AVI_SeekAbsolute( input_thread_t *p_input,
-                             off_t i_pos)
+
+static int AVI_PacketSearch( input_thread_t *p_input )
 {
-    off_t i_filepos;
-    /* FIXME add support for not seekable stream */
+    demux_sys_t     *p_avi = p_input->p_demux_data;
 
-    i_filepos = AVI_TellAbsolute( p_input );
-    if( i_pos != i_filepos )
+    avi_packet_t    avi_pk;
+    for( ;; )
     {
-//        msg_Err( p_input, "Seek --> delta %d", i_pos - i_filepos );
-        p_input->pf_seek( p_input, i_pos );
-        input_AccessReinit( p_input );
+        if( AVI_SkipBytes( p_input, 1 ) )
+        {
+            return VLC_EGENERIC;
+        }
+        AVI_PacketGetHeader( p_input, &avi_pk );
+        if( avi_pk.i_stream < p_avi->i_streams &&
+            ( avi_pk.i_cat == AUDIO_ES || avi_pk.i_cat == VIDEO_ES ) )
+        {
+            return VLC_SUCCESS;
+        }
+        switch( avi_pk.i_fourcc )
+        {
+            case AVIFOURCC_JUNK:
+            case AVIFOURCC_LIST:
+            case AVIFOURCC_idx1:
+                return VLC_SUCCESS;
+        }
     }
-    return( 1 );
 }
 
 
-static void __AVI_AddEntryIndex( AVIStreamInfo_t *p_info,
+static void __AVI_AddEntryIndex( avi_stream_t *p_info,
                                  AVIIndexEntry_t *p_index)
 {
-    AVIIndexEntry_t *p_tmp;
     if( p_info->p_index == NULL )
     {
         p_info->i_idxmax = 16384;
         p_info->i_idxnb = 0;
-        p_info->p_index = calloc( p_info->i_idxmax, 
-                                  sizeof( AVIIndexEntry_t ) );
-        if( p_info->p_index == NULL ) {return;}
+        if( !( p_info->p_index = calloc( p_info->i_idxmax,
+                                  sizeof( AVIIndexEntry_t ) ) ) )
+        {
+            return;
+        }
     }
     if( p_info->i_idxnb >= p_info->i_idxmax )
     {
         p_info->i_idxmax += 16384;
-        p_tmp = realloc( (void*)p_info->p_index,
-                           p_info->i_idxmax * 
-                           sizeof( AVIIndexEntry_t ) );
-        if( !p_tmp ) 
-        { 
-            p_info->i_idxmax -= 16384;
-            return; 
+        if( !( p_info->p_index = realloc( (void*)p_info->p_index,
+                           p_info->i_idxmax *
+                           sizeof( AVIIndexEntry_t ) ) ) )
+        {
+            return;
         }
-        p_info->p_index = p_tmp;
     }
     /* calculate cumulate length */
     if( p_info->i_idxnb > 0 )
     {
-        p_index->i_lengthtotal = p_info->p_index[p_info->i_idxnb-1].i_length +
-                p_info->p_index[p_info->i_idxnb-1].i_lengthtotal;
+        p_index->i_lengthtotal =
+            p_info->p_index[p_info->i_idxnb - 1].i_length +
+                p_info->p_index[p_info->i_idxnb - 1].i_lengthtotal;
     }
     else
     {
@@ -418,165 +450,373 @@ static void __AVI_AddEntryIndex( AVIStreamInfo_t *p_info,
 
     p_info->p_index[p_info->i_idxnb] = *p_index;
     p_info->i_idxnb++;
+
+}
+
+static void AVI_IndexAddEntry( demux_sys_t *p_avi,
+                               int i_stream,
+                               AVIIndexEntry_t *p_index)
+{
+    __AVI_AddEntryIndex( p_avi->pp_info[i_stream],
+                         p_index );
+    if( p_avi->i_movi_lastchunk_pos < p_index->i_pos )
+    {
+        p_avi->i_movi_lastchunk_pos = p_index->i_pos;
+    }
+}
+
+static void AVI_IndexLoad( input_thread_t *p_input )
+{
+    demux_sys_t *p_avi = p_input->p_demux_data;
+
+    avi_chunk_list_t    *p_riff;
+    avi_chunk_list_t    *p_movi;
+    avi_chunk_idx1_t    *p_idx1;
+
+    unsigned int i_stream;
+    unsigned int i_index;
+    off_t   i_offset;
+
+    p_riff = (avi_chunk_list_t*)AVI_ChunkFind( &p_avi->ck_root,
+                                               AVIFOURCC_RIFF, 0);
+
+    p_idx1 = (avi_chunk_idx1_t*)AVI_ChunkFind( p_riff, AVIFOURCC_idx1, 0);
+    p_movi = (avi_chunk_list_t*)AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0);
+
+    if( !p_idx1 )
+    {
+        msg_Warn( p_input, "cannot find idx1 chunk, no index defined" );
+        return;
+    }
+    for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
+    {
+        p_avi->pp_info[i_stream]->i_idxnb  = 0;
+        p_avi->pp_info[i_stream]->i_idxmax = 0;
+        p_avi->pp_info[i_stream]->p_index  = NULL;
+    }
+    /* *** calculate offset *** */
+    if( p_idx1->i_entry_count > 0 &&
+        p_idx1->entry[0].i_pos < p_movi->i_chunk_pos )
+    {
+        i_offset = p_movi->i_chunk_pos + 8;
+    }
+    else
+    {
+        i_offset = 0;
+    }
+
+    for( i_index = 0; i_index < p_idx1->i_entry_count; i_index++ )
+    {
+        unsigned int i_cat;
+
+        AVI_ParseStreamHeader( p_idx1->entry[i_index].i_fourcc,
+                               &i_stream,
+                               &i_cat );
+        if( i_stream < p_avi->i_streams &&
+            i_cat == p_avi->pp_info[i_stream]->i_cat )
+        {
+            AVIIndexEntry_t index;
+            index.i_id      = p_idx1->entry[i_index].i_fourcc;
+            index.i_flags   =
+                p_idx1->entry[i_index].i_flags&(~AVIIF_FIXKEYFRAME);
+            index.i_pos     = p_idx1->entry[i_index].i_pos + i_offset;
+            index.i_length  = p_idx1->entry[i_index].i_length;
+            AVI_IndexAddEntry( p_avi, i_stream, &index );
+        }
+    }
+    for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
+    {
+        msg_Dbg( p_input,
+                "stream[%d] creating %d index entries",
+                i_stream,
+                p_avi->pp_info[i_stream]->i_idxnb );
+    }
+
 }
 
-static void __AVI_GetIndex( input_thread_t *p_input )
+static void AVI_IndexCreate( input_thread_t *p_input )
 {
-    AVIIndexEntry_t index;
-    byte_t          *p_buff;
-    riffchunk_t     *p_idx1;
-    int             i_read;
-    int             i;
-    int             i_number;
-    int             i_type;
-    int             i_totalentry = 0;
-    demux_data_avi_file_t *p_avi_demux =
-                        (demux_data_avi_file_t*)p_input->p_demux_data  ;    
-
-    if( RIFF_FindAndGotoDataChunk( p_input,
-                                   p_avi_demux->p_riff, 
-                                   &p_idx1, 
-                                   FOURCC_idx1)!=0 )
-    {
-        msg_Warn( p_input, "cannot find index" );
-        RIFF_GoToChunk( p_input, p_avi_demux->p_hdrl );        
+    demux_sys_t *p_avi = p_input->p_demux_data;
+
+    avi_chunk_list_t    *p_riff;
+    avi_chunk_list_t    *p_movi;
+
+    unsigned int i_stream;
+    off_t i_movi_end;
+
+    p_riff = (avi_chunk_list_t*)AVI_ChunkFind( &p_avi->ck_root,
+                                               AVIFOURCC_RIFF, 0);
+    p_movi = (avi_chunk_list_t*)AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0);
+
+    if( !p_movi )
+    {
+        msg_Err( p_input, "cannot find p_movi" );
         return;
     }
-    p_avi_demux->p_idx1 = p_idx1;
-    msg_Dbg( p_input, "loading index" ); 
-    for(;;)
+
+    for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
+    {
+        p_avi->pp_info[i_stream]->i_idxnb  = 0;
+        p_avi->pp_info[i_stream]->i_idxmax = 0;
+        p_avi->pp_info[i_stream]->p_index  = NULL;
+    }
+    i_movi_end = __MIN( (off_t)(p_movi->i_chunk_pos + p_movi->i_chunk_size),
+                        p_input->stream.p_selected_area->i_size );
+
+    AVI_SeekAbsolute( p_input, p_movi->i_chunk_pos + 12);
+    msg_Warn( p_input, "creating index from LIST-movi, will take time !" );
+    for( ;; )
     {
-        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 ) )
+        avi_packet_t pk;
+
+        if( AVI_PacketGetHeader( p_input, &pk ) )
         {
-            msg_Dbg( p_input, "read %d idx entries", i_totalentry );
-            return;
+            break;
         }
-        i_read /= 16 ;
-        for( i = 0; i < i_read; i++ )
-        {
-            byte_t  *p_peek = p_buff + i * 16;
-            i_totalentry++;
-            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( ( i_number <  p_avi_demux->i_streams )
-               &&(p_avi_demux->pp_info[i_number]->i_cat == 
-                     AVI_GetESTypeFromTwoCC( i_type ))) 
+        if( pk.i_stream < p_avi->i_streams &&
+            pk.i_cat == p_avi->pp_info[pk.i_stream]->i_cat )
+        {
+            AVIIndexEntry_t index;
+            index.i_id      = pk.i_fourcc;
+            index.i_flags   =
+               AVI_GetKeyFlag(p_avi->pp_info[pk.i_stream]->i_codec, pk.i_peek);
+            index.i_pos     = pk.i_pos;
+            index.i_length  = pk.i_size;
+            AVI_IndexAddEntry( p_avi, pk.i_stream, &index );
+        }
+        else
+        {
+            switch( pk.i_fourcc )
             {
-                __AVI_AddEntryIndex( p_avi_demux->pp_info[i_number],
-                                     &index );
+                case AVIFOURCC_idx1:
+                    goto print_stat;
+                case AVIFOURCC_rec:
+                case AVIFOURCC_JUNK:
+                    break;
+                default:
+                    msg_Warn( p_input, "need resync, probably broken avi" );
+                    if( AVI_PacketSearch( p_input ) )
+                    {
+                        msg_Warn( p_input, "lost sync, abord index creation" );
+                        goto print_stat;
+                    }
             }
         }
-        __RIFF_SkipBytes( p_input, 16 * i_read );
+        if( pk.i_pos + pk.i_size >= i_movi_end ||
+            AVI_PacketNext( p_input ) )
+        {
+            break;
+        }
+    }
+
+print_stat:
+    for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
+    {
+        msg_Dbg( p_input,
+                "stream[%d] creating %d index entries",
+                i_stream,
+                p_avi->pp_info[i_stream]->i_idxnb );
+    }
+}
+
+
+/*****************************************************************************
+ * Stream management
+ *****************************************************************************/
+static vlc_bool_t AVI_StreamStart ( input_thread_t *, demux_sys_t *, int );
+static int  AVI_StreamSeek   ( input_thread_t *, demux_sys_t *, int, mtime_t );
+static void AVI_StreamStop   ( input_thread_t *, demux_sys_t *, int );
+static int  AVI_StreamStopFinishedStreams( input_thread_t *, demux_sys_t * );
+
+static vlc_bool_t AVI_StreamStart( input_thread_t *p_input,
+                                   demux_sys_t *p_avi, int i_stream )
+{
+#define p_stream    p_avi->pp_info[i_stream]
+    if( !p_stream->p_es )
+    {
+        msg_Warn( p_input, "stream[%d] unselectable", i_stream );
+        return VLC_FALSE;
+    }
+    if( p_stream->b_activated )
+    {
+        msg_Warn( p_input, "stream[%d] already selected", i_stream );
+        return VLC_TRUE;
+    }
+
+    if( !p_stream->p_es->p_decoder_fifo )
+    {
+        vlc_mutex_lock( &p_input->stream.stream_lock );
+        input_SelectES( p_input, p_stream->p_es );
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+    }
+    p_stream->b_activated = p_stream->p_es->p_decoder_fifo ? VLC_TRUE
+                                                           : VLC_FALSE;
+    if( p_stream->b_activated && p_avi->b_seekable)
+    {
+        AVI_StreamSeek( p_input, p_avi, i_stream, p_avi->i_time );
+    }
+
+    return p_stream->b_activated;
+#undef  p_stream
+}
+
+static void    AVI_StreamStop( input_thread_t *p_input,
+                               demux_sys_t *p_avi, int i_stream )
+{
+#define p_stream    p_avi->pp_info[i_stream]
+
+    if( !p_stream->b_activated )
+    {
+        msg_Warn( p_input, "stream[%d] already unselected", i_stream );
+        return;
+    }
+
+    if( p_stream->p_es->p_decoder_fifo )
+    {
+        vlc_mutex_lock( &p_input->stream.stream_lock );
+        input_UnselectES( p_input, p_stream->p_es );
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
     }
 
+
+    p_stream->b_activated = VLC_FALSE;
+
+#undef  p_stream
 }
 
-/* XXX call after get p_movi */
-static void __AVI_UpdateIndexOffset( input_thread_t *p_input )
+static int AVI_StreamStopFinishedStreams( input_thread_t *p_input,
+                                           demux_sys_t *p_avi )
 {
-    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;
+    unsigned int i_stream;
+    int b_end;
 
-/* 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++ )
+    for( i_stream = 0,b_end = VLC_TRUE;
+            i_stream < p_avi->i_streams; i_stream++ )
     {
-        if( ( p_info->p_index )
-           && ( p_info->p_index[0].i_pos < p_avi_demux->p_movi->i_pos + 8 ))
+#define p_stream    p_avi->pp_info[i_stream]
+        if( p_stream->i_idxposc >= p_stream->i_idxnb )
         {
-            b_start = 0;
-            break;
+            AVI_StreamStop( p_input, p_avi, i_stream );
+        }
+        else
+        {
+            b_end = VLC_FALSE;
         }
+#undef  p_stream
     }
-    if( !b_start )
+    return( b_end );
+}
+/****************************************************************************
+ * AVI_MovieGetLength give max streams length in second
+ ****************************************************************************/
+static mtime_t  AVI_MovieGetLength( input_thread_t *p_input, demux_sys_t *p_avi )
+{
+    unsigned int i_stream;
+    mtime_t i_maxlength;
+
+    i_maxlength = 0;
+    for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
     {
-        for( i_stream = 0; i_stream < p_avi_demux->i_streams; i_stream++ )
+#define p_stream  p_avi->pp_info[i_stream]
+        mtime_t i_length;
+        /* fix length for each stream */
+        if( p_stream->i_idxnb < 1 || !p_stream->p_index )
         {
-            int i;
-            if( p_info->p_index )
-            {
-                for( i = 0; i < p_info->i_idxnb; i++ )
-                {
-                    p_info->p_index[i].i_pos += p_avi_demux->p_movi->i_pos + 8;
-                }
-            }
+            continue;
+        }
+
+        if( p_stream->i_samplesize )
+        {
+            i_length =
+                (mtime_t)( p_stream->p_index[p_stream->i_idxnb-1].i_lengthtotal +
+                           p_stream->p_index[p_stream->i_idxnb-1].i_length ) *
+                (mtime_t)p_stream->i_scale /
+                (mtime_t)p_stream->i_rate /
+                (mtime_t)p_stream->i_samplesize;
+        }
+        else
+        {
+            i_length = (mtime_t)p_stream->i_idxnb *
+                       (mtime_t)p_stream->i_scale /
+                       (mtime_t)p_stream->i_rate;
         }
+
+        msg_Dbg( p_input,
+                 "stream[%d] length:"I64Fd" (based on index)",
+                 i_stream,
+                 i_length );
+        i_maxlength = __MAX( i_maxlength, i_length );
+#undef p_stream
     }
-#undef p_info
+
+    return i_maxlength;
 }
 
 /*****************************************************************************
  * 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 )
-    {
-        for( i = 0; i < p_avi_demux->i_streams; i++ )
-        {
-            if( p_avi_demux->pp_info[i] ) 
+    unsigned int i;
+    demux_sys_t *p_avi = p_input->p_demux_data  ;
+
+    if( p_avi->pp_info )
+    {
+        for( i = 0; i < p_avi->i_streams; i++ )
+        {
+            if( p_avi->pp_info[i] )
             {
-                if( p_avi_demux->pp_info[i]->p_index )
+                if( p_avi->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->pp_info[i]->p_index );
                 }
-                free( p_avi_demux->pp_info[i] ); 
+                free( p_avi->pp_info[i] );
             }
         }
-         free( p_avi_demux->pp_info );
+         free( p_avi->pp_info );
+    }
+#ifdef __AVI_SUBTITLE__
+    if( p_avi->p_sub )
+    {
+        subtitle_Close( p_avi->p_sub );
+        p_avi->p_sub = NULL;
     }
+#endif
+    AVI_ChunkFreeRoot( p_input, &p_avi->ck_root );
+
+    FREE( p_input->p_demux_data );
 }
 
 /*****************************************************************************
  * AVIInit: check file and initializes AVI structures
  *****************************************************************************/
 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;
-
-    p_input->pf_demux = AVIDemux;
-
-    if( !( p_input->p_demux_data = 
-                    p_avi_demux = malloc( sizeof(demux_data_avi_file_t) ) ) )
-    {
-        msg_Err( p_input, "out of memory" );
-        return( -1 );
+    avi_chunk_t         ck_riff;
+    avi_chunk_list_t    *p_riff = (avi_chunk_list_t*)&ck_riff;
+    avi_chunk_list_t    *p_hdrl, *p_movi;
+#if 0
+    avi_chunk_list_t    *p_INFO;
+    avi_chunk_strz_t    *p_name;
+#endif
+    avi_chunk_avih_t    *p_avih;
+    demux_sys_t *p_avi;
+    es_descriptor_t *p_es = NULL; /* avoid warning */
+    unsigned int i;
+#ifdef __AVI_SUBTITLE__
+    mtime_t i_microsecperframe = 0; // for some subtitle format
+#endif
+
+    vlc_bool_t b_stream_audio, b_stream_video;
+
+    p_input->pf_demux = AVIDemux_Seekable;
+    if( AVI_TestFile( p_input ) )
+    {
+        msg_Warn( p_input, "avi module discarded (invalid headr)" );
+        return VLC_EGENERIC;
     }
-    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 ) );
 
     /* Initialize access plug-in structures. */
     if( p_input->i_mtu == 0 )
@@ -585,53 +825,75 @@ static int AVIInit( vlc_object_t * p_this )
         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
     }
 
-    if( RIFF_TestFileHeader( p_input, &p_riff, FOURCC_AVI ) != 0 )    
+    if( !( p_input->p_demux_data =
+                    p_avi = malloc( sizeof(demux_sys_t) ) ) )
     {
-        AVIEnd( p_input );
-        msg_Warn( p_input, "RIFF-AVI module discarded" );
-        return( -1 );
+        msg_Err( p_input, "out of memory" );
+        return VLC_ENOMEM;
     }
-    p_avi_demux->p_riff = p_riff;
+    memset( p_avi, 0, sizeof( demux_sys_t ) );
+    p_avi->i_time = 0;
+    p_avi->i_pcr  = 0;
+    p_avi->b_seekable = ( ( p_input->stream.b_seekable )
+                        &&( p_input->stream.i_method == INPUT_METHOD_FILE ) );
+    p_avi->i_movi_lastchunk_pos = 0;
 
-    if ( RIFF_DescendChunk(p_input) != 0 )
+    /* *** for unseekable stream, automaticaly use AVIDemux_interleaved *** */
+    if( !p_avi->b_seekable || config_GetInt( p_input, "avi-interleaved" ) )
     {
-        AVIEnd( p_input );
-        msg_Err( p_input, "cannot look for subchunk" );
-        return ( -1 );
+        p_input->pf_demux = AVIDemux_UnSeekable;
     }
 
-    /* it's a riff-avi file, so search for LIST-hdrl */
-    if( RIFF_FindListChunk(p_input ,&p_hdrl,p_riff, FOURCC_hdrl) != 0 )
+    if( AVI_ChunkReadRoot( p_input, &p_avi->ck_root, p_avi->b_seekable ) )
     {
-        AVIEnd( p_input );
-        msg_Err( p_input, "cannot find \"LIST-hdrl\"" );
-        return( -1 );
+        msg_Err( p_input, "avi module discarded (invalid file)" );
+        return VLC_EGENERIC;
     }
-    p_avi_demux->p_hdrl = p_hdrl;
+    AVI_ChunkDumpDebug( p_input, &p_avi->ck_root );
 
-    if( RIFF_DescendChunk(p_input) != 0 )
+
+    p_riff  = (avi_chunk_list_t*)AVI_ChunkFind( &p_avi->ck_root,
+                                                AVIFOURCC_RIFF, 0 );
+    p_hdrl  = (avi_chunk_list_t*)AVI_ChunkFind( p_riff,
+                                                AVIFOURCC_hdrl, 0 );
+    p_movi  = (avi_chunk_list_t*)AVI_ChunkFind( p_riff,
+                                                AVIFOURCC_movi, 0 );
+#if 0
+    p_INFO  = (avi_chunk_list_t*)AVI_ChunkFind( p_riff,
+                                                AVIFOURCC_INFO, 0 );
+    p_name  = (avi_chunk_strz_t*)AVI_ChunkFind( p_INFO,
+                                                AVIFOURCC_INAM, 0 );
+    if( p_name )
     {
-        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 )
+#endif
+
+    if( !p_hdrl || !p_movi )
     {
-        AVIEnd( p_input );
-        msg_Err( p_input, "cannot find \"avih\" chunk" );
-        return( -1 );
+        msg_Err( p_input, "avi module discarded (invalid file)" );
+        return VLC_EGENERIC;
     }
-    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 */
+
+    if( !( p_avih = (avi_chunk_avih_t*)AVI_ChunkFind( p_hdrl,
+                                                      AVIFOURCC_avih, 0 ) ) )
     {
-        AVIEnd( p_input );
+        msg_Err( p_input, "cannot find avih chunk" );
+        return VLC_EGENERIC;
+    }
+    p_avi->i_streams = AVI_ChunkCount( p_hdrl, AVIFOURCC_strl );
+    if( p_avih->i_streams != p_avi->i_streams )
+    {
+        msg_Warn( p_input,
+                  "found %d stream but %d are declared",
+                  p_avi->i_streams,
+                  p_avih->i_streams );
+    }
+    if( p_avi->i_streams == 0 )
+    {
+        AVIEnd( p_input );
         msg_Err( p_input, "no stream defined!" );
-        return( -1 );
+        return VLC_EGENERIC;
     }
 
     /*  create one program */
@@ -641,231 +903,291 @@ static int AVIInit( vlc_object_t * p_this )
         vlc_mutex_unlock( &p_input->stream.stream_lock );
         AVIEnd( p_input );
         msg_Err( p_input, "cannot init stream" );
-        return( -1 );
+        return VLC_EGENERIC;
     }
     if( input_AddProgram( p_input, 0, 0) == NULL )
     {
         vlc_mutex_unlock( &p_input->stream.stream_lock );
         AVIEnd( p_input );
         msg_Err( p_input, "cannot add program" );
-        return( -1 );
+        return VLC_EGENERIC;
     }
     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
-    p_input->stream.i_mux_rate = p_avi_demux->avih.i_maxbytespersec / 50;
-    vlc_mutex_unlock( &p_input->stream.stream_lock ); 
-
-    /* now read info on each stream and create ES */
-    p_avi_demux->i_streams = p_avi_demux->avih.i_streams;
-    
-    p_avi_demux->pp_info = calloc( p_avi_demux->i_streams, 
-                                    sizeof( AVIStreamInfo_t* ) );
-    memset( p_avi_demux->pp_info, 
-            0, 
-            sizeof( AVIStreamInfo_t* ) * p_avi_demux->i_streams );
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
 
-    for( i = 0 ; i < p_avi_demux->i_streams; i++ )
-    {
-#define p_info  p_avi_demux->pp_info[i]
-        p_info = malloc( sizeof(AVIStreamInfo_t ) );
-        memset( p_info, 0, sizeof( AVIStreamInfo_t ) );        
+    /* print informations on streams */
+    msg_Dbg( p_input, "AVIH: %d stream, flags %s%s%s%s ",
+             p_avi->i_streams,
+             p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
+             p_avih->i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
+             p_avih->i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
+             p_avih->i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" );
+    {
+        input_info_category_t *p_cat = input_InfoCategory( p_input, "Avi" );
+        input_AddInfo( p_cat, "Number of streams", "%d", p_avi->i_streams );
+        input_AddInfo( p_cat, "Flags", "%s%s%s%s",
+                       p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
+                       p_avih->i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
+                       p_avih->i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
+                       p_avih->i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" );
+    }
 
-        if( ( RIFF_FindListChunk(p_input,
-                                &p_strl,p_hdrl, FOURCC_strl) != 0 )
-                ||( RIFF_DescendChunk(p_input) != 0 ))
-        {
-            AVIEnd( p_input );
-            msg_Err( p_input, "cannot find \"LIST-strl\"" );
-            return( -1 );
-        }
-        
-        /* in  LIST-strl search strh */
-        if( RIFF_FindAndLoadChunk( p_input, p_hdrl, 
-                                &p_strh, FOURCC_strh ) != 0 )
+    /* now read info on each stream and create ES */
+    p_avi->pp_info = calloc( p_avi->i_streams,
+                            sizeof( avi_stream_t* ) );
+    memset( p_avi->pp_info,
+            0,
+            sizeof( avi_stream_t* ) * p_avi->i_streams );
+
+    for( i = 0 ; i < p_avi->i_streams; i++ )
+    {
+        avi_chunk_list_t    *p_avi_strl;
+        avi_chunk_strh_t    *p_avi_strh;
+        avi_chunk_strf_auds_t    *p_avi_strf_auds;
+        avi_chunk_strf_vids_t    *p_avi_strf_vids;
+        int     i_init_size;
+        void    *p_init_data;
+#define p_info  p_avi->pp_info[i]
+        p_info = malloc( sizeof(avi_stream_t ) );
+        memset( p_info, 0, sizeof( avi_stream_t ) );
+
+        p_avi_strl = (avi_chunk_list_t*)AVI_ChunkFind( p_hdrl,
+                                                       AVIFOURCC_strl, i );
+        p_avi_strh = (avi_chunk_strh_t*)AVI_ChunkFind( p_avi_strl,
+                                                       AVIFOURCC_strh, 0 );
+        p_avi_strf_auds = (avi_chunk_strf_auds_t*)
+            p_avi_strf_vids = (avi_chunk_strf_vids_t*)
+                AVI_ChunkFind( p_avi_strl, AVIFOURCC_strf, 0 );
+
+        if( !p_avi_strl || !p_avi_strh ||
+                ( !p_avi_strf_auds && !p_avi_strf_vids ) )
         {
-            RIFF_DeleteChunk( p_input, p_strl );
-            AVIEnd( p_input );
-            msg_Err( p_input, "cannot find \"strh\"" );
-            return( -1 );
+            msg_Warn( p_input, "stream[%d] incomlete", i );
+            continue;
         }
-        AVI_Parse_Header( &p_info->header,
-                            p_strh->p_data->p_payload_start);
-        RIFF_DeleteChunk( p_input, p_strh );      
 
-        /* in  LIST-strl search strf */
-        if( RIFF_FindAndLoadChunk( p_input, p_hdrl, 
-                                &p_strf, FOURCC_strf ) != 0 )
-        {
-            RIFF_DeleteChunk( p_input, p_strl );
-            AVIEnd( p_input );
-            msg_Err( p_input, "cannot find \"strf\"" );
-            return( -1 );
-        }
-        /* we don't get strd, it's useless for divx,opendivx,mepgaudio */ 
-        if( RIFF_AscendChunk(p_input, p_strl) != 0 )
+        /* *** Init p_info *** */
+        p_info->i_rate  = p_avi_strh->i_rate;
+        p_info->i_scale = p_avi_strh->i_scale;
+        p_info->i_samplesize = p_avi_strh->i_samplesize;
+        msg_Dbg( p_input, "stream[%d] rate:%d scale:%d samplesize:%d",
+                 i,
+                 p_info->i_rate, p_info->i_scale, p_info->i_samplesize );
+        switch( p_avi_strh->i_type )
         {
-            RIFF_DeleteChunk( p_input, p_strf );
-            RIFF_DeleteChunk( p_input, p_strl );
-            AVIEnd( p_input );
-            msg_Err( p_input, "cannot go out (\"strl\")" );
-            return( -1 );
-        }
-
-        /* add one ES */
-        vlc_mutex_lock( &p_input->stream.stream_lock );
-        p_es = input_AddES( p_input,
-                            p_input->stream.p_selected_program, 1+i,
-                            p_strf->i_size );
-        vlc_mutex_unlock( &p_input->stream.stream_lock );
-        p_es->i_stream_id =i; /* XXX: i don't use it */ 
-       
-        switch( p_info->header.i_type )
-        {
-            case( FOURCC_auds ):
-                p_es->i_cat = AUDIO_ES;
-                AVI_Parse_WaveFormatEx( &p_info->audio_format,
-                                   p_strf->p_data->p_payload_start ); 
-                p_es->i_fourcc = AVI_AudioGetType(
-                                     p_info->audio_format.i_formattag );
+            case( AVIFOURCC_auds ):
+                p_info->i_cat = AUDIO_ES;
+                p_info->i_fourcc =
+                    AVI_FourccGetCodec( AUDIO_ES,
+                                        p_avi_strf_auds->p_wf->wFormatTag );
+                p_info->i_codec  = p_info->i_fourcc;
+                i_init_size = p_avi_strf_auds->i_chunk_size;
+                p_init_data = p_avi_strf_auds->p_wf;
+                msg_Dbg( p_input, "stream[%d] audio(0x%x) %d channels %dHz %dbits",
+                        i,
+                        p_avi_strf_auds->p_wf->wFormatTag,
+                        p_avi_strf_auds->p_wf->nChannels,
+                        p_avi_strf_auds->p_wf->nSamplesPerSec,
+                        p_avi_strf_auds->p_wf->wBitsPerSample );
+                {
+                    char hepp[sizeof("Stream") + 10];
+                    input_info_category_t *p_cat;
+                    sprintf(hepp, "Stream %d", i);
+                    p_cat = input_InfoCategory( p_input, hepp);
+                    input_AddInfo( p_cat, "Type", "audio(0x%x)",
+                                   p_avi_strf_auds->p_wf->wFormatTag );
+                    input_AddInfo( p_cat, "Codec", "%4.4s",
+                                   (const char*)&(p_info->i_codec) );
+                    input_AddInfo( p_cat, "Channels", "%d",
+                                   p_avi_strf_auds->p_wf->nChannels );
+                    input_AddInfo( p_cat, "Samplerate", "%d",
+                                   p_avi_strf_auds->p_wf->nSamplesPerSec );
+                    input_AddInfo( p_cat, "Bits Per Sample", "%d",
+                                   p_avi_strf_auds->p_wf->wBitsPerSample );
+                }
                 break;
-                
-            case( FOURCC_vids ):
-                p_es->i_cat = VIDEO_ES;
-                AVI_Parse_BitMapInfoHeader( &p_info->video_format,
-                                   p_strf->p_data->p_payload_start ); 
 
-                /* XXX quick hack for playing ffmpeg video, I don't know 
+            case( AVIFOURCC_vids ):
+                p_info->i_cat = VIDEO_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;
+                p_info->i_samplesize = 0;
+                p_info->i_fourcc = p_avi_strf_vids->p_bih->biCompression;
+                p_info->i_codec =
+                    AVI_FourccGetCodec( VIDEO_ES, p_info->i_fourcc );
+                i_init_size = p_avi_strf_vids->i_chunk_size;
+                p_init_data = p_avi_strf_vids->p_bih;
+                msg_Dbg( p_input, "stream[%d] video(%4.4s) %dx%d %dbpp %ffps",
+                        i,
+                         (char*)&p_avi_strf_vids->p_bih->biCompression,
+                         p_avi_strf_vids->p_bih->biWidth,
+                         p_avi_strf_vids->p_bih->biHeight,
+                         p_avi_strf_vids->p_bih->biBitCount,
+                         (float)p_info->i_rate /
+                             (float)p_info->i_scale );
+                {
+                    char hepp[sizeof("Stream") + 10];
+                    input_info_category_t *p_cat;
+                    sprintf(hepp, "stream %d", i);
+                    p_cat = input_InfoCategory( p_input, hepp);
+                    input_AddInfo( p_cat, "Type", "video" );
+                    input_AddInfo( p_cat, "Codec", "%4.4s",
+                                   (const char*)&(p_info->i_codec) );
+                    input_AddInfo( p_cat, "Resolution", "%dx%d",
+                                   p_avi_strf_vids->p_bih->biWidth,
+                                   p_avi_strf_vids->p_bih->biHeight );
+                    input_AddInfo( p_cat, "Frame Rate", "%f",
+                                   (float)p_info->i_rate /
+                                       (float)p_info->i_scale );
+                    input_AddInfo( p_cat, "Bits Per Pixel", "%d",
+                                   p_avi_strf_vids->p_bih->biBitCount );
+                }
+#ifdef __AVI_SUBTITLE__
+                if( i_microsecperframe == 0 )
+                {
+                    i_microsecperframe = (mtime_t)1000000 *
+                                         (mtime_t)p_info->i_scale /
+                                         (mtime_t)p_info->i_rate;
+                }
+#endif
                 break;
             default:
-                msg_Err( p_input, "unknown stream(%d) type", i );
-                p_es->i_cat = UNKNOWN_ES;
+                msg_Warn( p_input, "stream[%d] unknown type", i );
+                p_info->i_cat = UNKNOWN_ES;
+                i_init_size = 0;
+                p_init_data = NULL;
+                {
+                    char psz_cat[32]; /* We'll clip i just in case */
+                    input_info_category_t *p_cat;
+                    sprintf( psz_cat, "stream %d", __MIN( i, 100000 ) );
+                    p_cat = input_InfoCategory( p_input, psz_cat );
+                    input_AddInfo( p_cat, "Type", "unknown" );
+                }
                 break;
         }
-        p_info->p_es = p_es;
-        p_info->i_cat = p_es->i_cat;
-        /* We copy strf for decoder in p_es->p_demux_data */
-        memcpy( p_es->p_demux_data, 
-                p_strf->p_data->p_payload_start,
-                p_strf->i_size );
-        RIFF_DeleteChunk( p_input, p_strf );
-        RIFF_DeleteChunk( p_input, p_strl );
-#undef p_info           
+        p_info->b_activated = VLC_FALSE;
+        /* add one ES */
+        vlc_mutex_lock( &p_input->stream.stream_lock );
+        p_info->p_es =
+            p_es = input_AddES( p_input,
+                                p_input->stream.p_selected_program, 1+i,
+                                0 );
+        vlc_mutex_unlock( &p_input->stream.stream_lock );
+        p_es->i_stream_id =i; /* XXX: i don't use it */
+        p_es->i_fourcc = p_info->i_fourcc;
+        p_es->i_cat = p_info->i_cat;
+        if( p_es->i_cat == AUDIO_ES )
+        {
+            p_es->p_waveformatex = malloc( i_init_size );
+            memcpy( p_es->p_waveformatex, p_init_data, i_init_size );
+        }
+        else if( p_es->i_cat == VIDEO_ES )
+        {
+            p_es->p_bitmapinfoheader = malloc( i_init_size );
+            memcpy( p_es->p_bitmapinfoheader, p_init_data, i_init_size );
+        }
+#undef p_info
     }
 
-
-
-    /* go out of p_hdrl */
-    if( RIFF_AscendChunk(p_input, p_hdrl) != 0)
+#ifdef __AVI_SUBTITLE__
+    if( ( p_avi->p_sub = subtitle_New( p_input, NULL, i_microsecperframe ) ) )
     {
-        AVIEnd( p_input );
-        msg_Err( p_input, "cannot go out (\"hdrl\")" );
-        return( -1 );
+        subtitle_Select( p_avi->p_sub );
     }
+#endif
 
-    /* go to movi chunk to get it*/
-    if( RIFF_FindListChunk(p_input ,&p_movi,p_riff, FOURCC_movi) != 0 )
+    if( config_GetInt( p_input, "avi-index" ) )
     {
-        msg_Err( p_input, "cannot find \"LIST-movi\"" );
-        AVIEnd( p_input );
-        return( -1 );
+        if( p_avi->b_seekable )
+        {
+            AVI_IndexCreate( p_input );
+        }
+        else
+        {
+            msg_Warn( p_input, "cannot create index (unseekable stream)" );
+            AVI_IndexLoad( p_input );
+        }
     }
-    p_avi_demux->p_movi = p_movi;
-    
-    /* get index  XXX need to have p_movi */
-    if( p_avi_demux->b_seekable )
+    else
     {
-        /* get index */
-        __AVI_GetIndex( p_input ); 
-        /* try to get i_idxoffset for each stream  */
-        __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 );
-
+        AVI_IndexLoad( p_input );
     }
-    else
+
+    /* *** movie length in sec *** */
+    p_avi->i_length = AVI_MovieGetLength( p_input, p_avi );
+    if( p_avi->i_length < (mtime_t)p_avih->i_totalframes *
+                          (mtime_t)p_avih->i_microsecperframe /
+                          (mtime_t)1000000 )
     {
-        msg_Warn( p_input, "no index!" );
+        msg_Warn( p_input, "broken or missing index, 'seek' will be axproximative or will have strange behavour" );
     }
 
-    if( RIFF_DescendChunk( p_input ) != 0 )
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    if( p_avi->i_length )
     {
-        AVIEnd( p_input );
-        msg_Err( p_input, "cannot go in (\"movi\")" );
-        return( -1 );
+        p_input->stream.i_mux_rate =
+            p_input->stream.p_selected_area->i_size / 50 / p_avi->i_length;
+    }
+    else
+    {
+        p_input->stream.i_mux_rate = 0;
     }
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
 
-    /* print informations on streams */
-    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":"" );
+    b_stream_audio = VLC_FALSE;
+    b_stream_video = VLC_FALSE;
 
-    for( i = 0; i < p_avi_demux->i_streams; i++ )
+    for( i = 0; i < p_avi->i_streams; i++ )
     {
-#define p_info  p_avi_demux->pp_info[i]
+#define p_info  p_avi->pp_info[i]
         switch( p_info->p_es->i_cat )
         {
             case( VIDEO_ES ):
 
-                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) ) 
+                if( !b_stream_video )
                 {
-                    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 );
+                    b_stream_video = AVI_StreamStart( p_input, p_avi, i );
                 }
                 break;
 
             case( AUDIO_ES ):
-                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) ) 
+                if( !b_stream_audio )
                 {
-                    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 );
+                    b_stream_audio = AVI_StreamStart( p_input, p_avi, i );
                 }
                 break;
             default:
                 break;
         }
-#undef p_info    
+#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 ) 
+    if( !b_stream_video )
     {
         msg_Warn( p_input, "no video stream found" );
     }
-    if( !p_avi_demux->p_info_audio )
+    if( !b_stream_audio )
     {
         msg_Warn( p_input, "no audio stream found!" );
     }
+
+    vlc_mutex_lock( &p_input->stream.stream_lock );
     p_input->stream.p_selected_program->b_is_ok = 1;
     vlc_mutex_unlock( &p_input->stream.stream_lock );
 
-    return( 0 );
-}
-
+    if( p_avi->b_seekable )
+    {
+        AVI_ChunkGoto( p_input, p_movi );
+    }
+    else
+    {
+        // already at begining of p_movi
+    }
+    AVI_SkipBytes( p_input, 12 ); // enter in p_movi
 
+    p_avi->i_movi_begin = p_movi->i_chunk_pos;
+    return VLC_SUCCESS;
+}
 
 
 
@@ -874,31 +1196,51 @@ static int AVIInit( vlc_object_t * p_this )
  * Function to convert pts to chunk or byte
  *****************************************************************************/
 
-static inline mtime_t AVI_PTSToChunk( AVIStreamInfo_t *p_info, 
+static inline mtime_t AVI_PTSToChunk( avi_stream_t *p_info,
                                         mtime_t i_pts )
 {
-    return( (mtime_t)((s64)i_pts *
-                      (s64)p_info->header.i_rate /
-                      (s64)p_info->header.i_scale /
-                      (s64)1000000 ) );
+    return (mtime_t)((int64_t)i_pts *
+                     (int64_t)p_info->i_rate /
+                     (int64_t)p_info->i_scale /
+                     (int64_t)1000000 );
 }
-static inline mtime_t AVI_PTSToByte( AVIStreamInfo_t *p_info,
+static inline mtime_t AVI_PTSToByte( avi_stream_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 ) );
+    return (mtime_t)((int64_t)i_pts *
+                     (int64_t)p_info->i_rate /
+                     (int64_t)p_info->i_scale /
+                     (int64_t)1000000 *
+                     (int64_t)p_info->i_samplesize );
+}
+
+static mtime_t AVI_GetDPTS( avi_stream_t *p_stream, int i_count )
+{
+    if( p_stream->i_samplesize )
+    {
+        return (mtime_t)( (int64_t)1000000 *
+                   (int64_t)i_count *
+                   (int64_t)p_stream->i_scale /
+                   (int64_t)p_stream->i_rate /
+                   (int64_t)p_stream->i_samplesize );
+    }
+    else
+    {
+        return (mtime_t)( (int64_t)1000000 *
+                   (int64_t)i_count *
+                   (int64_t)p_stream->i_scale /
+                   (int64_t)p_stream->i_rate);
+    }
 
 }
-static mtime_t AVI_GetPTS( AVIStreamInfo_t *p_info )
+
+static mtime_t AVI_GetPTS( avi_stream_t *p_info )
 {
-    
-    if( p_info->header.i_samplesize )
+
+    if( p_info->i_samplesize )
     {
         /* we need a valid entry we will emulate one */
-        int i_len;
+        int64_t i_len;
         if( p_info->i_idxposc == p_info->i_idxnb )
         {
             if( p_info->i_idxposc )
@@ -910,7 +1252,7 @@ static mtime_t AVI_GetPTS( AVIStreamInfo_t *p_info )
             }
             else
             {
-                i_len = p_info->i_idxposb; 
+                i_len = p_info->i_idxposb;
                 /* no valid entry use only offset*/
             }
         }
@@ -919,1310 +1261,958 @@ static mtime_t AVI_GetPTS( AVIStreamInfo_t *p_info )
             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 ) );
+        return (mtime_t)( (int64_t)1000000 *
+                  (int64_t)i_len *
+                   (int64_t)p_info->i_scale /
+                   (int64_t)p_info->i_rate /
+                   (int64_t)p_info->i_samplesize );
     }
     else
     {
-        /* 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) );
+        /* even if p_info->i_idxposc isn't valid, there isn't any problem */
+        return (mtime_t)( (int64_t)1000000 *
+                   (int64_t)(p_info->i_idxposc ) *
+                   (int64_t)p_info->i_scale /
+                   (int64_t)p_info->i_rate);
     }
 }
 
-
-/*****************************************************************************
- * 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 
- *****************************************************************************/
-
-/* 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 )
+static int AVI_StreamChunkFind( input_thread_t *p_input,
+                                unsigned int i_stream )
 {
+    demux_sys_t *p_avi = p_input->p_demux_data;
+    avi_packet_t avi_pk;
 
-    int i_read;
-    data_packet_t *p_data;
-
-    
-    if( !(*pp_pes = input_NewPES( p_input->p_method_data ) ) )
-    {
-        return( 0 );
-    }
-
-    
-    if( !i_size )
-    {
-        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 );
-    }
-    
-    if( ( i_size&1 )&&( b_pad ) )
-    {
-        b_pad = 1;
-        i_size++;
-    }
-    else
-    {
-        b_pad = 0;
-    }
+    /* find first chunk of i_stream that isn't in index */
 
-    do
+    if( p_avi->i_movi_lastchunk_pos >= p_avi->i_movi_begin )
     {
-        i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size - 
-                                                              (*pp_pes)->i_pes_size, 1024 ) );
-        if( i_read < 0 )
-        {
-            return( (*pp_pes)->i_pes_size );
-        }
-        if( !(*pp_pes)->p_first )
+        AVI_SeekAbsolute( p_input, p_avi->i_movi_lastchunk_pos );
+        if( AVI_PacketNext( p_input ) )
         {
-            (*pp_pes)->p_first = 
-                    (*pp_pes)->p_last  = p_data;
-            (*pp_pes)->i_nb_data = 1;
-            (*pp_pes)->i_pes_size = i_read;
+            return VLC_EGENERIC;
         }
-        else
-        {
-            (*pp_pes)->p_last->p_next = 
-                    (*pp_pes)->p_last = p_data;
-            (*pp_pes)->i_nb_data++;
-            (*pp_pes)->i_pes_size += i_read;
-        }
-    } 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 );
-}
-
-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);
-
-    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 inline int __AVI_GetChunkMethod( input_thread_t  *p_input,
-                                 AVIStreamInfo_t *p_info,
-                                 AVIStreamInfo_t *p_other )
-{
-    int i_info_pos;
-    int i_other_pos;
-    
-    int i_info_pos_last;
-    int i_other_pos_last;
-
-    /*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_info->i_idxposc )&&( i_info_pos <= i_info_pos_last ) ) ||
-        ( ( p_other->i_idxposc )&&( i_other_pos <= i_other_pos_last ) ) )
-    {
-        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 )
+    else
     {
-        return( 0 );
+        AVI_SeekAbsolute( p_input, p_avi->i_movi_begin );
     }
-    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)
+    for( ;; )
     {
-        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
+        if( AVI_PacketGetHeader( p_input, &avi_pk ) )
         {
-            AVI_PESBuffer_Drop( p_input->p_method_data, p_info );
+            msg_Warn( p_input, "cannot get packet header" );
+            return VLC_EGENERIC;
         }
-    }
-    /* 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 ;
-
-    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 )
-    {
-        /* 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++ )
+        if( avi_pk.i_stream >= p_avi->i_streams ||
+            ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) )
         {
-            if( p_info_i->i_idxnb )
+            switch( avi_pk.i_fourcc )
             {
-                if( p_info_max->i_idxnb )
-                {
-                    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 )
+                case AVIFOURCC_LIST:
+                    AVI_SkipBytes( p_input, 12 );
+                    break;
+                default:
+                    if( AVI_PacketNext( p_input ) )
                     {
-                        p_info_max = p_info_i;
+                        return VLC_EGENERIC;
                     }
-                }
-                else
-                {
-                    p_info_max = p_info_i;
-                }
-            }
-        }
-        if( p_info_max->i_idxnb )
-        {
-            /* 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 */
-        }
-        else
-        {
-            i_posmax = p_avi_demux->p_movi->i_pos + 12;
-        }
-    }
-    else
-    {
-        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;
-    }
-
-    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 */
-    {
-        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*/
-            
-        {
-            RIFF_DeleteChunk( p_input, p_ck );
-            if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
-            {
-                return( 0 );
+                    break;
             }
         }
         else
         {
-            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))
+            /* add this chunk to the index */
+            AVIIndexEntry_t index;
+
+            index.i_id = avi_pk.i_fourcc;
+            index.i_flags =
+               AVI_GetKeyFlag(p_avi->pp_info[avi_pk.i_stream]->i_codec,
+                              avi_pk.i_peek);
+            index.i_pos = avi_pk.i_pos;
+            index.i_length = avi_pk.i_size;
+            AVI_IndexAddEntry( p_avi, avi_pk.i_stream, &index );
+
+            if( avi_pk.i_stream == i_stream  )
             {
-                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 );   
+                return VLC_SUCCESS;
             }
 
-
-            /* 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 )
-                {
-                    if( !__AVI_GetAndPutChunkInBuffer( p_input, p_other, 
-                                                       i_size, i_ck ) )
-                    {
-                        RIFF_DeleteChunk( p_input, p_ck );
-                        return( 0 );
-                    }
-                }
-                else
-                {
-                    if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
-                    {
-                        RIFF_DeleteChunk( p_input, p_ck );
-
-                        return( 0 );
-                    }
-
-                }
-                        
-                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
+            if( AVI_PacketNext( p_input ) )
             {
-                /* skip it */
-                RIFF_DeleteChunk( p_input, p_ck );
-                if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
-                {
-                    return( 0 );
-                }
+                return VLC_EGENERIC;
             }
         }
-
-    
     }
-    
-#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 )
+                               unsigned int i_stream,
+                               unsigned int i_ck )
 {
+    demux_sys_t *p_avi = p_input->p_demux_data;
+    avi_stream_t *p_stream = p_avi->pp_info[i_stream];
 
-    p_info->i_idxposc = i_ck;
-    p_info->i_idxposb = 0;
+    p_stream->i_idxposc = i_ck;
+    p_stream->i_idxposb = 0;
 
-    if(  i_ck < p_info->i_idxnb )
-    {
-        return( 1 );
-    }
-    else
+    if(  i_ck >= p_stream->i_idxnb )
     {
-        p_info->i_idxposc = p_info->i_idxnb - 1;
+        p_stream->i_idxposc = p_stream->i_idxnb - 1;
         do
         {
-            p_info->i_idxposc++;
-            if( !__AVI_GetChunk( p_input, p_info, 0 ) )
+            p_stream->i_idxposc++;
+            if( AVI_StreamChunkFind( p_input, i_stream ) )
             {
-                return( 0 );
+                return VLC_EGENERIC;
             }
-        } while( p_info->i_idxposc < i_ck );
 
-        return( 1 );
+        } while( p_stream->i_idxposc < i_ck );
     }
+
+    return VLC_SUCCESS;
 }
 
 
 /* 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,
+static int AVI_SetStreamBytes( input_thread_t    *p_input,
+                               unsigned int i_stream,
                                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 ) )
+    demux_sys_t *p_avi = p_input->p_demux_data;
+    avi_stream_t *p_stream = p_avi->pp_info[i_stream];
+
+    if( ( p_stream->i_idxnb > 0 )
+        &&( i_byte < p_stream->p_index[p_stream->i_idxnb - 1].i_lengthtotal +
+                p_stream->p_index[p_stream->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_idxposc = __MIN( p_stream->i_idxposc, p_stream->i_idxnb - 1 );
+        int i_idxmax  = p_stream->i_idxnb;
         int i_idxmin  = 0;
         for( ;; )
         {
-            if( p_info->p_index[i_idxposc].i_lengthtotal > i_byte )
+            if( p_stream->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)
+                if( p_stream->p_index[i_idxposc].i_lengthtotal +
+                        p_stream->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 );
+                    p_stream->i_idxposc = i_idxposc;
+                    p_stream->i_idxposb = i_byte -
+                            p_stream->p_index[i_idxposc].i_lengthtotal;
+                    return VLC_SUCCESS;
                 }
             }
         }
-        
+
     }
     else
     {
-        p_info->i_idxposc = p_info->i_idxnb - 1;
-        p_info->i_idxposb = 0;
+        p_stream->i_idxposc = p_stream->i_idxnb - 1;
+        p_stream->i_idxposb = 0;
         do
         {
-            p_info->i_idxposc++;
-            if( !__AVI_GetChunk( p_input, p_info, 0 ) )
+            p_stream->i_idxposc++;
+            if( AVI_StreamChunkFind( p_input, i_stream ) )
             {
-                return( 0 );
+                return VLC_EGENERIC;
             }
-        } 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 );
+        } while( p_stream->p_index[p_stream->i_idxposc].i_lengthtotal +
+                    p_stream->p_index[p_stream->i_idxposc].i_length <= i_byte );
+
+        p_stream->i_idxposb = i_byte -
+                       p_stream->p_index[p_stream->i_idxposc].i_lengthtotal;
+        return VLC_SUCCESS;
     }
 }
 
-static pes_packet_t *AVI_ReadStreamChunkInPES(  input_thread_t  *p_input,
-                                                AVIStreamInfo_t *p_info )
-
+static int AVI_StreamSeek( input_thread_t *p_input,
+                           demux_sys_t  *p_avi,
+                           int i_stream,
+                           mtime_t i_date )
 {
-    if( p_info->i_idxposc > p_info->i_idxnb )
-    {
-        return( NULL );
-    }
+#define p_stream    p_avi->pp_info[i_stream]
+    mtime_t i_oldpts;
+
+    i_oldpts = AVI_GetPTS( p_stream );
 
-    /* we want chunk (p_info->i_idxposc,0) */
-    p_info->i_idxposb = 0;
-    if( !__AVI_GetChunk( p_input, p_info, 1) )
+    if( !p_stream->i_samplesize )
     {
-        msg_Err( p_input, "Got one chunk : failed" );
-        return( NULL );
-    }
-    p_info->i_idxposc++;
-    return( AVI_PESBuffer_Get( p_info ) );
-}
+        if( AVI_SetStreamChunk( p_input,
+                                i_stream,
+                                AVI_PTSToChunk( p_stream, i_date ) ) )
+        {
+            return VLC_EGENERIC;
+        }
 
-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;
+        /* search key frame */
+        msg_Dbg( p_input,
+                 "old:"I64Fd" %s new "I64Fd,
+                 i_oldpts,
+                 i_oldpts > i_date ? ">" : "<",
+                 i_date );
 
-        
-    if( !( p_pes = input_NewPES( p_input->p_method_data ) ) )
-    {
-        return( NULL );
-    }
-    if( !( p_data = input_NewPacket( p_input->p_method_data, i_byte ) ) )
-    {
-        input_DeletePES( p_input->p_method_data, p_pes );
-        return( NULL );
-    }
-
-    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_GetChunk( p_input, p_info, 1) )
-        {
-         msg_Err( p_input, "Got one chunk : failed" );
-           
-            input_DeletePES( p_input->p_method_data, p_pes );
-            return( NULL );
-        }
-
-        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;
-        if( p_info->p_index[p_info->i_idxposc].i_length <= p_info->i_idxposb )
+        if( i_date < i_oldpts )
         {
-            p_info->i_idxposb -= p_info->p_index[p_info->i_idxposc].i_length;
-            p_info->i_idxposc++;
-        }
-    }
-   return( p_pes );
-}
-        
-
-
-/* try to realign after a seek */
-static int AVI_ReAlign( input_thread_t *p_input,
-                        AVIStreamInfo_t *p_info )
-{
-    int i;
-    off_t   i_pos;
-    int     b_after = 0;
-    demux_data_avi_file_t *p_avi_demux =
-                        (demux_data_avi_file_t*)p_input->p_demux_data;
-
-
-    for( i = 0; i < p_avi_demux->i_streams; i++ )
-    {
-        AVI_PESBuffer_Flush( p_input->p_method_data, p_avi_demux->pp_info[i] );
-    }
-    /* 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 ) )
-    {
-        /*  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_pos )
-           &&( p_info->i_idxposc > 0 ) )
-    {
-        /* search before 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_pos +
-               p_info->p_index[p_info->i_idxposc].i_length + 8 )
-    {
-        /* search after i_idxposc */
-
-        if( !AVI_SetStreamChunk( p_input, p_info, p_info->i_idxposc + 1 ) )
-        {
-            return( 0 );
-        }
-    }
-
-    /* search nearest key frame, only for video */
-    if( p_info->i_cat == VIDEO_ES )
-    {
-        if( b_after )
-        {
-            while(!(p_info->p_index[p_info->i_idxposc].i_flags&AVIIF_KEYFRAME) )
+            while( p_stream->i_idxposc > 0 &&
+               !( p_stream->p_index[p_stream->i_idxposc].i_flags &
+                                                            AVIIF_KEYFRAME ) )
             {
-                if( !AVI_SetStreamChunk( p_input, p_info, 
-                                         p_info->i_idxposc + 1 ) )
+                if( AVI_SetStreamChunk( p_input,
+                                        i_stream,
+                                        p_stream->i_idxposc - 1 ) )
                 {
-                    return( 0 );
+                    return VLC_EGENERIC;
                 }
             }
         }
         else
-        { 
-            while( ( p_info->i_idxposc > 0 ) &&
-              (!(p_info->p_index[p_info->i_idxposc].i_flags&AVIIF_KEYFRAME)) )
+        {
+            while( p_stream->i_idxposc < p_stream->i_idxnb &&
+                    !( p_stream->p_index[p_stream->i_idxposc].i_flags &
+                                                            AVIIF_KEYFRAME ) )
             {
-
-                if( !AVI_SetStreamChunk( p_input, p_info, 
-                                        p_info->i_idxposc - 1 ) )
+                if( AVI_SetStreamChunk( p_input,
+                                        i_stream,
+                                        p_stream->i_idxposc + 1 ) )
                 {
-
-                    return( 0 );
+                    return VLC_EGENERIC;
                 }
             }
         }
-    } 
-    return( 1 );
-}
-
-/* make difference between audio and video pts as little as possible */
-static void AVI_SynchroReInit( input_thread_t *p_input )
-{
-    demux_data_avi_file_t *p_avi_demux =
-                        (demux_data_avi_file_t*)p_input->p_demux_data;
-    
-#define p_info_video p_avi_demux->p_info_video
-#define p_info_audio p_avi_demux->p_info_audio
-    if( ( !p_info_audio )||( !p_info_video ) )
-    {
-        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
     {
-        AVI_SetStreamBytes( p_input,
-                            p_info_audio,
-                            AVI_PTSToByte( p_info_audio,
-                                            AVI_GetPTS( p_info_video ) ) ); 
+        if( AVI_SetStreamBytes( p_input,
+                                i_stream,
+                                AVI_PTSToByte( p_stream, i_date ) ) )
+        {
+            return VLC_EGENERIC;
+        }
     }
-#undef p_info_video
-#undef p_info_audio
-} 
+    return VLC_SUCCESS;
+#undef p_stream
+}
 
 /*****************************************************************************
- * AVI_GetFrameInPES : get dpts length(µs) in pes from stream
+ * AVISeek: goto to i_date or i_percent
  *****************************************************************************
- * Handle multiple pes, and set pts to the good value 
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
  *****************************************************************************/
-static pes_packet_t *AVI_GetFrameInPES( input_thread_t *p_input,
-                                        AVIStreamInfo_t *p_info,
-                                        mtime_t i_dpts)
+static int    AVISeek   ( input_thread_t *p_input,
+                          mtime_t i_date, int i_percent )
 {
-    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;
 
-    if( i_dpts < 1000 ) 
-    { 
-        return( NULL ) ; 
-    }
+    demux_sys_t *p_avi = p_input->p_demux_data;
+    unsigned int i_stream;
+    msg_Dbg( p_input,
+             "seek requested: "I64Fd" secondes %d%%",
+             i_date / 1000000,
+             i_percent );
 
-    if( !p_info->header.i_samplesize )
+    if( p_avi->b_seekable )
     {
-        int i_chunk = __MAX( AVI_PTSToChunk( p_info, i_dpts), 1 );
-        p_pes_first = NULL;
-        for( i = 0; i < i_chunk; i++ )
+        if( !p_avi->i_length )
         {
-            /* get pts while is valid */
-            i_pts = AVI_GetPTS( p_info ); 
-            p_pes_tmp = AVI_ReadStreamChunkInPES( p_input, p_info );
+            avi_stream_t *p_stream;
+            uint64_t i_pos;
 
-            if( !p_pes_tmp )
+            /* use i_percent to create a true i_date */
+            msg_Warn( p_input,
+                      "mmh, seeking without index at %d%%"
+                      " work only for interleaved file", i_percent );
+
+            if( i_percent >= 100 )
             {
-                return( p_pes_first );
+                msg_Warn( p_input, "cannot seek so far !" );
+                return( -1 );
             }
-            p_pes_tmp->i_pts = i_pts;
-            if( !p_pes_first )
+            i_percent = __MAX( i_percent, 0 );
+
+            /* try to find chunk that is at i_percent or the file */
+            i_pos = __MAX( i_percent *
+                           p_input->stream.p_selected_area->i_size / 100,
+                           p_avi->i_movi_begin );
+            /* search first selected stream */
+            for( i_stream = 0, p_stream = NULL;
+                        i_stream < p_avi->i_streams; i_stream++ )
             {
-                p_pes_first = p_pes_tmp;
+                p_stream = p_avi->pp_info[i_stream];
+                if( p_stream->b_activated )
+                {
+                    break;
+                }
             }
-            else
+            if( !p_stream || !p_stream->b_activated )
+            {
+                msg_Warn( p_input, "cannot find any selected stream" );
+                return( -1 );
+            }
+
+            /* be sure that the index exit */
+            if( AVI_SetStreamChunk( p_input,
+                                    i_stream,
+                                    0 ) )
             {
-                p_pes->p_next = p_pes_tmp;
+                msg_Warn( p_input, "cannot seek" );
+                return( -1 );
             }
-            p_pes = p_pes_tmp;
+
+            while( i_pos >= p_stream->p_index[p_stream->i_idxposc].i_pos +
+               p_stream->p_index[p_stream->i_idxposc].i_length + 8 )
+            {
+                /* search after i_idxposc */
+                if( AVI_SetStreamChunk( p_input,
+                                        i_stream, p_stream->i_idxposc + 1 ) )
+                {
+                    msg_Warn( p_input, "cannot seek" );
+                    return( -1 );
+                }
+            }
+            i_date = AVI_GetPTS( p_stream );
+            /* TODO better support for i_samplesize != 0 */
+            msg_Dbg( p_input, "estimate date "I64Fd, i_date );
         }
-        return( p_pes_first );
-    }
-    else
-    {
-        /* stream is byte based */
-        int i_byte = AVI_PTSToByte( p_info, i_dpts);
-        if( i_byte < 50 ) /* to avoid some problem with audio */
+
+#define p_stream    p_avi->pp_info[i_stream]
+        p_avi->i_time = 0;
+        /* seek for chunk based streams */
+        for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
         {
-            return( NULL );
+            if( p_stream->b_activated && !p_stream->i_samplesize )
+//            if( p_stream->b_activated )
+            {
+                AVI_StreamSeek( p_input, p_avi, i_stream, i_date );
+                p_avi->i_time = __MAX( AVI_GetPTS( p_stream ),
+                                        p_avi->i_time );
+            }
         }
-        i_pts = AVI_GetPTS( p_info );  /* ok even with broken index */
-        p_pes = AVI_ReadStreamBytesInPES( p_input, p_info, i_byte);
-
-        if( p_pes )
+#if 1
+        if( p_avi->i_time )
+        {
+            i_date = p_avi->i_time;
+        }
+        /* seek for bytes based streams */
+        for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
+        {
+            if( p_stream->b_activated && p_stream->i_samplesize )
+            {
+                AVI_StreamSeek( p_input, p_avi, i_stream, i_date );
+//                p_avi->i_time = __MAX( AVI_GetPTS( p_stream ), p_avi->i_time );
+            }
+        }
+        msg_Dbg( p_input, "seek: "I64Fd" secondes", p_avi->i_time /1000000 );
+        /* set true movie time */
+#endif
+        if( !p_avi->i_time )
         {
-            p_pes->i_pts = i_pts;
+            p_avi->i_time = i_date;
         }
-        return( p_pes );
+#undef p_stream
+        return( 1 );
+    }
+    else
+    {
+        msg_Err( p_input, "shouldn't yet be executed" );
+        return( -1 );
     }
 }
-/*****************************************************************************
- * 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 )
+
+#if 0
+static pes_packet_t *PES_split( input_thread_t *p_input, avi_stream_t *p_stream, pes_packet_t *p_pes )
 {
-    pes_packet_t    *p_pes_next;
-    /* input_decode want only one pes, but AVI_GetFrameInPES give
-          multiple pes so send one by one */
-    while( p_pes )
-    {
-        p_pes_next = p_pes->p_next;
-        p_pes->p_next = NULL;
-        p_pes->i_pts = input_ClockGetTS( p_input, 
-                                         p_input->stream.p_selected_program, 
-                                         p_pes->i_pts * 9/100);
-        input_DecodePES( p_info->p_es->p_decoder_fifo, p_pes );
-        p_pes = p_pes_next;
-    }
-  
+    pes_packet_t  *p_pes2;
+    data_packet_t *p_data;
+    int           i_nb_data;
+
+    if( p_pes->i_nb_data < 2 )
+    {
+        return( NULL );
+    }
+    p_pes2 = input_NewPES( p_input->p_method_data );
+    p_pes2->i_pts = p_pes->i_pts;
+    p_pes2->i_dts = p_pes->i_dts;
+    p_pes2->i_nb_data = p_pes->i_nb_data/2;
+    p_pes2->i_pes_size = 0;
+    for( i_nb_data = 0, p_data = p_pes->p_first;
+         i_nb_data < p_pes2->i_nb_data;
+         i_nb_data++, p_data = p_data->p_next )
+    {
+        p_pes2->i_pes_size +=
+            p_data->p_payload_end - p_data->p_payload_start;
+        p_pes2->p_last = p_data;
+    }
+    p_pes2->p_first = p_pes->p_first;
+    p_pes2->p_last->p_next = NULL;
+
+    p_pes->p_first = p_data;
+    p_pes->i_pes_size -= p_pes2->i_pes_size;
+    p_pes->i_nb_data -= p_pes2->i_nb_data;
+//    p_pes->i_pts += AVI_GetDPTS( p_stream, p_pes2->i_pes_size );
+//    p_pes->i_dts += AVI_GetDPTS( p_stream, p_pes2->i_pes_size );
+    p_pes->i_pts = 0;
+    p_pes->i_dts = 0;
+    return( p_pes2 );
 }
+#endif
 
 /*****************************************************************************
  * AVIDemux_Seekable: reads and demuxes data packets for stream seekable
  *****************************************************************************
- * Called by AVIDemux, that make common work
+ * AVIDemux: reads and demuxes data packets
+ *****************************************************************************
  * 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 )
+typedef struct avi_stream_toread_s
 {
-    demux_data_avi_file_t *p_avi_demux = 
-                (demux_data_avi_file_t*)p_input->p_demux_data;
+    vlc_bool_t b_ok;
 
-    pes_packet_t *p_pes_master;
-    pes_packet_t *p_pes_slave;
+    int i_toread;
 
-    /* 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 ) )
+    off_t i_posf; // where we will read :
+                  // if i_idxposb == 0 : begining of chunk (+8 to acces data)
+                  // else : point on data directly
+} avi_stream_toread_t;
+
+static int AVIDemux_Seekable( input_thread_t *p_input )
+{
+    unsigned int i_stream_count;
+    unsigned int i_stream;
+    vlc_bool_t b_stream;
+    vlc_bool_t b_play_audio;
+    vlc_bool_t b_video; /* is there some video track selected */
+    // cannot be more than 100 stream (dcXX or wbXX)
+    avi_stream_toread_t toread[100];
+
+    demux_sys_t *p_avi = p_input->p_demux_data;
+
+
+    /* detect new selected/unselected streams */
+    for( i_stream = 0,i_stream_count= 0, b_video = VLC_FALSE;
+            i_stream < p_avi->i_streams; i_stream++ )
+    {
+#define p_stream    p_avi->pp_info[i_stream]
+        if( p_stream->p_es )
         {
-            return( 0 ); /* assume EOF */
+            if( p_stream->p_es->p_decoder_fifo &&
+                !p_stream->b_activated )
+            {
+                AVI_StreamStart( p_input, p_avi, i_stream );
+            }
+            else
+            if( !p_stream->p_es->p_decoder_fifo &&
+                p_stream->b_activated )
+            {
+                AVI_StreamStop( p_input, p_avi, i_stream );
+            }
         }
-        AVI_SynchroReInit( p_input ); 
+        if( p_stream->b_activated )
+        {
+            i_stream_count++;
+            if( p_stream->i_cat == VIDEO_ES )
+            {
+                b_video = VLC_TRUE;
+            }
+        }
+#undef  p_stream
     }
 
-    /* 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 ) )
+    if( i_stream_count <= 0 )
     {
-        p_info_slave->b_selected = 0;
-        AVI_SynchroReInit( p_input );
+        msg_Warn( p_input, "no track selected, exiting..." );
+        return( 0 );
     }
 
-    /* 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
+    if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
     {
-        p_avi_demux->i_pcr =  AVI_GetPTS( p_info_master ) * 9/100;
-    }
+        mtime_t i_date;
+        int i_percent;
+        /* first wait for empty buffer, arbitrary time FIXME */
+        //msleep( DEFAULT_PTS_DELAY );
 
-    /* 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);
+        i_date = (mtime_t)1000000 *
+                 (mtime_t)p_avi->i_length *
+                 (mtime_t)AVI_TellAbsolute( p_input ) /
+                 (mtime_t)p_input->stream.p_selected_area->i_size;
+        i_percent = 100 * AVI_TellAbsolute( p_input ) /
+                        p_input->stream.p_selected_area->i_size;
 
+//        input_ClockInit( p_input->stream.p_selected_program );
+        AVISeek( p_input, i_date, i_percent);
 
-    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 );
+#ifdef __AVI_SUBTITLE__
+        if( p_avi->p_sub )
+        {
+            subtitle_Seek( p_avi->p_sub, p_avi->i_time );
+        }
+#endif
     }
 
 
-    /* at the end ? */
-    return( p_pes_master ? 1 : 0 );
+    /* wait for the good time */
 
-}
+    p_avi->i_pcr = p_avi->i_time * 9 / 100;
 
-/*****************************************************************************
- * 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
- *****************************************************************************/
+    input_ClockManageRef( p_input,
+                          p_input->stream.p_selected_program,
+                          p_avi->i_pcr );
 
-/* 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 )
+    p_avi->i_time += 25*1000;  /* read 25ms */
+
+#ifdef __AVI_SUBTITLE__
+    if( p_avi->p_sub )
     {
-        return( 0 ); /* read and/or update stream info */
+        subtitle_Demux( p_avi->p_sub, p_avi->i_time );
     }
+#endif
 
-    if( i_stream <= 99 )
+    /* *** send audio data to decoder if rate == DEFAULT_RATE or no video *** */
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    if( p_input->stream.control.i_rate == DEFAULT_RATE || !b_video )
     {
-        /* should not happen but ... */
-        return( 1 );
+        b_play_audio = VLC_TRUE;
     }
-
-    /* now we know that it's not a stream */
-
-    switch( p_ck->i_id )
+    else
     {
-        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?? */
+        b_play_audio = VLC_FALSE;
+    }
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
 
-    if( ( p_ck->i_id & 0xFFFF ) == VLC_TWOCC( 'i','x' ) )
+    /* init toread */
+    for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
     {
-        return( 1 );
-    }
+#define p_stream    p_avi->pp_info[i_stream]
+        mtime_t i_dpts;
 
-    return( 4 );
-}
+        toread[i_stream].b_ok = p_stream->b_activated;
+        if( p_stream->i_idxposc < p_stream->i_idxnb )
+        {
+            toread[i_stream].i_posf =
+                p_stream->p_index[p_stream->i_idxposc].i_pos;
+           if( p_stream->i_idxposb > 0 )
+           {
+                toread[i_stream].i_posf += 8 + p_stream->i_idxposb;
+           }
+        }
+        else
+        {
+            toread[i_stream].i_posf = -1;
+        }
 
-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;
+        i_dpts = p_avi->i_time - AVI_GetPTS( p_stream  );
 
-    for( ; ; )
-    {
-        if( input_Peek( p_input, &p_id, 4 ) < 4 )
+        if( p_stream->i_samplesize )
         {
-            return( 0 ); /* Failed */
+            toread[i_stream].i_toread = AVI_PTSToByte( p_stream,
+                                                       __ABS( i_dpts ) );
         }
-        i_id = GetDWLE( p_id );
-        switch( i_id )
+        else
         {
-            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
-                {
-
-                }
+            toread[i_stream].i_toread = AVI_PTSToChunk( p_stream,
+                                                        __ABS( i_dpts ) );
         }
-        /* Read 1 byte VERY unoptimised */
-        if( input_SplitBuffer( p_input, &p_pack, 1) < 1 )
+
+        if( i_dpts < 0 )
         {
-            return( 0 );
+            toread[i_stream].i_toread *= -1;
         }
-        input_DeletePacket( p_input->p_method_data, p_pack);
+#undef  p_stream
     }
 
-}
+    b_stream = VLC_FALSE;
 
-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++ )
+    for( ;; )
     {
-        int b_load =0;
-        
-        /* first find a ck for master or slave */
-        do
+#define p_stream    p_avi->pp_info[i_stream]
+        vlc_bool_t       b_done;
+        pes_packet_t    *p_pes;
+        off_t i_pos;
+        unsigned int i;
+        size_t i_size;
+
+        /* search for first chunk to be read */
+        for( i = 0, b_done = VLC_TRUE, i_pos = -1; i < p_avi->i_streams; i++ )
         {
+            if( !toread[i].b_ok ||
+                AVI_GetDPTS( p_avi->pp_info[i],
+                             toread[i].i_toread ) <= -25 * 1000 )
+            {
+                continue;
+            }
 
-            if( !(p_ck = RIFF_ReadChunk( p_input ) ) )
+            if( toread[i].i_toread > 0 )
             {
-                msg_Err( p_input, "Badd" );
-                return( 0 ); /* assume EOF */
+                b_done = VLC_FALSE; // not yet finished
             }
-            //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 ) )
+            if( toread[i].i_posf > 0 )
             {
-                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 )
+                if( i_pos == -1 || i_pos > toread[i_stream].i_posf )
+                {
+                    i_stream = i;
+                    i_pos = toread[i].i_posf;
+                }
+            }
+        }
+
+        if( b_done )
+        {
+//            return( b_stream ? 1 : 0 );
+            return( 1 );
+        }
+
+        if( i_pos == -1 )
+        {
+            /* no valid index, we will parse directly the stream
+             * in case we fail we will disable all finished stream */
+            if( p_avi->i_movi_lastchunk_pos >= p_avi->i_movi_begin )
+            {
+                AVI_SeekAbsolute( p_input, p_avi->i_movi_lastchunk_pos );
+                if( AVI_PacketNext( p_input ) )
+                {
+                    return( AVI_StreamStopFinishedStreams( p_input, p_avi ) ? 0 : 1 );
+                }
+            }
+            else
+            {
+                AVI_SeekAbsolute( p_input, p_avi->i_movi_begin );
+            }
+
+            for( ;; )
+            {
+                avi_packet_t avi_pk;
+
+                if( AVI_PacketGetHeader( p_input, &avi_pk ) )
+                {
+                    msg_Warn( p_input,
+                             "cannot get packet header, track disabled" );
+                    return( AVI_StreamStopFinishedStreams( p_input, p_avi ) ? 0 : 1 );
+                }
+                if( avi_pk.i_stream >= p_avi->i_streams ||
+                    ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) )
+                {
+                    switch( avi_pk.i_fourcc )
                     {
-                        return( 0 );
+                        case AVIFOURCC_LIST:
+                            AVI_SkipBytes( p_input, 12 );
+                            break;
+                        default:
+                            if( AVI_PacketNext( p_input ) )
+                            {
+                                msg_Warn( p_input,
+                                          "cannot skip packet, track disabled" );
+                                return( AVI_StreamStopFinishedStreams( p_input, p_avi ) ? 0 : 1 );
+                            }
+                            break;
                     }
-                    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 ) )
+                    continue;
+                }
+                else
+                {
+                    /* add this chunk to the index */
+                    AVIIndexEntry_t index;
+
+                    index.i_id = avi_pk.i_fourcc;
+                    index.i_flags =
+                       AVI_GetKeyFlag(p_avi->pp_info[avi_pk.i_stream]->i_codec,
+                                      avi_pk.i_peek);
+                    index.i_pos = avi_pk.i_pos;
+                    index.i_length = avi_pk.i_size;
+                    AVI_IndexAddEntry( p_avi, avi_pk.i_stream, &index );
+
+                    i_stream = avi_pk.i_stream;
+                    /* do we will read this data ? */
+                    if( AVI_GetDPTS( p_stream,
+                             toread[i_stream].i_toread ) > -25 * 1000 )
                     {
-                        msg_Err( p_input, "cannot recover, dying" );
-                        return( -1 );
+                        break;
                     }
                     else
                     {
-                        msg_Warn( p_input, "recovered sucessfully" );
+                        if( AVI_PacketNext( p_input ) )
+                        {
+                            msg_Warn( p_input,
+                                      "cannot skip packet, track disabled" );
+                            return( AVI_StreamStopFinishedStreams( p_input, p_avi ) ? 0 : 1 );
+                        }
                     }
-                    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
+            AVI_SeekAbsolute( p_input, i_pos );
+        }
+
+        /* read thoses data */
+        if( p_stream->i_samplesize )
+        {
+            unsigned int i_toread;
+
+            if( ( i_toread = toread[i_stream].i_toread ) <= 0 )
             {
-                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 )
+                if( p_stream->i_samplesize > 1 )
                 {
-                    b_load = 1;
-                } 
+                    i_toread = p_stream->i_samplesize;
+                }
                 else
                 {
-                    b_load = 0;
+                    i_toread = __MAX( AVI_PTSToByte( p_stream, 20 * 1000 ), 100 );
                 }
             }
+            i_size = __MIN( p_stream->p_index[p_stream->i_idxposc].i_length -
+                                p_stream->i_idxposb,
+                            i_toread );
+        }
+        else
+        {
+            i_size = p_stream->p_index[p_stream->i_idxposc].i_length;
+        }
 
+        if( p_stream->i_idxposb == 0 )
+        {
+            i_size += 8; // need to read and skip header
         }
 
-        /* now do we can load this chunk ? */ 
-        if( b_load )
+        if( input_ReadInPES( p_input, &p_pes, __EVEN( i_size ) ) < 0 )
         {
+            msg_Warn( p_input, "failled reading data" );
+            AVI_StreamStop( p_input, p_avi, i_stream );
+            toread[i_stream].b_ok = VLC_FALSE;
+            continue;
+        }
 
-            if( __AVI_GetDataInPES( p_input, &p_pes, p_ck->i_size + 8, 1) != p_ck->i_size + 8)
-            {
-                return( 0 );
-            }
+        if( i_size % 2 )    // read was padded on word boundary
+        {
+            p_pes->p_last->p_payload_end--;
+            p_pes->i_pes_size--;
+        }
+        // skip header
+        if( p_stream->i_idxposb == 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 );
+        }
+
+        p_pes->i_pts = AVI_GetPTS( p_stream );
+
+        /* read data */
+        if( p_stream->i_samplesize )
+        {
+            if( p_stream->i_idxposb == 0 )
+            {
+                i_size -= 8;
+            }
+            toread[i_stream].i_toread -= i_size;
+            p_stream->i_idxposb += i_size;
+            if( p_stream->i_idxposb >=
+                    p_stream->p_index[p_stream->i_idxposc].i_length )
+            {
+                p_stream->i_idxposb = 0;
+                p_stream->i_idxposc++;
+            }
         }
         else
         {
+            toread[i_stream].i_toread--;
+            p_stream->i_idxposc++;
+        }
 
-            if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+        if( p_stream->i_idxposc < p_stream->i_idxnb)
+        {
+            toread[i_stream].i_posf =
+                p_stream->p_index[p_stream->i_idxposc].i_pos;
+            if( p_stream->i_idxposb > 0 )
             {
-                RIFF_DeleteChunk( p_input, p_ck );
-                return( 0 );
+                toread[i_stream].i_posf += 8 + p_stream->i_idxposb;
             }
-        } 
-        
-        /* finaly update stream information */
-        if( p_info->header.i_samplesize )
+
+        }
+        else
         {
-            p_info->i_idxposb += p_ck->i_size;
+            toread[i_stream].i_posf = -1;
+        }
+
+        b_stream = VLC_TRUE; // at least one read succeed
+
+        if( p_stream->p_es && p_stream->p_es->p_decoder_fifo &&
+            ( b_play_audio || p_stream->i_cat != AUDIO_ES ) )
+        {
+            p_pes->i_dts =
+                p_pes->i_pts =
+                    input_ClockGetTS( p_input,
+                                      p_input->stream.p_selected_program,
+                                      p_pes->i_pts * 9/100);
+
+            input_DecodePES( p_stream->p_es->p_decoder_fifo, p_pes );
         }
         else
         {
-            p_info->i_idxposc++;
+            input_DeletePES( p_input->p_method_data, p_pes );
         }
-        
-        RIFF_DeleteChunk( p_input, p_ck );
     }
-
-    return( 1 );
-#undef p_info
 }
+
+
 /*****************************************************************************
- * AVIDemux: reads and demuxes data packets
+ * AVIDemux_UnSeekable: reads and demuxes data packets for unseekable file
  *****************************************************************************
  * 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 )
+static int AVIDemux_UnSeekable( input_thread_t *p_input )
 {
-    int i;
-    AVIStreamInfo_t *p_info_master;
-    AVIStreamInfo_t *p_info_slave;    
+    demux_sys_t     *p_avi = p_input->p_demux_data;
+    avi_stream_t *p_stream_master;
+    vlc_bool_t b_audio;
+    unsigned int i_stream;
+    unsigned int i_packet;
 
-    demux_data_avi_file_t *p_avi_demux = 
-                (demux_data_avi_file_t*)p_input->p_demux_data;
+    /* *** send audio data to decoder only if rate == DEFAULT_RATE *** */
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    b_audio = p_input->stream.control.i_rate == DEFAULT_RATE;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
 
-    /* search new video and audio stream selected 
-          if current have been unselected*/
-    if( ( !p_avi_demux->p_info_video )
-            || ( !p_avi_demux->p_info_video->p_es->p_decoder_fifo ) )
-    {
-        p_avi_demux->p_info_video = NULL;
-        for( i = 0; i < p_avi_demux->i_streams; i++ )
+    input_ClockManageRef( p_input,
+                          p_input->stream.p_selected_program,
+                          p_avi->i_pcr );
+    /* *** find master stream for data packet skipping algo *** */
+    /* *** -> first video, if any, or first audio ES *** */
+    for( i_stream = 0, p_stream_master = NULL;
+            i_stream < p_avi->i_streams; i_stream++ )
+    {
+#define p_stream    p_avi->pp_info[i_stream]
+        if( p_stream->p_es &&
+            p_stream->p_es->p_decoder_fifo )
         {
-            if( ( p_avi_demux->pp_info[i]->i_cat == VIDEO_ES )
-                  &&( p_avi_demux->pp_info[i]->p_es->p_decoder_fifo ) )
+            if( p_stream->i_cat == VIDEO_ES )
             {
-                p_avi_demux->p_info_video = p_avi_demux->pp_info[i];
-                p_avi_demux->p_info_video->b_selected = 1;
+                p_stream_master = p_stream;
                 break;
             }
-        }
-    }
-    if( ( !p_avi_demux->p_info_audio )
-            ||( !p_avi_demux->p_info_audio->p_es->p_decoder_fifo ) )
-    {
-        p_avi_demux->p_info_audio = NULL;
-        for( i = 0; i < p_avi_demux->i_streams; i++ )
-        {
-            if( ( p_avi_demux->pp_info[i]->i_cat == AUDIO_ES )
-                  &&( p_avi_demux->pp_info[i]->p_es->p_decoder_fifo ) )
+            if( p_stream->i_cat == AUDIO_ES && !p_stream_master )
             {
-                p_avi_demux->p_info_audio = p_avi_demux->pp_info[i];
-                p_avi_demux->p_info_audio->b_selected = 1;
-                break;
+                p_stream_master = p_stream;
             }
         }
+#undef p_stream
     }
-    /* by default video is master for resync audio (after a seek .. ) */
-    if( p_avi_demux->p_info_video )
-    {
-        p_info_master = p_avi_demux->p_info_video;
-        p_info_slave  = p_avi_demux->p_info_audio;
-    }
-    else
+    if( !p_stream_master )
     {
-        p_info_master = p_avi_demux->p_info_audio;
-        p_info_slave  = NULL;
-    }
-    
-    if( !p_info_master ) 
-    {
-        msg_Err( p_input, "no stream selected" );
-        return( -1 );
+        msg_Warn( p_input, "no more stream selected" );
+        return( 0 );
     }
 
-    /* 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 )
+    p_avi->i_pcr = AVI_GetPTS( p_stream_master ) * 9 / 100;
+
+    for( i_packet = 0; i_packet < 10; i_packet++)
     {
-        if( p_avi_demux->p_info_audio)
+#define p_stream    p_avi->pp_info[avi_pk.i_stream]
+
+        avi_packet_t    avi_pk;
+
+        if( AVI_PacketGetHeader( p_input, &avi_pk ) )
         {
-             p_avi_demux->p_info_audio->b_selected = 1;
+            return( 0 );
         }
-        p_avi_demux->i_rate = p_input->stream.control.i_rate;
-    }
-    vlc_mutex_unlock( &p_input->stream.stream_lock );    
-    p_avi_demux->i_rate = DEFAULT_RATE;
-    if( p_avi_demux->i_rate != DEFAULT_RATE )
-    {
-        p_info_slave = NULL;
-    }
+//        AVI_ParseStreamHeader( avi_pk.i_fourcc, &i_stream, &i_cat );
 
-    if( p_avi_demux->b_seekable )
-    {
-        return( AVIDemux_Seekable( p_input,
-                                   p_info_master,
-                                   p_info_slave) );
-    }
-    else
-    {
-        return( AVIDemux_NotSeekable( p_input,
-                                      p_info_master,
-                                      p_info_slave ) );
-    }
-}
+        if( avi_pk.i_stream >= p_avi->i_streams ||
+            ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) )
+        {
+            /* we haven't found an audio or video packet:
+             *  - we have seek, found first next packet
+             *  - others packets could be found, skip them
+             */
+            switch( avi_pk.i_fourcc )
+            {
+                case AVIFOURCC_JUNK:
+                case AVIFOURCC_LIST:
+                    return( !AVI_PacketNext( p_input ) ? 1 : 0 );
+                case AVIFOURCC_idx1:
+                    return( 0 );    // eof
+                default:
+                    msg_Warn( p_input,
+                              "seems to have lost position, resync" );
+                    if( AVI_PacketSearch( p_input ) )
+                    {
+                        msg_Err( p_input, "resync failed" );
+                        return( -1 );
+                    }
+            }
+        }
+        else
+        {
+            /* do will send this packet to decoder ? */
+            if( ( !b_audio && avi_pk.i_cat == AUDIO_ES )||
+                !p_stream->p_es ||
+                !p_stream->p_es->p_decoder_fifo )
+            {
+                if( AVI_PacketNext( p_input ) )
+                {
+                    return( 0 );
+                }
+            }
+            else
+            {
+                /* it's a selected stream, check for time */
+                if( __ABS( AVI_GetPTS( p_stream ) -
+                            AVI_GetPTS( p_stream_master ) )< 600*1000 )
+                {
+                    /* load it and send to decoder */
+                    pes_packet_t    *p_pes;
+                    if( AVI_PacketRead( p_input, &avi_pk, &p_pes ) || !p_pes)
+                    {
+                        return( -1 );
+                    }
+                    p_pes->i_dts =
+                        p_pes->i_pts =
+                            input_ClockGetTS( p_input,
+                                          p_input->stream.p_selected_program,
+                                          AVI_GetPTS( p_stream ) * 9/100);
+                    input_DecodePES( p_stream->p_es->p_decoder_fifo, p_pes );
+                }
+                else
+                {
+                    if( AVI_PacketNext( p_input ) )
+                    {
+                        return( 0 );
+                    }
+                }
+            }
 
+            /* *** update stream time position *** */
+            if( p_stream->i_samplesize )
+            {
+                p_stream->i_idxposb += avi_pk.i_size;
+            }
+            else
+            {
+                p_stream->i_idxposc++;
+            }
+
+        }
+
+#undef p_stream
+    }
 
+    return( 1 );
+}