mpeg_es.c 7.46 KB
Newer Older
Sam Hocevar's avatar
 
Sam Hocevar committed
1
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
2
 * mpeg_es.c : Elementary Stream input module for vlc
Sam Hocevar's avatar
 
Sam Hocevar committed
3 4
 *****************************************************************************
 * Copyright (C) 2001 VideoLAN
5
 * $Id: mpeg_es.c,v 1.11 2002/07/24 15:21:47 sam Exp $
Sam Hocevar's avatar
 
Sam Hocevar committed
6
 *
7
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
Sam Hocevar's avatar
 
Sam Hocevar committed
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
 *
 * 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
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
 *****************************************************************************/

/*****************************************************************************
 * Preamble
 *****************************************************************************/
#include <stdlib.h>                                      /* malloc(), free() */
#include <string.h>                                              /* strdup() */
Christophe Massiot's avatar
Christophe Massiot committed
29
#include <errno.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
30

31 32
#include <vlc/vlc.h>
#include <vlc/input.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
33

Christophe Massiot's avatar
Christophe Massiot committed
34 35 36 37 38 39 40 41
#include <sys/types.h>

/*****************************************************************************
 * Constants
 *****************************************************************************/
#define ES_PACKET_SIZE 65536
#define MAX_PACKETS_IN_FIFO 3

Sam Hocevar's avatar
 
Sam Hocevar committed
42
/*****************************************************************************
Christophe Massiot's avatar
Christophe Massiot committed
43
 * Local prototypes
Sam Hocevar's avatar
 
Sam Hocevar committed
44
 *****************************************************************************/
Christophe Massiot's avatar
Christophe Massiot committed
45
static void input_getfunctions( function_list_t * p_function_list );
46 47 48
static int  ESDemux ( input_thread_t * );
static int  ESInit  ( input_thread_t * );
static void ESEnd   ( input_thread_t * );
Sam Hocevar's avatar
 
Sam Hocevar committed
49 50

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
51
 * Build configuration tree.
Sam Hocevar's avatar
 
Sam Hocevar committed
52
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
53 54
MODULE_CONFIG_START
MODULE_CONFIG_STOP
Sam Hocevar's avatar
 
Sam Hocevar committed
55

Sam Hocevar's avatar
 
Sam Hocevar committed
56
MODULE_INIT_START
Sam Hocevar's avatar
 
Sam Hocevar committed
57
    SET_DESCRIPTION( _("ISO 13818-2 MPEG Elementary Stream input") )
Christophe Massiot's avatar
Christophe Massiot committed
58
    ADD_CAPABILITY( DEMUX, 150 )
Sam Hocevar's avatar
 
Sam Hocevar committed
59
    ADD_SHORTCUT( "es" )
Sam Hocevar's avatar
 
Sam Hocevar committed
60
MODULE_INIT_STOP
Sam Hocevar's avatar
 
Sam Hocevar committed
61

Sam Hocevar's avatar
 
Sam Hocevar committed
62
MODULE_ACTIVATE_START
Christophe Massiot's avatar
Christophe Massiot committed
63
    input_getfunctions( &p_module->p_functions->demux );
Sam Hocevar's avatar
 
Sam Hocevar committed
64
MODULE_ACTIVATE_STOP
Sam Hocevar's avatar
 
Sam Hocevar committed
65

Sam Hocevar's avatar
 
Sam Hocevar committed
66 67
MODULE_DEACTIVATE_START
MODULE_DEACTIVATE_STOP
Sam Hocevar's avatar
 
Sam Hocevar committed
68

Christophe Massiot's avatar
Christophe Massiot committed
69 70 71 72 73 74 75 76 77 78 79 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
/*****************************************************************************
 * Functions exported as capabilities. They are declared as static so that
 * we don't pollute the namespace too much.
 *****************************************************************************/
static void input_getfunctions( function_list_t * p_function_list )
{
#define input p_function_list->functions.demux
    input.pf_init             = ESInit;
    input.pf_end              = ESEnd;
    input.pf_demux            = ESDemux;
    input.pf_rewind           = NULL;
#undef input
}

/*
 * Data reading functions
 */

/*****************************************************************************
 * ESInit: initializes ES structures
 *****************************************************************************/
static int ESInit( input_thread_t * p_input )
{
    es_descriptor_t *   p_es;
    byte_t *            p_peek;

    /* Initialize access plug-in structures. */
    if( p_input->i_mtu == 0 )
    {
        /* Improve speed. */
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
    }

    /* Have a peep at the show. */
    if( input_Peek( p_input, &p_peek, 4 ) < 4 )
    {
        /* Stream shorter than 4 bytes... */
106
        msg_Err( p_input, "cannot peek()" );
Christophe Massiot's avatar
Christophe Massiot committed
107 108 109 110 111
        return( -1 );
    }

    if( *p_peek || *(p_peek + 1) || *(p_peek + 2) != 1 )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
112
        if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "es", 3 ) )
Christophe Massiot's avatar
Christophe Massiot committed
113 114
        {
            /* User forced */
115
            msg_Err( p_input, "this doesn't look like an MPEG ES stream, continuing" );
Christophe Massiot's avatar
Christophe Massiot committed
116 117 118
        }
        else
        {
119
            msg_Warn( p_input, "ES module discarded (no startcode)" );
Christophe Massiot's avatar
Christophe Massiot committed
120 121 122 123 124
            return( -1 );
        }
    }
    else if( *(p_peek + 3) > 0xb9 )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
125
        if( *p_input->psz_demux && !strncmp( p_input->psz_demux, "es", 3 ) )
Christophe Massiot's avatar
Christophe Massiot committed
126 127
        {
            /* User forced */
128
            msg_Err( p_input, "this seems to be a system stream (PS plug-in ?), but continuing" );
Christophe Massiot's avatar
Christophe Massiot committed
129 130 131
        }
        else
        {
132
            msg_Warn( p_input, "ES module discarded (system startcode)" );
Christophe Massiot's avatar
Christophe Massiot committed
133 134 135 136 137 138 139 140 141 142 143 144 145
            return( -1 );
        }
    }

    if( input_InitStream( p_input, 0 ) == -1 )
    {
        return( -1 );
    }
    input_AddProgram( p_input, 0, 0 );
    p_input->stream.p_selected_program = p_input->stream.pp_programs[0];
    vlc_mutex_lock( &p_input->stream.stream_lock );
    p_es = input_AddES( p_input, p_input->stream.p_selected_program, 0xE0, 0 );
    p_es->i_stream_id = 0xE0;
146
    p_es->i_fourcc = VLC_FOURCC('m','p','g','v');
Christophe Massiot's avatar
Christophe Massiot committed
147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
    p_es->i_cat = VIDEO_ES;
    input_SelectES( p_input, p_es );
    p_input->stream.p_selected_area->i_tell = 0;
    p_input->stream.p_selected_program->b_is_ok = 1;
    vlc_mutex_unlock( &p_input->stream.stream_lock );

    return( 0 );
}

/*****************************************************************************
 * ESEnd: frees unused data
 *****************************************************************************/
static void ESEnd( input_thread_t * p_input )
{
}

/*****************************************************************************
 * ESDemux: reads and demuxes data packets
 *****************************************************************************
 * Returns -1 in case of error, 0 in case of EOF, 1 otherwise
 *****************************************************************************/
static int ESDemux( input_thread_t * p_input )
{
    ssize_t         i_read;
    decoder_fifo_t * p_fifo =
        p_input->stream.p_selected_program->pp_es[0]->p_decoder_fifo;
    pes_packet_t *  p_pes;
    data_packet_t * p_data;
175 176 177 178 179 180

    if( p_fifo == NULL )
    {
        return -1;
    }

Christophe Massiot's avatar
Christophe Massiot committed
181 182 183 184
    i_read = input_SplitBuffer( p_input, &p_data, ES_PACKET_SIZE );

    if ( i_read <= 0 )
    {
185
        return i_read;
Christophe Massiot's avatar
Christophe Massiot committed
186 187 188 189 190 191
    }

    p_pes = input_NewPES( p_input->p_method_data );

    if( p_pes == NULL )
    {
192
        msg_Err( p_input, "out of memory" );
Christophe Massiot's avatar
Christophe Massiot committed
193
        input_DeletePacket( p_input->p_method_data, p_data );
194
        return -1;
Christophe Massiot's avatar
Christophe Massiot committed
195 196 197 198 199 200 201
    }

    p_pes->i_rate = p_input->stream.control.i_rate;
    p_pes->p_first = p_pes->p_last = p_data;
    p_pes->i_nb_data = 1;

    vlc_mutex_lock( &p_fifo->data_lock );
202 203 204 205

    /* If the decoder is waiting for us, wake him up */
    vlc_cond_signal( &p_fifo->data_wait );

Christophe Massiot's avatar
Christophe Massiot committed
206 207 208 209 210 211 212 213 214 215 216 217
    if( p_fifo->i_depth >= MAX_PACKETS_IN_FIFO )
    {
        /* Wait for the decoder. */
        vlc_cond_wait( &p_fifo->data_wait, &p_fifo->data_lock );
    }
    vlc_mutex_unlock( &p_fifo->data_lock );

    if( (p_input->stream.p_selected_program->i_synchro_state == SYNCHRO_REINIT)
         | (input_ClockManageControl( p_input, 
                      p_input->stream.p_selected_program,
                         (mtime_t)0 ) == PAUSE_S) )
    {
218
        msg_Warn( p_input, "synchro reinit" );
Christophe Massiot's avatar
Christophe Massiot committed
219 220 221 222 223 224
        p_pes->i_pts = mdate() + DEFAULT_PTS_DELAY;
        p_input->stream.p_selected_program->i_synchro_state = SYNCHRO_OK;
    }

    input_DecodePES( p_fifo, p_pes );

225
    return 1;
Christophe Massiot's avatar
Christophe Massiot committed
226 227
}