]> git.sesse.net Git - vlc/blobdiff - plugins/avi/avi.c
* ALL: new module API. Makes a few things a lot simpler, and we gain
[vlc] / plugins / avi / avi.c
index 171c06009e4806724829471b4ba8a0575fb86953..ed5bd7ee3945b821e3ebe373865e2a4c2f8a24c7 100644 (file)
@@ -2,7 +2,7 @@
  * avi.c : AVI file Stream input module for vlc
  *****************************************************************************
  * Copyright (C) 2001 VideoLAN
- * $Id: avi.c,v 1.28 2002/06/30 15:07:57 fenrir Exp $
+ * $Id: avi.c,v 1.33 2002/07/31 20:56:50 sam Exp $
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  * 
  * This program is free software; you can redistribute it and/or modify
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static void input_getfunctions( function_list_t * );
-static int  AVIDemux         ( input_thread_t * );
-static int  AVIInit          ( input_thread_t * );
-static void AVIEnd           ( input_thread_t * );
+static int    AVIInit   ( vlc_object_t * );
+static void __AVIEnd    ( vlc_object_t * );
+static int    AVIDemux  ( input_thread_t * );
 
-/*****************************************************************************
- * Build configuration tree.
- *****************************************************************************/
-MODULE_CONFIG_START
-MODULE_CONFIG_STOP
-
-MODULE_INIT_START
-    SET_DESCRIPTION( "RIFF-AVI Stream input" )
-    ADD_CAPABILITY( DEMUX, 150 )
-MODULE_INIT_STOP
-
-MODULE_ACTIVATE_START
-    input_getfunctions( &p_module->p_functions->demux );
-MODULE_ACTIVATE_STOP
-
-MODULE_DEACTIVATE_START
-MODULE_DEACTIVATE_STOP
+#define AVIEnd(a) __AVIEnd(VLC_OBJECT(a))
 
 /*****************************************************************************
- * Functions exported as capabilities. They are declared as static so that
- * we don't pollute the namespace too much.
+ * Module descriptor
  *****************************************************************************/
-static void input_getfunctions( function_list_t * p_function_list )
-{
-#define input p_function_list->functions.demux
-    input.pf_init             = AVIInit;
-    input.pf_end              = AVIEnd;
-    input.pf_demux            = AVIDemux;
-    input.pf_rewind           = NULL;
-#undef input
-}
-
+vlc_module_begin();
+    set_description( "RIFF-AVI demuxer" );
+    set_capability( "demux", 150 );
+    set_callbacks( AVIInit, __AVIEnd );
+vlc_module_end();
 
 /*****************************************************************************
  * Some usefull functions to manipulate memory 
@@ -180,77 +157,31 @@ static inline int AVI_GetESTypeFromTwoCC( u16 i_type )
     }
 }
 
-static int AVI_AudioGetType( u32 i_type )
+static vlc_fourcc_t AVI_AudioGetType( u32 i_type )
 {
     switch( i_type )
     {
 /*        case( WAVE_FORMAT_PCM ):
-            return( WAVE_AUDIO_ES ); */
+            return VLC_FOURCC('l','p','c','m'); */
         case( WAVE_FORMAT_AC3 ):
-            return( AC3_AUDIO_ES );
+            return VLC_FOURCC('a','5','2',' ');
         case( WAVE_FORMAT_MPEG):
         case( WAVE_FORMAT_MPEGLAYER3):
-            return( MPEG2_AUDIO_ES ); /* 2 for mpeg-2 layer 1 2 ou 3 */
+            return VLC_FOURCC('m','p','g','a'); /* for mpeg2 layer 1 2 ou 3 */
         default:
-            return( 0 );
+            return 0;
     }
 }
-static int AVI_VideoGetType( u32 i_type )
-{
-    switch( i_type )
-    {
-        case( FOURCC_DIV1 ): /* FIXME it is for msmpeg4v1 or old mpeg4 ?? */
-        case( FOURCC_div1 ):
-        case( FOURCC_MPG4 ):
-        case( FOURCC_mpg4 ):
-            return( MSMPEG4v1_VIDEO_ES );
-
-        case( FOURCC_DIV2 ):
-        case( FOURCC_div2 ):
-        case( FOURCC_MP42 ):
-        case( FOURCC_mp42 ):
-            return( MSMPEG4v2_VIDEO_ES );
-         
-        case( FOURCC_MPG3 ):
-        case( FOURCC_mpg3 ):
-        case( FOURCC_div3 ):
-        case( FOURCC_MP43 ):
-        case( FOURCC_mp43 ):
-        case( FOURCC_DIV3 ):
-        case( FOURCC_DIV4 ):
-        case( FOURCC_div4 ):
-        case( FOURCC_DIV5 ):
-        case( FOURCC_div5 ):
-        case( FOURCC_DIV6 ):
-        case( FOURCC_div6 ):
-        case( FOURCC_AP41 ):
-        case( FOURCC_3IV1 ):
-            return( MSMPEG4v3_VIDEO_ES );
-
-        case( FOURCC_DIVX ):
-        case( FOURCC_divx ):
-        case( FOURCC_MP4S ):
-        case( FOURCC_mp4s ):
-        case( FOURCC_M4S2 ):
-        case( FOURCC_m4s2 ):
-        case( FOURCC_xvid ):
-        case( FOURCC_XVID ):
-        case( FOURCC_XviD ):
-        case( FOURCC_DX50 ):
-        case( FOURCC_mp4v ):
-        case( FOURCC_4    ):
-            return( MPEG4_VIDEO_ES );
 
-        default:
-            return( 0 );
-    }
-}
 /* Test if it seems that it's a key frame */
-static int AVI_GetKeyFlag( int i_type, u8 *p_byte )
+static int AVI_GetKeyFlag( vlc_fourcc_t i_fourcc, u8 *p_byte )
 {
-    switch( i_type )
+    switch( i_fourcc )
     {
-        case( MSMPEG4v1_VIDEO_ES ):
+        case FOURCC_DIV1:
+        case FOURCC_div1:
+        case FOURCC_MPG4:
+        case FOURCC_mpg4:
             if( GetDWBE( p_byte ) != 0x00000100 ) 
             /* startcode perhaps swapped, I haven't tested */
             {
@@ -262,11 +193,38 @@ static int AVI_GetKeyFlag( int i_type, u8 *p_byte )
             {
                 return( (*(p_byte+4))&0x06 ? 0 : AVIIF_KEYFRAME);
             }
-        case( MSMPEG4v2_VIDEO_ES ):
-        case( MSMPEG4v3_VIDEO_ES ):
+        case FOURCC_DIV2:
+        case FOURCC_div2:
+        case FOURCC_MP42:
+        case FOURCC_mp42:
+        case FOURCC_MPG3:
+        case FOURCC_mpg3:
+        case FOURCC_div3:
+        case FOURCC_MP43:
+        case FOURCC_mp43:
+        case FOURCC_DIV3:
+        case FOURCC_DIV4:
+        case FOURCC_div4:
+        case FOURCC_DIV5:
+        case FOURCC_div5:
+        case FOURCC_DIV6:
+        case FOURCC_div6:
+        case FOURCC_AP41:
+        case FOURCC_3IV1:
 //            printf( "\n Is a Key Frame %s", (*p_byte)&0xC0 ? "no" : "yes!!" );
             return( (*p_byte)&0xC0 ? 0 : AVIIF_KEYFRAME );
-        case( MPEG4_VIDEO_ES ):
+        case FOURCC_DIVX:
+        case FOURCC_divx:
+        case FOURCC_MP4S:
+        case FOURCC_mp4s:
+        case FOURCC_M4S2:
+        case FOURCC_m4s2:
+        case FOURCC_xvid:
+        case FOURCC_XVID:
+        case FOURCC_XviD:
+        case FOURCC_DX50:
+        case FOURCC_mp4v:
+        case FOURCC_4:
             if( GetDWBE( p_byte ) != 0x000001b6 )
             {
                 /* not true , need to find the first VOP header
@@ -563,8 +521,9 @@ static void __AVI_UpdateIndexOffset( input_thread_t *p_input )
 /*****************************************************************************
  * AVIEnd: frees unused data
  *****************************************************************************/
-static void AVIEnd( input_thread_t *p_input )
+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  ; 
@@ -599,16 +558,18 @@ static void AVIEnd( input_thread_t *p_input )
 /*****************************************************************************
  * AVIInit: check file and initializes AVI structures
  *****************************************************************************/
-static int AVIInit( input_thread_t *p_input )
-{
+static int AVIInit( vlc_object_t * p_this )
+{   
+    input_thread_t *    p_input = (input_thread_t *)p_this;
     riffchunk_t *p_riff,*p_hdrl,*p_movi;
     riffchunk_t *p_avih;
     riffchunk_t *p_strl,*p_strh,*p_strf;
     demux_data_avi_file_t *p_avi_demux;
     es_descriptor_t *p_es = NULL; /* for not warning */
-
     int i;
 
+    p_input->pf_demux = AVIDemux;
+
     if( !( p_input->p_demux_data = 
                     p_avi_demux = malloc( sizeof(demux_data_avi_file_t) ) ) )
     {
@@ -766,30 +727,19 @@ static int AVIInit( input_thread_t *p_input )
                 p_es->i_cat = AUDIO_ES;
                 AVI_Parse_WaveFormatEx( &p_info->audio_format,
                                    p_strf->p_data->p_payload_start ); 
-                p_es->b_audio = 1;
-                p_es->i_type = 
-                    AVI_AudioGetType( p_info->audio_format.i_formattag );
-                if( !p_es->i_type )
-                {
-                    msg_Warn( p_input, "stream(%d,0x%x) not supported", i,
-                                       p_info->audio_format.i_formattag );
-                    p_es->i_cat = UNKNOWN_ES;
-                }
+                p_es->i_fourcc = AVI_AudioGetType(
+                                     p_info->audio_format.i_formattag );
                 break;
                 
             case( FOURCC_vids ):
                 p_es->i_cat = VIDEO_ES;
                 AVI_Parse_BitMapInfoHeader( &p_info->video_format,
                                    p_strf->p_data->p_payload_start ); 
-                p_es->b_audio = 0;
-                p_es->i_type = 
-                    AVI_VideoGetType( p_info->video_format.i_compression );
-                if( !p_es->i_type )
-                {
-                    msg_Warn( p_input, "stream(%d,%4.4s) not supported", i,
-                              (char*)&p_info->video_format.i_compression);
-                    p_es->i_cat = UNKNOWN_ES;
-                }
+
+                /* XXX quick hack for playing ffmpeg video, I don't know 
+                    who is doing something wrong */
+                p_info->header.i_samplesize = 0;
+                p_es->i_fourcc = p_info->video_format.i_compression;
                 break;
             default:
                 msg_Err( p_input, "unknown stream(%d) type", i );
@@ -827,8 +777,7 @@ static int AVIInit( input_thread_t *p_input )
     p_avi_demux->p_movi = p_movi;
     
     /* get index  XXX need to have p_movi */
-    if( ( p_avi_demux->b_seekable )
-        &&( p_avi_demux->avih.i_flags&AVIF_HASINDEX ) ) 
+    if( p_avi_demux->b_seekable )
     {
         /* get index */
         __AVI_GetIndex( p_input ); 
@@ -836,18 +785,19 @@ static int AVIInit( input_thread_t *p_input )
         __AVI_UpdateIndexOffset( p_input );
         /* to make sure to go the begining unless demux will see a seek */
         RIFF_GoToChunk( p_input, p_avi_demux->p_movi );
-        if( RIFF_DescendChunk( p_input ) != 0 )
-        {
-            AVIEnd( p_input );
-            msg_Err( p_input, "cannot go in (\"movi\")" );
-            return( -1 );
-        }
+
     }
     else
     {
         msg_Warn( p_input, "no index!" );
     }
 
+    if( RIFF_DescendChunk( p_input ) != 0 )
+    {
+        AVIEnd( p_input );
+        msg_Err( p_input, "cannot go in (\"movi\")" );
+        return( -1 );
+    }
 
     /* print informations on streams */
     msg_Dbg( p_input, "AVIH: %d stream, flags %s%s%s%s ", 
@@ -863,6 +813,7 @@ static int AVIInit( input_thread_t *p_input )
         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,
@@ -962,7 +913,8 @@ static mtime_t AVI_GetPTS( AVIStreamInfo_t *p_info )
             }
             else
             {
-                i_len = 0; /* no valid zntry */
+                i_len = p_info->i_idxposb; 
+                /* no valid entry use only offset*/
             }
         }
         else
@@ -1003,12 +955,23 @@ static int __AVI_GetDataInPES( input_thread_t *p_input,
 
     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;
@@ -1018,19 +981,11 @@ static int __AVI_GetDataInPES( input_thread_t *p_input,
     {
         b_pad = 0;
     }
-    
-    if( !i_size )
-    {
-        (*pp_pes)->p_first = (*pp_pes)->p_last  = NULL;
-        (*pp_pes)->i_nb_data = 0;
-        (*pp_pes)->i_pes_size = 0;
-        return( 0 );
-    }
 
     do
     {
-        i_read = input_SplitBuffer(p_input, &p_data, i_size - 
-                                                    (*pp_pes)->i_pes_size );
+        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 );
@@ -1065,7 +1020,7 @@ static int __AVI_SeekAndGetChunk( input_thread_t  *p_input,
                                   AVIStreamInfo_t *p_info )
 {
     pes_packet_t *p_pes;
-    int i_length;
+    int i_length, i_ret;
     
     i_length = __MIN( p_info->p_index[p_info->i_idxposc].i_length 
                         - p_info->i_idxposb,
@@ -1075,10 +1030,9 @@ static int __AVI_SeekAndGetChunk( input_thread_t  *p_input,
                       (off_t)p_info->p_index[p_info->i_idxposc].i_pos + 
                             p_info->i_idxposb + 8);
 
-    if( __AVI_GetDataInPES( p_input, 
-                            &p_pes, 
-                            i_length , 
-                            0) != i_length )
+    i_ret = __AVI_GetDataInPES( p_input, &p_pes, i_length , 0);
+
+    if( i_ret != i_length )
     {
         return( 0 );
     }
@@ -1197,6 +1151,7 @@ static int __AVI_GetAndPutChunkInBuffer( input_thread_t  *p_input,
         return( 0 );
     }
     p_pes->p_first->p_payload_start += 8;
+    p_pes->i_pes_size -= 8;
 
     i_size = GetDWLE( p_pes->p_first->p_demux_start + 4);
 
@@ -1356,7 +1311,7 @@ static int __AVI_GetChunk( input_thread_t  *p_input,
                 AVIIndexEntry_t index;
 
                 index.i_id = p_ck->i_id;
-                index.i_flags = AVI_GetKeyFlag( p_info_i->p_es->i_type,
+                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;
@@ -1557,6 +1512,7 @@ static pes_packet_t *AVI_ReadStreamBytesInPES(  input_thread_t  *p_input,
     {
         return( NULL );
     }
+fprintf(stderr, "blah ibyte %i\n", i_byte);
     if( !( p_data = input_NewPacket( p_input->p_method_data, i_byte ) ) )
     {
         input_DeletePES( p_input->p_method_data, p_pes );
@@ -1820,6 +1776,360 @@ static inline void AVI_DecodePES( input_thread_t *p_input,
   
 }
 
+/*****************************************************************************
+ * AVIDemux_Seekable: reads and demuxes data packets for stream seekable
+ *****************************************************************************
+ * Called by AVIDemux, that make common work
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
+static int AVIDemux_Seekable( input_thread_t *p_input,
+                              AVIStreamInfo_t *p_info_master,
+                              AVIStreamInfo_t *p_info_slave )
+{
+    demux_data_avi_file_t *p_avi_demux = 
+                (demux_data_avi_file_t*)p_input->p_demux_data;
+
+    pes_packet_t *p_pes_master;
+    pes_packet_t *p_pes_slave;
+
+    /* check for signal from interface */
+    if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
+    { 
+        /* we can supposed that is a seek */
+        /* first wait for empty buffer, arbitrary time */
+        msleep( DEFAULT_PTS_DELAY );
+        /* then try to realign in stream */
+        if( !AVI_ReAlign( p_input, p_info_master ) )
+        {
+            return( 0 ); /* assume EOF */
+        }
+        AVI_SynchroReInit( p_input ); 
+    }
+
+    /* take care of newly selected audio ES */
+    if( p_info_master->b_selected )
+    {
+        p_info_master->b_selected = 0;
+        AVI_SynchroReInit( p_input ); 
+    }
+    if( ( p_info_slave )&&( p_info_slave->b_selected ) )
+    {
+        p_info_slave->b_selected = 0;
+        AVI_SynchroReInit( p_input );
+    }
+
+    /* wait for the good time */
+    input_ClockManageRef( p_input,
+                          p_input->stream.p_selected_program,
+                          p_avi_demux->i_pcr /*- DEFAULT_PTS_DELAY / 2 */); 
+    /* calculate pcr, time when we must read the next data */
+    /* 9/100 kludge ->need to convert to 1/1000000 clock unit to 1/90000 */
+    if( p_info_slave )
+    {
+        p_avi_demux->i_pcr =  __MIN( AVI_GetPTS( p_info_master ),
+                                     AVI_GetPTS( p_info_slave ) ) * 9/100;
+    }
+    else
+    {
+        p_avi_demux->i_pcr =  AVI_GetPTS( p_info_master ) * 9/100;
+    }
+
+    /* get video and audio frames */
+    p_pes_master = AVI_GetFrameInPES( p_input,
+                                      p_info_master,
+                                      100000 ); /* 100 ms */
+    AVI_DecodePES( p_input,
+                   p_info_master,
+                   p_pes_master);
+
+
+    if( p_info_slave )
+    {
+        p_pes_slave = AVI_GetFrameInPES( p_input,
+                                         p_info_slave,
+                                         AVI_GetPTS( p_info_master ) -
+                                             AVI_GetPTS( p_info_slave) );
+        AVI_DecodePES( p_input,
+                       p_info_slave,
+                       p_pes_slave );
+    }
+
+
+    /* at the end ? */
+    return( p_pes_master ? 1 : 0 );
+
+}
+
+/*****************************************************************************
+ * AVIDemux_NotSeekable: reads and demuxes data packets for stream seekable
+ *****************************************************************************
+ * Called by AVIDemux, that makes common work
+ * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
+ *****************************************************************************/
+
+/* 0 if can be load/updated, 1 if skip, 2 if descend into, 3 if exit, 4 if error and need recover */
+static int __AVIDemux_ChunkAction( int i_streams_max,
+                                   riffchunk_t *p_ck )
+{
+    int i_stream;
+    int i_type;
+
+    AVI_ParseStreamHeader( p_ck->i_id, &i_stream, &i_type );
+    if( i_stream < i_streams_max )
+    {
+        return( 0 ); /* read and/or update stream info */
+    }
+
+    if( i_stream <= 99 )
+    {
+        /* should not happen but ... */
+        return( 1 );
+    }
+
+    /* now we know that it's not a stream */
+
+    switch( p_ck->i_id )
+    {
+        case( FOURCC_JUNK ):
+            return( 1 );
+        case( FOURCC_idx1 ):
+            return( 3 );
+        case( FOURCC_LIST ):
+            if( p_ck->i_type == FOURCC_rec )
+            {
+                return( 2 );
+            }
+            else
+            {
+                return( 1 );
+            }
+        default:
+            break;
+    } 
+    /* test for ix?? */
+
+    if( ( p_ck->i_id & 0xFFFF ) == VLC_TWOCC( 'i','x' ) )
+    {
+        return( 1 );
+    }
+
+    return( 4 );
+}
+
+static int AVI_NotSeekableRecover( input_thread_t *p_input )
+{
+    byte_t *p_id;
+    u32 i_id;
+    int i_number, i_type;
+    data_packet_t *p_pack;
+
+    for( ; ; )
+    {
+        if( input_Peek( p_input, &p_id, 4 ) < 4 )
+        {
+            return( 0 ); /* Failed */
+        }
+        i_id = GetDWLE( p_id );
+        switch( i_id )
+        {
+            case( FOURCC_idx1 ):
+            case( FOURCC_JUNK ):
+            case( FOURCC_LIST ):
+                return( 1 );
+            default:
+                AVI_ParseStreamHeader( i_id, &i_number, &i_type );
+                if( i_number <= 99 )
+                {
+                    switch( i_type )
+                    {
+                        case( TWOCC_wb ):
+                        case( TWOCC_db ):
+                        case( TWOCC_dc ):
+                        case( TWOCC_pc ):
+                            return( 1 );
+                    }
+                }
+                else
+                {
+
+                }
+        }
+        /* Read 1 byte VERY unoptimised */
+        if( input_SplitBuffer( p_input, &p_pack, 1) < 1 )
+        {
+            return( 0 );
+        }
+        input_DeletePacket( p_input->p_method_data, p_pack);
+    }
+
+}
+
+static int AVIDemux_NotSeekable( input_thread_t *p_input,
+                                 AVIStreamInfo_t *p_info_master,
+                                 AVIStreamInfo_t *p_info_slave )
+{
+    demux_data_avi_file_t *p_avi_demux = 
+                (demux_data_avi_file_t*)p_input->p_demux_data;
+    int i_loop;
+    int i_stream;
+    int i_type;
+    
+    riffchunk_t *p_ck;
+    pes_packet_t *p_pes;
+   
+/*
+    i_filepos = AVI_TellAbsolute( p_input );
+    p_input->pf_seek( p_input, i_filepos ); 
+    input_AccessReinit( p_input );
+*/
+    
+#define p_info p_avi_demux->pp_info[i_stream]
+
+    /* The managment is very basic, we will read packets, caclulate pts 
+    and send it to decoder, synchro made on video, and audio is very less
+    important */
+    
+    /* wait the good time */
+    input_ClockManageRef( p_input,
+                          p_input->stream.p_selected_program,
+                          p_avi_demux->i_pcr /*- DEFAULT_PTS_DELAY / 2 */); 
+    /* TODO be smart, seeing if we can wait for min( audio, video )
+        or there is a too big deep */
+    if( !p_info_slave )
+    {
+        p_avi_demux->i_pcr =  AVI_GetPTS( p_info_master ) * 9/100;
+    }
+    else
+    {
+        p_avi_demux->i_pcr =  __MIN( AVI_GetPTS( p_info_master ),
+                                 AVI_GetPTS( p_info_slave ) ) * 9/100;
+        p_avi_demux->i_pcr =  AVI_GetPTS( p_info_master ) * 9/100;
+    }
+    
+    for( i_loop = 0; i_loop < 10; i_loop++ )
+    {
+        int b_load =0;
+        
+        /* first find a ck for master or slave */
+        do
+        {
+
+            if( !(p_ck = RIFF_ReadChunk( p_input ) ) )
+            {
+                msg_Err( p_input, "Badd" );
+                return( 0 ); /* assume EOF */
+            }
+            //msg_Err( p_input,"Looking ck: %4.4s %d",&p_ck->i_id, p_ck->i_size );
+
+            switch( __AVIDemux_ChunkAction( p_avi_demux->i_streams, p_ck ) )
+            {
+                case( 0 ): /* load it if possible */
+                    b_load = 1;
+                    break;
+                case( 1 ): /* skip it */
+                    RIFF_DeleteChunk( p_input, p_ck );
+                    if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+                    {
+                        return( 0 );
+                    }
+                    b_load = 0;
+                    break;
+                case( 2 ): /* descend into */
+                    RIFF_DeleteChunk( p_input, p_ck );
+                    RIFF_DescendChunk( p_input );
+                    b_load = 0;
+                    break;
+                case( 3 ): /* exit */
+                    RIFF_DeleteChunk( p_input, p_ck );
+                    return( 0 );
+                case( 4 ): /* Error */
+                    RIFF_DeleteChunk( p_input, p_ck );
+                    msg_Warn( p_input, "unknown chunk id 0x%8.8x, trying to recover", p_ck->i_id );
+                    if( !AVI_NotSeekableRecover( p_input ) )
+                    {
+                        msg_Err( p_input, "cannot recover, dying" );
+                        return( -1 );
+                    }
+                    else
+                    {
+                        msg_Warn( p_input, "recovered sucessfully" );
+                    }
+                    b_load = 0;
+                    break;
+            }
+
+        } while( !b_load );
+
+        AVI_ParseStreamHeader( p_ck->i_id, &i_stream, &i_type );
+        /* now check if we really have to load it */
+        if( ( p_info != p_info_master )&&( p_info != p_info_slave ) )
+        {
+            b_load = 0;
+        }
+        else
+        {
+            if( p_info == p_info_master )
+            {
+                b_load = 1;
+            }
+            else
+            {
+                mtime_t i_dpts;
+                i_dpts = AVI_GetPTS( p_info_slave ) - 
+                            AVI_GetPTS( p_info_master );
+                if( i_dpts < 0 ) {i_dpts = - i_dpts; }
+                if( i_dpts < 600000 )
+                {
+                    b_load = 1;
+                } 
+                else
+                {
+                    b_load = 0;
+                }
+            }
+
+        }
+
+        /* now do we can load this chunk ? */ 
+        if( b_load )
+        {
+
+            if( __AVI_GetDataInPES( p_input, &p_pes, p_ck->i_size + 8, 1) != p_ck->i_size + 8)
+            {
+                return( 0 );
+            }
+            p_pes->p_first->p_payload_start += 8;
+            p_pes->i_pes_size -= 8;
+            /* get PTS */
+            p_pes->i_pts = AVI_GetPTS( p_info );
+            AVI_DecodePES( p_input, p_info, p_pes );
+        }
+        else
+        {
+
+            if( RIFF_NextChunk( p_input, p_avi_demux->p_movi ) != 0 )
+            {
+                RIFF_DeleteChunk( p_input, p_ck );
+                return( 0 );
+            }
+        } 
+        
+        /* finaly update stream information */
+        if( p_info->header.i_samplesize )
+        {
+            p_info->i_idxposb += p_ck->i_size;
+        }
+        else
+        {
+            p_info->i_idxposc++;
+        }
+        
+        RIFF_DeleteChunk( p_input, p_ck );
+    }
+
+    return( 1 );
+#undef p_info
+}
 /*****************************************************************************
  * AVIDemux: reads and demuxes data packets
  *****************************************************************************
@@ -1831,7 +2141,6 @@ static inline void AVI_DecodePES( input_thread_t *p_input,
 static int AVIDemux( input_thread_t *p_input )
 {
     int i;
-    pes_packet_t *p_pes;
     AVIStreamInfo_t *p_info_master;
     AVIStreamInfo_t *p_info_slave;    
 
@@ -1888,20 +2197,6 @@ static int AVIDemux( input_thread_t *p_input )
         return( -1 );
     }
 
-    /* check for signal from interface */
-    if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
-    { 
-        /* we can supposed that is a seek */
-        /* first wait for empty buffer, arbitrary time */
-        msleep( DEFAULT_PTS_DELAY );
-        /* then try to realign in stream */
-        if( !AVI_ReAlign( p_input, p_info_master ) )
-        {
-            return( 0 ); /* assume EOF */
-        }
-        AVI_SynchroReInit( p_input ); 
-    }
-
     /* 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 )
@@ -1913,63 +2208,25 @@ static int AVIDemux( input_thread_t *p_input )
         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;
     }
-    /* take care of newly selected audio ES */
-    if( p_info_master->b_selected )
-    {
-        p_info_master->b_selected = 0;
-        AVI_SynchroReInit( p_input ); 
-    }
-    if( ( p_info_slave )&&( p_info_slave->b_selected ) )
-    {
-        p_info_slave->b_selected = 0;
-        AVI_SynchroReInit( p_input );
-    }
 
-    /* wait for the good time */
-    input_ClockManageRef( p_input,
-                          p_input->stream.p_selected_program,
-                          p_avi_demux->i_pcr /*- DEFAULT_PTS_DELAY / 2 */); 
-    /* calculate pcr, time when we must read the next data */
-    /* 9/100 kludge ->need to convert to 1/1000000 clock unit to 1/90000 */
-    if( p_info_slave )
+    if( p_avi_demux->b_seekable )
     {
-        p_avi_demux->i_pcr =  __MIN( AVI_GetPTS( p_info_master ),
-                                     AVI_GetPTS( p_info_slave ) ) * 9/100;
+        return( AVIDemux_Seekable( p_input,
+                                   p_info_master,
+                                   p_info_slave) );
     }
     else
     {
-        p_avi_demux->i_pcr =  AVI_GetPTS( p_info_master ) * 9/100;
-    }
-
-    /* get video and audio frames */
-    p_pes = AVI_GetFrameInPES( p_input,
-                               p_info_master,
-                               100000 ); /* 100 ms */
-
-
-    if( p_info_slave )
-    {
-        pes_packet_t *p_pes_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 );
+        return( AVIDemux_NotSeekable( p_input,
+                                      p_info_master,
+                                      p_info_slave ) );
     }
+}
 
-    AVI_DecodePES( p_input,
-                   p_info_master,
-                   p_pes);
-
-    /* at the end ? */
-    return( p_pes ? 1 : 0 );
 
-}