]> git.sesse.net Git - vlc/blob - modules/demux/au.c
* Stringreview !!!
[vlc] / modules / demux / au.c
1 /*****************************************************************************
2  * au.c : au file input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001-2003 VideoLAN
5  * $Id: au.c,v 1.12 2004/01/25 20:05:28 hartman Exp $
6  *
7  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
8  *
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.
13  *
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.
18  *
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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28
29 #include <vlc/vlc.h>
30 #include <vlc/input.h>
31
32 #include <codecs.h>
33
34 /*****************************************************************************
35  * Module descriptor
36  *****************************************************************************/
37 static int  Open    ( vlc_object_t * );
38 static void Close  ( vlc_object_t * );
39
40 vlc_module_begin();
41     set_description( _("AU demuxer") );
42     set_capability( "demux", 142 );
43     set_callbacks( Open, Close );
44 vlc_module_end();
45
46 /*
47  * TODO:
48  *  - all adpcm things (I _NEED_ samples)
49  */
50
51 /*****************************************************************************
52  * Local prototypes
53  *****************************************************************************/
54 static int    DemuxPCM   ( input_thread_t * );
55 /* TODO static int    DemuxADPCM   ( input_thread_t * ); */
56
57 enum AuType_e
58 {
59     AU_UNKNOWN      =  0,
60     AU_MULAW_8      =  1,  /* 8-bit ISDN u-law */
61     AU_LINEAR_8     =  2,  /* 8-bit linear PCM */
62     AU_LINEAR_16    =  3,  /* 16-bit linear PCM */
63     AU_LINEAR_24    =  4,  /* 24-bit linear PCM */
64     AU_LINEAR_32    =  5,  /* 32-bit linear PCM */
65     AU_FLOAT        =  6,  /* 32-bit IEEE floating point */
66     AU_DOUBLE       =  7,  /* 64-bit IEEE floating point */
67     AU_ADPCM_G721   =  23, /* 4-bit CCITT g.721 ADPCM */
68     AU_ADPCM_G722   =  24, /* CCITT g.722 ADPCM */
69     AU_ADPCM_G723_3 =  25, /* CCITT g.723 3-bit ADPCM */
70     AU_ADPCM_G723_5 =  26, /* CCITT g.723 5-bit ADPCM */
71     AU_ALAW_8       =  27  /* 8-bit ISDN A-law */
72 };
73
74 enum AuCat_e
75 {
76     AU_CAT_UNKNOWN  = 0,
77     AU_CAT_PCM      = 1,
78     AU_CAT_ADPCM    = 2
79 };
80
81 typedef struct
82 #ifdef HAVE_ATTRIBUTE_PACKED
83     __attribute__((__packed__))
84 #endif
85 {
86     uint32_t    i_header_size;
87     uint32_t    i_data_size;
88     uint32_t    i_encoding;
89     uint32_t    i_sample_rate;
90     uint32_t    i_channels;
91 } au_t;
92
93 struct demux_sys_t
94 {
95     au_t            au;
96
97     mtime_t         i_time;
98
99     es_format_t     fmt;
100     es_out_id_t     *p_es;
101
102     int             i_frame_size;
103     mtime_t         i_frame_length;
104 };
105
106
107 /*****************************************************************************
108  * Open: check file and initializes structures
109  *****************************************************************************/
110 static int Open( vlc_object_t * p_this )
111 {
112     input_thread_t *p_input = (input_thread_t *)p_this;
113     demux_sys_t    *p_sys;
114
115     uint8_t         *p_peek;
116
117     int             i_cat;
118
119     /* a little test to see if it's a au file */
120     if( input_Peek( p_input, &p_peek, 4 ) < 4 )
121     {
122         msg_Warn( p_input, "AU module discarded (cannot peek)" );
123         return VLC_EGENERIC;
124     }
125     if( strncmp( p_peek, ".snd", 4 ) )
126     {
127         msg_Warn( p_input, "AU module discarded (not a valid file)" );
128         return VLC_EGENERIC;
129     }
130
131     p_input->p_demux_data = p_sys = malloc( sizeof( demux_sys_t ) );
132     p_sys->i_time = 0;
133
134     /* skip signature */
135     stream_Read( p_input->s, NULL, 4 );   /* cannot fail */
136
137     /* read header */
138     if( stream_Read( p_input->s, &p_sys->au, sizeof(au_t) )<(int)sizeof(au_t) )
139     {
140         msg_Err( p_input, "cannot load header" );
141         goto error;
142     }
143     p_sys->au.i_header_size   = GetDWBE( &p_sys->au.i_header_size );
144     p_sys->au.i_data_size     = GetDWBE( &p_sys->au.i_data_size );
145     p_sys->au.i_encoding      = GetDWBE( &p_sys->au.i_encoding );
146     p_sys->au.i_sample_rate   = GetDWBE( &p_sys->au.i_sample_rate );
147     p_sys->au.i_channels      = GetDWBE( &p_sys->au.i_channels );
148
149     msg_Dbg( p_input,
150              "au file: header_size=%d data_size=%d encoding=0x%x sample_rate=%d channels=%d",
151              p_sys->au.i_header_size,
152              p_sys->au.i_data_size,
153              p_sys->au.i_encoding,
154              p_sys->au.i_sample_rate,
155              p_sys->au.i_channels );
156
157     if( p_sys->au.i_header_size < 24 )
158     {
159         msg_Warn( p_input, "AU module discarded (not a valid file)" );
160         goto error;
161     }
162
163     /* skip extra header data */
164     if( p_sys->au.i_header_size > 4 + sizeof( au_t ) )
165     {
166         stream_Read( p_input->s,
167                      NULL, p_sys->au.i_header_size - 4 - sizeof( au_t ) );
168     }
169
170     /* Create WAVEFORMATEX structure */
171     es_format_Init( &p_sys->fmt, AUDIO_ES, 0 );
172     p_sys->fmt.audio.i_channels   = p_sys->au.i_channels;
173     p_sys->fmt.audio.i_rate = p_sys->au.i_sample_rate;
174     switch( p_sys->au.i_encoding )
175     {
176         case AU_ALAW_8:        /* 8-bit ISDN A-law */
177             p_sys->fmt.i_codec               = VLC_FOURCC( 'a','l','a','w' );
178             p_sys->fmt.audio.i_bitspersample = 8;
179             p_sys->fmt.audio.i_blockalign    = 1 * p_sys->fmt.audio.i_channels;
180             i_cat                    = AU_CAT_PCM;
181             break;
182
183         case AU_MULAW_8:       /* 8-bit ISDN u-law */
184             p_sys->fmt.i_codec               = VLC_FOURCC( 'u','l','a','w' );
185             p_sys->fmt.audio.i_bitspersample = 8;
186             p_sys->fmt.audio.i_blockalign    = 1 * p_sys->fmt.audio.i_channels;
187             i_cat                    = AU_CAT_PCM;
188             break;
189
190         case AU_LINEAR_8:      /* 8-bit linear PCM */
191             p_sys->fmt.i_codec               = VLC_FOURCC( 't','w','o','s' );
192             p_sys->fmt.audio.i_bitspersample = 8;
193             p_sys->fmt.audio.i_blockalign    = 1 * p_sys->fmt.audio.i_channels;
194             i_cat                    = AU_CAT_PCM;
195             break;
196
197         case AU_LINEAR_16:     /* 16-bit linear PCM */
198             p_sys->fmt.i_codec               = VLC_FOURCC( 't','w','o','s' );
199             p_sys->fmt.audio.i_bitspersample = 16;
200             p_sys->fmt.audio.i_blockalign    = 2 * p_sys->fmt.audio.i_channels;
201             i_cat                    = AU_CAT_PCM;
202             break;
203
204         case AU_LINEAR_24:     /* 24-bit linear PCM */
205             p_sys->fmt.i_codec               = VLC_FOURCC( 't','w','o','s' );
206             p_sys->fmt.audio.i_bitspersample = 24;
207             p_sys->fmt.audio.i_blockalign    = 3 * p_sys->fmt.audio.i_channels;
208             i_cat                    = AU_CAT_PCM;
209             break;
210
211         case AU_LINEAR_32:     /* 32-bit linear PCM */
212             p_sys->fmt.i_codec               = VLC_FOURCC( 't','w','o','s' );
213             p_sys->fmt.audio.i_bitspersample = 32;
214             p_sys->fmt.audio.i_blockalign    = 4 * p_sys->fmt.audio.i_channels;
215             i_cat                    = AU_CAT_PCM;
216             break;
217
218         case AU_FLOAT:         /* 32-bit IEEE floating point */
219             p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_FLOAT );
220             p_sys->fmt.audio.i_bitspersample = 32;
221             p_sys->fmt.audio.i_blockalign    = 4 * p_sys->fmt.audio.i_channels;
222             i_cat                    = AU_CAT_PCM;
223             break;
224
225         case AU_DOUBLE:        /* 64-bit IEEE floating point */
226             p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_DOUBLE );
227             p_sys->fmt.audio.i_bitspersample = 64;
228             p_sys->fmt.audio.i_blockalign    = 8 * p_sys->fmt.audio.i_channels;
229             i_cat                    = AU_CAT_PCM;
230             break;
231
232         case AU_ADPCM_G721:    /* 4-bit CCITT g.721 ADPCM */
233             p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G721 );
234             p_sys->fmt.audio.i_bitspersample = 0;
235             p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
236             i_cat                    = AU_CAT_ADPCM;
237             break;
238
239         case AU_ADPCM_G722:    /* CCITT g.722 ADPCM */
240             p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G722 );
241             p_sys->fmt.audio.i_bitspersample = 0;
242             p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
243             i_cat                    = AU_CAT_ADPCM;
244             break;
245
246         case AU_ADPCM_G723_3:  /* CCITT g.723 3-bit ADPCM */
247             p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G723_3 );
248             p_sys->fmt.audio.i_bitspersample = 0;
249             p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
250             i_cat                    = AU_CAT_ADPCM;
251             break;
252
253         case AU_ADPCM_G723_5:  /* CCITT g.723 5-bit ADPCM */
254             p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G723_5 );
255             p_sys->fmt.audio.i_bitspersample = 0;
256             p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
257             i_cat                    = AU_CAT_ADPCM;
258             break;
259
260         default:
261             msg_Warn( p_input, "unknow encoding=0x%x", p_sys->au.i_encoding );
262             i_cat                    = AU_CAT_UNKNOWN;
263             goto error;
264     }
265     p_sys->fmt.i_bitrate = p_sys->fmt.audio.i_rate *
266                            p_sys->fmt.audio.i_channels *
267                            p_sys->fmt.audio.i_bitspersample;
268
269     if( i_cat == AU_CAT_UNKNOWN || i_cat == AU_CAT_ADPCM )
270     {
271         p_sys->i_frame_size = 0;
272         p_sys->i_frame_length = 0;
273
274         msg_Err( p_input, "unsupported codec/type (Please report it)" );
275         goto error;
276     }
277     else
278     {
279         int i_samples, i_modulo;
280
281         /* read samples for 50ms of */
282         i_samples = __MAX( p_sys->fmt.audio.i_rate / 20, 1 );
283
284         p_sys->i_frame_size = i_samples * p_sys->fmt.audio.i_channels * ( (p_sys->fmt.audio.i_bitspersample + 7) / 8 );
285
286         if( p_sys->fmt.audio.i_blockalign > 0 )
287         {
288             if( ( i_modulo = p_sys->i_frame_size % p_sys->fmt.audio.i_blockalign ) != 0 )
289             {
290                 p_sys->i_frame_size += p_sys->fmt.audio.i_blockalign - i_modulo;
291             }
292         }
293
294         p_sys->i_frame_length = (mtime_t)1000000 *
295                                 (mtime_t)i_samples /
296                                 (mtime_t)p_sys->fmt.audio.i_rate;
297
298         p_input->pf_demux = DemuxPCM;
299         p_input->pf_demux_control = demux_vaControlDefault;
300     }
301
302     vlc_mutex_lock( &p_input->stream.stream_lock );
303     if( input_InitStream( p_input, 0 ) == -1)
304     {
305         vlc_mutex_unlock( &p_input->stream.stream_lock );
306         msg_Err( p_input, "cannot init stream" );
307         goto error;
308     }
309     p_input->stream.i_mux_rate =  p_sys->fmt.i_bitrate / 50 / 8;
310     vlc_mutex_unlock( &p_input->stream.stream_lock );
311
312     p_sys->p_es = es_out_Add( p_input->p_es_out, &p_sys->fmt );
313     return VLC_SUCCESS;
314
315 error:
316     free( p_sys );
317     return VLC_EGENERIC;
318 }
319
320 /*****************************************************************************
321  * DemuxPCM: read packet and send them to decoders
322  *****************************************************************************
323  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
324  *****************************************************************************/
325 static int DemuxPCM( input_thread_t *p_input )
326 {
327     demux_sys_t  *p_sys = p_input->p_demux_data;
328     block_t *p_block;
329
330     if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
331     {
332         int64_t i_pos = stream_Tell( p_input->s );
333
334         if( p_sys->fmt.audio.i_blockalign != 0 )
335         {
336             i_pos += p_sys->fmt.audio.i_blockalign - i_pos % p_sys->fmt.audio.i_blockalign;
337             if( stream_Seek( p_input->s, i_pos ) )
338             {
339                 msg_Err( p_input, "seek failed (cannot resync)" );
340             }
341         }
342     }
343
344     input_ClockManageRef( p_input,
345                           p_input->stream.p_selected_program,
346                           p_sys->i_time * 9 / 100 );
347
348     if( ( p_block = stream_Block( p_input->s, p_sys->i_frame_size ) ) == NULL )
349     {
350         msg_Warn( p_input, "cannot read data" );
351         return 0;
352     }
353     p_block->i_dts =
354     p_block->i_pts = input_ClockGetTS( p_input,
355                                      p_input->stream.p_selected_program,
356                                      p_sys->i_time * 9 / 100 );
357
358     es_out_Send( p_input->p_es_out, p_sys->p_es, p_block );
359
360     p_sys->i_time += p_sys->i_frame_length;
361
362     return( 1 );
363 }
364
365 /*****************************************************************************
366  * Close: frees unused data
367  *****************************************************************************/
368 static void Close( vlc_object_t * p_this )
369 {
370     input_thread_t *p_input = (input_thread_t *)p_this;
371     demux_sys_t    *p_sys = p_input->p_demux_data;
372
373     free( p_sys );
374 }
375