vorbis.c 34.5 KB
Newer Older
gbazin's avatar
   
gbazin committed
1
/*****************************************************************************
gbazin's avatar
   
gbazin committed
2
 * vorbis.c: vorbis decoder/encoder/packetizer module making use of libvorbis.
gbazin's avatar
   
gbazin committed
3
 *****************************************************************************
4
 * Copyright (C) 2001-2003 the VideoLAN team
5
 * $Id$
gbazin's avatar
   
gbazin committed
6
 *
7
 * Authors: Gildas Bazin <gbazin@videolan.org>
gbazin's avatar
   
gbazin committed
8
9
10
11
12
 *
 * 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.
Sam Hocevar's avatar
Sam Hocevar committed
13
 *
gbazin's avatar
   
gbazin committed
14
15
16
17
18
19
20
 * 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.
gbazin's avatar
   
gbazin committed
22
23
24
25
26
27
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <vlc/vlc.h>
zorglub's avatar
zorglub committed
28
29
30
31
#include <vlc_codec.h>
#include <vlc_aout.h>
#include <vlc_input.h>
#include <vlc_sout.h>
gbazin's avatar
   
gbazin committed
32
33

#include <ogg/ogg.h>
gbazin's avatar
   
gbazin committed
34

gbazin's avatar
   
gbazin committed
35
36
#ifdef MODULE_NAME_IS_tremor
#include <tremor/ivorbiscodec.h>
gbazin's avatar
   
gbazin committed
37

gbazin's avatar
   
gbazin committed
38
#else
gbazin's avatar
   
gbazin committed
39
#include <vorbis/codec.h>
gbazin's avatar
   
gbazin committed
40
41
42
43
44
45
46
47
48

/* vorbis header */
#ifdef HAVE_VORBIS_VORBISENC_H
#   include <vorbis/vorbisenc.h>
#   ifndef OV_ECTL_RATEMANAGE_AVG
#       define OV_ECTL_RATEMANAGE_AVG 0x0
#   endif
#endif

gbazin's avatar
   
gbazin committed
49
#endif
gbazin's avatar
   
gbazin committed
50
51

/*****************************************************************************
gbazin's avatar
   
gbazin committed
52
 * decoder_sys_t : vorbis decoder descriptor
gbazin's avatar
   
gbazin committed
53
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
54
struct decoder_sys_t
gbazin's avatar
   
gbazin committed
55
{
gbazin's avatar
   
gbazin committed
56
57
58
    /* Module mode */
    vlc_bool_t b_packetizer;

gbazin's avatar
   
gbazin committed
59
    /*
gbazin's avatar
   
gbazin committed
60
     * Input properties
gbazin's avatar
   
gbazin committed
61
     */
gbazin's avatar
   
gbazin committed
62
    int i_headers;
gbazin's avatar
   
gbazin committed
63
64
65
66
67
68
69
70
71
72
73
74

    /*
     * Vorbis properties
     */
    vorbis_info      vi; /* struct that stores all the static vorbis bitstream
                            settings */
    vorbis_comment   vc; /* struct that stores all the bitstream user
                          * comments */
    vorbis_dsp_state vd; /* central working state for the packet->PCM
                          * decoder */
    vorbis_block     vb; /* local working space for packet->PCM decode */

gbazin's avatar
   
gbazin committed
75
76
77
    /*
     * Common properties
     */
gbazin's avatar
   
gbazin committed
78
79
    audio_date_t end_date;
    int          i_last_block_size;
gbazin's avatar
   
gbazin committed
80

81
82
    int i_input_rate;

83
84
85
86
    /*
    ** Channel reordering
    */
    int pi_chan_table[AOUT_CHAN_MAX];
gbazin's avatar
   
gbazin committed
87
};
gbazin's avatar
   
gbazin committed
88

gbazin's avatar
   
gbazin committed
89
static int pi_channels_maps[7] =
90
91
{
    0,
gbazin's avatar
   
gbazin committed
92
93
    AOUT_CHAN_CENTER,
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
94
    AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
gbazin's avatar
   
gbazin committed
95
96
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
     | AOUT_CHAN_REARRIGHT,
97
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
gbazin's avatar
   
gbazin committed
98
99
100
     | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT,
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
     | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT | AOUT_CHAN_LFE
101
102
};

103
104
105
106
107
108
/*
**  channel order as defined in http://www.ogghelp.com/ogg/glossary.cfm#Audio_Channels
*/

/* recommended vorbis channel order for 6 channels */
static const uint32_t pi_6channels_in[] =
dionoea's avatar
dionoea committed
109
{ AOUT_CHAN_LEFT, AOUT_CHAN_CENTER, AOUT_CHAN_RIGHT,
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
  AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,AOUT_CHAN_LFE,0 };

/* recommended vorbis channel order for 4 channels */
static const uint32_t pi_4channels_in[] =
{ AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };

/* recommended vorbis channel order for 3 channels */
static const uint32_t pi_3channels_in[] =
{ AOUT_CHAN_LEFT, AOUT_CHAN_CENTER, AOUT_CHAN_RIGHT, 0 };

/* our internal channel order (WG-4 order) */
static const uint32_t pi_channels_out[] =
{ AOUT_CHAN_LEFT, AOUT_CHAN_RIGHT, AOUT_CHAN_REARLEFT, AOUT_CHAN_REARRIGHT,
  AOUT_CHAN_CENTER, AOUT_CHAN_LFE, 0 };

gbazin's avatar
   
gbazin committed
125
/****************************************************************************
gbazin's avatar
   
gbazin committed
126
 * Local prototypes
gbazin's avatar
   
gbazin committed
127
 ****************************************************************************/
gbazin's avatar
   
gbazin committed
128
129
130
131
static int  OpenDecoder   ( vlc_object_t * );
static int  OpenPacketizer( vlc_object_t * );
static void CloseDecoder  ( vlc_object_t * );
static void *DecodeBlock  ( decoder_t *, block_t ** );
gbazin's avatar
   
gbazin committed
132

133
static int  ProcessHeaders( decoder_t * );
gbazin's avatar
   
gbazin committed
134
static void *ProcessPacket ( decoder_t *, ogg_packet *, block_t ** );
gbazin's avatar
   
gbazin committed
135

gbazin's avatar
   
gbazin committed
136
137
static aout_buffer_t *DecodePacket  ( decoder_t *, ogg_packet * );
static block_t *SendPacket( decoder_t *, ogg_packet *, block_t * );
gbazin's avatar
   
gbazin committed
138
139

static void ParseVorbisComments( decoder_t * );
gbazin's avatar
   
gbazin committed
140

141
142
static void ConfigureChannelOrder(int *, int, uint32_t, vlc_bool_t );

gbazin's avatar
   
gbazin committed
143
#ifdef MODULE_NAME_IS_tremor
144
static void Interleave   ( int32_t *, const int32_t **, int, int, int * );
gbazin's avatar
   
gbazin committed
145
#else
146
static void Interleave   ( float *, const float **, int, int, int * );
gbazin's avatar
   
gbazin committed
147
#endif
gbazin's avatar
   
gbazin committed
148

gbazin's avatar
   
gbazin committed
149
150
151
152
153
154
#ifndef MODULE_NAME_IS_tremor
static int OpenEncoder   ( vlc_object_t * );
static void CloseEncoder ( vlc_object_t * );
static block_t *Encode   ( encoder_t *, aout_buffer_t * );
#endif

gbazin's avatar
   
gbazin committed
155
156
157
/*****************************************************************************
 * Module descriptor
 *****************************************************************************/
gbazin's avatar
gbazin committed
158
159
#define ENC_QUALITY_TEXT N_("Encoding quality")
#define ENC_QUALITY_LONGTEXT N_( \
zorglub's avatar
zorglub committed
160
  "Enforce a quality between 1 (low) and 10 (high), instead " \
gbazin's avatar
gbazin committed
161
162
163
  "of specifying a particular bitrate. This will produce a VBR stream." )
#define ENC_MAXBR_TEXT N_("Maximum encoding bitrate")
#define ENC_MAXBR_LONGTEXT N_( \
zorglub's avatar
zorglub committed
164
  "Maximum bitrate in kbps. This is useful for streaming applications." )
gbazin's avatar
gbazin committed
165
166
#define ENC_MINBR_TEXT N_("Minimum encoding bitrate")
#define ENC_MINBR_LONGTEXT N_( \
zorglub's avatar
zorglub committed
167
  "Minimum bitrate in kbps. This is useful for encoding for a fixed-size channel." )
168
169
#define ENC_CBR_TEXT N_("CBR encoding")
#define ENC_CBR_LONGTEXT N_( \
zorglub's avatar
zorglub committed
170
  "Force a constant bitrate encoding (CBR)." )
gbazin's avatar
gbazin committed
171

gbazin's avatar
   
gbazin committed
172
vlc_module_begin();
173
    set_shortname( "Vorbis" );
gbazin's avatar
   
gbazin committed
174
    set_description( _("Vorbis audio decoder") );
gbazin's avatar
   
gbazin committed
175
176
177
#ifdef MODULE_NAME_IS_tremor
    set_capability( "decoder", 90 );
#else
gbazin's avatar
   
gbazin committed
178
    set_capability( "decoder", 100 );
gbazin's avatar
   
gbazin committed
179
#endif
zorglub's avatar
zorglub committed
180
181
    set_category( CAT_INPUT );
    set_subcategory( SUBCAT_INPUT_ACODEC );
gbazin's avatar
   
gbazin committed
182
    set_callbacks( OpenDecoder, CloseDecoder );
gbazin's avatar
   
gbazin committed
183
184
185
186

    add_submodule();
    set_description( _("Vorbis audio packetizer") );
    set_capability( "packetizer", 100 );
gbazin's avatar
   
gbazin committed
187
    set_callbacks( OpenPacketizer, CloseDecoder );
gbazin's avatar
   
gbazin committed
188
189

#ifndef MODULE_NAME_IS_tremor
gbazin's avatar
gbazin committed
190
#   define ENC_CFG_PREFIX "sout-vorbis-"
gbazin's avatar
   
gbazin committed
191
192
    add_submodule();
    set_description( _("Vorbis audio encoder") );
gbazin's avatar
   
gbazin committed
193
    set_capability( "encoder", 100 );
194
#if defined(HAVE_VORBIS_VORBISENC_H)
dionoea's avatar
dionoea committed
195
    set_callbacks( OpenEncoder, CloseEncoder );
196
#endif
gbazin's avatar
gbazin committed
197

bigben's avatar
   
bigben committed
198
    add_integer( ENC_CFG_PREFIX "quality", 0, NULL, ENC_QUALITY_TEXT,
gbazin's avatar
gbazin committed
199
200
201
202
203
                 ENC_QUALITY_LONGTEXT, VLC_FALSE );
    add_integer( ENC_CFG_PREFIX "max-bitrate", 0, NULL, ENC_MAXBR_TEXT,
                 ENC_MAXBR_LONGTEXT, VLC_FALSE );
    add_integer( ENC_CFG_PREFIX "min-bitrate", 0, NULL, ENC_MINBR_TEXT,
                 ENC_MINBR_LONGTEXT, VLC_FALSE );
204
205
    add_bool( ENC_CFG_PREFIX "cbr", 0, NULL, ENC_CBR_TEXT,
                 ENC_CBR_LONGTEXT, VLC_FALSE );
gbazin's avatar
   
gbazin committed
206
207
#endif

gbazin's avatar
   
gbazin committed
208
209
vlc_module_end();

210
#ifndef MODULE_NAME_IS_tremor
gbazin's avatar
gbazin committed
211
static const char *ppsz_enc_options[] = {
212
    "quality", "max-bitrate", "min-bitrate", "cbr", NULL
gbazin's avatar
gbazin committed
213
};
214
#endif
gbazin's avatar
gbazin committed
215

gbazin's avatar
   
gbazin committed
216
217
218
219
220
/*****************************************************************************
 * OpenDecoder: probe the decoder and return score
 *****************************************************************************/
static int OpenDecoder( vlc_object_t *p_this )
{
gbazin's avatar
   
gbazin committed
221
    decoder_t *p_dec = (decoder_t*)p_this;
gbazin's avatar
   
gbazin committed
222
    decoder_sys_t *p_sys;
gbazin's avatar
   
gbazin committed
223

gbazin's avatar
   
gbazin committed
224
    if( p_dec->fmt_in.i_codec != VLC_FOURCC('v','o','r','b') )
gbazin's avatar
   
gbazin committed
225
226
227
228
    {
        return VLC_EGENERIC;
    }

gbazin's avatar
   
gbazin committed
229
    /* Allocate the memory needed to store the decoder's structure */
gbazin's avatar
   
gbazin committed
230
    if( ( p_dec->p_sys = p_sys =
gbazin's avatar
   
gbazin committed
231
232
233
234
235
          (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
    {
        msg_Err( p_dec, "out of memory" );
        return VLC_EGENERIC;
    }
gbazin's avatar
   
gbazin committed
236
237
238

    /* Misc init */
    aout_DateSet( &p_sys->end_date, 0 );
239
    p_sys->i_last_block_size = 0;
gbazin's avatar
   
gbazin committed
240
241
    p_sys->b_packetizer = VLC_FALSE;
    p_sys->i_headers = 0;
242
    p_sys->i_input_rate = INPUT_RATE_DEFAULT;
gbazin's avatar
   
gbazin committed
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260

    /* Take care of vorbis init */
    vorbis_info_init( &p_sys->vi );
    vorbis_comment_init( &p_sys->vc );

    /* Set output properties */
    p_dec->fmt_out.i_cat = AUDIO_ES;
#ifdef MODULE_NAME_IS_tremor
    p_dec->fmt_out.i_codec = VLC_FOURCC('f','i','3','2');
#else
    p_dec->fmt_out.i_codec = VLC_FOURCC('f','l','3','2');
#endif

    /* Set callbacks */
    p_dec->pf_decode_audio = (aout_buffer_t *(*)(decoder_t *, block_t **))
        DecodeBlock;
    p_dec->pf_packetize    = (block_t *(*)(decoder_t *, block_t **))
        DecodeBlock;
gbazin's avatar
   
gbazin committed
261

gbazin's avatar
   
gbazin committed
262
263
264
    return VLC_SUCCESS;
}

gbazin's avatar
   
gbazin committed
265
266
267
268
269
270
static int OpenPacketizer( vlc_object_t *p_this )
{
    decoder_t *p_dec = (decoder_t*)p_this;

    int i_ret = OpenDecoder( p_this );

gbazin's avatar
   
gbazin committed
271
272
273
274
275
    if( i_ret == VLC_SUCCESS )
    {
        p_dec->p_sys->b_packetizer = VLC_TRUE;
        p_dec->fmt_out.i_codec = VLC_FOURCC('v','o','r','b');
    }
gbazin's avatar
   
gbazin committed
276
277
278
279
280

    return i_ret;
}

/****************************************************************************
gbazin's avatar
   
gbazin committed
281
 * DecodeBlock: the whole thing
gbazin's avatar
   
gbazin committed
282
283
284
 ****************************************************************************
 * This function must be fed with ogg packets.
 ****************************************************************************/
gbazin's avatar
   
gbazin committed
285
static void *DecodeBlock( decoder_t *p_dec, block_t **pp_block )
gbazin's avatar
   
gbazin committed
286
287
288
289
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    ogg_packet oggpacket;

gbazin's avatar
   
gbazin committed
290
291
292
293
294
295
296
    if( !pp_block ) return NULL;

    if( *pp_block )
    {
        /* Block to Ogg packet */
        oggpacket.packet = (*pp_block)->p_buffer;
        oggpacket.bytes = (*pp_block)->i_buffer;
297
298
299

        if( (*pp_block)->i_rate > 0 )
            p_sys->i_input_rate = (*pp_block)->i_rate;
gbazin's avatar
   
gbazin committed
300
301
302
303
304
305
306
307
308
309
    }
    else
    {
        if( p_sys->b_packetizer ) return NULL;

        /* Block to Ogg packet */
        oggpacket.packet = NULL;
        oggpacket.bytes = 0;
    }

gbazin's avatar
   
gbazin committed
310
    oggpacket.granulepos = -1;
gbazin's avatar
   
gbazin committed
311
312
313
314
    oggpacket.b_o_s = 0;
    oggpacket.e_o_s = 0;
    oggpacket.packetno = 0;

315
316
    /* Check for headers */
    if( p_sys->i_headers == 0 && p_dec->fmt_in.i_extra )
317
    {
318
        /* Headers already available as extra data */
319
        msg_Dbg( p_dec, "headers already available as extra data" );
320
321
322
323
324
325
326
327
328
329
        p_sys->i_headers = 3;
    }
    else if( oggpacket.bytes && p_sys->i_headers < 3 )
    {
        /* Backup headers as extra data */
        uint8_t *p_extra;

        p_dec->fmt_in.p_extra =
            realloc( p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra +
                     oggpacket.bytes + 2 );
330
        p_extra = (uint8_t *)p_dec->fmt_in.p_extra + p_dec->fmt_in.i_extra;
331
332
        *(p_extra++) = oggpacket.bytes >> 8;
        *(p_extra++) = oggpacket.bytes & 0xFF;
gbazin's avatar
   
gbazin committed
333

334
335
336
337
338
339
340
341
342
343
344
        memcpy( p_extra, oggpacket.packet, oggpacket.bytes );
        p_dec->fmt_in.i_extra += oggpacket.bytes + 2;

        block_Release( *pp_block );
        p_sys->i_headers++;
        return NULL;
    }

    if( p_sys->i_headers == 3 )
    {
        if( ProcessHeaders( p_dec ) != VLC_SUCCESS )
gbazin's avatar
   
gbazin committed
345
        {
346
347
            p_sys->i_headers = 0;
            p_dec->fmt_in.i_extra = 0;
gbazin's avatar
   
gbazin committed
348
349
            block_Release( *pp_block );
            return NULL;
gbazin's avatar
   
gbazin committed
350
        }
351
352
        else p_sys->i_headers++;
    }
gbazin's avatar
   
gbazin committed
353

354
355
    return ProcessPacket( p_dec, &oggpacket, pp_block );
}
gbazin's avatar
   
gbazin committed
356

357
358
359
360
361
362
363
364
365
/*****************************************************************************
 * ProcessHeaders: process Vorbis headers.
 *****************************************************************************/
static int ProcessHeaders( decoder_t *p_dec )
{
    decoder_sys_t *p_sys = p_dec->p_sys;
    ogg_packet oggpacket;
    uint8_t *p_extra;
    int i_extra;
gbazin's avatar
   
gbazin committed
366

367
    if( !p_dec->fmt_in.i_extra ) return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
368

369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
    oggpacket.granulepos = -1;
    oggpacket.b_o_s = 1; /* yes this actually is a b_o_s packet :) */
    oggpacket.e_o_s = 0;
    oggpacket.packetno = 0;
    p_extra = p_dec->fmt_in.p_extra;
    i_extra = p_dec->fmt_in.i_extra;

    /* Take care of the initial Vorbis header */
    oggpacket.bytes = *(p_extra++) << 8;
    oggpacket.bytes |= (*(p_extra++) & 0xFF);
    oggpacket.packet = p_extra;
    p_extra += oggpacket.bytes;
    i_extra -= (oggpacket.bytes + 2);
    if( i_extra < 0 )
    {
        msg_Err( p_dec, "header data corrupted");
        return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
386
387
    }

388
    if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 )
gbazin's avatar
   
gbazin committed
389
    {
390
391
392
        msg_Err( p_dec, "this bitstream does not contain Vorbis audio data");
        return VLC_EGENERIC;
    }
Sam Hocevar's avatar
Sam Hocevar committed
393

394
395
396
    /* Setup the format */
    p_dec->fmt_out.audio.i_rate     = p_sys->vi.rate;
    p_dec->fmt_out.audio.i_channels = p_sys->vi.channels;
397
398
399
400
401
402
403
404
405

    if( p_dec->fmt_out.audio.i_channels < 0 ||
        p_dec->fmt_out.audio.i_channels > 6 )
    {
        msg_Err( p_dec, "invalid number of channels (not between 1 and 6): %i",
                 p_dec->fmt_out.audio.i_channels );
        return VLC_EGENERIC;
    }

406
407
408
409
410
411
412
    p_dec->fmt_out.audio.i_physical_channels =
        p_dec->fmt_out.audio.i_original_channels =
            pi_channels_maps[p_sys->vi.channels];
    p_dec->fmt_out.i_bitrate = p_sys->vi.bitrate_nominal;

    aout_DateInit( &p_sys->end_date, p_sys->vi.rate );
    aout_DateSet( &p_sys->end_date, 0 );
gbazin's avatar
   
gbazin committed
413

414
415
416
417
418
419
420
421
422
423
424
425
426
427
    msg_Dbg( p_dec, "channels:%d samplerate:%ld bitrate:%ld",
             p_sys->vi.channels, p_sys->vi.rate, p_sys->vi.bitrate_nominal );

    /* The next packet in order is the comments header */
    oggpacket.b_o_s = 0;
    oggpacket.bytes = *(p_extra++) << 8;
    oggpacket.bytes |= (*(p_extra++) & 0xFF);
    oggpacket.packet = p_extra;
    p_extra += oggpacket.bytes;
    i_extra -= (oggpacket.bytes + 2);
    if( i_extra < 0 )
    {
        msg_Err( p_dec, "header data corrupted");
        return VLC_EGENERIC;
gbazin's avatar
   
gbazin committed
428
429
    }

430
    if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 )
gbazin's avatar
   
gbazin committed
431
    {
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
        msg_Err( p_dec, "2nd Vorbis header is corrupted" );
        return VLC_EGENERIC;
    }
    ParseVorbisComments( p_dec );

    /* The next packet in order is the codebooks header
     * We need to watch out that this packet is not missing as a
     * missing or corrupted header is fatal. */
    oggpacket.bytes = *(p_extra++) << 8;
    oggpacket.bytes |= (*(p_extra++) & 0xFF);
    oggpacket.packet = p_extra;
    i_extra -= (oggpacket.bytes + 2);
    if( i_extra < 0 )
    {
        msg_Err( p_dec, "header data corrupted");
        return VLC_EGENERIC;
    }
Sam Hocevar's avatar
Sam Hocevar committed
449

450
451
452
453
454
    if( vorbis_synthesis_headerin( &p_sys->vi, &p_sys->vc, &oggpacket ) < 0 )
    {
        msg_Err( p_dec, "3rd Vorbis header is corrupted" );
        return VLC_EGENERIC;
    }
gbazin's avatar
   
gbazin committed
455

456
457
458
459
460
461
462
463
464
465
466
467
468
    if( !p_sys->b_packetizer )
    {
        /* Initialize the Vorbis packet->PCM decoder */
        vorbis_synthesis_init( &p_sys->vd, &p_sys->vi );
        vorbis_block_init( &p_sys->vd, &p_sys->vb );
    }
    else
    {
        p_dec->fmt_out.i_extra = p_dec->fmt_in.i_extra;
        p_dec->fmt_out.p_extra =
            realloc( p_dec->fmt_out.p_extra, p_dec->fmt_out.i_extra );
        memcpy( p_dec->fmt_out.p_extra,
                p_dec->fmt_in.p_extra, p_dec->fmt_out.i_extra );
gbazin's avatar
   
gbazin committed
469
470
    }

471
472
473
    ConfigureChannelOrder(p_sys->pi_chan_table, p_sys->vi.channels,
            p_dec->fmt_out.audio.i_physical_channels, VLC_TRUE);

474
    return VLC_SUCCESS;
gbazin's avatar
   
gbazin committed
475
}
gbazin's avatar
   
gbazin committed
476

gbazin's avatar
   
gbazin committed
477
478
479
/*****************************************************************************
 * ProcessPacket: processes a Vorbis packet.
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
480
481
static void *ProcessPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
                            block_t **pp_block )
gbazin's avatar
   
gbazin committed
482
483
{
    decoder_sys_t *p_sys = p_dec->p_sys;
gbazin's avatar
   
gbazin committed
484
    block_t *p_block = *pp_block;
gbazin's avatar
   
gbazin committed
485

gbazin's avatar
   
gbazin committed
486
    /* Date management */
gbazin's avatar
   
gbazin committed
487
488
    if( p_block && p_block->i_pts > 0 &&
        p_block->i_pts != aout_DateGet( &p_sys->end_date ) )
gbazin's avatar
   
gbazin committed
489
    {
gbazin's avatar
   
gbazin committed
490
        aout_DateSet( &p_sys->end_date, p_block->i_pts );
gbazin's avatar
   
gbazin committed
491
492
    }

gbazin's avatar
   
gbazin committed
493
494
495
    if( !aout_DateGet( &p_sys->end_date ) )
    {
        /* We've just started the stream, wait for the first PTS. */
gbazin's avatar
   
gbazin committed
496
497
        if( p_block ) block_Release( p_block );
        return NULL;
gbazin's avatar
   
gbazin committed
498
499
    }

gbazin's avatar
   
gbazin committed
500
501
    *pp_block = NULL; /* To avoid being fed the same packet again */

gbazin's avatar
   
gbazin committed
502
503
    if( p_sys->b_packetizer )
    {
gbazin's avatar
   
gbazin committed
504
        return SendPacket( p_dec, p_oggpacket, p_block );
gbazin's avatar
   
gbazin committed
505
506
507
    }
    else
    {
gbazin's avatar
   
gbazin committed
508
509
510
511
512
513
514
        aout_buffer_t *p_aout_buffer;

        if( p_sys->i_headers >= 3 )
            p_aout_buffer = DecodePacket( p_dec, p_oggpacket );
        else
            p_aout_buffer = NULL;

515
        if( p_block ) block_Release( p_block );
gbazin's avatar
   
gbazin committed
516
        return p_aout_buffer;
gbazin's avatar
   
gbazin committed
517
    }
gbazin's avatar
   
gbazin committed
518
519
520
521
522
}

/*****************************************************************************
 * DecodePacket: decodes a Vorbis packet.
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
523
static aout_buffer_t *DecodePacket( decoder_t *p_dec, ogg_packet *p_oggpacket )
gbazin's avatar
   
gbazin committed
524
{
gbazin's avatar
   
gbazin committed
525
526
527
    decoder_sys_t *p_sys = p_dec->p_sys;
    int           i_samples;

gbazin's avatar
   
gbazin committed
528
529
530
#ifdef MODULE_NAME_IS_tremor
    int32_t       **pp_pcm;
#else
gbazin's avatar
   
gbazin committed
531
    float         **pp_pcm;
gbazin's avatar
   
gbazin committed
532
#endif
gbazin's avatar
   
gbazin committed
533

gbazin's avatar
   
gbazin committed
534
    if( p_oggpacket->bytes &&
535
536
537
#ifdef MODULE_NAME_IS_tremor
        vorbis_synthesis( &p_sys->vb, p_oggpacket, 1 ) == 0 )
#else
gbazin's avatar
   
gbazin committed
538
        vorbis_synthesis( &p_sys->vb, p_oggpacket ) == 0 )
539
#endif
gbazin's avatar
   
gbazin committed
540
        vorbis_synthesis_blockin( &p_sys->vd, &p_sys->vb );
gbazin's avatar
   
gbazin committed
541
542
543
544
545
546

    /* **pp_pcm is a multichannel float vector. In stereo, for
     * example, pp_pcm[0] is left, and pp_pcm[1] is right. i_samples is
     * the size of each channel. Convert the float values
     * (-1.<=range<=1.) to whatever PCM format and write it out */

gbazin's avatar
   
gbazin committed
547
    if( ( i_samples = vorbis_synthesis_pcmout( &p_sys->vd, &pp_pcm ) ) > 0 )
gbazin's avatar
   
gbazin committed
548
549
    {

gbazin's avatar
   
gbazin committed
550
        aout_buffer_t *p_aout_buffer;
gbazin's avatar
   
gbazin committed
551
552
553
554
555

        p_aout_buffer =
            p_dec->pf_aout_buffer_new( p_dec, i_samples );

        if( p_aout_buffer == NULL ) return NULL;
gbazin's avatar
   
gbazin committed
556
557

        /* Interleave the samples */
gbazin's avatar
   
gbazin committed
558
559
#ifdef MODULE_NAME_IS_tremor
        Interleave( (int32_t *)p_aout_buffer->p_buffer,
560
                    (const int32_t **)pp_pcm, p_sys->vi.channels, i_samples, p_sys->pi_chan_table);
gbazin's avatar
   
gbazin committed
561
562
#else
        Interleave( (float *)p_aout_buffer->p_buffer,
563
                    (const float **)pp_pcm, p_sys->vi.channels, i_samples, p_sys->pi_chan_table);
gbazin's avatar
   
gbazin committed
564
#endif
gbazin's avatar
   
gbazin committed
565
566

        /* Tell libvorbis how many samples we actually consumed */
gbazin's avatar
   
gbazin committed
567
        vorbis_synthesis_read( &p_sys->vd, i_samples );
gbazin's avatar
   
gbazin committed
568
569

        /* Date management */
gbazin's avatar
   
gbazin committed
570
571
        p_aout_buffer->start_date = aout_DateGet( &p_sys->end_date );
        p_aout_buffer->end_date = aout_DateIncrement( &p_sys->end_date,
572
                                                      i_samples * p_sys->i_input_rate / INPUT_RATE_DEFAULT );
gbazin's avatar
   
gbazin committed
573
574
575
576
577
        return p_aout_buffer;
    }
    else
    {
        return NULL;
gbazin's avatar
   
gbazin committed
578
579
580
581
    }
}

/*****************************************************************************
gbazin's avatar
   
gbazin committed
582
 * SendPacket: send an ogg dated packet to the stream output.
gbazin's avatar
   
gbazin committed
583
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
584
585
static block_t *SendPacket( decoder_t *p_dec, ogg_packet *p_oggpacket,
                            block_t *p_block )
gbazin's avatar
   
gbazin committed
586
{
gbazin's avatar
   
gbazin committed
587
    decoder_sys_t *p_sys = p_dec->p_sys;
gbazin's avatar
   
gbazin committed
588
    int i_block_size, i_samples;
gbazin's avatar
   
gbazin committed
589

gbazin's avatar
   
gbazin committed
590
591
592
593
    i_block_size = vorbis_packet_blocksize( &p_sys->vi, p_oggpacket );
    if( i_block_size < 0 ) i_block_size = 0; /* non audio packet */
    i_samples = ( p_sys->i_last_block_size + i_block_size ) >> 2;
    p_sys->i_last_block_size = i_block_size;
gbazin's avatar
   
gbazin committed
594

gbazin's avatar
   
gbazin committed
595
    /* Date management */
gbazin's avatar
   
gbazin committed
596
    p_block->i_dts = p_block->i_pts = aout_DateGet( &p_sys->end_date );
gbazin's avatar
   
gbazin committed
597
598

    if( p_sys->i_headers >= 3 )
599
600
601
        p_block->i_length = aout_DateIncrement( &p_sys->end_date,
            i_samples * p_sys->i_input_rate / INPUT_RATE_DEFAULT ) -
                p_block->i_pts;
gbazin's avatar
   
gbazin committed
602
    else
gbazin's avatar
   
gbazin committed
603
        p_block->i_length = 0;
gbazin's avatar
   
gbazin committed
604

gbazin's avatar
   
gbazin committed
605
    return p_block;
gbazin's avatar
   
gbazin committed
606
607
}

gbazin's avatar
   
gbazin committed
608
/*****************************************************************************
609
 * ParseVorbisComments
gbazin's avatar
   
gbazin committed
610
611
612
613
614
 *****************************************************************************/
static void ParseVorbisComments( decoder_t *p_dec )
{
    input_thread_t *p_input = (input_thread_t *)p_dec->p_parent;
    char *psz_name, *psz_value, *psz_comment;
zorglub's avatar
zorglub committed
615
    input_item_t *p_item;
616
617
618
619
    int i = 0;

    if( p_input->i_object_type != VLC_OBJECT_INPUT ) return;

zorglub's avatar
zorglub committed
620
621
    p_item = input_GetItem( p_input );

622
    while( i < p_dec->p_sys->vc.comments )
gbazin's avatar
   
gbazin committed
623
624
625
626
    {
        psz_comment = strdup( p_dec->p_sys->vc.user_comments[i] );
        if( !psz_comment )
        {
bigben's avatar
bigben committed
627
            msg_Warn( p_dec, "out of memory" );
gbazin's avatar
   
gbazin committed
628
629
630
631
632
633
634
635
            break;
        }
        psz_name = psz_comment;
        psz_value = strchr( psz_comment, '=' );
        if( psz_value )
        {
            *psz_value = '\0';
            psz_value++;
636
            input_Control( p_input, INPUT_ADD_INFO, _("Vorbis comment"),
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
637
                           psz_name, "%s", psz_value );
638
#ifndef HAVE_TAGLIB
639
            if( !strcasecmp( psz_name, "artist" ) )
640
            {
641
642
                if( psz_value && ( *psz_value != '\0' ) )
                {
643
                    input_item_SetArtist( p_item, psz_value );
zorglub's avatar
zorglub committed
644
                    input_ItemAddInfo( p_item,
645
646
                                        _(VLC_META_INFO_CAT),
                                        _(VLC_META_ARTIST),
647
                                        "%s", psz_value );
648
                }
649
            }
650
            else if( !strcasecmp( psz_name, "title" ) )
651
            {
652
653
                if( psz_value && ( *psz_value != '\0' ) )
                {
654
                    input_item_SetTitle( p_item, psz_value );
zorglub's avatar
zorglub committed
655
                    p_item->psz_name = strdup( psz_value );
656
                }
657
            }
658
            else if( !strcasecmp( psz_name, "album" ) )
659
            {
660
661
                if( psz_value && ( *psz_value != '\0' ) )
                {
662
                    input_item_SetAlbum( p_item, psz_value );
663
                }
664
665
666
            }
            else if( !strcasecmp( psz_name, "musicbrainz_trackid" ) )
            {
667
668
                if( psz_value && ( *psz_value != '\0' ) )
                {
669
                    input_item_SetTrackID( p_item, psz_value );
670
                }
671
            }
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
#if 0 //not used
            else if( !strcasecmp( psz_name, "musicbrainz_artistid" ) )
            {
                if( psz_value && ( *psz_value != '\0' ) )
                {
                    vlc_meta_SetArtistID( p_item, psz_value );
                }
            }
            else if( !strcasecmp( psz_name, "musicbrainz_albumid" ) )
            {
                if( psz_value && ( *psz_value != '\0' ) )
                {
                    input_item_SetAlbumID( p_item, psz_value );
                }
            }
#endif
#endif
            if( !strcasecmp( psz_name, "REPLAYGAIN_TRACK_GAIN" ) ||
Laurent Aimar's avatar
Laurent Aimar committed
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
                     !strcasecmp( psz_name, "RG_RADIO" ) )
            {
                audio_replay_gain_t *r = &p_dec->fmt_out.audio_replay_gain;

                r->pb_gain[AUDIO_REPLAY_GAIN_TRACK] = VLC_TRUE;
                r->pf_gain[AUDIO_REPLAY_GAIN_TRACK] = atof( psz_value );
            }
            else if( !strcasecmp( psz_name, "REPLAYGAIN_TRACK_PEAK" ) ||
                     !strcasecmp( psz_name, "RG_PEAK" ) )
            {
                audio_replay_gain_t *r = &p_dec->fmt_out.audio_replay_gain;

                r->pb_peak[AUDIO_REPLAY_GAIN_TRACK] = VLC_TRUE;
                r->pf_peak[AUDIO_REPLAY_GAIN_TRACK] = atof( psz_value );
            }
            else if( !strcasecmp( psz_name, "REPLAYGAIN_ALBUM_GAIN" ) ||
                     !strcasecmp( psz_name, "RG_AUDIOPHILE" ) )
            {
                audio_replay_gain_t *r = &p_dec->fmt_out.audio_replay_gain;

                r->pb_gain[AUDIO_REPLAY_GAIN_ALBUM] = VLC_TRUE;
                r->pf_gain[AUDIO_REPLAY_GAIN_ALBUM] = atof( psz_value );
            }
            else if( !strcasecmp( psz_name, "REPLAYGAIN_ALBUM_PEAK" ) )
            {
                audio_replay_gain_t *r = &p_dec->fmt_out.audio_replay_gain;

                r->pb_peak[AUDIO_REPLAY_GAIN_ALBUM] = VLC_TRUE;
                r->pf_peak[AUDIO_REPLAY_GAIN_ALBUM] = atof( psz_value );
            }
gbazin's avatar
   
gbazin committed
720
        }
721
        /* FIXME */
zorglub's avatar
zorglub committed
722
        var_SetInteger( p_input, "item-change", p_item->i_id );
gbazin's avatar
   
gbazin committed
723
724
725
726
727
        free( psz_comment );
        i++;
    }
}

728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
/*****************************************************************************
 * Interleave: helper function to interleave channels
 *****************************************************************************/
static void ConfigureChannelOrder(int *pi_chan_table, int i_channels, uint32_t i_channel_mask, vlc_bool_t b_decode)
{
    const uint32_t *pi_channels_in;
    switch( i_channels )
    {
        case 6:
        case 5:
            pi_channels_in = pi_6channels_in;
            break;
        case 4:
            pi_channels_in = pi_4channels_in;
            break;
        case 3:
            pi_channels_in = pi_3channels_in;
            break;
        default:
            {
                int i;
                for( i = 0; i< i_channels; ++i )
                {
                    pi_chan_table[i] = i;
                }
                return;
            }
    }

    if( b_decode )
        aout_CheckChannelReorder( pi_channels_in, pi_channels_out,
759
760
761
                                  i_channel_mask & AOUT_CHAN_PHYSMASK,
                                  i_channels,
                                  pi_chan_table );
762
763
    else
        aout_CheckChannelReorder( pi_channels_out, pi_channels_in,
764
765
766
                                  i_channel_mask & AOUT_CHAN_PHYSMASK,
                                  i_channels,
                                  pi_chan_table );
767
768
}

gbazin's avatar
   
gbazin committed
769
770
771
/*****************************************************************************
 * Interleave: helper function to interleave channels
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
772
#ifdef MODULE_NAME_IS_tremor
773
static void Interleave( int32_t *p_out, const int32_t **pp_in,
774
                        int i_nb_channels, int i_samples, int *pi_chan_table)
775
776
777
778
779
{
    int i, j;

    for ( j = 0; j < i_samples; j++ )
        for ( i = 0; i < i_nb_channels; i++ )
780
            p_out[j * i_nb_channels + pi_chan_table[i]] = pp_in[i][j] * (FIXED32_ONE >> 24);
781
}
gbazin's avatar
   
gbazin committed
782
#else
783
static void Interleave( float *p_out, const float **pp_in,
784
                        int i_nb_channels, int i_samples, int *pi_chan_table )
gbazin's avatar
   
gbazin committed
785
786
787
788
{
    int i, j;

    for ( j = 0; j < i_samples; j++ )
789
        for ( i = 0; i < i_nb_channels; i++ )
790
            p_out[j * i_nb_channels + pi_chan_table[i]] = pp_in[i][j];
gbazin's avatar
   
gbazin committed
791
}
792
#endif
gbazin's avatar
   
gbazin committed
793
794

/*****************************************************************************
gbazin's avatar
   
gbazin committed
795
 * CloseDecoder: vorbis decoder destruction
gbazin's avatar
   
gbazin committed
796
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
797
static void CloseDecoder( vlc_object_t *p_this )
gbazin's avatar
   
gbazin committed
798
{
gbazin's avatar
   
gbazin committed
799
    decoder_t *p_dec = (decoder_t *)p_this;
gbazin's avatar
   
gbazin committed
800
801
    decoder_sys_t *p_sys = p_dec->p_sys;

802
    if( !p_sys->b_packetizer && p_sys->i_headers > 3 )
gbazin's avatar
   
gbazin committed
803
    {
gbazin's avatar
   
gbazin committed
804
805
        vorbis_block_clear( &p_sys->vb );
        vorbis_dsp_clear( &p_sys->vd );
gbazin's avatar
   
gbazin committed
806
    }
gbazin's avatar
   
gbazin committed
807
808
809
810
811

    vorbis_comment_clear( &p_sys->vc );
    vorbis_info_clear( &p_sys->vi );  /* must be called last */

    free( p_sys );
gbazin's avatar
   
gbazin committed
812
}
gbazin's avatar
   
gbazin committed
813
814
815
816

#if defined(HAVE_VORBIS_VORBISENC_H) && !defined(MODULE_NAME_IS_tremor)

/*****************************************************************************
817
 * encoder_sys_t : vorbis encoder descriptor
gbazin's avatar
   
gbazin committed
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
 *****************************************************************************/
struct encoder_sys_t
{
    /*
     * Vorbis properties
     */
    vorbis_info      vi; /* struct that stores all the static vorbis bitstream
                            settings */
    vorbis_comment   vc; /* struct that stores all the bitstream user
                          * comments */
    vorbis_dsp_state vd; /* central working state for the packet->PCM
                          * decoder */
    vorbis_block     vb; /* local working space for packet->PCM decode */

    int i_last_block_size;
    int i_samples_delay;
gbazin's avatar
   
gbazin committed
834
    int i_channels;
gbazin's avatar
   
gbazin committed
835
836
837
838
839

    /*
     * Common properties
     */
    mtime_t i_pts;
840
841
842
843
844
845

    /*
    ** Channel reordering
    */
    int pi_chan_table[AOUT_CHAN_MAX];

gbazin's avatar
   
gbazin committed
846
847
848
849
850
851
852
853
};

/*****************************************************************************
 * OpenEncoder: probe the encoder and return score
 *****************************************************************************/
static int OpenEncoder( vlc_object_t *p_this )
{
    encoder_t *p_enc = (encoder_t *)p_this;
gbazin's avatar
   
gbazin committed
854
    encoder_sys_t *p_sys;
855
856
    int i_quality, i_min_bitrate, i_max_bitrate, i;
    ogg_packet header[3];
gbazin's avatar
gbazin committed
857
    vlc_value_t val;
858
    uint8_t *p_extra;
gbazin's avatar
   
gbazin committed
859

860
861
    if( p_enc->fmt_out.i_codec != VLC_FOURCC('v','o','r','b') &&
        !p_enc->b_force )
gbazin's avatar
   
gbazin committed
862
863
864
865
866
867
868
869
870
871
872
873
874
    {
        return VLC_EGENERIC;
    }

    /* Allocate the memory needed to store the decoder's structure */
    if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL )
    {
        msg_Err( p_enc, "out of memory" );
        return VLC_EGENERIC;
    }
    p_enc->p_sys = p_sys;

    p_enc->pf_encode_audio = Encode;
875
    p_enc->fmt_in.i_codec = VLC_FOURCC('f','l','3','2');
876
    p_enc->fmt_out.i_codec = VLC_FOURCC('v','o','r','b');
gbazin's avatar
   
gbazin committed
877

878
    config_ChainParse( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg );
gbazin's avatar
gbazin committed
879
880
881

    var_Get( p_enc, ENC_CFG_PREFIX "quality", &val );
    i_quality = val.i_int;
882
883
    if( i_quality > 10 ) i_quality = 10;
    if( i_quality < 0 ) i_quality = 0;
884
885
    var_Get( p_enc, ENC_CFG_PREFIX "cbr", &val );
    if( val.b_bool ) i_quality = 0;
gbazin's avatar
gbazin committed
886
887
888
889
890
    var_Get( p_enc, ENC_CFG_PREFIX "max-bitrate", &val );
    i_max_bitrate = val.i_int;
    var_Get( p_enc, ENC_CFG_PREFIX "min-bitrate", &val );
    i_min_bitrate = val.i_int;

gbazin's avatar
   
gbazin committed
891
892
893
    /* Initialize vorbis encoder */
    vorbis_info_init( &p_sys->vi );

gbazin's avatar
gbazin committed
894
    if( i_quality > 0 )
Sam Hocevar's avatar
Sam Hocevar committed
895
    {
gbazin's avatar
gbazin committed
896
897
898
        /* VBR mode */
        if( vorbis_encode_setup_vbr( &p_sys->vi,
              p_enc->fmt_in.audio.i_channels, p_enc->fmt_in.audio.i_rate,
899
              i_quality * 0.1 ) )
gbazin's avatar
gbazin committed
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
        {
            vorbis_info_clear( &p_sys->vi );
            free( p_enc->p_sys );
            msg_Err( p_enc, "VBR mode initialisation failed" );
            return VLC_EGENERIC;
        }

        /* Do we have optional hard quality restrictions? */
        if( i_max_bitrate > 0 || i_min_bitrate > 0 )
        {
            struct ovectl_ratemanage_arg ai;
            vorbis_encode_ctl( &p_sys->vi, OV_ECTL_RATEMANAGE_GET, &ai );

            ai.bitrate_hard_min = i_min_bitrate;
            ai.bitrate_hard_max = i_max_bitrate;
            ai.management_active = 1;

            vorbis_encode_ctl( &p_sys->vi, OV_ECTL_RATEMANAGE_SET, &ai );

        }
        else
        {
            /* Turn off management entirely */
            vorbis_encode_ctl( &p_sys->vi, OV_ECTL_RATEMANAGE_SET, NULL );
        }
Sam Hocevar's avatar
Sam Hocevar committed
925
    }
gbazin's avatar
gbazin committed
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
    else
    {
        if( vorbis_encode_setup_managed( &p_sys->vi,
              p_enc->fmt_in.audio.i_channels, p_enc->fmt_in.audio.i_rate,
              i_min_bitrate > 0 ? i_min_bitrate * 1000: -1,
              p_enc->fmt_out.i_bitrate,
              i_max_bitrate > 0 ? i_max_bitrate * 1000: -1 ) )
          {
              vorbis_info_clear( &p_sys->vi );
              msg_Err( p_enc, "CBR mode initialisation failed" );
              free( p_enc->p_sys );
              return VLC_EGENERIC;
          }
    }

    vorbis_encode_setup_init( &p_sys->vi );
gbazin's avatar
   
gbazin committed
942

943
    /* Add a comment */
gbazin's avatar
   
gbazin committed
944
945
946
    vorbis_comment_init( &p_sys->vc);
    vorbis_comment_add_tag( &p_sys->vc, "ENCODER", "VLC media player");

947
    /* Set up the analysis state and auxiliary encoding storage */
gbazin's avatar
   
gbazin committed
948
949
950
    vorbis_analysis_init( &p_sys->vd, &p_sys->vi );
    vorbis_block_init( &p_sys->vd, &p_sys->vb );

951
952
953
    /* Create and store headers */
    vorbis_analysis_headerout( &p_sys->vd, &p_sys->vc,
                               &header[0], &header[1], &header[2]);
954
    p_enc->fmt_out.i_extra = 3 * 2 + header[0].bytes +
955
956
957
958
959
960
961
962
963
964
       header[1].bytes + header[2].bytes;
    p_extra = p_enc->fmt_out.p_extra = malloc( p_enc->fmt_out.i_extra );
    for( i = 0; i < 3; i++ )
    {
        *(p_extra++) = header[i].bytes >> 8;
        *(p_extra++) = header[i].bytes & 0xFF;
        memcpy( p_extra, header[i].packet, header[i].bytes );
        p_extra += header[i].bytes;
    }

gbazin's avatar
   
gbazin committed
965
    p_sys->i_channels = p_enc->fmt_in.audio.i_channels;
gbazin's avatar
   
gbazin committed
966
967
968
969
    p_sys->i_last_block_size = 0;
    p_sys->i_samples_delay = 0;
    p_sys->i_pts = 0;

970
971
972
    ConfigureChannelOrder(p_sys->pi_chan_table, p_sys->vi.channels,
            p_enc->fmt_in.audio.i_physical_channels, VLC_TRUE);

gbazin's avatar
   
gbazin committed
973
974
975
976
977
978
979
980
981
982
983
984
985
986
    return VLC_SUCCESS;
}

/****************************************************************************
 * Encode: the whole thing
 ****************************************************************************
 * This function spits out ogg packets.
 ****************************************************************************/
static block_t *Encode( encoder_t *p_enc, aout_buffer_t *p_aout_buf )
{
    encoder_sys_t *p_sys = p_enc->p_sys;
    ogg_packet oggpacket;
    block_t *p_block, *p_chain = NULL;
    float **buffer;
987
988
    int i;
    unsigned int j;
gbazin's avatar
   
gbazin committed
989
990
991

    p_sys->i_pts = p_aout_buf->start_date -
                (mtime_t)1000000 * (mtime_t)p_sys->i_samples_delay /
gbazin's avatar
   
gbazin committed
992
                (mtime_t)p_enc->fmt_in.audio.i_rate;
gbazin's avatar
   
gbazin committed
993

gbazin's avatar
   
gbazin committed
994
    p_sys->i_samples_delay += p_aout_buf->i_nb_samples;
gbazin's avatar
   
gbazin committed
995

gbazin's avatar
   
gbazin committed
996
    buffer = vorbis_analysis_buffer( &p_sys->vd, p_aout_buf->i_nb_samples );
gbazin's avatar
   
gbazin committed
997
998

    /* convert samples to float and uninterleave */
gbazin's avatar
   
gbazin committed
999
    for( i = 0; i < p_sys->i_channels; i++ )
gbazin's avatar
   
gbazin committed
1000
    {
gbazin's avatar
   
gbazin committed
1001
        for( j = 0 ; j < p_aout_buf->i_nb_samples ; j++ )
gbazin's avatar
   
gbazin committed
1002
        {
1003
1004
            buffer[i][j]= ((float *)p_aout_buf->p_buffer)
                                    [j * p_sys->i_channels + p_sys->pi_chan_table[i]];
gbazin's avatar
   
gbazin committed
1005
1006
1007
        }
    }

gbazin's avatar
   
gbazin committed
1008
    vorbis_analysis_wrote( &p_sys->vd, p_aout_buf->i_nb_samples );
gbazin's avatar
   
gbazin committed
1009
1010
1011

    while( vorbis_analysis_blockout( &p_sys->vd, &p_sys->vb ) == 1 )
    {
gbazin's avatar
   
gbazin committed
1012
1013
        int i_samples;

gbazin's avatar
   
gbazin committed
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
        vorbis_analysis( &p_sys->vb, NULL );
        vorbis_bitrate_addblock( &p_sys->vb );

        while( vorbis_bitrate_flushpacket( &p_sys->vd, &oggpacket ) )
        {
            int i_block_size;
            p_block = block_New( p_enc, oggpacket.bytes );
            memcpy( p_block->p_buffer, oggpacket.packet, oggpacket.bytes );

            i_block_size = vorbis_packet_blocksize( &p_sys->vi, &oggpacket );

            if( i_block_size < 0 ) i_block_size = 0;
            i_samples = ( p_sys->i_last_block_size + i_block_size ) >> 2;
            p_sys->i_last_block_size = i_block_size;

            p_block->i_length = (mtime_t)1000000 *
gbazin's avatar
   
gbazin committed
1030
                (mtime_t)i_samples / (mtime_t)p_enc->fmt_in.audio.i_rate;
gbazin's avatar
   
gbazin committed
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045

            p_block->i_dts = p_block->i_pts = p_sys->i_pts;

            p_sys->i_samples_delay -= i_samples;

            /* Update pts */
            p_sys->i_pts += p_block->i_length;
            block_ChainAppend( &p_chain, p_block );
        }
    }

    return p_chain;
}

/*****************************************************************************
1046
 * CloseEncoder: vorbis encoder destruction
gbazin's avatar
   
gbazin committed
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
 *****************************************************************************/
static void CloseEncoder( vlc_object_t *p_this )
{
    encoder_t *p_enc = (encoder_t *)p_this;
    encoder_sys_t *p_sys = p_enc->p_sys;

    vorbis_block_clear( &p_sys->vb );
    vorbis_dsp_clear( &p_sys->vd );
    vorbis_comment_clear( &p_sys->vc );
    vorbis_info_clear( &p_sys->vi );  /* must be called last */

    free( p_sys );
}

#endif /* HAVE_VORBIS_VORBISENC_H && !MODULE_NAME_IS_tremor */