]> git.sesse.net Git - vlc/blob - modules/demux/au.c
- Fix a bunch of warnings
[vlc] / modules / demux / au.c
1 /*****************************************************************************
2  * au.c : au file input module for vlc
3  *****************************************************************************
4  * Copyright (C) 2001-2007 the VideoLAN team
5  * $Id$
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., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #include <stdlib.h>                                      /* malloc(), free() */
28
29 #include <vlc/vlc.h>
30 #include <vlc_demux.h>
31
32 /* TODO:
33  *  - all adpcm things (I _NEED_ samples)
34  *  - ...
35  */
36
37 /*****************************************************************************
38  * Module descriptor
39  *****************************************************************************/
40 static int  Open ( vlc_object_t * );
41 static void Close( vlc_object_t * );
42
43 vlc_module_begin();
44     set_category( CAT_INPUT );
45     set_subcategory( SUBCAT_INPUT_DEMUX );
46     set_description( _("AU demuxer") );
47     set_capability( "demux2", 10 );
48     set_callbacks( Open, Close );
49     add_shortcut( "au" );
50 vlc_module_end();
51
52 /*****************************************************************************
53  * Local prototypes
54  *****************************************************************************/
55 enum AuType_e
56 {
57     AU_UNKNOWN      =  0,
58     AU_MULAW_8      =  1,  /* 8-bit ISDN u-law */
59     AU_LINEAR_8     =  2,  /* 8-bit linear PCM */
60     AU_LINEAR_16    =  3,  /* 16-bit linear PCM */
61     AU_LINEAR_24    =  4,  /* 24-bit linear PCM */
62     AU_LINEAR_32    =  5,  /* 32-bit linear PCM */
63     AU_FLOAT        =  6,  /* 32-bit IEEE floating point */
64     AU_DOUBLE       =  7,  /* 64-bit IEEE floating point */
65     AU_ADPCM_G721   =  23, /* 4-bit CCITT g.721 ADPCM */
66     AU_ADPCM_G722   =  24, /* CCITT g.722 ADPCM */
67     AU_ADPCM_G723_3 =  25, /* CCITT g.723 3-bit ADPCM */
68     AU_ADPCM_G723_5 =  26, /* CCITT g.723 5-bit ADPCM */
69     AU_ALAW_8       =  27  /* 8-bit ISDN A-law */
70 };
71
72 enum AuCat_e
73 {
74     AU_CAT_UNKNOWN  = 0,
75     AU_CAT_PCM      = 1,
76     AU_CAT_ADPCM    = 2
77 };
78
79 struct demux_sys_t
80 {
81     es_format_t     fmt;
82     es_out_id_t     *es;
83
84     mtime_t         i_time;
85
86     int             i_frame_size;
87     mtime_t         i_frame_length;
88
89     int             i_header_size;
90 };
91
92 static int Demux( demux_t * );
93 static int Control ( demux_t *, int i_query, va_list args );
94
95 /*****************************************************************************
96  * Open: check file and initializes structures
97  *****************************************************************************/
98 static int Open( vlc_object_t *p_this )
99 {
100     demux_t     *p_demux = (demux_t*)p_this;
101     demux_sys_t *p_sys;
102
103     uint8_t      hdr[20];
104     const uint8_t *p_peek;
105     int          i_cat;
106     int          i_samples, i_modulo;
107
108     CHECK_PEEK( p_peek, 4 );
109
110     if( memcmp( p_peek, ".snd", 4 ) )
111     {
112         return VLC_EGENERIC;
113     }
114
115     /* skip signature */
116     stream_Read( p_demux->s, NULL, 4 );   /* cannot fail */
117
118     /* read header */
119     if( stream_Read( p_demux->s, hdr, 20 ) < 20 )
120     {
121         msg_Err( p_demux, "cannot read" );
122         return VLC_EGENERIC;
123     }
124
125     if( GetDWBE( &hdr[0]  ) < 24 )
126     {
127         msg_Err( p_demux, "invalid file" );
128         return VLC_EGENERIC;
129     }
130
131     STANDARD_DEMUX_INIT; p_sys = p_demux->p_sys;
132     p_sys->i_time = 1;
133     p_sys->i_header_size = GetDWBE( &hdr[0] );
134
135     /* skip extra header data */
136     if( p_sys->i_header_size > 24 )
137     {
138         stream_Read( p_demux->s, NULL, p_sys->i_header_size - 24 );
139     }
140
141     /* init fmt */
142     es_format_Init( &p_sys->fmt, AUDIO_ES, 0 );
143     p_sys->fmt.audio.i_rate     = GetDWBE( &hdr[12] );
144     p_sys->fmt.audio.i_channels = GetDWBE( &hdr[16] );
145
146 #if 0
147     p_sys->au.i_header_size   = GetDWBE( &p_sys->au.i_header_size );
148     p_sys->au.i_data_size     = GetDWBE( &p_sys->au.i_data_size );
149     p_sys->au.i_encoding      = GetDWBE( &p_sys->au.i_encoding );
150     p_sys->au.i_sample_rate   = GetDWBE( &p_sys->au.i_sample_rate );
151     p_sys->au.i_channels      = GetDWBE( &p_sys->au.i_channels );
152 #endif
153     switch( GetDWBE( &hdr[8] ) )
154     {
155         case AU_ALAW_8:        /* 8-bit ISDN A-law */
156             p_sys->fmt.i_codec               = VLC_FOURCC( 'a','l','a','w' );
157             p_sys->fmt.audio.i_bitspersample = 8;
158             p_sys->fmt.audio.i_blockalign    = 1 * p_sys->fmt.audio.i_channels;
159             i_cat                    = AU_CAT_PCM;
160             break;
161
162         case AU_MULAW_8:       /* 8-bit ISDN u-law */
163             p_sys->fmt.i_codec               = VLC_FOURCC( 'u','l','a','w' );
164             p_sys->fmt.audio.i_bitspersample = 8;
165             p_sys->fmt.audio.i_blockalign    = 1 * p_sys->fmt.audio.i_channels;
166             i_cat                    = AU_CAT_PCM;
167             break;
168
169         case AU_LINEAR_8:      /* 8-bit linear PCM */
170             p_sys->fmt.i_codec               = VLC_FOURCC( 't','w','o','s' );
171             p_sys->fmt.audio.i_bitspersample = 8;
172             p_sys->fmt.audio.i_blockalign    = 1 * p_sys->fmt.audio.i_channels;
173             i_cat                    = AU_CAT_PCM;
174             break;
175
176         case AU_LINEAR_16:     /* 16-bit linear PCM */
177             p_sys->fmt.i_codec               = VLC_FOURCC( 't','w','o','s' );
178             p_sys->fmt.audio.i_bitspersample = 16;
179             p_sys->fmt.audio.i_blockalign    = 2 * p_sys->fmt.audio.i_channels;
180             i_cat                    = AU_CAT_PCM;
181             break;
182
183         case AU_LINEAR_24:     /* 24-bit linear PCM */
184             p_sys->fmt.i_codec               = VLC_FOURCC( 't','w','o','s' );
185             p_sys->fmt.audio.i_bitspersample = 24;
186             p_sys->fmt.audio.i_blockalign    = 3 * p_sys->fmt.audio.i_channels;
187             i_cat                    = AU_CAT_PCM;
188             break;
189
190         case AU_LINEAR_32:     /* 32-bit linear PCM */
191             p_sys->fmt.i_codec               = VLC_FOURCC( 't','w','o','s' );
192             p_sys->fmt.audio.i_bitspersample = 32;
193             p_sys->fmt.audio.i_blockalign    = 4 * p_sys->fmt.audio.i_channels;
194             i_cat                    = AU_CAT_PCM;
195             break;
196
197         case AU_FLOAT:         /* 32-bit IEEE floating point */
198             p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_FLOAT );
199             p_sys->fmt.audio.i_bitspersample = 32;
200             p_sys->fmt.audio.i_blockalign    = 4 * p_sys->fmt.audio.i_channels;
201             i_cat                    = AU_CAT_PCM;
202             break;
203
204         case AU_DOUBLE:        /* 64-bit IEEE floating point */
205             p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_DOUBLE );
206             p_sys->fmt.audio.i_bitspersample = 64;
207             p_sys->fmt.audio.i_blockalign    = 8 * p_sys->fmt.audio.i_channels;
208             i_cat                    = AU_CAT_PCM;
209             break;
210
211         case AU_ADPCM_G721:    /* 4-bit CCITT g.721 ADPCM */
212             p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G721 );
213             p_sys->fmt.audio.i_bitspersample = 0;
214             p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
215             i_cat                    = AU_CAT_ADPCM;
216             break;
217
218         case AU_ADPCM_G722:    /* CCITT g.722 ADPCM */
219             p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G722 );
220             p_sys->fmt.audio.i_bitspersample = 0;
221             p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
222             i_cat                    = AU_CAT_ADPCM;
223             break;
224
225         case AU_ADPCM_G723_3:  /* CCITT g.723 3-bit ADPCM */
226             p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G723_3 );
227             p_sys->fmt.audio.i_bitspersample = 0;
228             p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
229             i_cat                    = AU_CAT_ADPCM;
230             break;
231
232         case AU_ADPCM_G723_5:  /* CCITT g.723 5-bit ADPCM */
233             p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G723_5 );
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         default:
240             msg_Warn( p_demux, "unknow encoding=0x%x", GetDWBE( &hdr[8] ) );
241             p_sys->fmt.audio.i_bitspersample = 0;
242             p_sys->fmt.audio.i_blockalign    = 0;
243             i_cat                    = AU_CAT_UNKNOWN;
244             break;
245     }
246
247     p_sys->fmt.i_bitrate = p_sys->fmt.audio.i_rate *
248                            p_sys->fmt.audio.i_channels *
249                            p_sys->fmt.audio.i_bitspersample;
250
251     if( i_cat == AU_CAT_UNKNOWN || i_cat == AU_CAT_ADPCM )
252     {
253         p_sys->i_frame_size = 0;
254         p_sys->i_frame_length = 0;
255
256         msg_Err( p_demux, "unsupported codec/type (Please report it)" );
257         free( p_sys );
258         return VLC_EGENERIC;
259     }
260
261     /* add the es */
262     p_sys->es = es_out_Add( p_demux->out, &p_sys->fmt );
263
264     /* calculate 50ms frame size/time */
265     i_samples = __MAX( p_sys->fmt.audio.i_rate / 20, 1 );
266     p_sys->i_frame_size = i_samples * p_sys->fmt.audio.i_channels *
267                           ( (p_sys->fmt.audio.i_bitspersample + 7) / 8 );
268     if( p_sys->fmt.audio.i_blockalign > 0 )
269     {
270         if( ( i_modulo = p_sys->i_frame_size % p_sys->fmt.audio.i_blockalign ) != 0 )
271         {
272             p_sys->i_frame_size += p_sys->fmt.audio.i_blockalign - i_modulo;
273         }
274     }
275     p_sys->i_frame_length = (mtime_t)1000000 *
276                             (mtime_t)i_samples /
277                             (mtime_t)p_sys->fmt.audio.i_rate;
278
279     return VLC_SUCCESS;
280 }
281
282 /*****************************************************************************
283  * Demux: read packet and send them to decoders
284  *****************************************************************************
285  * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
286  *****************************************************************************/
287 static int Demux( demux_t *p_demux )
288 {
289     demux_sys_t *p_sys = p_demux->p_sys;
290     block_t     *p_block;
291
292     /* set PCR */
293     es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_time );
294
295     if( ( p_block = stream_Block( p_demux->s, p_sys->i_frame_size ) ) == NULL )
296     {
297         msg_Warn( p_demux, "cannot read data" );
298         return 0;
299     }
300
301     p_block->i_dts =
302     p_block->i_pts = p_sys->i_time;
303
304     es_out_Send( p_demux->out, p_sys->es, p_block );
305
306     p_sys->i_time += p_sys->i_frame_length;
307
308     return 1;
309 }
310
311 /*****************************************************************************
312  * Close: frees unused data
313  *****************************************************************************/
314 static void Close( vlc_object_t * p_this )
315 {
316     demux_t     *p_demux = (demux_t*)p_this;
317     demux_sys_t *p_sys = p_demux->p_sys;
318
319     free( p_sys );
320 }
321
322 /*****************************************************************************
323  * Control:
324  *****************************************************************************/
325 static int Control( demux_t *p_demux, int i_query, va_list args )
326 {
327     demux_sys_t *p_sys = p_demux->p_sys;
328
329     return demux2_vaControlHelper( p_demux->s, p_sys->i_header_size, -1,
330                                    p_sys->fmt.i_bitrate, p_sys->fmt.audio.i_blockalign,
331                                    i_query, args );
332 }
333