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>
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 /*****************************************************************************
25 *****************************************************************************/
26 #include <stdlib.h> /* malloc(), free() */
29 #include <vlc/input.h>
33 #include "libioRIFF.h"
35 inline u16 __GetWLE( byte_t *p_buff )
37 return( (*p_buff) + ( *(p_buff+1) <<8 ) );
40 inline u32 __GetDWLE( byte_t *p_buff )
42 return( *(p_buff) + ( *(p_buff+1) <<8 ) +
43 ( *(p_buff+2) <<16 ) + ( *(p_buff+3) <<24 ) );
46 inline u32 __EVEN( u32 i )
48 return( (i & 1) ? ++i : i );
51 int __RIFF_TellPos( input_thread_t *p_input, u32 *pos )
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 );
60 int __RIFF_SkipBytes(input_thread_t * p_input,int nb)
62 data_packet_t *p_pack;
65 if( p_input->stream.b_seekable )
68 __RIFF_TellPos( p_input, &i_pos);
69 p_input->pf_seek( p_input, (off_t)(i_pos + nb) );
70 input_AccessReinit( p_input );
74 msg_Warn( p_input, "cannot seek, it will take times" );
75 if( nb < 0 ) { return( -1 ); }
81 i = input_SplitBuffer( p_input, &p_pack, 4096);
85 i = input_SplitBuffer( p_input, &p_pack, i_rest);
88 if ( i < 0 ) { return ( -1 ); }
90 input_DeletePacket( p_input->p_method_data, p_pack);
91 if( ( i == 0 )&&( i_rest != 0 )) { return( -1 ); }
98 void RIFF_DeleteChunk( input_thread_t *p_input, riffchunk_t *p_chunk )
102 if( p_chunk->p_data != NULL )
104 input_DeletePacket( p_input->p_method_data, p_chunk->p_data );
110 riffchunk_t * RIFF_ReadChunk(input_thread_t * p_input)
112 riffchunk_t * p_riff;
116 if( !(p_riff = malloc( sizeof(riffchunk_t))) )
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 )
125 msg_Err( p_input, "cannot peek()" );
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 ;
134 __RIFF_TellPos(p_input, &(p_riff->i_pos) );
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)
149 if( ( p_riff = RIFF_ReadChunk( p_input ) ) == NULL )
151 msg_Err( p_input, "cannot read chunk" );
154 i_len = __EVEN( p_riff->i_size );
156 if ( p_rifffather != NULL )
158 i_lenfather = __EVEN( p_rifffather->i_size );
159 if ( p_rifffather->i_pos + i_lenfather <= p_riff->i_pos + i_len + 8 )
161 msg_Err( p_input, "next chunk out of bounds" );
163 return( 1 ); /* pas dans nos frontiere */
166 if ( __RIFF_SkipBytes( p_input,i_len + 8 ) != 0 )
169 msg_Err( p_input, "cannot go to the next chunk" );
176 /****************************************************************
177 * Permet de rentrer dans un ck RIFF ou LIST *
178 ****************************************************************/
179 int RIFF_DescendChunk(input_thread_t * p_input)
181 return( __RIFF_SkipBytes(p_input,12) != 0 ? -1 : 0 );
184 /***************************************************************
185 * Permet de sortir d'un sous chunk et d'aller sur le suivant *
187 ***************************************************************/
189 int RIFF_AscendChunk(input_thread_t * p_input ,riffchunk_t *p_riff)
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 );
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)
204 riffchunk_t *p_riff = NULL;
210 if ( RIFF_NextChunk(p_input ,p_rifffather) != 0 )
215 p_riff=RIFF_ReadChunk(p_input);
216 } while ( ( p_riff )&&( p_riff->i_id != i_id ) );
218 if ( ( !p_riff )||( p_riff->i_id != i_id ) )
226 /*****************************************************************
227 * Permet de pointer sur la zone de donné du chunk courant *
228 *****************************************************************/
229 int RIFF_GoToChunkData(input_thread_t * p_input)
231 return( ( __RIFF_SkipBytes(p_input,8) != 0 ) ? -1 : 0 );
234 int RIFF_LoadChunkData(input_thread_t * p_input,riffchunk_t *p_riff )
236 off_t i_read = __EVEN( p_riff->i_size );
238 RIFF_GoToChunkData(p_input);
239 if ( input_SplitBuffer( p_input,
243 msg_Err( p_input, "cannot read enough data " );
247 if( p_riff->i_size&1 )
249 p_riff->p_data->p_payload_end--;
254 int RIFF_LoadChunkDataInPES(input_thread_t * p_input,
255 pes_packet_t **pp_pes,
259 data_packet_t *p_data;
264 if( (p_riff = RIFF_ReadChunk( p_input )) == NULL )
269 RIFF_GoToChunkData(p_input);
270 *pp_pes = input_NewPES( p_input->p_method_data );
272 if( *pp_pes == NULL )
277 if( (!p_riff->i_size) || (!i_size_index ) )
279 i_size = __MAX( i_size_index, p_riff->i_size );
283 i_size = __MIN( p_riff->i_size, i_size_index );
286 if( !p_riff->i_size )
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;
303 i_read = input_SplitBuffer(p_input, &p_data, i_size -
304 (*pp_pes)->i_pes_size );
307 /* FIXME free on all packets */
310 if( (*pp_pes)->p_first == NULL )
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 );
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 );
326 } while( ((*pp_pes)->i_pes_size < i_size)&&(i_read != 0) );
330 (*pp_pes)->i_pes_size--;
331 (*pp_pes)->p_last->p_payload_end--;
336 int RIFF_GoToChunk(input_thread_t * p_input, riffchunk_t *p_riff)
338 if( p_input->stream.b_seekable )
340 p_input->pf_seek( p_input, (off_t)p_riff->i_pos );
341 input_AccessReinit( p_input );
347 int RIFF_TestFileHeader( input_thread_t * p_input, riffchunk_t ** pp_riff, u32 i_type )
349 if( !( *pp_riff = RIFF_ReadChunk( p_input ) ) )
353 if( ( (*pp_riff)->i_id != FOURCC_RIFF )||( (*pp_riff)->i_type != i_type ) )
362 int RIFF_FindAndLoadChunk( input_thread_t * p_input, riffchunk_t *p_riff, riffchunk_t **pp_fmt, u32 i_type )
365 if ( RIFF_FindChunk( p_input, i_type, p_riff ) != 0)
369 if ( ( (*pp_fmt = RIFF_ReadChunk( p_input )) == NULL)
370 || ( RIFF_LoadChunkData( p_input, *pp_fmt ) != 0 ) )
372 if( *pp_fmt != NULL )
374 RIFF_DeleteChunk( p_input, *pp_fmt );
381 int RIFF_FindAndGotoDataChunk( input_thread_t * p_input, riffchunk_t *p_riff, riffchunk_t **pp_data, u32 i_type )
384 if ( RIFF_FindChunk( p_input, i_type, p_riff ) != 0)
388 if ( ( *pp_data = RIFF_ReadChunk( p_input ) ) == NULL )
392 if ( RIFF_GoToChunkData( p_input ) != 0 )
394 RIFF_DeleteChunk( p_input, *pp_data );
400 int RIFF_FindListChunk( input_thread_t *p_input, riffchunk_t **pp_riff, riffchunk_t *p_rifffather, u32 i_type )
408 if( *pp_riff != NULL )
412 if( RIFF_FindChunk( p_input, FOURCC_LIST, p_rifffather) != 0 )
416 *pp_riff = RIFF_ReadChunk( p_input );
418 if( *pp_riff == NULL )
422 if( (*pp_riff)->i_type != i_type )
424 if( RIFF_NextChunk( p_input, p_rifffather ) != 0 )