voc.c 16.3 KB
Newer Older
1
2
3
/*****************************************************************************
 * voc.c : Creative Voice File (.VOC) demux module for vlc
 *****************************************************************************
4
 * Copyright (C) 2005 the VideoLAN team
5
 * $Id$
6
 *
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
7
 * Authors: Remi Denis-Courmont <rem # videolan.org>
8
9
10
11
12
13
14
15
16
17
18
19
20
 *
 * 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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */

#include <vlc/vlc.h>
#include <vlc/input.h>
#include <vlc/aout.h>

#include <codecs.h>

/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
static int  Open ( vlc_object_t * );
static void Close( vlc_object_t * );

vlc_module_begin();
    set_description( _("VOC demuxer") );
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_DEMUX );
    set_capability( "demux2", 10 );
    set_callbacks( Open, Close );
vlc_module_end();

/*****************************************************************************
 * Local prototypes
 *****************************************************************************/
static int Demux  ( demux_t * );
static int Control( demux_t *, int i_query, va_list args );

struct demux_sys_t
{
    es_format_t     fmt;
    es_out_id_t     *p_es;

60
61
    int64_t         i_block_start;
    int64_t         i_block_end;
62
63
64
65
66

    int64_t         i_loop_offset;
    unsigned        i_loop_count;
    unsigned        i_silence_countdown;

67
68
69
70
71
72
73
74
75
76
77
78
    date_t          pts;
};

static const char ct_header[] = "Creative Voice File\x1a";

/*****************************************************************************
 * Open: check file and initializes structures
 *****************************************************************************/
static int Open( vlc_object_t * p_this )
{
    demux_t     *p_demux = (demux_t*)p_this;
    demux_sys_t *p_sys;
79
    uint8_t     *p_buf;
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
    uint16_t    i_data_offset, i_version;

    if( stream_Peek( p_demux->s, &p_buf, 26 ) < 26 )
        return VLC_EGENERIC;

    if( memcmp( p_buf, ct_header, 20 ) )
        return VLC_EGENERIC;
    p_buf += 20;

    i_data_offset = GetWLE( p_buf );
    if ( i_data_offset < 26 /* not enough room for full VOC header */ )
        return VLC_EGENERIC;
    p_buf += 2;

    i_version = GetWLE( p_buf );
    if( ( i_version != 0x10A ) && ( i_version != 0x114 ) )
        return VLC_EGENERIC; /* unknown VOC version */
    p_buf += 2;

    if( GetWLE( p_buf ) != (uint16_t)(0x1234 + ~i_version) )
        return VLC_EGENERIC;

    /* We have a valid VOC header */
    msg_Dbg( p_demux, "CT Voice file v%d.%d", i_version >> 8,
             i_version & 0xff );

    /* skip VOC header */
    if( stream_Read( p_demux->s, NULL, i_data_offset ) < i_data_offset )
        return VLC_EGENERIC;

    p_demux->pf_demux   = Demux;
    p_demux->pf_control = Control;
    p_demux->p_sys      = p_sys = malloc( sizeof( demux_sys_t ) );
113
114
115
    if( p_sys == NULL )
        return VLC_ENOMEM;

116
    p_sys->i_silence_countdown = p_sys->i_block_start = p_sys->i_block_end =
117
    p_sys->i_loop_count = 0;
118
119
120
121
122
    p_sys->p_es = NULL;

    date_Init( &p_sys->pts, 1, 1 );
    date_Set( &p_sys->pts, 1 );

123
124
    es_format_Init( &p_sys->fmt, AUDIO_ES, 0 );

125
126
    return VLC_SUCCESS;
}
127

128
129
130
131
132
133
134
135
136

static int fmtcmp( es_format_t *ofmt, es_format_t *nfmt )
{
    return (ofmt->audio.i_bitspersample != nfmt->audio.i_bitspersample)
        || (ofmt->audio.i_rate != nfmt->audio.i_rate)
        || (ofmt->audio.i_channels != nfmt->audio.i_channels);
}


137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/*
 * Converts old-style VOC sample rates to commonly used ones
 * so as not to confuse sound card drivers.
 * (I assume 16k, 24k and 32k are never found in .VOC files)
 */
static unsigned int fix_voc_sr( unsigned int sr )
{
    switch( sr )
    {
        /*case 8000:
            return 8000;*/
        case 11111:
            return 11025;

        case 22222:
            return 22050;

        case 44444:
            return 44100;
    }
    return sr;
}

160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
static int ReadBlockHeader( demux_t *p_demux )
{
    es_format_t     new_fmt;
    uint8_t buf[8];
    int32_t i_block_size;
    demux_sys_t *p_sys = p_demux->p_sys;

    if( stream_Read( p_demux->s, buf, 4 ) < 4 )
        return VLC_EGENERIC; /* EOF */

    i_block_size = GetDWLE( buf ) >> 8;
    msg_Dbg( p_demux, "new block: type: %u, size: %u",
             (unsigned)*buf, i_block_size );

    es_format_Init( &new_fmt, AUDIO_ES, 0 );
175
176
177

    switch( *buf )
    {
178
179
180
        case 0: /* not possible : caught with earlier stream_Read */
            goto corrupt;

181
        case 1:
182
            if( i_block_size < 2 )
183
                goto corrupt;
184
            i_block_size -= 2;
185
186

            if( stream_Read( p_demux->s, buf, 2 ) < 2 )
187
                goto corrupt;
188
189
190

            if( buf[1] )
            {
191
                msg_Err( p_demux, "unsupported compression" );
192
                return VLC_EGENERIC;
193
194
            }

195
            new_fmt.i_codec = VLC_FOURCC('u','8',' ',' ');
196
            new_fmt.audio.i_rate = fix_voc_sr( 1000000L / (256L - buf[0]) );
197
198
199
200
201
            new_fmt.audio.i_bytes_per_frame = 1;
            new_fmt.audio.i_frame_length = 1;
            new_fmt.audio.i_channels = 1;
            new_fmt.audio.i_blockalign = 1;
            new_fmt.audio.i_bitspersample = 8;
202
            new_fmt.i_bitrate = new_fmt.audio.i_rate * 8;
203
204
            break;

205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
        case 2: /* data block with same format as the previous one */
            if( p_sys->p_es == NULL )
                goto corrupt; /* no previous block! */

            memcpy( &new_fmt, &p_sys->fmt, sizeof( new_fmt ) );
            break;

        case 3: /* silence block */
            if( ( i_block_size != 3 )
             || ( stream_Read( p_demux->s, buf, 3 ) < 3 ) )
                goto corrupt;

            i_block_size = 0;
            p_sys->i_silence_countdown = GetWLE( buf );

            new_fmt.i_codec = VLC_FOURCC('u','8',' ',' ');
221
            new_fmt.audio.i_rate = fix_voc_sr( 1000000L / (256L - buf[0]) );
222
223
224
225
226
            new_fmt.audio.i_bytes_per_frame = 1;
            new_fmt.audio.i_frame_length = 1;
            new_fmt.audio.i_channels = 1;
            new_fmt.audio.i_blockalign = 1;
            new_fmt.audio.i_bitspersample = 8;
227
            new_fmt.i_bitrate = new_fmt.audio.i_rate * 8;
228
229
230
231
232
233
            break;

        case 6: /* repeat block */
            if( ( i_block_size != 2 )
             || ( stream_Read( p_demux->s, buf, 2 ) < 2 ) )
                goto corrupt;
234
235

            i_block_size = 0;
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
            p_sys->i_loop_count = GetWLE( buf );
            p_sys->i_loop_offset = stream_Tell( p_demux->s );
            break;

        case 7: /* repeat end block */
            if( i_block_size != 0 )
                goto corrupt;

            if( p_sys->i_loop_count > 0 )
            {
                if( stream_Seek( p_demux->s, p_sys->i_loop_offset ) )
                    msg_Warn( p_demux, "cannot loop: seek failed" );
                else
                    p_sys->i_loop_count--;
            }
251
252
            break;

253
254
255
256
257
258
259
260
261
262
263
264
265
266
        case 8: 
            /* 
             * Block 8 is a big kludge to add stereo support to block 1 :
             * A block of type 8 is always followed by a block of type 1
             * and specifies the number of channels in that 1-block
             * (normally block 1 are always mono). In practice, block type 9
             * is used for stereo rather than 8
             */
            if( ( i_block_size != 4 )
             || ( stream_Read( p_demux->s, buf, 4 ) < 4 ) )
                goto corrupt;

            if( buf[2] )
            {
267
                msg_Err( p_demux, "unsupported compression" );
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
                return VLC_EGENERIC;
            }

            new_fmt.i_codec = VLC_FOURCC('u','8',' ',' ');
            new_fmt.audio.i_channels = buf[3] + 1; /* can't be nul */
            new_fmt.audio.i_rate = 256000000L /
                          ((65536L - GetWLE(buf)) * new_fmt.audio.i_channels);
            new_fmt.audio.i_bytes_per_frame = new_fmt.audio.i_channels;
            new_fmt.audio.i_frame_length = 1;
            new_fmt.audio.i_blockalign = new_fmt.audio.i_bytes_per_frame;
            new_fmt.audio.i_bitspersample = 8 * new_fmt.audio.i_bytes_per_frame;
            new_fmt.i_bitrate = new_fmt.audio.i_rate * 8;

            /* read subsequent block 1 */
            if( stream_Read( p_demux->s, buf, 4 ) < 4 )
                return VLC_EGENERIC; /* EOF */
        
            i_block_size = GetDWLE( buf ) >> 8;
            msg_Dbg( p_demux, "new block: type: %u, size: %u",
                    (unsigned)*buf, i_block_size );
            if( i_block_size < 2 )
                goto corrupt;
            i_block_size -= 2;

            if( stream_Read( p_demux->s, buf, 2 ) < 2 )
                goto corrupt;

            if( buf[1] )
            {
297
                msg_Err( p_demux, "unsupported compression" );
298
299
300
301
                return VLC_EGENERIC;
            }

            break;
302

303
        case 9: /* newer data block with channel number and bits resolution */
304
            if( i_block_size < 12 )
305
                goto corrupt;
306
            i_block_size -= 12;
307
308
309

            if( ( stream_Read( p_demux->s, buf, 8 ) < 8 )
             || ( stream_Read( p_demux->s, NULL, 4 ) < 4 ) )
310
                goto corrupt;
311

312
313
314
            new_fmt.audio.i_rate = GetDWLE( buf );
            new_fmt.audio.i_bitspersample = buf[4];
            new_fmt.audio.i_channels = buf[5];
315
316
317
318

            switch( GetWLE( &buf[6] ) ) /* format */
            {
                case 0x0000: /* PCM */
319
                    switch( new_fmt.audio.i_bitspersample )
320
321
                    {
                        case 8:
322
                            new_fmt.i_codec = VLC_FOURCC('u','8',' ',' ');
323
324
325
                            break;

                        case 16:
326
                            new_fmt.i_codec = VLC_FOURCC('u','1','6','l');
327
328
329
                            break;

                        default:
330
                            msg_Err( p_demux, "unsupported bit res.: %u bits",
331
                                     new_fmt.audio.i_bitspersample );
332
333
334
335
336
                            return VLC_EGENERIC;
                    }
                    break;

                case 0x0004: /* signed */
337
                    switch( new_fmt.audio.i_bitspersample )
338
339
                    {
                        case 8:
340
                            new_fmt.i_codec = VLC_FOURCC('s','8',' ',' ');
341
342
343
                            break;

                        case 16:
344
                            new_fmt.i_codec = VLC_FOURCC('s','1','6','l');
345
346
347
                            break;

                        default:
348
                            msg_Err( p_demux, "unsupported bit res.: %u bits",
349
                                     new_fmt.audio.i_bitspersample );
350
351
352
353
354
                            return VLC_EGENERIC;
                    }
                    break;

                default: 
355
                    msg_Err( p_demux, "unsupported compression" );
356
                    return VLC_EGENERIC;
357
358
            }

359
360
361
            new_fmt.audio.i_bytes_per_frame = new_fmt.audio.i_channels
                * (new_fmt.audio.i_bitspersample / 8);
            new_fmt.audio.i_frame_length = 1;
362
            new_fmt.audio.i_blockalign = new_fmt.audio.i_bytes_per_frame;
363
364
            new_fmt.i_bitrate = 8 * new_fmt.audio.i_rate
                                     * new_fmt.audio.i_bytes_per_frame;
365
366
367
            break;

        default:
368
            msg_Dbg( p_demux, "unknown block type %u - skipping block",
369
370
371
372
373
374
375
                     (unsigned)*buf);
        case 4: /* blocks of non-audio types can be skipped */
        case 5:
            if( stream_Read( p_demux->s, NULL, i_block_size ) < i_block_size )
                goto corrupt;
            i_block_size = 0;
            break;
376
377
    }

378
379
    p_sys->i_block_start = stream_Tell( p_demux->s );
    p_sys->i_block_end = p_sys->i_block_start + i_block_size;
380

381
    if( i_block_size || p_sys->i_silence_countdown )
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
    {
        /* we've read a block with data in it - update decoder */
        msg_Dbg( p_demux, "fourcc: %4.4s, channels: %d, "
                 "freq: %d Hz, bitrate: %dKo/s, blockalign: %d, "
                 "bits/samples: %d", (char *)&new_fmt.i_codec,
                 new_fmt.audio.i_channels, new_fmt.audio.i_rate,
                 new_fmt.i_bitrate / 8192, new_fmt.audio.i_blockalign,
                 new_fmt.audio.i_bitspersample );

        if( ( p_sys->p_es != NULL ) && fmtcmp( &p_sys->fmt, &new_fmt ) )
        {
            msg_Dbg( p_demux, "codec change needed" );
            es_out_Del( p_demux->out, p_sys->p_es );
            p_sys->p_es = NULL;
        }

        if( p_sys->p_es == NULL )
        {
            memcpy( &p_sys->fmt, &new_fmt, sizeof( p_sys->fmt ) );
            date_Change( &p_sys->pts, p_sys->fmt.audio.i_rate, 1 );
            p_sys->p_es = es_out_Add( p_demux->out, &p_sys->fmt );
        }
    }
405
406

    return VLC_SUCCESS;
407
408
409
410

corrupt:
    msg_Err( p_demux, "corrupted file - halting demux" );
    return VLC_EGENERIC;
411
412
413
414
415
416
417
}

/*****************************************************************************
 * Demux: read packet and send them to decoders
 *****************************************************************************
 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
 *****************************************************************************/
418
#define SAMPLES_BUFFER 1000
419
420
421
422
static int Demux( demux_t *p_demux )
{
    demux_sys_t *p_sys = p_demux->p_sys;
    block_t     *p_block;
423
424
425
426
427
428
429
430
    int64_t     i_offset, i;

    i_offset = stream_Tell( p_demux->s );

    while( ( i_offset >= p_sys->i_block_end )
         && ( p_sys->i_silence_countdown == 0 ) )
        if( ReadBlockHeader( p_demux ) != VLC_SUCCESS )
            return 0;
431

432
433
    if( p_sys->i_silence_countdown == 0 )
    {
434
435
        i = ( p_sys->i_block_end - i_offset )
            / p_sys->fmt.audio.i_bytes_per_frame;
436
437
        if( i > SAMPLES_BUFFER )
            i = SAMPLES_BUFFER;
438

439
        p_block = stream_Block( p_demux->s,
440
                                p_sys->fmt.audio.i_bytes_per_frame * i );
441
442
443
        if( p_block == NULL )
        {
            msg_Warn( p_demux, "cannot read data" );
444
            return 0;
445
446
447
448
        }
    }
    else
    {   /* emulates silence from the stream */
449
        i = p_sys->i_silence_countdown;
450
451
        if( i > SAMPLES_BUFFER )
            i = SAMPLES_BUFFER;
452
453

        p_block = block_New( p_demux, i );
454
455
456
        if( p_block == NULL )
            return VLC_ENOMEM;

457
458
        memset( p_block->p_buffer, 0, i );
        p_sys->i_silence_countdown -= i;
459
460
461
    }

    p_block->i_dts = p_block->i_pts =
462
        date_Increment( &p_sys->pts, p_sys->fmt.audio.i_frame_length * i );
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487

    es_out_Control( p_demux->out, ES_OUT_SET_PCR, p_block->i_pts );

    es_out_Send( p_demux->out, p_sys->p_es, p_block );

    return 1;
}

/*****************************************************************************
 * Close: frees unused data
 *****************************************************************************/
static void Close ( vlc_object_t * p_this )
{
    demux_sys_t *p_sys  = ((demux_t *)p_this)->p_sys;

    free( p_sys );
}

/*****************************************************************************
 * Control:
 *****************************************************************************/
static int Control( demux_t *p_demux, int i_query, va_list args )
{
    demux_sys_t *p_sys  = p_demux->p_sys;

488
489
    return demux2_vaControlHelper( p_demux->s, p_sys->i_block_start,
                                   p_sys->i_block_end,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
490
                                   p_sys->fmt.i_bitrate,
491
492
493
                                   p_sys->fmt.audio.i_blockalign,
                                   i_query, args );
}