]> git.sesse.net Git - vlc/blob - plugins/avi/libioRIFF.c
* ./src/misc/modules.c: added the --plugin-path option to give vlc an
[vlc] / plugins / avi / libioRIFF.c
1 /*****************************************************************************
2  * libioRIFF.c : AVI file Stream input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001 VideoLAN
5  * $Id: libioRIFF.c,v 1.9 2002/06/27 19:05:17 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
28 #include <vlc/vlc.h>
29 #include <vlc/input.h>
30
31 #include "video.h"
32
33 #include "libioRIFF.h"
34
35 inline u16 __GetWLE( byte_t *p_buff )
36 {
37     return( (*p_buff) + ( *(p_buff+1) <<8 ) );
38 }
39
40 inline u32 __GetDWLE( byte_t *p_buff )
41 {
42     return( *(p_buff) + ( *(p_buff+1) <<8 ) + 
43             ( *(p_buff+2) <<16 ) + ( *(p_buff+3) <<24 ) );
44 }
45
46 inline u32 __EVEN( u32 i )
47 {
48     return( (i & 1) ? ++i : i );
49 }
50         
51 int __RIFF_TellPos( input_thread_t *p_input, u32 *pos )
52
53     vlc_mutex_lock( &p_input->stream.stream_lock );
54     *pos= p_input->stream.p_selected_area->i_tell - 
55             ( p_input->p_last_data - p_input->p_current_data  );
56     vlc_mutex_unlock( &p_input->stream.stream_lock );
57     return 0;
58 }
59
60 int     __RIFF_SkipBytes(input_thread_t * p_input,int nb)
61 {  
62     data_packet_t *p_pack;
63     int i;
64     int i_rest;
65     if( p_input->stream.b_seekable )
66     {
67         u32 i_pos;
68         __RIFF_TellPos( p_input, &i_pos);
69         p_input->pf_seek( p_input, (off_t)(i_pos + nb) );
70         input_AccessReinit( p_input );
71     }
72     else
73     {
74         msg_Warn( p_input, "cannot seek, it will take times" );
75         if( nb < 0 ) { return( -1 ); }
76         i_rest = nb;
77         while (i_rest != 0 )
78         {
79             if ( i_rest >= 4096 )
80             {
81                 i = input_SplitBuffer( p_input, &p_pack, 4096);
82             }
83             else
84             {
85                 i = input_SplitBuffer( p_input, &p_pack, i_rest);
86             }
87                     
88             if ( i < 0 ) { return ( -1 ); }
89             i_rest-=i;
90             input_DeletePacket( p_input->p_method_data, p_pack);
91             if( ( i == 0 )&&( i_rest != 0 )) { return( -1 ); }
92         }
93     }
94         return ( 0 );
95 }
96
97
98 void RIFF_DeleteChunk( input_thread_t *p_input, riffchunk_t *p_chunk )
99 {
100     if( p_chunk != NULL)
101     {
102         if( p_chunk->p_data != NULL )
103         {
104             input_DeletePacket( p_input->p_method_data, p_chunk->p_data );
105         }
106         free( p_chunk );
107     }
108 }
109
110 riffchunk_t     * RIFF_ReadChunk(input_thread_t * p_input)
111 {
112     riffchunk_t * p_riff;
113     int count;
114     byte_t * p_peek;
115  
116         if( !(p_riff = malloc( sizeof(riffchunk_t))) )
117         {
118                 return( NULL );
119         }
120         
121         p_riff->p_data = NULL;
122         /* peek to have the begining, 8+4 where 4 are to get type */
123         if( ( count = input_Peek( p_input, &p_peek, 12 ) ) < 8 )
124         {
125                 msg_Err( p_input, "cannot peek()" );
126                 free(p_riff);
127                 return( NULL );
128         }
129         
130         p_riff->i_id = __GetDWLE( p_peek );
131         p_riff->i_size =__GetDWLE( p_peek + 4 );
132         p_riff->i_type = ( count == 12 ) ? __GetDWLE( p_peek + 8 ) : 0 ;
133
134         __RIFF_TellPos(p_input, &(p_riff->i_pos) );
135         
136         return( p_riff );       
137 }
138
139 /**************************************************
140  * Va au chunk juste d'apres si il en a encore    *
141  * -1 si erreur , 1 si y'en a plus                *
142  **************************************************/
143 int RIFF_NextChunk( input_thread_t * p_input,riffchunk_t *p_rifffather)
144 {
145     int i_len;
146     int i_lenfather;
147     riffchunk_t *p_riff;
148
149         if( ( p_riff = RIFF_ReadChunk( p_input ) ) == NULL )
150         {
151                 msg_Err( p_input, "cannot read chunk" );
152                 return( -1 );
153         }
154         i_len = __EVEN( p_riff->i_size );
155
156         if ( p_rifffather != NULL )
157         {
158                 i_lenfather = __EVEN( p_rifffather->i_size );
159                 if ( p_rifffather->i_pos + i_lenfather  <= p_riff->i_pos + i_len + 8 )
160                 {
161             msg_Err( p_input, "next chunk out of bounds" );
162                         free( p_riff );
163                         return( 1 ); /* pas dans nos frontiere */
164                 }
165         }
166         if ( __RIFF_SkipBytes( p_input,i_len + 8 ) != 0 )
167         { 
168                 free( p_riff );
169                 msg_Err( p_input, "cannot go to the next chunk" );
170                 return( -1 );
171         }
172         free( p_riff );
173         return( 0 );
174 }
175
176 /****************************************************************
177  * Permet de rentrer dans un ck RIFF ou LIST                    *
178  ****************************************************************/
179 int     RIFF_DescendChunk(input_thread_t * p_input)
180 {
181         return(  __RIFF_SkipBytes(p_input,12) != 0 ? -1 : 0 );
182 }
183
184 /***************************************************************
185  * Permet de sortir d'un sous chunk et d'aller sur le suivant  *
186  * chunk                                                       *
187  ***************************************************************/
188
189 int     RIFF_AscendChunk(input_thread_t * p_input ,riffchunk_t *p_riff)
190 {
191     int i_skip;
192     u32 i_posactu;
193
194     __RIFF_TellPos(p_input, &i_posactu);
195         i_skip  = __EVEN( p_riff->i_pos + p_riff->i_size + 8 ) - i_posactu;
196     return( (( __RIFF_SkipBytes(p_input,i_skip)) != 0) ? -1 : 0 );
197 }
198
199 /***************************************************************
200  * Permet de se deplacer jusqu'au premier chunk avec le bon id *
201  * *************************************************************/
202 int     RIFF_FindChunk(input_thread_t * p_input ,u32 i_id,riffchunk_t *p_rifffather)
203 {
204  riffchunk_t *p_riff = NULL;
205         do
206         {
207                 if ( p_riff ) 
208                 { 
209                         free(p_riff); 
210                         if ( RIFF_NextChunk(p_input ,p_rifffather) != 0 ) 
211             { 
212                 return( -1 );
213             }
214                 }
215                 p_riff=RIFF_ReadChunk(p_input);
216         } while ( ( p_riff )&&( p_riff->i_id != i_id ) );
217
218     if ( ( !p_riff )||( p_riff->i_id != i_id ) )
219     { 
220         return( -1 );
221     }
222     free( p_riff );
223         return( 0 );
224 }
225
226 /*****************************************************************
227  * Permet de pointer sur la zone de donnĂ© du chunk courant       *
228  *****************************************************************/
229 int  RIFF_GoToChunkData(input_thread_t * p_input)
230 {
231         return( ( __RIFF_SkipBytes(p_input,8) != 0 ) ? -1 : 0 );
232 }
233
234 int     RIFF_LoadChunkData(input_thread_t * p_input,riffchunk_t *p_riff )
235 {
236     off_t   i_read = __EVEN( p_riff->i_size );
237
238         RIFF_GoToChunkData(p_input);
239         if ( input_SplitBuffer( p_input, 
240                             &p_riff->p_data, 
241                             i_read ) != i_read )
242         {
243                 msg_Err( p_input, "cannot read enough data " );
244                 return ( -1 );
245         }
246
247     if( p_riff->i_size&1 )
248     {
249         p_riff->p_data->p_payload_end--;
250     }
251         return( 0 );
252 }
253
254 int     RIFF_LoadChunkDataInPES(input_thread_t * p_input,
255                                     pes_packet_t **pp_pes,
256                                     int i_size_index)
257 {
258     u32 i_read;
259     data_packet_t *p_data;
260     riffchunk_t   *p_riff;
261     int i_size;
262     int b_pad = 0;
263     
264     if( (p_riff = RIFF_ReadChunk( p_input )) == NULL )
265     {
266         *pp_pes = NULL;
267         return( -1 );
268     }
269         RIFF_GoToChunkData(p_input);
270     *pp_pes = input_NewPES( p_input->p_method_data );
271
272     if( *pp_pes == NULL )
273     {
274         return( -1 );
275     }
276
277     if( (!p_riff->i_size) || (!i_size_index ) )
278     {
279         i_size = __MAX( i_size_index, p_riff->i_size );
280     }
281     else
282     {
283         i_size = __MIN( p_riff->i_size, i_size_index );
284     }
285     
286     if( !p_riff->i_size )
287     {
288         p_data = input_NewPacket( p_input->p_method_data, 0 );
289         (*pp_pes)->p_first = p_data;
290         (*pp_pes)->p_last  = p_data;
291         (*pp_pes)->i_nb_data = 1;
292         (*pp_pes)->i_pes_size = 0;
293         return( 0 );
294     }
295     if( i_size&1 )
296     {
297         i_size++;
298         b_pad = 1;
299     }
300
301     do
302     {
303         i_read = input_SplitBuffer(p_input, &p_data, i_size - 
304                                                     (*pp_pes)->i_pes_size );
305         if( i_read < 0 )
306         {
307             /* FIXME free on all packets */
308             return( -1 );
309         }
310         if( (*pp_pes)->p_first == NULL )
311         {
312             (*pp_pes)->p_first = p_data;
313             (*pp_pes)->p_last  = p_data;
314             (*pp_pes)->i_nb_data = 1;
315             (*pp_pes)->i_pes_size = ( p_data->p_payload_end - 
316                                         p_data->p_payload_start );
317         }
318         else
319         {
320             (*pp_pes)->p_last->p_next = p_data;
321             (*pp_pes)->p_last = p_data;
322             (*pp_pes)->i_nb_data++;
323             (*pp_pes)->i_pes_size += ( p_data->p_payload_end -
324                                        p_data->p_payload_start );
325         }
326     } while( ((*pp_pes)->i_pes_size < i_size)&&(i_read != 0) );
327
328     if( b_pad )
329     {
330         (*pp_pes)->i_pes_size--;
331         (*pp_pes)->p_last->p_payload_end--;
332     }
333         return( 0 );
334 }
335
336 int     RIFF_GoToChunk(input_thread_t * p_input, riffchunk_t *p_riff)
337 {
338     if( p_input->stream.b_seekable )
339     {
340         p_input->pf_seek( p_input, (off_t)p_riff->i_pos );
341         input_AccessReinit( p_input );
342             return( 0 );
343     }
344     return( -1 );
345 }
346
347 int   RIFF_TestFileHeader( input_thread_t * p_input, riffchunk_t ** pp_riff, u32 i_type )
348 {
349     if( !( *pp_riff = RIFF_ReadChunk( p_input ) ) )
350     {
351         return( -1 );
352     }
353     if( ( (*pp_riff)->i_id != FOURCC_RIFF )||( (*pp_riff)->i_type != i_type ) )
354     {
355         free( *pp_riff );
356         return( -1 );
357     } 
358     return( 0 );  
359 }
360
361
362 int   RIFF_FindAndLoadChunk( input_thread_t * p_input, riffchunk_t *p_riff, riffchunk_t **pp_fmt, u32 i_type )
363 {
364     *pp_fmt = NULL;
365     if ( RIFF_FindChunk( p_input, i_type, p_riff ) != 0)
366     {
367         return( -1 );
368     }
369     if ( ( (*pp_fmt = RIFF_ReadChunk( p_input )) == NULL) 
370                     || ( RIFF_LoadChunkData( p_input, *pp_fmt ) != 0 ) )
371     {
372         if( *pp_fmt != NULL ) 
373         { 
374             RIFF_DeleteChunk( p_input, *pp_fmt ); 
375         }
376         return( -1 );
377     }
378     return( 0 );
379 }
380
381 int   RIFF_FindAndGotoDataChunk( input_thread_t * p_input, riffchunk_t *p_riff, riffchunk_t **pp_data, u32 i_type )
382 {
383     *pp_data = NULL;
384     if ( RIFF_FindChunk( p_input, i_type, p_riff ) != 0)
385     {
386         return( -1 );
387     }
388     if ( ( *pp_data = RIFF_ReadChunk( p_input ) ) == NULL )
389     {
390         return( -1 );
391     }
392     if ( RIFF_GoToChunkData( p_input ) != 0 )
393     {
394         RIFF_DeleteChunk( p_input, *pp_data );
395         return( -1 );
396     }
397     return( 0 );
398 }
399
400 int   RIFF_FindListChunk( input_thread_t *p_input, riffchunk_t **pp_riff, riffchunk_t *p_rifffather, u32 i_type )
401 {
402     int i_ok;
403     
404     *pp_riff = NULL;
405     i_ok = 0;
406     while( i_ok == 0 )
407     {
408         if( *pp_riff != NULL )
409         {
410             free( *pp_riff );
411         }
412         if( RIFF_FindChunk( p_input, FOURCC_LIST, p_rifffather) != 0 )
413         {
414             return( -1 );
415         }
416         *pp_riff = RIFF_ReadChunk( p_input );
417                         
418         if( *pp_riff == NULL )
419         {
420             return( -1 );
421         }
422         if( (*pp_riff)->i_type != i_type )
423         {
424             if( RIFF_NextChunk( p_input, p_rifffather ) != 0 )
425             {
426                 return( -1 );
427             }
428         }
429         else
430         {
431             i_ok = 1;
432         }
433     }
434     return( 0 );  
435 }