Coverage Report

Created: 2025-08-25 07:17

/src/vlc/modules/demux/au.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * au.c : au file input module for vlc
3
 *****************************************************************************
4
 * Copyright (C) 2001-2007 VLC authors and VideoLAN
5
 *
6
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
7
 *
8
 * This program is free software; you can redistribute it and/or modify it
9
 * under the terms of the GNU Lesser General Public License as published by
10
 * the Free Software Foundation; either version 2.1 of the License, or
11
 * (at your option) any later version.
12
 *
13
 * This program is distributed in the hope that it will be useful,
14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
 * GNU Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program; if not, write to the Free Software Foundation,
20
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
21
 *****************************************************************************/
22
23
/*****************************************************************************
24
 * Preamble
25
 *****************************************************************************/
26
27
#ifdef HAVE_CONFIG_H
28
# include "config.h"
29
#endif
30
31
#include <limits.h>
32
#include <vlc_common.h>
33
#include <vlc_plugin.h>
34
#include <vlc_demux.h>
35
36
/* TODO:
37
 *  - all adpcm things (I _NEED_ samples)
38
 *  - ...
39
 */
40
41
/*****************************************************************************
42
 * Module descriptor
43
 *****************************************************************************/
44
static int  Open ( vlc_object_t * );
45
46
100
vlc_module_begin ()
47
50
    set_subcategory( SUBCAT_INPUT_DEMUX )
48
50
    set_description( N_("AU demuxer") )
49
50
    set_capability( "demux", 10 )
50
50
    set_callback( Open )
51
50
    add_shortcut( "au" )
52
50
    add_file_extension("au")
53
50
vlc_module_end ()
54
55
/*****************************************************************************
56
 * Local prototypes
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
{
84
    es_format_t     fmt;
85
    es_out_id_t     *es;
86
87
    vlc_tick_t      i_time;
88
89
    int             i_frame_size;
90
    vlc_tick_t      i_frame_length;
91
92
    uint32_t        i_header_size;
93
} demux_sys_t;
94
95
static int Demux( demux_t * );
96
static int Control ( demux_t *, int i_query, va_list args );
97
98
/*****************************************************************************
99
 * Open: check file and initializes structures
100
 *****************************************************************************/
101
static int Open( vlc_object_t *p_this )
102
0
{
103
0
    demux_t     *p_demux = (demux_t*)p_this;
104
105
0
    uint8_t      hdr[20];
106
0
    const uint8_t *p_peek;
107
0
    int          i_cat;
108
109
0
    if( vlc_stream_Peek( p_demux->s , &p_peek, 4 ) < 4 )
110
0
        return VLC_EGENERIC;
111
112
0
    if( memcmp( p_peek, ".snd", 4 ) )
113
0
        return VLC_EGENERIC;
114
115
    /* skip signature */
116
0
    if( vlc_stream_Read( p_demux->s, NULL, 4 ) != 4 )
117
0
        return VLC_EGENERIC;
118
119
    /* read header */
120
0
    if( vlc_stream_Read( p_demux->s, hdr, 20 ) < 20 )
121
0
    {
122
0
        msg_Err( p_demux, "cannot read" );
123
0
        return VLC_EGENERIC;
124
0
    }
125
126
0
    if( GetDWBE( &hdr[0]  ) < 24 )
127
0
    {
128
0
        msg_Err( p_demux, "invalid file" );
129
0
        return VLC_EGENERIC;
130
0
    }
131
132
0
    demux_sys_t *p_sys = vlc_obj_malloc( p_this, sizeof (*p_sys) );
133
0
    if( unlikely(p_sys == NULL) )
134
0
        return VLC_ENOMEM;
135
136
0
    p_sys->i_time = 0;
137
0
    p_sys->i_header_size = GetDWBE( &hdr[0] );
138
139
    /* skip extra header data */
140
0
    if( p_sys->i_header_size > 24 )
141
0
    {
142
#if (SSIZE_MAX <= INT32_MAX)
143
        if( p_sys->i_header_size > SSIZE_MAX )
144
            return VLC_EGENERIC;
145
#endif
146
0
        uint32_t skip = p_sys->i_header_size - 24;
147
0
        if( vlc_stream_Read( p_demux->s, NULL, skip ) != skip )
148
0
            return VLC_EGENERIC;
149
0
    }
150
151
    /* init fmt */
152
0
    es_format_Init( &p_sys->fmt, AUDIO_ES, 0 );
153
0
    p_sys->fmt.audio.i_rate     = GetDWBE( &hdr[12] );
154
0
    p_sys->fmt.audio.i_channels = GetDWBE( &hdr[16] );
155
156
#if 0
157
    p_sys->au.i_header_size   = GetDWBE( &p_sys->au.i_header_size );
158
    p_sys->au.i_data_size     = GetDWBE( &p_sys->au.i_data_size );
159
    p_sys->au.i_encoding      = GetDWBE( &p_sys->au.i_encoding );
160
    p_sys->au.i_sample_rate   = GetDWBE( &p_sys->au.i_sample_rate );
161
    p_sys->au.i_channels      = GetDWBE( &p_sys->au.i_channels );
162
#endif
163
0
    switch( GetDWBE( &hdr[8] ) )
164
0
    {
165
0
        case AU_ALAW_8:        /* 8-bit ISDN A-law */
166
0
            p_sys->fmt.i_codec               = VLC_CODEC_ALAW;
167
0
            p_sys->fmt.audio.i_bitspersample = 8;
168
0
            p_sys->fmt.audio.i_blockalign    = 1 * p_sys->fmt.audio.i_channels;
169
0
            i_cat                    = AU_CAT_PCM;
170
0
            break;
171
172
0
        case AU_MULAW_8:       /* 8-bit ISDN u-law */
173
0
            p_sys->fmt.i_codec               = VLC_CODEC_MULAW;
174
0
            p_sys->fmt.audio.i_bitspersample = 8;
175
0
            p_sys->fmt.audio.i_blockalign    = 1 * p_sys->fmt.audio.i_channels;
176
0
            i_cat                    = AU_CAT_PCM;
177
0
            break;
178
179
0
        case AU_LINEAR_8:      /* 8-bit linear PCM */
180
0
            p_sys->fmt.i_codec               = VLC_CODEC_S8;
181
0
            p_sys->fmt.audio.i_bitspersample = 8;
182
0
            p_sys->fmt.audio.i_blockalign    = 1 * p_sys->fmt.audio.i_channels;
183
0
            i_cat                    = AU_CAT_PCM;
184
0
            break;
185
186
0
        case AU_LINEAR_16:     /* 16-bit linear PCM */
187
0
            p_sys->fmt.i_codec               = VLC_CODEC_S16B;
188
0
            p_sys->fmt.audio.i_bitspersample = 16;
189
0
            p_sys->fmt.audio.i_blockalign    = 2 * p_sys->fmt.audio.i_channels;
190
0
            i_cat                    = AU_CAT_PCM;
191
0
            break;
192
193
0
        case AU_LINEAR_24:     /* 24-bit linear PCM */
194
0
            p_sys->fmt.i_codec               = VLC_CODEC_S24B;
195
0
            p_sys->fmt.audio.i_bitspersample = 24;
196
0
            p_sys->fmt.audio.i_blockalign    = 3 * p_sys->fmt.audio.i_channels;
197
0
            i_cat                    = AU_CAT_PCM;
198
0
            break;
199
200
0
        case AU_LINEAR_32:     /* 32-bit linear PCM */
201
0
            p_sys->fmt.i_codec               = VLC_CODEC_S32B;
202
0
            p_sys->fmt.audio.i_bitspersample = 32;
203
0
            p_sys->fmt.audio.i_blockalign    = 4 * p_sys->fmt.audio.i_channels;
204
0
            i_cat                    = AU_CAT_PCM;
205
0
            break;
206
207
0
        case AU_FLOAT:         /* 32-bit IEEE floating point */
208
0
            p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_FLOAT );
209
0
            p_sys->fmt.audio.i_bitspersample = 32;
210
0
            p_sys->fmt.audio.i_blockalign    = 4 * p_sys->fmt.audio.i_channels;
211
0
            i_cat                    = AU_CAT_PCM;
212
0
            break;
213
214
0
        case AU_DOUBLE:        /* 64-bit IEEE floating point */
215
0
            p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_DOUBLE );
216
0
            p_sys->fmt.audio.i_bitspersample = 64;
217
0
            p_sys->fmt.audio.i_blockalign    = 8 * p_sys->fmt.audio.i_channels;
218
0
            i_cat                    = AU_CAT_PCM;
219
0
            break;
220
221
0
        case AU_ADPCM_G721:    /* 4-bit CCITT g.721 ADPCM */
222
0
            p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G721 );
223
0
            p_sys->fmt.audio.i_bitspersample = 0;
224
0
            p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
225
0
            i_cat                    = AU_CAT_ADPCM;
226
0
            break;
227
228
0
        case AU_ADPCM_G722:    /* CCITT g.722 ADPCM */
229
0
            p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G722 );
230
0
            p_sys->fmt.audio.i_bitspersample = 0;
231
0
            p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
232
0
            i_cat                    = AU_CAT_ADPCM;
233
0
            break;
234
235
0
        case AU_ADPCM_G723_3:  /* CCITT g.723 3-bit ADPCM */
236
0
            p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G723_3 );
237
0
            p_sys->fmt.audio.i_bitspersample = 0;
238
0
            p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
239
0
            i_cat                    = AU_CAT_ADPCM;
240
0
            break;
241
242
0
        case AU_ADPCM_G723_5:  /* CCITT g.723 5-bit ADPCM */
243
0
            p_sys->fmt.i_codec               = VLC_FOURCC( 'a', 'u', 0, AU_ADPCM_G723_5 );
244
0
            p_sys->fmt.audio.i_bitspersample = 0;
245
0
            p_sys->fmt.audio.i_blockalign    = 0 * p_sys->fmt.audio.i_channels;
246
0
            i_cat                    = AU_CAT_ADPCM;
247
0
            break;
248
249
0
        default:
250
0
            msg_Warn( p_demux, "unknown encoding=0x%x", GetDWBE( &hdr[8] ) );
251
0
            p_sys->fmt.audio.i_bitspersample = 0;
252
0
            p_sys->fmt.audio.i_blockalign    = 0;
253
0
            i_cat                    = AU_CAT_UNKNOWN;
254
0
            break;
255
0
    }
256
257
0
    p_sys->fmt.i_bitrate = p_sys->fmt.audio.i_rate *
258
0
                           p_sys->fmt.audio.i_channels *
259
0
                           p_sys->fmt.audio.i_bitspersample;
260
261
0
    if( i_cat == AU_CAT_UNKNOWN || i_cat == AU_CAT_ADPCM )
262
0
    {
263
0
        msg_Err( p_demux, "unsupported codec/type (Please report it)" );
264
0
        return VLC_EGENERIC;
265
0
    }
266
267
0
    if( p_sys->fmt.audio.i_rate == 0 )
268
0
    {
269
0
        msg_Err( p_demux, "invalid samplerate: 0" );
270
0
        return VLC_EGENERIC;
271
0
    }
272
273
    /* add the es */
274
0
    p_sys->fmt.i_id = 0;
275
0
    p_sys->es = es_out_Add( p_demux->out, &p_sys->fmt );
276
0
    if( unlikely(p_sys->es == NULL) )
277
0
        return VLC_ENOMEM;
278
279
    /* calculate 50ms frame size/time */
280
0
    unsigned i_samples = __MAX( p_sys->fmt.audio.i_rate / 20, 1 );
281
0
    p_sys->i_frame_size = i_samples * p_sys->fmt.audio.i_channels *
282
0
                          ( (p_sys->fmt.audio.i_bitspersample + 7) / 8 );
283
0
    if( p_sys->fmt.audio.i_blockalign > 0 )
284
0
    {
285
0
        unsigned mod = p_sys->i_frame_size % p_sys->fmt.audio.i_blockalign;
286
0
        if( mod != 0 )
287
0
        {
288
0
            p_sys->i_frame_size += p_sys->fmt.audio.i_blockalign - mod;
289
0
        }
290
0
    }
291
0
    p_sys->i_frame_length = vlc_tick_from_samples( i_samples,
292
0
                                                   p_sys->fmt.audio.i_rate );
293
294
0
    p_demux->p_sys = p_sys;
295
0
    p_demux->pf_demux = Demux;
296
0
    p_demux->pf_control = Control;
297
0
    return VLC_SUCCESS;
298
0
}
299
300
/*****************************************************************************
301
 * Demux: read packet and send them to decoders
302
 *****************************************************************************
303
 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
304
 *****************************************************************************/
305
static int Demux( demux_t *p_demux )
306
0
{
307
0
    demux_sys_t *p_sys = p_demux->p_sys;
308
0
    block_t     *p_block;
309
310
    /* set PCR */
311
0
    es_out_SetPCR( p_demux->out, VLC_TICK_0 + p_sys->i_time );
312
313
0
    p_block = vlc_stream_Block( p_demux->s, p_sys->i_frame_size );
314
0
    if( p_block == NULL )
315
0
    {
316
0
        msg_Warn( p_demux, "cannot read data" );
317
0
        return VLC_DEMUXER_EOF;
318
0
    }
319
320
0
    p_block->i_dts =
321
0
    p_block->i_pts = VLC_TICK_0 + p_sys->i_time;
322
0
    es_out_Send( p_demux->out, p_sys->es, p_block );
323
324
0
    p_sys->i_time += p_sys->i_frame_length;
325
326
0
    return VLC_DEMUXER_SUCCESS;
327
0
}
328
329
/*****************************************************************************
330
 * Control:
331
 *****************************************************************************/
332
static int Control( demux_t *p_demux, int i_query, va_list args )
333
0
{
334
0
    demux_sys_t *p_sys = p_demux->p_sys;
335
336
0
    return demux_vaControlHelper( p_demux->s, p_sys->i_header_size, -1,
337
0
                                   p_sys->fmt.i_bitrate, p_sys->fmt.audio.i_blockalign,
338
0
                                   i_query, args );
339
0
}
340