1 /*****************************************************************************
2 * aiff.c: Audio Interchange File Format demuxer
3 *****************************************************************************
4 * Copyright (C) 2004-2007 the VideoLAN team
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 *****************************************************************************/
24 /*****************************************************************************
26 *****************************************************************************/
32 #include <vlc_common.h>
33 #include <vlc_plugin.h>
34 #include <vlc_demux.h>
40 /*****************************************************************************
42 *****************************************************************************/
43 static int Open ( vlc_object_t
* );
44 static void Close ( vlc_object_t
* );
47 set_category( CAT_INPUT
)
48 set_subcategory( SUBCAT_INPUT_DEMUX
)
49 set_description( N_("AIFF demuxer" ) )
50 set_capability( "demux", 10 )
51 set_callbacks( Open
, Close
)
52 add_shortcut( "aiff" )
55 /*****************************************************************************
57 *****************************************************************************/
78 static int Demux ( demux_t
*p_demux
);
79 static int Control( demux_t
*p_demux
, int i_query
, va_list args
);
81 /* GetF80BE: read a 80 bits float in big endian */
82 static unsigned int GetF80BE( const uint8_t p
[10] )
84 unsigned int i_mantissa
= GetDWBE( &p
[2] );
85 int i_exp
= 30 - p
[1];
86 unsigned int i_last
= 0;
100 /*****************************************************************************
102 *****************************************************************************/
103 static int Open( vlc_object_t
*p_this
)
105 demux_t
*p_demux
= (demux_t
*)p_this
;
108 const uint8_t *p_peek
;
110 if( stream_Peek( p_demux
->s
, &p_peek
, 12 ) < 12 )
112 if( memcmp( p_peek
, "FORM", 4 ) || memcmp( &p_peek
[8], "AIFF", 4 ) )
115 /* skip aiff header */
116 stream_Read( p_demux
->s
, NULL
, 12 );
118 /* Fill p_demux field */
119 DEMUX_INIT_COMMON(); p_sys
= p_demux
->p_sys
;
120 es_format_Init( &p_sys
->fmt
, UNKNOWN_ES
, 0 );
122 p_sys
->i_ssnd_pos
= -1;
128 if( stream_Peek( p_demux
->s
, &p_peek
, 8 ) < 8 )
131 i_size
= GetDWBE( &p_peek
[4] );
133 msg_Dbg( p_demux
, "chunk fcc=%4.4s size=%d", p_peek
, i_size
);
135 if( !memcmp( p_peek
, "COMM", 4 ) )
137 if( stream_Peek( p_demux
->s
, &p_peek
, 18+8 ) < 18+8 )
140 es_format_Init( &p_sys
->fmt
, AUDIO_ES
, VLC_FOURCC( 't', 'w', 'o', 's' ) );
141 p_sys
->fmt
.audio
.i_channels
= GetWBE( &p_peek
[8] );
142 p_sys
->fmt
.audio
.i_bitspersample
= GetWBE( &p_peek
[14] );
143 p_sys
->fmt
.audio
.i_rate
= GetF80BE( &p_peek
[16] );
145 msg_Dbg( p_demux
, "COMM: channels=%d samples_frames=%d bits=%d rate=%d",
146 GetWBE( &p_peek
[8] ), GetDWBE( &p_peek
[10] ), GetWBE( &p_peek
[14] ), GetF80BE( &p_peek
[16] ) );
148 else if( !memcmp( p_peek
, "SSND", 4 ) )
150 if( stream_Peek( p_demux
->s
, &p_peek
, 8+8 ) < 8+8 )
153 p_sys
->i_ssnd_pos
= stream_Tell( p_demux
->s
);
154 p_sys
->i_ssnd_size
= i_size
;
155 p_sys
->i_ssnd_offset
= GetDWBE( &p_peek
[8] );
156 p_sys
->i_ssnd_blocksize
= GetDWBE( &p_peek
[12] );
158 msg_Dbg( p_demux
, "SSND: (offset=%d blocksize=%d)",
159 p_sys
->i_ssnd_offset
, p_sys
->i_ssnd_blocksize
);
161 if( p_sys
->i_ssnd_pos
>= 12 && p_sys
->fmt
.i_cat
== AUDIO_ES
)
163 /* We have found the 2 needed chunks */
167 /* Skip this chunk */
169 if( (i_size
% 2) != 0 )
171 if( stream_Read( p_demux
->s
, NULL
, i_size
) != (int)i_size
)
173 msg_Warn( p_demux
, "incomplete file" );
178 p_sys
->i_ssnd_start
= p_sys
->i_ssnd_pos
+ 16 + p_sys
->i_ssnd_offset
;
179 p_sys
->i_ssnd_end
= p_sys
->i_ssnd_start
+ p_sys
->i_ssnd_size
;
181 p_sys
->i_ssnd_fsize
= p_sys
->fmt
.audio
.i_channels
*
182 ((p_sys
->fmt
.audio
.i_bitspersample
+ 7) / 8);
184 if( p_sys
->i_ssnd_fsize
<= 0 )
186 msg_Err( p_demux
, "invalid audio parameters" );
190 if( p_sys
->i_ssnd_size
<= 0 )
193 p_sys
->i_ssnd_end
= 0;
196 /* seek into SSND chunk */
197 if( stream_Seek( p_demux
->s
, p_sys
->i_ssnd_start
) )
199 msg_Err( p_demux
, "cannot seek to data chunk" );
204 p_sys
->es
= es_out_Add( p_demux
->out
, &p_sys
->fmt
);
213 /*****************************************************************************
215 *****************************************************************************/
216 static void Close( vlc_object_t
*p_this
)
218 demux_t
*p_demux
= (demux_t
*)p_this
;
219 demux_sys_t
*p_sys
= p_demux
->p_sys
;
225 /*****************************************************************************
227 *****************************************************************************/
228 static int Demux( demux_t
*p_demux
)
230 demux_sys_t
*p_sys
= p_demux
->p_sys
;
231 int64_t i_tell
= stream_Tell( p_demux
->s
);
236 if( p_sys
->i_ssnd_end
> 0 && i_tell
>= p_sys
->i_ssnd_end
)
243 es_out_Control( p_demux
->out
, ES_OUT_SET_PCR
, VLC_TS_0
+ p_sys
->i_time
);
245 /* we will read 100ms at once */
246 i_read
= p_sys
->i_ssnd_fsize
* ( p_sys
->fmt
.audio
.i_rate
/ 10 );
247 if( p_sys
->i_ssnd_end
> 0 && p_sys
->i_ssnd_end
- i_tell
< i_read
)
249 i_read
= p_sys
->i_ssnd_end
- i_tell
;
251 if( ( p_block
= stream_Block( p_demux
->s
, i_read
) ) == NULL
)
257 p_block
->i_pts
= VLC_TS_0
+ p_sys
->i_time
;
259 p_sys
->i_time
+= (int64_t)1000000 *
261 p_sys
->i_ssnd_fsize
/
262 p_sys
->fmt
.audio
.i_rate
;
265 es_out_Send( p_demux
->out
, p_sys
->es
, p_block
);
269 /*****************************************************************************
271 *****************************************************************************/
272 static int Control( demux_t
*p_demux
, int i_query
, va_list args
)
274 demux_sys_t
*p_sys
= p_demux
->p_sys
;
280 case DEMUX_GET_POSITION
:
282 int64_t i_start
= p_sys
->i_ssnd_start
;
283 int64_t i_end
= p_sys
->i_ssnd_end
> 0 ? p_sys
->i_ssnd_end
: stream_Size( p_demux
->s
);
284 int64_t i_tell
= stream_Tell( p_demux
->s
);
286 pf
= (double*) va_arg( args
, double* );
288 if( i_start
< i_end
)
290 *pf
= (double)(i_tell
- i_start
)/(double)(i_end
- i_start
);
296 case DEMUX_SET_POSITION
:
298 int64_t i_start
= p_sys
->i_ssnd_start
;
299 int64_t i_end
= p_sys
->i_ssnd_end
> 0 ? p_sys
->i_ssnd_end
: stream_Size( p_demux
->s
);
301 f
= (double) va_arg( args
, double );
303 if( i_start
< i_end
)
305 int i_frame
= (f
* ( i_end
- i_start
)) / p_sys
->i_ssnd_fsize
;
306 int64_t i_new
= i_start
+ i_frame
* p_sys
->i_ssnd_fsize
;
308 if( stream_Seek( p_demux
->s
, i_new
) )
312 p_sys
->i_time
= (int64_t)1000000 * i_frame
/ p_sys
->fmt
.audio
.i_rate
;
319 pi64
= (int64_t*)va_arg( args
, int64_t * );
320 *pi64
= p_sys
->i_time
;
323 case DEMUX_GET_LENGTH
:
325 int64_t i_end
= p_sys
->i_ssnd_end
> 0 ? p_sys
->i_ssnd_end
: stream_Size( p_demux
->s
);
327 pi64
= (int64_t*)va_arg( args
, int64_t * );
328 if( p_sys
->i_ssnd_start
< i_end
)
330 *pi64
= (int64_t)1000000 * ( i_end
- p_sys
->i_ssnd_start
) / p_sys
->i_ssnd_fsize
/ p_sys
->fmt
.audio
.i_rate
;