]> git.sesse.net Git - vlc/blob - modules/demux/avi/avi.c
* all : begin to rewrite some parts of avi demux, mainly to clean ugly code
[vlc] / 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.6 2002/10/15 00:55:07 fenrir 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 #include <string.h>                                              /* strdup() */
28 #include <errno.h>
29 #include <sys/types.h>
30
31 #include <vlc/vlc.h>
32 #include <vlc/input.h>
33
34 #include "video.h"
35
36 #include "libioRIFF.h"
37 #include "libavi.h"
38 #include "avi.h"
39
40 /*****************************************************************************
41  * Local prototypes
42  *****************************************************************************/
43 static int    AVIInit   ( vlc_object_t * );
44 static void __AVIEnd    ( vlc_object_t * );
45 static int    AVISeek   ( input_thread_t *, mtime_t, int );
46 static int    AVIDemux_Seekable  ( input_thread_t * );
47 static int    AVIDemux_UnSeekable( input_thread_t *p_input );
48
49 #define AVIEnd(a) __AVIEnd(VLC_OBJECT(a))
50
51 /*****************************************************************************
52  * Module descriptor
53  *****************************************************************************/
54 vlc_module_begin();
55     add_category_hint( "demuxer", NULL );
56         add_bool( "avi-interleaved", 0, NULL,
57                   "force interleaved method", 
58                   "force interleaved method" );
59         add_bool( "avi-index", 0, NULL,
60                   "force index creation", 
61                   "force index creation" );
62
63     set_description( "avi demuxer" );
64     set_capability( "demux", 160 );
65     set_callbacks( AVIInit, __AVIEnd );
66 vlc_module_end();
67
68 /*****************************************************************************
69  * Some usefull functions to manipulate memory 
70  *****************************************************************************/
71 static int __AVI_GetDataInPES( input_thread_t *, pes_packet_t **, int, int );
72
73 static u16 GetWLE( byte_t *p_buff )
74 {
75     return( p_buff[0] + ( p_buff[1] << 8 ) );
76 }
77 static u32 GetDWLE( byte_t *p_buff )
78 {
79     return( p_buff[0] + ( p_buff[1] << 8 ) + 
80             ( p_buff[2] << 16 ) + ( p_buff[3] << 24 ) );
81 }
82 static u32 GetDWBE( byte_t *p_buff )
83 {
84     return( p_buff[3] + ( p_buff[2] << 8 ) + 
85             ( p_buff[1] << 16 ) + ( p_buff[0] << 24 ) );
86 }
87 static vlc_fourcc_t GetFOURCC( byte_t *p_buff )
88 {
89     return( VLC_FOURCC( p_buff[0], p_buff[1], p_buff[2], p_buff[3] ) );
90 }
91
92 static inline off_t __EVEN( off_t i )
93 {
94     return( (i & 1) ? i+1 : i );
95 }
96
97 #define __ABS( x ) ( (x) < 0 ? (-(x)) : (x) )
98
99 /* Test if it seems that it's a key frame */
100 static int AVI_GetKeyFlag( vlc_fourcc_t i_fourcc, u8 *p_byte )
101 {
102     switch( i_fourcc )
103     {
104         case FOURCC_DIV1:
105             /* we have:
106                 startcode:      0x00000100   32bits
107                 framenumber     ?             5bits
108                 piture type     0(I),1(P)     2bits
109              */
110             if( GetDWBE( p_byte ) != 0x00000100 ) 
111             {
112             /* it's not an msmpegv1 stream, strange...*/
113                 return( AVIIF_KEYFRAME );
114             }
115             else
116             {
117                 return( p_byte[4]&0x06 ? 0 : AVIIF_KEYFRAME);
118             }
119         case FOURCC_DIV2:
120         case FOURCC_DIV3:   // wmv1 also
121             /* we have
122                 picture type    0(I),1(P)     2bits
123              */
124             return( p_byte[0]&0xC0 ? 0 : AVIIF_KEYFRAME );
125         case FOURCC_mp4v:
126             /* we should find first occurence of 0x000001b6 (32bits)
127                 startcode:      0x000001b6   32bits
128                 piture type     0(I),1(P)     2bits
129             */
130             if( GetDWBE( p_byte ) != 0x000001b6 )
131             {
132                 /* not true , need to find the first VOP header */
133                 return( AVIIF_KEYFRAME );
134             }
135             else
136             {
137                 return( p_byte[4]&0xC0 ? 0 : AVIIF_KEYFRAME );
138             }
139         default:
140             /* I can't do it, so said yes */
141             return( AVIIF_KEYFRAME );
142     }
143 }
144
145 vlc_fourcc_t AVI_FourccGetCodec( int i_cat, vlc_fourcc_t i_codec )
146 {
147     switch( i_cat )
148     {
149         case( AUDIO_ES ):
150             switch( i_codec )
151             {
152                 case( WAVE_FORMAT_PCM ):
153                     return( VLC_FOURCC( 'a', 'r', 'a', 'w' ) );
154                 case( WAVE_FORMAT_MPEG ):
155                 case( WAVE_FORMAT_MPEGLAYER3 ):
156                     return( VLC_FOURCC( 'm', 'p', 'g', 'a' ) );
157                 case( WAVE_FORMAT_A52 ):
158                     return( VLC_FOURCC( 'a', '5', '2', ' ' ) );
159                 case( WAVE_FORMAT_WMA1 ):
160                     return( VLC_FOURCC( 'w', 'm', 'a', '1' ) );
161                 case( WAVE_FORMAT_WMA2 ):
162                     return( VLC_FOURCC( 'w', 'm', 'a', '2' ) );
163                 default:
164                     return( VLC_FOURCC( 'm', 's', 
165                                         ( i_codec >> 8 )&0xff, 
166                                         i_codec&0xff ) );
167             }
168         case( VIDEO_ES ):
169             // XXX DIV1 <- msmpeg4v1, DIV2 <- msmpeg4v2, DIV3 <- msmpeg4v3, mp4v for mpeg4 
170             switch( i_codec )
171             {
172                 case FOURCC_DIV1:
173                 case FOURCC_div1:
174                 case FOURCC_MPG4:
175                 case FOURCC_mpg4:
176                     return( FOURCC_DIV1 );
177                 case FOURCC_DIV2:
178                 case FOURCC_div2:
179                 case FOURCC_MP42:
180                 case FOURCC_mp42:
181                 case FOURCC_MPG3:
182                 case FOURCC_mpg3:
183                     return( FOURCC_DIV2 );
184                 case FOURCC_div3:
185                 case FOURCC_MP43:
186                 case FOURCC_mp43:
187                 case FOURCC_DIV3:
188                 case FOURCC_DIV4:
189                 case FOURCC_div4:
190                 case FOURCC_DIV5:
191                 case FOURCC_div5:
192                 case FOURCC_DIV6:
193                 case FOURCC_div6:
194                 case FOURCC_AP41:
195                 case FOURCC_3IV1:
196                     return( FOURCC_DIV3 );
197                 case FOURCC_DIVX:
198                 case FOURCC_divx:
199                 case FOURCC_MP4S:
200                 case FOURCC_mp4s:
201                 case FOURCC_M4S2:
202                 case FOURCC_m4s2:
203                 case FOURCC_xvid:
204                 case FOURCC_XVID:
205                 case FOURCC_XviD:
206                 case FOURCC_DX50:
207                 case FOURCC_mp4v:
208                 case FOURCC_4:
209                     return( FOURCC_mp4v );
210             }
211         default:
212             return( VLC_FOURCC( 'u', 'n', 'd', 'f' ) );
213     }
214 }
215 /*****************************************************************************
216  * Data and functions to manipulate pes buffer
217  *****************************************************************************/
218 #define BUFFER_MAXTOTALSIZE     500*1024 /* 1/2 Mo */
219 #define BUFFER_MAXSPESSIZE      200*1024
220 static int  AVI_PESBuffer_IsFull( AVIStreamInfo_t *p_info )
221 {
222     return( p_info->i_pes_totalsize > BUFFER_MAXTOTALSIZE ? 1 : 0);
223 }
224 static void AVI_PESBuffer_Add( input_buffers_t *p_method_data,
225                                AVIStreamInfo_t *p_info,
226                                pes_packet_t *p_pes,
227                                int i_posc,
228                                int i_posb )
229 {
230     AVIESBuffer_t   *p_buffer_pes;
231
232     if( p_info->i_pes_totalsize > BUFFER_MAXTOTALSIZE )
233     {
234         input_DeletePES( p_method_data, p_pes );
235         return;
236     }
237     
238     if( !( p_buffer_pes = malloc( sizeof( AVIESBuffer_t ) ) ) )
239     {
240         input_DeletePES( p_method_data, p_pes );
241         return;
242     }
243     p_buffer_pes->p_next = NULL;
244     p_buffer_pes->p_pes = p_pes;
245     p_buffer_pes->i_posc = i_posc;
246     p_buffer_pes->i_posb = i_posb;
247
248     if( p_info->p_pes_last ) 
249     {
250         p_info->p_pes_last->p_next = p_buffer_pes;
251     }
252     p_info->p_pes_last = p_buffer_pes;
253     if( !p_info->p_pes_first )
254     {
255         p_info->p_pes_first = p_buffer_pes;
256     }
257     p_info->i_pes_count++;
258     p_info->i_pes_totalsize += p_pes->i_pes_size;
259 }
260 static pes_packet_t *AVI_PESBuffer_Get( AVIStreamInfo_t *p_info )
261 {
262     AVIESBuffer_t   *p_buffer_pes;
263     pes_packet_t    *p_pes;
264     if( p_info->p_pes_first )
265     {
266         p_buffer_pes = p_info->p_pes_first;
267         p_info->p_pes_first = p_buffer_pes->p_next;
268         if( !p_info->p_pes_first )
269         {
270             p_info->p_pes_last = NULL;
271         }
272         p_pes = p_buffer_pes->p_pes;
273
274         free( p_buffer_pes );
275         p_info->i_pes_count--;
276         p_info->i_pes_totalsize -= p_pes->i_pes_size;
277         return( p_pes );
278     }
279     else
280     {
281         return( NULL );
282     }
283 }
284 static int AVI_PESBuffer_Drop( input_buffers_t *p_method_data,
285                                 AVIStreamInfo_t *p_info )
286 {
287     pes_packet_t *p_pes = AVI_PESBuffer_Get( p_info );
288     if( p_pes )
289     {
290         input_DeletePES( p_method_data, p_pes );
291         return( 1 );
292     }
293     else
294     {
295         return( 0 );
296     }
297 }
298 static void AVI_PESBuffer_Flush( input_buffers_t *p_method_data,
299                                  AVIStreamInfo_t *p_info )
300 {
301     while( p_info->p_pes_first )
302     {
303         AVI_PESBuffer_Drop( p_method_data, p_info );
304     }
305 }
306
307 static void AVI_ParseStreamHeader( u32 i_id, int *pi_number, int *pi_type )
308 {
309 #define SET_PTR( p, v ) if( p ) *(p) = (v);
310     int c1,c2;
311 /* XXX i_id have to be read using MKFOURCC and NOT VLC_FOURCC */
312     c1 = ( i_id ) & 0xFF;
313     c2 = ( i_id >>  8 ) & 0xFF;
314
315     if( c1 < '0' || c1 > '9' || c2 < '0' || c2 > '9' )
316     {
317         SET_PTR( pi_number, 100); /* > max stream number */
318         SET_PTR( pi_type, UNKNOWN_ES);
319     }
320     else
321     {
322         SET_PTR( pi_number, (c1 - '0') * 10 + (c2 - '0' ) );
323         switch( ( i_id >> 16 ) & 0xFFFF )
324         {
325             case( AVITWOCC_wb ):
326                 SET_PTR( pi_type, AUDIO_ES );
327                 break;
328              case( AVITWOCC_dc ):
329              case( AVITWOCC_db ):
330                 SET_PTR( pi_type, VIDEO_ES);
331                 break;
332              default:
333                 SET_PTR( pi_type, UNKNOWN_ES );
334                 break;
335         }
336     }
337 #undef SET_PTR
338 }
339
340 typedef struct avi_packet_s
341 {
342     u32     i_fourcc;
343     off_t   i_pos;
344     u32     i_size;
345     u32     i_type;     // only for AVIFOURCC_LIST
346     u8      i_peek[8];  //first 8 bytes
347
348     int     i_stream;
349     int     i_cat;
350 } avi_packet_t;
351
352 static int AVI_PacketGetHeader( input_thread_t *p_input, avi_packet_t *p_pk )
353 {
354     u8  *p_peek;
355     
356     if( input_Peek( p_input, &p_peek, 16 ) < 16 )
357     {
358         return( 0 );
359     }
360     p_pk->i_fourcc  = GetDWLE( p_peek );
361     p_pk->i_size    = GetDWLE( p_peek + 4 );
362     p_pk->i_pos     = AVI_TellAbsolute( p_input );
363     if( p_pk->i_fourcc == AVIFOURCC_LIST )
364     {
365         p_pk->i_type = GetDWLE( p_peek + 8 );
366     }
367     else
368     {
369         p_pk->i_type = 0;
370     }
371     
372     memcpy( p_pk->i_peek, p_peek + 8, 8 );
373
374     AVI_ParseStreamHeader( p_pk->i_fourcc, &p_pk->i_stream, &p_pk->i_cat );
375     return( 1 );
376 }
377
378 static int AVI_PacketNext( input_thread_t *p_input )
379 {
380     avi_packet_t    avi_ck;
381
382     if( !AVI_PacketGetHeader( p_input, &avi_ck ) )
383     {
384         return( 0 );
385     }
386     if( avi_ck.i_fourcc == AVIFOURCC_LIST && avi_ck.i_type == AVIFOURCC_rec )
387     {
388         return( AVI_SkipBytes( p_input, 12 ) );
389     }
390     else
391     {
392         return( AVI_SkipBytes( p_input, __EVEN( avi_ck.i_size ) + 8 ));
393     }
394 }
395 static int AVI_PacketRead( input_thread_t   *p_input,
396                            avi_packet_t     *p_pk,
397                            pes_packet_t     **pp_pes )
398 {
399
400     if( __AVI_GetDataInPES( p_input, pp_pes, p_pk->i_size + 8, 1) 
401             != p_pk->i_size + 8)
402     {
403         return( 0 );
404     }
405     (*pp_pes)->p_first->p_payload_start += 8;
406     (*pp_pes)->i_pes_size -= 8;
407     return( 1 );
408 }
409
410 static int AVI_PacketSearch( input_thread_t *p_input )
411 {
412     demux_sys_t     *p_avi = p_input->p_demux_data;
413
414     avi_packet_t    avi_pk;
415     for( ;; )
416     {
417         if( !AVI_SkipBytes( p_input, 1 ) )
418         {
419             return( 0 );
420         }
421         AVI_PacketGetHeader( p_input, &avi_pk );
422         if( avi_pk.i_stream < p_avi->i_streams &&
423             ( avi_pk.i_cat == AUDIO_ES || avi_pk.i_cat == VIDEO_ES ) )
424         {
425             return( 1 );
426         }
427         switch( avi_pk.i_fourcc )
428         {
429             case AVIFOURCC_JUNK:
430             case AVIFOURCC_LIST:
431             case AVIFOURCC_idx1:
432                 return( 1 );
433         }
434     }
435 }
436
437
438 static void __AVI_AddEntryIndex( AVIStreamInfo_t *p_info,
439                                  AVIIndexEntry_t *p_index)
440 {
441     if( p_info->p_index == NULL )
442     {
443         p_info->i_idxmax = 16384;
444         p_info->i_idxnb = 0;
445         if( !( p_info->p_index = calloc( p_info->i_idxmax, 
446                                   sizeof( AVIIndexEntry_t ) ) ) )
447         {
448             return;
449         }
450     }
451     if( p_info->i_idxnb >= p_info->i_idxmax )
452     {
453         p_info->i_idxmax += 16384;
454         if( !( p_info->p_index = realloc( (void*)p_info->p_index,
455                            p_info->i_idxmax * 
456                            sizeof( AVIIndexEntry_t ) ) ) )
457         {
458             return;
459         }
460     }
461     /* calculate cumulate length */
462     if( p_info->i_idxnb > 0 )
463     {
464         p_index->i_lengthtotal = 
465             p_info->p_index[p_info->i_idxnb - 1].i_length +
466                 p_info->p_index[p_info->i_idxnb - 1].i_lengthtotal;
467     }
468     else
469     {
470         p_index->i_lengthtotal = 0;
471     }
472
473     p_info->p_index[p_info->i_idxnb] = *p_index;
474     p_info->i_idxnb++;
475 }
476
477 static void AVI_IndexLoad( input_thread_t *p_input )
478 {
479     demux_sys_t *p_avi = p_input->p_demux_data;
480     
481     avi_chunk_list_t    *p_riff;
482     avi_chunk_list_t    *p_movi;
483     avi_chunk_idx1_t    *p_idx1;
484
485     int i_stream;
486     int i_index;
487     off_t   i_offset;
488     
489     p_riff = (avi_chunk_list_t*)AVI_ChunkFind( &p_avi->ck_root, 
490                                                AVIFOURCC_RIFF, 0);
491     
492     p_idx1 = (avi_chunk_idx1_t*)AVI_ChunkFind( p_riff, AVIFOURCC_idx1, 0);
493     p_movi = (avi_chunk_list_t*)AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0);
494
495     if( !p_idx1 )
496     {
497         msg_Warn( p_input, "cannot find idx1 chunk, no index defined" );
498         return;
499     }
500     for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
501     {
502         p_avi->pp_info[i_stream]->i_idxnb  = 0;
503         p_avi->pp_info[i_stream]->i_idxmax = 0;
504         p_avi->pp_info[i_stream]->p_index  = NULL;
505     }
506     /* *** calculate offset *** */
507     if( p_idx1->i_entry_count > 0 && 
508         p_idx1->entry[0].i_pos < p_movi->i_chunk_pos )
509     {
510         i_offset = p_movi->i_chunk_pos + 8;
511     }
512     else
513     {
514         i_offset = 0;
515     }
516
517     for( i_index = 0; i_index < p_idx1->i_entry_count; i_index++ )
518     {
519         int i_cat;
520         
521         AVI_ParseStreamHeader( p_idx1->entry[i_index].i_fourcc,
522                                &i_stream,
523                                &i_cat );
524         if( i_stream < p_avi->i_streams &&
525             i_cat == p_avi->pp_info[i_stream]->i_cat )
526         {
527             AVIIndexEntry_t index;
528             index.i_id      = p_idx1->entry[i_index].i_fourcc;
529             index.i_flags   = p_idx1->entry[i_index].i_flags&(~AVIIF_FIXKEYFRAME);
530             index.i_pos     = p_idx1->entry[i_index].i_pos + i_offset;
531             index.i_length  = p_idx1->entry[i_index].i_length;
532             __AVI_AddEntryIndex( p_avi->pp_info[i_stream],
533                                  &index );
534         }
535     }
536     for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
537     {
538         msg_Dbg( p_input, 
539                 "stream[%d] creating %d index entries", 
540                 i_stream,
541                 p_avi->pp_info[i_stream]->i_idxnb );
542     }
543     
544 }
545
546 static void AVI_IndexCreate( input_thread_t *p_input )
547 {
548     demux_sys_t *p_avi = p_input->p_demux_data;
549     
550     avi_chunk_list_t    *p_riff;
551     avi_chunk_list_t    *p_movi;
552
553     int i_stream;
554     off_t   i_movi_end;
555     
556     p_riff = (avi_chunk_list_t*)AVI_ChunkFind( &p_avi->ck_root, 
557                                                AVIFOURCC_RIFF, 0);
558     p_movi = (avi_chunk_list_t*)AVI_ChunkFind( p_riff, AVIFOURCC_movi, 0);
559     
560     if( !p_movi )
561     {
562         msg_Err( p_input, "cannot find p_movi" );
563         return;
564     }
565
566     for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
567     {
568         p_avi->pp_info[i_stream]->i_idxnb  = 0;
569         p_avi->pp_info[i_stream]->i_idxmax = 0;
570         p_avi->pp_info[i_stream]->p_index  = NULL;
571     }
572     i_movi_end = __MIN( p_movi->i_chunk_pos + p_movi->i_chunk_size,
573                         p_input->stream.p_selected_area->i_size );
574
575     AVI_SeekAbsolute( p_input, p_movi->i_chunk_pos + 12);
576     msg_Warn( p_input, "creating index from LIST-movi, will take time !" );
577     for( ;; )
578     {
579         avi_packet_t pk;
580         
581         if( !AVI_PacketGetHeader( p_input, &pk ) )
582         {
583             break;
584         }
585         if( pk.i_stream < p_avi->i_streams &&
586             pk.i_cat == p_avi->pp_info[pk.i_stream]->i_cat )
587         {
588             AVIIndexEntry_t index;
589             index.i_id      = pk.i_fourcc;
590             index.i_flags   = 
591                AVI_GetKeyFlag(p_avi->pp_info[pk.i_stream]->i_codec, pk.i_peek);
592             index.i_pos     = pk.i_pos;
593             index.i_length  = pk.i_size;
594             __AVI_AddEntryIndex( p_avi->pp_info[pk.i_stream],
595                                  &index );
596         }
597         else
598         {
599             switch( pk.i_fourcc )
600             {
601                 case AVIFOURCC_idx1:
602                     goto print_stat;
603                 case AVIFOURCC_rec:
604                 case AVIFOURCC_JUNK:
605                     break;
606                 default:
607                     msg_Warn( p_input, "need resync, probably broken avi" );
608                     if( !AVI_PacketSearch( p_input ) )
609                     {
610                         msg_Warn( p_input, "lost sync, abord index creation" );
611                         goto print_stat;
612                     }
613             }
614         }
615         if( pk.i_pos + pk.i_size >= i_movi_end ||
616             !AVI_PacketNext( p_input ) )
617         {
618             break;
619         }
620     }
621
622 print_stat:
623     for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
624     {
625         msg_Dbg( p_input, 
626                 "stream[%d] creating %d index entries", 
627                 i_stream,
628                 p_avi->pp_info[i_stream]->i_idxnb );
629     }
630 }
631
632
633 /*****************************************************************************
634  * Stream managment
635  *****************************************************************************/
636 static int  AVI_StreamStart  ( input_thread_t *, demux_sys_t *, int );
637 static int  AVI_StreamSeek   ( input_thread_t *, demux_sys_t *, int, mtime_t );
638 static void AVI_StreamStop   ( input_thread_t *, demux_sys_t *, int );
639
640 static int  AVI_StreamStart( input_thread_t *p_input,  
641                              demux_sys_t *p_avi, int i_stream )
642 {
643 #define p_stream    p_avi->pp_info[i_stream]
644     if( !p_stream->p_es )
645     {
646         msg_Warn( p_input, "stream[%d] unselectable", i_stream );
647         return( 0 );
648     }
649     if( p_stream->i_activated )
650     {
651         msg_Warn( p_input, "stream[%d] already selected", i_stream );
652         return( 1 );
653     }
654     
655     if( !p_stream->p_es->p_decoder_fifo )
656     {
657         vlc_mutex_lock( &p_input->stream.stream_lock );
658         input_SelectES( p_input, p_stream->p_es );
659         vlc_mutex_unlock( &p_input->stream.stream_lock );
660     }
661     p_stream->i_activated = p_stream->p_es->p_decoder_fifo ? 1 : 0;
662
663     AVI_StreamSeek( p_input, p_avi, i_stream, p_avi->i_time );
664
665     return( p_stream->i_activated );
666 #undef  p_stream
667 }
668
669 static void    AVI_StreamStop( input_thread_t *p_input,
670                                demux_sys_t *p_avi, int i_stream )
671 {
672 #define p_stream    p_avi->pp_info[i_stream]
673
674     if( !p_stream->i_activated )
675     {
676         msg_Warn( p_input, "stream[%d] already unselected", i_stream );
677         return;
678     }
679     
680 //    AVI_PESBuffer_Flush( p_input->p_method_data, p_stream );
681
682     if( p_stream->p_es->p_decoder_fifo )
683     {
684         vlc_mutex_lock( &p_input->stream.stream_lock );
685         input_UnselectES( p_input, p_stream->p_es );
686         vlc_mutex_unlock( &p_input->stream.stream_lock );
687     }
688
689             
690     p_stream->i_activated = 0;
691
692 #undef  p_stream
693 }
694
695 /****************************************************************************
696  * AVI_MovieGetLength give max streams length in second
697  ****************************************************************************/
698 static mtime_t  AVI_MovieGetLength( input_thread_t *p_input, demux_sys_t *p_avi )
699 {
700     int i_stream;
701     mtime_t i_maxlength;
702     
703     i_maxlength = 0;
704     for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
705     {
706 #define p_stream  p_avi->pp_info[i_stream]
707         mtime_t i_length;
708         /* fix length for each stream */
709         if( p_stream->i_idxnb < 1 || !p_stream->p_index )
710         {
711             continue;
712         }
713
714         if( p_stream->i_samplesize )
715         {
716             i_length = 
717                 (mtime_t)( p_stream->p_index[p_stream->i_idxnb-1].i_lengthtotal + 
718                            p_stream->p_index[p_stream->i_idxnb-1].i_length ) /
719                 (mtime_t)p_stream->i_scale /
720                 (mtime_t)p_stream->i_rate /
721                 (mtime_t)p_stream->i_samplesize;
722         }
723         else
724         {
725             i_length = (mtime_t)p_stream->i_idxnb *
726                        (mtime_t)p_stream->i_scale /
727                        (mtime_t)p_stream->i_rate;
728         }
729
730         msg_Dbg( p_input, 
731                  "stream[%d] length:%lld (based on index)",
732                  i_stream,
733                  i_length );
734         i_maxlength = __MAX( i_maxlength, i_length );
735 #undef p_stream                         
736     }
737
738     return( i_maxlength );
739 }
740
741 /*****************************************************************************
742  * AVIEnd: frees unused data
743  *****************************************************************************/
744 static void __AVIEnd ( vlc_object_t * p_this )
745 {   
746     input_thread_t *    p_input = (input_thread_t *)p_this;
747     int i;
748     demux_sys_t *p_avi = p_input->p_demux_data  ; 
749     
750     if( p_avi->p_movi ) 
751             RIFF_DeleteChunk( p_input, p_avi->p_movi );
752     if( p_avi->pp_info )
753     {
754         for( i = 0; i < p_avi->i_streams; i++ )
755         {
756             if( p_avi->pp_info[i] ) 
757             {
758                 if( p_avi->pp_info[i]->p_index )
759                 {
760                       free( p_avi->pp_info[i]->p_index );
761                       AVI_PESBuffer_Flush( p_input->p_method_data, 
762                                            p_avi->pp_info[i] );
763                 }
764                 free( p_avi->pp_info[i] ); 
765             }
766         }
767          free( p_avi->pp_info );
768     }
769     AVI_ChunkFreeRoot( p_input, &p_avi->ck_root );
770 }
771
772 /*****************************************************************************
773  * AVIInit: check file and initializes AVI structures
774  *****************************************************************************/
775 static int AVIInit( vlc_object_t * p_this )
776 {   
777     input_thread_t *    p_input = (input_thread_t *)p_this;
778     avi_chunk_t         ck_riff;
779     avi_chunk_list_t    *p_riff = (avi_chunk_list_t*)&ck_riff;
780     avi_chunk_list_t    *p_hdrl, *p_movi;
781 #if 0
782     avi_chunk_list_t    *p_INFO;
783     avi_chunk_strz_t    *p_name;
784 #endif
785     avi_chunk_avih_t    *p_avih;
786     demux_sys_t *p_avi;
787     es_descriptor_t *p_es = NULL; /* avoid warning */
788     int i;
789
790     p_input->pf_demux = AVIDemux_Seekable;
791     if( !AVI_TestFile( p_input ) )
792     {
793         msg_Warn( p_input, "avi module discarded (invalid headr)" );
794         return( -1 );
795     }
796
797     /* Initialize access plug-in structures. */
798     if( p_input->i_mtu == 0 )
799     {
800         /* Improve speed. */
801         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
802     }
803
804     if( !( p_input->p_demux_data = 
805                     p_avi = malloc( sizeof(demux_sys_t) ) ) )
806     {
807         msg_Err( p_input, "out of memory" );
808         return( -1 );
809     }
810     memset( p_avi, 0, sizeof( demux_sys_t ) );
811     p_avi->i_time = 0;
812     p_avi->i_pcr  = 0;
813     p_avi->i_rate = DEFAULT_RATE;
814     p_avi->b_seekable = ( ( p_input->stream.b_seekable )
815                         &&( p_input->stream.i_method == INPUT_METHOD_FILE ) );
816     /* *** for unseekable stream, automaticaly use AVIDemux_interleaved *** */
817     if( !p_avi->b_seekable || config_GetInt( p_input, "avi-interleaved" ) )
818     {
819         p_input->pf_demux = AVIDemux_UnSeekable;
820     }
821     
822     if( !AVI_ChunkReadRoot( p_input, &p_avi->ck_root, p_avi->b_seekable ) )
823     {
824         msg_Err( p_input, "avi module discarded (invalid file)" );
825         return( -1 );
826     }
827     AVI_ChunkDumpDebug( p_input, &p_avi->ck_root );
828
829
830     p_riff  = (avi_chunk_list_t*)AVI_ChunkFind( &p_avi->ck_root, 
831                                                 AVIFOURCC_RIFF, 0 );
832     p_hdrl  = (avi_chunk_list_t*)AVI_ChunkFind( p_riff,
833                                                 AVIFOURCC_hdrl, 0 );
834     p_movi  = (avi_chunk_list_t*)AVI_ChunkFind( p_riff, 
835                                                 AVIFOURCC_movi, 0 );
836 #if 0
837     p_INFO  = (avi_chunk_list_t*)AVI_ChunkFind( p_riff,
838                                                 AVIFOURCC_INFO, 0 );
839     p_name  = (avi_chunk_strz_t*)AVI_ChunkFind( p_INFO,
840                                                 AVIFOURCC_INAM, 0 );
841     if( p_name )
842     {
843         
844     }
845 #endif
846
847     if( !p_hdrl || !p_movi )
848     {
849         msg_Err( p_input, "avi module discarded (invalid file)" );
850         return( -1 );
851     }
852     
853     if( !( p_avih = (avi_chunk_avih_t*)AVI_ChunkFind( p_hdrl, 
854                                                       AVIFOURCC_avih, 0 ) ) )
855     {
856         msg_Err( p_input, "cannot find avih chunk" );
857         return( -1 );
858     }
859     p_avi->i_streams = AVI_ChunkCount( p_hdrl, AVIFOURCC_strl );
860     if( p_avih->i_streams != p_avi->i_streams )
861     {
862         msg_Warn( p_input, 
863                   "found %d stream but %d are declared",
864                   p_avi->i_streams,
865                   p_avih->i_streams );
866     }
867     if( p_avi->i_streams == 0 )
868     {
869         AVIEnd( p_input );
870         msg_Err( p_input, "no stream defined!" );
871         return( -1 );
872     }
873
874     /*  create one program */
875     vlc_mutex_lock( &p_input->stream.stream_lock );
876     if( input_InitStream( p_input, 0 ) == -1)
877     {
878         vlc_mutex_unlock( &p_input->stream.stream_lock );
879         AVIEnd( p_input );
880         msg_Err( p_input, "cannot init stream" );
881         return( -1 );
882     }
883     if( input_AddProgram( p_input, 0, 0) == NULL )
884     {
885         vlc_mutex_unlock( &p_input->stream.stream_lock );
886         AVIEnd( p_input );
887         msg_Err( p_input, "cannot add program" );
888         return( -1 );
889     }
890     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
891     vlc_mutex_unlock( &p_input->stream.stream_lock ); 
892     
893     /* print informations on streams */
894     msg_Dbg( p_input, "AVIH: %d stream, flags %s%s%s%s ", 
895              p_avi->i_streams,
896              p_avih->i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
897              p_avih->i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
898              p_avih->i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
899              p_avih->i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"" );
900
901     /* now read info on each stream and create ES */
902     p_avi->pp_info = calloc( p_avi->i_streams, 
903                             sizeof( AVIStreamInfo_t* ) );
904     memset( p_avi->pp_info, 
905             0, 
906             sizeof( AVIStreamInfo_t* ) * p_avi->i_streams );
907
908     for( i = 0 ; i < p_avi->i_streams; i++ )
909     {
910         avi_chunk_list_t    *p_avi_strl;
911         avi_chunk_strh_t    *p_avi_strh;
912         avi_chunk_strf_auds_t    *p_avi_strf_auds;
913         avi_chunk_strf_vids_t    *p_avi_strf_vids;
914         int     i_init_size;
915         void    *p_init_data;
916 #define p_info  p_avi->pp_info[i]
917         p_info = malloc( sizeof(AVIStreamInfo_t ) );
918         memset( p_info, 0, sizeof( AVIStreamInfo_t ) );        
919     
920         p_avi_strl = (avi_chunk_list_t*)AVI_ChunkFind( p_hdrl, 
921                                                        AVIFOURCC_strl, i );
922         p_avi_strh = (avi_chunk_strh_t*)AVI_ChunkFind( p_avi_strl, 
923                                                        AVIFOURCC_strh, 0 );
924         p_avi_strf_auds = 
925             p_avi_strf_vids = AVI_ChunkFind( p_avi_strl, AVIFOURCC_strf, 0 );
926
927         if( !p_avi_strl || !p_avi_strh || 
928                 ( !p_avi_strf_auds && !p_avi_strf_vids ) )
929         {
930             msg_Warn( p_input, "stream[%d] incomlete", i );
931             continue;
932         }
933         
934         /* *** Init p_info *** */
935         p_info->i_rate  = p_avi_strh->i_rate;
936         p_info->i_scale = p_avi_strh->i_scale;
937         p_info->i_samplesize = p_avi_strh->i_samplesize;
938
939         switch( p_avi_strh->i_type )
940         {
941             case( AVIFOURCC_auds ):
942                 p_info->i_cat = AUDIO_ES;
943                 p_info->i_fourcc = 
944                     AVI_FourccGetCodec( AUDIO_ES, 
945                                         p_avi_strf_auds->i_formattag );
946                 p_info->i_codec  = p_info->i_fourcc;
947                 i_init_size = p_avi_strf_auds->i_chunk_size;
948                 p_init_data = p_avi_strf_auds->p_wfx;
949                 msg_Dbg( p_input, "stream[%d] audio(0x%x) %d channels %dHz %dbits",
950                         i,
951                         p_avi_strf_auds->i_formattag,
952                         p_avi_strf_auds->i_channels,
953                         p_avi_strf_auds->i_samplespersec,
954                         p_avi_strf_auds->i_bitspersample );
955                 break;
956                 
957             case( AVIFOURCC_vids ):
958                 p_info->i_cat = VIDEO_ES;
959                 /* XXX quick hack for playing ffmpeg video, I don't know 
960                     who is doing something wrong */
961                 p_info->i_samplesize = 0;
962                 p_info->i_fourcc = p_avi_strf_vids->i_compression;
963                 p_info->i_codec = 
964                     AVI_FourccGetCodec( VIDEO_ES, p_info->i_fourcc );
965                 i_init_size = p_avi_strf_vids->i_chunk_size;
966                 p_init_data = p_avi_strf_vids->p_bih;
967                 msg_Dbg( p_input, "stream[%d] video(%4.4s) %dx%d %dbpp %ffps",
968                         i,
969                          (char*)&p_avi_strf_vids->i_compression,
970                          p_avi_strf_vids->i_width,
971                          p_avi_strf_vids->i_height,
972                          p_avi_strf_vids->i_bitcount,
973                          (float)p_info->i_rate /
974                              (float)p_info->i_scale );
975                 break;
976             default:
977                 msg_Err( p_input, "stream[%d] unknown type", i );
978                 p_info->i_cat = UNKNOWN_ES;
979                 i_init_size = 0;
980                 p_init_data = NULL;
981                 break;
982         }
983         p_info->i_activated = 0;
984         /* add one ES */
985         vlc_mutex_lock( &p_input->stream.stream_lock );
986         p_info->p_es =
987             p_es = input_AddES( p_input,
988                                 p_input->stream.p_selected_program, 1+i,
989                                 i_init_size );
990         vlc_mutex_unlock( &p_input->stream.stream_lock );
991         p_es->i_stream_id =i; /* XXX: i don't use it */ 
992         p_es->i_fourcc = p_info->i_fourcc;
993         p_es->i_cat = p_info->i_cat;
994
995         /* We copy strf for decoder in p_es->p_demux_data */
996         if( p_init_data )
997         {
998             memcpy( p_es->p_demux_data, 
999                     p_init_data,
1000                     i_init_size );
1001         }
1002 #undef p_info           
1003     }
1004     if( config_GetInt( p_input, "avi-index" ) )
1005     {
1006         if( p_avi->b_seekable )
1007         {
1008             AVI_IndexCreate( p_input );
1009         }
1010         else
1011         {
1012             msg_Warn( p_input, "cannot create index (unseekable stream)" );
1013             AVI_IndexLoad( p_input );
1014         }
1015     }
1016     else
1017     {
1018         AVI_IndexLoad( p_input );
1019     }
1020     
1021     /* *** movie length in sec *** */
1022 #if 0
1023     p_avi->i_length = (mtime_t)p_avih->i_totalframes * 
1024                       (mtime_t)p_avih->i_microsecperframe / 
1025                       (mtime_t)1000000;
1026 #endif
1027
1028     p_avi->i_length = AVI_MovieGetLength( p_input, p_avi );
1029     if( p_avi->i_length < (mtime_t)p_avih->i_totalframes *
1030                           (mtime_t)p_avih->i_microsecperframe /
1031                           (mtime_t)1000000 )
1032     {
1033         msg_Warn( p_input, "broken or missing index, 'seek' will be axproximative or will have strange behavour" );
1034     }
1035
1036     vlc_mutex_lock( &p_input->stream.stream_lock ); 
1037     if( p_avi->i_length )
1038     {
1039         p_input->stream.i_mux_rate = 
1040             p_input->stream.p_selected_area->i_size / 50 / p_avi->i_length;
1041     }
1042     else
1043     {
1044         p_input->stream.i_mux_rate = 0;
1045     }
1046     vlc_mutex_unlock( &p_input->stream.stream_lock ); 
1047
1048     /* create a pseudo p_movi */
1049     p_avi->p_movi = malloc( sizeof( riffchunk_t ) );
1050     p_avi->p_movi->i_id = AVIFOURCC_LIST;
1051     p_avi->p_movi->i_type = AVIFOURCC_movi;
1052     p_avi->p_movi->i_size = p_movi->i_chunk_size;
1053     p_avi->p_movi->i_pos = p_movi->i_chunk_pos;
1054     p_avi->p_movi->p_data = NULL;
1055         
1056
1057     for( i = 0; i < p_avi->i_streams; i++ )
1058     {
1059 #define p_info  p_avi->pp_info[i]
1060         switch( p_info->p_es->i_cat )
1061         {
1062             case( VIDEO_ES ):
1063
1064                 if( (p_avi->p_info_video == NULL) ) 
1065                 {
1066                     p_avi->p_info_video = p_info;
1067                     /* TODO add test to see if a decoder has been found */
1068                     AVI_StreamStart( p_input, p_avi, i );
1069                 }
1070                 break;
1071
1072             case( AUDIO_ES ):
1073                 if( (p_avi->p_info_audio == NULL) ) 
1074                 {
1075                     p_avi->p_info_audio = p_info;
1076                     AVI_StreamStart( p_input, p_avi, i );
1077                 }
1078                 break;
1079             default:
1080                 break;
1081         }
1082 #undef p_info    
1083     }
1084
1085     /* we select the first audio and video ES */
1086     vlc_mutex_lock( &p_input->stream.stream_lock );
1087     if( !p_avi->p_info_video ) 
1088     {
1089         msg_Warn( p_input, "no video stream found" );
1090     }
1091     if( !p_avi->p_info_audio )
1092     {
1093         msg_Warn( p_input, "no audio stream found!" );
1094     }
1095     p_input->stream.p_selected_program->b_is_ok = 1;
1096     vlc_mutex_unlock( &p_input->stream.stream_lock );
1097     
1098     if( p_avi->b_seekable )
1099     {
1100         AVI_ChunkGoto( p_input, p_movi );
1101     }
1102     else
1103     {
1104         // already at begining of p_movi
1105     }
1106     AVI_SkipBytes( p_input, 12 ); // enter in p_movi
1107     return( 0 );
1108 }
1109
1110
1111
1112
1113 /*****************************************************************************
1114  * Function to convert pts to chunk or byte
1115  *****************************************************************************/
1116
1117 static inline mtime_t AVI_PTSToChunk( AVIStreamInfo_t *p_info, 
1118                                         mtime_t i_pts )
1119 {
1120     return( (mtime_t)((s64)i_pts *
1121                       (s64)p_info->i_rate /
1122                       (s64)p_info->i_scale /
1123                       (s64)1000000 ) );
1124 }
1125 static inline mtime_t AVI_PTSToByte( AVIStreamInfo_t *p_info,
1126                                        mtime_t i_pts )
1127 {
1128     return( (mtime_t)((s64)i_pts * 
1129                       (s64)p_info->i_samplesize *
1130                       (s64)p_info->i_rate /
1131                       (s64)p_info->i_scale /
1132                       (s64)1000000 ) );
1133
1134 }
1135 static mtime_t AVI_GetPTS( AVIStreamInfo_t *p_info )
1136 {
1137     
1138     if( p_info->i_samplesize )
1139     {
1140         /* we need a valid entry we will emulate one */
1141         int i_len;
1142         if( p_info->i_idxposc == p_info->i_idxnb )
1143         {
1144             if( p_info->i_idxposc )
1145             {
1146                 /* use the last entry */
1147                 i_len = p_info->p_index[p_info->i_idxnb - 1].i_lengthtotal
1148                             + p_info->p_index[p_info->i_idxnb - 1].i_length
1149                             + p_info->i_idxposb; /* should be 0 */
1150             }
1151             else
1152             {
1153                 i_len = p_info->i_idxposb; 
1154                 /* no valid entry use only offset*/
1155             }
1156         }
1157         else
1158         {
1159             i_len = p_info->p_index[p_info->i_idxposc].i_lengthtotal
1160                                 + p_info->i_idxposb;
1161         }
1162         return( (mtime_t)( (s64)1000000 *
1163                    (s64)i_len *
1164                     (s64)p_info->i_scale /
1165                     (s64)p_info->i_rate /
1166                     (s64)p_info->i_samplesize ) );
1167     }
1168     else
1169     {
1170         /* even if p_info->i_idxposc isn't valid, there isn't any problem */
1171         return( (mtime_t)( (s64)1000000 *
1172                     (s64)(p_info->i_idxposc ) *
1173                     (s64)p_info->i_scale /
1174                     (s64)p_info->i_rate) );
1175     }
1176 }
1177
1178
1179 /*****************************************************************************
1180  * Functions to acces streams data 
1181  * Uses it, because i plane to read unseekable stream
1182  * XXX NEVER set directly i_idxposc and i_idxposb unless you know what you do 
1183  *****************************************************************************/
1184
1185 /* FIXME FIXME change b_pad to number of bytes to skipp after reading */
1186 static int __AVI_GetDataInPES( input_thread_t *p_input,
1187                                pes_packet_t   **pp_pes,
1188                                int i_size,
1189                                int b_pad )
1190 {
1191
1192     int i_read;
1193     data_packet_t *p_data;
1194
1195     
1196     if( !(*pp_pes = input_NewPES( p_input->p_method_data ) ) )
1197     {
1198         return( 0 );
1199     }
1200
1201     
1202     if( !i_size )
1203     {
1204         p_data = input_NewPacket( p_input->p_method_data, 0 );
1205         (*pp_pes)->p_first = (*pp_pes)->p_last  = p_data;
1206         (*pp_pes)->i_nb_data = 1;
1207         (*pp_pes)->i_pes_size = 0;
1208         return( 0 );
1209     }
1210     
1211     if( ( i_size&1 )&&( b_pad ) )
1212     {
1213         b_pad = 1;
1214         i_size++;
1215     }
1216     else
1217     {
1218         b_pad = 0;
1219     }
1220
1221     do
1222     {
1223         i_read = input_SplitBuffer(p_input, &p_data, __MIN( i_size - 
1224                                                               (*pp_pes)->i_pes_size, 1024 ) );
1225         if( i_read < 0 )
1226         {
1227             return( (*pp_pes)->i_pes_size );
1228         }
1229         if( !(*pp_pes)->p_first )
1230         {
1231             (*pp_pes)->p_first = 
1232                     (*pp_pes)->p_last  = p_data;
1233             (*pp_pes)->i_nb_data = 1;
1234             (*pp_pes)->i_pes_size = i_read;
1235         }
1236         else
1237         {
1238             (*pp_pes)->p_last->p_next = 
1239                     (*pp_pes)->p_last = p_data;
1240             (*pp_pes)->i_nb_data++;
1241             (*pp_pes)->i_pes_size += i_read;
1242         }
1243     } while( ((*pp_pes)->i_pes_size < i_size)&&( i_read ) );
1244
1245     if( b_pad )
1246     {
1247         (*pp_pes)->i_pes_size--;
1248         (*pp_pes)->p_last->p_payload_end--;
1249         i_size--;
1250     }
1251
1252         return( i_size );
1253 }
1254
1255 static int __AVI_SeekAndGetChunk( input_thread_t  *p_input,
1256                                   AVIStreamInfo_t *p_info )
1257 {
1258     pes_packet_t *p_pes;
1259     int i_length, i_ret;
1260     
1261     i_length = __MIN( p_info->p_index[p_info->i_idxposc].i_length 
1262                         - p_info->i_idxposb,
1263                             BUFFER_MAXSPESSIZE );
1264
1265     AVI_SeekAbsolute( p_input, 
1266                       (off_t)p_info->p_index[p_info->i_idxposc].i_pos + 
1267                             p_info->i_idxposb + 8);
1268
1269     i_ret = __AVI_GetDataInPES( p_input, &p_pes, i_length , 0);
1270
1271     if( i_ret != i_length )
1272     {
1273         return( 0 );
1274     }
1275     /*  TODO test key frame if i_idxposb == 0*/
1276     AVI_PESBuffer_Add( p_input->p_method_data,
1277                        p_info,
1278                        p_pes,
1279                        p_info->i_idxposc,
1280                        p_info->i_idxposb );
1281     return( 1 );
1282 }
1283 /* TODO check if it's correct (humm...) and optimisation ... */
1284 /* return 0 if we choose to get only the ck we want 
1285  *        1 if index is invalid
1286  *        2 if there is a ck_other before ck_info and the last proced ck_info*/
1287 /* XXX XXX XXX avi file is some BIG shit, and sometime index give 
1288  * a refenrence to the same chunk BUT with a different size ( usually 0 )
1289  */
1290
1291 static inline int __AVI_GetChunkMethod( input_thread_t  *p_input,
1292                                  AVIStreamInfo_t *p_info,
1293                                  AVIStreamInfo_t *p_other )
1294 {
1295     int i_info_pos;
1296     int i_other_pos;
1297     
1298     int i_info_pos_last;
1299     int i_other_pos_last;
1300
1301     /*If we don't have a valid entry we need to parse from last 
1302         defined chunk and it's the only way that we return 1*/
1303     if( p_info->i_idxposc >= p_info->i_idxnb )
1304     {
1305         return( 1 );
1306     }
1307
1308     /* KNOW we have a valid entry for p_info */
1309     /* we return 0 if we haven't an valid entry for p_other */ 
1310     if( ( !p_other )||( p_other->i_idxposc >= p_other->i_idxnb ) )
1311     {
1312         return( 0 );
1313     }
1314
1315     /* KNOW there are 2 streams with valid entry */
1316    
1317     /* we return 0 if for one of the two streams we will not read 
1318        chunk-aligned */
1319     if( ( p_info->i_idxposb )||( p_other->i_idxposb ) )
1320     { 
1321         return( 0 );
1322     }
1323     
1324     /* KNOW we have a valid entry for the 2 streams
1325          and for the 2 we want an aligned chunk (given by i_idxposc )*/
1326         /* if in stream, the next chunk is back than the one we 
1327            have just read, it's useless to parse */
1328     i_info_pos  = p_info->p_index[p_info->i_idxposc].i_pos;
1329     i_other_pos = p_other->p_index[p_other->i_idxposc].i_pos ;
1330
1331     i_info_pos_last  = p_info->i_idxposc ? 
1332                             p_info->p_index[p_info->i_idxposc - 1].i_pos : 0;
1333     i_other_pos_last = p_other->i_idxposc ?
1334                             p_other->p_index[p_other->i_idxposc - 1].i_pos : 0 ;
1335    
1336     
1337     if( ( ( p_info->i_idxposc )&&( i_info_pos <= i_info_pos_last ) ) ||
1338         ( ( p_other->i_idxposc )&&( i_other_pos <= i_other_pos_last ) ) )
1339     {
1340         return( 0 );
1341     }
1342
1343     /* KNOW for the 2 streams, the ck we want are after the last read 
1344            or it's the first */
1345
1346     /* if the first ck_other we want isn't between ck_info_last 
1347        and ck_info, don't parse */
1348     /* TODO fix this, use also number in buffered PES */
1349     if( ( i_other_pos > i_info_pos) /* ck_other too far */
1350         ||( i_other_pos < i_info_pos_last ) ) /* it's too late for ck_other */
1351     {
1352         return( 0 );
1353     } 
1354    
1355     /* we Know we will find ck_other, and before ck_info 
1356         "if ck_info is too far" will be handle after */
1357     return( 2 );
1358 }
1359
1360                          
1361 static inline int __AVI_ChooseSize( int l1, int l2 )
1362 {
1363     /* XXX l2 is prefered if 0 otherwise min not equal to 0 */
1364     if( !l2 )
1365     { 
1366         return( 0 );
1367     }
1368     return( !l1 ? l2 : __MIN( l1,l2 ) );
1369 }
1370
1371 /* We know we will read chunk align */
1372 static int __AVI_GetAndPutChunkInBuffer( input_thread_t  *p_input,
1373                                   AVIStreamInfo_t *p_info,
1374                                   int i_size,
1375                                   int i_ck )
1376 {
1377
1378     pes_packet_t    *p_pes;
1379     int i_length; 
1380
1381     i_length = __MIN( i_size, BUFFER_MAXSPESSIZE );
1382
1383     /* Skip chunk header */
1384
1385     if( __AVI_GetDataInPES( p_input, &p_pes, i_length + 8,1 ) != i_length +8 )
1386     {
1387         return( 0 );
1388     }
1389     p_pes->p_first->p_payload_start += 8;
1390     p_pes->i_pes_size -= 8;
1391
1392     i_size = GetDWLE( p_pes->p_first->p_demux_start + 4);
1393
1394     AVI_PESBuffer_Add( p_input->p_method_data,
1395                        p_info,
1396                        p_pes,
1397                        i_ck,
1398                        0 );
1399     /* skip unwanted bytes */
1400     if( i_length != i_size)
1401     {
1402         msg_Err( p_input, "Chunk Size mismatch" );
1403         AVI_SeekAbsolute( p_input,
1404                           __EVEN( AVI_TellAbsolute( p_input ) + 
1405                                   i_size - i_length ) );
1406     }
1407     return( 1 );
1408 }
1409
1410 /* XXX Don't use this function directly ! XXX */
1411 static int __AVI_GetChunk( input_thread_t  *p_input,
1412                            AVIStreamInfo_t *p_info,
1413                            int b_load )
1414 {
1415     demux_sys_t *p_avi = p_input->p_demux_data;
1416     AVIStreamInfo_t *p_other;
1417     int i_method;
1418     off_t i_posmax;
1419     int i;
1420    
1421 #define p_info_i p_avi->pp_info[i]
1422     while( p_info->p_pes_first )
1423     {
1424         if( ( p_info->p_pes_first->i_posc == p_info->i_idxposc ) 
1425              &&( p_info->i_idxposb >= p_info->p_pes_first->i_posb )
1426              &&( p_info->i_idxposb < p_info->p_pes_first->i_posb + 
1427                      p_info->p_pes_first->p_pes->i_pes_size ) )
1428   
1429         {
1430             return( 1 ); /* we have it in buffer */
1431         }
1432         else
1433         {
1434             AVI_PESBuffer_Drop( p_input->p_method_data, p_info );
1435         }
1436     }
1437     /* up to now we handle only one audio and video streams at the same time */
1438     p_other = (p_info == p_avi->p_info_video ) ?
1439                      p_avi->p_info_audio : p_avi->p_info_video ;
1440
1441     i_method = __AVI_GetChunkMethod( p_input, p_info, p_other );
1442
1443     if( !i_method )
1444     {
1445         /* get directly the good chunk */
1446         return( b_load ? __AVI_SeekAndGetChunk( p_input, p_info ) : 1 );
1447     }
1448     /* We will parse
1449         * because invalid index
1450         * or will find ck_other before ck_info 
1451     */
1452 /*    msg_Warn( p_input, "method %d", i_method ); */
1453     /* we will calculate the better position we have to reach */
1454     if( i_method == 1 )
1455     {
1456         /* invalid index */
1457     /*  the position max we have already reached */
1458         /* FIXME this isn't the better because sometime will fail to
1459             put in buffer p_other since it could be too far */
1460         AVIStreamInfo_t *p_info_max = p_info;
1461         
1462         for( i = 0; i < p_avi->i_streams; i++ )
1463         {
1464             if( p_info_i->i_idxnb )
1465             {
1466                 if( p_info_max->i_idxnb )
1467                 {
1468                     if( p_info_i->p_index[p_info_i->i_idxnb -1 ].i_pos >
1469                             p_info_max->p_index[p_info_max->i_idxnb -1 ].i_pos )
1470                     {
1471                         p_info_max = p_info_i;
1472                     }
1473                 }
1474                 else
1475                 {
1476                     p_info_max = p_info_i;
1477                 }
1478             }
1479         }
1480         if( p_info_max->i_idxnb )
1481         {
1482             /* be carefull that size between index and ck can sometime be 
1483               different without any error (and other time it's an error) */
1484            i_posmax = p_info_max->p_index[p_info_max->i_idxnb -1 ].i_pos; 
1485            /* so choose this, and I know that we have already reach it */
1486         }
1487         else
1488         {
1489             i_posmax = p_avi->p_movi->i_pos + 12;
1490         }
1491     }
1492     else
1493     {
1494         if( !b_load )
1495         {
1496             return( 1 ); /* all is ok */
1497         }
1498         /* valid index */
1499         /* we know that the entry and the last one are valid for the 2 stream */
1500         /* and ck_other will come *before* index so go directly to it*/
1501         i_posmax = p_other->p_index[p_other->i_idxposc].i_pos;
1502     }
1503
1504     AVI_SeekAbsolute( p_input, i_posmax );
1505     /* the first chunk we will see is :
1506             * the last chunk that we have already seen for broken index 
1507             * the first ck for other with good index */ 
1508     for( ; ; ) /* infinite parsing until the ck we want */
1509     {
1510         riffchunk_t  *p_ck;
1511         int i_type;
1512         
1513         /* Get the actual chunk in the stream */
1514         if( !(p_ck = RIFF_ReadChunk( p_input )) )
1515         {
1516             return( 0 );
1517         }
1518 /*        msg_Dbg( p_input, "ck: %4.4s len %d", &p_ck->i_id, p_ck->i_size ); */
1519         /* special case for LIST-rec chunk */
1520         if( ( p_ck->i_id == AVIFOURCC_LIST )&&( p_ck->i_type == AVIFOURCC_rec ) )
1521         {
1522             AVI_SkipBytes( p_input, 12 );
1523 //            RIFF_DescendChunk( p_input );
1524             RIFF_DeleteChunk( p_input, p_ck );
1525             continue;
1526         }
1527         AVI_ParseStreamHeader( p_ck->i_id, &i, &i_type );
1528         /* littles checks but not too much if you want to read all file */ 
1529         if( i >= p_avi->i_streams )
1530         {
1531             RIFF_DeleteChunk( p_input, p_ck );
1532             if( RIFF_NextChunk( p_input, p_avi->p_movi ) != 0 )
1533             {
1534                 return( 0 );
1535             }
1536         }
1537         else
1538         {
1539             int i_size;
1540
1541             /* have we found a new entry (not present in index)? */
1542             if( ( !p_info_i->i_idxnb )
1543                 ||(p_info_i->p_index[p_info_i->i_idxnb-1].i_pos < p_ck->i_pos))
1544             {
1545                 AVIIndexEntry_t index;
1546
1547                 index.i_id = p_ck->i_id;
1548                 index.i_flags = AVI_GetKeyFlag( p_info_i->i_codec,
1549                                                 (u8*)&p_ck->i_8bytes);
1550                 index.i_pos = p_ck->i_pos;
1551                 index.i_length = p_ck->i_size;
1552                 __AVI_AddEntryIndex( p_info_i, &index );   
1553             }
1554
1555
1556             /* TODO check if p_other is full and then if is possible 
1557                 go directly to the good chunk */
1558             if( ( p_info_i == p_other )
1559                 &&( !AVI_PESBuffer_IsFull( p_other ) )
1560                 &&( ( !p_other->p_pes_last )||
1561                     ( p_other->p_pes_last->p_pes->i_pes_size != 
1562                                                     BUFFER_MAXSPESSIZE ) ) )
1563             {
1564                 int i_ck = p_other->p_pes_last ? 
1565                         p_other->p_pes_last->i_posc + 1 : p_other->i_idxposc;
1566                 i_size = __AVI_ChooseSize( p_ck->i_size,
1567                                            p_other->p_index[i_ck].i_length);
1568                
1569                 if( p_other->p_index[i_ck].i_pos == p_ck->i_pos )
1570                 {
1571                     if( !__AVI_GetAndPutChunkInBuffer( p_input, p_other, 
1572                                                        i_size, i_ck ) )
1573                     {
1574                         RIFF_DeleteChunk( p_input, p_ck );
1575                         return( 0 );
1576                     }
1577                 }
1578                 else
1579                 {
1580                     if( RIFF_NextChunk( p_input, p_avi->p_movi ) != 0 )
1581                     {
1582                         RIFF_DeleteChunk( p_input, p_ck );
1583
1584                         return( 0 );
1585                     }
1586
1587                 }
1588                         
1589                 RIFF_DeleteChunk( p_input, p_ck );
1590             }
1591             else
1592             if( ( p_info_i == p_info)
1593                 &&( p_info->i_idxposc < p_info->i_idxnb ) )
1594             {
1595                 /* the first ck_info is ok otherwise it should be 
1596                         loaded without parsing */
1597                 i_size = __AVI_ChooseSize( p_ck->i_size,
1598                                  p_info->p_index[p_info->i_idxposc].i_length);
1599
1600
1601                 RIFF_DeleteChunk( p_input, p_ck );
1602                 
1603                 return( b_load ? __AVI_GetAndPutChunkInBuffer( p_input,
1604                                                                p_info,
1605                                                                i_size,
1606                                                      p_info->i_idxposc ) : 1 );
1607             }
1608             else
1609             {
1610                 /* skip it */
1611                 RIFF_DeleteChunk( p_input, p_ck );
1612                 if( RIFF_NextChunk( p_input, p_avi->p_movi ) != 0 )
1613                 {
1614                     return( 0 );
1615                 }
1616             }
1617         }
1618
1619     
1620     }
1621     
1622 #undef p_info_i
1623 }
1624
1625 /* be sure that i_ck will be a valid index entry */
1626 static int AVI_SetStreamChunk( input_thread_t    *p_input,
1627                                AVIStreamInfo_t   *p_info,
1628                                int   i_ck )
1629 {
1630
1631     p_info->i_idxposc = i_ck;
1632     p_info->i_idxposb = 0;
1633
1634     if(  i_ck < p_info->i_idxnb )
1635     {
1636         return( 1 );
1637     }
1638     else
1639     {
1640         p_info->i_idxposc = p_info->i_idxnb - 1;
1641         do
1642         {
1643             p_info->i_idxposc++;
1644             if( !__AVI_GetChunk( p_input, p_info, 0 ) )
1645             {
1646                 return( 0 );
1647             }
1648         } while( p_info->i_idxposc < i_ck );
1649
1650         return( 1 );
1651     }
1652 }
1653
1654
1655 /* XXX FIXME up to now, we assume that all chunk are one after one */
1656 static int AVI_SetStreamBytes( input_thread_t    *p_input, 
1657                                AVIStreamInfo_t   *p_info,
1658                                off_t   i_byte )
1659 {
1660     if( ( p_info->i_idxnb > 0 )
1661         &&( i_byte < p_info->p_index[p_info->i_idxnb - 1].i_lengthtotal + 
1662                 p_info->p_index[p_info->i_idxnb - 1].i_length ) )
1663     {
1664         /* index is valid to find the ck */
1665         /* uses dichototmie to be fast enougth */
1666         int i_idxposc = __MIN( p_info->i_idxposc, p_info->i_idxnb - 1 );
1667         int i_idxmax  = p_info->i_idxnb;
1668         int i_idxmin  = 0;
1669         for( ;; )
1670         {
1671             if( p_info->p_index[i_idxposc].i_lengthtotal > i_byte )
1672             {
1673                 i_idxmax  = i_idxposc ;
1674                 i_idxposc = ( i_idxmin + i_idxposc ) / 2 ;
1675             }
1676             else
1677             {
1678                 if( p_info->p_index[i_idxposc].i_lengthtotal + 
1679                         p_info->p_index[i_idxposc].i_length <= i_byte)
1680                 {
1681                     i_idxmin  = i_idxposc ;
1682                     i_idxposc = (i_idxmax + i_idxposc ) / 2 ;
1683                 }
1684                 else
1685                 {
1686                     p_info->i_idxposc = i_idxposc;
1687                     p_info->i_idxposb = i_byte - 
1688                             p_info->p_index[i_idxposc].i_lengthtotal;
1689                     return( 1 );
1690                 }
1691             }
1692         }
1693         
1694     }
1695     else
1696     {
1697         p_info->i_idxposc = p_info->i_idxnb - 1;
1698         p_info->i_idxposb = 0;
1699         do
1700         {
1701             p_info->i_idxposc++;
1702             if( !__AVI_GetChunk( p_input, p_info, 0 ) )
1703             {
1704                 return( 0 );
1705             }
1706         } while( p_info->p_index[p_info->i_idxposc].i_lengthtotal +
1707                     p_info->p_index[p_info->i_idxposc].i_length <= i_byte );
1708
1709         p_info->i_idxposb = i_byte -
1710                        p_info->p_index[p_info->i_idxposc].i_lengthtotal;
1711         return( 1 );
1712     }
1713 }
1714
1715 static pes_packet_t *AVI_ReadStreamChunkInPES(  input_thread_t  *p_input,
1716                                                 AVIStreamInfo_t *p_info )
1717
1718 {
1719     if( p_info->i_idxposc > p_info->i_idxnb )
1720     {
1721         return( NULL );
1722     }
1723
1724     /* we want chunk (p_info->i_idxposc,0) */
1725     p_info->i_idxposb = 0;
1726     if( !__AVI_GetChunk( p_input, p_info, 1) )
1727     {
1728         msg_Err( p_input, "Got one chunk : failed" );
1729         return( NULL );
1730     }
1731     p_info->i_idxposc++;
1732     return( AVI_PESBuffer_Get( p_info ) );
1733 }
1734
1735 static pes_packet_t *AVI_ReadStreamBytesInPES(  input_thread_t  *p_input,
1736                                                 AVIStreamInfo_t *p_info,
1737                                                 int i_byte )
1738 {
1739     pes_packet_t    *p_pes;
1740     data_packet_t   *p_data;
1741     int             i_count = 0;
1742     int             i_read;
1743
1744         
1745     if( !( p_pes = input_NewPES( p_input->p_method_data ) ) )
1746     {
1747         return( NULL );
1748     }
1749     if( !( p_data = input_NewPacket( p_input->p_method_data, i_byte ) ) )
1750     {
1751         input_DeletePES( p_input->p_method_data, p_pes );
1752         return( NULL );
1753     }
1754
1755     p_pes->p_first =
1756             p_pes->p_last = p_data;
1757     p_pes->i_nb_data = 1;
1758     p_pes->i_pes_size = i_byte;
1759
1760     while( i_byte > 0 )
1761     {
1762         if( !__AVI_GetChunk( p_input, p_info, 1) )
1763         {
1764          msg_Err( p_input, "Got one chunk : failed" );
1765            
1766             input_DeletePES( p_input->p_method_data, p_pes );
1767             return( NULL );
1768         }
1769
1770         i_read = __MIN( p_info->p_pes_first->p_pes->i_pes_size - 
1771                             ( p_info->i_idxposb - p_info->p_pes_first->i_posb ),
1772                         i_byte);
1773         /* FIXME FIXME FIXME follow all data packet */
1774         memcpy( p_data->p_payload_start + i_count, 
1775                 p_info->p_pes_first->p_pes->p_first->p_payload_start + 
1776                     p_info->i_idxposb - p_info->p_pes_first->i_posb,
1777                 i_read );
1778
1779         AVI_PESBuffer_Drop( p_input->p_method_data, p_info );
1780         i_byte  -= i_read;
1781         i_count += i_read;
1782
1783         p_info->i_idxposb += i_read;
1784         if( p_info->p_index[p_info->i_idxposc].i_length <= p_info->i_idxposb )
1785         {
1786             p_info->i_idxposb -= p_info->p_index[p_info->i_idxposc].i_length;
1787             p_info->i_idxposc++;
1788         }
1789     }
1790    return( p_pes );
1791 }
1792
1793 /*****************************************************************************
1794  * AVI_GetFrameInPES : get dpts length(µs) in pes from stream
1795  *****************************************************************************
1796  * Handle multiple pes, and set pts to the good value 
1797  *****************************************************************************/
1798 static pes_packet_t *AVI_GetFrameInPES( input_thread_t *p_input,
1799                                         AVIStreamInfo_t *p_info,
1800                                         mtime_t i_dpts)
1801 {
1802     int i;
1803     pes_packet_t *p_pes = NULL;
1804     pes_packet_t *p_pes_tmp = NULL;
1805     pes_packet_t *p_pes_first = NULL;
1806     mtime_t i_pts;
1807
1808     if( i_dpts < 1000 ) 
1809     { 
1810         return( NULL ) ; 
1811     }
1812
1813     if( !p_info->i_samplesize )
1814     {
1815         int i_chunk = __MAX( AVI_PTSToChunk( p_info, i_dpts), 1 );
1816         p_pes_first = NULL;
1817         for( i = 0; i < i_chunk; i++ )
1818         {
1819             /* get pts while is valid */
1820             i_pts = AVI_GetPTS( p_info ); 
1821  
1822             p_pes_tmp = AVI_ReadStreamChunkInPES( p_input, p_info );
1823
1824             if( !p_pes_tmp )
1825             {
1826                 return( p_pes_first );
1827             }
1828             p_pes_tmp->i_pts = i_pts;
1829             if( !p_pes_first )
1830             {
1831                 p_pes_first = p_pes_tmp;
1832             }
1833             else
1834             {
1835                 p_pes->p_next = p_pes_tmp;
1836             }
1837             p_pes = p_pes_tmp;
1838         }
1839         return( p_pes_first );
1840     }
1841     else
1842     {
1843         /* stream is byte based */
1844         int i_byte = AVI_PTSToByte( p_info, i_dpts);
1845         if( i_byte < 50 ) /* to avoid some problem with audio */
1846         {
1847             return( NULL );
1848         }
1849         i_pts = AVI_GetPTS( p_info );  /* ok even with broken index */
1850         p_pes = AVI_ReadStreamBytesInPES( p_input, p_info, i_byte);
1851
1852         if( p_pes )
1853         {
1854             p_pes->i_pts = i_pts;
1855         }
1856         return( p_pes );
1857     }
1858 }
1859 /*****************************************************************************
1860  * AVI_DecodePES : send a pes to decoder 
1861  *****************************************************************************
1862  * Handle multiple pes, and update pts to the good value 
1863  *****************************************************************************/
1864 static inline void AVI_DecodePES( input_thread_t *p_input,
1865                                   AVIStreamInfo_t *p_info,
1866                                   pes_packet_t *p_pes )
1867 {
1868     pes_packet_t    *p_pes_next;
1869     /* input_decode want only one pes, but AVI_GetFrameInPES give
1870           multiple pes so send one by one */
1871     while( p_pes )
1872     {
1873         p_pes_next = p_pes->p_next;
1874         p_pes->p_next = NULL;
1875         p_pes->i_pts = input_ClockGetTS( p_input, 
1876                                          p_input->stream.p_selected_program, 
1877                                          p_pes->i_pts * 9/100);
1878         input_DecodePES( p_info->p_es->p_decoder_fifo, p_pes );
1879         p_pes = p_pes_next;
1880     }
1881   
1882 }
1883
1884 static int AVI_StreamSeek( input_thread_t *p_input,
1885                            demux_sys_t  *p_avi,
1886                            int i_stream, 
1887                            mtime_t i_date )
1888 {
1889 #define p_stream    p_avi->pp_info[i_stream]
1890     mtime_t i_oldpts;
1891     
1892     AVI_PESBuffer_Flush( p_input->p_method_data, p_stream );
1893     i_oldpts = AVI_GetPTS( p_stream );
1894
1895     if( !p_stream->i_samplesize )
1896     {
1897         AVI_SetStreamChunk( p_input,
1898                             p_stream, 
1899                             AVI_PTSToChunk( p_stream, i_date ) );
1900         /* search key frame */
1901         msg_Dbg( p_input, 
1902                  "old:%lld %s new %lld",
1903                  i_oldpts, 
1904                  i_oldpts > i_date ? ">" : "<",
1905                  i_date );
1906
1907         if( i_date < i_oldpts )
1908         {
1909             while( p_stream->i_idxposc > 0 && 
1910                !( p_stream->p_index[p_stream->i_idxposc].i_flags & 
1911                                                             AVIIF_KEYFRAME ) )
1912             {
1913                 if( !AVI_SetStreamChunk( p_input,
1914                                          p_stream,
1915                                          p_stream->i_idxposc - 1 ) )
1916                 {
1917                     return( 0 );
1918                 }
1919             }
1920         }
1921         else
1922         {
1923             while( !( p_stream->p_index[p_stream->i_idxposc].i_flags &
1924                                                             AVIIF_KEYFRAME ) )
1925             {
1926                 if( !AVI_SetStreamChunk( p_input, 
1927                                          p_stream, 
1928                                          p_stream->i_idxposc + 1 ) )
1929                 {
1930                     return( 0 );
1931                 }
1932             }
1933         }
1934     }
1935     else
1936     {
1937         AVI_SetStreamBytes( p_input,
1938                             p_stream,
1939                             AVI_PTSToByte( p_stream, i_date ) );
1940     }
1941     return( 1 );
1942 #undef p_stream
1943 }
1944
1945 /*****************************************************************************
1946  * AVISeek: goto to i_date or i_percent
1947  *****************************************************************************
1948  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
1949  *****************************************************************************/
1950 static int    AVISeek   ( input_thread_t *p_input, 
1951                           mtime_t i_date, int i_percent )
1952 {
1953
1954     demux_sys_t *p_avi = p_input->p_demux_data;
1955     int         i_stream;
1956     msg_Dbg( p_input, 
1957              "seek requested: %lld secondes %d%%", 
1958              i_date / 1000000,
1959              i_percent );
1960
1961     if( p_avi->b_seekable )
1962     {
1963         if( !p_avi->i_length )
1964         {
1965             int i_index;
1966             AVIStreamInfo_t *p_stream;
1967             u64 i_pos;
1968
1969             /* use i_percent to create a true i_date */
1970             msg_Warn( p_input, 
1971                       "mmh, seeking without index at %d%%"
1972                       " work only for interleaved file", i_percent );
1973
1974             if( i_percent >= 100 )
1975             {
1976                 msg_Err( p_input, "cannot seek so far !" );
1977                 return( -1 );
1978             }
1979             i_percent = __MAX( i_percent, 0 );
1980             
1981             /* try to find chunk that is at i_percent or the file */
1982             i_pos = __MAX( i_percent * 
1983                            p_input->stream.p_selected_area->i_size / 100,
1984                            p_avi->p_movi->i_pos );
1985             /* search first selected stream */
1986             for( i_index = 0,p_stream = NULL; 
1987                  i_index < p_avi->i_streams; i_stream++ )
1988             {
1989                 p_stream = p_avi->pp_info[i_index];
1990                 if( p_stream->i_activated )
1991                 {
1992                     break;
1993                 }
1994             }
1995             if( !p_stream || !p_stream->p_index )
1996             {
1997                 msg_Err( p_input, "cannot find any selected stream" );
1998                 return( -1 );
1999             }
2000             /* search chunk */
2001             p_stream->i_idxposc =  __MAX( p_stream->i_idxposc - 1, 0 );
2002             while( ( i_pos < p_stream->p_index[p_stream->i_idxposc].i_pos )
2003                    &&( p_stream->i_idxposc > 0 ) )
2004             {
2005                 /* search before i_idxposc */
2006                 if( !AVI_SetStreamChunk( p_input, 
2007                                          p_stream, p_stream->i_idxposc - 1 ) )
2008                 {
2009                     msg_Err( p_input, "cannot seek" );
2010                     return( -1 );
2011                 }
2012             }
2013             while( i_pos >= p_stream->p_index[p_stream->i_idxposc].i_pos +
2014                p_stream->p_index[p_stream->i_idxposc].i_length + 8 )
2015             {
2016                 /* search after i_idxposc */
2017                 if( !AVI_SetStreamChunk( p_input, 
2018                                          p_stream, p_stream->i_idxposc + 1 ) )
2019                 {
2020                     msg_Err( p_input, "cannot seek" );
2021                     return( -1 );
2022                 }
2023             }
2024             i_date = AVI_GetPTS( p_stream );
2025             /* TODO better support for i_samplesize != 0 */
2026             msg_Dbg( p_input, "estimate date %lld", i_date );
2027         }
2028
2029 #define p_stream    p_avi->pp_info[i_stream]
2030         p_avi->i_time = 0;
2031         /* seek for chunk based streams */
2032         for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
2033         {
2034             if( p_stream->i_activated && !p_stream->i_samplesize )
2035 //            if( p_stream->i_activated )
2036             {
2037                 AVI_StreamSeek( p_input, p_avi, i_stream, i_date );
2038                 p_avi->i_time = __MAX( AVI_GetPTS( p_stream ), 
2039                                         p_avi->i_time );
2040             }
2041         }
2042 #if 1
2043         if( p_avi->i_time )
2044         {
2045             i_date = p_avi->i_time;
2046         }
2047         /* seek for bytes based streams */
2048         for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
2049         {
2050             if( p_stream->i_activated && p_stream->i_samplesize )
2051             {
2052                 AVI_StreamSeek( p_input, p_avi, i_stream, i_date );
2053 //                p_avi->i_time = __MAX( AVI_GetPTS( p_stream ), p_avi->i_time );
2054             }
2055         }
2056         msg_Dbg( p_input, "seek: %lld secondes", p_avi->i_time /1000000 );
2057         /* set true movie time */
2058 #endif
2059         if( !p_avi->i_time )
2060         {
2061             p_avi->i_time = i_date;
2062         }
2063 #undef p_stream
2064         return( 1 );
2065     }
2066     else
2067     {
2068         msg_Err( p_input, "shouldn't yet be executed" );
2069         return( -1 );
2070     }
2071 }
2072
2073 /*****************************************************************************
2074  * AVIDemux_Seekable: reads and demuxes data packets for stream seekable
2075  *****************************************************************************
2076  * AVIDemux: reads and demuxes data packets
2077  *****************************************************************************
2078  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
2079  * TODO add support for unstreable file, just read a chunk and send it 
2080  *      to the right decoder, very easy
2081  *****************************************************************************/
2082
2083 static int AVIDemux_Seekable( input_thread_t *p_input )
2084 {
2085     int i;
2086     int i_stream;
2087     int b_stream;
2088
2089     demux_sys_t *p_avi = p_input->p_demux_data;
2090
2091     /* detect new selected/unselected streams */
2092     for( i_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
2093     {
2094 #define p_stream    p_avi->pp_info[i_stream]
2095         if( p_stream->p_es )
2096         {
2097             if( p_stream->p_es->p_decoder_fifo &&
2098                 !p_stream->i_activated )
2099             {
2100                 AVI_StreamStart( p_input, p_avi, i_stream );
2101             }
2102             else
2103             if( !p_stream->p_es->p_decoder_fifo &&
2104                 p_stream->i_activated )
2105             {
2106                 AVI_StreamStop( p_input, p_avi, i_stream );
2107             }
2108         }       
2109 #undef  p_stream
2110     }
2111     /* search new video and audio stream selected 
2112           if current have been unselected*/
2113     if( ( !p_avi->p_info_video )
2114             || ( !p_avi->p_info_video->p_es->p_decoder_fifo ) )
2115     {
2116         p_avi->p_info_video = NULL;
2117         for( i = 0; i < p_avi->i_streams; i++ )
2118         {
2119             if( ( p_avi->pp_info[i]->i_cat == VIDEO_ES )
2120                   &&( p_avi->pp_info[i]->p_es->p_decoder_fifo ) )
2121             {
2122                 p_avi->p_info_video = p_avi->pp_info[i];
2123                 break;
2124             }
2125         }
2126     }
2127     if( ( !p_avi->p_info_audio )
2128             ||( !p_avi->p_info_audio->p_es->p_decoder_fifo ) )
2129     {
2130         p_avi->p_info_audio = NULL;
2131         for( i = 0; i < p_avi->i_streams; i++ )
2132         {
2133             if( ( p_avi->pp_info[i]->i_cat == AUDIO_ES )
2134                   &&( p_avi->pp_info[i]->p_es->p_decoder_fifo ) )
2135             {
2136                 p_avi->p_info_audio = p_avi->pp_info[i];
2137                 break;
2138             }
2139         }
2140     }
2141
2142     if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
2143     {
2144         mtime_t i_date;
2145         int i_percent;
2146         /* first wait for empty buffer, arbitrary time FIXME */
2147         msleep( DEFAULT_PTS_DELAY );
2148
2149         i_date = (mtime_t)1000000 *
2150                  (mtime_t)p_avi->i_length *
2151                  (mtime_t)AVI_TellAbsolute( p_input ) /
2152                  (mtime_t)p_input->stream.p_selected_area->i_size;
2153         i_percent = 100 * AVI_TellAbsolute( p_input ) / 
2154                         p_input->stream.p_selected_area->i_size;
2155         AVISeek( p_input, i_date, i_percent);
2156 //        input_ClockInit( p_input->stream.p_selected_program );
2157     }
2158     /* wait for the good time */
2159     input_ClockManageRef( p_input,
2160                           p_input->stream.p_selected_program,
2161                           p_avi->i_pcr ); 
2162
2163     p_avi->i_pcr = p_avi->i_time * 9 / 100;
2164     p_avi->i_time += 100*1000;  /* read 100ms */
2165     
2166     for( i_stream = 0, b_stream = 0; i_stream < p_avi->i_streams; i_stream++ )
2167     {
2168 #define p_stream    p_avi->pp_info[i_stream]
2169         pes_packet_t    *p_pes;
2170
2171         if( !p_stream->p_es ||
2172             !p_stream->p_es->p_decoder_fifo )
2173         {
2174
2175             continue;
2176         }
2177         if( p_avi->i_time <= AVI_GetPTS( p_stream  ) )
2178         {
2179             msg_Warn( p_input, "skeeping stream %d", i_stream );
2180             b_stream = 1;
2181             continue;
2182         }
2183         p_pes = AVI_GetFrameInPES( p_input,
2184                                    p_stream,
2185                                    p_avi->i_time - AVI_GetPTS( p_stream  ) ); 
2186         if( p_pes )
2187         {
2188             AVI_DecodePES( p_input, p_stream, p_pes );
2189             b_stream = 1;
2190         }
2191 #undef p_stream
2192     }
2193
2194     /* at the end ? */
2195     return( b_stream ? 1 : 0 );
2196
2197 }
2198
2199
2200 /*****************************************************************************
2201  * AVIDemux_UnSeekable: reads and demuxes data packets for unseekable
2202  *                       file
2203  *****************************************************************************
2204  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
2205  *****************************************************************************/
2206 static int AVIDemux_UnSeekable( input_thread_t *p_input )
2207 {
2208     demux_sys_t     *p_avi = p_input->p_demux_data;
2209     AVIStreamInfo_t *p_stream_master;
2210     int     i_stream;
2211     int     b_audio;
2212     int     i_packet;
2213
2214     /* *** send audio data to decoder only if rate == DEFAULT_RATE *** */
2215     vlc_mutex_lock( &p_input->stream.stream_lock );
2216     b_audio = p_input->stream.control.i_rate == DEFAULT_RATE;
2217     vlc_mutex_unlock( &p_input->stream.stream_lock );    
2218
2219     input_ClockManageRef( p_input,
2220                           p_input->stream.p_selected_program,
2221                           p_avi->i_pcr );
2222     /* *** find master stream for data packet skipping algo *** */
2223     /* *** -> first video, if any, or first audio ES *** */
2224     for( i_stream = 0, p_stream_master = NULL; 
2225             i_stream < p_avi->i_streams; i_stream++ )
2226     {
2227 #define p_stream    p_avi->pp_info[i_stream]
2228         if( p_stream->p_es &&
2229             p_stream->p_es->p_decoder_fifo )
2230         {
2231             if( p_stream->i_cat == VIDEO_ES )
2232             {
2233                 p_stream_master = p_stream;
2234                 break;
2235             }
2236             if( p_stream->i_cat == AUDIO_ES && !p_stream_master )
2237             {
2238                 p_stream_master = p_stream;
2239             }
2240         }
2241 #undef p_stream
2242     }
2243     if( !p_stream_master )
2244     {
2245         msg_Err( p_input, "no more stream selected" );
2246         return( 0 );
2247     }
2248
2249     p_avi->i_pcr = AVI_GetPTS( p_stream_master ) * 9 / 100;
2250     
2251     for( i_packet = 0; i_packet < 10; i_packet++)
2252     {
2253 #define p_stream    p_avi->pp_info[avi_pk.i_stream]
2254
2255         avi_packet_t    avi_pk;
2256
2257         if( !AVI_PacketGetHeader( p_input, &avi_pk ) )
2258         {
2259             return( 0 );
2260         }
2261 //        AVI_ParseStreamHeader( avi_pk.i_fourcc, &i_stream, &i_cat );
2262
2263         if( avi_pk.i_stream >= p_avi->i_streams ||
2264             ( avi_pk.i_cat != AUDIO_ES && avi_pk.i_cat != VIDEO_ES ) )
2265         {
2266             /* we haven't found an audio or video packet:
2267                 - we have seek, found first next packet
2268                 - others packets could be found, skip them
2269             */
2270             switch( avi_pk.i_fourcc )
2271             {
2272                 case AVIFOURCC_JUNK:
2273                 case AVIFOURCC_LIST:
2274                     return( AVI_PacketNext( p_input ) ? 1 : 0 );
2275                 case AVIFOURCC_idx1:
2276                     return( 0 );    // eof
2277                 default:
2278                     msg_Warn( p_input, 
2279                               "seems to have lost position, resync" );
2280                     if( !AVI_PacketSearch( p_input ) )
2281                     {
2282                         msg_Err( p_input, "resync failed" );
2283                         return( -1 );
2284                     }
2285             }
2286         }
2287         else
2288         {  
2289             /* do will send this packet to decoder ? */
2290             if( ( !b_audio && avi_pk.i_cat == AUDIO_ES )||
2291                 !p_stream->p_es ||
2292                 !p_stream->p_es->p_decoder_fifo )
2293             {
2294                 if( !AVI_PacketNext( p_input ) )
2295                 {
2296                     return( 0 );
2297                 }
2298             }
2299             else
2300             {
2301                 /* it's a selected stream, check for time */
2302                 if( __ABS( AVI_GetPTS( p_stream ) - 
2303                             AVI_GetPTS( p_stream_master ) )< 600*1000 )
2304                 {
2305                     /* load it and send to decoder */
2306                     pes_packet_t    *p_pes;
2307                     if( !AVI_PacketRead( p_input, &avi_pk, &p_pes ) || !p_pes)
2308                     {
2309                         return( -1 );
2310                     }
2311                     p_pes->i_pts = AVI_GetPTS( p_stream );
2312                     AVI_DecodePES( p_input, p_stream, p_pes );
2313                 }
2314                 else
2315                 {
2316                     if( !AVI_PacketNext( p_input ) )
2317                     {
2318                         return( 0 );
2319                     }
2320                 }
2321             }
2322
2323             /* *** update stream time position *** */
2324             if( p_stream->i_samplesize )
2325             {
2326                 p_stream->i_idxposb += avi_pk.i_size;
2327             }
2328             else
2329             {
2330                 p_stream->i_idxposc++;
2331             }
2332
2333         }
2334
2335 #undef p_stream     
2336     }
2337
2338     return( 1 );
2339 }
2340