X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=plugins%2Fmpeg%2Finput_ps.c;h=856856c723f61ca56ab35a7e85f1ffb8ebb383d5;hb=440f9992ee947ea5fd0debbf35fdd1011c6404b3;hp=b9190e360daba5e7656f804063057e76bd618467;hpb=a0c1805bd992c0ae1fa018156358d831fbaf8f93;p=vlc diff --git a/plugins/mpeg/input_ps.c b/plugins/mpeg/input_ps.c index b9190e360d..856856c723 100644 --- a/plugins/mpeg/input_ps.c +++ b/plugins/mpeg/input_ps.c @@ -2,9 +2,10 @@ * input_ps.c: PS demux and packet management ***************************************************************************** * Copyright (C) 1998, 1999, 2000 VideoLAN - * $Id: input_ps.c,v 1.11 2001/03/15 01:42:20 sam Exp $ + * $Id: input_ps.c,v 1.25 2001/05/30 17:03:12 sam Exp $ * * Authors: Christophe Massiot + * Cyril Deguet * * 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 @@ -31,6 +32,9 @@ #include #include +#ifdef STRNCASECMP_IN_STRINGS_H +# include +#endif #include #include @@ -84,8 +88,8 @@ void _M( input_getfunctions )( function_list_t * p_function_list ) #define input p_function_list->functions.input p_function_list->pf_probe = PSProbe; input.pf_init = PSInit; - input.pf_open = input_FileOpen; - input.pf_close = input_FileClose; + input.pf_open = NULL; /* Set in PSInit */ + input.pf_close = NULL; input.pf_end = PSEnd; input.pf_set_area = NULL; input.pf_read = PSRead; @@ -142,6 +146,7 @@ static int PSProbe( probedata_t *p_data ) static void PSInit( input_thread_t * p_input ) { thread_ps_data_t * p_method; + packet_cache_t * p_packet_cache; if( (p_method = (thread_ps_data_t *)malloc( sizeof(thread_ps_data_t) )) == NULL ) @@ -150,10 +155,69 @@ static void PSInit( input_thread_t * p_input ) p_input->b_error = 1; return; } - p_input->p_plugin_data = (void *)p_method; - p_input->p_method_data = NULL; - + + /* creates the packet cache structure */ + p_packet_cache = malloc( sizeof(packet_cache_t) ); + if ( p_packet_cache == NULL ) + { + intf_ErrMsg( "Out of memory" ); + p_input->b_error = 1; + return; + } + p_input->p_method_data = (void *)p_packet_cache; + + /* Set callback */ + p_input->pf_open = p_input->pf_file_open; + p_input->pf_close = p_input->pf_file_close; + + /* Initialize packet cache mutex */ + vlc_mutex_init( &p_packet_cache->lock ); + + /* allocates the data cache */ + p_packet_cache->data.p_stack = malloc( DATA_CACHE_SIZE * + sizeof(data_packet_t*) ); + if ( p_packet_cache->data.p_stack == NULL ) + { + intf_ErrMsg( "Out of memory" ); + p_input->b_error = 1; + return; + } + p_packet_cache->data.l_index = 0; + + /* allocates the PES cache */ + p_packet_cache->pes.p_stack = malloc( PES_CACHE_SIZE * + sizeof(pes_packet_t*) ); + if ( p_packet_cache->pes.p_stack == NULL ) + { + intf_ErrMsg( "Out of memory" ); + p_input->b_error = 1; + return; + } + p_packet_cache->pes.l_index = 0; + + /* allocates the small buffer cache */ + p_packet_cache->small.p_stack = malloc( SMALL_CACHE_SIZE * + sizeof(packet_buffer_t) ); + if ( p_packet_cache->small.p_stack == NULL ) + { + intf_ErrMsg( "Out of memory" ); + p_input->b_error = 1; + return; + } + p_packet_cache->small.l_index = 0; + + /* allocates the large buffer cache */ + p_packet_cache->large.p_stack = malloc( LARGE_CACHE_SIZE * + sizeof(packet_buffer_t) ); + if ( p_packet_cache->large.p_stack == NULL ) + { + intf_ErrMsg( "Out of memory" ); + p_input->b_error = 1; + return; + } + p_packet_cache->large.l_index = 0; + /* Re-open the socket as a buffered FILE stream */ if( (p_method->stream = fdopen( p_input->i_handle, "r" )) == NULL ) { @@ -213,7 +277,10 @@ static void PSInit( input_thread_t * p_input ) } rewind( p_method->stream ); vlc_mutex_lock( &p_input->stream.stream_lock ); + + p_input->stream.i_method = INPUT_METHOD_FILE; p_input->stream.p_selected_area->i_tell = 0; + if( p_demux_data->b_has_PSM ) { /* (The PSM decoder will care about spawning the decoders) */ @@ -275,7 +342,16 @@ static void PSInit( input_thread_t * p_input ) break; case LPCM_AUDIO_ES: - /* FIXME ! */ + if( main_GetIntVariable( INPUT_CHANNEL_VAR, 0 ) + == ((p_es->i_id & 0x1F00) >> 8) ) + switch( main_GetIntVariable( INPUT_AUDIO_VAR, 0 ) ) + { + case 0: + main_PutIntVariable( INPUT_AUDIO_VAR, + REQUESTED_LPCM ); + case REQUESTED_LPCM: + input_SelectES( p_input, p_es ); + } break; } } @@ -291,6 +367,7 @@ static void PSInit( input_thread_t * p_input ) { /* The programs will be added when we read them. */ vlc_mutex_lock( &p_input->stream.stream_lock ); + p_input->stream.i_method = INPUT_METHOD_FILE; p_input->stream.pp_programs[0]->b_is_ok = 0; vlc_mutex_unlock( &p_input->stream.stream_lock ); } @@ -301,6 +378,7 @@ static void PSInit( input_thread_t * p_input ) *****************************************************************************/ static void PSEnd( input_thread_t * p_input ) { + vlc_mutex_destroy( &((packet_cache_t *)p_input->p_plugin_data)->lock ); free( p_input->p_plugin_data ); } @@ -371,7 +449,7 @@ static int PSRead( input_thread_t * p_input, /* It is common for MPEG-1 streams to pad with zeros * (although it is forbidden by the recommendation), so * don't bother everybody in this case. */ - intf_WarnMsg( 1, "Garbage at input (%.8x)", i_startcode ); + intf_WarnMsg( 3, "Garbage at input (%.8x)", i_startcode ); } while( (i_startcode & 0xFFFFFF00) != 0x100L ) @@ -420,7 +498,8 @@ static int PSRead( input_thread_t * p_input, } /* Fetch a packet of the appropriate size. */ - if( (p_data = NewPacket( p_input, i_packet_size + 6 )) == NULL ) + if( (p_data = NewPacket( p_input->p_method_data, i_packet_size + 6 )) + == NULL ) { intf_ErrMsg( "Out of memory" ); return( -1 ); @@ -468,7 +547,11 @@ static void PSSeek( input_thread_t * p_input, off_t i_position ) p_method = (thread_ps_data_t *)p_input->p_plugin_data; /* A little bourrin but should work for a while --Meuuh */ +#ifndef WIN32 fseeko( p_method->stream, i_position, SEEK_SET ); +#else + fseek( p_method->stream, (long)i_position, SEEK_SET ); +#endif p_input->stream.p_selected_area->i_tell = i_position; } @@ -477,56 +560,213 @@ static void PSSeek( input_thread_t * p_input, off_t i_position ) * Packet management utilities */ + /***************************************************************************** * NewPacket: allocates a data packet *****************************************************************************/ -static struct data_packet_s * NewPacket( void * p_garbage, - size_t i_size ) -{ - data_packet_t * p_data; +static struct data_packet_s * NewPacket( void * p_packet_cache, + size_t l_size ) +{ + packet_cache_t * p_cache; + data_packet_t * p_data; + long l_index; - /* Safety check */ - if( i_size > INPUT_MAX_PACKET_SIZE ) + p_cache = (packet_cache_t *)p_packet_cache; + +#ifdef DEBUG + if ( p_cache == NULL ) { - intf_ErrMsg( "Packet too big (%d)", i_size ); + intf_ErrMsg( "PPacket cache not initialized" ); return NULL; } +#endif - if( (p_data = (data_packet_t *)malloc( sizeof(data_packet_t) )) == NULL ) + /* Safety check */ + if( l_size > INPUT_MAX_PACKET_SIZE ) { - intf_DbgMsg( "Out of memory" ); + intf_ErrMsg( "Packet too big (%d)", l_size ); return NULL; } - if( (p_data->p_buffer = (byte_t *)malloc( i_size )) == NULL ) + vlc_mutex_lock( &p_cache->lock ); + + /* Checks whether the data cache is empty */ + if( p_cache->data.l_index == 0 ) { - intf_DbgMsg( "Out of memory" ); - free( p_data ); - return NULL; + /* Allocates a new packet */ + if ( (p_data = malloc( sizeof(data_packet_t) )) == NULL ) + { + intf_ErrMsg( "Out of memory" ); + vlc_mutex_unlock( &p_cache->lock ); + return NULL; + } +#ifdef TRACE_INPUT + intf_DbgMsg( "PS input: data packet allocated" ); +#endif + } + else + { + /* Takes the packet out from the cache */ + if( (p_data = p_cache->data.p_stack[ -- p_cache->data.l_index ]) + == NULL ) + { + intf_ErrMsg( "NULL packet in the data cache" ); + vlc_mutex_unlock( &p_cache->lock ); + return NULL; + } + } + + if( l_size < MAX_SMALL_SIZE ) + { + /* Small buffer */ + + /* Checks whether the buffer cache is empty */ + if( p_cache->small.l_index == 0 ) + { + /* Allocates a new packet */ + if ( (p_data->p_buffer = malloc( l_size )) == NULL ) + { + intf_DbgMsg( "Out of memory" ); + free( p_data ); + vlc_mutex_unlock( &p_cache->lock ); + return NULL; + } +#ifdef TRACE_INPUT + intf_DbgMsg( "PS input: small buffer allocated" ); +#endif + p_data->l_size = l_size; + } + else + { + /* Takes the packet out from the cache */ + l_index = -- p_cache->small.l_index; + if( (p_data->p_buffer = p_cache->small.p_stack[l_index].p_data) + == NULL ) + { + intf_ErrMsg( "NULL packet in the small buffer cache" ); + free( p_data ); + vlc_mutex_unlock( &p_cache->lock ); + return NULL; + } + /* Reallocates the packet if it is too small or too large */ + if( p_cache->small.p_stack[l_index].l_size < l_size || + p_cache->small.p_stack[l_index].l_size > 2*l_size ) + { + p_data->p_buffer = realloc( p_data->p_buffer, l_size ); + p_data->l_size = l_size; + } + else + { + p_data->l_size = p_cache->small.p_stack[l_index].l_size; + } + } + } + else + { + /* Large buffer */ + + /* Checks whether the buffer cache is empty */ + if( p_cache->large.l_index == 0 ) + { + /* Allocates a new packet */ + if ( (p_data->p_buffer = malloc( l_size )) == NULL ) + { + intf_ErrMsg( "Out of memory" ); + free( p_data ); + vlc_mutex_unlock( &p_cache->lock ); + return NULL; + } +#ifdef TRACE_INPUT + intf_DbgMsg( "PS input: large buffer allocated" ); +#endif + p_data->l_size = l_size; + } + else + { + /* Takes the packet out from the cache */ + l_index = -- p_cache->large.l_index; + if( (p_data->p_buffer = p_cache->large.p_stack[l_index].p_data) + == NULL ) + { + intf_ErrMsg( "NULL packet in the small buffer cache" ); + free( p_data ); + vlc_mutex_unlock( &p_cache->lock ); + return NULL; + } + /* Reallocates the packet if it is too small or too large */ + if( p_cache->large.p_stack[l_index].l_size < l_size || + p_cache->large.p_stack[l_index].l_size > 2*l_size ) + { + p_data->p_buffer = realloc( p_data->p_buffer, l_size ); + p_data->l_size = l_size; + } + else + { + p_data->l_size = p_cache->large.p_stack[l_index].l_size; + } + } } + vlc_mutex_unlock( &p_cache->lock ); + /* Initialize data */ p_data->p_next = NULL; p_data->b_discard_payload = 0; - p_data->p_payload_start = p_data->p_buffer; - p_data->p_payload_end = p_data->p_buffer + i_size; + p_data->p_payload_end = p_data->p_buffer + l_size; return( p_data ); + } + /***************************************************************************** * NewPES: allocates a pes packet *****************************************************************************/ -static pes_packet_t * NewPES( void * p_garbage ) +static pes_packet_t * NewPES( void * p_packet_cache ) { - pes_packet_t * p_pes; + packet_cache_t * p_cache; + pes_packet_t * p_pes; - if( (p_pes = (pes_packet_t *)malloc( sizeof(pes_packet_t) )) == NULL ) + p_cache = (packet_cache_t *)p_packet_cache; + +#ifdef DEBUG + if ( p_cache == NULL ) { - intf_DbgMsg( "Out of memory" ); + intf_ErrMsg( "Packet cache not initialized" ); return NULL; } +#endif + + vlc_mutex_lock( &p_cache->lock ); + + /* Checks whether the PES cache is empty */ + if( p_cache->pes.l_index == 0 ) + { + /* Allocates a new packet */ + if ( (p_pes = malloc( sizeof(pes_packet_t) )) == NULL ) + { + intf_DbgMsg( "Out of memory" ); + vlc_mutex_unlock( &p_cache->lock ); + return NULL; + } +#ifdef TRACE_INPUT + intf_DbgMsg( "PS input: PES packet allocated" ); +#endif + } + else + { + /* Takes the packet out from the cache */ + if( (p_pes = p_cache->pes.p_stack[ -- p_cache->pes.l_index ]) + == NULL ) + { + intf_ErrMsg( "NULL packet in the data cache" ); + vlc_mutex_unlock( &p_cache->lock ); + return NULL; + } + } + + vlc_mutex_unlock( &p_cache->lock ); p_pes->b_data_alignment = p_pes->b_discontinuity = p_pes->i_pts = p_pes->i_dts = 0; @@ -534,39 +774,136 @@ static pes_packet_t * NewPES( void * p_garbage ) p_pes->p_first = NULL; return( p_pes ); + } /***************************************************************************** * DeletePacket: deletes a data packet *****************************************************************************/ -static void DeletePacket( void * p_garbage, +static void DeletePacket( void * p_packet_cache, data_packet_t * p_data ) { - ASSERT(p_data); - ASSERT(p_data->p_buffer); - free( p_data->p_buffer ); - free( p_data ); + packet_cache_t * p_cache; + + p_cache = (packet_cache_t *)p_packet_cache; + +#ifdef DEBUG + if ( p_cache == NULL ) + { + intf_ErrMsg( "Packet cache not initialized" ); + return; + } +#endif + + ASSERT( p_data ); + + vlc_mutex_lock( &p_cache->lock ); + + /* Checks whether the data cache is full */ + if ( p_cache->data.l_index < DATA_CACHE_SIZE ) + { + /* Cache not full: store the packet in it */ + p_cache->data.p_stack[ p_cache->data.l_index ++ ] = p_data; + /* Small buffer or large buffer? */ + if ( p_data->l_size < MAX_SMALL_SIZE ) + { + /* Checks whether the small buffer cache is full */ + if ( p_cache->small.l_index < SMALL_CACHE_SIZE ) + { + p_cache->small.p_stack[ p_cache->small.l_index ].l_size = + p_data->l_size; + p_cache->small.p_stack[ p_cache->small.l_index ++ ].p_data = + p_data->p_buffer; + } + else + { + ASSERT( p_data->p_buffer ); + free( p_data->p_buffer ); +#ifdef TRACE_INPUT + intf_DbgMsg( "PS input: small buffer freed" ); +#endif + } + } + else + { + /* Checks whether the large buffer cache is full */ + if ( p_cache->large.l_index < LARGE_CACHE_SIZE ) + { + p_cache->large.p_stack[ p_cache->large.l_index ].l_size = + p_data->l_size; + p_cache->large.p_stack[ p_cache->large.l_index ++ ].p_data = + p_data->p_buffer; + } + else + { + ASSERT( p_data->p_buffer ); + free( p_data->p_buffer ); +#ifdef TRACE_INPUT + intf_DbgMsg( "PS input: large buffer freed" ); +#endif + } + } + } + else + { + /* Cache full: the packet must be freed */ + free( p_data->p_buffer ); + free( p_data ); +#ifdef TRACE_INPUT + intf_DbgMsg( "PS input: data packet freed" ); +#endif + } + + vlc_mutex_unlock( &p_cache->lock ); } /***************************************************************************** * DeletePES: deletes a PES packet and associated data packets *****************************************************************************/ -static void DeletePES( void * p_garbage, pes_packet_t * p_pes ) +static void DeletePES( void * p_packet_cache, pes_packet_t * p_pes ) { + packet_cache_t * p_cache; data_packet_t * p_data; data_packet_t * p_next; + p_cache = (packet_cache_t *)p_packet_cache; + +#ifdef DEBUG + if ( p_cache == NULL ) + { + intf_ErrMsg( "Packet cache not initialized" ); + return; + } +#endif + + ASSERT( p_pes); + p_data = p_pes->p_first; while( p_data != NULL ) { p_next = p_data->p_next; - free( p_data->p_buffer ); - free( p_data ); + DeletePacket( p_cache, p_data ); p_data = p_next; } - free( p_pes ); -} + vlc_mutex_lock( &p_cache->lock ); + + /* Checks whether the PES cache is full */ + if ( p_cache->pes.l_index < PES_CACHE_SIZE ) + { + /* Cache not full: store the packet in it */ + p_cache->pes.p_stack[ p_cache->pes.l_index ++ ] = p_pes; + } + else + { + /* Cache full: the packet must be freed */ + free( p_pes ); +#ifdef TRACE_INPUT + intf_DbgMsg( "PS input: PES packet freed" ); +#endif + } + vlc_mutex_unlock( &p_cache->lock ); +}