audio.c 8.04 KB
Newer Older
1
2
3
/*****************************************************************************
 * audio.c: audio decoder using ffmpeg library
 *****************************************************************************
gbazin's avatar
   
gbazin committed
4
 * Copyright (C) 1999-2003 VideoLAN
5
 * $Id: audio.c,v 1.23 2003/11/17 02:52:39 fenrir Exp $
6
7
 *
 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
gbazin's avatar
   
gbazin committed
8
 *          Gildas Bazin <gbazin@netcourrier.com>
9
10
11
12
13
 *
 * 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.
14
 *
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 * 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
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */
gbazin's avatar
   
gbazin committed
29
#include <string.h>
30
31
32
33
34

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

35
#include "codecs.h"
36
#include "aout_internal.h"
37

gbazin's avatar
   
gbazin committed
38
39
40
41
42
43
/* ffmpeg header */
#ifdef HAVE_FFMPEG_AVCODEC_H
#   include <ffmpeg/avcodec.h>
#else
#   include <avcodec.h>
#endif
44
45
46

#include "ffmpeg.h"

47
static unsigned int pi_channels_maps[6] =
48
49
{
    0,
50
51
    AOUT_CHAN_CENTER,   AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
    AOUT_CHAN_CENTER | AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT,
gbazin's avatar
   
gbazin committed
52
53
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_REARLEFT
     | AOUT_CHAN_REARRIGHT,
54
55
    AOUT_CHAN_LEFT | AOUT_CHAN_RIGHT | AOUT_CHAN_CENTER
     | AOUT_CHAN_REARLEFT | AOUT_CHAN_REARRIGHT
56
};
57
58

/*****************************************************************************
gbazin's avatar
   
gbazin committed
59
 * decoder_sys_t : decoder descriptor
60
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
struct decoder_sys_t
{
    /* Common part between video and audio decoder */
    int i_cat;
    int i_codec_id;
    char *psz_namecodec;
    AVCodecContext      *p_context;
    AVCodec             *p_codec;

    /* Temporary buffer for libavcodec */
    uint8_t *p_output;

    /*
     * Output properties
     */
    audio_sample_format_t aout_format;
    audio_date_t          end_date;
};
79
80

/*****************************************************************************
gbazin's avatar
   
gbazin committed
81
 * InitAudioDec: initialize audio decoder
82
 *****************************************************************************
gbazin's avatar
   
gbazin committed
83
 * The ffmpeg codec will be opened, some memory allocated.
84
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
85
86
int E_(InitAudioDec)( decoder_t *p_dec, AVCodecContext *p_context,
                      AVCodec *p_codec, int i_codec_id, char *psz_namecodec )
87
{
gbazin's avatar
   
gbazin committed
88
    decoder_sys_t *p_sys;
89

gbazin's avatar
   
gbazin committed
90
91
92
    /* Allocate the memory needed to store the decoder's structure */
    if( ( p_dec->p_sys = p_sys =
          (decoder_sys_t *)malloc(sizeof(decoder_sys_t)) ) == NULL )
93
    {
gbazin's avatar
   
gbazin committed
94
95
96
97
98
99
100
101
102
        msg_Err( p_dec, "out of memory" );
        return VLC_EGENERIC;
    }

    p_dec->p_sys->p_context = p_context;
    p_dec->p_sys->p_codec = p_codec;
    p_dec->p_sys->i_codec_id = i_codec_id;
    p_dec->p_sys->psz_namecodec = psz_namecodec;

103
    /* ***** Fill p_context with init values ***** */
gbazin's avatar
   
gbazin committed
104
105
106
107
    p_sys->p_context->sample_rate = p_dec->fmt_in.audio.i_rate;
    p_sys->p_context->channels = p_dec->fmt_in.audio.i_channels;
    p_sys->p_context->block_align = p_dec->fmt_in.audio.i_blockalign;
    p_sys->p_context->bit_rate = p_dec->fmt_in.i_bitrate;
108

gbazin's avatar
   
gbazin committed
109
    if( ( p_sys->p_context->extradata_size = p_dec->fmt_in.i_extra ) > 0 )
110
    {
gbazin's avatar
   
gbazin committed
111
        p_sys->p_context->extradata =
gbazin's avatar
   
gbazin committed
112
113
114
115
            malloc( p_dec->fmt_in.i_extra + FF_INPUT_BUFFER_PADDING_SIZE );
        memcpy( p_sys->p_context->extradata,
                p_dec->fmt_in.p_extra, p_dec->fmt_in.i_extra );
        memset( p_sys->p_context->extradata + p_dec->fmt_in.i_extra, 0,
gbazin's avatar
   
gbazin committed
116
                FF_INPUT_BUFFER_PADDING_SIZE );
117
    }
118

119
    /* ***** Open the codec ***** */
gbazin's avatar
   
gbazin committed
120
    if (avcodec_open( p_sys->p_context, p_sys->p_codec ) < 0)
121
    {
gbazin's avatar
   
gbazin committed
122
123
        msg_Err( p_dec, "cannot open codec (%s)", p_sys->psz_namecodec );
        return VLC_EGENERIC;
124
125
126
    }
    else
    {
gbazin's avatar
   
gbazin committed
127
        msg_Dbg( p_dec, "ffmpeg codec (%s) started", p_sys->psz_namecodec );
128
129
    }

gbazin's avatar
   
gbazin committed
130
    p_sys->p_output = malloc( 3 * AVCODEC_MAX_AUDIO_FRAME_SIZE );
131

gbazin's avatar
   
gbazin committed
132
    aout_DateSet( &p_sys->end_date, 0 );
133

gbazin's avatar
   
gbazin committed
134
135
136
137
    /* Set output properties */
    p_dec->fmt_out.i_cat = AUDIO_ES;
    p_dec->fmt_out.i_codec = AOUT_FMT_S16_NE;

gbazin's avatar
   
gbazin committed
138
    return VLC_SUCCESS;
139
140
141
}

/*****************************************************************************
gbazin's avatar
   
gbazin committed
142
 * DecodeAudio: Called to decode one frame
143
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
144
aout_buffer_t *E_( DecodeAudio )( decoder_t *p_dec, block_t **pp_block )
145
{
gbazin's avatar
   
gbazin committed
146
    decoder_sys_t *p_sys = p_dec->p_sys;
gbazin's avatar
   
gbazin committed
147
148
149
150
151
152
    int i_used, i_output, i_samples;
    uint8_t *p_samples;
    aout_buffer_t *p_buffer;
    block_t *p_block;

    if( !pp_block || !*pp_block ) return NULL;
153

gbazin's avatar
   
gbazin committed
154
    p_block = *pp_block;
155

gbazin's avatar
   
gbazin committed
156
157
158
159
    if( !aout_DateGet( &p_sys->end_date ) && !p_block->i_pts )
    {
        /* We've just started the stream, wait for the first PTS. */
        block_Release( p_block );
gbazin's avatar
   
gbazin committed
160
        return NULL;
gbazin's avatar
   
gbazin committed
161
    }
162

163
    if( p_block->i_buffer <= 0 )
164
    {
gbazin's avatar
   
gbazin committed
165
166
167
        block_Release( p_block );
        return NULL;
    }
gbazin's avatar
   
gbazin committed
168

gbazin's avatar
   
gbazin committed
169
170
171
172
173
174
    i_used = avcodec_decode_audio( p_sys->p_context,
                                   (int16_t*)p_sys->p_output, &i_output,
                                   p_block->p_buffer, p_block->i_buffer );

    if( i_used < 0 )//|| i_output == 0 )
    {
gbazin's avatar
   
gbazin committed
175
        if( i_used < 0 )
gbazin's avatar
   
gbazin committed
176
177
178
179
180
            msg_Warn( p_dec, "cannot decode one frame (%d bytes)",
                      p_block->i_buffer );

        block_Release( p_block );
        return NULL;
181
    }
182
183
184
185
    else if( i_used > p_block->i_buffer )
    {
        i_used = p_block->i_buffer;
    }
186

gbazin's avatar
   
gbazin committed
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
    p_block->i_buffer -= i_used;
    p_block->p_buffer += i_used;

    if( p_sys->p_context->channels <= 0 || p_sys->p_context->channels > 6 )
    {
        msg_Warn( p_dec, "invalid channels count %d",
                  p_sys->p_context->channels );
        block_Release( p_block );
        return NULL;
    }

    if( p_dec->fmt_out.audio.i_rate != p_sys->p_context->sample_rate )
    {
        aout_DateInit( &p_sys->end_date, p_sys->p_context->sample_rate );
        aout_DateSet( &p_sys->end_date, p_block->i_pts );
    }

    /* **** Set audio output parameters **** */
    p_dec->fmt_out.audio.i_rate     = p_sys->p_context->sample_rate;
    p_dec->fmt_out.audio.i_channels = p_sys->p_context->channels;
    p_dec->fmt_out.audio.i_original_channels =
        p_dec->fmt_out.audio.i_physical_channels =
            pi_channels_maps[p_sys->p_context->channels];

    if( p_block->i_pts != 0 &&
        p_block->i_pts != aout_DateGet( &p_sys->end_date ) )
    {
        aout_DateSet( &p_sys->end_date, p_block->i_pts );
        p_block->i_pts = 0;
    }

    /* **** Now we can output these samples **** */
    i_samples = i_output / 2 / p_sys->p_context->channels;
    p_samples = p_sys->p_output;

    p_buffer = p_dec->pf_aout_buffer_new( p_dec, i_samples );
    if( !p_buffer )
    {
        msg_Err( p_dec, "cannot get aout buffer" );
        block_Release( p_block );
        return NULL;
    }

    p_buffer->start_date = aout_DateGet( &p_sys->end_date );
    p_buffer->end_date = aout_DateIncrement( &p_sys->end_date, i_samples );

    memcpy( p_buffer->p_buffer, p_samples, p_buffer->i_nb_bytes );

    return p_buffer;
236
237
238
}

/*****************************************************************************
gbazin's avatar
   
gbazin committed
239
 * EndAudioDec: audio decoder destruction
240
 *****************************************************************************/
gbazin's avatar
   
gbazin committed
241
void E_(EndAudioDec)( decoder_t *p_dec )
242
{
gbazin's avatar
   
gbazin committed
243
244
245
    decoder_sys_t *p_sys = p_dec->p_sys;

    if( p_sys->p_output ) free( p_sys->p_output );
246
}