dec.c 7.77 KB
Newer Older
1 2 3
/*****************************************************************************
 * dec.c : audio output API towards decoders
 *****************************************************************************
4
 * Copyright (C) 2002-2007 the VideoLAN team
5
 * $Id$
6 7 8 9 10 11 12
 *
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
 *
 * 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.
13
 *
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.
22 23 24 25 26
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
27 28 29 30
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

31 32
#include <assert.h>

33
#include <vlc_common.h>
34

zorglub's avatar
zorglub committed
35 36 37
#include <vlc_aout.h>
#include <vlc_input.h>

38 39
#include "aout_internal.h"

40 41 42 43
#undef aout_DecNew
/**
 * Creates an audio output
 */
44
aout_input_t *aout_DecNew( audio_output_t *p_aout,
45 46 47
                           audio_sample_format_t *p_format,
                           const audio_replay_gain_t *p_replay_gain,
                           const aout_request_vout_t *p_request_vout )
48
{
49 50 51 52 53
    /* Sanitize audio format */
    if( p_format->i_channels > 32 )
    {
        msg_Err( p_aout, "too many audio channels (%u)",
                 p_format->i_channels );
54
        return NULL;
55
    }
56 57 58 59 60
    if( p_format->i_channels <= 0 )
    {
        msg_Err( p_aout, "no audio channels" );
        return NULL;
    }
61 62 63 64 65
    if( p_format->i_channels != aout_FormatNbChannels( p_format ) )
    {
        msg_Err( p_aout, "incompatible audio channels count with layout mask" );
        return NULL;
    }
66 67 68 69 70

    if( p_format->i_rate > 192000 )
    {
        msg_Err( p_aout, "excessive audio sample frequency (%u)",
                 p_format->i_rate );
71
        return NULL;
72
    }
73 74 75 76 77 78
    if( p_format->i_rate < 4000 )
    {
        msg_Err( p_aout, "too low audio sample frequency (%u)",
                 p_format->i_rate );
        return NULL;
    }
79

80
    aout_input_t *p_input = calloc( 1, sizeof(aout_input_t));
ivoire's avatar
ivoire committed
81
    if( !p_input )
82
        return NULL;
83

Laurent Aimar's avatar
Laurent Aimar committed
84 85 86
    p_input->b_error = true;
    p_input->b_paused = false;
    p_input->i_pause_date = 0;
87

88
    aout_FormatPrepare( p_format );
89

90 91
    memcpy( &p_input->input, p_format,
            sizeof(audio_sample_format_t) );
92 93
    if( p_replay_gain )
        p_input->replay_gain = *p_replay_gain;
94

95 96
    /* We can only be called by the decoder, so no need to lock
     * p_input->lock. */
97
    aout_lock( p_aout );
98 99
    assert( p_aout->p_input == NULL );
    p_aout->p_input = p_input;
100

101 102
    var_Destroy( p_aout, "audio-device" );
    var_Destroy( p_aout, "audio-channels" );
103

104 105 106 107 108 109 110
    /* Recreate the output using the new format. */
    if( aout_OutputNew( p_aout, p_format ) < 0 )
#warning Input without output and mixer = bad idea.
        goto out;

    assert( p_aout->p_mixer == NULL );
    if( aout_MixerNew( p_aout ) == -1 )
111 112
    {
        aout_OutputDelete( p_aout );
113 114 115
#warning Memory leak.
        p_input = NULL;
        goto out;
116 117
    }

118
    aout_InputNew( p_aout, p_input, p_request_vout );
119
out:
120
    aout_unlock( p_aout );
121 122 123 124 125 126
    return p_input;
}

/*****************************************************************************
 * aout_DecDelete : delete a decoder
 *****************************************************************************/
127
void aout_DecDelete( audio_output_t * p_aout, aout_input_t * p_input )
128
{
129
    aout_lock( p_aout );
130
    /* Remove the input. */
131
    assert( p_input == p_aout->p_input ); /* buggy decoder? */
132
    p_aout->p_input = NULL;
133 134
    aout_InputDelete( p_aout, p_input );

135 136 137 138
    aout_OutputDelete( p_aout );
    aout_MixerDelete( p_aout );
    var_Destroy( p_aout, "audio-device" );
    var_Destroy( p_aout, "audio-channels" );
139

140
    aout_unlock( p_aout );
141
    free( p_input );
142 143 144 145 146 147 148 149 150 151
}


/*
 * Buffer management
 */

/*****************************************************************************
 * aout_DecNewBuffer : ask for a new empty buffer
 *****************************************************************************/
152
aout_buffer_t * aout_DecNewBuffer( aout_input_t * p_input,
153 154
                                   size_t i_nb_samples )
{
155 156 157
    size_t length = i_nb_samples * p_input->input.i_bytes_per_frame
                                 / p_input->input.i_frame_length;
    block_t *block = block_Alloc( length );
158 159 160 161 162 163
    if( likely(block != NULL) )
    {
        block->i_nb_samples = i_nb_samples;
        block->i_pts = block->i_length = 0;
    }
    return block;
164 165 166 167 168
}

/*****************************************************************************
 * aout_DecDeleteBuffer : destroy an undecoded buffer
 *****************************************************************************/
169
void aout_DecDeleteBuffer( audio_output_t * p_aout, aout_input_t * p_input,
170 171
                           aout_buffer_t * p_buffer )
{
172
    (void)p_aout; (void)p_input;
173 174 175 176 177 178
    aout_BufferFree( p_buffer );
}

/*****************************************************************************
 * aout_DecPlay : filter & mix the decoded buffer
 *****************************************************************************/
179
int aout_DecPlay( audio_output_t * p_aout, aout_input_t * p_input,
180
                  aout_buffer_t * p_buffer, int i_input_rate )
181
{
182 183
    assert( i_input_rate >= INPUT_RATE_DEFAULT / AOUT_MAX_INPUT_RATE &&
            i_input_rate <= INPUT_RATE_DEFAULT * AOUT_MAX_INPUT_RATE );
184

185
    assert( p_buffer->i_pts > 0 );
186

187
    p_buffer->i_length = (mtime_t)p_buffer->i_nb_samples * 1000000
188 189
                                / p_input->input.i_rate;

190
    aout_lock( p_aout );
191
    if( p_input->b_error )
192
    {
193
        aout_unlock( p_aout );
194 195 196 197
        aout_BufferFree( p_buffer );
        return -1;
    }

198
    aout_InputCheckAndRestart( p_aout, p_input );
199
    aout_InputPlay( p_aout, p_input, p_buffer, i_input_rate );
200
    /* Run the mixer if it is able to run. */
201
    aout_MixerRun( p_aout, p_aout->mixer_multiplier * p_input->multiplier );
202
    aout_unlock( p_aout );
203 204
    return 0;
}
205

206
int aout_DecGetResetLost( audio_output_t *p_aout, aout_input_t *p_input )
207
{
208 209 210 211
    int val;

    aout_lock( p_aout );
    val = p_input->i_buffer_lost;
212
    p_input->i_buffer_lost = 0;
213
    aout_unlock( p_aout );
214

215
    return val;
216 217
}

218
void aout_DecChangePause( audio_output_t *p_aout, aout_input_t *p_input, bool b_paused, mtime_t i_date )
Laurent Aimar's avatar
Laurent Aimar committed
219 220
{
    mtime_t i_duration = 0;
221 222 223

    aout_lock( p_aout );
    assert( p_aout->p_input == p_input );
Laurent Aimar's avatar
Laurent Aimar committed
224 225 226 227 228 229 230 231 232 233
    assert( !p_input->b_paused || !b_paused );
    if( p_input->b_paused )
    {
        i_duration = i_date - p_input->i_pause_date;
    }
    p_input->b_paused = b_paused;
    p_input->i_pause_date = i_date;

    if( i_duration != 0 )
    {
234 235
        aout_FifoMoveDates( &p_input->fifo, i_duration );
        aout_FifoMoveDates( &p_aout->fifo, i_duration );
Laurent Aimar's avatar
Laurent Aimar committed
236
    }
237
    aout_OutputPause( p_aout, b_paused, i_date );
238
    aout_unlock( p_aout );
Laurent Aimar's avatar
Laurent Aimar committed
239 240
}

241
void aout_DecFlush( audio_output_t *p_aout, aout_input_t *p_input )
Laurent Aimar's avatar
Laurent Aimar committed
242
{
243
    aout_lock( p_aout );
244
    aout_FifoReset( &p_input->fifo );
245 246
    aout_FifoReset( &p_aout->fifo );
    aout_OutputFlush( p_aout, false );
247
    aout_unlock( p_aout );
Laurent Aimar's avatar
Laurent Aimar committed
248 249
}

250
bool aout_DecIsEmpty( audio_output_t * p_aout, aout_input_t * p_input )
251 252 253
{
    mtime_t end_date;

254
    aout_lock( p_aout );
255
    end_date = aout_FifoNextStart( &p_input->fifo );
256
    aout_unlock( p_aout );
257
    return end_date == VLC_TS_INVALID || end_date <= mdate();
258
}