a742403c10898df68e83db53c059b020e2f0394b
[vlc.git] / modules / demux / avi / avi.c
1 /*****************************************************************************
2  * avi.c : AVI file Stream input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: avi.c,v 1.76 2003/11/24 13:40:03 gbazin Exp $
6  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
21  *****************************************************************************/
22
23 /*****************************************************************************
24  * Preamble
25  *****************************************************************************/
26 #include <stdlib.h>                                      /* malloc(), free() */
27
28 #include <vlc/vlc.h>
29 #include <vlc/input.h>
30 #include "codecs.h"
31
32 #include "libavi.h"
33 #include "avi.h"
34
35 /*****************************************************************************
36  * Module descriptor
37  *****************************************************************************/
38 static int  Open   ( vlc_object_t * );
39 static void Close  ( vlc_object_t * );
40
41 vlc_module_begin();
42     add_category_hint( N_("avi-demuxer"), NULL, VLC_TRUE );
43         add_bool( "avi-interleaved", 0, NULL,
44                   N_("force interleaved method"),
45                   N_("force interleaved method"), VLC_TRUE );
46         add_bool( "avi-index", 0, NULL,
47                   N_("force index creation"),
48                   N_("force index creation"), VLC_TRUE );
49
50     set_description( N_("AVI demuxer") );
51     set_capability( "demux", 212 );
52     set_callbacks( Open, Close );
53 vlc_module_end();
54
55 /*****************************************************************************
56  * Local prototypes
57  *****************************************************************************/
58 static int    Control         ( input_thread_t *, int, va_list );
59 static int    Seek            ( input_thread_t *, mtime_t, int );
60 static int    Demux_Seekable  ( input_thread_t * );
61 static int    Demux_UnSeekable( input_thread_t *p_input );
62
63 #define FREE( p ) if( p ) { free( p ); (p) = NULL; }
64 #define __ABS( x ) ( (x) < 0 ? (-(x)) : (x) )
65
66 static inline off_t __EVEN( off_t i )
67 {
68     return (i & 1) ? i + 1 : i;
69 }
70
71 static mtime_t AVI_PTSToChunk( avi_track_t *, mtime_t i_pts );
72 static mtime_t AVI_PTSToByte ( avi_track_t *, mtime_t i_pts );
73 static mtime_t AVI_GetDPTS   ( avi_track_t *, int64_t i_count );
74 static mtime_t AVI_GetPTS    ( avi_track_t * );
75
76
77 static int AVI_StreamChunkFind( input_thread_t *, unsigned int i_stream );
78 static int AVI_StreamChunkSet ( input_thread_t *,
79                                 unsigned int i_stream, unsigned int i_ck );
80 static int AVI_StreamBytesSet ( input_thread_t *,
81                                 unsigned int i_stream, off_t   i_byte );
82
83 vlc_fourcc_t AVI_FourccGetCodec( unsigned int i_cat, vlc_fourcc_t );
84 static int   AVI_GetKeyFlag    ( vlc_fourcc_t , uint8_t * );
85
86 static int AVI_PacketGetHeader( input_thread_t *, avi_packet_t *p_pk );
87 static int AVI_PacketNext     ( input_thread_t * );
88 static int AVI_PacketRead     ( input_thread_t *, avi_packet_t *, block_t **);
89 static int AVI_PacketSearch   ( input_thread_t * );
90
91 static void AVI_IndexLoad    ( input_thread_t * );
92 static void AVI_IndexCreate  ( input_thread_t * );
93 static void AVI_IndexAddEntry( demux_sys_t *, int, AVIIndexEntry_t * );
94
95 static mtime_t  AVI_MovieGetLength( input_thread_t * );
96
97 /*****************************************************************************
98  * Stream management
99  *****************************************************************************/
100 static int        AVI_TrackSeek  ( input_thread_t *, int, mtime_t );
101 static int        AVI_TrackStopFinishedStreams( input_thread_t *);
102
103 /*****************************************************************************
104  * Open: check file and initializes AVI structures
105  *****************************************************************************/
106 static int Open( vlc_object_t * p_this )
107 {
108     input_thread_t  *p_input = (input_thread_t *)p_this;
109     demux_sys_t     *p_sys;
110
111     avi_chunk_t         ck_riff;
112     avi_chunk_list_t    *p_riff = (avi_chunk_list_t*)&ck_riff;
113     avi_chunk_list_t    *p_hdrl, *p_movi;
114     avi_chunk_avih_t    *p_avih;
115
116     unsigned int i_track;
117     unsigned int i;
118
119     uint8_t  *p_peek;
120
121
122     /* Is it an avi file ? */
123     if( stream_Peek( p_input->s, &p_peek, 12 ) < 12 )
124     {
125         msg_Err( p_input, "cannot peek()" );
126         return VLC_EGENERIC;
127     }
128     if( strncmp( &p_peek[0], "RIFF", 4 ) || strncmp( &p_peek[8], "AVI ", 4 ) )
129     {
130         msg_Warn( p_input, "avi module discarded (invalid header)" );
131         return VLC_EGENERIC;
132     }
133
134     /* Initialize input  structures. */
135     p_sys = p_input->p_demux_data = malloc( sizeof(demux_sys_t) );
136     memset( p_sys, 0, sizeof( demux_sys_t ) );
137     p_sys->i_time   = 0;
138     p_sys->i_length = 0;
139     p_sys->i_pcr    = 0;
140     p_sys->i_movi_lastchunk_pos = 0;
141     p_sys->b_odml   = VLC_FALSE;
142     p_sys->i_track  = 0;
143     p_sys->track    = NULL;
144
145     stream_Control( p_input->s, STREAM_CAN_FASTSEEK, &p_sys->b_seekable );
146
147     p_input->pf_demux_control = Control;
148     p_input->pf_demux = Demux_Seekable;
149     /* For unseekable stream, automaticaly use Demux_UnSeekable */
150     if( !p_sys->b_seekable || config_GetInt( p_input, "avi-interleaved" ) )
151     {
152         p_input->pf_demux = Demux_UnSeekable;
153     }
154
155     if( AVI_ChunkReadRoot( p_input->s, &p_sys->ck_root ) )
156     {
157         msg_Err( p_input, "avi module discarded (invalid file)" );
158         return VLC_EGENERIC;
159     }
160
161     if( AVI_ChunkCount( &p_sys->ck_root, AVIFOURCC_RIFF ) > 1 )
162     {
163         unsigned int i_count =
164             AVI_ChunkCount( &p_sys->ck_root, AVIFOURCC_RIFF );
165
166         msg_Warn( p_input, "multiple riff -> OpenDML ?" );
167         for( i = 1; i < i_count; i++ )
168         {
169             avi_chunk_list_t *p_sysx;
170
171             p_sysx = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, i );
172             if( p_sysx->i_type == AVIFOURCC_AVIX )
173             {
174                 msg_Warn( p_input, "detected OpenDML file" );
175                 p_sys->b_odml = VLC_TRUE;
176                 break;
177             }
178         }
179     }
180
181     p_riff  = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0 );
182     p_hdrl  = AVI_ChunkFind( p_riff, AVIFOURCC_hdrl, 0 );
183     p_movi  = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0 );
184
185     if( !p_hdrl || !p_movi )
186     {
187         msg_Err( p_input, "avi module discarded (invalid file)" );
188         goto error;
189     }
190
191     if( !( p_avih = AVI_ChunkFind( p_hdrl, AVIFOURCC_avih, 0 ) ) )
192     {
193         msg_Err( p_input, "cannot find avih chunk" );
194         goto error;
195     }
196     i_track = AVI_ChunkCount( p_hdrl, AVIFOURCC_strl );
197     if( p_avih->i_streams != i_track )
198     {
199         msg_Warn( p_input,
200                   "found %d stream but %d are declared",
201                   i_track, p_avih->i_streams );
202     }
203     if( i_track == 0 )
204     {
205         msg_Err( p_input, "no stream defined!" );
206         goto error;
207     }
208
209     /*  create one program */
210     vlc_mutex_lock( &p_input->stream.stream_lock );
211     if( input_InitStream( p_input, 0 ) == -1)
212     {
213         vlc_mutex_unlock( &p_input->stream.stream_lock );
214         msg_Err( p_input, "cannot init stream" );
215         goto error;
216     }
217     p_input->stream.i_mux_rate = 0; /* Fixed later */
218     vlc_mutex_unlock( &p_input->stream.stream_lock );
219
220     /* print informations on streams */
221     msg_Dbg( p_input, "AVIH: %d stream, flags %s%s%s%s ",
222              i_track,
223              p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
224              p_avih->i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
225              p_avih->i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
226              p_avih->i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" );
227     {
228         input_info_category_t *p_cat = input_InfoCategory( p_input, _("Avi") );
229         input_AddInfo( p_cat, _("Number of Streams"), "%d", i_track );
230         input_AddInfo( p_cat, _("Flags"), "%s%s%s%s",
231                        p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
232                        p_avih->i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
233                        p_avih->i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
234                        p_avih->i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" );
235     }
236
237     /* now read info on each stream and create ES */
238     for( i = 0 ; i < i_track; i++ )
239     {
240         avi_track_t      *tk = malloc( sizeof( avi_track_t ) );
241         avi_chunk_list_t *p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i );
242         avi_chunk_strh_t *p_strh = AVI_ChunkFind( p_strl, AVIFOURCC_strh, 0 );
243         avi_chunk_strf_auds_t *p_auds;
244         avi_chunk_strf_vids_t *p_vids;
245         es_format_t fmt;
246
247         tk->b_activated = VLC_FALSE;
248         tk->p_index     = 0;
249         tk->i_idxnb     = 0;
250         tk->i_idxmax    = 0;
251         tk->i_idxposc   = 0;
252         tk->i_idxposb   = 0;
253
254         p_auds = (void*)p_vids = (void*)AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 );
255
256         if( p_strl == NULL || p_strh == NULL || p_auds == NULL || p_vids == NULL )
257         {
258             msg_Warn( p_input, "stream[%d] incomplete", i );
259             continue;
260         }
261
262         tk->i_rate  = p_strh->i_rate;
263         tk->i_scale = p_strh->i_scale;
264         tk->i_samplesize = p_strh->i_samplesize;
265         msg_Dbg( p_input, "stream[%d] rate:%d scale:%d samplesize:%d",
266                  i, tk->i_rate, tk->i_scale, tk->i_samplesize );
267
268         switch( p_strh->i_type )
269         {
270             case( AVIFOURCC_auds ):
271                 tk->i_cat   = AUDIO_ES;
272                 tk->i_codec = AVI_FourccGetCodec( AUDIO_ES,
273                                                   p_auds->p_wf->wFormatTag );
274                 es_format_Init( &fmt, AUDIO_ES, tk->i_codec );
275
276                 fmt.audio.i_channels        = p_auds->p_wf->nChannels;
277                 fmt.audio.i_rate            = p_auds->p_wf->nSamplesPerSec;
278                 fmt.i_bitrate               = p_auds->p_wf->nAvgBytesPerSec*8;
279                 fmt.audio.i_blockalign      = p_auds->p_wf->nBlockAlign;
280                 fmt.audio.i_bitspersample   = p_auds->p_wf->wBitsPerSample;
281                 if( ( fmt.i_extra = __MIN( p_auds->p_wf->cbSize,
282                                            p_auds->i_chunk_size - sizeof(WAVEFORMATEX) ) ) > 0 )
283                 {
284                     fmt.p_extra = malloc( fmt.i_extra );
285                     memcpy( fmt.p_extra, &p_auds->p_wf[1], fmt.i_extra );
286                 }
287                 msg_Dbg( p_input, "stream[%d] audio(0x%x) %d channels %dHz %dbits",
288                          i,
289                          p_auds->p_wf->wFormatTag, p_auds->p_wf->nChannels,
290                          p_auds->p_wf->nSamplesPerSec, p_auds->p_wf->wBitsPerSample);
291                 break;
292
293             case( AVIFOURCC_vids ):
294                 tk->i_cat   = VIDEO_ES;
295                 tk->i_codec = AVI_FourccGetCodec( VIDEO_ES,
296                                                   p_vids->p_bih->biCompression );
297                 es_format_Init( &fmt, VIDEO_ES, p_vids->p_bih->biCompression );
298                 tk->i_samplesize = 0;
299                 fmt.video.i_width  = p_vids->p_bih->biWidth;
300                 fmt.video.i_height = p_vids->p_bih->biHeight;
301                 if( ( fmt.i_extra = __MIN( p_vids->p_bih->biSize - sizeof( BITMAPINFOHEADER ),
302                                            p_vids->i_chunk_size - sizeof(BITMAPINFOHEADER) ) ) > 0 )
303                 {
304                     fmt.p_extra = malloc( fmt.i_extra );
305                     memcpy( fmt.p_extra, &p_vids->p_bih[1], fmt.i_extra );
306                 }
307                 msg_Dbg( p_input, "stream[%d] video(%4.4s) %dx%d %dbpp %ffps",
308                         i,
309                          (char*)&p_vids->p_bih->biCompression,
310                          p_vids->p_bih->biWidth,
311                          p_vids->p_bih->biHeight,
312                          p_vids->p_bih->biBitCount,
313                          (float)tk->i_rate/(float)tk->i_scale );
314                 break;
315             default:
316                 msg_Warn( p_input, "stream[%d] unknown type", i );
317                 free( tk );
318                 continue;
319         }
320         tk->p_es = es_out_Add( p_input->p_es_out, &fmt );
321         TAB_APPEND( p_sys->i_track, p_sys->track, tk );
322     }
323
324     if( p_sys->i_track <= 0 )
325     {
326         msg_Err( p_input, "No valid track" );
327         goto error;
328     }
329
330     if( config_GetInt( p_input, "avi-index" ) )
331     {
332         if( p_sys->b_seekable )
333         {
334             AVI_IndexCreate( p_input );
335         }
336         else
337         {
338             msg_Warn( p_input, "cannot create index (unseekable stream)" );
339             AVI_IndexLoad( p_input );
340         }
341     }
342     else
343     {
344         AVI_IndexLoad( p_input );
345     }
346
347     /* *** movie length in sec *** */
348     p_sys->i_length = AVI_MovieGetLength( p_input );
349     if( p_sys->i_length < (mtime_t)p_avih->i_totalframes *
350                           (mtime_t)p_avih->i_microsecperframe /
351                           (mtime_t)1000000 )
352     {
353         msg_Warn( p_input, "broken or missing index, 'seek' will be axproximative or will have strange behavour" );
354     }
355     /* fix some BeOS MediaKit generated file */
356     for( i = 0 ; i < p_sys->i_track; i++ )
357     {
358         avi_track_t         *tk = p_sys->track[i];
359         avi_chunk_list_t    *p_strl;
360         avi_chunk_strh_t    *p_strh;
361         avi_chunk_strf_auds_t    *p_auds;
362
363         if( tk->i_cat != AUDIO_ES )
364         {
365             continue;
366         }
367         if( tk->i_idxnb < 1 ||
368             tk->i_scale != 1 ||
369             tk->i_samplesize != 0 )
370         {
371             continue;
372         }
373         p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i );
374         p_strh = AVI_ChunkFind( p_strl, AVIFOURCC_strh, 0 );
375         p_auds = AVI_ChunkFind( p_strl, AVIFOURCC_strf, 0 );
376
377         if( p_auds->p_wf->wFormatTag != WAVE_FORMAT_PCM &&
378             (unsigned int)tk->i_rate == p_auds->p_wf->nSamplesPerSec )
379         {
380             int64_t i_track_length =
381                 tk->p_index[tk->i_idxnb-1].i_length +
382                 tk->p_index[tk->i_idxnb-1].i_lengthtotal;
383             mtime_t i_length = (mtime_t)p_avih->i_totalframes *
384                                (mtime_t)p_avih->i_microsecperframe;
385
386             if( i_length == 0 )
387             {
388                 msg_Warn( p_input, "track[%d] cannot be fixed (BeOS MediaKit generated)", i );
389                 continue;
390             }
391             tk->i_samplesize = 1;
392             tk->i_rate       = i_track_length  * (int64_t)1000000/ i_length;
393             msg_Warn( p_input, "track[%d] fixed with rate=%d scale=%d (BeOS MediaKit generated)", i, tk->i_rate, tk->i_scale );
394         }
395     }
396
397     if( p_sys->i_length )
398     {
399         p_input->stream.i_mux_rate =
400             stream_Size( p_input->s ) / 50 / p_sys->i_length;
401     }
402
403     if( p_sys->b_seekable )
404     {
405         /* we have read all chunk so go back to movi */
406         stream_Seek( p_input->s, p_movi->i_chunk_pos );
407     }
408     /* Skip movi header */
409     stream_Read( p_input->s, NULL, 12 );
410
411     p_sys->i_movi_begin = p_movi->i_chunk_pos;
412     return VLC_SUCCESS;
413
414 error:
415     AVI_ChunkFreeRoot( p_input->s, &p_sys->ck_root );
416     free( p_sys );
417     return VLC_EGENERIC;
418 }
419
420 /*****************************************************************************
421  * Close: frees unused data
422  *****************************************************************************/
423 static void Close ( vlc_object_t * p_this )
424 {
425     input_thread_t *    p_input = (input_thread_t *)p_this;
426     unsigned int i;
427     demux_sys_t *p_sys = p_input->p_demux_data  ;
428
429     for( i = 0; i < p_sys->i_track; i++ )
430     {
431         if( p_sys->track[i] )
432         {
433             FREE( p_sys->track[i]->p_index );
434             free( p_sys->track[i] );
435         }
436     }
437     FREE( p_sys->track );
438     AVI_ChunkFreeRoot( p_input->s, &p_sys->ck_root );
439
440     free( p_sys );
441 }
442
443 /*****************************************************************************
444  * Demux_Seekable: reads and demuxes data packets for stream seekable
445  *****************************************************************************
446  * AVIDemux: reads and demuxes data packets
447  *****************************************************************************
448  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
449  *****************************************************************************/
450 typedef struct
451 {
452     vlc_bool_t b_ok;
453
454     int i_toread;
455
456     off_t i_posf; /* where we will read :
457                    if i_idxposb == 0 : begining of chunk (+8 to acces data)
458                    else : point on data directly */
459 } avi_track_toread_t;
460
461 static int Demux_Seekable( input_thread_t *p_input )
462 {
463     demux_sys_t *p_sys = p_input->p_demux_data;
464
465     unsigned int i_track_count = 0;
466     unsigned int i_track;
467     vlc_bool_t b_stream;
468     /* cannot be more than 100 stream (dcXX or wbXX) */
469     avi_track_toread_t toread[100];
470
471
472     /* detect new selected/unselected streams */
473     for( i_track = 0; i_track < p_sys->i_track; i_track++ )
474     {
475         avi_track_t *tk = p_sys->track[i_track];
476         vlc_bool_t  b;
477
478         es_out_Control( p_input->p_es_out, ES_OUT_GET_SELECT, tk->p_es, &b );
479         if( b && !tk->b_activated )
480         {
481             if( p_sys->b_seekable)
482             {
483                 AVI_TrackSeek( p_input, i_track, p_sys->i_time );
484             }
485             tk->b_activated = VLC_TRUE;
486         }
487         else if( !b && tk->b_activated )
488         {
489             tk->b_activated = VLC_FALSE;
490         }
491         if( b )
492         {
493             i_track_count++;
494         }
495     }
496
497     if( i_track_count <= 0 )
498     {
499         msg_Warn( p_input, "no track selected, exiting..." );
500         return( 0 );
501     }
502
503     /* wait for the good time */
504     p_sys->i_pcr = p_sys->i_time * 9 / 100;
505
506     input_ClockManageRef( p_input,
507                           p_input->stream.p_selected_program,
508                           p_sys->i_pcr );
509
510
511     p_sys->i_time += 25*1000;  /* read 25ms */
512
513     /* init toread */
514     for( i_track = 0; i_track < p_sys->i_track; i_track++ )
515     {
516         avi_track_t *tk = p_sys->track[i_track];
517         mtime_t i_dpts;
518
519         toread[i_track].b_ok = tk->b_activated;
520         if( tk->i_idxposc < tk->i_idxnb )
521         {
522             toread[i_track].i_posf = tk->p_index[tk->i_idxposc].i_pos;
523            if( tk->i_idxposb > 0 )
524            {
525                 toread[i_track].i_posf += 8 + tk->i_idxposb;
526            }
527         }
528         else
529         {
530             toread[i_track].i_posf = -1;
531         }
532
533         i_dpts = p_sys->i_time - AVI_GetPTS( tk  );
534
535         if( tk->i_samplesize )
536         {
537             toread[i_track].i_toread = AVI_PTSToByte( tk, __ABS( i_dpts ) );
538         }
539         else
540         {
541             toread[i_track].i_toread = AVI_PTSToChunk( tk, __ABS( i_dpts ) );
542         }
543
544         if( i_dpts < 0 )
545         {
546             toread[i_track].i_toread *= -1;
547         }
548     }
549
550     b_stream = VLC_FALSE;
551
552     for( ;; )
553     {
554         avi_track_t     *tk;
555         vlc_bool_t       b_done;
556         block_t         *p_frame;
557         off_t i_pos;
558         unsigned int i;
559         size_t i_size;
560
561         /* search for first chunk to be read */
562         for( i = 0, b_done = VLC_TRUE, i_pos = -1; i < p_sys->i_track; i++ )
563         {
564             if( !toread[i].b_ok ||
565                 AVI_GetDPTS( p_sys->track[i],
566                              toread[i].i_toread ) <= -25 * 1000 )
567             {
568                 continue;
569             }
570
571             if( toread[i].i_toread > 0 )
572             {
573                 b_done = VLC_FALSE; /* not yet finished */
574             }
575             if( toread[i].i_posf > 0 )
576             {
577                 if( i_pos == -1 || i_pos > toread[i_track].i_posf )
578                 {
579                     i_track = i;
580                     i_pos = toread[i].i_posf;
581                 }
582             }
583         }
584
585         if( b_done )
586         {
587             return( 1 );
588         }
589
590         if( i_pos == -1 )
591         {
592             /* no valid index, we will parse directly the stream
593              * in case we fail we will disable all finished stream */
594             if( p_sys->i_movi_lastchunk_pos >= p_sys->i_movi_begin + 12 )
595             {
596                 stream_Seek( p_input->s, p_sys->i_movi_lastchunk_pos );
597                 if( AVI_PacketNext( p_input ) )
598                 {
599                     return( AVI_TrackStopFinishedStreams( p_input ) ? 0 : 1 );
600                 }
601             }
602             else
603             {
604                 stream_Seek( p_input->s, p_sys->i_movi_begin + 12 );
605             }
606
607             for( ;; )
608             {
609                 avi_packet_t avi_pk;
610
611                 if( AVI_PacketGetHeader( p_input, &avi_pk ) )
612                 {
613                     msg_Warn( p_input,
614                              "cannot get packet header, track disabled" );
615                     return( AVI_TrackStopFinishedStreams( p_input ) ? 0 : 1 );
616                 }
617                 if( avi_pk.i_stream >= p_sys->i_track ||
618                     ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) )
619                 {
620                     if( AVI_PacketNext( p_input ) )
621                     {
622                         msg_Warn( p_input,
623                                   "cannot skip packet, track disabled" );
624                         return( AVI_TrackStopFinishedStreams( p_input ) ? 0 : 1 );
625                     }
626                     continue;
627                 }
628                 else
629                 {
630                     /* add this chunk to the index */
631                     AVIIndexEntry_t index;
632
633                     index.i_id = avi_pk.i_fourcc;
634                     index.i_flags =
635                        AVI_GetKeyFlag(p_sys->track[avi_pk.i_stream]->i_codec,
636                                       avi_pk.i_peek);
637                     index.i_pos = avi_pk.i_pos;
638                     index.i_length = avi_pk.i_size;
639                     AVI_IndexAddEntry( p_sys, avi_pk.i_stream, &index );
640
641                     i_track = avi_pk.i_stream;
642                     tk = p_sys->track[i_track];
643                     /* do we will read this data ? */
644                     if( AVI_GetDPTS( tk, toread[i_track].i_toread ) > -25*1000 )
645                     {
646                         break;
647                     }
648                     else
649                     {
650                         if( AVI_PacketNext( p_input ) )
651                         {
652                             msg_Warn( p_input,
653                                       "cannot skip packet, track disabled" );
654                             return( AVI_TrackStopFinishedStreams( p_input ) ? 0 : 1 );
655                         }
656                     }
657                 }
658             }
659
660         }
661         else
662         {
663             stream_Seek( p_input->s, i_pos );
664         }
665
666         /* Set the track to use */
667         tk = p_sys->track[i_track];
668
669         /* read thoses data */
670         if( tk->i_samplesize )
671         {
672             unsigned int i_toread;
673
674             if( ( i_toread = toread[i_track].i_toread ) <= 0 )
675             {
676                 if( tk->i_samplesize > 1 )
677                 {
678                     i_toread = tk->i_samplesize;
679                 }
680                 else
681                 {
682                     i_toread = __MAX( AVI_PTSToByte( tk, 20 * 1000 ), 100 );
683                 }
684             }
685             i_size = __MIN( tk->p_index[tk->i_idxposc].i_length -
686                                 tk->i_idxposb,
687                             i_toread );
688         }
689         else
690         {
691             i_size = tk->p_index[tk->i_idxposc].i_length;
692         }
693
694         if( tk->i_idxposb == 0 )
695         {
696             i_size += 8; /* need to read and skip header */
697         }
698
699         if( ( p_frame = stream_Block( p_input->s, __EVEN( i_size ) ) )==NULL )
700         {
701             msg_Warn( p_input, "failled reading data" );
702             tk->b_activated = VLC_FALSE;
703             toread[i_track].b_ok = VLC_FALSE;
704             continue;
705         }
706         if( i_size % 2 )    /* read was padded on word boundary */
707         {
708             p_frame->i_buffer--;
709         }
710         /* skip header */
711         if( tk->i_idxposb == 0 )
712         {
713             p_frame->p_buffer += 8;
714             p_frame->i_buffer -= 8;
715         }
716         p_frame->i_pts = AVI_GetPTS( tk );
717
718         /* read data */
719         if( tk->i_samplesize )
720         {
721             if( tk->i_idxposb == 0 )
722             {
723                 i_size -= 8;
724             }
725             toread[i_track].i_toread -= i_size;
726             tk->i_idxposb += i_size;
727             if( tk->i_idxposb >=
728                     tk->p_index[tk->i_idxposc].i_length )
729             {
730                 tk->i_idxposb = 0;
731                 tk->i_idxposc++;
732             }
733         }
734         else
735         {
736             toread[i_track].i_toread--;
737             tk->i_idxposc++;
738         }
739
740         if( tk->i_idxposc < tk->i_idxnb)
741         {
742             toread[i_track].i_posf =
743                 tk->p_index[tk->i_idxposc].i_pos;
744             if( tk->i_idxposb > 0 )
745             {
746                 toread[i_track].i_posf += 8 + tk->i_idxposb;
747             }
748
749         }
750         else
751         {
752             toread[i_track].i_posf = -1;
753         }
754
755         b_stream = VLC_TRUE; /* at least one read succeed */
756
757         p_frame->i_pts =
758             input_ClockGetTS( p_input,
759                               p_input->stream.p_selected_program,
760                               p_frame->i_pts * 9/100);
761
762         if( tk->i_cat != VIDEO_ES )
763             p_frame->i_dts = p_frame->i_pts;
764         else
765         {
766             p_frame->i_dts = p_frame->i_pts;
767             p_frame->i_pts = 0;
768         }
769
770         //p_pes->i_rate = p_input->stream.control.i_rate;
771         es_out_Send( p_input->p_es_out, tk->p_es, p_frame );
772     }
773 }
774
775
776 /*****************************************************************************
777  * Demux_UnSeekable: reads and demuxes data packets for unseekable file
778  *****************************************************************************
779  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
780  *****************************************************************************/
781 static int Demux_UnSeekable( input_thread_t *p_input )
782 {
783     demux_sys_t     *p_sys = p_input->p_demux_data;
784     avi_track_t *p_stream_master = NULL;
785     vlc_bool_t b_audio;
786     unsigned int i_stream;
787     unsigned int i_packet;
788
789     /* Check if we need to send the audio data to decoder */
790     b_audio = !p_input->stream.control.b_mute;
791
792     input_ClockManageRef( p_input,
793                           p_input->stream.p_selected_program,
794                           p_sys->i_pcr );
795
796     /* *** find master stream for data packet skipping algo *** */
797     /* *** -> first video, if any, or first audio ES *** */
798     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
799     {
800         avi_track_t *tk = p_sys->track[i_stream];
801         vlc_bool_t  b;
802
803         es_out_Control( p_input->p_es_out, ES_OUT_GET_SELECT, tk->p_es, &b );
804
805         if( b && tk->i_cat == VIDEO_ES )
806         {
807             p_stream_master = tk;
808         }
809         else if( b )
810         {
811             p_stream_master = tk;
812         }
813     }
814
815     if( !p_stream_master )
816     {
817         msg_Warn( p_input, "no more stream selected" );
818         return( 0 );
819     }
820
821     p_sys->i_pcr = AVI_GetPTS( p_stream_master ) * 9 / 100;
822
823     for( i_packet = 0; i_packet < 10; i_packet++)
824     {
825 #define p_stream    p_sys->track[avi_pk.i_stream]
826
827         avi_packet_t    avi_pk;
828
829         if( AVI_PacketGetHeader( p_input, &avi_pk ) )
830         {
831             return( 0 );
832         }
833
834         if( avi_pk.i_stream >= p_sys->i_track ||
835             ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) )
836         {
837             /* we haven't found an audio or video packet:
838              *  - we have seek, found first next packet
839              *  - others packets could be found, skip them
840              */
841             switch( avi_pk.i_fourcc )
842             {
843                 case AVIFOURCC_JUNK:
844                 case AVIFOURCC_LIST:
845                 case AVIFOURCC_RIFF:
846                     return( !AVI_PacketNext( p_input ) ? 1 : 0 );
847                 case AVIFOURCC_idx1:
848                     if( p_sys->b_odml )
849                     {
850                         return( !AVI_PacketNext( p_input ) ? 1 : 0 );
851                     }
852                     return( 0 );    /* eof */
853                 default:
854                     msg_Warn( p_input,
855                               "seems to have lost position, resync" );
856                     if( AVI_PacketSearch( p_input ) )
857                     {
858                         msg_Err( p_input, "resync failed" );
859                         return( -1 );
860                     }
861             }
862         }
863         else
864         {
865             /* do will send this packet to decoder ? */
866             if( !b_audio && avi_pk.i_cat == AUDIO_ES )
867             {
868                 if( AVI_PacketNext( p_input ) )
869                 {
870                     return( 0 );
871                 }
872             }
873             else
874             {
875                 /* it's a selected stream, check for time */
876                 if( __ABS( AVI_GetPTS( p_stream ) -
877                             AVI_GetPTS( p_stream_master ) )< 600*1000 )
878                 {
879                     /* load it and send to decoder */
880                     block_t *p_frame;
881                     if( AVI_PacketRead( p_input, &avi_pk, &p_frame ) || p_frame == NULL )
882                     {
883                         return( -1 );
884                     }
885                     p_frame->i_pts =
886                         input_ClockGetTS( p_input,
887                                           p_input->stream.p_selected_program,
888                                           AVI_GetPTS( p_stream ) * 9/100);
889
890                     if( avi_pk.i_cat != VIDEO_ES )
891                         p_frame->i_dts = p_frame->i_pts;
892                     else
893                     {
894                         p_frame->i_dts = p_frame->i_pts;
895                         p_frame->i_pts = 0;
896                     }
897
898                     //p_pes->i_rate = p_input->stream.control.i_rate;
899                     es_out_Send( p_input->p_es_out, p_stream->p_es, p_frame );
900                 }
901                 else
902                 {
903                     if( AVI_PacketNext( p_input ) )
904                     {
905                         return( 0 );
906                     }
907                 }
908             }
909
910             /* *** update stream time position *** */
911             if( p_stream->i_samplesize )
912             {
913                 p_stream->i_idxposb += avi_pk.i_size;
914             }
915             else
916             {
917                 p_stream->i_idxposc++;
918             }
919
920         }
921 #undef p_stream
922     }
923
924     return( 1 );
925 }
926
927 /*****************************************************************************
928  * Seek: goto to i_date or i_percent
929  *****************************************************************************
930  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
931  *****************************************************************************/
932 static int Seek( input_thread_t *p_input, mtime_t i_date, int i_percent )
933 {
934
935     demux_sys_t *p_sys = p_input->p_demux_data;
936     unsigned int i_stream;
937     msg_Dbg( p_input,
938              "seek requested: "I64Fd" secondes %d%%",
939              i_date / 1000000,
940              i_percent );
941
942     if( p_sys->b_seekable )
943     {
944         if( !p_sys->i_length )
945         {
946             avi_track_t *p_stream;
947             int64_t i_pos;
948
949             /* use i_percent to create a true i_date */
950             msg_Warn( p_input,
951                       "mmh, seeking without index at %d%%"
952                       " work only for interleaved file", i_percent );
953             if( i_percent >= 100 )
954             {
955                 msg_Warn( p_input, "cannot seek so far !" );
956                 return( -1 );
957             }
958             i_percent = __MAX( i_percent, 0 );
959
960             /* try to find chunk that is at i_percent or the file */
961             i_pos = __MAX( i_percent *
962                            stream_Size( p_input->s ) / 100,
963                            p_sys->i_movi_begin );
964             /* search first selected stream */
965             for( i_stream = 0, p_stream = NULL;
966                         i_stream < p_sys->i_track; i_stream++ )
967             {
968                 p_stream = p_sys->track[i_stream];
969                 if( p_stream->b_activated )
970                 {
971                     break;
972                 }
973             }
974             if( !p_stream || !p_stream->b_activated )
975             {
976                 msg_Warn( p_input, "cannot find any selected stream" );
977                 return( -1 );
978             }
979
980             /* be sure that the index exist */
981             if( AVI_StreamChunkSet( p_input,
982                                     i_stream,
983                                     0 ) )
984             {
985                 msg_Warn( p_input, "cannot seek" );
986                 return( -1 );
987             }
988
989             while( i_pos >= p_stream->p_index[p_stream->i_idxposc].i_pos +
990                p_stream->p_index[p_stream->i_idxposc].i_length + 8 )
991             {
992                 /* search after i_idxposc */
993                 if( AVI_StreamChunkSet( p_input,
994                                         i_stream, p_stream->i_idxposc + 1 ) )
995                 {
996                     msg_Warn( p_input, "cannot seek" );
997                     return( -1 );
998                 }
999             }
1000             i_date = AVI_GetPTS( p_stream );
1001             /* TODO better support for i_samplesize != 0 */
1002             msg_Dbg( p_input, "estimate date "I64Fd, i_date );
1003         }
1004
1005 #define p_stream    p_sys->track[i_stream]
1006         p_sys->i_time = 0;
1007         /* seek for chunk based streams */
1008         for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
1009         {
1010             if( p_stream->b_activated && !p_stream->i_samplesize )
1011 /*            if( p_stream->b_activated ) */
1012             {
1013                 AVI_TrackSeek( p_input, i_stream, i_date );
1014                 p_sys->i_time = __MAX( AVI_GetPTS( p_stream ),
1015                                         p_sys->i_time );
1016             }
1017         }
1018 #if 1
1019         if( p_sys->i_time )
1020         {
1021             i_date = p_sys->i_time;
1022         }
1023         /* seek for bytes based streams */
1024         for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
1025         {
1026             if( p_stream->b_activated && p_stream->i_samplesize )
1027             {
1028                 AVI_TrackSeek( p_input, i_stream, i_date );
1029 /*                p_sys->i_time = __MAX( AVI_GetPTS( p_stream ), p_sys->i_time );*/
1030             }
1031         }
1032         msg_Dbg( p_input, "seek: "I64Fd" secondes", p_sys->i_time /1000000 );
1033         /* set true movie time */
1034 #endif
1035         if( !p_sys->i_time )
1036         {
1037             p_sys->i_time = i_date;
1038         }
1039 #undef p_stream
1040         return( 1 );
1041     }
1042     else
1043     {
1044         msg_Err( p_input, "shouldn't yet be executed" );
1045         return( -1 );
1046     }
1047 }
1048
1049 /*****************************************************************************
1050  * Control:
1051  *****************************************************************************
1052  *
1053  *****************************************************************************/
1054 static double ControlGetPosition( input_thread_t *p_input )
1055 {
1056     demux_sys_t *p_sys = p_input->p_demux_data;
1057
1058     if( p_sys->i_length > 0 )
1059     {
1060         return (double)p_sys->i_time / (double)( p_sys->i_length * (mtime_t)1000000 );
1061     }
1062     else if( stream_Size( p_input->s ) > 0 )
1063     {
1064         unsigned int i;
1065         int64_t i_tmp;
1066         int64_t i64 = 0;
1067
1068         /* search the more advanced selected es */
1069         for( i = 0; i < p_sys->i_track; i++ )
1070         {
1071             avi_track_t *tk = p_sys->track[i];
1072             if( tk->b_activated && tk->i_idxposc < tk->i_idxnb )
1073             {
1074                 i_tmp = tk->p_index[tk->i_idxposc].i_pos +
1075                         tk->p_index[tk->i_idxposc].i_length + 8;
1076                 if( i_tmp > i64 )
1077                 {
1078                     i64 = i_tmp;
1079                 }
1080             }
1081         }
1082         return (double)i64 / (double)stream_Size( p_input->s );
1083     }
1084     return 0.0;
1085 }
1086
1087 static int    Control( input_thread_t *p_input, int i_query, va_list args )
1088 {
1089     demux_sys_t *p_sys = p_input->p_demux_data;
1090     int i;
1091     double   f, *pf;
1092     int64_t i64, *pi64;
1093
1094     switch( i_query )
1095     {
1096         case DEMUX_GET_POSITION:
1097             pf = (double*)va_arg( args, double * );
1098             *pf = ControlGetPosition( p_input );
1099             return VLC_SUCCESS;
1100         case DEMUX_SET_POSITION:
1101             if( p_sys->b_seekable )
1102             {
1103                 f = (double)va_arg( args, double );
1104                 i64 = (mtime_t)(1000000.0 * p_sys->i_length * f );
1105                 return Seek( p_input, i64, (int)(f * 100) );
1106             }
1107             return demux_vaControlDefault( p_input, i_query, args );
1108
1109         case DEMUX_GET_TIME:
1110             pi64 = (int64_t*)va_arg( args, int64_t * );
1111             *pi64 = p_sys->i_time;
1112             return VLC_SUCCESS;
1113
1114         case DEMUX_SET_TIME:
1115         {
1116             int i_percent = 0;
1117
1118             i64 = (int64_t)va_arg( args, int64_t );
1119             if( p_sys->i_length > 0 )
1120             {
1121                 i_percent = 100 * i64 / (p_sys->i_length*1000000ULL);
1122             }
1123             else if( p_sys->i_time > 0 )
1124             {
1125                 i_percent = (int)( 100.0 * ControlGetPosition( p_input ) *
1126                                    (double)i64 / (double)p_sys->i_time );
1127             }
1128             return Seek( p_input, i64, i_percent );
1129         }
1130         case DEMUX_GET_LENGTH:
1131             pi64 = (int64_t*)va_arg( args, int64_t * );
1132             *pi64 = p_sys->i_length * (mtime_t)1000000;
1133             return VLC_SUCCESS;
1134
1135         case DEMUX_GET_FPS:
1136             pf = (double*)va_arg( args, double * );
1137             *pf = 0.0;
1138             for( i = 0; i < (int)p_sys->i_track; i++ )
1139             {
1140                 avi_track_t *tk = p_sys->track[i];
1141                 if( tk->i_cat == VIDEO_ES && tk->i_scale > 0)
1142                 {
1143                     *pf = (float)tk->i_rate / (float)tk->i_scale;
1144                     break;
1145                 }
1146             }
1147             return VLC_SUCCESS;
1148
1149         default:
1150             return demux_vaControlDefault( p_input, i_query, args );
1151     }
1152     return VLC_EGENERIC;
1153 }
1154
1155 /*****************************************************************************
1156  * Function to convert pts to chunk or byte
1157  *****************************************************************************/
1158
1159 static mtime_t AVI_PTSToChunk( avi_track_t *tk, mtime_t i_pts )
1160 {
1161     return (mtime_t)((int64_t)i_pts *
1162                      (int64_t)tk->i_rate /
1163                      (int64_t)tk->i_scale /
1164                      (int64_t)1000000 );
1165 }
1166 static mtime_t AVI_PTSToByte( avi_track_t *tk, mtime_t i_pts )
1167 {
1168     return (mtime_t)((int64_t)i_pts *
1169                      (int64_t)tk->i_rate /
1170                      (int64_t)tk->i_scale /
1171                      (int64_t)1000000 *
1172                      (int64_t)tk->i_samplesize );
1173 }
1174
1175 static mtime_t AVI_GetDPTS( avi_track_t *tk, int64_t i_count )
1176 {
1177     mtime_t i_dpts;
1178
1179     i_dpts = (mtime_t)( (int64_t)1000000 *
1180                         (int64_t)i_count *
1181                         (int64_t)tk->i_scale /
1182                         (int64_t)tk->i_rate );
1183
1184     if( tk->i_samplesize )
1185     {
1186         return i_dpts / tk->i_samplesize;
1187     }
1188     return i_dpts;
1189 }
1190
1191 static mtime_t AVI_GetPTS( avi_track_t *tk )
1192 {
1193     if( tk->i_samplesize )
1194     {
1195         int64_t i_count = 0;
1196
1197         /* we need a valid entry we will emulate one */
1198         if( tk->i_idxposc == tk->i_idxnb )
1199         {
1200             if( tk->i_idxposc )
1201             {
1202                 /* use the last entry */
1203                 i_count = tk->p_index[tk->i_idxnb - 1].i_lengthtotal
1204                             + tk->p_index[tk->i_idxnb - 1].i_length;
1205             }
1206         }
1207         else
1208         {
1209             i_count = tk->p_index[tk->i_idxposc].i_lengthtotal;
1210         }
1211         return AVI_GetDPTS( tk, i_count + tk->i_idxposb );
1212     }
1213     else
1214     {
1215         return AVI_GetDPTS( tk, tk->i_idxposc );
1216     }
1217 }
1218
1219 static int AVI_StreamChunkFind( input_thread_t *p_input,
1220                                 unsigned int i_stream )
1221 {
1222     demux_sys_t *p_sys = p_input->p_demux_data;
1223     avi_packet_t avi_pk;
1224
1225     /* find first chunk of i_stream that isn't in index */
1226
1227     if( p_sys->i_movi_lastchunk_pos >= p_sys->i_movi_begin + 12 )
1228     {
1229         stream_Seek( p_input->s, p_sys->i_movi_lastchunk_pos );
1230         if( AVI_PacketNext( p_input ) )
1231         {
1232             return VLC_EGENERIC;
1233         }
1234     }
1235     else
1236     {
1237         stream_Seek( p_input->s, p_sys->i_movi_begin + 12 );
1238     }
1239
1240     for( ;; )
1241     {
1242         if( p_input->b_die )
1243         {
1244             return VLC_EGENERIC;
1245         }
1246
1247         if( AVI_PacketGetHeader( p_input, &avi_pk ) )
1248         {
1249             msg_Warn( p_input, "cannot get packet header" );
1250             return VLC_EGENERIC;
1251         }
1252         if( avi_pk.i_stream >= p_sys->i_track ||
1253             ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) )
1254         {
1255             if( AVI_PacketNext( p_input ) )
1256             {
1257                 return VLC_EGENERIC;
1258             }
1259         }
1260         else
1261         {
1262             /* add this chunk to the index */
1263             AVIIndexEntry_t index;
1264
1265             index.i_id = avi_pk.i_fourcc;
1266             index.i_flags =
1267                AVI_GetKeyFlag(p_sys->track[avi_pk.i_stream]->i_codec,
1268                               avi_pk.i_peek);
1269             index.i_pos = avi_pk.i_pos;
1270             index.i_length = avi_pk.i_size;
1271             AVI_IndexAddEntry( p_sys, avi_pk.i_stream, &index );
1272
1273             if( avi_pk.i_stream == i_stream  )
1274             {
1275                 return VLC_SUCCESS;
1276             }
1277
1278             if( AVI_PacketNext( p_input ) )
1279             {
1280                 return VLC_EGENERIC;
1281             }
1282         }
1283     }
1284 }
1285
1286
1287 /* be sure that i_ck will be a valid index entry */
1288 static int AVI_StreamChunkSet( input_thread_t    *p_input,
1289                                unsigned int i_stream,
1290                                unsigned int i_ck )
1291 {
1292     demux_sys_t *p_sys = p_input->p_demux_data;
1293     avi_track_t *p_stream = p_sys->track[i_stream];
1294
1295     p_stream->i_idxposc = i_ck;
1296     p_stream->i_idxposb = 0;
1297
1298     if(  i_ck >= p_stream->i_idxnb )
1299     {
1300         p_stream->i_idxposc = p_stream->i_idxnb - 1;
1301         do
1302         {
1303             p_stream->i_idxposc++;
1304             if( AVI_StreamChunkFind( p_input, i_stream ) )
1305             {
1306                 return VLC_EGENERIC;
1307             }
1308
1309         } while( p_stream->i_idxposc < i_ck );
1310     }
1311
1312     return VLC_SUCCESS;
1313 }
1314
1315
1316 /* XXX FIXME up to now, we assume that all chunk are one after one */
1317 static int AVI_StreamBytesSet( input_thread_t    *p_input,
1318                                unsigned int i_stream,
1319                                off_t   i_byte )
1320 {
1321     demux_sys_t *p_sys = p_input->p_demux_data;
1322     avi_track_t *p_stream = p_sys->track[i_stream];
1323
1324     if( ( p_stream->i_idxnb > 0 )
1325         &&( i_byte < p_stream->p_index[p_stream->i_idxnb - 1].i_lengthtotal +
1326                 p_stream->p_index[p_stream->i_idxnb - 1].i_length ) )
1327     {
1328         /* index is valid to find the ck */
1329         /* uses dichototmie to be fast enougth */
1330         int i_idxposc = __MIN( p_stream->i_idxposc, p_stream->i_idxnb - 1 );
1331         int i_idxmax  = p_stream->i_idxnb;
1332         int i_idxmin  = 0;
1333         for( ;; )
1334         {
1335             if( p_stream->p_index[i_idxposc].i_lengthtotal > i_byte )
1336             {
1337                 i_idxmax  = i_idxposc ;
1338                 i_idxposc = ( i_idxmin + i_idxposc ) / 2 ;
1339             }
1340             else
1341             {
1342                 if( p_stream->p_index[i_idxposc].i_lengthtotal +
1343                         p_stream->p_index[i_idxposc].i_length <= i_byte)
1344                 {
1345                     i_idxmin  = i_idxposc ;
1346                     i_idxposc = (i_idxmax + i_idxposc ) / 2 ;
1347                 }
1348                 else
1349                 {
1350                     p_stream->i_idxposc = i_idxposc;
1351                     p_stream->i_idxposb = i_byte -
1352                             p_stream->p_index[i_idxposc].i_lengthtotal;
1353                     return VLC_SUCCESS;
1354                 }
1355             }
1356         }
1357
1358     }
1359     else
1360     {
1361         p_stream->i_idxposc = p_stream->i_idxnb - 1;
1362         p_stream->i_idxposb = 0;
1363         do
1364         {
1365             p_stream->i_idxposc++;
1366             if( AVI_StreamChunkFind( p_input, i_stream ) )
1367             {
1368                 return VLC_EGENERIC;
1369             }
1370
1371         } while( p_stream->p_index[p_stream->i_idxposc].i_lengthtotal +
1372                     p_stream->p_index[p_stream->i_idxposc].i_length <= i_byte );
1373
1374         p_stream->i_idxposb = i_byte -
1375                        p_stream->p_index[p_stream->i_idxposc].i_lengthtotal;
1376         return VLC_SUCCESS;
1377     }
1378 }
1379
1380 static int AVI_TrackSeek( input_thread_t *p_input,
1381                            int i_stream,
1382                            mtime_t i_date )
1383 {
1384     demux_sys_t  *p_sys = p_input->p_demux_data;
1385 #define p_stream    p_sys->track[i_stream]
1386     mtime_t i_oldpts;
1387
1388     i_oldpts = AVI_GetPTS( p_stream );
1389
1390     if( !p_stream->i_samplesize )
1391     {
1392         if( AVI_StreamChunkSet( p_input,
1393                                 i_stream,
1394                                 AVI_PTSToChunk( p_stream, i_date ) ) )
1395         {
1396             return VLC_EGENERIC;
1397         }
1398
1399         msg_Dbg( p_input,
1400                  "old:"I64Fd" %s new "I64Fd,
1401                  i_oldpts,
1402                  i_oldpts > i_date ? ">" : "<",
1403                  i_date );
1404
1405         if( p_stream->i_cat == VIDEO_ES )
1406         {
1407             /* search key frame */
1408             if( i_date < i_oldpts )
1409             {
1410                 while( p_stream->i_idxposc > 0 &&
1411                    !( p_stream->p_index[p_stream->i_idxposc].i_flags &
1412                                                                 AVIIF_KEYFRAME ) )
1413                 {
1414                     if( AVI_StreamChunkSet( p_input,
1415                                             i_stream,
1416                                             p_stream->i_idxposc - 1 ) )
1417                     {
1418                         return VLC_EGENERIC;
1419                     }
1420                 }
1421             }
1422             else
1423             {
1424                 while( p_stream->i_idxposc < p_stream->i_idxnb &&
1425                         !( p_stream->p_index[p_stream->i_idxposc].i_flags &
1426                                                                 AVIIF_KEYFRAME ) )
1427                 {
1428                     if( AVI_StreamChunkSet( p_input,
1429                                             i_stream,
1430                                             p_stream->i_idxposc + 1 ) )
1431                     {
1432                         return VLC_EGENERIC;
1433                     }
1434                 }
1435             }
1436         }
1437     }
1438     else
1439     {
1440         if( AVI_StreamBytesSet( p_input,
1441                                 i_stream,
1442                                 AVI_PTSToByte( p_stream, i_date ) ) )
1443         {
1444             return VLC_EGENERIC;
1445         }
1446     }
1447     return VLC_SUCCESS;
1448 #undef p_stream
1449 }
1450
1451 /****************************************************************************
1452  * Return VLC_TRUE if it's a key frame
1453  ****************************************************************************/
1454 static int AVI_GetKeyFlag( vlc_fourcc_t i_fourcc, uint8_t *p_byte )
1455 {
1456     switch( i_fourcc )
1457     {
1458         case FOURCC_DIV1:
1459             /* we have:
1460              *  startcode:      0x00000100   32bits
1461              *  framenumber     ?             5bits
1462              *  piture type     0(I),1(P)     2bits
1463              */
1464             if( GetDWBE( p_byte ) != 0x00000100 )
1465             {
1466                 /* it's not an msmpegv1 stream, strange...*/
1467                 return AVIIF_KEYFRAME;
1468             }
1469             else
1470             {
1471                 return p_byte[4] & 0x06 ? 0 : AVIIF_KEYFRAME;
1472             }
1473         case FOURCC_DIV2:
1474         case FOURCC_DIV3:   /* wmv1 also */
1475             /* we have
1476              *  picture type    0(I),1(P)     2bits
1477              */
1478             return p_byte[0] & 0xC0 ? 0 : AVIIF_KEYFRAME;
1479         case FOURCC_mp4v:
1480             /* we should find first occurence of 0x000001b6 (32bits)
1481              *  startcode:      0x000001b6   32bits
1482              *  piture type     0(I),1(P)     2bits
1483              */
1484             if( GetDWBE( p_byte ) != 0x000001b6 )
1485             {
1486                 /* not true , need to find the first VOP header */
1487                 return AVIIF_KEYFRAME;
1488             }
1489             else
1490             {
1491                 return p_byte[4] & 0xC0 ? 0 : AVIIF_KEYFRAME;
1492             }
1493         default:
1494             /* I can't do it, so say yes */
1495             return AVIIF_KEYFRAME;
1496     }
1497 }
1498
1499 vlc_fourcc_t AVI_FourccGetCodec( unsigned int i_cat, vlc_fourcc_t i_codec )
1500 {
1501     switch( i_cat )
1502     {
1503         case AUDIO_ES:
1504             wf_tag_to_fourcc( i_codec, &i_codec, NULL );
1505             return i_codec;
1506
1507         case VIDEO_ES:
1508             /* XXX DIV1 <- msmpeg4v1, DIV2 <- msmpeg4v2, DIV3 <- msmpeg4v3, mp4v for mpeg4 */
1509             switch( i_codec )
1510             {
1511                 case FOURCC_DIV1:
1512                 case FOURCC_div1:
1513                 case FOURCC_MPG4:
1514                 case FOURCC_mpg4:
1515                     return FOURCC_DIV1;
1516                 case FOURCC_DIV2:
1517                 case FOURCC_div2:
1518                 case FOURCC_MP42:
1519                 case FOURCC_mp42:
1520                 case FOURCC_MPG3:
1521                 case FOURCC_mpg3:
1522                     return FOURCC_DIV2;
1523                 case FOURCC_div3:
1524                 case FOURCC_MP43:
1525                 case FOURCC_mp43:
1526                 case FOURCC_DIV3:
1527                 case FOURCC_DIV4:
1528                 case FOURCC_div4:
1529                 case FOURCC_DIV5:
1530                 case FOURCC_div5:
1531                 case FOURCC_DIV6:
1532                 case FOURCC_div6:
1533                 case FOURCC_AP41:
1534                 case FOURCC_3IV1:
1535                 case FOURCC_3iv1:
1536                 case FOURCC_3IVD:
1537                 case FOURCC_3ivd:
1538                 case FOURCC_3VID:
1539                 case FOURCC_3vid:
1540                     return FOURCC_DIV3;
1541                 case FOURCC_DIVX:
1542                 case FOURCC_divx:
1543                 case FOURCC_MP4S:
1544                 case FOURCC_mp4s:
1545                 case FOURCC_M4S2:
1546                 case FOURCC_m4s2:
1547                 case FOURCC_xvid:
1548                 case FOURCC_XVID:
1549                 case FOURCC_XviD:
1550                 case FOURCC_DX50:
1551                 case FOURCC_mp4v:
1552                 case FOURCC_4:
1553                 case FOURCC_3IV2:
1554                 case FOURCC_3iv2:
1555                     return FOURCC_mp4v;
1556             }
1557         default:
1558             return VLC_FOURCC( 'u', 'n', 'd', 'f' );
1559     }
1560 }
1561
1562 /****************************************************************************
1563  *
1564  ****************************************************************************/
1565 static void AVI_ParseStreamHeader( vlc_fourcc_t i_id,
1566                                    int *pi_number, int *pi_type )
1567 {
1568 #define SET_PTR( p, v ) if( p ) *(p) = (v);
1569     int c1, c2;
1570
1571     c1 = ((uint8_t *)&i_id)[0];
1572     c2 = ((uint8_t *)&i_id)[1];
1573
1574     if( c1 < '0' || c1 > '9' || c2 < '0' || c2 > '9' )
1575     {
1576         SET_PTR( pi_number, 100 ); /* > max stream number */
1577         SET_PTR( pi_type, UNKNOWN_ES );
1578     }
1579     else
1580     {
1581         SET_PTR( pi_number, (c1 - '0') * 10 + (c2 - '0' ) );
1582         switch( VLC_TWOCC( ((uint8_t *)&i_id)[2], ((uint8_t *)&i_id)[3] ) )
1583         {
1584             case AVITWOCC_wb:
1585                 SET_PTR( pi_type, AUDIO_ES );
1586                 break;
1587             case AVITWOCC_dc:
1588             case AVITWOCC_db:
1589                 SET_PTR( pi_type, VIDEO_ES );
1590                 break;
1591             default:
1592                 SET_PTR( pi_type, UNKNOWN_ES );
1593                 break;
1594         }
1595     }
1596 #undef SET_PTR
1597 }
1598
1599 /****************************************************************************
1600  *
1601  ****************************************************************************/
1602 static int AVI_PacketGetHeader( input_thread_t *p_input, avi_packet_t *p_pk )
1603 {
1604     uint8_t  *p_peek;
1605
1606     if( stream_Peek( p_input->s, &p_peek, 16 ) < 16 )
1607     {
1608         return VLC_EGENERIC;
1609     }
1610     p_pk->i_fourcc  = VLC_FOURCC( p_peek[0], p_peek[1], p_peek[2], p_peek[3] );
1611     p_pk->i_size    = GetDWLE( p_peek + 4 );
1612     p_pk->i_pos     = stream_Tell( p_input->s );
1613     if( p_pk->i_fourcc == AVIFOURCC_LIST || p_pk->i_fourcc == AVIFOURCC_RIFF )
1614     {
1615         p_pk->i_type = VLC_FOURCC( p_peek[8],  p_peek[9],
1616                                    p_peek[10], p_peek[11] );
1617     }
1618     else
1619     {
1620         p_pk->i_type = 0;
1621     }
1622
1623     memcpy( p_pk->i_peek, p_peek + 8, 8 );
1624
1625     AVI_ParseStreamHeader( p_pk->i_fourcc, &p_pk->i_stream, &p_pk->i_cat );
1626     return VLC_SUCCESS;
1627 }
1628
1629 static int AVI_PacketNext( input_thread_t *p_input )
1630 {
1631     avi_packet_t    avi_ck;
1632     int             i_skip = 0;
1633
1634     if( AVI_PacketGetHeader( p_input, &avi_ck ) )
1635     {
1636         return VLC_EGENERIC;
1637     }
1638
1639     if( avi_ck.i_fourcc == AVIFOURCC_LIST &&
1640         ( avi_ck.i_type == AVIFOURCC_rec || avi_ck.i_type == AVIFOURCC_movi ) )
1641     {
1642         i_skip = 12;
1643     }
1644     else if( avi_ck.i_fourcc == AVIFOURCC_RIFF &&
1645              avi_ck.i_type == AVIFOURCC_AVIX )
1646     {
1647         i_skip = 24;
1648     }
1649     else
1650     {
1651         i_skip = __EVEN( avi_ck.i_size ) + 8;
1652     }
1653
1654     if( stream_Read( p_input->s, NULL, i_skip ) != i_skip )
1655     {
1656         return VLC_EGENERIC;
1657     }
1658     return VLC_SUCCESS;
1659 }
1660 static int AVI_PacketRead( input_thread_t   *p_input,
1661                            avi_packet_t     *p_pk,
1662                            block_t          **pp_frame )
1663 {
1664     size_t i_size;
1665
1666     i_size = __EVEN( p_pk->i_size + 8 );
1667
1668     if( ( *pp_frame = stream_Block( p_input->s, i_size ) ) == NULL )
1669     {
1670         return VLC_EGENERIC;
1671     }
1672     (*pp_frame)->p_buffer += 8;
1673     (*pp_frame)->i_buffer -= 8;
1674
1675     if( i_size != p_pk->i_size + 8 )
1676     {
1677         (*pp_frame)->i_buffer--;
1678     }
1679
1680     return VLC_SUCCESS;
1681 }
1682
1683 static int AVI_PacketSearch( input_thread_t *p_input )
1684 {
1685     demux_sys_t     *p_sys = p_input->p_demux_data;
1686     avi_packet_t    avi_pk;
1687     int             i_count = 0;
1688
1689     for( ;; )
1690     {
1691         if( stream_Read( p_input->s, NULL, 1 ) != 1 )
1692         {
1693             return VLC_EGENERIC;
1694         }
1695         AVI_PacketGetHeader( p_input, &avi_pk );
1696         if( avi_pk.i_stream < p_sys->i_track &&
1697             ( avi_pk.i_cat == AUDIO_ES || avi_pk.i_cat == VIDEO_ES ) )
1698         {
1699             return VLC_SUCCESS;
1700         }
1701         switch( avi_pk.i_fourcc )
1702         {
1703             case AVIFOURCC_JUNK:
1704             case AVIFOURCC_LIST:
1705             case AVIFOURCC_RIFF:
1706             case AVIFOURCC_idx1:
1707                 return VLC_SUCCESS;
1708         }
1709
1710         /* Prevents from eating all the CPU with broken files.
1711          * This value should be low enough so that it doesn't affect the
1712          * reading speed too much (not that we care much anyway because
1713          * this code is called only on broken files). */
1714         if( !(++i_count % 1024) )
1715         {
1716             if( p_input->b_die ) return VLC_EGENERIC;
1717
1718             msleep( 10000 );
1719             if( !(i_count % (1024 * 10)) )
1720                 msg_Warn( p_input, "trying to resync..." );
1721         }
1722     }
1723 }
1724
1725 /****************************************************************************
1726  * Index stuff.
1727  ****************************************************************************/
1728 static void AVI_IndexAddEntry( demux_sys_t *p_sys,
1729                                int i_stream,
1730                                AVIIndexEntry_t *p_index)
1731 {
1732     avi_track_t *tk = p_sys->track[i_stream];
1733
1734     /* Update i_movi_lastchunk_pos */
1735     if( p_sys->i_movi_lastchunk_pos < p_index->i_pos )
1736     {
1737         p_sys->i_movi_lastchunk_pos = p_index->i_pos;
1738     }
1739
1740     /* add the entry */
1741     if( tk->i_idxnb >= tk->i_idxmax )
1742     {
1743         tk->i_idxmax += 16384;
1744         tk->p_index = realloc( tk->p_index,
1745                                tk->i_idxmax * sizeof( AVIIndexEntry_t ) );
1746         if( tk->p_index == NULL )
1747         {
1748             return;
1749         }
1750     }
1751     /* calculate cumulate length */
1752     if( tk->i_idxnb > 0 )
1753     {
1754         p_index->i_lengthtotal =
1755             tk->p_index[tk->i_idxnb - 1].i_length +
1756                 tk->p_index[tk->i_idxnb - 1].i_lengthtotal;
1757     }
1758     else
1759     {
1760         p_index->i_lengthtotal = 0;
1761     }
1762
1763     tk->p_index[tk->i_idxnb++] = *p_index;
1764 }
1765
1766 static int AVI_IndexLoad_idx1( input_thread_t *p_input )
1767 {
1768     demux_sys_t *p_sys = p_input->p_demux_data;
1769
1770     avi_chunk_list_t    *p_riff;
1771     avi_chunk_list_t    *p_movi;
1772     avi_chunk_idx1_t    *p_idx1;
1773
1774     unsigned int i_stream;
1775     unsigned int i_index;
1776     off_t        i_offset;
1777     unsigned int i;
1778
1779     p_riff = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0);
1780     p_idx1 = AVI_ChunkFind( p_riff, AVIFOURCC_idx1, 0);
1781     p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0);
1782
1783     if( !p_idx1 )
1784     {
1785         msg_Warn( p_input, "cannot find idx1 chunk, no index defined" );
1786         return VLC_EGENERIC;
1787     }
1788
1789     /* *** calculate offset *** */
1790     /* Well, avi is __SHIT__ so test more than one entry 
1791      * (needed for some avi files) */
1792     i_offset = 0;
1793     for( i = 0; i < __MIN( p_idx1->i_entry_count, 10 ); i++ )
1794     {
1795         if( p_idx1->entry[i].i_pos < p_movi->i_chunk_pos )
1796         {
1797             i_offset = p_movi->i_chunk_pos + 8;
1798             break;
1799         }
1800     }
1801
1802     for( i_index = 0; i_index < p_idx1->i_entry_count; i_index++ )
1803     {
1804         unsigned int i_cat;
1805
1806         AVI_ParseStreamHeader( p_idx1->entry[i_index].i_fourcc,
1807                                &i_stream,
1808                                &i_cat );
1809         if( i_stream < p_sys->i_track &&
1810             i_cat == p_sys->track[i_stream]->i_cat )
1811         {
1812             AVIIndexEntry_t index;
1813             index.i_id      = p_idx1->entry[i_index].i_fourcc;
1814             index.i_flags   =
1815                 p_idx1->entry[i_index].i_flags&(~AVIIF_FIXKEYFRAME);
1816             index.i_pos     = p_idx1->entry[i_index].i_pos + i_offset;
1817             index.i_length  = p_idx1->entry[i_index].i_length;
1818             AVI_IndexAddEntry( p_sys, i_stream, &index );
1819         }
1820     }
1821     return VLC_SUCCESS;
1822 }
1823
1824 static void __Parse_indx( input_thread_t    *p_input,
1825                           int               i_stream,
1826                           avi_chunk_indx_t  *p_indx )
1827 {
1828     demux_sys_t         *p_sys    = p_input->p_demux_data;
1829     AVIIndexEntry_t     index;
1830     int32_t             i;
1831
1832     msg_Dbg( p_input, "loading subindex(0x%x) %d entries", p_indx->i_indextype, p_indx->i_entriesinuse );
1833     if( p_indx->i_indexsubtype == 0 )
1834     {
1835         for( i = 0; i < p_indx->i_entriesinuse; i++ )
1836         {
1837             index.i_id      = p_indx->i_id;
1838             index.i_flags   = p_indx->idx.std[i].i_size & 0x80000000 ? 0 : AVIIF_KEYFRAME;
1839             index.i_pos     = p_indx->i_baseoffset + p_indx->idx.std[i].i_offset - 8;
1840             index.i_length  = p_indx->idx.std[i].i_size&0x7fffffff;
1841
1842             AVI_IndexAddEntry( p_sys, i_stream, &index );
1843         }
1844     }
1845     else if( p_indx->i_indexsubtype == AVI_INDEX_2FIELD )
1846     {
1847         for( i = 0; i < p_indx->i_entriesinuse; i++ )
1848         {
1849             index.i_id      = p_indx->i_id;
1850             index.i_flags   = p_indx->idx.field[i].i_size & 0x80000000 ? 0 : AVIIF_KEYFRAME;
1851             index.i_pos     = p_indx->i_baseoffset + p_indx->idx.field[i].i_offset - 8;
1852             index.i_length  = p_indx->idx.field[i].i_size;
1853
1854             AVI_IndexAddEntry( p_sys, i_stream, &index );
1855         }
1856     }
1857     else
1858     {
1859         msg_Warn( p_input, "unknow subtype index(0x%x)", p_indx->i_indexsubtype );
1860     }
1861 }
1862
1863 static void AVI_IndexLoad_indx( input_thread_t *p_input )
1864 {
1865     demux_sys_t         *p_sys = p_input->p_demux_data;
1866     unsigned int        i_stream;
1867     int32_t             i;
1868
1869     avi_chunk_list_t    *p_riff;
1870     avi_chunk_list_t    *p_hdrl;
1871
1872     p_riff = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0);
1873     p_hdrl = AVI_ChunkFind( p_riff, AVIFOURCC_hdrl, 0 );
1874
1875     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
1876     {
1877         avi_chunk_list_t    *p_strl;
1878         avi_chunk_indx_t    *p_indx;
1879
1880 #define p_stream  p_sys->track[i_stream]
1881         p_strl = AVI_ChunkFind( p_hdrl, AVIFOURCC_strl, i_stream );
1882         p_indx = AVI_ChunkFind( p_strl, AVIFOURCC_indx, 0 );
1883
1884         if( !p_indx )
1885         {
1886             msg_Warn( p_input, "cannot find indx (misdetect/broken OpenDML file?)" );
1887             continue;
1888         }
1889
1890         if( p_indx->i_indextype == AVI_INDEX_OF_CHUNKS )
1891         {
1892             __Parse_indx( p_input, i_stream, p_indx );
1893         }
1894         else if( p_indx->i_indextype == AVI_INDEX_OF_INDEXES )
1895         {
1896             avi_chunk_indx_t    ck_sub;
1897             for( i = 0; i < p_indx->i_entriesinuse; i++ )
1898             {
1899                 if( stream_Seek( p_input->s, p_indx->idx.super[i].i_offset )||
1900                     AVI_ChunkRead( p_input->s, &ck_sub, NULL  ) )
1901                 {
1902                     break;
1903                 }
1904                 __Parse_indx( p_input, i_stream, &ck_sub );
1905             }
1906         }
1907         else
1908         {
1909             msg_Warn( p_input, "unknow type index(0x%x)", p_indx->i_indextype );
1910         }
1911 #undef p_stream
1912     }
1913 }
1914
1915 static void AVI_IndexLoad( input_thread_t *p_input )
1916 {
1917     demux_sys_t *p_sys = p_input->p_demux_data;
1918     unsigned int i_stream;
1919
1920     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
1921     {
1922         p_sys->track[i_stream]->i_idxnb  = 0;
1923         p_sys->track[i_stream]->i_idxmax = 0;
1924         p_sys->track[i_stream]->p_index  = NULL;
1925     }
1926
1927     if( p_sys->b_odml )
1928     {
1929         AVI_IndexLoad_indx( p_input );
1930     }
1931     else  if( AVI_IndexLoad_idx1( p_input ) )
1932     {
1933         /* try indx if idx1 failed as some "normal" file have indx too */
1934         AVI_IndexLoad_indx( p_input );
1935     }
1936
1937     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
1938     {
1939         msg_Dbg( p_input, "stream[%d] created %d index entries",
1940                 i_stream, p_sys->track[i_stream]->i_idxnb );
1941     }
1942 }
1943
1944 static void AVI_IndexCreate( input_thread_t *p_input )
1945 {
1946     demux_sys_t *p_sys = p_input->p_demux_data;
1947
1948     avi_chunk_list_t    *p_riff;
1949     avi_chunk_list_t    *p_movi;
1950
1951     unsigned int i_stream;
1952     off_t i_movi_end;
1953
1954     p_riff = AVI_ChunkFind( &p_sys->ck_root, AVIFOURCC_RIFF, 0);
1955     p_movi = AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0);
1956
1957     if( !p_movi )
1958     {
1959         msg_Err( p_input, "cannot find p_movi" );
1960         return;
1961     }
1962
1963     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
1964     {
1965         p_sys->track[i_stream]->i_idxnb  = 0;
1966         p_sys->track[i_stream]->i_idxmax = 0;
1967         p_sys->track[i_stream]->p_index  = NULL;
1968     }
1969     i_movi_end = __MIN( (off_t)(p_movi->i_chunk_pos + p_movi->i_chunk_size),
1970                         stream_Size( p_input->s ) );
1971
1972     stream_Seek( p_input->s, p_movi->i_chunk_pos + 12 );
1973     msg_Warn( p_input, "creating index from LIST-movi, will take time !" );
1974     for( ;; )
1975     {
1976         avi_packet_t pk;
1977
1978         if( p_input->b_die )
1979         {
1980             return;
1981         }
1982
1983         if( AVI_PacketGetHeader( p_input, &pk ) )
1984         {
1985             break;
1986         }
1987         if( pk.i_stream < p_sys->i_track &&
1988             pk.i_cat == p_sys->track[pk.i_stream]->i_cat )
1989         {
1990             AVIIndexEntry_t index;
1991             index.i_id      = pk.i_fourcc;
1992             index.i_flags   =
1993                AVI_GetKeyFlag(p_sys->track[pk.i_stream]->i_codec, pk.i_peek);
1994             index.i_pos     = pk.i_pos;
1995             index.i_length  = pk.i_size;
1996             AVI_IndexAddEntry( p_sys, pk.i_stream, &index );
1997         }
1998         else
1999         {
2000             switch( pk.i_fourcc )
2001             {
2002                 case AVIFOURCC_idx1:
2003                     if( p_sys->b_odml )
2004                     {
2005                         avi_chunk_list_t *p_sysx;
2006                         p_sysx = AVI_ChunkFind( &p_sys->ck_root,
2007                                                 AVIFOURCC_RIFF, 1 );
2008
2009                         msg_Dbg( p_input, "looking for new RIFF chunk" );
2010                         if( stream_Seek( p_input->s, p_sysx->i_chunk_pos + 24))
2011                         {
2012                             goto print_stat;
2013                         }
2014                         break;
2015                     }
2016                     goto print_stat;
2017                 case AVIFOURCC_RIFF:
2018                         msg_Dbg( p_input, "new RIFF chunk found" );
2019                 case AVIFOURCC_rec:
2020                 case AVIFOURCC_JUNK:
2021                     break;
2022                 default:
2023                     msg_Warn( p_input, "need resync, probably broken avi" );
2024                     if( AVI_PacketSearch( p_input ) )
2025                     {
2026                         msg_Warn( p_input, "lost sync, abord index creation" );
2027                         goto print_stat;
2028                     }
2029             }
2030         }
2031
2032         if( ( !p_sys->b_odml && pk.i_pos + pk.i_size >= i_movi_end ) ||
2033             AVI_PacketNext( p_input ) )
2034         {
2035             break;
2036         }
2037     }
2038
2039 print_stat:
2040     for( i_stream = 0; i_stream < p_sys->i_track; i_stream++ )
2041     {
2042         msg_Dbg( p_input,
2043                 "stream[%d] creating %d index entries",
2044                 i_stream,
2045                 p_sys->track[i_stream]->i_idxnb );
2046     }
2047 }
2048
2049 /*****************************************************************************
2050  * Stream management
2051  *****************************************************************************/
2052 static int AVI_TrackStopFinishedStreams( input_thread_t *p_input )
2053 {
2054     demux_sys_t *p_sys = p_input->p_demux_data;
2055     unsigned int i;
2056     int b_end = VLC_TRUE;
2057
2058     for( i = 0; i < p_sys->i_track; i++ )
2059     {
2060         avi_track_t *tk = p_sys->track[i];
2061         if( tk->i_idxposc >= tk->i_idxnb )
2062         {
2063             tk->b_activated = VLC_FALSE;
2064         }
2065         else
2066         {
2067             b_end = VLC_FALSE;
2068         }
2069     }
2070     return( b_end );
2071 }
2072
2073 /****************************************************************************
2074  * AVI_MovieGetLength give max streams length in second
2075  ****************************************************************************/
2076 static mtime_t  AVI_MovieGetLength( input_thread_t *p_input )
2077 {
2078     demux_sys_t  *p_sys = p_input->p_demux_data;
2079     mtime_t      i_maxlength = 0;
2080     unsigned int i;
2081
2082     for( i = 0; i < p_sys->i_track; i++ )
2083     {
2084         avi_track_t *tk = p_sys->track[i];
2085         mtime_t i_length;
2086
2087         /* fix length for each stream */
2088         if( tk->i_idxnb < 1 || !tk->p_index )
2089         {
2090             continue;
2091         }
2092
2093         if( tk->i_samplesize )
2094         {
2095             i_length = AVI_GetDPTS( tk,
2096                                     tk->p_index[tk->i_idxnb-1].i_lengthtotal +
2097                                         tk->p_index[tk->i_idxnb-1].i_length );
2098         }
2099         else
2100         {
2101             i_length = AVI_GetDPTS( tk, tk->i_idxnb );
2102         }
2103         i_length /= (mtime_t)1000000;    /* in seconds */
2104
2105         msg_Dbg( p_input,
2106                  "stream[%d] length:"I64Fd" (based on index)",
2107                  i,
2108                  i_length );
2109         i_maxlength = __MAX( i_maxlength, i_length );
2110     }
2111
2112     return i_maxlength;
2113 }
2114
2115