mpeg_adec.c 7.83 KB
Newer Older
1
/*****************************************************************************
Henri Fallon's avatar
 
Henri Fallon committed
2
 * mpeg_adec.c: MPEG audio decoder thread
3
 *****************************************************************************
4
 * Copyright (C) 1999-2001 VideoLAN
5
 * $Id: mpeg_adec.c,v 1.27 2002/07/31 20:56:52 sam Exp $
6
 *
7 8 9
 * Authors: Michel Kaempf <maxx@via.ecp.fr>
 *          Michel Lespinasse <walken@via.ecp.fr>
 *          Samuel Hocevar <sam@via.ecp.fr>
10
 *          Cyril Deguet <asmax@via.ecp.fr>
11 12 13 14 15
 *
 * 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
16
 * 
17 18
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
21
 *
22 23 24
 * 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.
25
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
26

Sam Hocevar's avatar
 
Sam Hocevar committed
27 28 29 30
/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */
31
#include <string.h>
Michel Kaempf's avatar
Michel Kaempf committed
32

33 34 35
#include <vlc/vlc.h>
#include <vlc/decoder.h>
#include <vlc/aout.h>
Michel Kaempf's avatar
Michel Kaempf committed
36

Henri Fallon's avatar
 
Henri Fallon committed
37 38
#include "mpeg_adec_generic.h"
#include "mpeg_adec.h"
Michel Kaempf's avatar
Michel Kaempf committed
39

Sam Hocevar's avatar
 
Sam Hocevar committed
40
#define ADEC_FRAME_SIZE (2*1152)
41

Sam Hocevar's avatar
 
Sam Hocevar committed
42
/*****************************************************************************
Henri Fallon's avatar
 
Henri Fallon committed
43
 * Local Prototypes
Sam Hocevar's avatar
 
Sam Hocevar committed
44
 *****************************************************************************/
45 46
static int  OpenDecoder    ( vlc_object_t * );
static int  RunDecoder     ( decoder_fifo_t * );
Henri Fallon's avatar
 
Henri Fallon committed
47

48 49
static void EndThread      ( adec_thread_t * );
static void DecodeThread   ( adec_thread_t * );
Henri Fallon's avatar
 
Henri Fallon committed
50 51

/*****************************************************************************
52
 * Module descriptor
Henri Fallon's avatar
 
Henri Fallon committed
53
 *****************************************************************************/
54 55 56 57 58 59 60
vlc_module_begin();
    set_description( _("MPEG I/II layer 1/2 audio decoder") );
    set_capability( "decoder", 50 );
    add_requirement( FPU );
    add_shortcut( "builtin" );
    set_callbacks( OpenDecoder, NULL );
vlc_module_end();
61

Henri Fallon's avatar
 
Henri Fallon committed
62
/*****************************************************************************
63 64 65 66
 * OpenDecoder: probe the decoder and return score
 *****************************************************************************
 * Tries to launch a decoder and return score so that the interface is able
 * to choose.
Henri Fallon's avatar
 
Henri Fallon committed
67
 *****************************************************************************/
68 69 70 71 72 73 74 75 76 77 78
static int OpenDecoder( vlc_object_t *p_this )
{   
    decoder_fifo_t *p_fifo = (decoder_fifo_t*) p_this;

    if( p_fifo->i_fourcc != VLC_FOURCC('m','p','g','a') )
    {   
        return VLC_EGENERIC;
    }
    
    p_fifo->pf_run = RunDecoder;
    return VLC_SUCCESS;
Henri Fallon's avatar
 
Henri Fallon committed
79 80 81
}

/*****************************************************************************
82
 * RunDecoder: initialize, go inside main loop, destroy
Henri Fallon's avatar
 
Henri Fallon committed
83
 *****************************************************************************/
84
static int RunDecoder( decoder_fifo_t *p_fifo )
Henri Fallon's avatar
 
Henri Fallon committed
85 86 87
{
    adec_thread_t   * p_adec;
    
Sam Hocevar's avatar
 
Sam Hocevar committed
88 89
    /* Allocate the memory needed to store the thread's structure */
    if ( (p_adec = (adec_thread_t *)malloc (sizeof(adec_thread_t))) == NULL ) 
Henri Fallon's avatar
 
Henri Fallon committed
90
    {
91 92
        msg_Err( p_fifo, "out of memory" );
        DecoderError( p_fifo );
Sam Hocevar's avatar
 
Sam Hocevar committed
93
        return 0;
Michel Kaempf's avatar
Michel Kaempf committed
94
    }
Henri Fallon's avatar
 
Henri Fallon committed
95
    
Sam Hocevar's avatar
 
Sam Hocevar committed
96 97 98
    /*
     * Initialize the thread properties
     */
99
    p_adec->p_fifo = p_fifo;
100

Henri Fallon's avatar
 
Henri Fallon committed
101 102
    /* 
     * Initilize the banks
Sam Hocevar's avatar
 
Sam Hocevar committed
103
     */
Henri Fallon's avatar
 
Henri Fallon committed
104 105 106 107 108
    p_adec->bank_0.actual = p_adec->bank_0.v1;
    p_adec->bank_0.pos = 0;
    p_adec->bank_1.actual = p_adec->bank_1.v1;
    p_adec->bank_1.pos = 0;
    
Sam Hocevar's avatar
 
Sam Hocevar committed
109
    /*
Henri Fallon's avatar
 
Henri Fallon committed
110
     * Initialize bit stream 
Sam Hocevar's avatar
 
Sam Hocevar committed
111
     */
112
    InitBitstream( &p_adec->bit_stream, p_adec->p_fifo, NULL, NULL );
Sam Hocevar's avatar
Sam Hocevar committed
113

114 115 116
    /* We do not create the audio output fifo now, but
       it will be created when the first frame is received */
    p_adec->p_aout_fifo = NULL;
117

Henri Fallon's avatar
 
Henri Fallon committed
118
    p_adec->i_sync = 0;
Michel Kaempf's avatar
Michel Kaempf committed
119

Henri Fallon's avatar
 
Henri Fallon committed
120 121
    /* Audio decoder thread's main loop */
    while( (!p_adec->p_fifo->b_die) && (!p_adec->p_fifo->b_error) )
Henri Fallon's avatar
 
Henri Fallon committed
122
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
123
        DecodeThread( p_adec );
Henri Fallon's avatar
 
Henri Fallon committed
124 125 126 127 128
    }
    
    /* If b_error is set, the audio decoder thread enters the error loop */
    if( p_adec->p_fifo->b_error ) 
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
129
        DecoderError( p_adec->p_fifo );
Michel Kaempf's avatar
Michel Kaempf committed
130 131
    }

Henri Fallon's avatar
 
Henri Fallon committed
132
    /* End of the audio decoder thread */
Sam Hocevar's avatar
 
Sam Hocevar committed
133
    EndThread( p_adec );
Henri Fallon's avatar
 
Henri Fallon committed
134 135

    return( 0 );
136 137
}

Henri Fallon's avatar
 
Henri Fallon committed
138
/*
139
 * Following functions are local to this module
Henri Fallon's avatar
 
Henri Fallon committed
140 141
 */

Sam Hocevar's avatar
 
Sam Hocevar committed
142
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
143
 * DecodeThread: decodes a mpeg frame
Sam Hocevar's avatar
 
Sam Hocevar committed
144
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
145
static void DecodeThread( adec_thread_t * p_adec )
146
{
Sam Hocevar's avatar
 
Sam Hocevar committed
147
    s16 *p_buffer;
Henri Fallon's avatar
 
Henri Fallon committed
148
    adec_sync_info_t sync_info;
Henri Fallon's avatar
 
Henri Fallon committed
149

Henri Fallon's avatar
 
Henri Fallon committed
150 151
    if( ! adec_SyncFrame (p_adec, &sync_info) )
    {
152 153 154 155 156 157
        
        /* TODO: check if audio type has changed */
        
        /* Create the output fifo if it doesn't exist yet */
        if( p_adec->p_aout_fifo == NULL )
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
158
            int i_channels;
159
            
160
            if( !config_GetInt( p_adec->p_fifo, "mono" ) )
161
            {
162
                msg_Dbg( p_adec->p_fifo, "setting stereo output" );
Sam Hocevar's avatar
 
Sam Hocevar committed
163
                i_channels = 2;
164 165
            }
            else if( sync_info.b_stereo )
166
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
167
                i_channels = 2;
168 169 170
            }
            else
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
171
                i_channels = 1;
172
            }
173
            p_adec->p_aout_fifo =
174
               aout_CreateFifo( p_adec->p_fifo, AOUT_FIFO_PCM, i_channels,
175
                                sync_info.sample_rate, ADEC_FRAME_SIZE, NULL );
176 177
            if( p_adec->p_aout_fifo == NULL)
            {
178
                msg_Err( p_adec->p_fifo, "failed to create aout fifo" );
Sam Hocevar's avatar
 
Sam Hocevar committed
179 180
                p_adec->p_fifo->b_error = 1;
                return;
181 182 183
            }
        }

Henri Fallon's avatar
 
Henri Fallon committed
184
        p_adec->i_sync = 1;
Henri Fallon's avatar
 
Henri Fallon committed
185

Sam Hocevar's avatar
 
Sam Hocevar committed
186 187
        p_buffer = ((s16 *)p_adec->p_aout_fifo->buffer)
                    + (p_adec->p_aout_fifo->i_end_frame * ADEC_FRAME_SIZE);
Henri Fallon's avatar
 
Henri Fallon committed
188

189
        CurrentPTS( &p_adec->bit_stream,
Sam Hocevar's avatar
 
Sam Hocevar committed
190
            &p_adec->p_aout_fifo->date[p_adec->p_aout_fifo->i_end_frame],
191
            NULL );
Sam Hocevar's avatar
 
Sam Hocevar committed
192
        if( !p_adec->p_aout_fifo->date[p_adec->p_aout_fifo->i_end_frame] )
Henri Fallon's avatar
 
Henri Fallon committed
193
        {
Sam Hocevar's avatar
 
Sam Hocevar committed
194
            p_adec->p_aout_fifo->date[p_adec->p_aout_fifo->i_end_frame] =
Henri Fallon's avatar
 
Henri Fallon committed
195 196
                LAST_MDATE;
        }
Henri Fallon's avatar
 
Henri Fallon committed
197

Sam Hocevar's avatar
 
Sam Hocevar committed
198
        if( adec_DecodeFrame (p_adec, p_buffer) )
Sam Hocevar's avatar
Sam Hocevar committed
199
        {
Henri Fallon's avatar
 
Henri Fallon committed
200 201
            /* Ouch, failed decoding... We'll have to resync */
            p_adec->i_sync = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
202
        }
Henri Fallon's avatar
 
Henri Fallon committed
203 204 205
        else
        {
            vlc_mutex_lock (&p_adec->p_aout_fifo->data_lock);
Sam Hocevar's avatar
 
Sam Hocevar committed
206 207
            p_adec->p_aout_fifo->i_end_frame =
                (p_adec->p_aout_fifo->i_end_frame + 1) & AOUT_FIFO_SIZE;
Henri Fallon's avatar
 
Henri Fallon committed
208 209 210
            vlc_cond_signal (&p_adec->p_aout_fifo->data_wait);
            vlc_mutex_unlock (&p_adec->p_aout_fifo->data_lock);
        }
Sam Hocevar's avatar
Sam Hocevar committed
211
    }
212
}
Michel Kaempf's avatar
Michel Kaempf committed
213

Sam Hocevar's avatar
 
Sam Hocevar committed
214
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
215
 * EndThread : audio decoder thread destruction
Sam Hocevar's avatar
 
Sam Hocevar committed
216 217 218 219
 *****************************************************************************
 * This function is called when the thread ends after a sucessful
 * initialization.
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
220
static void EndThread ( adec_thread_t *p_adec )
Sam Hocevar's avatar
 
Sam Hocevar committed
221 222 223
{
    /* If the audio output fifo was created, we destroy it */
    if ( p_adec->p_aout_fifo != NULL ) 
Sam Hocevar's avatar
Sam Hocevar committed
224
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
225
        aout_DestroyFifo ( p_adec->p_aout_fifo );
Michel Lespinasse's avatar
 
Michel Lespinasse committed
226

Sam Hocevar's avatar
 
Sam Hocevar committed
227 228 229 230
        /* Make sure the output thread leaves the NextFrame() function */
        vlc_mutex_lock (&(p_adec->p_aout_fifo->data_lock));
        vlc_cond_signal (&(p_adec->p_aout_fifo->data_wait));
        vlc_mutex_unlock (&(p_adec->p_aout_fifo->data_lock));
Sam Hocevar's avatar
Sam Hocevar committed
231
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
232
    /* Destroy descriptor */
233
    free( p_adec );
Michel Kaempf's avatar
Michel Kaempf committed
234 235
}