]> git.sesse.net Git - vlc/blob - plugins/avi/avi.c
* ./src/misc/modules_plugin.h: exported input_ClockManageRef for fenrir.
[vlc] / plugins / 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.4 2002/04/25 21:52:42 sam 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 <videolan/vlc.h>
32
33 #include "stream_control.h"
34 #include "input_ext-intf.h"
35 #include "input_ext-dec.h"
36 #include "input_ext-plugins.h"
37
38 #include "video.h"
39
40 /*****************************************************************************
41  * Constants
42  *****************************************************************************/
43
44 /*****************************************************************************
45  * Local prototypes
46  *****************************************************************************/
47 static void input_getfunctions( function_list_t * p_function_list );
48 static int  AVIDemux         ( struct input_thread_s * );
49 static int  AVIInit          ( struct input_thread_s * );
50 static void AVIEnd           ( struct input_thread_s * );
51
52 /*****************************************************************************
53  * Build configuration tree.
54  *****************************************************************************/
55 MODULE_CONFIG_START
56 MODULE_CONFIG_STOP
57
58 MODULE_INIT_START
59     SET_DESCRIPTION( "RIFF-AVI Stream input" )
60     ADD_CAPABILITY( DEMUX, 150 )
61     ADD_SHORTCUT( "avi" )
62 MODULE_INIT_STOP
63
64 MODULE_ACTIVATE_START
65     input_getfunctions( &p_module->p_functions->demux );
66 MODULE_ACTIVATE_STOP
67
68 MODULE_DEACTIVATE_START
69 MODULE_DEACTIVATE_STOP
70
71 /*****************************************************************************
72  * Definition of structures and libraries for this plugins 
73  *****************************************************************************/
74 #include "libLE.c"
75 #include "libioRIFF.c"
76 #include "avi.h"
77
78 /*****************************************************************************
79  * Functions exported as capabilities. They are declared as static so that
80  * we don't pollute the namespace too much.
81  *****************************************************************************/
82 static void input_getfunctions( function_list_t * p_function_list )
83 {
84 #define input p_function_list->functions.demux
85     input.pf_init             = AVIInit;
86     input.pf_end              = AVIEnd;
87     input.pf_demux            = AVIDemux;
88     input.pf_rewind           = NULL;
89 #undef input
90 }
91
92 /********************************************************************/
93
94
95 static void __AVIFreeDemuxData( input_thread_t *p_input )
96 {
97     int i;
98     demux_data_avi_file_t *p_avi_demux;
99     p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data  ; 
100     
101     if( p_avi_demux->p_riff != NULL ) 
102             RIFF_DeleteChunk( p_input->p_demux_data, p_avi_demux->p_riff );
103     if( p_avi_demux->p_hdrl != NULL ) 
104             RIFF_DeleteChunk( p_input->p_demux_data, p_avi_demux->p_hdrl );
105     if( p_avi_demux->p_movi != NULL ) 
106             RIFF_DeleteChunk( p_input->p_demux_data, p_avi_demux->p_movi );
107     if( p_avi_demux->p_idx1 != NULL ) 
108             RIFF_DeleteChunk( p_input->p_demux_data, p_avi_demux->p_idx1 );
109     if( p_avi_demux->pp_info != NULL )
110     {
111         for( i = 0; i < p_avi_demux->i_streams; i++ )
112         {
113             if( p_avi_demux->pp_info[i] != NULL ) 
114             {
115 #define p_info p_avi_demux->pp_info[i]
116 /* don't uses RIFF_DeleteChunk -> it will segfault here ( probably because of
117     data_packey already unallocated ? */
118                 if( p_info->p_strl != NULL ) 
119                 {
120                     free( p_info->p_strl );
121                 }
122                 if( p_info->p_strh != NULL )
123                 {
124                    free( p_info->p_strh );
125                 }
126                 
127                 if( p_info->p_strf != NULL ) 
128                 {
129                     free( p_info->p_strf );
130                 }
131                 if( p_info->p_strd != NULL )
132                 {
133                    free( p_info->p_strd );
134                 }
135                 if( p_info->p_index != NULL )
136                 {
137                       free( p_info->p_index );
138                 }
139                 free( p_info ); 
140 #undef  p_info
141             }
142         }
143          free( p_avi_demux->pp_info );
144     }
145 }
146
147 static void __AVI_Parse_avih( MainAVIHeader_t *p_avih, byte_t *p_buff )
148 {
149     p_avih->i_microsecperframe = __GetDoubleWordLittleEndianFromBuff( p_buff );
150     p_avih->i_maxbytespersec = __GetDoubleWordLittleEndianFromBuff( p_buff + 4);
151     p_avih->i_reserved1 = __GetDoubleWordLittleEndianFromBuff( p_buff + 8);
152     p_avih->i_flags = __GetDoubleWordLittleEndianFromBuff( p_buff + 12);
153     p_avih->i_totalframes = __GetDoubleWordLittleEndianFromBuff( p_buff + 16);
154     p_avih->i_initialframes = __GetDoubleWordLittleEndianFromBuff( p_buff + 20);
155     p_avih->i_streams = __GetDoubleWordLittleEndianFromBuff( p_buff + 24);
156     p_avih->i_suggestedbuffersize = 
157                         __GetDoubleWordLittleEndianFromBuff( p_buff + 28);
158     p_avih->i_width = __GetDoubleWordLittleEndianFromBuff( p_buff + 32 );
159     p_avih->i_height = __GetDoubleWordLittleEndianFromBuff( p_buff + 36 );
160     p_avih->i_scale = __GetDoubleWordLittleEndianFromBuff( p_buff + 40 );
161     p_avih->i_rate = __GetDoubleWordLittleEndianFromBuff( p_buff + 44 );
162     p_avih->i_start = __GetDoubleWordLittleEndianFromBuff( p_buff + 48);
163     p_avih->i_length = __GetDoubleWordLittleEndianFromBuff( p_buff + 52);
164 }
165
166 static void __AVI_Parse_Header( AVIStreamHeader_t *p_strh, byte_t *p_buff )
167 {
168     p_strh->i_type = __GetDoubleWordLittleEndianFromBuff( p_buff );
169     p_strh->i_handler = __GetDoubleWordLittleEndianFromBuff( p_buff + 4 );
170     p_strh->i_flags = __GetDoubleWordLittleEndianFromBuff( p_buff + 8 );
171     p_strh->i_reserved1 = __GetDoubleWordLittleEndianFromBuff( p_buff + 12);
172     p_strh->i_initialframes = __GetDoubleWordLittleEndianFromBuff( p_buff + 16);
173     p_strh->i_scale = __GetDoubleWordLittleEndianFromBuff( p_buff + 20);
174     p_strh->i_rate = __GetDoubleWordLittleEndianFromBuff( p_buff + 24);
175     p_strh->i_start = __GetDoubleWordLittleEndianFromBuff( p_buff + 28);
176     p_strh->i_length = __GetDoubleWordLittleEndianFromBuff( p_buff + 32);
177     p_strh->i_suggestedbuffersize = 
178                         __GetDoubleWordLittleEndianFromBuff( p_buff + 36);
179     p_strh->i_quality = __GetDoubleWordLittleEndianFromBuff( p_buff + 40);
180     p_strh->i_samplesize = __GetDoubleWordLittleEndianFromBuff( p_buff + 44);
181 }
182
183 int avi_ParseBitMapInfoHeader( bitmapinfoheader_t *h, byte_t *p_data )
184 {
185     h->i_size          = __GetDoubleWordLittleEndianFromBuff( p_data );
186     h->i_width         = __GetDoubleWordLittleEndianFromBuff( p_data + 4 );
187     h->i_height        = __GetDoubleWordLittleEndianFromBuff( p_data + 8 );
188     h->i_planes        = __GetWordLittleEndianFromBuff( p_data + 12 );
189     h->i_bitcount      = __GetWordLittleEndianFromBuff( p_data + 14 );
190     h->i_compression   = __GetDoubleWordLittleEndianFromBuff( p_data + 16 );
191     h->i_sizeimage     = __GetDoubleWordLittleEndianFromBuff( p_data + 20 );
192     h->i_xpelspermeter = __GetDoubleWordLittleEndianFromBuff( p_data + 24 );
193     h->i_ypelspermeter = __GetDoubleWordLittleEndianFromBuff( p_data + 28 );
194     h->i_clrused       = __GetDoubleWordLittleEndianFromBuff( p_data + 32 );
195     h->i_clrimportant  = __GetDoubleWordLittleEndianFromBuff( p_data + 36 );
196     return( 0 );
197 }
198
199 int avi_ParseWaveFormatEx( waveformatex_t *h, byte_t *p_data )
200 {
201     h->i_formattag     = __GetWordLittleEndianFromBuff( p_data );
202     h->i_channels      = __GetWordLittleEndianFromBuff( p_data + 2 );
203     h->i_samplespersec = __GetDoubleWordLittleEndianFromBuff( p_data + 4 );
204     h->i_avgbytespersec= __GetDoubleWordLittleEndianFromBuff( p_data + 8 );
205     h->i_blockalign    = __GetWordLittleEndianFromBuff( p_data + 12 );
206     h->i_bitspersample = __GetWordLittleEndianFromBuff( p_data + 14 );
207     h->i_size          = __GetWordLittleEndianFromBuff( p_data + 16 );
208     return( 0 );
209 }
210
211 static int __AVI_ParseStreamHeader( u32 i_id, int *i_number, u16 *i_type )
212 {
213     int c1,c2,c3,c4;
214
215     c1 = ( i_id ) & 0xFF;
216     c2 = ( i_id >>  8 ) & 0xFF;
217     c3 = ( i_id >> 16 ) & 0xFF;
218     c4 = ( i_id >> 24 ) & 0xFF;
219
220     if( c1 < '0' || c1 > '9' || c2 < '0' || c2 > '9' )
221     {
222         return( -1 );
223     }
224     *i_number = (c1 - '0') * 10 + (c2 - '0' );
225     *i_type = ( c3 << 8) + c4;
226     return( 0 );
227 }   
228 /*
229 static int __AVI_HeaderMoviValid( u32 i_header )
230 {
231     switch( i_header&0xFFFF0000 )
232     {
233         case( TWOCC_wb ):
234         case( TWOCC_db ):
235         case( TWOCC_dc ):
236         case( TWOCC_pc ):
237             return( 1 );
238             break;
239     }
240     switch( i_header )
241     {
242         case( FOURCC_LIST ):
243         case( FOURCC_JUNK ):
244             return( 1 );
245             break;
246     }
247     return( 0 );
248 }
249 */
250 static void __AVI_AddEntryIndex( AVIStreamInfo_t *p_info,
251                                  AVIIndexEntry_t *p_index)
252 {
253     if( p_info->p_index == NULL )
254     {
255         p_info->i_idxmax = 4096;
256         p_info->i_idxnb = 0;
257         p_info->p_index = calloc( p_info->i_idxmax, 
258                                   sizeof( AVIIndexEntry_t ) );
259     }
260     if( p_info->i_idxnb >= p_info->i_idxmax )
261     {
262         p_info->i_idxmax += 4096;
263         p_info->p_index = realloc( (void*)p_info->p_index,
264                                     p_info->i_idxmax * 
265                                     sizeof( AVIIndexEntry_t ) );
266     }
267     /* calculate cumulate length */
268     if( p_info->i_idxnb > 0 )
269     {
270         p_index->i_lengthtotal = p_index->i_length +
271             p_info->p_index[p_info->i_idxnb-1].i_lengthtotal;
272     }
273     else
274     {
275         p_index->i_lengthtotal = 0;
276     }
277
278     p_info->p_index[p_info->i_idxnb] = *p_index;
279     p_info->i_idxnb++;
280 }
281
282 static void __AVI_GetIndex( input_thread_t *p_input )
283 {
284     demux_data_avi_file_t *p_avi_demux;
285     AVIIndexEntry_t index;
286     byte_t          *p_buff;
287     riffchunk_t     *p_idx1;
288     int             i_read;
289     int             i;
290     int             i_number;
291     u16             i_type;
292     
293     p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data  ;    
294
295     if( RIFF_FindAndGotoDataChunk( p_input,
296                                    p_avi_demux->p_riff, 
297                                    &p_idx1, 
298                                    FOURCC_idx1)!=0 )
299     {
300         intf_WarnMsg( 1, "input init: cannot find index" );
301         RIFF_GoToChunk( p_input, p_avi_demux->p_hdrl );        
302         return;
303     }
304     p_avi_demux->p_idx1 = p_idx1;
305     intf_WarnMsg( 1, "input init: loading index" ); 
306     for(;;)
307     {
308         if( (i_read = input_Peek( p_input, &p_buff, 16*1024 )) < 16 )
309         {
310             for( i = 0, i_read = 0; i < p_avi_demux->i_streams; i++ )
311             {
312                 i_read += p_avi_demux->pp_info[i]->i_idxnb;
313             }
314             intf_WarnMsg( 1,"input info: read %d idx chunk", i_read );
315             return;
316         }
317         i_read /= 16 ;
318         /* TODO try to verify if we are beyond end of p_idx1 */
319         for( i = 0; i < i_read; i++ )
320         {
321             byte_t  *p_peek = p_buff + i * 16;
322             index.i_id = __GetDoubleWordLittleEndianFromBuff( p_peek );
323             index.i_flags = __GetDoubleWordLittleEndianFromBuff( p_peek+4);
324             index.i_offset = __GetDoubleWordLittleEndianFromBuff( p_peek+8);
325             index.i_length = __GetDoubleWordLittleEndianFromBuff(p_peek+12);
326             
327             if( (__AVI_ParseStreamHeader( index.i_id, &i_number, &i_type ) != 0)
328              ||(i_number > p_avi_demux->i_streams)) 
329             {
330                 continue;
331             }
332             __AVI_AddEntryIndex( p_avi_demux->pp_info[i_number],
333                                  &index );
334         }
335         __RIFF_SkipBytes( p_input, 16 * i_read );
336     }
337
338 }
339 static int __AVI_SeekToChunk( input_thread_t *p_input, AVIStreamInfo_t *p_info )
340 {
341     demux_data_avi_file_t *p_avi_demux;
342     p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
343     
344     if( (p_info->p_index != NULL)&&(p_info->i_idxpos < p_info->i_idxnb) )
345     {
346         /* perfect */
347         off_t i_pos;
348         i_pos = (off_t)p_info->p_index[p_info->i_idxpos].i_offset +
349                     p_info->i_idxoffset;
350
351         p_input->pf_seek( p_input, i_pos );
352         input_AccessReinit( p_input );
353         return( 0 );
354     }
355     /* index are no longer valid */
356     if( p_info->p_index != NULL )
357     {
358         return( -1 );
359     }
360     /* no index */
361     return( -1 );
362 }
363
364
365 /* XXX call after get p_movi */
366 static int __AVI_GetIndexOffset( input_thread_t *p_input )
367 {
368     riffchunk_t *p_chunk;
369     demux_data_avi_file_t *p_avi_demux;
370     int i;
371
372     p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
373     for( i = 0; i < p_avi_demux->i_streams; i++ )
374     {
375 #define p_info p_avi_demux->pp_info[i]
376         if( p_info->p_index == NULL ) {continue;}
377         p_info->i_idxoffset = 0;
378         __AVI_SeekToChunk( p_input, p_info );
379         p_chunk = RIFF_ReadChunk( p_input );
380         if( (p_chunk == NULL)||(p_chunk->i_id != p_info->p_index[0].i_id) )
381         {
382             p_info->i_idxoffset = p_avi_demux->p_movi->i_pos + 8;
383             __AVI_SeekToChunk( p_input, p_info );
384             p_chunk = RIFF_ReadChunk( p_input );
385             if( (p_chunk == NULL)||(p_chunk->i_id != p_info->p_index[0].i_id) )
386             {
387                 intf_WarnMsg( 1, "input demux: can't find offset for stream %d",
388                                 i);
389                 continue; /* TODO: search manually from p_movi */
390             }
391         }
392 #undef p_info
393     }
394     return( 0 );
395 }
396 static int __AVI_AudioGetType( u32 i_type )
397 {
398     switch( i_type )
399     {
400 /*        case( WAVE_FORMAT_PCM ):
401             return( WAVE_AUDIO_ES ); */
402         case( WAVE_FORMAT_AC3 ):
403             return( AC3_AUDIO_ES );
404         case( WAVE_FORMAT_MPEG):
405         case( WAVE_FORMAT_MPEGLAYER3):
406             return( MPEG2_AUDIO_ES ); /* 2 for mpeg-2 layer 1 2 ou 3 */
407         default:
408             return( 0 );
409     }
410 }
411
412 static int __AVI_VideoGetType( u32 i_type )
413 {
414     switch( i_type )
415     {
416         case( FOURCC_DIV3 ):
417         case( FOURCC_div3 ):
418         case( FOURCC_DIV4 ):
419         case( FOURCC_div4 ):
420         case( FOURCC_DIV5 ):
421         case( FOURCC_div5 ):
422         case( FOURCC_DIV6 ):
423         case( FOURCC_div6 ):
424         case( FOURCC_3IV1 ):
425         case( FOURCC_AP41 ):
426         case( FOURCC_MP43 ):
427         case( FOURCC_mp43 ):
428             return( MSMPEG4_VIDEO_ES );
429
430         case( FOURCC_DIVX ):
431         case( FOURCC_divx ):
432         case( FOURCC_DX50 ):
433         case( FOURCC_MP4S ):
434         case( FOURCC_MPG4 ):
435         case( FOURCC_mpg4 ):
436         case( FOURCC_mp4v ):
437             return( MPEG4_VIDEO_ES );
438
439         default:
440             return( 0 );
441     }
442 }
443 /**************************************************************************/
444
445 /* Tention: bcp de test à ajouter mais aussi beaucoup de MEMOIRE a DESALLOUER pas fait */
446 static int AVIInit( input_thread_t *p_input )
447 {
448     riffchunk_t *p_riff,*p_hdrl,*p_movi;
449     riffchunk_t *p_avih;
450     riffchunk_t *p_strl,*p_strh,*p_strf/* ,*p_strd */;
451     
452     demux_data_avi_file_t *p_avi_demux;
453     es_descriptor_t *p_es = NULL; /* for not warning */
454     es_descriptor_t *p_es_video = NULL; 
455     es_descriptor_t *p_es_audio = NULL;
456
457     int i;
458     
459     p_avi_demux = malloc( sizeof(demux_data_avi_file_t) );
460     memset( p_avi_demux, 0, sizeof( demux_data_avi_file_t ) );
461     p_input->p_demux_data = p_avi_demux;
462
463     /* FIXME FIXME Je sais pas trop a quoi ca sert juste copié de ESInit */
464     /* Initialize access plug-in structures. */
465     if( p_input->i_mtu == 0 )
466     {
467         /* Improve speed. */
468         p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
469     }
470
471     if( RIFF_TestFileHeader( p_input, &p_riff, FOURCC_AVI ) != 0 )    
472     {
473         __AVIFreeDemuxData( p_input );
474         intf_ErrMsg( "input: RIFF-AVI plug-in discarded (avi_file)" );
475         return( -1 );
476     }
477     p_avi_demux->p_riff = p_riff;
478
479     if ( RIFF_DescendChunk(p_input) != 0 )
480     {
481         __AVIFreeDemuxData( p_input );
482         intf_ErrMsg( "input error: cannot look for subchunk (avi_file)" );
483         return ( -1 );
484     }
485
486     /* it's a riff-avi file, so search for LIST-hdrl */
487     if( RIFF_FindListChunk(p_input ,&p_hdrl,p_riff, FOURCC_hdrl) != 0 )
488     {
489         __AVIFreeDemuxData( p_input );
490         intf_ErrMsg( "input error: cannot find \"LIST-hdrl\" (avi_file)" );
491         return( -1 );
492     }
493     p_avi_demux->p_hdrl = p_hdrl;
494
495     if( RIFF_DescendChunk(p_input) != 0 )
496     {
497         __AVIFreeDemuxData( p_input );
498         intf_ErrMsg( "input error: cannot look for subchunk (avi_file)" );
499         return ( -1 );
500     }
501     /* ds  LIST-hdrl cherche avih */
502     if( RIFF_FindAndLoadChunk( p_input, p_hdrl, 
503                                     &p_avih, FOURCC_avih ) != 0 )
504     {
505         __AVIFreeDemuxData( p_input );
506         intf_ErrMsg( "input error: cannot find \"avih\" chunk (avi_file)" );
507         return( -1 );
508     }
509     __AVI_Parse_avih( &p_avi_demux->avih, p_avih->p_data->p_payload_start );
510     RIFF_DeleteChunk( p_input, p_avih );
511     
512     if( p_avi_demux->avih.i_streams == 0 )  
513             /* aucun flux defini, peut etre essayer de trouver ss connaitre */
514                                       /* le nombre serait pas mal, a voir */
515     {
516         __AVIFreeDemuxData( p_input );
517         intf_ErrMsg( "input error: no defined stream !" );
518         return( -1 );
519     }
520     
521     /* On creer les tableau pr les flux */
522     p_avi_demux->i_streams = p_avi_demux->avih.i_streams;
523     
524     p_avi_demux->pp_info = calloc( p_avi_demux->i_streams, 
525                                     sizeof( AVIStreamInfo_t* ) );
526     memset( p_avi_demux->pp_info, 0, 
527                         sizeof( AVIStreamInfo_t* ) * p_avi_demux->i_streams );
528     
529     for( i = 0 ; i < p_avi_demux->i_streams; i++ )
530     {
531         p_avi_demux->pp_info[i] = malloc( sizeof(AVIStreamInfo_t ) );
532         memset( p_avi_demux->pp_info[i], 0, sizeof( AVIStreamInfo_t ) );        
533
534         /* pour chaque flux on cherche ses infos */
535         if( RIFF_FindListChunk(p_input,
536                                 &p_strl,p_hdrl, FOURCC_strl) != 0 )
537         {
538             __AVIFreeDemuxData( p_input );
539             intf_ErrMsg( "input error: cannot find \"LIST-strl\" (avi_file)" );
540             return( -1 );
541         }
542         p_avi_demux->pp_info[i]->p_strl = p_strl;
543         
544         if( RIFF_DescendChunk(p_input) != 0 )
545         {
546             __AVIFreeDemuxData( p_input );
547             intf_ErrMsg( "input error: cannot look for subchunk (avi_file)" );
548             return ( -1 );
549         }
550         /* ds  LIST-strl cherche strh */
551         if( RIFF_FindAndLoadChunk( p_input, p_hdrl, 
552                                 &p_strh, FOURCC_strh ) != 0 )
553         {
554             __AVIFreeDemuxData( p_input );
555             intf_ErrMsg( "input error: cannot find \"strh\" (avi_file)" );
556             return( -1 );
557         }
558         p_avi_demux->pp_info[i]->p_strh = p_strh;
559         
560         /* ds  LIST-strl cherche strf */
561         if( RIFF_FindAndLoadChunk( p_input, p_hdrl, 
562                                 &p_strf, FOURCC_strf ) != 0 )
563         {
564             __AVIFreeDemuxData( p_input );
565             intf_ErrMsg( "input error: cannot find \"strf\" (avi_file)" );
566             return( -1 );
567         }
568          p_avi_demux->pp_info[i]->p_strf = p_strf;
569         /* FIXME faudrait cherche et charger strd */
570         /* mais a priori pas vraiment utile pr divx */
571
572          if( RIFF_AscendChunk(p_input, p_strl) != 0 )
573         {
574             __AVIFreeDemuxData( p_input );
575             intf_ErrMsg( "input error: cannot go out (\"strl\") (avi_file)" );
576             return( -1 );
577         }
578         
579     }
580     
581
582     if( RIFF_AscendChunk(p_input, p_hdrl) != 0)
583     {
584         __AVIFreeDemuxData( p_input );
585         intf_ErrMsg( "input error: cannot go out (\"hdrl\") (avi_file)" );
586         return( -1 );
587     }
588
589     intf_Msg( "input init: AVIH: %d stream, flags %s%s%s%s%s%s ", 
590             p_avi_demux->i_streams,
591             p_avi_demux->avih.i_flags&AVIF_HASINDEX?" HAS_INDEX":"",
592             p_avi_demux->avih.i_flags&AVIF_MUSTUSEINDEX?" MUST_USE_INDEX":"",
593             p_avi_demux->avih.i_flags&AVIF_ISINTERLEAVED?" IS_INTERLEAVED":"",
594             p_avi_demux->avih.i_flags&AVIF_TRUSTCKTYPE?" TRUST_CKTYPE":"",
595             p_avi_demux->avih.i_flags&AVIF_WASCAPTUREFILE?" CAPTUREFILE":"",
596             p_avi_demux->avih.i_flags&AVIF_COPYRIGHTED?" COPYRIGHTED":"" );
597
598     /* go to movi chunk */
599     if( RIFF_FindListChunk(p_input ,&p_movi,p_riff, FOURCC_movi) != 0 )
600     {
601         intf_ErrMsg( "input error: cannot find \"LIST-movi\" (avi_file)" );
602         __AVIFreeDemuxData( p_input );
603         return( -1 );
604     }
605     p_avi_demux->p_movi = p_movi;
606     
607     /* get index */
608     if( (p_input->stream.b_seekable)
609          &&((p_avi_demux->avih.i_flags&AVIF_HASINDEX) != 0) )
610     {
611         __AVI_GetIndex( p_input );
612         /* try to get i_idxoffset with first stream*/
613         __AVI_GetIndexOffset( p_input );
614         RIFF_GoToChunk( p_input, p_avi_demux->p_movi );
615     }
616     else
617     {
618         intf_WarnMsg( 1, "input init: cannot get index" );
619     }
620
621     if( RIFF_DescendChunk( p_input ) != 0 )
622     {
623         __AVIFreeDemuxData( p_input );
624         intf_ErrMsg( "input error: cannot go in (\"movi\") (avi_file)" );
625         return( -1 );
626     }
627    /* TODO: check for index and read it if possible( seekable )*/
628
629    /** We have now finished with reading the file **/
630    /** we make the last initialisation  **/
631
632     if( input_InitStream( p_input, 0 ) == -1)
633     {
634         __AVIFreeDemuxData( p_input );
635         intf_ErrMsg( "input error: cannot init stream" );
636         return( -1 );
637     }
638
639     if( input_AddProgram( p_input, 0, 0) == NULL )
640     {
641         __AVIFreeDemuxData( p_input );
642         intf_ErrMsg( "input error: cannot add program" );
643         return( -1 );
644     }
645     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
646     p_input->stream.p_new_program = p_input->stream.pp_programs[0] ;
647             
648     vlc_mutex_lock( &p_input->stream.stream_lock );
649     for( i = 0; i < p_avi_demux->i_streams; i++ )
650     {
651 #define p_info  p_avi_demux->pp_info[i]
652         __AVI_Parse_Header( &p_info->header,
653                         p_info->p_strh->p_data->p_payload_start);
654         switch( p_info->header.i_type )
655         {
656             case( FOURCC_auds ):
657                 /* pour l'id j'ai mis 12+i pr audio et 42+i pour video */
658                 /* et le numero du flux(ici i) dans i_stream_id */
659                 avi_ParseWaveFormatEx( &p_info->audio_format,
660                                    p_info->p_strf->p_data->p_payload_start ); 
661                 p_es = input_AddES( p_input, 
662                                 p_input->stream.p_selected_program, 12+i, 
663                                     p_info->p_strf->i_size );
664                 p_es->b_audio = 1;
665                 p_es->i_type = 
666                     __AVI_AudioGetType( p_info->audio_format.i_formattag );
667                 p_es->i_stream_id =i; /* FIXME */                
668                 if( p_es->i_type == 0 )
669                 {
670                     intf_ErrMsg( "input error: stream(%d,0x%x) not supported",
671                                     i,
672                                     p_info->audio_format.i_formattag );
673                     p_es->i_cat = UNKNOWN_ES;
674                 }
675                 else
676                 {
677                     if( p_es_audio == NULL ) {p_es_audio = p_es;}
678                     p_es->i_cat = AUDIO_ES;
679                 }
680                 break;
681                 
682             case( FOURCC_vids ):
683                 avi_ParseBitMapInfoHeader( &p_info->video_format,
684                                    p_info->p_strf->p_data->p_payload_start ); 
685
686                 p_es = input_AddES( p_input, 
687                                 p_input->stream.p_selected_program, 42+i,
688                                     p_info->p_strf->i_size );
689                 p_es->b_audio = 0;
690                 p_es->i_type = 
691                     __AVI_VideoGetType( p_info->video_format.i_compression );
692                 p_es->i_stream_id =i; /* FIXME */                
693                 if( p_es->i_type == 0 )
694                 {
695                     intf_ErrMsg( "input error: stream(%d,%4.4s) not supported",
696                                i,
697                                (char*)&p_info->video_format.i_compression);
698                     p_es->i_cat = UNKNOWN_ES;
699                 }
700                 else
701                 {
702                     if( p_es_video == NULL ) {p_es_video = p_es;}
703                     p_es->i_cat = VIDEO_ES;
704                 }
705                 break;
706             default:
707                 p_es = input_AddES( p_input, 
708                                 p_input->stream.p_selected_program, 12, 
709                                     p_info->p_strf->i_size );
710                 intf_ErrMsg( "input error: unknown stream(%d) type",
711                             i );
712                 p_es->i_cat = UNKNOWN_ES;
713                 break;
714         }
715         p_info->p_es = p_es;
716         p_info->i_cat = p_es->i_cat;
717         /* We copy strf for decoder in p_es->p_demux_data */
718         memcpy( p_es->p_demux_data, 
719                 p_info->p_strf->p_data->p_payload_start,
720                 p_info->p_strf->i_size );
721         /* print informations on stream */
722         switch( p_es->i_cat )
723         {
724             case( VIDEO_ES ):
725                 intf_Msg("input init: video(%4.4s) %dx%d %dbpp %ffps (size %d)",
726                         (char*)&p_info->video_format.i_compression,
727                         p_info->video_format.i_width,
728                         p_info->video_format.i_height,
729                         p_info->video_format.i_bitcount,
730                         (float)p_info->header.i_rate /
731                             (float)p_info->header.i_scale,
732                         p_info->header.i_samplesize );
733                 break;
734             case( AUDIO_ES ):
735                 intf_Msg( "input init: audio(0x%x) %d channels %dHz %dbits %ffps (size %d)",
736                         p_info->audio_format.i_formattag,
737                         p_info->audio_format.i_channels,
738                         p_info->audio_format.i_samplespersec,
739                         p_info->audio_format.i_bitspersample,
740                         (float)p_info->header.i_rate /
741                             (float)p_info->header.i_scale,
742                         p_info->header.i_samplesize );
743                 break;
744         }
745
746 #undef p_info    
747     }
748
749     /* we select the first audio and video ES */
750     if( p_es_video != NULL ) 
751     {
752         input_SelectES( p_input, p_es_video );
753     }
754     else
755     {
756         intf_ErrMsg( "input error: no video stream found !" );
757         vlc_mutex_unlock( &p_input->stream.stream_lock );
758         return( -1 );
759     }
760     if( p_es_audio != NULL ) 
761     {
762         input_SelectES( p_input, p_es_audio );
763     }
764     else
765     {
766         intf_Msg( "input init: no audio stream found !" );
767     }
768
769    /* p_input->stream.p_selected_area->i_tell = 0; */
770     p_input->stream.i_mux_rate = p_avi_demux->avih.i_maxbytespersec / 50;
771     p_input->stream.p_selected_program->b_is_ok = 1;
772     vlc_mutex_unlock( &p_input->stream.stream_lock );
773     
774     return( 0 );
775 }
776
777 static void AVIEnd( input_thread_t *p_input )
778 {   
779     __AVIFreeDemuxData( p_input ); 
780     return;
781 }
782
783
784 static mtime_t __AVI_GetPTS( AVIStreamInfo_t *p_info )
785 {
786     /* XXX you need to had p_info->i_date to have correct pts */
787     /* p_info->p_index[p_info->i_idxpos] need to be valid !! */
788     mtime_t i_pts;
789
790     /* be careful to  *1000000 before round  ! */
791     if( p_info->header.i_samplesize != 0 )
792     {
793         i_pts = (mtime_t)( (double)1000000.0 *
794                     (double)p_info->p_index[p_info->i_idxpos].i_lengthtotal *
795                     (double)p_info->header.i_scale /
796                     (double)p_info->header.i_rate /
797                     (double)p_info->header.i_samplesize );
798     }
799     else
800     {
801         i_pts = (mtime_t)( (double)1000000.0 *
802                     (double)p_info->i_idxpos *
803                     (double)p_info->header.i_scale /
804                     (double)p_info->header.i_rate);
805     }
806     return( i_pts );
807 }
808
809
810
811 static void __AVI_NextIndexEntry( input_thread_t *p_input, 
812                                   AVIStreamInfo_t *p_info )
813 {
814    p_info->i_idxpos++;
815    if( p_info->i_idxpos >= p_info->i_idxnb )
816    {
817         /* we need to verify if we reach end of file
818             or if index is broken and search manually */
819         intf_WarnMsg( 1, "input demux: out of index" );
820    }
821 }
822
823 static int __AVI_ReAlign( input_thread_t *p_input, 
824                             AVIStreamInfo_t  *p_info )
825 {
826     u32     u32_pos;
827     off_t   i_pos;
828     
829     __RIFF_TellPos( p_input, &u32_pos );
830      i_pos = (off_t)u32_pos - (off_t)p_info->i_idxoffset;
831    
832     /* TODO verifier si on est dans p_movi */
833     
834     if( p_info->p_index[p_info->i_idxnb-1].i_offset <= i_pos )
835     {
836         p_info->i_idxpos = p_info->i_idxnb-1;
837         return( 0 ); 
838     }
839     
840     if( i_pos <= p_info->p_index[0].i_offset )
841     {
842         p_info->i_idxpos = 0;
843         return( 0 );
844     }
845     /* if we have seek in the current chunk then do nothing 
846         __AVI_SeekToChunk will correct */
847     if( (p_info->p_index[p_info->i_idxpos].i_offset <= i_pos)
848             && ( i_pos < p_info->p_index[p_info->i_idxpos].i_offset + 
849                     p_info->p_index[p_info->i_idxpos].i_length ) )
850     {
851         return( 0 );
852     }
853
854     if( i_pos >= p_info->p_index[p_info->i_idxpos].i_offset )
855     {
856         /* search for a chunk after i_idxpos */
857         while( (p_info->p_index[p_info->i_idxpos].i_offset < i_pos)
858                 &&( p_info->i_idxpos < p_info->i_idxnb - 1 ) )
859         {
860             p_info->i_idxpos++;
861         }
862         while( ((p_info->p_index[p_info->i_idxpos].i_flags&AVIIF_KEYFRAME) == 0)
863                 &&( p_info->i_idxpos < p_info->i_idxnb - 1 ) )
864         {
865             p_info->i_idxpos++;
866         }
867     }
868     else
869     {
870         /* search for a chunk before i_idxpos */
871         while( (p_info->p_index[p_info->i_idxpos].i_offset + 
872                     p_info->p_index[p_info->i_idxpos].i_length >= i_pos)
873                         &&( p_info->i_idxpos > 0 ) )
874         {
875             p_info->i_idxpos--;
876         }
877         while( ((p_info->p_index[p_info->i_idxpos].i_flags&AVIIF_KEYFRAME) == 0)
878                 &( p_info->i_idxpos > 0 ) )
879         {
880             p_info->i_idxpos--;
881         }
882     }
883     
884     return( 0 );
885 }
886 static void __AVI_SynchroReInit( input_thread_t *p_input,
887                                  AVIStreamInfo_t *p_info_master,
888                                  AVIStreamInfo_t *p_info_slave )
889 {
890     demux_data_avi_file_t *p_avi_demux;
891     p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
892     p_avi_demux->i_date = mdate() + DEFAULT_PTS_DELAY 
893                             - __AVI_GetPTS( p_info_master );
894     if( p_info_slave != NULL )
895     {
896         /* TODO: a optimiser */
897         p_info_slave->i_idxpos = 0; 
898         p_info_slave->b_unselected = 1; /* to correct audio */
899     }
900     p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK;
901
902 /** -1 in case of error, 0 of EOF, 1 otherwise **/
903 static int AVIDemux( input_thread_t *p_input )
904 {
905     /* on cherche un block
906        plusieurs cas :
907         * encapsuler dans un chunk "rec "
908         * juste une succesion de 00dc 01wb ...
909         * pire tout audio puis tout video ou vice versa
910      */
911 /* TODO :   * a better method to realign
912             * verify that we are reading in p_movi 
913             * XXX be sure to send audio before video to avoid click
914             * 
915  */
916     riffchunk_t *p_chunk;
917     int i;
918     pes_packet_t *p_pes;
919     demux_data_avi_file_t *p_avi_demux;
920
921     AVIStreamInfo_t *p_info_video;
922     AVIStreamInfo_t *p_info_audio;
923     AVIStreamInfo_t *p_info;
924     /* XXX arrive pas a avoir acces a cette fct° 
925     input_ClockManageRef( p_input,
926                             p_input->stream.p_selected_program,
927                             (mtime_t)0 ); */
928     p_avi_demux = (demux_data_avi_file_t*)p_input->p_demux_data;
929
930     /* search video and audio stream selected */
931     p_info_video = NULL;
932     p_info_audio = NULL;
933     
934     for( i = 0; i < p_avi_demux->i_streams; i++ )
935     {
936         if( p_avi_demux->pp_info[i]->p_es->p_decoder_fifo != NULL )
937         {
938             switch( p_avi_demux->pp_info[i]->p_es->i_cat )
939             {
940                 case( VIDEO_ES ):
941                     p_info_video = p_avi_demux->pp_info[i];
942                     break;
943                 case( AUDIO_ES ):
944                     p_info_audio = p_avi_demux->pp_info[i];
945                     break;
946             }
947         }
948         else
949         {
950             p_avi_demux->pp_info[i]->b_unselected = 1;
951         }
952     }
953     if( p_info_video == NULL )
954     {
955         intf_ErrMsg( "input error: no video ouput selected" );
956         return( -1 );
957     }
958
959     if( input_ClockManageControl( p_input, p_input->stream.p_selected_program,
960                             (mtime_t)0) == PAUSE_S )
961     {   
962         __AVI_SynchroReInit( p_input, p_info_video, p_info_audio );
963     }
964
965     /* after updated p_avi_demux->pp_info[i]->b_unselected  !! */
966     if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
967     { 
968         __AVI_ReAlign( p_input, p_info_video ); /*on se realigne pr la video */
969         __AVI_SynchroReInit( p_input, p_info_video, p_info_audio );
970     }
971
972      /* update i_date if previously unselected ES (ex: 2 channels audio ) */
973     if( (p_info_audio != NULL)&&(p_info_audio->b_unselected ))
974     {
975         /* we have to go to the good pts */
976         /* we will reach p_info_ok pts */
977         while( __AVI_GetPTS( p_info_audio) < __AVI_GetPTS( p_info_video) )
978         {
979             __AVI_NextIndexEntry( p_input, p_info_audio );
980         }
981        p_info_audio->b_unselected = 0 ;
982     }
983   
984     /* what stream we should read in first */
985     if( p_info_audio == NULL )
986     {
987         p_info = p_info_video;
988     }
989     else
990     {
991         if( __AVI_GetPTS( p_info_audio ) <= 
992                         __AVI_GetPTS( p_info_video ) )
993         {
994             p_info = p_info_audio;
995         }
996         else
997         {
998             p_info = p_info_video;
999         }
1000     }
1001
1002     /* go to the good chunk to read */
1003
1004     __AVI_SeekToChunk( p_input, p_info );
1005     
1006     /* now we just need to read a chunk */
1007     if( (p_chunk = RIFF_ReadChunk( p_input )) == NULL )
1008     {   
1009         intf_ErrMsg( "input demux: cannot read chunk" );
1010         return( -1 );
1011     }
1012
1013     if( (p_chunk->i_id&0xFFFF0000) != 
1014                     (p_info->p_index[p_info->i_idxpos].i_id&0xFFFF0000) )
1015     {
1016         intf_WarnMsg( 2, "input demux: bad index entry" );
1017         __AVI_NextIndexEntry( p_input, p_info );
1018         return( 1 );
1019     }
1020 /*    
1021     intf_WarnMsg( 6, "input demux: read %4.4s chunk %d bytes",
1022                     (char*)&p_chunk->i_id,
1023                     p_chunk->i_size);
1024 */                    
1025     if( RIFF_LoadChunkDataInPES(p_input, p_chunk, &p_pes) != 0 )
1026     {
1027         intf_ErrMsg( "input error: cannot read data" );
1028         return( -1 );
1029     }
1030
1031     p_pes->i_rate = p_input->stream.control.i_rate; 
1032     p_pes->i_pts = p_avi_demux->i_date + __AVI_GetPTS( p_info );
1033     p_pes->i_dts = 0;
1034     
1035     /* send to decoder */
1036     vlc_mutex_lock( &p_info->p_es->p_decoder_fifo->data_lock );
1037     /* change MAX_PACKET and replace it to have same duration of audio 
1038         and video in buffer, to avoid unsynchronization while seeking */
1039     if( p_info->p_es->p_decoder_fifo->i_depth >= MAX_PACKETS_IN_FIFO )
1040     {
1041         /* Wait for the decoder. */
1042         vlc_cond_wait( &p_info->p_es->p_decoder_fifo->data_wait, 
1043                         &p_info->p_es->p_decoder_fifo->data_lock );
1044     }
1045     vlc_mutex_unlock( &p_info->p_es->p_decoder_fifo->data_lock );
1046     input_DecodePES( p_info->p_es->p_decoder_fifo, p_pes );
1047
1048     __AVI_NextIndexEntry( p_input, p_info );
1049     if( p_info->i_idxpos >= p_info->i_idxnb ) 
1050     {
1051         /* reach end of p_index , to be corrected to use p_movi instead */
1052         return( 0 ); 
1053     }
1054
1055     return( 1 );
1056 }