1 /*****************************************************************************
2 * aiff.c: Audio Interchange File Format demuxer
3 *****************************************************************************
4 * Copyright (C) 2004-2007 VLC authors and VideoLAN
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU Lesser General Public License as published by
11 * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with this program; if not, write to the Free Software Foundation,
21 * 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>
41 /*****************************************************************************
43 *****************************************************************************/
44 static int Open ( vlc_object_t
* );
45 static void Close ( vlc_object_t
* );
48 set_category( CAT_INPUT
)
49 set_subcategory( SUBCAT_INPUT_DEMUX
)
50 set_description( N_("AIFF demuxer" ) )
51 set_capability( "demux", 10 )
52 set_callbacks( Open
, Close
)
53 add_shortcut( "aiff" )
56 /*****************************************************************************
58 *****************************************************************************/
79 static int Demux ( demux_t
*p_demux
);
80 static int Control( demux_t
*p_demux
, int i_query
, va_list args
);
82 /* GetF80BE: read a 80 bits float in big endian */
83 static unsigned int GetF80BE( const uint8_t p
[10] )
85 unsigned int i_mantissa
= GetDWBE( &p
[2] );
86 int i_exp
= 30 - p
[1];
87 unsigned int i_last
= 0;
101 /*****************************************************************************
103 *****************************************************************************/
104 static int Open( vlc_object_t
*p_this
)
106 demux_t
*p_demux
= (demux_t
*)p_this
;
109 const uint8_t *p_peek
;
111 if( vlc_stream_Peek( p_demux
->s
, &p_peek
, 12 ) < 12 )
113 if( memcmp( p_peek
, "FORM", 4 ) || memcmp( &p_peek
[8], "AIFF", 4 ) )
116 /* skip aiff header */
117 if( vlc_stream_Read( p_demux
->s
, NULL
, 12 ) < 12 )
120 /* Fill p_demux field */
121 DEMUX_INIT_COMMON(); p_sys
= p_demux
->p_sys
;
122 es_format_Init( &p_sys
->fmt
, AUDIO_ES
, VLC_FOURCC( 't', 'w', 'o', 's' ) );
124 p_sys
->i_ssnd_pos
= -1;
128 if( vlc_stream_Peek( p_demux
->s
, &p_peek
, 8 ) < 8 )
131 uint32_t i_data_size
= GetDWBE( &p_peek
[4] );
132 uint64_t i_chunk_size
= UINT64_C( 8 ) + i_data_size
+ ( i_data_size
& 1 );
134 msg_Dbg( p_demux
, "chunk fcc=%4.4s size=%" PRIu64
" data_size=%" PRIu32
,
135 p_peek
, i_chunk_size
, i_data_size
);
137 if( !memcmp( p_peek
, "COMM", 4 ) )
139 if( vlc_stream_Peek( p_demux
->s
, &p_peek
, 18+8 ) < 18+8 )
142 p_sys
->fmt
.audio
.i_channels
= GetWBE( &p_peek
[8] );
143 p_sys
->fmt
.audio
.i_bitspersample
= GetWBE( &p_peek
[14] );
144 p_sys
->fmt
.audio
.i_rate
= GetF80BE( &p_peek
[16] );
146 msg_Dbg( p_demux
, "COMM: channels=%d samples_frames=%d bits=%d rate=%d",
147 GetWBE( &p_peek
[8] ), GetDWBE( &p_peek
[10] ), GetWBE( &p_peek
[14] ),
148 GetF80BE( &p_peek
[16] ) );
150 else if( !memcmp( p_peek
, "SSND", 4 ) )
152 if( vlc_stream_Peek( p_demux
->s
, &p_peek
, 8+8 ) < 8+8 )
155 p_sys
->i_ssnd_pos
= vlc_stream_Tell( p_demux
->s
);
156 p_sys
->i_ssnd_size
= i_data_size
;
157 p_sys
->i_ssnd_offset
= GetDWBE( &p_peek
[8] );
158 p_sys
->i_ssnd_blocksize
= GetDWBE( &p_peek
[12] );
160 msg_Dbg( p_demux
, "SSND: (offset=%d blocksize=%d)",
161 p_sys
->i_ssnd_offset
, p_sys
->i_ssnd_blocksize
);
163 if( p_sys
->i_ssnd_pos
>= 12 && p_sys
->fmt
.audio
.i_channels
!= 0 )
165 /* We have found the 2 needed chunks */
169 /* consume chunk data */
170 for( ssize_t i_req
; i_chunk_size
; i_chunk_size
-= i_req
)
172 #if SSIZE_MAX < UINT64_MAX
173 i_req
= __MIN( SSIZE_MAX
, i_chunk_size
);
175 i_req
= i_chunk_size
;
177 if( vlc_stream_Read( p_demux
->s
, NULL
, i_req
) != i_req
)
179 msg_Warn( p_demux
, "incomplete file" );
185 p_sys
->i_ssnd_start
= p_sys
->i_ssnd_pos
+ 16 + p_sys
->i_ssnd_offset
;
186 p_sys
->i_ssnd_end
= p_sys
->i_ssnd_start
+ p_sys
->i_ssnd_size
;
188 p_sys
->i_ssnd_fsize
= p_sys
->fmt
.audio
.i_channels
*
189 ((p_sys
->fmt
.audio
.i_bitspersample
+ 7) / 8);
191 if( p_sys
->i_ssnd_fsize
<= 0 || p_sys
->fmt
.audio
.i_rate
== 0 )
193 msg_Err( p_demux
, "invalid audio parameters" );
197 if( p_sys
->i_ssnd_size
<= 0 )
200 p_sys
->i_ssnd_end
= 0;
203 /* seek into SSND chunk */
204 if( vlc_stream_Seek( p_demux
->s
, p_sys
->i_ssnd_start
) )
206 msg_Err( p_demux
, "cannot seek to data chunk" );
211 p_sys
->es
= es_out_Add( p_demux
->out
, &p_sys
->fmt
);
220 /*****************************************************************************
222 *****************************************************************************/
223 static void Close( vlc_object_t
*p_this
)
225 demux_t
*p_demux
= (demux_t
*)p_this
;
226 demux_sys_t
*p_sys
= p_demux
->p_sys
;
232 /*****************************************************************************
234 *****************************************************************************/
235 static int Demux( demux_t
*p_demux
)
237 demux_sys_t
*p_sys
= p_demux
->p_sys
;
238 int64_t i_tell
= vlc_stream_Tell( p_demux
->s
);
243 if( p_sys
->i_ssnd_end
> 0 && i_tell
>= p_sys
->i_ssnd_end
)
250 es_out_SetPCR( p_demux
->out
, VLC_TS_0
+ p_sys
->i_time
);
252 /* we will read 100ms at once */
253 i_read
= p_sys
->i_ssnd_fsize
* ( p_sys
->fmt
.audio
.i_rate
/ 10 );
254 if( p_sys
->i_ssnd_end
> 0 && p_sys
->i_ssnd_end
- i_tell
< i_read
)
256 i_read
= p_sys
->i_ssnd_end
- i_tell
;
258 if( ( p_block
= vlc_stream_Block( p_demux
->s
, i_read
) ) == NULL
)
264 p_block
->i_pts
= VLC_TS_0
+ p_sys
->i_time
;
266 p_sys
->i_time
+= (int64_t)1000000 *
268 p_sys
->i_ssnd_fsize
/
269 p_sys
->fmt
.audio
.i_rate
;
272 es_out_Send( p_demux
->out
, p_sys
->es
, p_block
);
276 /*****************************************************************************
278 *****************************************************************************/
279 static int Control( demux_t
*p_demux
, int i_query
, va_list args
)
281 demux_sys_t
*p_sys
= p_demux
->p_sys
;
288 return vlc_stream_vaControl( p_demux
->s
, i_query
, args
);
290 case DEMUX_GET_POSITION
:
292 int64_t i_start
= p_sys
->i_ssnd_start
;
293 int64_t i_end
= p_sys
->i_ssnd_end
> 0 ? p_sys
->i_ssnd_end
: stream_Size( p_demux
->s
);
294 int64_t i_tell
= vlc_stream_Tell( p_demux
->s
);
296 pf
= va_arg( args
, double * );
298 if( i_start
< i_end
)
300 *pf
= (double)(i_tell
- i_start
)/(double)(i_end
- i_start
);
306 case DEMUX_SET_POSITION
:
308 int64_t i_start
= p_sys
->i_ssnd_start
;
309 int64_t i_end
= p_sys
->i_ssnd_end
> 0 ? p_sys
->i_ssnd_end
: stream_Size( p_demux
->s
);
311 f
= va_arg( args
, double );
313 if( i_start
< i_end
)
315 int i_frame
= (f
* ( i_end
- i_start
)) / p_sys
->i_ssnd_fsize
;
316 int64_t i_new
= i_start
+ i_frame
* p_sys
->i_ssnd_fsize
;
318 if( vlc_stream_Seek( p_demux
->s
, i_new
) )
322 p_sys
->i_time
= (int64_t)1000000 * i_frame
/ p_sys
->fmt
.audio
.i_rate
;
329 pi64
= va_arg( args
, int64_t * );
330 *pi64
= p_sys
->i_time
;
333 case DEMUX_GET_LENGTH
:
335 int64_t i_end
= p_sys
->i_ssnd_end
> 0 ? p_sys
->i_ssnd_end
: stream_Size( p_demux
->s
);
337 pi64
= va_arg( args
, int64_t * );
338 if( p_sys
->i_ssnd_start
< i_end
)
340 *pi64
= (int64_t)1000000 * ( i_end
- p_sys
->i_ssnd_start
) / p_sys
->i_ssnd_fsize
/ p_sys
->fmt
.audio
.i_rate
;
349 case DEMUX_CAN_PAUSE
:
350 case DEMUX_SET_PAUSE_STATE
:
351 case DEMUX_CAN_CONTROL_PACE
:
352 case DEMUX_GET_PTS_DELAY
:
353 return demux_vaControlHelper( p_demux
->s
, 0, -1, 0, 1, i_query
, args
);