1 /*****************************************************************************
2 * libioRIFF.c : AVI file Stream input module for vlc
3 *****************************************************************************
4 * Copyright (C) 2001 VideoLAN
5 * $Id: libioRIFF.c,v 1.1 2002/04/23 23:44:36 fenrir Exp $
6 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
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.
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.
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 *****************************************************************************/
23 typedef struct riffchunk_s
28 u32 i_pos; /* peut etre a changer */
29 data_packet_t *p_data; /* pas forcement utilise */
30 struct riffchunk_s *p_next;
31 struct riffchunk_s *p_subchunk;
34 /* ttes ces fonctions permettent un acces lineaire sans avoir besoin de revenrir en arriere */
35 static riffchunk_t * RIFF_ReadChunk(input_thread_t * p_input);
36 static int RIFF_NextChunk(input_thread_t * p_input,riffchunk_t *p_rifffather);
37 static int RIFF_DescendChunk(input_thread_t * p_input);
38 static int RIFF_AscendChunk(input_thread_t * p_input,riffchunk_t *p_rifffather);
39 static int RIFF_FindChunk(input_thread_t * p_input,u32 i_id,riffchunk_t *p_rifffather);
40 static int RIFF_GoToChunkData(input_thread_t * p_input);
41 static int RIFF_LoadChunkData(input_thread_t * p_input,riffchunk_t *p_riff);
42 static int RIFF_TestFileHeader(input_thread_t * p_input, riffchunk_t **pp_riff, u32 i_type);
43 static int RIFF_FindAndLoadChunk( input_thread_t * p_input, riffchunk_t *p_riff, riffchunk_t **pp_fmt, u32 i_type );
44 static int RIFF_FindAndGotoDataChunk( input_thread_t * p_input, riffchunk_t *p_riff, riffchunk_t **pp_data, u32 i_type );
45 static int RIFF_FindListChunk( input_thread_t *p_input, riffchunk_t **pp_riff, riffchunk_t *p_rifffather, u32 i_type );
47 static void RIFF_DeleteChunk( input_thread_t * p_input, riffchunk_t *p_chunk );
51 ces fonctions on besoin de pouvoir faire des seek
52 static int RIFF_GoToChunk(input_thread_t * p_input,riffchunk_t *p_riff);
55 static u32 RIFF_4cToI(char c1,char c2,char c3,char c4);
56 static char * RIFF_IToStr(u32 i);
58 /*************************************************************************/
60 /********************************************
61 * Fonction locale maintenant *
62 ********************************************/
64 static int __RIFF_TellPos( input_thread_t *p_input, u32 *pos )
65 { /* pas sur que ca marche */
68 vlc_mutex_lock( &p_input->stream.stream_lock );
69 i = p_input->stream.p_selected_area->i_tell - ( p_input->p_last_data - p_input->p_current_data );
70 vlc_mutex_unlock( &p_input->stream.stream_lock );
75 static int __RIFF_SkipBytes(input_thread_t * p_input,int nb)
77 data_packet_t *p_pack;
80 if( p_input->stream.b_seekable )
83 __RIFF_TellPos( p_input, &i_pos);
84 p_input->pf_seek( p_input, (off_t)(i_pos + nb) );
85 input_AccessReinit( p_input );
89 intf_WarnMsg( 1, "input demux: cannot seek, it will take times" );
90 if( nb < 0 ) { return( -1 ); }
96 i = input_SplitBuffer( p_input, &p_pack, 4096);
100 i = input_SplitBuffer( p_input, &p_pack, i_rest);
103 if ( i < 0 ) { return ( -1 ); }
105 input_DeletePacket( p_input->p_method_data, p_pack);
112 static void RIFF_DeleteChunk( input_thread_t *p_input, riffchunk_t *p_chunk )
116 if( p_chunk->p_data != NULL )
118 input_DeletePacket( p_input->p_method_data, p_chunk->p_data );
124 /* ******************************************
125 * lit une structure riffchunk sans avancer *
126 ********************************************/
127 static riffchunk_t * RIFF_ReadChunk(input_thread_t * p_input)
129 riffchunk_t * p_riff;
133 if((p_riff = malloc( sizeof(riffchunk_t))) == NULL)
135 intf_ErrMsg("input error: not enough memory (ioriff)" );
139 p_riff->p_data = NULL; /* Par defaut */
140 p_riff->p_next = NULL;
141 p_riff->p_subchunk = NULL;
142 /* peek to have the begining, 8+4 where 4 are to get type */
143 count=input_Peek( p_input, &p_peek, 12 );
146 intf_ErrMsg( "input error: cannot peek() (ioriff)" );
151 p_riff->i_id = __GetDoubleWordLittleEndianFromBuff( p_peek );
152 p_riff->i_size =__GetDoubleWordLittleEndianFromBuff( p_peek + 4 );
155 p_riff->i_type = __GetDoubleWordLittleEndianFromBuff( p_peek + 8 );
161 __RIFF_TellPos(p_input, &(p_riff->i_pos) );
166 /**************************************************
167 * Va au chunk juste d'apres si il en a encore *
168 * -1 si erreur , 1 si y'en a plus *
169 **************************************************/
170 static int RIFF_NextChunk( input_thread_t * p_input,riffchunk_t *p_rifffather)
176 if( ( p_riff = RIFF_ReadChunk( p_input ) ) == NULL )
178 intf_ErrMsg( "ioriff: cannot read chunk." );
181 i_len = p_riff->i_size;
182 if( i_len%2 != 0 ) {i_len++;} /* aligné sur un mot */
184 if ( p_rifffather != NULL )
186 i_lenfather=p_rifffather->i_size;
187 if ( i_lenfather%2 !=0 ) {i_lenfather++;}
188 if ( p_rifffather->i_pos + i_lenfather <= p_riff->i_pos + i_len )
190 intf_ErrMsg( "ioriff: next chunk out of bound" );
192 return( 1 ); /* pas dans nos frontiere */
195 if ( __RIFF_SkipBytes( p_input,i_len + 8 ) != 0 )
198 intf_ErrMsg( "input error: cannot go to the next chunk (ioriff)." );
205 /****************************************************************
206 * Permet de rentrer dans un ck RIFF ou LIST *
207 ****************************************************************/
208 static int RIFF_DescendChunk(input_thread_t * p_input)
210 if ( __RIFF_SkipBytes(p_input,12) != 0)
212 intf_ErrMsg( "input error: cannot go into chunk." );
218 /***************************************************************
219 * Permet de sortir d'un sous chunk et d'aller sur le suivant *
221 ***************************************************************/
223 static int RIFF_AscendChunk(input_thread_t * p_input ,riffchunk_t *p_rifffather)
228 i_skip = p_rifffather->i_pos + p_rifffather->i_size + 8;
229 if ( i_skip%2 != 0) {i_skip++;}
231 __RIFF_TellPos(p_input, &i_posactu);
234 if (( __RIFF_SkipBytes(p_input,i_skip)) != 0)
236 intf_ErrMsg( "ioriff: cannot exit from subchunk.");
242 /***************************************************************
243 * Permet de se deplacer jusqu'au premier chunk avec le bon id *
244 * *************************************************************/
245 static int RIFF_FindChunk(input_thread_t * p_input ,u32 i_id,riffchunk_t *p_rifffather)
247 riffchunk_t *p_riff=NULL;
253 if ( RIFF_NextChunk(p_input ,p_rifffather) != 0 )
258 p_riff=RIFF_ReadChunk(p_input);
259 } while ( ( p_riff != NULL )&&( p_riff->i_id != i_id ) );
261 if ( ( p_riff == NULL )||( p_riff->i_id != i_id ) )
269 /*****************************************************************
270 * Permet de pointer sur la zone de donné du chunk courant *
271 *****************************************************************/
272 static int RIFF_GoToChunkData(input_thread_t * p_input)
274 if ( __RIFF_SkipBytes(p_input,8) != 0 )
281 static int RIFF_LoadChunkData(input_thread_t * p_input,riffchunk_t *p_riff )
284 RIFF_GoToChunkData(p_input);
285 if ( input_SplitBuffer( p_input, &p_riff->p_data, p_riff->i_size ) != p_riff->i_size )
287 intf_ErrMsg( "ioriff: cannot read enough data " );
290 if ( p_riff->i_size%2 != 0)
292 __RIFF_SkipBytes(p_input,1);
293 } /* aligne sur un mot */
297 static int RIFF_LoadChunkDataInPES(input_thread_t * p_input,riffchunk_t *p_riff,pes_packet_t **pp_pes)
300 data_packet_t *p_data;
302 RIFF_GoToChunkData(p_input);
303 *pp_pes = input_NewPES( p_input->p_method_data );
305 if( *pp_pes == NULL )
309 if( p_riff->i_size == 0 )
311 p_data = input_NewPacket( p_input->p_method_data, 0 );
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 = 0;
321 i_read = input_SplitBuffer(p_input, &p_data, p_riff->i_size -
322 (*pp_pes)->i_pes_size );
325 /* FIXME free sur tout les packets */
328 if( (*pp_pes)->p_first == NULL )
330 (*pp_pes)->p_first = p_data;
331 (*pp_pes)->p_last = p_data;
332 (*pp_pes)->i_nb_data = 1;
333 (*pp_pes)->i_pes_size = ( p_data->p_payload_end -
334 p_data->p_payload_start );
338 (*pp_pes)->p_last->p_next = p_data;
339 (*pp_pes)->p_last = p_data;
340 (*pp_pes)->i_nb_data++;
341 (*pp_pes)->i_pes_size += ( p_data->p_payload_end -
342 p_data->p_payload_start );
344 } while( ((*pp_pes)->i_pes_size < p_riff->i_size)&&(i_read != 0) );
345 /* i_read = 0 si fin du stream sinon block */
346 if ( p_riff->i_size%2 != 0)
348 __RIFF_SkipBytes(p_input,1);
349 } /* aligne sur un mot */
356 static int RIFF_GoToChunk(input_thread_t * p_input, riffchunk_t *p_riff)
358 /* TODO rajouter les test */
359 if( p_input->stream.b_seekable )
361 p_input->pf_seek( p_input, (off_t)p_riff->i_pos );
362 input_AccessReinit( p_input );
370 static u32 RIFF_4cToI(char c1,char c2,char c3,char c4)
373 i = ( ((u32)c1) << 24 ) + ( ((u32)c2) << 16 ) + ( ((u32)c3) << 8 ) + (u32)c4;
378 static char * RIFF_IToStr(u32 l)
382 str=calloc(5,sizeof(char));
383 for( i = 0; i < 4; i++)
385 str[i] = ( l >> ( (3-i) * 8) )&0xFF;
391 static int RIFF_TestFileHeader( input_thread_t * p_input, riffchunk_t ** pp_riff, u32 i_type )
393 *pp_riff = RIFF_ReadChunk( p_input );
395 if( *pp_riff == NULL )
397 intf_ErrMsg( "input error: cannot retrieve header" );
400 if( (*pp_riff)->i_id != FOURCC_RIFF )
405 if( (*pp_riff)->i_type != i_type )
414 static int RIFF_FindAndLoadChunk( input_thread_t * p_input, riffchunk_t *p_riff, riffchunk_t **pp_fmt, u32 i_type )
417 if ( RIFF_FindChunk( p_input, i_type, p_riff ) != 0)
421 if ( ( (*pp_fmt = RIFF_ReadChunk( p_input )) == NULL) || ( RIFF_LoadChunkData( p_input, *pp_fmt ) != 0 ) )
423 if( *pp_fmt != NULL ) { RIFF_DeleteChunk( p_input, *pp_fmt ); }
429 static int RIFF_FindAndGotoDataChunk( input_thread_t * p_input, riffchunk_t *p_riff, riffchunk_t **pp_data, u32 i_type )
432 if ( RIFF_FindChunk( p_input, i_type, p_riff ) != 0)
436 if ( ( *pp_data = RIFF_ReadChunk( p_input ) ) == NULL )
440 if ( RIFF_GoToChunkData( p_input ) != 0 )
442 RIFF_DeleteChunk( p_input, *pp_data );
448 static int RIFF_FindListChunk( input_thread_t *p_input, riffchunk_t **pp_riff, riffchunk_t *p_rifffather, u32 i_type )
456 if( *pp_riff != NULL )
460 if( RIFF_FindChunk( p_input, FOURCC_LIST, p_rifffather) != 0 )
464 *pp_riff = RIFF_ReadChunk( p_input );
466 if( *pp_riff == NULL )
470 if( (*pp_riff)->i_type != i_type )
472 if( RIFF_NextChunk( p_input, p_rifffather ) != 0 )