au.c 11.9 KB
Newer Older
1 2 3
/*****************************************************************************
 * au.c : au file input module for vlc
 *****************************************************************************
4
 * Copyright (C) 2001-2007 the VideoLAN team
5
 * $Id$
6
 *
7 8 9 10 11 12 13 14 15 16 17 18 19 20
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22 23 24 25 26 27 28
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/

#include <vlc/vlc.h>
zorglub's avatar
zorglub committed
29
#include <vlc_demux.h>
30

Laurent Aimar's avatar
Laurent Aimar committed
31 32 33 34
/* TODO:
 *  - all adpcm things (I _NEED_ samples)
 *  - ...
 */
35 36 37 38

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
39 40
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );
41

42
vlc_module_begin();
zorglub's avatar
zorglub committed
43 44
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_DEMUX );
45
    set_description( _("AU demuxer") );
Laurent Aimar's avatar
Laurent Aimar committed
46
    set_capability( "demux2", 10 );
47
    set_callbacks( Open, Close );
Laurent Aimar's avatar
Laurent Aimar committed
48
    add_shortcut( "au" );
49 50
vlc_module_end();

51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
enum AuType_e
{
    AU_UNKNOWN      =  0,
    AU_MULAW_8      =  1,  /* 8-bit ISDN u-law */
    AU_LINEAR_8     =  2,  /* 8-bit linear PCM */
    AU_LINEAR_16    =  3,  /* 16-bit linear PCM */
    AU_LINEAR_24    =  4,  /* 24-bit linear PCM */
    AU_LINEAR_32    =  5,  /* 32-bit linear PCM */
    AU_FLOAT        =  6,  /* 32-bit IEEE floating point */
    AU_DOUBLE       =  7,  /* 64-bit IEEE floating point */
    AU_ADPCM_G721   =  23, /* 4-bit CCITT g.721 ADPCM */
    AU_ADPCM_G722   =  24, /* CCITT g.722 ADPCM */
    AU_ADPCM_G723_3 =  25, /* CCITT g.723 3-bit ADPCM */
    AU_ADPCM_G723_5 =  26, /* CCITT g.723 5-bit ADPCM */
    AU_ALAW_8       =  27  /* 8-bit ISDN A-law */
};
70

71 72 73 74 75 76
enum AuCat_e
{
    AU_CAT_UNKNOWN  = 0,
    AU_CAT_PCM      = 1,
    AU_CAT_ADPCM    = 2
};
77 78 79

struct demux_sys_t
{
Laurent Aimar's avatar
Laurent Aimar committed
80 81
    es_format_t     fmt;
    es_out_id_t     *es;
82 83 84

    mtime_t         i_time;

85 86
    int             i_frame_size;
    mtime_t         i_frame_length;
Laurent Aimar's avatar
Laurent Aimar committed
87 88

    int             i_header_size;
89 90
};

91
static int Demux( demux_t * );
Laurent Aimar's avatar
Laurent Aimar committed
92
static int Control ( demux_t *, int i_query, va_list args );
93

94
/*****************************************************************************
95
 * Open: check file and initializes structures
96
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
97
static int Open( vlc_object_t *p_this )
98
{
Laurent Aimar's avatar
Laurent Aimar committed
99 100
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys;
101

Laurent Aimar's avatar
Laurent Aimar committed
102
    uint8_t      hdr[20];
103
    const uint8_t *p_peek;
Laurent Aimar's avatar
Laurent Aimar committed
104 105
    int          i_cat;
    int          i_samples, i_modulo;
106

107
    CHECK_PEEK( p_peek, 4 );
108

zorglub's avatar
zorglub committed
109
    if( memcmp( p_peek, ".snd", 4 ) )
110
    {
111
        return VLC_EGENERIC;
112 113
    }

114
    /* skip signature */
Laurent Aimar's avatar
Laurent Aimar committed
115
    stream_Read( p_demux->s, NULL, 4 );   /* cannot fail */
116

117
    /* read header */
Laurent Aimar's avatar
Laurent Aimar committed
118
    if( stream_Read( p_demux->s, hdr, 20 ) < 20 )
119
    {
Laurent Aimar's avatar
Laurent Aimar committed
120 121
        msg_Err( p_demux, "cannot read" );
        return VLC_EGENERIC;
122 123
    }

Laurent Aimar's avatar
Laurent Aimar committed
124
    if( GetDWBE( &hdr[0]  ) < 24 )
125
    {
Laurent Aimar's avatar
Laurent Aimar committed
126 127
        msg_Err( p_demux, "invalid file" );
        return VLC_EGENERIC;
128
    }
129

130
    DEMUX_INIT_COMMON(); p_sys = p_demux->p_sys;
131
    p_sys->i_time = 1;
Laurent Aimar's avatar
Laurent Aimar committed
132 133
    p_sys->i_header_size = GetDWBE( &hdr[0] );

134
    /* skip extra header data */
Laurent Aimar's avatar
Laurent Aimar committed
135
    if( p_sys->i_header_size > 24 )
136
    {
Laurent Aimar's avatar
Laurent Aimar committed
137
        stream_Read( p_demux->s, NULL, p_sys->i_header_size - 24 );
138 139
    }

Laurent Aimar's avatar
Laurent Aimar committed
140
    /* init fmt */
141
    es_format_Init( &p_sys->fmt, AUDIO_ES, 0 );
Laurent Aimar's avatar
Laurent Aimar committed
142 143 144 145 146 147 148 149 150 151 152
    p_sys->fmt.audio.i_rate     = GetDWBE( &hdr[12] );
    p_sys->fmt.audio.i_channels = GetDWBE( &hdr[16] );

#if 0
    p_sys->au.i_header_size   = GetDWBE( &p_sys->au.i_header_size );
    p_sys->au.i_data_size     = GetDWBE( &p_sys->au.i_data_size );
    p_sys->au.i_encoding      = GetDWBE( &p_sys->au.i_encoding );
    p_sys->au.i_sample_rate   = GetDWBE( &p_sys->au.i_sample_rate );
    p_sys->au.i_channels      = GetDWBE( &p_sys->au.i_channels );
#endif
    switch( GetDWBE( &hdr[8] ) )
153
    {
154
        case AU_ALAW_8:        /* 8-bit ISDN A-law */
155 156 157
            p_sys->fmt.i_codec               = VLC_FOURCC( 'a','l','a','w' );
            p_sys->fmt.audio.i_bitspersample = 8;
            p_sys->fmt.audio.i_blockalign    = 1 * p_sys->fmt.audio.i_channels;
158
            i_cat                    = AU_CAT_PCM;
159
            break;
160 161

        case AU_MULAW_8:       /* 8-bit ISDN u-law */
162 163 164
            p_sys->fmt.i_codec               = VLC_FOURCC( 'u','l','a','w' );
            p_sys->fmt.audio.i_bitspersample = 8;
            p_sys->fmt.audio.i_blockalign    = 1 * p_sys->fmt.audio.i_channels;
165
            i_cat                    = AU_CAT_PCM;
166 167
            break;

168
        case AU_LINEAR_8:      /* 8-bit linear PCM */
169 170 171
            p_sys->fmt.i_codec               = VLC_FOURCC( 't','w','o','s' );
            p_sys->fmt.audio.i_bitspersample = 8;
            p_sys->fmt.audio.i_blockalign    = 1 * p_sys->fmt.audio.i_channels;
172
            i_cat                    = AU_CAT_PCM;
173 174
            break;

175
        case AU_LINEAR_16:     /* 16-bit linear PCM */
176 177 178
            p_sys->fmt.i_codec               = VLC_FOURCC( 't','w','o','s' );
            p_sys->fmt.audio.i_bitspersample = 16;
            p_sys->fmt.audio.i_blockalign    = 2 * p_sys->fmt.audio.i_channels;
179
            i_cat                    = AU_CAT_PCM;
180 181
            break;

182
        case AU_LINEAR_24:     /* 24-bit linear PCM */
183 184 185
            p_sys->fmt.i_codec               = VLC_FOURCC( 't','w','o','s' );
            p_sys->fmt.audio.i_bitspersample = 24;
            p_sys->fmt.audio.i_blockalign    = 3 * p_sys->fmt.audio.i_channels;
186
            i_cat                    = AU_CAT_PCM;
187 188
            break;

189
        case AU_LINEAR_32:     /* 32-bit linear PCM */
190 191 192
            p_sys->fmt.i_codec               = VLC_FOURCC( 't','w','o','s' );
            p_sys->fmt.audio.i_bitspersample = 32;
            p_sys->fmt.audio.i_blockalign    = 4 * p_sys->fmt.audio.i_channels;
193
            i_cat                    = AU_CAT_PCM;
194 195
            break;

196
        case AU_FLOAT:         /* 32-bit IEEE floating point */
197 198 199
            p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_FLOAT );
            p_sys->fmt.audio.i_bitspersample = 32;
            p_sys->fmt.audio.i_blockalign    = 4 * p_sys->fmt.audio.i_channels;
200
            i_cat                    = AU_CAT_PCM;
201 202
            break;

203
        case AU_DOUBLE:        /* 64-bit IEEE floating point */
204 205 206
            p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_DOUBLE );
            p_sys->fmt.audio.i_bitspersample = 64;
            p_sys->fmt.audio.i_blockalign    = 8 * p_sys->fmt.audio.i_channels;
207
            i_cat                    = AU_CAT_PCM;
208 209
            break;

210
        case AU_ADPCM_G721:    /* 4-bit CCITT g.721 ADPCM */
211 212 213
            p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G721 );
            p_sys->fmt.audio.i_bitspersample = 0;
            p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
214
            i_cat                    = AU_CAT_ADPCM;
215 216
            break;

217
        case AU_ADPCM_G722:    /* CCITT g.722 ADPCM */
218 219 220
            p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G722 );
            p_sys->fmt.audio.i_bitspersample = 0;
            p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
221
            i_cat                    = AU_CAT_ADPCM;
222 223
            break;

224
        case AU_ADPCM_G723_3:  /* CCITT g.723 3-bit ADPCM */
225 226 227
            p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G723_3 );
            p_sys->fmt.audio.i_bitspersample = 0;
            p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
228
            i_cat                    = AU_CAT_ADPCM;
229 230
            break;

231
        case AU_ADPCM_G723_5:  /* CCITT g.723 5-bit ADPCM */
232 233 234
            p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G723_5 );
            p_sys->fmt.audio.i_bitspersample = 0;
            p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
235
            i_cat                    = AU_CAT_ADPCM;
236 237 238
            break;

        default:
Laurent Aimar's avatar
Laurent Aimar committed
239 240 241
            msg_Warn( p_demux, "unknow encoding=0x%x", GetDWBE( &hdr[8] ) );
            p_sys->fmt.audio.i_bitspersample = 0;
            p_sys->fmt.audio.i_blockalign    = 0;
242
            i_cat                    = AU_CAT_UNKNOWN;
Laurent Aimar's avatar
Laurent Aimar committed
243
            break;
244
    }
Laurent Aimar's avatar
Laurent Aimar committed
245

gbazin's avatar
 
gbazin committed
246 247 248
    p_sys->fmt.i_bitrate = p_sys->fmt.audio.i_rate *
                           p_sys->fmt.audio.i_channels *
                           p_sys->fmt.audio.i_bitspersample;
249 250 251 252 253 254

    if( i_cat == AU_CAT_UNKNOWN || i_cat == AU_CAT_ADPCM )
    {
        p_sys->i_frame_size = 0;
        p_sys->i_frame_length = 0;

Laurent Aimar's avatar
Laurent Aimar committed
255 256 257
        msg_Err( p_demux, "unsupported codec/type (Please report it)" );
        free( p_sys );
        return VLC_EGENERIC;
258 259
    }

Laurent Aimar's avatar
Laurent Aimar committed
260 261
    /* add the es */
    p_sys->es = es_out_Add( p_demux->out, &p_sys->fmt );
262

Laurent Aimar's avatar
Laurent Aimar committed
263 264 265 266 267 268 269
    /* calculate 50ms frame size/time */
    i_samples = __MAX( p_sys->fmt.audio.i_rate / 20, 1 );
    p_sys->i_frame_size = i_samples * p_sys->fmt.audio.i_channels *
                          ( (p_sys->fmt.audio.i_bitspersample + 7) / 8 );
    if( p_sys->fmt.audio.i_blockalign > 0 )
    {
        if( ( i_modulo = p_sys->i_frame_size % p_sys->fmt.audio.i_blockalign ) != 0 )
270
        {
Laurent Aimar's avatar
Laurent Aimar committed
271
            p_sys->i_frame_size += p_sys->fmt.audio.i_blockalign - i_modulo;
272
        }
273
    }
Laurent Aimar's avatar
Laurent Aimar committed
274 275 276
    p_sys->i_frame_length = (mtime_t)1000000 *
                            (mtime_t)i_samples /
                            (mtime_t)p_sys->fmt.audio.i_rate;
277

278
    return VLC_SUCCESS;
279 280 281
}

/*****************************************************************************
282
 * Demux: read packet and send them to decoders
283 284 285
 *****************************************************************************
 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
 *****************************************************************************/
286
static int Demux( demux_t *p_demux )
287
{
Laurent Aimar's avatar
Laurent Aimar committed
288 289
    demux_sys_t *p_sys = p_demux->p_sys;
    block_t     *p_block;
290

Laurent Aimar's avatar
Laurent Aimar committed
291 292
    /* set PCR */
    es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_sys->i_time );
293

Laurent Aimar's avatar
Laurent Aimar committed
294
    if( ( p_block = stream_Block( p_demux->s, p_sys->i_frame_size ) ) == NULL )
295
    {
Laurent Aimar's avatar
Laurent Aimar committed
296
        msg_Warn( p_demux, "cannot read data" );
297
        return 0;
298
    }
Laurent Aimar's avatar
Laurent Aimar committed
299

gbazin's avatar
 
gbazin committed
300
    p_block->i_dts =
Laurent Aimar's avatar
Laurent Aimar committed
301
    p_block->i_pts = p_sys->i_time;
302

Laurent Aimar's avatar
Laurent Aimar committed
303
    es_out_Send( p_demux->out, p_sys->es, p_block );
304

305
    p_sys->i_time += p_sys->i_frame_length;
306

Laurent Aimar's avatar
Laurent Aimar committed
307
    return 1;
308 309 310
}

/*****************************************************************************
311
 * Close: frees unused data
312
 *****************************************************************************/
313
static void Close( vlc_object_t * p_this )
314
{
Laurent Aimar's avatar
Laurent Aimar committed
315 316
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys = p_demux->p_sys;
317

318
    free( p_sys );
319 320
}

Laurent Aimar's avatar
Laurent Aimar committed
321 322 323 324 325 326 327
/*****************************************************************************
 * Control:
 *****************************************************************************/
static int Control( demux_t *p_demux, int i_query, va_list args )
{
    demux_sys_t *p_sys = p_demux->p_sys;

328 329 330
    return demux2_vaControlHelper( p_demux->s, p_sys->i_header_size, -1,
                                   p_sys->fmt.i_bitrate, p_sys->fmt.audio.i_blockalign,
                                   i_query, args );
Laurent Aimar's avatar
Laurent Aimar committed
331 332
}