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