]> git.sesse.net Git - vlc/blob - modules/demux/au.c
* configure.ac: remove old wav and aac directories.
[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.3 2003/08/01 00:05:57 fenrir 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 #include <ninput.h>
34
35 /*****************************************************************************
36  * Module descriptor
37  *****************************************************************************/
38 static int  Open    ( vlc_object_t * );
39 static void Close  ( vlc_object_t * );
40
41 vlc_module_begin();
42     set_description( _("AU demuxer") );
43     set_capability( "demux", 142 );
44     set_callbacks( Open, Close );
45 vlc_module_end();
46
47 /*
48  * TODO:
49  *  - all adpcm things (I _NEED_ samples)
50  */
51
52 /*****************************************************************************
53  * Local prototypes
54  *****************************************************************************/
55 static int    DemuxPCM   ( input_thread_t * );
56 /* TODO static int    DemuxADPCM   ( input_thread_t * ); */
57
58 #define GetDWBE( p ) __GetDWBE( (uint8_t*)(p) )
59 static inline uint32_t __GetDWBE( uint8_t *p )
60 {
61     return( ( p[0] << 24 ) + ( p[1] << 16 ) + ( p[2] << 8 ) + p[3] );
62 }
63
64 enum AuType_e
65 {
66     AU_UNKNOWN      =  0,
67     AU_MULAW_8      =  1,  /* 8-bit ISDN u-law */
68     AU_LINEAR_8     =  2,  /* 8-bit linear PCM */
69     AU_LINEAR_16    =  3,  /* 16-bit linear PCM */
70     AU_LINEAR_24    =  4,  /* 24-bit linear PCM */
71     AU_LINEAR_32    =  5,  /* 32-bit linear PCM */
72     AU_FLOAT        =  6,  /* 32-bit IEEE floating point */
73     AU_DOUBLE       =  7,  /* 64-bit IEEE floating point */
74     AU_ADPCM_G721   =  23, /* 4-bit CCITT g.721 ADPCM */
75     AU_ADPCM_G722   =  24, /* CCITT g.722 ADPCM */
76     AU_ADPCM_G723_3 =  25, /* CCITT g.723 3-bit ADPCM */
77     AU_ADPCM_G723_5 =  26, /* CCITT g.723 5-bit ADPCM */
78     AU_ALAW_8       =  27  /* 8-bit ISDN A-law */
79 };
80
81 enum AuCat_e
82 {
83     AU_CAT_UNKNOWN  = 0,
84     AU_CAT_PCM      = 1,
85     AU_CAT_ADPCM    = 2
86 };
87
88 typedef struct
89 #ifdef HAVE_ATTRIBUTE_PACKED
90     __attribute__((__packed__))
91 #endif
92 {
93     uint32_t    i_header_size;
94     uint32_t    i_data_size;
95     uint32_t    i_encoding;
96     uint32_t    i_sample_rate;
97     uint32_t    i_channels;
98 } au_t;
99
100 struct demux_sys_t
101 {
102     stream_t        *s;
103
104     au_t            au;
105     WAVEFORMATEX    wf;
106
107     mtime_t         i_time;
108
109     es_descriptor_t *p_es;
110
111     int             i_frame_size;
112     mtime_t         i_frame_length;
113 };
114
115
116 /*****************************************************************************
117  * Open: check file and initializes structures
118  *****************************************************************************/
119 static int Open( vlc_object_t * p_this )
120 {
121     input_thread_t *p_input = (input_thread_t *)p_this;
122     demux_sys_t    *p_sys;
123
124     uint8_t         *p_peek;
125
126     vlc_fourcc_t    i_fourcc;
127
128     int             i_cat;
129
130     /* a little test to see if it's a au file */
131     if( input_Peek( p_input, &p_peek, 4 ) < 4 )
132     {
133         msg_Warn( p_input, "AU module discarded (cannot peek)" );
134         return VLC_EGENERIC;
135     }
136     if( strncmp( p_peek, ".snd", 4 ) )
137     {
138         msg_Warn( p_input, "AU module discarded (not a valid file)" );
139         return VLC_EGENERIC;
140     }
141
142     p_input->p_demux_data = p_sys = malloc( sizeof( demux_sys_t ) );
143     p_sys->i_time = 0;
144
145
146     if( ( p_sys->s = stream_OpenInput( p_input ) ) == NULL )
147     {
148         msg_Err( p_input, "cannot create stream" );
149         goto error;
150     }
151
152     /* skip signature */
153     stream_Read( p_sys->s, NULL, 4 );   /* cannot fail */
154
155     /* read header */
156     if( stream_Read( p_sys->s, &p_sys->au, sizeof( au_t ) ) < (int)sizeof( au_t ) )
157     {
158         msg_Err( p_input, "cannot load header" );
159         goto error;
160     }
161     p_sys->au.i_header_size   = GetDWBE( &p_sys->au.i_header_size );
162     p_sys->au.i_data_size     = GetDWBE( &p_sys->au.i_data_size );
163     p_sys->au.i_encoding      = GetDWBE( &p_sys->au.i_encoding );
164     p_sys->au.i_sample_rate   = GetDWBE( &p_sys->au.i_sample_rate );
165     p_sys->au.i_channels      = GetDWBE( &p_sys->au.i_channels );
166
167     msg_Dbg( p_input,
168              "au file: header_size=%d data_size=%d encoding=0x%x sample_rate=%d channels=%d",
169              p_sys->au.i_header_size,
170              p_sys->au.i_data_size,
171              p_sys->au.i_encoding,
172              p_sys->au.i_sample_rate,
173              p_sys->au.i_channels );
174
175     if( p_sys->au.i_header_size < 24 )
176     {
177         msg_Warn( p_input, "AU module discarded (not a valid file)" );
178         goto error;
179     }
180
181     /* skip extra header data */
182     if( p_sys->au.i_header_size > 4 + sizeof( au_t ) )
183     {
184         stream_Read( p_sys->s, NULL, p_sys->au.i_header_size - 4 - sizeof( au_t ) );
185     }
186
187     /* Create WAVEFORMATEX structure */
188     p_sys->wf.nChannels     = p_sys->au.i_channels;
189     p_sys->wf.nSamplesPerSec= p_sys->au.i_sample_rate;
190     p_sys->wf.cbSize        = 0;
191
192     switch( p_sys->au.i_encoding )
193     {
194         case AU_ALAW_8:        /* 8-bit ISDN A-law */
195             p_sys->wf.wFormatTag     = WAVE_FORMAT_ALAW;   // FIXME ??
196             p_sys->wf.wBitsPerSample = 8;
197             p_sys->wf.nBlockAlign    = 1 * p_sys->wf.nChannels;
198             i_fourcc                 = VLC_FOURCC( 'a','l','a','w' );
199             i_cat                    = AU_CAT_PCM;
200             break;
201
202         case AU_MULAW_8:       /* 8-bit ISDN u-law */
203             p_sys->wf.wFormatTag     = WAVE_FORMAT_MULAW;   // FIXME ??
204             p_sys->wf.wBitsPerSample = 8;
205             p_sys->wf.nBlockAlign    = 1 * p_sys->wf.nChannels;
206             i_fourcc                 = VLC_FOURCC( 'u','l','a','w' );
207             i_cat                    = AU_CAT_PCM;
208             break;
209
210         case AU_LINEAR_8:      /* 8-bit linear PCM */
211             p_sys->wf.wFormatTag     = WAVE_FORMAT_PCM;
212             p_sys->wf.wBitsPerSample = 8;
213             p_sys->wf.nBlockAlign    = 1 * p_sys->wf.nChannels;
214             i_fourcc                 = VLC_FOURCC( 't','w','o','s' );
215             i_cat                    = AU_CAT_PCM;
216             break;
217
218         case AU_LINEAR_16:     /* 16-bit linear PCM */
219             p_sys->wf.wFormatTag     = WAVE_FORMAT_PCM;
220             p_sys->wf.wBitsPerSample = 16;
221             p_sys->wf.nBlockAlign    = 2 * p_sys->wf.nChannels;
222             i_fourcc                 = VLC_FOURCC( 't','w','o','s' );
223             i_cat                    = AU_CAT_PCM;
224             break;
225
226         case AU_LINEAR_24:     /* 24-bit linear PCM */
227             p_sys->wf.wFormatTag     = WAVE_FORMAT_PCM;
228             p_sys->wf.wBitsPerSample = 24;
229             p_sys->wf.nBlockAlign    = 3 * p_sys->wf.nChannels;
230             i_fourcc                 = VLC_FOURCC( 't','w','o','s' );
231             i_cat                    = AU_CAT_PCM;
232             break;
233
234         case AU_LINEAR_32:     /* 32-bit linear PCM */
235             p_sys->wf.wFormatTag     = WAVE_FORMAT_PCM;
236             p_sys->wf.wBitsPerSample = 32;
237             p_sys->wf.nBlockAlign    = 4 * p_sys->wf.nChannels;
238             i_fourcc                 = VLC_FOURCC( 't','w','o','s' );
239             i_cat                    = AU_CAT_PCM;
240             break;
241
242         case AU_FLOAT:         /* 32-bit IEEE floating point */
243             p_sys->wf.wFormatTag     = WAVE_FORMAT_UNKNOWN;
244             p_sys->wf.wBitsPerSample = 32;
245             p_sys->wf.nBlockAlign    = 4 * p_sys->wf.nChannels;
246             i_fourcc                  = VLC_FOURCC( 'a', 'u', 0, AU_FLOAT );
247             i_cat                    = AU_CAT_PCM;
248             break;
249
250         case AU_DOUBLE:        /* 64-bit IEEE floating point */
251             p_sys->wf.wFormatTag     = WAVE_FORMAT_UNKNOWN;
252             p_sys->wf.wBitsPerSample = 64;
253             p_sys->wf.nBlockAlign    = 8 * p_sys->wf.nChannels;
254             i_fourcc                 = VLC_FOURCC( 'a', 'u', 0, AU_DOUBLE );
255             i_cat                    = AU_CAT_PCM;
256             break;
257
258         case AU_ADPCM_G721:    /* 4-bit CCITT g.721 ADPCM */
259             p_sys->wf.wFormatTag     = WAVE_FORMAT_UNKNOWN;
260             p_sys->wf.wBitsPerSample = 0;
261             p_sys->wf.nBlockAlign    = 0 * p_sys->wf.nChannels;
262             i_fourcc                 = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G721 );
263             i_cat                    = AU_CAT_ADPCM;
264             break;
265
266         case AU_ADPCM_G722:    /* CCITT g.722 ADPCM */
267             p_sys->wf.wFormatTag     = WAVE_FORMAT_UNKNOWN;
268             p_sys->wf.wBitsPerSample = 0;
269             p_sys->wf.nBlockAlign    = 0 * p_sys->wf.nChannels;
270             i_fourcc                 = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G722 );
271             i_cat                    = AU_CAT_ADPCM;
272             break;
273
274         case AU_ADPCM_G723_3:  /* CCITT g.723 3-bit ADPCM */
275             p_sys->wf.wFormatTag     = WAVE_FORMAT_UNKNOWN;
276             p_sys->wf.wBitsPerSample = 0;
277             p_sys->wf.nBlockAlign    = 0 * p_sys->wf.nChannels;
278             i_fourcc                 = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G723_3 );
279             i_cat                    = AU_CAT_ADPCM;
280             break;
281
282         case AU_ADPCM_G723_5:  /* CCITT g.723 5-bit ADPCM */
283             p_sys->wf.wFormatTag     = WAVE_FORMAT_UNKNOWN;
284             p_sys->wf.wBitsPerSample = 0;
285             p_sys->wf.nBlockAlign    = 0 * p_sys->wf.nChannels;
286             i_fourcc                 = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G723_5 );
287             i_cat                    = AU_CAT_ADPCM;
288             break;
289
290         default:
291             msg_Warn( p_input, "unknow encoding=0x%x", p_sys->au.i_encoding );
292             i_cat                    = AU_CAT_UNKNOWN;
293             goto error;
294     }
295     p_sys->wf.nAvgBytesPerSec        = p_sys->wf.nSamplesPerSec * p_sys->wf.nChannels * p_sys->wf.wBitsPerSample / 8;
296
297
298
299     if( i_cat == AU_CAT_UNKNOWN || i_cat == AU_CAT_ADPCM )
300     {
301         p_sys->i_frame_size = 0;
302         p_sys->i_frame_length = 0;
303
304         msg_Err( p_input, "unsupported codec/type (Please report it)" );
305         goto error;
306     }
307     else
308     {
309         int i_samples, i_modulo;
310
311         /* read samples for 50ms of */
312         i_samples = __MAX( p_sys->wf.nSamplesPerSec / 20, 1 );
313
314         p_sys->i_frame_size = i_samples * p_sys->wf.nChannels * ( (p_sys->wf.wBitsPerSample + 7) / 8 );
315
316         if( p_sys->wf.nBlockAlign > 0 )
317         {
318             if( ( i_modulo = p_sys->i_frame_size % p_sys->wf.nBlockAlign ) != 0 )
319             {
320                 p_sys->i_frame_size += p_sys->wf.nBlockAlign - i_modulo;
321             }
322         }
323
324         p_sys->i_frame_length = (mtime_t)1000000 *
325                                 (mtime_t)i_samples /
326                                 (mtime_t)p_sys->wf.nSamplesPerSec;
327
328         p_input->pf_demux = DemuxPCM;
329     }
330
331     /*  create one program */
332     vlc_mutex_lock( &p_input->stream.stream_lock );
333     if( input_InitStream( p_input, 0 ) == -1)
334     {
335         vlc_mutex_unlock( &p_input->stream.stream_lock );
336         msg_Err( p_input, "cannot init stream" );
337         goto error;
338     }
339     if( input_AddProgram( p_input, 0, 0) == NULL )
340     {
341         vlc_mutex_unlock( &p_input->stream.stream_lock );
342         msg_Err( p_input, "cannot add program" );
343         goto error;
344     }
345
346     p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
347     p_input->stream.i_mux_rate =  p_sys->wf.nAvgBytesPerSec / 50;
348
349     p_sys->p_es = input_AddES( p_input, p_input->stream.p_selected_program,
350                                0x01, AUDIO_ES, NULL, 0 );
351
352     p_sys->p_es->i_stream_id   = 0x01;
353     p_sys->p_es->i_fourcc      = i_fourcc;
354     p_sys->p_es->p_waveformatex= malloc( sizeof( WAVEFORMATEX ) );
355     memcpy( p_sys->p_es->p_waveformatex, &p_sys->wf, sizeof( WAVEFORMATEX ) );
356
357     input_SelectES( p_input, p_sys->p_es );
358
359     p_input->stream.p_selected_program->b_is_ok = 1;
360     vlc_mutex_unlock( &p_input->stream.stream_lock );
361
362     return VLC_SUCCESS;
363
364 error:
365     if( p_sys->s )
366     {
367         stream_Release( p_sys->s );
368     }
369     free( p_sys );
370     return VLC_EGENERIC;
371 }
372
373 /*****************************************************************************
374  * DemuxPCM: read packet and send them to decoders
375  *****************************************************************************
376  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
377  *****************************************************************************/
378 static int DemuxPCM( input_thread_t *p_input )
379 {
380     demux_sys_t  *p_sys = p_input->p_demux_data;
381     pes_packet_t *p_pes;
382
383     if( p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT )
384     {
385         int64_t i_pos;
386
387         stream_Control( p_sys->s, STREAM_GET_POSITION, &i_pos );
388         if( p_sys->wf.nBlockAlign != 0 )
389         {
390             i_pos += p_sys->wf.nBlockAlign - i_pos % p_sys->wf.nBlockAlign;
391             if( stream_Control( p_sys->s, STREAM_SET_POSITION, i_pos ) )
392             {
393                 msg_Err( p_input, "STREAM_SET_POSITION failed (cannot resync)" );
394             }
395         }
396     }
397
398     input_ClockManageRef( p_input,
399                           p_input->stream.p_selected_program,
400                           p_sys->i_time * 9 / 100 );
401
402     if( ( p_pes = stream_PesPacket( p_sys->s, p_sys->i_frame_size ) ) == NULL )
403     {
404         msg_Warn( p_input, "cannot read data" );
405         return 0;
406     }
407     p_pes->i_dts =
408     p_pes->i_pts = input_ClockGetTS( p_input,
409                                      p_input->stream.p_selected_program,
410                                      p_sys->i_time * 9 / 100 );
411
412     if( !p_sys->p_es->p_decoder_fifo )
413     {
414         msg_Err( p_input, "no audio decoder" );
415         input_DeletePES( p_input->p_method_data, p_pes );
416         return( -1 );
417     }
418
419     input_DecodePES( p_sys->p_es->p_decoder_fifo, p_pes );
420     p_sys->i_time += p_sys->i_frame_length;
421     return( 1 );
422 }
423
424 /*****************************************************************************
425  * Close: frees unused data
426  *****************************************************************************/
427 static void Close( vlc_object_t * p_this )
428 {
429     input_thread_t *p_input = (input_thread_t *)p_this;
430     demux_sys_t    *p_sys = p_input->p_demux_data;
431
432     stream_Release( p_sys->s );
433     free( p_sys );
434 }
435