Coverage Report

Created: 2025-07-11 07:16

/src/vlc/modules/demux/wav.c
Line
Count
Source (jump to first uncovered line)
1
/*****************************************************************************
2
 * wav.c : wav file input module for vlc
3
 *****************************************************************************
4
 * Copyright (C) 2001-2008 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 <assert.h>
32
#include <limits.h>
33
34
#include <vlc_common.h>
35
#include <vlc_plugin.h>
36
#include <vlc_demux.h>
37
#include <vlc_aout.h>
38
#include <vlc_codecs.h>
39
40
#include "windows_audio_commons.h"
41
42
882
#define WAV_CHAN_MAX 32
43
static_assert( INPUT_CHAN_MAX >= WAV_CHAN_MAX, "channel count mismatch" );
44
45
typedef struct
46
{
47
    es_format_t     fmt;
48
    es_out_id_t     *p_es;
49
50
    uint64_t        i_data_pos;
51
    uint64_t        i_data_size;
52
53
    unsigned int    i_frame_size;
54
    int             i_frame_samples;
55
56
    date_t          pts;
57
58
    uint32_t i_channel_mask;
59
    uint8_t i_chans_to_reorder;            /* do we need channel reordering */
60
    uint8_t pi_chan_table[AOUT_CHAN_MAX];
61
} demux_sys_t;
62
63
enum wav_chunk_id {
64
    wav_chunk_id_data,
65
    wav_chunk_id_ds64,
66
    wav_chunk_id_fmt,
67
};
68
69
static const struct wav_chunk_id_key
70
{
71
    enum wav_chunk_id id;
72
    char key[5];
73
} wav_chunk_id_key_list[] =  {
74
    /* Alphabetical order */
75
    { wav_chunk_id_data, "data" },
76
    { wav_chunk_id_ds64, "ds64" },
77
    { wav_chunk_id_fmt,  "fmt " },
78
};
79
static const size_t wav_chunk_id_key_count = ARRAY_SIZE(wav_chunk_id_key_list);
80
81
static int
82
wav_chunk_CompareCb(const void *a, const void *b)
83
18.2k
{
84
18.2k
    const struct wav_chunk_id_key *id = b;
85
18.2k
    return memcmp(a, id->key, 4);
86
18.2k
}
87
88
static int Demux( demux_t *p_demux )
89
1.51M
{
90
1.51M
    demux_sys_t *p_sys = p_demux->p_sys;
91
1.51M
    block_t     *p_block;
92
1.51M
    const int64_t i_pos = vlc_stream_Tell( p_demux->s );
93
1.51M
    unsigned int i_read_size = p_sys->i_frame_size;
94
1.51M
    uint32_t i_read_samples = p_sys->i_frame_samples;
95
96
97
1.51M
    if( p_sys->i_data_size > 0 )
98
1.51M
    {
99
1.51M
        int64_t i_end = p_sys->i_data_pos + p_sys->i_data_size;
100
1.51M
        if ( i_pos >= i_end )
101
60
            return VLC_DEMUXER_EOF;  /* EOF */
102
103
        /* Don't read past data chunk boundary */
104
1.51M
        if ( i_end < i_pos + i_read_size )
105
57
        {
106
57
            i_read_size = i_end - i_pos;
107
57
            i_read_samples = ( p_sys->i_frame_size - i_read_size )
108
57
                           * p_sys->i_frame_samples / p_sys->i_frame_size;
109
57
        }
110
1.51M
    }
111
112
1.51M
    if( ( p_block = vlc_stream_Block( p_demux->s, i_read_size ) ) == NULL )
113
193
    {
114
193
        msg_Warn( p_demux, "cannot read data" );
115
193
        return VLC_DEMUXER_EOF;
116
193
    }
117
118
1.51M
    p_block->i_dts =
119
1.51M
    p_block->i_pts = date_Get( &p_sys->pts );
120
121
    /* set PCR */
122
1.51M
    es_out_SetPCR( p_demux->out, p_block->i_pts );
123
124
    /* Do the channel reordering */
125
1.51M
    if( p_sys->i_chans_to_reorder )
126
2.75k
        aout_ChannelReorder( p_block->p_buffer, p_block->i_buffer,
127
2.75k
                             p_sys->fmt.audio.i_channels,
128
2.75k
                             p_sys->pi_chan_table, p_sys->fmt.i_codec );
129
130
1.51M
    es_out_Send( p_demux->out, p_sys->p_es, p_block );
131
132
1.51M
    date_Increment( &p_sys->pts, i_read_samples );
133
134
1.51M
    return VLC_DEMUXER_SUCCESS;
135
1.51M
}
136
137
static int Control( demux_t *p_demux, int i_query, va_list args )
138
0
{
139
0
    demux_sys_t *p_sys  = p_demux->p_sys;
140
0
    int64_t i_end = -1;
141
142
0
    if( p_sys->i_data_size > 0 )
143
0
        i_end = p_sys->i_data_pos + p_sys->i_data_size;
144
145
0
    int ret = demux_vaControlHelper( p_demux->s, p_sys->i_data_pos, i_end,
146
0
                                     p_sys->fmt.i_bitrate,
147
0
                                     p_sys->fmt.audio.i_blockalign,
148
0
                                     i_query, args );
149
0
    if( ret != VLC_SUCCESS )
150
0
        return ret;
151
152
    /* Update the date to the new seek point */
153
0
    switch( i_query )
154
0
    {
155
0
        case DEMUX_SET_POSITION:
156
0
        case DEMUX_SET_TIME:
157
0
        {
158
0
            uint64_t ofs = vlc_stream_Tell( p_demux->s );
159
0
            if( unlikely( ofs < p_sys->i_data_pos ) )
160
0
                return VLC_SUCCESS;
161
162
0
            ofs -= p_sys->i_data_pos;
163
0
            vlc_tick_t pts =
164
0
                vlc_tick_from_samples( ofs * 8, p_sys->fmt.i_bitrate );
165
0
            date_Set( &p_sys->pts, pts );
166
0
            break;
167
0
        }
168
0
        default:
169
0
            break;
170
0
    }
171
0
    return VLC_SUCCESS;
172
0
}
173
174
static int ChunkSkip( demux_t *p_demux, uint32_t i_size )
175
7.82k
{
176
7.82k
    i_size += i_size & 1;
177
178
7.82k
    if( unlikely( i_size >= 65536 ) )
179
58
    {
180
        /* Arbitrary size where a seek should be performed instead of skipping
181
         * by reading NULL. Non data chunks are generally smaller than this.
182
         * This seek may be used to skip the data chunk if there is an other
183
         * chunk after it (unlikely). */
184
58
        return vlc_stream_Seek( p_demux->s,
185
58
                                vlc_stream_Tell( p_demux->s ) + i_size );
186
58
    }
187
188
7.76k
    return vlc_stream_Read( p_demux->s, NULL, i_size ) != i_size ? VLC_EGENERIC : VLC_SUCCESS;
189
7.82k
}
190
191
static int ChunkGetNext( demux_t *p_demux, enum wav_chunk_id *p_id,
192
                         uint32_t *pi_size )
193
4.18k
{
194
4.18k
#ifndef NDEBUG
195
    /* assert that keys are in alphabetical order */
196
12.5k
    for( size_t i = 0; i < wav_chunk_id_key_count - 1; ++i )
197
8.36k
        assert( strcmp( wav_chunk_id_key_list[i].key,
198
4.18k
                        wav_chunk_id_key_list[i + 1].key ) < 0 );
199
4.18k
#endif
200
201
4.18k
    for( ;; )
202
9.99k
    {
203
9.99k
        const uint8_t *p_peek;
204
9.99k
        if( vlc_stream_Peek( p_demux->s, &p_peek, 8 ) < 8 )
205
80
            return VLC_EGENERIC;
206
207
9.91k
        const struct wav_chunk_id_key *id =
208
9.91k
            bsearch( p_peek, wav_chunk_id_key_list, wav_chunk_id_key_count,
209
9.91k
                     sizeof(*wav_chunk_id_key_list), wav_chunk_CompareCb );
210
9.91k
        uint32_t i_size = GetDWLE( p_peek + 4 );
211
212
9.91k
        if( id == NULL )
213
5.83k
        {
214
5.83k
            msg_Warn( p_demux, "unknown chunk '%4.4s' of size: %u",
215
5.83k
                      p_peek, i_size );
216
217
5.83k
            if( vlc_stream_Read( p_demux->s, NULL, 8 ) != 8 )
218
0
                return VLC_EGENERIC;
219
220
5.83k
            if( ChunkSkip( p_demux, i_size ) != VLC_SUCCESS )
221
21
                return VLC_EGENERIC;
222
5.81k
            continue;
223
5.83k
        }
224
225
4.08k
        if( vlc_stream_Read( p_demux->s, NULL, 8 ) != 8 )
226
0
            return VLC_EGENERIC;
227
228
4.08k
        *p_id = id->id;
229
4.08k
        *pi_size = i_size;
230
231
4.08k
        return VLC_SUCCESS;
232
4.08k
    }
233
4.18k
}
234
235
static int FrameInfo_PCM( unsigned int *pi_size, int *pi_samples,
236
                          const es_format_t *p_fmt )
237
885
{
238
885
    int i_bytes;
239
240
885
    if( p_fmt->audio.i_rate > 352800
241
885
     || p_fmt->audio.i_bitspersample > 64
242
885
     || p_fmt->audio.i_channels > WAV_CHAN_MAX )
243
3
        return VLC_EGENERIC;
244
245
    /* read samples for 50ms of */
246
882
    *pi_samples = __MAX( p_fmt->audio.i_rate / 20, 1 );
247
248
882
    i_bytes = *pi_samples * p_fmt->audio.i_channels *
249
882
        ( (p_fmt->audio.i_bitspersample + 7) / 8 );
250
251
882
    if( p_fmt->audio.i_blockalign > 0 )
252
762
    {
253
762
        const int i_modulo = i_bytes % p_fmt->audio.i_blockalign;
254
762
        if( i_modulo > 0 )
255
514
            i_bytes += p_fmt->audio.i_blockalign - i_modulo;
256
762
    }
257
258
882
    *pi_size = i_bytes;
259
882
    return VLC_SUCCESS;
260
885
}
261
262
static int FrameInfo_MS_ADPCM( unsigned int *pi_size, int *pi_samples,
263
                               const es_format_t *p_fmt )
264
149
{
265
149
    if( p_fmt->audio.i_channels == 0 )
266
0
        return VLC_EGENERIC;
267
268
149
    *pi_samples = 2 + 2 * ( p_fmt->audio.i_blockalign -
269
149
        7 * p_fmt->audio.i_channels ) / p_fmt->audio.i_channels;
270
149
    *pi_size = p_fmt->audio.i_blockalign;
271
272
149
    return VLC_SUCCESS;
273
149
}
274
275
static int FrameInfo_IMA_ADPCM( unsigned int *pi_size, int *pi_samples,
276
                                const es_format_t *p_fmt )
277
200
{
278
200
    if( p_fmt->audio.i_channels == 0 )
279
0
        return VLC_EGENERIC;
280
281
200
    *pi_samples = 2 * ( p_fmt->audio.i_blockalign -
282
200
        4 * p_fmt->audio.i_channels ) / p_fmt->audio.i_channels;
283
200
    *pi_size = p_fmt->audio.i_blockalign;
284
285
200
    return VLC_SUCCESS;
286
200
}
287
288
static int FrameInfo_Creative_ADPCM( unsigned int *pi_size, int *pi_samples,
289
                                     const es_format_t *p_fmt )
290
35
{
291
35
    if( p_fmt->audio.i_channels == 0 )
292
0
        return VLC_EGENERIC;
293
294
    /* 4 bits / sample */
295
35
    *pi_samples = p_fmt->audio.i_blockalign * 2 / p_fmt->audio.i_channels;
296
35
    *pi_size = p_fmt->audio.i_blockalign;
297
298
35
    return VLC_SUCCESS;
299
35
}
300
301
static int FrameInfo_MSGSM( unsigned int *pi_size, int *pi_samples,
302
                            const es_format_t *p_fmt )
303
572
{
304
572
    if( p_fmt->i_bitrate <= 0 )
305
0
        return VLC_EGENERIC;
306
307
572
    *pi_samples = ( p_fmt->audio.i_blockalign * p_fmt->audio.i_rate * 8)
308
572
                    / p_fmt->i_bitrate;
309
572
    *pi_size = p_fmt->audio.i_blockalign;
310
311
572
    return VLC_SUCCESS;
312
572
}
313
static void Close ( vlc_object_t * p_this )
314
253
{
315
253
    demux_t     *p_demux = (demux_t*)p_this;
316
253
    demux_sys_t *p_sys   = p_demux->p_sys;
317
318
253
    es_format_Clean( &p_sys->fmt );
319
253
    free( p_sys );
320
253
}
321
322
static int ChunkParseDS64( demux_t *p_demux, uint32_t i_size )
323
1.53k
{
324
1.53k
    demux_sys_t *p_sys = p_demux->p_sys;
325
1.53k
    const uint8_t *p_peek;
326
327
1.53k
    if( i_size < 24 )
328
0
    {
329
0
        msg_Err( p_demux, "invalid 'ds64' chunk" );
330
0
        return VLC_EGENERIC;
331
0
    }
332
333
1.53k
    if( vlc_stream_Peek( p_demux->s, &p_peek, 24 ) < 24 )
334
2
        return VLC_EGENERIC;
335
336
1.53k
    p_sys->i_data_size = GetQWLE( &p_peek[8] );
337
338
1.53k
    return ChunkSkip( p_demux, i_size );
339
1.53k
}
340
341
static int ChunkParseFmt( demux_t *p_demux, uint32_t i_size )
342
1.89k
{
343
1.89k
    demux_sys_t *p_sys = p_demux->p_sys;
344
1.89k
    WAVEFORMATEXTENSIBLE *p_wf_ext = NULL;
345
1.89k
    WAVEFORMATEX         *p_wf = NULL;
346
1.89k
    const char *psz_name;
347
1.89k
    unsigned int i_extended;
348
349
1.89k
    i_size += 2;
350
1.89k
    if( i_size < sizeof( WAVEFORMATEX ) )
351
0
    {
352
0
        msg_Err( p_demux, "invalid 'fmt ' chunk" );
353
0
        goto error;
354
0
    }
355
356
    /* load waveformatex */
357
1.89k
    p_wf_ext = malloc( i_size );
358
1.89k
    if( unlikely( !p_wf_ext ) )
359
0
         goto error;
360
361
1.89k
    p_wf         = &p_wf_ext->Format;
362
1.89k
    p_wf->cbSize = 0;
363
1.89k
    i_size      -= 2;
364
1.89k
    if( vlc_stream_Read( p_demux->s, p_wf, i_size ) != (int)i_size ||
365
1.89k
        ( ( i_size & 1 ) && vlc_stream_Read( p_demux->s, NULL, 1 ) != 1 ) )
366
26
    {
367
26
        msg_Err( p_demux, "cannot load 'fmt ' chunk" );
368
26
        goto error;
369
26
    }
370
371
1.86k
    wf_tag_to_fourcc( GetWLE( &p_wf->wFormatTag ), &p_sys->fmt.i_codec,
372
1.86k
                      &psz_name );
373
1.86k
    p_sys->fmt.audio.i_channels      = GetWLE ( &p_wf->nChannels );
374
1.86k
    p_sys->fmt.audio.i_rate          = GetDWLE( &p_wf->nSamplesPerSec );
375
1.86k
    p_sys->fmt.audio.i_blockalign    = GetWLE( &p_wf->nBlockAlign );
376
1.86k
    p_sys->fmt.i_bitrate             = GetDWLE( &p_wf->nAvgBytesPerSec ) * 8;
377
1.86k
    p_sys->fmt.audio.i_bitspersample = GetWLE( &p_wf->wBitsPerSample );
378
1.86k
    if( i_size >= sizeof(WAVEFORMATEX) )
379
111
        p_sys->fmt.i_extra = __MIN( GetWLE( &p_wf->cbSize ), i_size - sizeof(WAVEFORMATEX) );
380
1.86k
    i_extended = 0;
381
382
    /* Handle new WAVE_FORMAT_EXTENSIBLE wav files */
383
    /* see the following link for more information:
384
     * http://www.microsoft.com/whdc/device/audio/multichaud.mspx#EFAA */
385
1.86k
    if( GetWLE( &p_wf->wFormatTag ) == WAVE_FORMAT_EXTENSIBLE &&
386
1.86k
        i_size >= sizeof( WAVEFORMATEXTENSIBLE ) &&
387
1.86k
        ( p_sys->fmt.i_extra + sizeof( WAVEFORMATEX )
388
7
            >= sizeof( WAVEFORMATEXTENSIBLE ) ) )
389
6
    {
390
6
        unsigned i_channel_mask;
391
6
        GUID guid_subformat;
392
393
6
        guid_subformat = p_wf_ext->SubFormat;
394
6
        guid_subformat.Data1 = GetDWLE( &p_wf_ext->SubFormat.Data1 );
395
6
        guid_subformat.Data2 = GetWLE( &p_wf_ext->SubFormat.Data2 );
396
6
        guid_subformat.Data3 = GetWLE( &p_wf_ext->SubFormat.Data3 );
397
398
6
        sf_tag_to_fourcc( &guid_subformat, &p_sys->fmt.i_codec, &psz_name );
399
400
6
        msg_Dbg( p_demux, "extensible format guid " GUID_FMT, GUID_PRINT(guid_subformat) );
401
402
6
        i_extended = sizeof( WAVEFORMATEXTENSIBLE ) - sizeof( WAVEFORMATEX );
403
6
        p_sys->fmt.i_extra -= i_extended;
404
405
6
        i_channel_mask = GetDWLE( &p_wf_ext->dwChannelMask );
406
6
        if( i_channel_mask )
407
5
        {
408
5
            int i_match = 0;
409
5
            p_sys->i_channel_mask = getChannelMask( &i_channel_mask, p_sys->fmt.audio.i_channels, &i_match );
410
5
            if( i_channel_mask )
411
5
                msg_Warn( p_demux, "Some channels are unrecognized or uselessly specified (0x%x)", i_channel_mask );
412
5
            if( i_match < p_sys->fmt.audio.i_channels )
413
4
            {
414
4
                int i_missing = p_sys->fmt.audio.i_channels - i_match;
415
4
                msg_Warn( p_demux, "Trying to fill up unspecified position for %d channels", p_sys->fmt.audio.i_channels - i_match );
416
417
4
                static const uint32_t pi_pair[] = { AOUT_CHAN_REARLEFT|AOUT_CHAN_REARRIGHT,
418
4
                                                    AOUT_CHAN_MIDDLELEFT|AOUT_CHAN_MIDDLERIGHT,
419
4
                                                    AOUT_CHAN_LEFT|AOUT_CHAN_RIGHT };
420
                /* FIXME: Unused yet
421
                static const uint32_t pi_center[] = { AOUT_CHAN_REARCENTER,
422
                                                      0,
423
                                                      AOUT_CHAN_CENTER }; */
424
425
                /* Try to complete with pair */
426
16
                for( unsigned i = 0; i < sizeof(pi_pair)/sizeof(*pi_pair); i++ )
427
12
                {
428
12
                    if( i_missing >= 2 && !(p_sys->i_channel_mask & pi_pair[i] ) )
429
6
                    {
430
6
                        i_missing -= 2;
431
6
                        p_sys->i_channel_mask |= pi_pair[i];
432
6
                    }
433
12
                }
434
                /* Well fill up with what we can */
435
44
                for( unsigned i = 0; i < sizeof(pi_channels_aout)/sizeof(*pi_channels_aout) && i_missing > 0; i++ )
436
40
                {
437
40
                    if( !( p_sys->i_channel_mask & pi_channels_aout[i] ) )
438
11
                    {
439
11
                        p_sys->i_channel_mask |= pi_channels_aout[i];
440
11
                        i_missing--;
441
442
11
                        if( i_missing <= 0 )
443
0
                            break;
444
11
                    }
445
40
                }
446
447
4
                i_match = p_sys->fmt.audio.i_channels - i_missing;
448
4
            }
449
5
            if( i_match < p_sys->fmt.audio.i_channels )
450
4
            {
451
4
                msg_Err( p_demux, "Invalid/unsupported channel mask" );
452
4
                p_sys->i_channel_mask = 0;
453
4
            }
454
5
        }
455
6
    }
456
1.86k
    if( p_sys->i_channel_mask == 0 && p_sys->fmt.audio.i_channels > 2
457
1.86k
     && p_sys->fmt.audio.i_channels <= AOUT_CHAN_MAX )
458
179
    {
459
        /* A dwChannelMask of 0 tells the audio device to render the first
460
         * channel to the first port on the device, the second channel to the
461
         * second port on the device, and so on. pi_default_channels is
462
         * different than pi_channels_aout. Indeed FLC/FRC must be treated a
463
         * SL/SR in that case. See "Default Channel Ordering" and "Details
464
         * about dwChannelMask" from msdn */
465
466
179
        static const uint32_t pi_default_channels[] = {
467
179
            AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER,
468
179
            AOUT_CHAN_LFE, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
469
179
            AOUT_CHAN_MIDDLELEFT, AOUT_CHAN_MIDDLERIGHT, AOUT_CHAN_REARCENTER };
470
471
1.34k
        for( unsigned i = 0; i < p_sys->fmt.audio.i_channels &&
472
1.34k
             i < (sizeof(pi_default_channels) / sizeof(*pi_default_channels));
473
1.16k
             i++ )
474
1.16k
            p_sys->i_channel_mask |= pi_default_channels[i];
475
179
    }
476
477
1.86k
    if( p_sys->i_channel_mask )
478
843
    {
479
843
        if( p_sys->fmt.i_codec == VLC_FOURCC('a','r','a','w') ||
480
843
            p_sys->fmt.i_codec == VLC_FOURCC('a','f','l','t') )
481
605
            p_sys->i_chans_to_reorder =
482
605
                aout_CheckChannelReorder( pi_channels_aout, NULL,
483
605
                                          p_sys->i_channel_mask,
484
605
                                          p_sys->pi_chan_table );
485
486
843
        msg_Dbg( p_demux, "channel mask: %x, reordering: %u",
487
843
                 p_sys->i_channel_mask, p_sys->i_chans_to_reorder );
488
843
    }
489
490
1.86k
    p_sys->fmt.audio.i_physical_channels = p_sys->i_channel_mask;
491
492
1.86k
    if( p_sys->fmt.i_extra > 0 )
493
87
    {
494
87
        p_sys->fmt.p_extra = malloc( p_sys->fmt.i_extra );
495
87
        if( unlikely(!p_sys->fmt.p_extra) )
496
0
        {
497
0
            p_sys->fmt.i_extra = 0;
498
0
            goto error;
499
0
        }
500
87
        memcpy( p_sys->fmt.p_extra, (uint8_t *)p_wf + sizeof( WAVEFORMATEX ) + i_extended,
501
87
                p_sys->fmt.i_extra );
502
87
    }
503
504
1.86k
    msg_Dbg( p_demux, "format: 0x%4.4x, fourcc: %4.4s, channels: %d, "
505
1.86k
             "freq: %u Hz, bitrate: %uKo/s, blockalign: %d, bits/samples: %d, "
506
1.86k
             "extra size: %zu",
507
1.86k
             GetWLE( &p_wf->wFormatTag ), (char *)&p_sys->fmt.i_codec,
508
1.86k
             p_sys->fmt.audio.i_channels, p_sys->fmt.audio.i_rate,
509
1.86k
             p_sys->fmt.i_bitrate / 8 / 1024, p_sys->fmt.audio.i_blockalign,
510
1.86k
             p_sys->fmt.audio.i_bitspersample, p_sys->fmt.i_extra );
511
512
1.86k
    free( p_wf );
513
1.86k
    p_wf = NULL;
514
515
1.86k
    switch( p_sys->fmt.i_codec )
516
1.86k
    {
517
418
    case VLC_FOURCC( 'a', 'r', 'a', 'w' ):
518
663
    case VLC_FOURCC( 'a', 'f', 'l', 't' ):
519
663
    case VLC_FOURCC( 'u', 'l', 'a', 'w' ):
520
865
    case VLC_CODEC_ALAW:
521
885
    case VLC_CODEC_MULAW:
522
885
        if( FrameInfo_PCM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
523
885
                           &p_sys->fmt ) )
524
3
            goto error;
525
882
        p_sys->fmt.i_codec =
526
882
            vlc_fourcc_GetCodecAudio( p_sys->fmt.i_codec,
527
882
                                      p_sys->fmt.audio.i_bitspersample );
528
882
        if( p_sys->fmt.i_codec == 0 ) {
529
0
            msg_Err( p_demux, "Unrecognized codec" );
530
0
            goto error;
531
0
        }
532
882
        break;
533
882
    case VLC_CODEC_ADPCM_MS:
534
    /* FIXME not sure at all FIXME */
535
84
    case VLC_FOURCC( 'm', 's', 0x00, 0x61 ):
536
149
    case VLC_FOURCC( 'm', 's', 0x00, 0x62 ):
537
149
        if( FrameInfo_MS_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
538
149
                                &p_sys->fmt ) )
539
0
            goto error;
540
149
        break;
541
200
    case VLC_CODEC_ADPCM_IMA_WAV:
542
200
        if( FrameInfo_IMA_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
543
200
                                 &p_sys->fmt ) )
544
0
            goto error;
545
200
        break;
546
200
    case VLC_CODEC_ADPCM_CREATIVE:
547
35
        if( FrameInfo_Creative_ADPCM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
548
35
                                      &p_sys->fmt ) )
549
0
            goto error;
550
35
        break;
551
35
    case VLC_CODEC_MPGA:
552
0
    case VLC_CODEC_A52:
553
        /* FIXME set end of area FIXME */
554
0
        goto error;
555
5
    case VLC_CODEC_GSM_MS:
556
186
    case VLC_CODEC_ADPCM_G726:
557
187
    case VLC_CODEC_TRUESPEECH:
558
187
    case VLC_CODEC_ATRAC3P:
559
220
    case VLC_CODEC_ATRAC3:
560
513
    case VLC_CODEC_G723_1:
561
572
    case VLC_CODEC_WMA2:
562
572
        if( FrameInfo_MSGSM( &p_sys->i_frame_size, &p_sys->i_frame_samples,
563
572
                             &p_sys->fmt ) )
564
0
            goto error;
565
572
        break;
566
572
    default:
567
23
        msg_Err( p_demux, "unsupported codec (%4.4s)",
568
23
                 (char*)&p_sys->fmt.i_codec );
569
23
        goto error;
570
1.86k
    }
571
572
1.83k
    if( p_sys->i_frame_size <= 0 || p_sys->i_frame_samples <= 0 )
573
1
    {
574
1
        msg_Dbg( p_demux, "invalid frame size: %i %i", p_sys->i_frame_size,
575
1
                                                       p_sys->i_frame_samples );
576
1
        goto error;
577
1
    }
578
1.83k
    if( p_sys->fmt.audio.i_rate == 0 )
579
0
    {
580
0
        msg_Dbg( p_demux, "invalid sample rate: %i", p_sys->fmt.audio.i_rate );
581
0
        goto error;
582
0
    }
583
584
1.83k
    msg_Dbg( p_demux, "found %s audio format", psz_name );
585
586
1.83k
    return VLC_SUCCESS;
587
588
53
error:
589
53
    free( p_wf );
590
53
    return VLC_EGENERIC;
591
1.83k
}
592
593
static int Open( vlc_object_t * p_this )
594
361
{
595
361
    demux_t     *p_demux = (demux_t*)p_this;
596
361
    demux_sys_t *p_sys;
597
598
361
    const uint8_t *p_peek;
599
361
    bool           b_is_rf64;
600
361
    uint32_t       i_size;
601
602
    /* Is it a wav file ? */
603
361
    if( vlc_stream_Peek( p_demux->s, &p_peek, 12 ) < 12 )
604
0
        return VLC_EGENERIC;
605
606
361
    b_is_rf64 = ( memcmp( p_peek, "RF64", 4 ) == 0 );
607
361
    if( ( !b_is_rf64 && memcmp( p_peek, "RIFF", 4 ) ) ||
608
361
          memcmp( &p_peek[8], "WAVE", 4 ) )
609
9
    {
610
9
        return VLC_EGENERIC;
611
9
    }
612
613
352
    p_demux->pf_demux     = Demux;
614
352
    p_demux->pf_control   = Control;
615
352
    p_demux->p_sys        = p_sys = malloc( sizeof( *p_sys ) );
616
352
    if( unlikely(!p_sys) )
617
0
        return VLC_ENOMEM;
618
619
352
    es_format_Init( &p_sys->fmt, AUDIO_ES, 0 );
620
352
    p_sys->p_es           = NULL;
621
352
    p_sys->i_data_pos = p_sys->i_data_size = 0;
622
352
    p_sys->i_chans_to_reorder = 0;
623
352
    p_sys->i_channel_mask = 0;
624
625
    /* skip riff header */
626
352
    if( vlc_stream_Read( p_demux->s, NULL, 12 ) != 12 )
627
0
        goto error;
628
629
352
    bool eof = false;
630
352
    enum wav_chunk_id id;
631
4.37k
    while( !eof && ( ChunkGetNext( p_demux, &id, &i_size ) ) == VLC_SUCCESS )
632
4.08k
    {
633
4.08k
        if( i_size == 0 )
634
0
        {
635
0
            msg_Err( p_demux, "invalid chunk with a size 0");
636
0
            goto error;
637
0
        }
638
639
4.08k
        switch( id )
640
4.08k
        {
641
655
            case wav_chunk_id_data:
642
655
            {
643
655
                uint64_t i_stream_size;
644
655
                if( vlc_stream_GetSize( p_demux->s, &i_stream_size ) != VLC_SUCCESS )
645
0
                    goto error;
646
655
                p_sys->i_data_pos = vlc_stream_Tell( p_demux->s );
647
648
655
                if( !b_is_rf64 && i_stream_size >= i_size + p_sys->i_data_pos )
649
265
                    p_sys->i_data_size = i_size;
650
651
655
                if( likely( b_is_rf64
652
655
                 || p_sys->i_data_pos + i_size == i_stream_size ) )
653
194
                {
654
                    /* Bypass the final ChunkGetNext() to avoid a read+seek
655
                     * since this chunk is the last one */
656
194
                    eof = true;
657
194
                }   /* Unlikely case where there is a chunk after 'data' */
658
461
                else if( ChunkSkip( p_demux, i_size ) != VLC_SUCCESS )
659
1
                    goto error;
660
654
                break;
661
655
            }
662
1.53k
            case wav_chunk_id_ds64:
663
1.53k
                if( b_is_rf64 )
664
1.53k
                {
665
1.53k
                    if( ChunkParseDS64( p_demux, i_size ) != VLC_SUCCESS )
666
3
                        goto error;
667
1.53k
                }
668
0
                else
669
0
                {
670
0
                    msg_Err( p_demux, "'ds64' chunk found but format not RF64" );
671
0
                    goto error;
672
0
                }
673
1.53k
                break;
674
1.89k
            case wav_chunk_id_fmt:
675
1.89k
                if( ChunkParseFmt( p_demux, i_size ) != VLC_SUCCESS )
676
53
                    goto error;
677
1.83k
                break;
678
4.08k
        }
679
4.08k
    }
680
681
295
    if( p_sys->i_data_pos == 0 || p_sys->i_data_size == 0
682
295
     || p_sys->i_frame_samples <= 0 )
683
42
    {
684
42
        msg_Err( p_demux, "'%s' chunk not found",
685
42
                 p_sys->i_data_pos == 0 ? "data" :
686
42
                 p_sys->i_frame_samples <= 0 ? "fmt " :
687
42
                 b_is_rf64 ? "ds64" : "data" );
688
42
        goto error;
689
42
    }
690
691
    /* Seek back to data position if needed */
692
253
    if( unlikely( vlc_stream_Tell( p_demux->s ) != p_sys->i_data_pos )
693
253
     && vlc_stream_Seek( p_demux->s, p_sys->i_data_pos ) != VLC_SUCCESS )
694
0
        goto error;
695
696
253
    if( p_sys->fmt.i_bitrate <= 0 )
697
44
    {
698
44
        p_sys->fmt.i_bitrate = (int64_t)p_sys->i_frame_size *
699
44
            p_sys->fmt.audio.i_rate * 8 / p_sys->i_frame_samples;
700
44
    }
701
702
253
    p_sys->fmt.i_id = 0;
703
253
    p_sys->p_es = es_out_Add( p_demux->out, &p_sys->fmt );
704
253
    if( unlikely(p_sys->p_es == NULL) )
705
0
        goto error;
706
707
253
    date_Init( &p_sys->pts, p_sys->fmt.audio.i_rate, 1 );
708
253
    date_Set( &p_sys->pts, VLC_TICK_0 );
709
710
253
    return VLC_SUCCESS;
711
712
99
error:
713
99
    es_format_Clean( &p_sys->fmt );
714
99
    free( p_sys );
715
99
    return VLC_EGENERIC;
716
253
}
717
718
104
vlc_module_begin ()
719
52
    set_description( N_("WAV demuxer") )
720
52
    set_subcategory( SUBCAT_INPUT_DEMUX )
721
52
    set_capability( "demux", 142 )
722
104
    set_callbacks( Open, Close )
723
52
vlc_module_end ()