#include <vlc/vlc.h>
#include <vlc/input.h>
-#include "ninput.h"
-
-int access_vaControl( input_thread_t *p_input, int i_query, va_list args )
-{
- if( p_input->pf_access_control )
- {
- return p_input->pf_access_control( p_input, i_query, args );
- }
- return VLC_EGENERIC;
-}
-
-int access_Control( input_thread_t *p_input, int i_query, ... )
-{
- va_list args;
- int i_result;
-
- va_start( args, i_query );
- i_result = access_vaControl( p_input, i_query, args );
- va_end( args );
-
- return i_result;
-}
-
-int access_vaControlDefault( input_thread_t *p_input, int i_query, va_list args )
-{
- return VLC_EGENERIC;
-}
+#include "input_internal.h"
/*****************************************************************************
* access2_New:
/*****************************************************************************
* Preamble
*****************************************************************************/
-#include <string.h> /* memcpy(), memset() */
-
+#include <stdlib.h>
#include <vlc/vlc.h>
-#include "stream_control.h"
-#include "input_ext-intf.h"
-#include "input_ext-dec.h"
-#include "input_ext-plugins.h"
+#include <vlc/input.h>
+#include "input_internal.h"
/*
* DISCUSSION : SYNCHRONIZATION METHOD
* new_average = (old_average * c_average + new_sample_value) / (c_average +1)
*/
-static void ClockNewRef( pgrm_descriptor_t * p_pgrm,
+
+static void ClockNewRef( input_clock_t * p_pgrm,
mtime_t i_clock, mtime_t i_sysdate );
/*****************************************************************************
/*****************************************************************************
* ClockToSysdate: converts a movie clock to system date
*****************************************************************************/
-static mtime_t ClockToSysdate( input_thread_t * p_input,
- pgrm_descriptor_t * p_pgrm, mtime_t i_clock )
+static mtime_t ClockToSysdate( input_thread_t *p_input,
+ input_clock_t *cl, mtime_t i_clock )
{
mtime_t i_sysdate = 0;
- if( p_pgrm->i_synchro_state == SYNCHRO_OK )
+ if( cl->i_synchro_state == SYNCHRO_OK )
{
- i_sysdate = (mtime_t)(i_clock - p_pgrm->cr_ref)
- * (mtime_t)p_input->stream.control.i_rate
+ i_sysdate = (mtime_t)(i_clock - cl->cr_ref)
+ * (mtime_t)p_input->i_rate
* (mtime_t)300;
i_sysdate /= 27;
i_sysdate /= 1000;
- i_sysdate += (mtime_t)p_pgrm->sysdate_ref;
+ i_sysdate += (mtime_t)cl->sysdate_ref;
}
return( i_sysdate );
*****************************************************************************
* Caution : the synchro state must be SYNCHRO_OK for this to operate.
*****************************************************************************/
-static mtime_t ClockCurrent( input_thread_t * p_input,
- pgrm_descriptor_t * p_pgrm )
+static mtime_t ClockCurrent( input_thread_t *p_input,
+ input_clock_t *cl )
{
- return( (mdate() - p_pgrm->sysdate_ref) * 27 * DEFAULT_RATE
- / p_input->stream.control.i_rate / 300
- + p_pgrm->cr_ref );
+ return( (mdate() - cl->sysdate_ref) * 27 * INPUT_RATE_DEFAULT
+ / p_input->i_rate / 300
+ + cl->cr_ref );
}
/*****************************************************************************
* ClockNewRef: writes a new clock reference
*****************************************************************************/
-static void ClockNewRef( pgrm_descriptor_t * p_pgrm,
+static void ClockNewRef( input_clock_t *cl,
mtime_t i_clock, mtime_t i_sysdate )
{
- p_pgrm->cr_ref = i_clock;
- p_pgrm->sysdate_ref = i_sysdate ;
+ cl->cr_ref = i_clock;
+ cl->sysdate_ref = i_sysdate ;
}
/*****************************************************************************
* input_ClockInit: reinitializes the clock reference after a stream
* discontinuity
*****************************************************************************/
-void input_ClockInit( pgrm_descriptor_t * p_pgrm )
+void input_ClockInit( input_clock_t *cl, vlc_bool_t b_master, int i_cr_average )
{
- p_pgrm->last_cr = 0;
- p_pgrm->last_pts = 0;
- p_pgrm->cr_ref = 0;
- p_pgrm->sysdate_ref = 0;
- p_pgrm->delta_cr = 0;
- p_pgrm->c_average_count = 0;
+ cl->i_synchro_state = SYNCHRO_START;
+
+ cl->last_cr = 0;
+ cl->last_pts = 0;
+ cl->cr_ref = 0;
+ cl->sysdate_ref = 0;
+ cl->delta_cr = 0;
+ cl->c_average_count = 0;
+
+ cl->i_cr_average = i_cr_average;
+
+ cl->b_master = b_master;
}
+#if 0
/*****************************************************************************
* input_ClockManageControl: handles the messages from the interface
*****************************************************************************
* Returns UNDEF_S if nothing happened, PAUSE_S if the stream was paused
*****************************************************************************/
int input_ClockManageControl( input_thread_t * p_input,
- pgrm_descriptor_t * p_pgrm, mtime_t i_clock )
+ input_clock_t *cl, mtime_t i_clock )
{
+#if 0
vlc_value_t val;
int i_return_value = UNDEF_S;
vlc_mutex_unlock( &p_input->stream.stream_lock );
return( i_return_value );
+#endif
+ return UNDEF_S;
}
+#endif
/*****************************************************************************
- * input_ClockManageRef: manages a clock reference
+ * input_ClockSetPCR: manages a clock reference
*****************************************************************************/
-void input_ClockManageRef( input_thread_t * p_input,
- pgrm_descriptor_t * p_pgrm, mtime_t i_clock )
+void input_ClockSetPCR( input_thread_t *p_input,
+ input_clock_t *cl, mtime_t i_clock )
{
- /* take selected program if none specified */
- if( !p_pgrm )
- {
- p_pgrm = p_input->stream.p_selected_program;
- }
-
- if( ( p_pgrm->i_synchro_state != SYNCHRO_OK ) ||
- ( i_clock == 0 && p_pgrm->last_cr != 0 ) )
+ if( ( cl->i_synchro_state != SYNCHRO_OK ) ||
+ ( i_clock == 0 && cl->last_cr != 0 ) )
{
/* Feed synchro with a new reference point. */
- ClockNewRef( p_pgrm, i_clock,
- p_pgrm->last_pts + CR_MEAN_PTS_GAP > mdate() ?
- p_pgrm->last_pts + CR_MEAN_PTS_GAP : mdate() );
- p_pgrm->i_synchro_state = SYNCHRO_OK;
+ ClockNewRef( cl, i_clock,
+ cl->last_pts + CR_MEAN_PTS_GAP > mdate() ?
+ cl->last_pts + CR_MEAN_PTS_GAP : mdate() );
+ cl->i_synchro_state = SYNCHRO_OK;
- if( p_input->stream.b_pace_control
- && p_input->stream.p_selected_program == p_pgrm )
+ if( p_input->b_can_pace_control && cl->b_master )
{
- p_pgrm->last_cr = i_clock;
+ cl->last_cr = i_clock;
if( !p_input->b_out_pace_control )
{
- mtime_t i_wakeup = ClockToSysdate( p_input, p_pgrm, i_clock );
+ mtime_t i_wakeup = ClockToSysdate( p_input, cl, i_clock );
while( (i_wakeup - mdate()) / CLOCK_FREQ > 1 )
{
msleep( CLOCK_FREQ );
}
else
{
- p_pgrm->last_cr = 0;
- p_pgrm->delta_cr = 0;
- p_pgrm->c_average_count = 0;
+ cl->last_cr = 0;
+ cl->delta_cr = 0;
+ cl->c_average_count = 0;
}
}
else
{
- if ( p_pgrm->last_cr != 0 &&
- ( (p_pgrm->last_cr - i_clock) > CR_MAX_GAP
- || (p_pgrm->last_cr - i_clock) < - CR_MAX_GAP ) )
+ if ( cl->last_cr != 0 &&
+ ( (cl->last_cr - i_clock) > CR_MAX_GAP
+ || (cl->last_cr - i_clock) < - CR_MAX_GAP ) )
{
/* Stream discontinuity, for which we haven't received a
* warning from the stream control facilities (dd-edited
* stream ?). */
msg_Warn( p_input, "clock gap, unexpected stream discontinuity" );
- input_ClockInit( p_pgrm );
- p_pgrm->i_synchro_state = SYNCHRO_START;
+ input_ClockInit( cl, cl->b_master, cl->i_cr_average );
+ /* FIXME needed ? */
+#if 0
input_EscapeDiscontinuity( p_input );
+#endif
}
- p_pgrm->last_cr = i_clock;
+ cl->last_cr = i_clock;
- if( p_input->stream.b_pace_control
- && p_input->stream.p_selected_program == p_pgrm )
+ if( p_input->b_can_pace_control && cl->b_master )
{
/* Wait a while before delivering the packets to the decoder.
* In case of multiple programs, we arbitrarily follow the
* clock of the selected program. */
if( !p_input->b_out_pace_control )
{
- mtime_t i_wakeup = ClockToSysdate( p_input, p_pgrm, i_clock );
+ mtime_t i_wakeup = ClockToSysdate( p_input, cl, i_clock );
while( (i_wakeup - mdate()) / CLOCK_FREQ > 1 )
{
msleep( CLOCK_FREQ );
}
mwait( i_wakeup );
}
-
+ /* FIXME Not needed anymore ? */
+#if 0
/* Now take into account interface changes. */
- input_ClockManageControl( p_input, p_pgrm, i_clock );
+ input_ClockManageControl( p_input, cl, i_clock );
+#endif
}
else
{
/* Smooth clock reference variations. */
- mtime_t i_extrapoled_clock = ClockCurrent( p_input, p_pgrm );
+ mtime_t i_extrapoled_clock = ClockCurrent( p_input, cl );
/* Bresenham algorithm to smooth variations. */
- if( p_pgrm->c_average_count == p_input->i_cr_average )
+ if( cl->c_average_count == cl->i_cr_average )
{
- p_pgrm->delta_cr = ( p_pgrm->delta_cr
- * (p_input->i_cr_average - 1)
+ cl->delta_cr = ( cl->delta_cr
+ * (cl->i_cr_average - 1)
+ ( i_extrapoled_clock - i_clock ) )
- / p_input->i_cr_average;
+ / cl->i_cr_average;
}
else
{
- p_pgrm->delta_cr = ( p_pgrm->delta_cr
- * p_pgrm->c_average_count
+ cl->delta_cr = ( cl->delta_cr
+ * cl->c_average_count
+ ( i_extrapoled_clock - i_clock ) )
- / (p_pgrm->c_average_count + 1);
- p_pgrm->c_average_count++;
+ / (cl->c_average_count + 1);
+ cl->c_average_count++;
}
}
}
* input_ClockGetTS: manages a PTS or DTS
*****************************************************************************/
mtime_t input_ClockGetTS( input_thread_t * p_input,
- pgrm_descriptor_t * p_pgrm, mtime_t i_ts )
+ input_clock_t *cl, mtime_t i_ts )
{
- /* take selected program if none specified */
- if( !p_pgrm )
- {
- p_pgrm = p_input->stream.p_selected_program;
- }
-
- if( p_pgrm->i_synchro_state == SYNCHRO_OK )
- {
- p_pgrm->last_pts = ClockToSysdate( p_input, p_pgrm,
- i_ts + p_pgrm->delta_cr );
- return( p_pgrm->last_pts + p_input->i_pts_delay );
- }
- else
- {
+ if( cl->i_synchro_state != SYNCHRO_OK )
return 0;
- }
+
+ cl->last_pts = ClockToSysdate( p_input, cl, i_ts + cl->delta_cr );
+ return cl->last_pts + p_input->i_pts_delay;
}
*****************************************************************************/
#include <stdlib.h>
-#include <stdio.h>
#include <vlc/vlc.h>
#include <vlc/input.h>
+#include "input_internal.h"
#include "vlc_playlist.h"
-#include "ninput.h"
-#include "../../modules/demux/util/sub.h"
-
-struct input_thread_sys_t
-{
- /* subtitles */
- int i_sub;
- subtitle_demux_t **sub;
- int64_t i_stop_time;
-};
static void UpdateBookmarksOption( input_thread_t * );
int input_vaControl( input_thread_t *p_input, int i_query, va_list args )
{
- int i_ret;
seekpoint_t *p_bkmk, ***ppp_bkmk;
int i_bkmk = 0;
int *pi_bkmk;
double f, *pf;
int64_t i_64, *pi_64;
- vlc_mutex_lock( &p_input->stream.stream_lock );
switch( i_query )
{
case INPUT_GET_POSITION:
pf = (double*)va_arg( args, double * );
*pf = var_GetFloat( p_input, "position" );
- i_ret = VLC_SUCCESS;
- break;
+ return VLC_SUCCESS;
+
case INPUT_SET_POSITION:
f = (double)va_arg( args, double );
- i_ret = var_SetFloat( p_input, "position", f );
- break;
+ return var_SetFloat( p_input, "position", f );
case INPUT_GET_LENGTH:
pi_64 = (int64_t*)va_arg( args, int64_t * );
*pi_64 = var_GetTime( p_input, "length" );
- i_ret = VLC_SUCCESS;
- break;
+ return VLC_SUCCESS;
+
case INPUT_GET_TIME:
pi_64 = (int64_t*)va_arg( args, int64_t * );
*pi_64 = var_GetTime( p_input, "time" );
- i_ret = VLC_SUCCESS;
- break;
+ return VLC_SUCCESS;
+
case INPUT_SET_TIME:
i_64 = (int64_t)va_arg( args, int64_t );
- i_ret = var_SetTime( p_input, "time", i_64 );
- break;
+ return var_SetTime( p_input, "time", i_64 );
case INPUT_GET_RATE:
pi_int = (int*)va_arg( args, int * );
*pi_int = var_GetInteger( p_input, "rate" );
- i_ret = VLC_SUCCESS;
- break;
+ return VLC_SUCCESS;
+
case INPUT_SET_RATE:
i_int = (int)va_arg( args, int );
- i_ret = var_SetInteger( p_input, "rate", i_int );
- break;
+ return var_SetInteger( p_input, "rate", i_int );
case INPUT_GET_STATE:
pi_int = (int*)va_arg( args, int * );
*pi_int = var_GetInteger( p_input, "state" );
- i_ret = VLC_SUCCESS;
- break;
+ return VLC_SUCCESS;
+
case INPUT_SET_STATE:
i_int = (int)va_arg( args, int );
- i_ret = var_SetInteger( p_input, "state", i_int );
- break;
+ return var_SetInteger( p_input, "state", i_int );
+#if 0
case INPUT_ADD_OPTION:
{
psz_option = (char *)va_arg( args, char * );
i_ret = VLC_EGENERIC;
vlc_mutex_lock( &p_input->p_item->lock );
- /* Check if option already exists */
+ /* Check if option already exists */
for( i = 0; i < p_input->p_item->i_options; i++ )
{
if( !strncmp( p_input->p_item->ppsz_options[i], psz_option,
i_ret = VLC_EGENERIC;
}
break;
-
+#endif
+ case INPUT_GET_BOOKMARKS:
+ case INPUT_CLEAR_BOOKMARKS:
+ case INPUT_ADD_BOOKMARK:
+ case INPUT_CHANGE_BOOKMARK:
+ case INPUT_DEL_BOOKMARK:
+ case INPUT_SET_BOOKMARK:
+ case INPUT_ADD_OPTION:
+ case INPUT_ADD_INFO:
+ case INPUT_GET_INFO:
+ case INPUT_SET_NAME:
+ case INPUT_GET_SUBDELAY:
+ case INPUT_SET_SUBDELAY:
+ /* FIXME */
+ msg_Err( p_input, "unimplemented query in input_vaControl" );
default:
msg_Err( p_input, "unknown query in input_vaControl" );
- i_ret = VLC_EGENERIC;
- break;
+ return VLC_EGENERIC;
}
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- return i_ret;
}
static void UpdateBookmarksOption( input_thread_t *p_input )
{
int i, i_len = 0;
char *psz_value = NULL, *psz_next = NULL;
-
+ /* FIXME */
+#if 0
vlc_mutex_unlock( &p_input->stream.stream_lock );
for( i = 0; i < p_input->i_bookmarks; i++ )
psz_value ? psz_value : "" );
vlc_mutex_lock( &p_input->stream.stream_lock );
+#endif
}
/*****************************************************************************
- * input_dec.c: Functions for the management of decoders
+ * decoder.c: Functions for the management of decoders
*****************************************************************************
* Copyright (C) 1999-2004 VideoLAN
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
* Gildas Bazin <gbazin@netcourrier.com>
+ * Laurent Aimar <fenrir@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
* Preamble
*****************************************************************************/
#include <stdlib.h>
-#include <string.h> /* memcpy(), memset() */
-
#include <vlc/vlc.h>
+
#include <vlc/decoder.h>
#include <vlc/vout.h>
+#include <vlc/input.h>
#include "stream_output.h"
+#include "input_internal.h"
-#include "input_ext-intf.h"
-#include "input_ext-plugins.h"
-
-#include "codecs.h"
-
-static void input_NullPacket( input_thread_t *, es_descriptor_t * );
+static decoder_t * CreateDecoder( input_thread_t *, es_format_t *, int );
+static void DeleteDecoder( decoder_t * );
-static decoder_t * CreateDecoder( input_thread_t *, es_descriptor_t *, int );
static int DecoderThread( decoder_t * );
static int DecoderDecode( decoder_t * p_dec, block_t *p_block );
-static void DeleteDecoder( decoder_t * );
/* Buffers allocation callbacks for the decoders */
static aout_buffer_t *aout_new_buffer( decoder_t *, int );
/* fifo */
block_fifo_t *p_fifo;
-
- /* */
- input_buffers_t *p_method_data;
- es_descriptor_t *p_es_descriptor;
};
* \param p_es the es descriptor
* \return the spawned decoder object
*/
-decoder_t * input_RunDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
+decoder_t *input_DecoderNew( input_thread_t *p_input,
+ es_format_t *fmt, vlc_bool_t b_force_decoder )
{
decoder_t *p_dec = NULL;
vlc_value_t val;
/* If we are in sout mode, search for packetizer module */
- if( !p_es->b_force_decoder && p_input->stream.p_sout )
+ if( p_input->p_sout && !b_force_decoder )
{
/* Create the decoder configuration structure */
- p_dec = CreateDecoder( p_input, p_es, VLC_OBJECT_PACKETIZER );
+ p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_PACKETIZER );
if( p_dec == NULL )
{
msg_Err( p_input, "could not create packetizer" );
else
{
/* Create the decoder configuration structure */
- p_dec = CreateDecoder( p_input, p_es, VLC_OBJECT_DECODER );
+ p_dec = CreateDecoder( p_input, fmt, VLC_OBJECT_DECODER );
if( p_dec == NULL )
{
msg_Err( p_input, "could not create decoder" );
return NULL;
}
- if( !p_es->b_force_decoder && p_input->stream.p_sout && p_input->stream.b_pace_control )
+ if( p_input->p_sout && p_input->input.b_can_pace_control &&
+ !b_force_decoder )
{
msg_Dbg( p_input, "stream out mode -> no decoder thread" );
p_dec->p_owner->b_own_thread = VLC_FALSE;
if( p_dec->p_owner->b_own_thread )
{
int i_priority;
- if ( p_es->i_cat == AUDIO_ES )
- {
+ if( fmt->i_cat == AUDIO_ES )
i_priority = VLC_THREAD_PRIORITY_AUDIO;
- }
else
- {
i_priority = VLC_THREAD_PRIORITY_VIDEO;
- }
/* Spawn the decoder thread */
if( vlc_thread_create( p_dec, "decoder", DecoderThread,
}
}
- /* Select a new ES */
- INSERT_ELEM( p_input->stream.pp_selected_es,
- p_input->stream.i_selected_es_number,
- p_input->stream.i_selected_es_number,
- p_es );
-
- p_input->stream.b_changed = 1;
-
return p_dec;
}
* \param p_es the es descriptor
* \return nothing
*/
-void input_EndDecoder( input_thread_t * p_input, es_descriptor_t * p_es )
+void input_DecoderDelete( decoder_t *p_dec )
{
- decoder_t *p_dec = p_es->p_dec;
-
p_dec->b_die = VLC_TRUE;
if( p_dec->p_owner->b_own_thread )
/* Make sure the thread leaves the function by
* sending it an empty block. */
block_t *p_block = block_New( p_dec, 0 );
- input_DecodeBlock( p_dec, p_block );
+ input_DecoderDecode( p_dec, p_block );
vlc_thread_join( p_dec );
/* Delete the decoder */
vlc_object_destroy( p_dec );
-
- /* Tell the input there is no more decoder */
- p_es->p_dec = NULL;
-
- p_input->stream.b_changed = 1;
-}
-
-/**
- * Put a PES in the decoder's fifo.
- *
- * \param p_dec the decoder object
- * \param p_pes the pes packet
- * \return nothing
- */
-void input_DecodePES( decoder_t * p_dec, pes_packet_t * p_pes )
-{
- data_packet_t *p_data;
- int i_size = 0;
-
- for( p_data = p_pes->p_first; p_data != NULL; p_data = p_data->p_next )
- {
- i_size += p_data->p_payload_end - p_data->p_payload_start;
- }
- if( i_size > 0 )
- {
- block_t *p_block = block_New( p_dec, i_size );
- if( p_block )
- {
- uint8_t *p_buffer = p_block->p_buffer;
-
- for( p_data = p_pes->p_first; p_data; p_data = p_data->p_next )
- {
- int i_copy = p_data->p_payload_end - p_data->p_payload_start;
-
- memcpy( p_buffer, p_data->p_payload_start, i_copy );
-
- p_buffer += i_copy;
- }
- p_block->i_pts = p_pes->i_pts;
- p_block->i_dts = p_pes->i_dts;
- if( p_pes->b_discontinuity )
- p_block->i_flags |= BLOCK_FLAG_DISCONTINUITY;
- p_block->i_rate = p_pes->i_rate;
-
- input_DecodeBlock( p_dec, p_block );
- }
- }
-
- input_DeletePES( p_dec->p_owner->p_method_data, p_pes );
}
/**
* \param p_dec the decoder object
* \param p_block the data block
*/
-void input_DecodeBlock( decoder_t * p_dec, block_t *p_block )
+void input_DecoderDecode( decoder_t * p_dec, block_t *p_block )
{
if( p_dec->p_owner->b_own_thread )
{
}
}
+void input_DecoderDiscontinuity( decoder_t * p_dec )
+{
+ block_t *p_null;
+
+ /* Empty the fifo */
+ if( p_dec->p_owner->b_own_thread )
+ {
+ block_FifoEmpty( p_dec->p_owner->p_fifo );
+ }
+
+ /* Send a special block */
+ p_null = block_New( p_dec, 128 );
+ p_null->i_flags |= BLOCK_FLAG_DISCONTINUITY;
+ memset( p_null->p_buffer, 0, p_null->i_buffer );
+
+ input_DecoderDecode( p_dec, p_null );
+}
+
+#if 0
/**
* Create a NULL packet for padding in case of a data loss
*
static void input_NullPacket( input_thread_t * p_input,
es_descriptor_t * p_es )
{
+#if 0
block_t *p_block = block_New( p_input, PADDING_PACKET_SIZE );
if( p_block )
{
block_FifoPut( p_es->p_dec->p_owner->p_fifo, p_block );
}
+#endif
}
/**
*/
void input_EscapeDiscontinuity( input_thread_t * p_input )
{
+#if 0
unsigned int i_es, i;
for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
}
}
}
+#endif
}
/**
*/
void input_EscapeAudioDiscontinuity( input_thread_t * p_input )
{
+#if 0
unsigned int i_es, i;
for( i_es = 0; i_es < p_input->stream.i_selected_es_number; i_es++ )
}
}
}
+#endif
}
+#endif
/**
* Create a decoder object
* \param i_object_type Object type as define in include/vlc_objects.h
* \return the decoder object
*/
-static decoder_t * CreateDecoder( input_thread_t * p_input,
- es_descriptor_t * p_es, int i_object_type )
+static decoder_t * CreateDecoder( input_thread_t *p_input,
+ es_format_t *fmt, int i_object_type )
{
decoder_t *p_dec;
/* Initialize the decoder fifo */
p_dec->p_module = NULL;
- es_format_Copy( &p_dec->fmt_in, &p_es->fmt );
- if( p_es->p_waveformatex )
- {
-#define p_wf ((WAVEFORMATEX *)p_es->p_waveformatex)
- p_dec->fmt_in.audio.i_channels = p_wf->nChannels;
- p_dec->fmt_in.audio.i_rate = p_wf->nSamplesPerSec;
- p_dec->fmt_in.i_bitrate = p_wf->nAvgBytesPerSec * 8;
- p_dec->fmt_in.audio.i_blockalign = p_wf->nBlockAlign;
- p_dec->fmt_in.audio.i_bitspersample = p_wf->wBitsPerSample;
- p_dec->fmt_in.i_extra = p_wf->cbSize;
- p_dec->fmt_in.p_extra = NULL;
- if( p_wf->cbSize )
- {
- p_dec->fmt_in.p_extra = malloc( p_wf->cbSize );
- memcpy( p_dec->fmt_in.p_extra, &p_wf[1], p_wf->cbSize );
- }
- }
-
- if( p_es->p_bitmapinfoheader )
- {
-#define p_bih ((BITMAPINFOHEADER *) p_es->p_bitmapinfoheader)
- p_dec->fmt_in.i_extra = p_bih->biSize - sizeof(BITMAPINFOHEADER);
- p_dec->fmt_in.p_extra = NULL;
- if( p_dec->fmt_in.i_extra )
- {
- p_dec->fmt_in.p_extra = malloc( p_dec->fmt_in.i_extra );
- memcpy( p_dec->fmt_in.p_extra, &p_bih[1], p_dec->fmt_in.i_extra );
- }
-
- p_dec->fmt_in.video.i_width = p_bih->biWidth;
- p_dec->fmt_in.video.i_height = p_bih->biHeight;
- }
-
- /* FIXME
- * - 1: beurk
- * - 2: I'm not sure there isn't any endian problem here (spu)... */
- if( p_es->i_cat == SPU_ES && p_es->p_demux_data )
- {
- if( ( p_es->i_fourcc == VLC_FOURCC( 's', 'p', 'u', ' ' ) ||
- p_es->i_fourcc == VLC_FOURCC( 's', 'p', 'u', 'b' ) ) &&
- *((uint32_t*)p_es->p_demux_data) == 0xBeef )
- {
- memcpy( p_dec->fmt_in.subs.spu.palette,
- p_es->p_demux_data, 17 * 4 );
- }
- else if( p_es->i_fourcc == VLC_FOURCC( 'd', 'v', 'b', 's' ) &&
- p_es->p_spuinfo )
- {
- dvb_spuinfo_t *p_dvbs = (dvb_spuinfo_t*)p_es->p_spuinfo;
- p_dec->fmt_in.subs.dvb.i_id = p_dvbs->i_id;
- }
- }
-
- p_dec->fmt_in.i_cat = p_es->i_cat;
- p_dec->fmt_in.i_codec = p_es->i_fourcc;
-
- p_dec->fmt_out = null_es_format;
+ es_format_Copy( &p_dec->fmt_in, fmt );
+ es_format_Copy( &p_dec->fmt_out, &null_es_format );
/* Allocate our private structure for the decoder */
- p_dec->p_owner = (decoder_owner_sys_t*)malloc(sizeof(decoder_owner_sys_t));
+ p_dec->p_owner = malloc( sizeof( decoder_owner_sys_t ) );
if( p_dec->p_owner == NULL )
{
msg_Err( p_dec, "out of memory" );
p_dec->p_owner->p_aout = NULL;
p_dec->p_owner->p_aout_input = NULL;
p_dec->p_owner->p_vout = NULL;
- p_dec->p_owner->p_sout = p_input->stream.p_sout;
+ p_dec->p_owner->p_sout = p_input->p_sout;
p_dec->p_owner->p_sout_input = NULL;
p_dec->p_owner->p_packetizer = NULL;
- p_dec->p_owner->p_es_descriptor = p_es;
/* decoder fifo */
msg_Err( p_dec, "out of memory" );
return NULL;
}
- p_dec->p_owner->p_method_data = p_input->p_method_data;
-
/* Set buffers allocation callbacks for the decoders */
p_dec->pf_aout_buffer_new = aout_new_buffer;
p_dec->pf_aout_buffer_del = aout_del_buffer;
vlc_object_create( p_input, VLC_OBJECT_PACKETIZER );
if( p_dec->p_owner->p_packetizer )
{
- p_dec->p_owner->p_packetizer->fmt_in = null_es_format;
- p_dec->p_owner->p_packetizer->fmt_out = null_es_format;
es_format_Copy( &p_dec->p_owner->p_packetizer->fmt_in,
&p_dec->fmt_in );
+ es_format_Copy( &p_dec->p_owner->p_packetizer->fmt_out,
+ &null_es_format );
+
vlc_object_attach( p_dec->p_owner->p_packetizer, p_input );
p_dec->p_owner->p_packetizer->p_module =
if( !p_dec->p_owner->p_sout_input )
{
es_format_Copy( &p_dec->p_owner->sout, &p_dec->fmt_out );
- if( p_dec->p_owner->p_es_descriptor->p_pgrm )
- {
- p_dec->p_owner->sout.i_group =
- p_dec->p_owner->p_es_descriptor->p_pgrm->i_number;
- }
- p_dec->p_owner->sout.i_id =
- p_dec->p_owner->p_es_descriptor->i_id - 1;
+
+ p_dec->p_owner->sout.i_group =p_dec->fmt_in.i_group;
+ p_dec->p_owner->sout.i_id = p_dec->fmt_in.i_id;
if( p_dec->fmt_in.psz_language )
{
p_dec->p_owner->sout.psz_language =
#include <vlc/vlc.h>
#include <vlc/input.h>
-#include "ninput.h"
-
-int demux_vaControl( input_thread_t *p_input, int i_query, va_list args )
-{
- if( p_input->pf_demux_control )
- {
- return p_input->pf_demux_control( p_input, i_query, args );
- }
- return VLC_EGENERIC;
-}
-
-int demux_Control( input_thread_t *p_input, int i_query, ... )
-{
- va_list args;
- int i_result;
-
- va_start( args, i_query );
- i_result = demux_vaControl( p_input, i_query, args );
- va_end( args );
-
- return i_result;
-}
-
-static void SeekOffset( input_thread_t *p_input, int64_t i_pos );
-
-int demux_vaControlDefault( input_thread_t *p_input, int i_query,
- va_list args )
-{
- int i_ret;
- double f, *pf;
- int64_t i64, *pi64;
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
- switch( i_query )
- {
- case DEMUX_GET_POSITION:
- pf = (double*)va_arg( args, double * );
- if( p_input->stream.p_selected_area->i_size <= 0 )
- {
- *pf = 0.0;
- }
- else
- {
- *pf = (double)p_input->stream.p_selected_area->i_tell /
- (double)p_input->stream.p_selected_area->i_size;
- }
- i_ret = VLC_SUCCESS;
- break;
-
- case DEMUX_SET_POSITION:
- f = (double)va_arg( args, double );
- if( p_input->stream.b_seekable && p_input->pf_seek != NULL &&
- f >= 0.0 && f <= 1.0 )
- {
- SeekOffset( p_input, (int64_t)(f *
- (double)p_input->stream.p_selected_area->i_size) );
- i_ret = VLC_SUCCESS;
- }
- else
- {
- i_ret = VLC_EGENERIC;
- }
- break;
-
- case DEMUX_GET_TIME:
- pi64 = (int64_t*)va_arg( args, int64_t * );
- if( p_input->stream.i_mux_rate > 0 )
- {
- *pi64 = (int64_t)1000000 *
- ( p_input->stream.p_selected_area->i_tell / 50 ) /
- p_input->stream.i_mux_rate;
- i_ret = VLC_SUCCESS;
- }
- else
- {
- *pi64 = 0;
- i_ret = VLC_EGENERIC;
- }
- break;
-
- case DEMUX_SET_TIME:
- i64 = (int64_t)va_arg( args, int64_t );
- if( p_input->stream.i_mux_rate > 0 &&
- p_input->stream.b_seekable &&
- p_input->pf_seek != NULL && i64 >= 0 )
- {
- SeekOffset( p_input, i64 * 50 *
- (int64_t)p_input->stream.i_mux_rate /
- (int64_t)1000000 );
- i_ret = VLC_SUCCESS;
- }
- else
- {
- i_ret = VLC_EGENERIC;
- }
- break;
-
- case DEMUX_GET_LENGTH:
- pi64 = (int64_t*)va_arg( args, int64_t * );
- if( p_input->stream.i_mux_rate > 0 )
- {
- *pi64 = (int64_t)1000000 *
- ( p_input->stream.p_selected_area->i_size / 50 ) /
- p_input->stream.i_mux_rate;
- i_ret = VLC_SUCCESS;
- }
- else
- {
- *pi64 = 0;
- i_ret = VLC_EGENERIC;
- }
- break;
- case DEMUX_GET_FPS:
- i_ret = VLC_EGENERIC;
- break;
- case DEMUX_GET_META:
- i_ret = VLC_EGENERIC;
- break;
-
- default:
- msg_Err( p_input, "unknown query in demux_vaControlDefault" );
- i_ret = VLC_EGENERIC;
- break;
- }
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- return i_ret;
-}
-
-static void SeekOffset( input_thread_t *p_input, int64_t i_pos )
-{
- /* Reinitialize buffer manager. */
- input_AccessReinit( p_input );
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- p_input->pf_seek( p_input, i_pos );
- vlc_mutex_lock( &p_input->stream.stream_lock );
-}
-
+#include "input_internal.h"
/*****************************************************************************
* demux2_New:
+ * if s is NULL then load a access_demux
*****************************************************************************/
demux_t *__demux2_New( vlc_object_t *p_obj,
char *psz_access, char *psz_demux, char *psz_path,
p_demux->info.i_title = 0;
p_demux->info.i_seekpoint = 0;
- psz_module = p_demux->psz_demux;
- if( *psz_module == '\0' && strrchr( p_demux->psz_path, '.' ) )
+ if( s )
+ psz_module = p_demux->psz_demux;
+ else
+ psz_module = p_demux->psz_access;
+
+ if( s && *psz_module == '\0' && strrchr( p_demux->psz_path, '.' ) )
{
/* XXX: add only file without any problem here and with strong detection.
* - no .mp3, .a52, ... (aac is added as it works only by file ext anyway
/* Before module_Need (for var_Create...) */
vlc_object_attach( p_demux, p_obj );
- p_demux->p_module =
- module_Need( p_demux, "demux2", psz_module,
- !strcmp( psz_module, p_demux->psz_demux ) ? VLC_TRUE : VLC_FALSE );
+ if( s )
+ {
+ p_demux->p_module =
+ module_Need( p_demux, "demux2", psz_module,
+ !strcmp( psz_module, p_demux->psz_demux ) ? VLC_TRUE : VLC_FALSE );
+ }
+ else
+ {
+ p_demux->p_module =
+ module_Need( p_demux, "access_demux", psz_module,
+ !strcmp( psz_module, p_demux->psz_access ) ? VLC_TRUE : VLC_FALSE );
+ }
if( p_demux->p_module == NULL )
{
}
}
+/****************************************************************************
+ * stream_Demux*: create a demuxer for an outpout stream (allow demuxer chain)
+ ****************************************************************************/
+typedef struct
+{
+ /* Data buffer */
+ vlc_mutex_t lock;
+ int i_buffer;
+ int i_buffer_size;
+ uint8_t *p_buffer;
+
+ int64_t i_pos;
+
+ /* Demuxer */
+ char *psz_name;
+ es_out_t *out;
+ demux_t *p_demux;
+} d_stream_sys_t;
+
+static int DStreamRead ( stream_t *, void *p_read, int i_read );
+static int DStreamPeek ( stream_t *, uint8_t **pp_peek, int i_peek );
+static int DStreamControl( stream_t *, int i_query, va_list );
+static int DStreamThread ( stream_t * );
+
+
+stream_t *__stream_DemuxNew( vlc_object_t *p_obj, char *psz_demux, es_out_t *out )
+{
+ /* We create a stream reader, and launch a thread */
+ stream_t *s;
+ d_stream_sys_t *p_sys;
+
+ if( psz_demux == NULL || *psz_demux == '\0' )
+ {
+ return NULL;
+ }
+
+ s = vlc_object_create( p_obj, VLC_OBJECT_STREAM );
+ s->pf_block = NULL;
+ s->pf_read = DStreamRead;
+ s->pf_peek = DStreamPeek;
+ s->pf_control= DStreamControl;
+
+ s->p_sys = malloc( sizeof( d_stream_sys_t) );
+ p_sys = (d_stream_sys_t*)s->p_sys;
+
+ vlc_mutex_init( s, &p_sys->lock );
+ p_sys->i_buffer = 0;
+ p_sys->i_buffer_size = 1000000;
+ p_sys->p_buffer = malloc( p_sys->i_buffer_size );
+ p_sys->i_pos = 0;
+ p_sys->psz_name = strdup( psz_demux );
+ p_sys->out = out;
+ p_sys->p_demux = NULL;
+
+ if( vlc_thread_create( s, "stream out", DStreamThread, VLC_THREAD_PRIORITY_INPUT, VLC_FALSE ) )
+ {
+ vlc_mutex_destroy( &p_sys->lock );
+ vlc_object_destroy( s );
+ free( p_sys );
+ return NULL;
+ }
+
+ return s;
+}
+
+void stream_DemuxSend( stream_t *s, block_t *p_block )
+{
+ d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+
+ if( p_block->i_buffer > 0 )
+ {
+ vlc_mutex_lock( &p_sys->lock );
+ /* Realloc if needed */
+ if( p_sys->i_buffer + p_block->i_buffer > p_sys->i_buffer_size )
+ {
+ if( p_sys->i_buffer_size > 5000000 )
+ {
+ vlc_mutex_unlock( &p_sys->lock );
+ msg_Err( s, "stream_DemuxSend: buffer size > 5000000" );
+ block_Release( p_block );
+ return;
+ }
+ /* I know, it's more than needed but that's perfect */
+ p_sys->i_buffer_size += p_block->i_buffer;
+ /* FIXME won't work with PEEK -> segfault */
+ p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size );
+ msg_Dbg( s, "stream_DemuxSend: realloc to %d", p_sys->i_buffer_size );
+ }
+
+ /* copy data */
+ memcpy( &p_sys->p_buffer[p_sys->i_buffer], p_block->p_buffer, p_block->i_buffer );
+ p_sys->i_buffer += p_block->i_buffer;
+
+ vlc_mutex_unlock( &p_sys->lock );
+ }
+
+ block_Release( p_block );
+}
+
+void stream_DemuxDelete( stream_t *s )
+{
+ d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+
+ s->b_die = VLC_TRUE;
+
+ vlc_mutex_lock( &p_sys->lock );
+ if( p_sys->p_demux )
+ {
+ p_sys->p_demux->b_die = VLC_TRUE;
+ }
+ vlc_mutex_unlock( &p_sys->lock );
+
+ vlc_thread_join( s );
+
+ if( p_sys->p_demux )
+ {
+ demux2_Delete( p_sys->p_demux );
+ }
+ vlc_mutex_destroy( &p_sys->lock );
+ free( p_sys->psz_name );
+ free( p_sys->p_buffer );
+ free( p_sys );
+ vlc_object_destroy( s );
+}
+
+
+static int DStreamRead ( stream_t *s, void *p_read, int i_read )
+{
+ d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+ int i_copy;
+
+ //msg_Dbg( s, "DStreamRead: wanted %d bytes", i_read );
+ for( ;; )
+ {
+ vlc_mutex_lock( &p_sys->lock );
+ //msg_Dbg( s, "DStreamRead: buffer %d", p_sys->i_buffer );
+ if( p_sys->i_buffer >= i_read || s->b_die )
+ {
+ break;
+ }
+ vlc_mutex_unlock( &p_sys->lock );
+ msleep( 10000 );
+ }
+
+ //msg_Dbg( s, "DStreamRead: read %d buffer %d", i_read, p_sys->i_buffer );
+
+ i_copy = __MIN( i_read, p_sys->i_buffer );
+ if( i_copy > 0 )
+ {
+ if( p_read )
+ {
+ memcpy( p_read, p_sys->p_buffer, i_copy );
+ }
+ p_sys->i_buffer -= i_copy;
+ p_sys->i_pos += i_copy;
+
+ if( p_sys->i_buffer > 0 )
+ {
+ memmove( p_sys->p_buffer, &p_sys->p_buffer[i_copy], p_sys->i_buffer );
+ }
+
+ }
+ vlc_mutex_unlock( &p_sys->lock );
+
+ return i_copy;
+}
+static int DStreamPeek ( stream_t *s, uint8_t **pp_peek, int i_peek )
+{
+ d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+ int i_copy;
+
+ //msg_Dbg( s, "DStreamPeek: wanted %d bytes", i_peek );
+ for( ;; )
+ {
+ vlc_mutex_lock( &p_sys->lock );
+ //msg_Dbg( s, "DStreamPeek: buffer %d", p_sys->i_buffer );
+ if( p_sys->i_buffer >= i_peek || s->b_die )
+ {
+ break;
+ }
+ vlc_mutex_unlock( &p_sys->lock );
+ msleep( 10000 );
+ }
+ *pp_peek = p_sys->p_buffer;
+ i_copy = __MIN( i_peek, p_sys->i_buffer );
+
+ vlc_mutex_unlock( &p_sys->lock );
+
+ return i_copy;
+}
+
+static int DStreamControl( stream_t *s, int i_query, va_list args )
+{
+ d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+ int64_t *p_i64;
+ vlc_bool_t *p_b;
+ int *p_int;
+ switch( i_query )
+ {
+ case STREAM_GET_SIZE:
+ p_i64 = (int64_t*) va_arg( args, int64_t * );
+ *p_i64 = 0;
+ return VLC_SUCCESS;
+
+ case STREAM_CAN_SEEK:
+ p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
+ *p_b = VLC_FALSE;
+ return VLC_SUCCESS;
+
+ case STREAM_CAN_FASTSEEK:
+ p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
+ *p_b = VLC_FALSE;
+ return VLC_SUCCESS;
+
+ case STREAM_GET_POSITION:
+ p_i64 = (int64_t*) va_arg( args, int64_t * );
+ *p_i64 = p_sys->i_pos;
+ return VLC_SUCCESS;
+
+ case STREAM_SET_POSITION:
+ return VLC_EGENERIC;
+
+ case STREAM_GET_MTU:
+ p_int = (int*) va_arg( args, int * );
+ *p_int = 0;
+ return VLC_SUCCESS;
+
+ default:
+ msg_Err( s, "invalid DStreamControl query=0x%x", i_query );
+ return VLC_EGENERIC;
+ }
+}
+
+static int DStreamThread ( stream_t *s )
+{
+ d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+ demux_t *p_demux;
+
+ /* Create the demuxer */
+
+ if( ( p_demux = demux2_New( s, "", p_sys->psz_name, "", s, p_sys->out ) ) == NULL )
+ {
+ return VLC_EGENERIC;
+ }
+
+ vlc_mutex_lock( &p_sys->lock );
+ p_sys->p_demux = p_demux;
+ vlc_mutex_unlock( &p_sys->lock );
+
+ /* Main loop */
+ while( !s->b_die && !p_demux->b_die )
+ {
+ if( p_demux->pf_demux( p_demux ) <= 0 )
+ {
+ break;
+ }
+ }
+ p_demux->b_die = VLC_TRUE;
+ return VLC_SUCCESS;
+}
#include <vlc/input.h>
#include <vlc/decoder.h>
+#include "input_internal.h"
+
#include "vlc_playlist.h"
-#include "codecs.h"
#include "iso_lang.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
+typedef struct
+{
+ /* Program ID */
+ int i_id;
+
+ /* Number of es for this pgrm */
+ int i_es;
+
+ vlc_bool_t b_selected;
+
+ /* Clock for this program */
+ input_clock_t clock;
+
+} es_out_pgrm_t;
+
struct es_out_id_t
{
- int i_channel;
- es_descriptor_t *p_es;
+ /* ES ID */
+ int i_id;
+ es_out_pgrm_t *p_pgrm;
+
+ /* Channel in the track type */
+ int i_channel;
+ es_format_t fmt;
+ char *psz_description;
+ decoder_t *p_dec;
};
struct es_out_sys_t
{
input_thread_t *p_input;
+ /* all programs */
+ int i_pgrm;
+ es_out_pgrm_t **pgrm;
+ es_out_pgrm_t *p_pgrm; /* Master program */
+
/* all es */
int i_id;
-
int i_es;
es_out_id_t **es;
static es_out_id_t *EsOutAdd ( es_out_t *, es_format_t * );
static int EsOutSend ( es_out_t *, es_out_id_t *, block_t * );
static void EsOutDel ( es_out_t *, es_out_id_t * );
+static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force );
static int EsOutControl( es_out_t *, int i_query, va_list );
+
+static void EsSelect( es_out_t *out, es_out_id_t *es );
+static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update );
static char *LanguageGetName( const char *psz_code );
-/**
- * Create a new es_out structure
- *
- * \param p_input The related input thread
- * \return the new es_out_t
- */
+/*****************************************************************************
+ * input_EsOutNew:
+ *****************************************************************************/
es_out_t *input_EsOutNew( input_thread_t *p_input )
{
es_out_t *out = malloc( sizeof( es_out_t ) );
p_sys->b_active = VLC_FALSE;
p_sys->i_mode = ES_OUT_MODE_AUTO;
- p_sys->i_id = 1;
+ p_sys->i_pgrm = 0;
+ p_sys->pgrm = NULL;
+ p_sys->p_pgrm = NULL;
+
+ p_sys->i_id = 0;
p_sys->i_es = 0;
p_sys->es = NULL;
return out;
}
-/**
- * Deletes an es_out structure
- *
- * \param out the es_out structure to destroy
- * \return nothing
- */
+/*****************************************************************************
+ * input_EsOutDelete:
+ *****************************************************************************/
void input_EsOutDelete( es_out_t *out )
{
es_out_sys_t *p_sys = out->p_sys;
for( i = 0; i < p_sys->i_es; i++ )
{
+ if( p_sys->es[i]->p_dec )
+ {
+ input_DecoderDelete( p_sys->es[i]->p_dec );
+ }
+ if( p_sys->es[i]->psz_description )
+ free( p_sys->es[i]->psz_description );
+ es_format_Clean( &p_sys->es[i]->fmt );
+
free( p_sys->es[i] );
}
if( p_sys->es )
- {
free( p_sys->es );
+
+ for( i = 0; i < p_sys->i_pgrm; i++ )
+ {
+ free( p_sys->pgrm[i] );
}
+ if( p_sys->pgrm )
+ free( p_sys->pgrm );
+
free( p_sys );
free( out );
}
-/**
- * Add a program
- *
- * \param out the es_out
- * \param i_group ...
- * \return a program descriptor for the new program
- */
-static pgrm_descriptor_t *EsOutAddProgram( es_out_t *out, int i_group )
+es_out_id_t *input_EsOutGetFromID( es_out_t *out, int i_id )
{
- input_thread_t *p_input = out->p_sys->p_input;
- pgrm_descriptor_t *p_pgrm;
- es_descriptor_t *p_pmt;
-
- /* FIXME we should use a object variable but a lot of place in src/input
- * have to be changed */
- int i_select = config_GetInt( p_input, "program" );
+ int i;
+ if( i_id < 0 )
+ {
+ /* Special HACK, -i_id is tha cat of the stream */
+ return (es_out_id_t*)((uint8_t*)NULL-i_id);
+ }
- /* create it */
- p_pgrm = input_AddProgram( p_input, i_group, 0 );
+ for( i = 0; i < out->p_sys->i_es; i++ )
+ {
+ if( out->p_sys->es[i]->i_id == i_id )
+ return out->p_sys->es[i];
+ }
+ return NULL;
+}
- /* XXX welcome to kludge, add a dummy es, if you want to understand
- * why have a look at input_SetProgram. Basicaly, it assume the first
- * es to be the PMT, how that is stupid, nevertheless it is needed for
- * the old ts demuxer */
- p_pmt = input_AddES( p_input, p_pgrm, 0, UNKNOWN_ES, NULL, 0 );
- p_pmt->i_fourcc = VLC_FOURCC( 'n', 'u', 'l', 'l' );
+void input_EsOutDiscontinuity( es_out_t *out, vlc_bool_t b_audio )
+{
+ es_out_sys_t *p_sys = out->p_sys;
+ int i;
- /* Select i_select or the first by default */
- if( p_input->stream.p_selected_program == NULL &&
- ( i_select <= 0 || i_select == i_group ) )
+ for( i = 0; i < p_sys->i_es; i++ )
{
- p_input->stream.p_selected_program = p_pgrm;
- }
+ es_out_id_t *es = p_sys->es[i];
- return p_pgrm;
+ /* Send a dummy block to let decoder know that
+ * there is a discontinuity */
+ if( es->p_dec && ( !b_audio || es->fmt.i_cat == AUDIO_ES ) )
+ {
+ input_DecoderDiscontinuity( es->p_dec );
+ }
+ }
}
-/**
- * Select an ES given the current mode
- * XXX: you need to take a the lock before (stream.stream_lock)
+/*****************************************************************************
*
- * \param out The es_out structure
- * \param es es_out_id structure
- * \param b_force ...
- * \return nothing
- */
-static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
+ *****************************************************************************/
+static void EsOutESVarUpdate( es_out_t *out, es_out_id_t *es )
{
es_out_sys_t *p_sys = out->p_sys;
input_thread_t *p_input = p_sys->p_input;
+ vlc_value_t val, text;
- int i_cat = es->p_es->i_cat;
+ char *psz_var;
- if( !p_sys->b_active ||
- ( !b_force && es->p_es->fmt.i_priority < 0 ) )
- {
+ if( es->fmt.i_cat == AUDIO_ES )
+ psz_var = "audio-es";
+ else if( es->fmt.i_cat == VIDEO_ES )
+ psz_var = "video-es";
+ else if( es->fmt.i_cat == SPU_ES )
+ psz_var = "spu-es";
+ else
return;
+
+ /* Get the number of ES already added */
+ var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
+ if( val.i_int == 0 )
+ {
+ vlc_value_t val2;
+
+ /* First one, we need to add the "Disable" choice */
+ val2.i_int = -1; text.psz_string = _("Disable");
+ var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
+ val.i_int++;
}
- if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
+ /* Take care of the ES description */
+ if( es->psz_description && *es->psz_description )
{
- if( !es->p_es->p_dec )
- {
- input_SelectES( p_input, es->p_es );
- }
+ text.psz_string = strdup( es->psz_description );
}
- else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
+ else
{
- int i_wanted = -1;
+ text.psz_string = malloc( strlen( _("Track %i") ) + 20 );
+ sprintf( text.psz_string, _("Track %i"), val.i_int );
+ }
- if( es->p_es->p_pgrm != NULL &&
- es->p_es->p_pgrm != p_input->stream.p_selected_program )
- {
- return;
- }
+ val.i_int = es->i_id;
+ var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
- if( i_cat == AUDIO_ES )
- {
- if( p_sys->p_es_audio &&
- p_sys->p_es_audio->p_es->fmt.i_priority >=
- es->p_es->fmt.i_priority )
- {
- return;
- }
- i_wanted = p_sys->i_audio_last >= 0 ?
- p_sys->i_audio_last : es->i_channel;
- }
- else if( i_cat == SPU_ES )
- {
- if( p_sys->p_es_sub &&
- p_sys->p_es_sub->p_es->fmt.i_priority >=
- es->p_es->fmt.i_priority )
- {
- return;
- }
- i_wanted = p_sys->i_sub_last;
- }
- else if( i_cat == VIDEO_ES )
- {
- i_wanted = es->i_channel;
- }
+ free( text.psz_string );
+
+ var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
+}
+
+/* EsOutProgramSelect:
+ * Select a program and update the object variable
+ */
+static void EsOutProgramSelect( es_out_t *out, es_out_pgrm_t *p_pgrm )
+{
+ es_out_sys_t *p_sys = out->p_sys;
+ input_thread_t *p_input = p_sys->p_input;
+ vlc_value_t val;
+ int i;
+
+ if( p_sys->p_pgrm == p_pgrm )
+ return; /* Nothing to do */
+
+ if( p_sys->p_pgrm )
+ {
+ es_out_pgrm_t *old = p_sys->p_pgrm;
+ msg_Dbg( p_input, "Unselecting program id=%d", old->i_id );
- if( i_wanted == es->i_channel && es->p_es->p_dec == NULL )
+ for( i = 0; i < p_sys->i_es; i++ )
{
- input_SelectES( p_input, es->p_es );
+ if( p_sys->es[i]->p_pgrm == old && p_sys->es[i]->p_dec &&
+ p_sys->i_mode != ES_OUT_MODE_ALL )
+ EsUnselect( out, p_sys->es[i], VLC_TRUE );
}
}
- /* FIXME TODO handle priority here */
- if( es->p_es->p_dec )
+ msg_Dbg( p_input, "Selecting program id=%d", p_pgrm->i_id );
+
+ /* Mark it selected */
+ p_pgrm->b_selected = VLC_TRUE;
+
+ /* Switch master stream */
+ if( p_sys->p_pgrm && p_sys->p_pgrm->clock.b_master )
{
- if( i_cat == AUDIO_ES )
- {
- if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
- p_sys->p_es_audio && p_sys->p_es_audio->p_es->p_dec )
- {
- input_UnselectES( p_input, p_sys->p_es_audio->p_es );
- }
- p_sys->p_es_audio = es;
- }
- else if( i_cat == SPU_ES )
- {
- if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
- p_sys->p_es_sub && p_sys->p_es_sub->p_es->p_dec )
- {
- input_UnselectES( p_input, p_sys->p_es_sub->p_es );
- }
- p_sys->p_es_sub = es;
- }
- else if( i_cat == VIDEO_ES )
- {
- p_sys->p_es_video = es;
- }
+ p_sys->p_pgrm->clock.b_master = VLC_FALSE;
+ }
+ p_pgrm->clock.b_master = VLC_TRUE;
+ p_sys->p_pgrm = p_pgrm;
+
+ /* Update "program" */
+ val.i_int = p_pgrm->i_id;
+ var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
+
+ /* Update "es-*" */
+ var_Change( p_input, "audio-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
+ var_Change( p_input, "video-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
+ var_Change( p_input, "spu-es", VLC_VAR_CLEARCHOICES, NULL, NULL );
+ for( i = 0; i < p_sys->i_es; i++ )
+ {
+ EsOutESVarUpdate( out, p_sys->es[i] );
+ EsOutSelect( out, p_sys->es[i], VLC_FALSE );
+ }
+
+ var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
+}
+
+/* EsOutAddProgram:
+ * Add a program
+ */
+static es_out_pgrm_t *EsOutProgramAdd( es_out_t *out, int i_group )
+{
+ es_out_sys_t *p_sys = out->p_sys;
+ input_thread_t *p_input = p_sys->p_input;
+ vlc_value_t val;
+
+ es_out_pgrm_t *p_pgrm = malloc( sizeof( es_out_pgrm_t ) );
+
+ /* Init */
+ p_pgrm->i_id = i_group;
+ p_pgrm->i_es = 0;
+ p_pgrm->b_selected = VLC_FALSE;
+ input_ClockInit( &p_pgrm->clock, VLC_FALSE, p_input->input.i_cr_average );
+
+ /* Append it */
+ TAB_APPEND( p_sys->i_pgrm, p_sys->pgrm, p_pgrm );
+
+ /* Update "program" variable */
+ val.i_int = i_group;
+ var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
+
+ if( i_group == var_GetInteger( p_input, "program" ) )
+ {
+ EsOutProgramSelect( out, p_pgrm );
+ }
+ else
+ {
+ var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
}
+ return p_pgrm;
}
-/**
- * Add an es_out
- *
- * \param out the es_out to add
- * \param fmt the es_format of the es_out
- * \return an es_out id
+/* EsOutAdd:
+ * Add an es_out
*/
static es_out_id_t *EsOutAdd( es_out_t *out, es_format_t *fmt )
{
es_out_sys_t *p_sys = out->p_sys;
input_thread_t *p_input = p_sys->p_input;
+
es_out_id_t *es = malloc( sizeof( es_out_id_t ) );
- pgrm_descriptor_t *p_pgrm = NULL;
- char psz_cat[sizeof( _("Stream ") ) + 10];
- char *psz_description;
+ es_out_pgrm_t *p_pgrm = NULL;
+ int i;
- vlc_mutex_lock( &p_input->stream.stream_lock );
- if( fmt->i_group >= 0 )
+ if( fmt->i_group < 0 )
{
- /* search program */
- p_pgrm = input_FindProgram( p_input, fmt->i_group );
+ msg_Err( p_input, "invakud group number" );
+ return NULL;
+ }
- if( p_pgrm == NULL )
+ /* Search the program */
+ for( i = 0; i < p_sys->i_pgrm; i++ )
+ {
+ if( fmt->i_group == p_sys->pgrm[i]->i_id )
{
- /* Create it */
- p_pgrm = EsOutAddProgram( out, fmt->i_group );
+ p_pgrm = p_sys->pgrm[i];
+ break;
}
}
- if( fmt->i_id < 0 )
+ if( p_pgrm == NULL )
{
- fmt->i_id = out->p_sys->i_id - 1;
+ /* Create a new one */
+ p_pgrm = EsOutProgramAdd( out, fmt->i_group );
}
- psz_description = LanguageGetName( fmt->psz_language );
- es->p_es = input_AddES( p_input, p_pgrm, fmt->i_id + 1,
- fmt->i_cat, psz_description, 0 );
- es->p_es->i_stream_id = fmt->i_id;
- es->p_es->i_fourcc = fmt->i_codec;
+ /* Increase ref count for program */
+ p_pgrm->i_es++;
+ /* Set up ES */
+ if( fmt->i_id < 0 )
+ fmt->i_id = out->p_sys->i_id;
+ es->i_id = fmt->i_id;
+ es->p_pgrm = p_pgrm;
+ es_format_Copy( &es->fmt, fmt );
switch( fmt->i_cat )
{
case AUDIO_ES:
es->i_channel = 0;
break;
}
+ es->psz_description = LanguageGetName( fmt->psz_language );
+ es->p_dec = NULL;
+
+ if( es->p_pgrm == p_sys->p_pgrm )
+ EsOutESVarUpdate( out, es );
+#if 0
/* Add stream info */
- vlc_mutex_unlock( &p_input->stream.stream_lock );
sprintf( psz_cat, _("Stream %d"), out->p_sys->i_id - 1 );
input_Control( p_input, INPUT_ADD_INFO, psz_cat, _("Codec"),
default:
break;
}
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
free( psz_description );
+#endif
- es_format_Copy( &es->p_es->fmt, fmt );
+ /* Select it if needed */
+ EsOutSelect( out, es, VLC_FALSE );
- /* Apply mode
- * XXX change that when we do group too */
- if( 1 )
- {
- EsOutSelect( out, es, VLC_FALSE );
- }
- vlc_mutex_unlock( &p_input->stream.stream_lock );
TAB_APPEND( out->p_sys->i_es, out->p_sys->es, es );
p_sys->i_id++; /* always incremented */
return es;
}
+static void EsSelect( es_out_t *out, es_out_id_t *es )
+{
+ es_out_sys_t *p_sys = out->p_sys;
+ input_thread_t *p_input = p_sys->p_input;
+ vlc_value_t val;
+ char *psz_var;
+
+ if( es->p_dec )
+ {
+ msg_Warn( p_input, "ES 0x%x is already selected", es->i_id );
+ return;
+ }
+
+ if( es->fmt.i_cat == VIDEO_ES || es->fmt.i_cat == SPU_ES )
+ {
+ if( !var_GetBool( p_input, "video" ) || ( p_input->p_sout && !var_GetBool( p_input, "sout-video" ) ) )
+ {
+ msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x", es->i_id );
+ return;
+ }
+ }
+ else if( es->fmt.i_cat == AUDIO_ES )
+ {
+ var_Get( p_input, "audio", &val );
+ if( !var_GetBool( p_input, "audio" ) || ( p_input->p_sout && !var_GetBool( p_input, "sout-audio" ) ) )
+ {
+ msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x", es->i_id );
+ return;
+ }
+ }
+
+ es->p_dec = input_DecoderNew( p_input, &es->fmt, VLC_FALSE );
+ if( es->p_dec == NULL || es->p_pgrm != p_sys->p_pgrm )
+ return;
+
+ if( es->fmt.i_cat == VIDEO_ES )
+ psz_var = "video-es";
+ else if( es->fmt.i_cat == AUDIO_ES )
+ psz_var = "audio-es";
+ else if( es->fmt.i_cat == SPU_ES )
+ psz_var = "spu-es";
+ else
+ return;
+
+ /* Mark it as selected */
+ val.i_int = es->i_id;
+ var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
+
+
+ var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
+}
+
+static void EsUnselect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_update )
+{
+ es_out_sys_t *p_sys = out->p_sys;
+ input_thread_t *p_input = p_sys->p_input;
+ vlc_value_t val;
+ char *psz_var;
+
+ if( es->p_dec == NULL )
+ {
+ msg_Warn( p_input, "ES 0x%x is already unselected", es->i_id );
+ return;
+ }
+
+ input_DecoderDelete( es->p_dec );
+ es->p_dec = NULL;
+
+ if( !b_update )
+ return;
+
+ /* Update var */
+ if( es->p_dec == NULL )
+ return;
+ if( es->fmt.i_cat == VIDEO_ES )
+ psz_var = "video-es";
+ else if( es->fmt.i_cat == AUDIO_ES )
+ psz_var = "audio-es";
+ else if( es->fmt.i_cat == SPU_ES )
+ psz_var = "spu-es";
+ else
+ return;
+
+ /* Mark it as selected */
+ val.i_int = -1;
+ var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
+
+ var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
+}
+
+/**
+ * Select an ES given the current mode
+ * XXX: you need to take a the lock before (stream.stream_lock)
+ *
+ * \param out The es_out structure
+ * \param es es_out_id structure
+ * \param b_force ...
+ * \return nothing
+ */
+static void EsOutSelect( es_out_t *out, es_out_id_t *es, vlc_bool_t b_force )
+{
+ es_out_sys_t *p_sys = out->p_sys;
+
+ int i_cat = es->fmt.i_cat;
+
+ if( !p_sys->b_active ||
+ ( !b_force && es->fmt.i_priority < 0 ) )
+ {
+ return;
+ }
+
+ if( p_sys->i_mode == ES_OUT_MODE_ALL || b_force )
+ {
+ if( !es->p_dec )
+ EsSelect( out, es );
+ }
+ else if( p_sys->i_mode == ES_OUT_MODE_AUTO )
+ {
+ int i_wanted = -1;
+
+ if( es->p_pgrm != p_sys->p_pgrm )
+ return;
+
+ if( i_cat == AUDIO_ES )
+ {
+ if( p_sys->p_es_audio &&
+ p_sys->p_es_audio->fmt.i_priority >= es->fmt.i_priority )
+ {
+ return;
+ }
+ i_wanted = p_sys->i_audio_last >= 0 ?
+ p_sys->i_audio_last : es->i_channel;
+ }
+ else if( i_cat == SPU_ES )
+ {
+ if( p_sys->p_es_sub &&
+ p_sys->p_es_sub->fmt.i_priority >=
+ es->fmt.i_priority )
+ {
+ return;
+ }
+ i_wanted = p_sys->i_sub_last;
+ }
+ else if( i_cat == VIDEO_ES )
+ {
+ i_wanted = es->i_channel;
+ }
+
+ if( i_wanted == es->i_channel && es->p_dec == NULL )
+ EsSelect( out, es );
+ }
+
+ /* FIXME TODO handle priority here */
+ if( es->p_dec )
+ {
+ if( i_cat == AUDIO_ES )
+ {
+ if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
+ p_sys->p_es_audio && p_sys->p_es_audio->p_dec )
+ {
+ EsUnselect( out, p_sys->p_es_audio, VLC_FALSE );
+ }
+ p_sys->p_es_audio = es;
+ }
+ else if( i_cat == SPU_ES )
+ {
+ if( p_sys->i_mode == ES_OUT_MODE_AUTO &&
+ p_sys->p_es_sub && p_sys->p_es_sub->p_dec )
+ {
+ EsUnselect( out, p_sys->p_es_sub, VLC_FALSE );
+ }
+ p_sys->p_es_sub = es;
+ }
+ else if( i_cat == VIDEO_ES )
+ {
+ p_sys->p_es_video = es;
+ }
+ }
+}
+
/**
* Send a block for the given es_out
*
static int EsOutSend( es_out_t *out, es_out_id_t *es, block_t *p_block )
{
es_out_sys_t *p_sys = out->p_sys;
- pgrm_descriptor_t *p_pgrm = es->p_es->p_pgrm;
input_thread_t *p_input = p_sys->p_input;
-
- if( p_pgrm == NULL )
- {
- p_pgrm = p_sys->p_input->stream.p_selected_program;
- }
+ es_out_pgrm_t *p_pgrm = es->p_pgrm;
/* +11 -> avoid null value with non null dts/pts */
- if( p_block->i_dts > 0 && p_pgrm )
+ if( p_block->i_dts > 0 )
{
p_block->i_dts =
- input_ClockGetTS( p_input, p_pgrm, ( p_block->i_dts + 11 ) * 9 / 100 );
+ input_ClockGetTS( p_input, &p_pgrm->clock, ( p_block->i_dts + 11 ) * 9 / 100 );
}
- if( p_block->i_pts > 0 && p_pgrm )
+ if( p_block->i_pts > 0 )
{
p_block->i_pts =
- input_ClockGetTS( p_input, p_pgrm, ( p_block->i_pts + 11 )* 9 / 100 );
+ input_ClockGetTS( p_input, &p_pgrm->clock, ( p_block->i_pts + 11 )* 9 / 100 );
}
- vlc_mutex_lock( &out->p_sys->p_input->stream.stream_lock );
- p_block->i_rate = out->p_sys->p_input->stream.control.i_rate;
- if( es->p_es->p_dec &&
- (es->p_es->i_cat!=AUDIO_ES || !p_sys->p_input->stream.control.b_mute) )
+ p_block->i_rate = p_input->i_rate;
+
+ /* TODO handle mute */
+ if( es->p_dec && ( es->fmt.i_cat != AUDIO_ES || p_input->i_rate == INPUT_RATE_DEFAULT ) )
{
- vlc_mutex_unlock( &out->p_sys->p_input->stream.stream_lock );
- input_DecodeBlock( es->p_es->p_dec, p_block );
+ input_DecoderDecode( es->p_dec, p_block );
}
else
{
- vlc_mutex_unlock( &out->p_sys->p_input->stream.stream_lock );
block_Release( p_block );
}
{
es_out_sys_t *p_sys = out->p_sys;
+ /* We don't try to reselect */
+ if( es->p_dec )
+ EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
+
TAB_REMOVE( p_sys->i_es, p_sys->es, es );
- switch( es->p_es->i_cat )
+ es->p_pgrm->i_es--;
+ if( es->p_pgrm->i_es == 0 )
+ {
+ msg_Err( p_sys->p_input, "Program doesn't have es anymore, clenaing TODO ?" );
+ }
+
+ if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
+ if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
+ if( p_sys->p_es_sub == es ) p_sys->p_es_sub = NULL;
+
+ switch( es->fmt.i_cat )
{
case AUDIO_ES:
p_sys->i_audio--;
break;
}
- /* We don't try to reselect */
- vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
- if( es->p_es->p_dec )
- {
- input_UnselectES( p_sys->p_input, es->p_es );
- }
-
- if( es->p_es->p_waveformatex )
- {
- free( es->p_es->p_waveformatex );
- es->p_es->p_waveformatex = NULL;
- }
- if( es->p_es->p_bitmapinfoheader )
- {
- free( es->p_es->p_bitmapinfoheader );
- es->p_es->p_bitmapinfoheader = NULL;
- }
- input_DelES( p_sys->p_input, es->p_es );
+ if( es->psz_description )
+ free( es->psz_description );
- if( p_sys->p_es_audio == es ) p_sys->p_es_audio = NULL;
- if( p_sys->p_es_video == es ) p_sys->p_es_video = NULL;
- if( p_sys->p_es_sub == es ) p_sys->p_es_sub = NULL;
-
- vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
+ es_format_Clean( &es->fmt );
free( es );
}
switch( i_query )
{
case ES_OUT_SET_ES_STATE:
- vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
es = (es_out_id_t*) va_arg( args, es_out_id_t * );
b = (vlc_bool_t) va_arg( args, vlc_bool_t );
- if( b && es->p_es->p_dec == NULL )
+ if( b && es->p_dec == NULL )
{
- input_SelectES( p_sys->p_input, es->p_es );
- vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
- return es->p_es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
+ EsSelect( out, es );
+ return es->p_dec ? VLC_SUCCESS : VLC_EGENERIC;
}
- else if( !b && es->p_es->p_dec )
+ else if( !b && es->p_dec )
{
- input_UnselectES( p_sys->p_input, es->p_es );
- vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
+ EsUnselect( out, es, es->p_pgrm == p_sys->p_pgrm );
return VLC_SUCCESS;
}
- vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
return VLC_SUCCESS;
case ES_OUT_GET_ES_STATE:
es = (es_out_id_t*) va_arg( args, es_out_id_t * );
pb = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
- *pb = es->p_es->p_dec ? VLC_TRUE : VLC_FALSE;
+ *pb = es->p_dec ? VLC_TRUE : VLC_FALSE;
return VLC_SUCCESS;
case ES_OUT_SET_ACTIVE:
{
b = (vlc_bool_t) va_arg( args, vlc_bool_t );
p_sys->b_active = b;
-
+ /* Needed ? */
if( b )
- {
- vlc_value_t val;
- val.b_bool = VLC_TRUE;
- var_Set( p_sys->p_input, "intf-change", val );
- }
+ var_SetBool( p_sys->p_input, "intf-change", VLC_TRUE );
return VLC_SUCCESS;
}
if( i == ES_OUT_MODE_NONE || i == ES_OUT_MODE_ALL ||
i == ES_OUT_MODE_AUTO )
{
- vlc_value_t val;
-
p_sys->i_mode = i;
/* Reapply policy mode */
- vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
for( i = 0; i < p_sys->i_es; i++ )
{
- if( p_sys->es[i]->p_es->p_dec )
+ if( p_sys->es[i]->p_dec )
{
- input_UnselectES( p_sys->p_input, p_sys->es[i]->p_es );
+ EsUnselect( out, p_sys->es[i], p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
}
}
for( i = 0; i < p_sys->i_es; i++ )
{
EsOutSelect( out, p_sys->es[i], VLC_FALSE );
}
- vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
-
- val.b_bool = VLC_TRUE;
- var_Set( p_sys->p_input, "intf-change", val );
-
return VLC_SUCCESS;
}
return VLC_EGENERIC;
case ES_OUT_SET_ES:
es = (es_out_id_t*) va_arg( args, es_out_id_t * );
+ /* Special case NULL, NULL+i_cat */
if( es == NULL )
{
for( i = 0; i < p_sys->i_es; i++ )
{
- vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
- if( p_sys->es[i]->p_es->p_dec )
- {
- input_UnselectES( p_sys->p_input, p_sys->es[i]->p_es );
- }
- vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
+ if( p_sys->es[i]->p_dec )
+ EsUnselect( out, p_sys->es[i],
+ p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
+ }
+ }
+ else if( es == (es_out_id_t*)((uint8_t*)NULL+AUDIO_ES) )
+ {
+ for( i = 0; i < p_sys->i_es; i++ )
+ {
+ if( p_sys->es[i]->p_dec && p_sys->es[i]->fmt.i_cat == AUDIO_ES )
+ EsUnselect( out, p_sys->es[i], p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
+ }
+ }
+ else if( es == (es_out_id_t*)((uint8_t*)NULL+VIDEO_ES) )
+ {
+ for( i = 0; i < p_sys->i_es; i++ )
+ {
+ if( p_sys->es[i]->p_dec && p_sys->es[i]->fmt.i_cat == VIDEO_ES )
+ EsUnselect( out, p_sys->es[i], p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
+ }
+ }
+ else if( es == (es_out_id_t*)((uint8_t*)NULL+SPU_ES) )
+ {
+ for( i = 0; i < p_sys->i_es; i++ )
+ {
+ if( p_sys->es[i]->p_dec && p_sys->es[i]->fmt.i_cat == SPU_ES )
+ EsUnselect( out, p_sys->es[i], p_sys->es[i]->p_pgrm == p_sys->p_pgrm );
}
}
else
{
- vlc_mutex_lock( &p_sys->p_input->stream.stream_lock );
- EsOutSelect( out, es, VLC_TRUE );
- vlc_mutex_unlock( &p_sys->p_input->stream.stream_lock );
+ for( i = 0; i < p_sys->i_es; i++ )
+ {
+ if( es == p_sys->es[i] )
+ {
+ EsOutSelect( out, es, VLC_TRUE );
+ break;
+ }
+ }
}
return VLC_SUCCESS;
case ES_OUT_SET_PCR:
case ES_OUT_SET_GROUP_PCR:
{
- pgrm_descriptor_t *p_pgrm = NULL;
- int64_t i_pcr;
+ es_out_pgrm_t *p_pgrm = NULL;
+ int i_group = 0;
+ int64_t i_pcr;
if( i_query == ES_OUT_SET_PCR )
{
- p_pgrm = p_sys->p_input->stream.p_selected_program;
+ p_pgrm = p_sys->p_pgrm;
}
else
{
- int i_group = (int)va_arg( args, int );
- p_pgrm = input_FindProgram( p_sys->p_input, i_group );
- if( p_pgrm == NULL )
+ int i;
+ i_group = (int)va_arg( args, int );
+ for( i = 0; i < p_sys->i_pgrm; i++ )
{
- /* we create the requested program */
- p_pgrm = EsOutAddProgram( out, i_group );
+ if( p_sys->pgrm[i]->i_id == i_group )
+ {
+ p_pgrm = p_sys->pgrm[i];
+ break;
+ }
}
}
+ if( p_pgrm == NULL )
+ p_pgrm = EsOutProgramAdd( out, i_group ); /* Create it */
+
i_pcr = (int64_t)va_arg( args, int64_t );
/* search program */
- if( p_pgrm )
- {
/* 11 is a vodoo trick to avoid non_pcr*9/100 to be null */
- input_ClockManageRef( p_sys->p_input, p_pgrm, (i_pcr + 11 ) * 9 / 100);
- }
+ input_ClockSetPCR( p_sys->p_input, &p_pgrm->clock, (i_pcr + 11 ) * 9 / 100);
return VLC_SUCCESS;
}
case ES_OUT_RESET_PCR:
- for( i = 0; i < p_sys->p_input->stream.i_pgrm_number; i++ )
+ for( i = 0; i < p_sys->i_pgrm; i++ )
{
- p_sys->p_input->stream.pp_programs[i]->i_synchro_state =
- SYNCHRO_REINIT;
- p_sys->p_input->stream.pp_programs[i]->last_pts = 0;
+ p_sys->pgrm[i]->clock.i_synchro_state = SYNCHRO_REINIT;
+ p_sys->pgrm[i]->clock.last_pts = 0;
}
return VLC_SUCCESS;
+ case ES_OUT_GET_GROUP:
+ pi = (int*) va_arg( args, int* );
+ if( p_sys->p_pgrm )
+ *pi = p_sys->p_pgrm->i_id;
+ else
+ *pi = -1; /* FIXME */
+ return VLC_SUCCESS;
+
+ case ES_OUT_SET_GROUP:
+ {
+ int j;
+ i = (int) va_arg( args, int );
+ for( j = 0; j < p_sys->i_pgrm; j++ )
+ {
+ es_out_pgrm_t *p_pgrm = p_sys->pgrm[j];
+ if( p_pgrm->i_id == i )
+ {
+ EsOutProgramSelect( out, p_pgrm );
+ return VLC_SUCCESS;
+ }
+ }
+ return VLC_EGENERIC;
+ }
+
default:
msg_Err( p_sys->p_input, "unknown query in es_out_Control" );
return VLC_EGENERIC;
/*****************************************************************************
* input.c: input thread
- * Read a stream, demultiplex and parse it before sending it to
- * decoders.
*****************************************************************************
* Copyright (C) 1998-2004 VideoLAN
* $Id$
*
* Authors: Christophe Massiot <massiot@via.ecp.fr>
+ * Laurent Aimar <fenrir@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
#include <vlc/decoder.h>
#include <vlc/vout.h>
-#ifdef HAVE_SYS_TIMES_H
-# include <sys/times.h>
-#endif
+#include "input_internal.h"
#include "stream_output.h"
#include "vlc_interface.h"
-#include "codecs.h"
#include "vlc_meta.h"
-#include "../../modules/demux/util/sub.h"
/*****************************************************************************
* Local prototypes
*****************************************************************************/
-struct input_thread_sys_t
-{
- /* subtitles */
- int i_sub;
- subtitle_demux_t **sub;
+static int Run ( input_thread_t *p_input );
+
+static int Init ( input_thread_t *p_input );
+static void Error( input_thread_t *p_input );
+static void End ( input_thread_t *p_input );
+
+static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * );
+static void ControlReduce( input_thread_t * );
+static vlc_bool_t Control( input_thread_t *, int, vlc_value_t );
- int64_t i_stop_time;
-};
-static int RunThread ( input_thread_t *p_input );
-static int InitThread ( input_thread_t *p_input );
-static void ErrorThread( input_thread_t *p_input );
-static void EndThread ( input_thread_t *p_input );
+static void UpdateFromAccess( input_thread_t * );
+static void UpdateFromDemux( input_thread_t * );
static void ParseOption( input_thread_t *p_input, const char *psz_option );
static void DecodeUrl ( char * );
-/*****************************************************************************
- * Callbacks
- *****************************************************************************/
-static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data );
-static int TimeCallback ( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data );
-static int StateCallback ( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data );
-static int RateCallback ( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data );
-static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data );
-
/*****************************************************************************
* input_CreateThread: creates a new input thread
*****************************************************************************
* This function creates a new input, and returns a pointer
* to its description. On error, it returns NULL.
+ *
+ * Variables for _public_ use:
+ * * Get and Set:
+ * - state
+ * - rate,rate-slower, rate-faster
+ * - position, position-offset
+ * - time, time-offset
+ * - title,title-next,title-prev
+ * - chapter,chapter-next, chapter-prev
+ * - program, audio-es, video-es, spu-es
+ * - bookmark
+ * * Get only:
+ * - length
+ * - bookmarks
+ * * For intf callback upon changes
+ * - intf-change
+ * TODO explain when Callback is called
+ * TODO complete this list (?)
*****************************************************************************/
input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
input_item_t *p_item )
{
input_thread_t *p_input; /* thread descriptor */
- vlc_value_t val;
int i;
/* Allocate descriptor */
return NULL;
}
- /* Store pointer to input item descriptor */
- p_input->p_item = p_item;
+ /* Init Common fields */
+ p_input->b_eof = VLC_FALSE;
+ p_input->b_can_pace_control = VLC_TRUE;
+ p_input->i_start = 0;
+ p_input->i_time = 0;
+ p_input->i_stop = 0;
+ p_input->i_title = 0;
+ p_input->title = NULL;
+ p_input->i_state = INIT_S;
+ p_input->i_rate = INPUT_RATE_DEFAULT;
+ p_input->i_bookmark = 0;
+ p_input->bookmark = NULL;
+ p_input->p_es_out = NULL;
+ p_input->p_sout = NULL;
+ p_input->b_out_pace_control = VLC_FALSE;
+ p_input->i_pts_delay = 0;
+
+
+ /* Init Input fields */
+ p_input->input.p_item = p_item;
+ p_input->input.p_access = NULL;
+ p_input->input.p_stream = NULL;
+ p_input->input.p_demux = NULL;
+ p_input->input.b_title_demux = VLC_FALSE;
+ p_input->input.i_title = 0;
+ p_input->input.title = NULL;
+ p_input->input.b_can_pace_control = VLC_TRUE;
+ p_input->input.b_eof = VLC_FALSE;
+ p_input->input.i_cr_average = 0;
+
+ /* Init control buffer */
+ vlc_mutex_init( p_input, &p_input->lock_control );
+ p_input->i_control = 0;
+ p_input->p_sys = NULL;
/* Parse input options */
vlc_mutex_lock( &p_item->lock );
}
vlc_mutex_unlock( &p_item->lock );
- /* Create a few object variables we'll need later on */
- var_Create( p_input, "video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
- var_Create( p_input, "audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
- var_Create( p_input, "audio-channel", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
- var_Create( p_input, "spu-channel", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
- var_Create( p_input, "sub-file", VLC_VAR_FILE | VLC_VAR_DOINHERIT );
- var_Create( p_input, "sub-autodetect-file", VLC_VAR_BOOL |
- VLC_VAR_DOINHERIT );
- var_Create( p_input, "sub-autodetect-path", VLC_VAR_STRING |
- VLC_VAR_DOINHERIT );
- var_Create( p_input, "sub-autodetect-fuzzy", VLC_VAR_INTEGER |
- VLC_VAR_DOINHERIT );
-
- var_Create( p_input, "sout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Create( p_input, "sout-all", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
- var_Create( p_input, "sout-audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
- var_Create( p_input, "sout-video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
- var_Create( p_input, "sout-keep", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
-
- /* repeat variable */
- var_Create( p_input, "input-repeat", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
-
- /* start/stop time */
- var_Create( p_input, "start-time", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
- var_Create( p_input, "stop-time", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
-
- /* decoders */
- var_Create( p_input, "minimize-threads", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
-
- /* play status */
-
- /* position variable */
- var_Create( p_input, "position", VLC_VAR_FLOAT ); /* position 0.0->1.0 */
- var_Create( p_input, "position-offset", VLC_VAR_FLOAT ); /* relative */
- val.f_float = 0.0;
- var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
- var_AddCallback( p_input, "position", PositionCallback, NULL );
- var_AddCallback( p_input, "position-offset", PositionCallback, NULL );
-
- /* time variable */
- var_Create( p_input, "time", VLC_VAR_TIME );
- var_Create( p_input, "time-offset", VLC_VAR_TIME ); /* relative */
- val.i_time = 0;
- var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
- var_AddCallback( p_input, "time", TimeCallback, NULL );
- var_AddCallback( p_input, "time-offset", TimeCallback, NULL );
-
- /* length variable */
- var_Create( p_input, "length", VLC_VAR_TIME );
- val.i_time = 0;
- var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
-
- /* rate variable */
- var_Create( p_input, "rate", VLC_VAR_INTEGER );
- var_Create( p_input, "rate-slower", VLC_VAR_VOID );
- var_Create( p_input, "rate-faster", VLC_VAR_VOID );
- val.i_int = DEFAULT_RATE;
- var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
- var_AddCallback( p_input, "rate", RateCallback, NULL );
- var_AddCallback( p_input, "rate-slower", RateCallback, NULL );
- var_AddCallback( p_input, "rate-faster", RateCallback, NULL );
-
- /* state variable */
- var_Create( p_input, "state", VLC_VAR_INTEGER );
- val.i_int = INIT_S;
- var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
- var_AddCallback( p_input, "state", StateCallback, NULL );
-
- /* state variable */
- var_Create( p_input, "demuxed-id3", VLC_VAR_BOOL );
- val.b_bool = VLC_FALSE;
- var_Change( p_input, "demuxed-id3", VLC_VAR_SETVALUE, &val, NULL );
-
- /* Initialize thread properties */
- p_input->b_eof = 0;
- p_input->b_out_pace_control = VLC_FALSE;
- p_input->p_sys = NULL;
-
- /* Set target */
- vlc_mutex_lock( &p_item->lock );
- p_input->psz_source = strdup( p_item->psz_uri );
- vlc_mutex_unlock( &p_item->lock );
-
- /* Stream */
- p_input->s = NULL;
-
- /* es out */
- p_input->p_es_out = NULL;
-
- /* Demux */
- p_input->p_demux = NULL;
- p_input->pf_demux = NULL;
- p_input->pf_rewind = NULL;
- p_input->pf_demux_control = demux_vaControlDefault;
- p_input->i_cr_average = config_GetInt( p_input, "cr-average" );
-
- /* Access */
- p_input->p_access = NULL;
- p_input->pf_access_control = NULL;
-
- p_input->i_bufsize = 0;
- p_input->i_mtu = 0;
- p_input->i_pts_delay = DEFAULT_PTS_DELAY;
-
- /* Initialize statistics */
- p_input->c_loops = 0;
- p_input->stream.c_packets_read = 0;
- p_input->stream.c_packets_trashed = 0;
-
- /* Set locks. */
- vlc_mutex_init( p_input, &p_input->stream.stream_lock );
- vlc_cond_init( p_input, &p_input->stream.stream_wait );
- vlc_mutex_init( p_input, &p_input->stream.control.control_lock );
-
- /* Initialize stream description */
- p_input->stream.b_changed = 0;
- p_input->stream.i_es_number = 0;
- p_input->stream.i_selected_es_number = 0;
- p_input->stream.i_pgrm_number = 0;
- p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
- p_input->stream.b_new_mute = MUTE_NO_CHANGE;
- p_input->stream.i_mux_rate = 0;
- p_input->stream.b_seekable = 0;
- p_input->stream.p_sout = NULL;
-
- /* no stream, no program, no area, no es */
- p_input->stream.p_new_program = NULL;
-
- p_input->stream.i_area_nb = 0;
- p_input->stream.pp_areas = NULL;
- p_input->stream.p_selected_area = NULL;
- p_input->stream.p_new_area = NULL;
-
- p_input->stream.pp_selected_es = NULL;
- p_input->stream.p_removed_es = NULL;
- p_input->stream.p_newly_selected_es = NULL;
-
- /* By default there is one area in a stream */
- input_AddArea( p_input, 0, 1 );
- p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
-
- /* Initialize stream control properties. */
- p_input->stream.control.i_status = INIT_S;
- p_input->stream.control.i_rate = DEFAULT_RATE;
- p_input->stream.control.b_mute = 0;
- p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale");
-
- msg_Info( p_input, "playlist item `%s'", p_input->psz_source );
+ /* Create Object Variables for private use only */
+ input_ConfigVarInit( p_input );
- /* Bookmarks */
- var_Create( p_input, "bookmarks", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
- var_Create( p_input, "bookmark", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE |
- VLC_VAR_ISCOMMAND );
- val.psz_string = _("Bookmark");
- var_Change( p_input, "bookmark", VLC_VAR_SETTEXT, &val, NULL );
- var_AddCallback( p_input, "bookmark", BookmarkCallback, NULL );
-
- p_input->i_bookmarks = 0;
- p_input->pp_bookmarks = NULL;
+ /* Create Objects variables for public Get and Set */
+ input_ControlVarInit( p_input );
+ p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
+#if 0
+ /* TODO */
var_Get( p_input, "bookmarks", &val );
if( val.psz_string )
{
}
free( val.psz_string );
}
+#endif
+ /* Now we can attach our new input */
vlc_object_attach( p_input, p_parent );
/* Create thread and wait for its readiness. */
- if( vlc_thread_create( p_input, "input", RunThread,
+ if( vlc_thread_create( p_input, "input", Run,
VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
{
msg_Err( p_input, "cannot create input thread" );
- free( p_input );
+ vlc_object_detach( p_input );
+ vlc_object_destroy( p_input );
return NULL;
}
*****************************************************************************/
void input_StopThread( input_thread_t *p_input )
{
- demux_t *p_demux;
- access_t *p_access;
+ vlc_list_t *p_list;
+ int i;
- /* Make the thread exit from a possible vlc_cond_wait() */
- vlc_mutex_lock( &p_input->stream.stream_lock );
+ /* Set die for input */
+ p_input->b_die = VLC_TRUE;
- /* Request thread destruction */
+ /* We cannot touch p_input fields directly (we can from another thread),
+ * so use the vlc_object_find way, it's perfectly safe */
- /* Temporary demux2 hack */
- p_demux = (demux_t *)vlc_object_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
- if( p_demux )
+ /* Set die for all access */
+ p_list = vlc_list_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
+ for( i = 0; i < p_list->i_count; i++ )
{
- p_demux->b_die = 1;
- vlc_object_release( p_demux );
+ p_list->p_values[i].p_object->b_die = VLC_TRUE;
}
+ vlc_list_release( p_list );
- /* Temporary access2 hack */
- p_access = (access_t *)vlc_object_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
- if( p_access )
+ /* Set die for all stream */
+ p_list = vlc_list_find( p_input, VLC_OBJECT_STREAM, FIND_CHILD );
+ for( i = 0; i < p_list->i_count; i++ )
{
- p_access->b_die = 1;
- vlc_object_release( p_access );
+ p_list->p_values[i].p_object->b_die = VLC_TRUE;
}
+ vlc_list_release( p_list );
- p_input->b_die = 1;
+ /* Set die for all demux */
+ p_list = vlc_list_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
+ for( i = 0; i < p_list->i_count; i++ )
+ {
+ p_list->p_values[i].p_object->b_die = VLC_TRUE;
+ }
+ vlc_list_release( p_list );
- vlc_cond_signal( &p_input->stream.stream_wait );
- vlc_mutex_unlock( &p_input->stream.stream_lock );
+ input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
}
/*****************************************************************************
/* Join the thread */
vlc_thread_join( p_input );
- /* Destroy Mutex locks */
- vlc_mutex_destroy( &p_input->stream.control.control_lock );
- vlc_cond_destroy( &p_input->stream.stream_wait );
- vlc_mutex_destroy( &p_input->stream.stream_lock );
+ /* Delete input lock (only after thread joined) */
+ vlc_mutex_destroy( &p_input->lock_control );
+
+ /* TODO: maybe input_DestroyThread should also delete p_input instead
+ * of the playlist but I'm not sure if it's possible */
}
/*****************************************************************************
- * RunThread: main thread loop
+ * Run: main thread loop
*****************************************************************************
* Thread in charge of processing the network packets and demultiplexing.
*****************************************************************************/
-static int RunThread( input_thread_t *p_input )
+static int Run( input_thread_t *p_input )
{
- vlc_value_t val;
- mtime_t i_update_next = -1;
+ int64_t i_intf_update = 0;
- /* Signal right now, otherwise we'll get stuck in a peek */
+ /* Signal that the thread is launched */
vlc_thread_ready( p_input );
- if( InitThread( p_input ) )
+ if( Init( p_input ) )
{
/* If we failed, wait before we are killed, and exit */
- p_input->b_error = 1;
+ p_input->b_error = VLC_TRUE;
- ErrorThread( p_input );
+ Error( p_input );
/* Tell we're dead */
- p_input->b_dead = 1;
+ p_input->b_dead = VLC_TRUE;
return 0;
}
- /* initialization is complete */
- vlc_mutex_lock( &p_input->stream.stream_lock );
- p_input->stream.b_changed = 1;
- p_input->stream.control.i_status = PLAYING_S;
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- val.i_int = PLAYING_S;
- var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
-
+ /* Main loop */
while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
{
- unsigned int i, i_count;
-
- p_input->c_loops++;
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
+ vlc_bool_t b_force_update = VLC_FALSE;
+ int i_ret;
+ int i_type;
+ vlc_value_t val;
- if( p_input->stream.p_new_program )
+ /* Do the read */
+ if( p_input->i_state != PAUSE_S )
{
- if( p_input->pf_set_program != NULL )
- {
-
- /* Reinitialize buffer manager. */
- input_AccessReinit( p_input );
-
- p_input->pf_set_program( p_input,
- p_input->stream.p_new_program );
+ if( p_input->i_stop <= 0 || p_input->i_time < p_input->i_stop )
+ i_ret=p_input->input.p_demux->pf_demux(p_input->input.p_demux);
+ else
+ i_ret = 0; /* EOF */
- /* Escape all decoders for the stream discontinuity they
- * will encounter. */
- input_EscapeDiscontinuity( p_input );
+ if( i_ret > 0 )
+ {
+ /* TODO */
+ if( p_input->input.b_title_demux &&
+ p_input->input.p_demux->info.i_update )
+ {
+ UpdateFromDemux( p_input );
+ b_force_update = VLC_TRUE;
+ }
+ else if( !p_input->input.b_title_demux &&
+ p_input->input.p_access &&
+ p_input->input.p_access->info.i_update )
+ {
+ UpdateFromAccess( p_input );
+ b_force_update = VLC_TRUE;
+ }
+ }
+ else if( i_ret == 0 ) /* EOF */
+ {
+ vlc_value_t repeat;
- for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
+ var_Get( p_input, "input-repeat", &repeat );
+ if( repeat.i_int == 0 )
+ {
+ /* End of file - we do not set b_die because only the
+ * playlist is allowed to do so. */
+ msg_Dbg( p_input, "EOF reached" );
+ p_input->b_eof = VLC_TRUE;
+ p_input->input.b_eof = VLC_TRUE;
+ }
+ else
{
- pgrm_descriptor_t * p_pgrm
- = p_input->stream.pp_programs[i];
+ msg_Dbg( p_input, "repeating the same input (%d)", repeat.i_int );
+ if( repeat.i_int > 0 )
+ {
+ repeat.i_int--;
+ var_Set( p_input, "input-repeat", repeat );
+ }
- /* Reinitialize synchro. */
- p_pgrm->i_synchro_state = SYNCHRO_REINIT;
+ /* Seek to title 0 position 0(start) */
+ val.i_int = 0;
+ input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
+ if( p_input->i_start > 0 )
+ {
+ val.i_time = p_input->i_start;
+ input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
+ &val );
+ }
+ else
+ {
+ val.f_float = 0.0;
+ input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
+ &val );
+ }
}
}
- p_input->stream.p_new_program = NULL;
+ else if( i_ret < 0 )
+ {
+ p_input->b_error = VLC_TRUE;
+ }
}
-
- if( p_input->stream.p_new_area )
+ else
{
- if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
- {
- input_AccessReinit( p_input );
+ /* Small wait */
+ msleep( 10*1000 );
+ }
- p_input->pf_set_area( p_input, p_input->stream.p_new_area );
+ /* Handle control */
+ vlc_mutex_lock( &p_input->lock_control );
+ ControlReduce( p_input );
+ while( !ControlPopNoLock( p_input, &i_type, &val ) )
+ {
+ msg_Dbg( p_input, "control type=%d", i_type );
+ if( Control( p_input, i_type, val ) )
+ b_force_update = VLC_TRUE;
+ }
+ vlc_mutex_unlock( &p_input->lock_control );
- /* Escape all decoders for the stream discontinuity they
- * will encounter. */
- input_EscapeDiscontinuity( p_input );
+ if( b_force_update ||
+ i_intf_update < mdate() )
+ {
+ vlc_value_t val;
+ double f_pos;
+ int64_t i_time, i_length;
+ /* update input status variables */
+ if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_POSITION, &f_pos ) )
+ {
+ val.f_float = (float)f_pos;
+ var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
+ }
+ if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_TIME, &i_time ) )
+ {
+ p_input->i_time = i_time;
+ val.i_time = i_time;
+ var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
+ }
+ if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH, &i_length ) )
+ {
+ vlc_value_t old_val;
+ var_Get( p_input, "length", &old_val );
+ val.i_time = i_length;
+ var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
- for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
+ if( old_val.i_time != val.i_time )
{
- pgrm_descriptor_t * p_pgrm
- = p_input->stream.pp_programs[i];
+ /* TODO */
+#if 0
+ char psz_buffer[MSTRTIME_MAX_SIZE];
- /* Reinitialize synchro. */
- p_pgrm->i_synchro_state = SYNCHRO_REINIT;
+ vlc_mutex_lock( &p_input->p_item->lock );
+ p_input->p_item->i_duration = i_length;
+ vlc_mutex_unlock( &p_input->p_item->lock );
+
+ input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
+ msecstotimestr( psz_buffer, i_length / 1000 ) );
+#endif
}
}
- p_input->stream.p_new_area = NULL;
+
+ var_SetBool( p_input, "intf-change", VLC_TRUE );
+ i_intf_update = mdate() + I64C(150000);
}
+ }
+
+ /* Wait we are asked to die */
+ if( !p_input->b_die )
+ {
+ Error( p_input );
+ }
+
+ /* Clean up */
+ End( p_input );
+
+ return 0;
+#if 0
+ while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
+ {
if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
{
if( p_input->stream.p_selected_area->i_size > 0 )
p_input->stream.p_selected_area->i_seek = NO_SEEK;
}
- if( p_input->stream.p_removed_es )
- {
- input_UnselectES( p_input, p_input->stream.p_removed_es );
- p_input->stream.p_removed_es = NULL;
- }
-
- if( p_input->stream.p_newly_selected_es )
- {
- input_SelectES( p_input, p_input->stream.p_newly_selected_es );
- p_input->stream.p_newly_selected_es = NULL;
- }
-
- if( p_input->stream.b_new_mute != MUTE_NO_CHANGE )
- {
- if( p_input->stream.b_new_mute )
- {
- input_EscapeAudioDiscontinuity( p_input );
- }
-
- vlc_mutex_lock( &p_input->stream.control.control_lock );
- p_input->stream.control.b_mute = p_input->stream.b_new_mute;
- vlc_mutex_unlock( &p_input->stream.control.control_lock );
-
- p_input->stream.b_new_mute = MUTE_NO_CHANGE;
- }
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
/* Read and demultiplex some data. */
i_count = p_input->pf_demux( p_input );
- if( i_count == 0 )
- {
- vlc_value_t repeat;
-
- var_Get( p_input, "input-repeat", &repeat );
- if( repeat.i_int == 0 || p_input->stream.i_area_nb <= 0 )
- {
- /* End of file - we do not set b_die because only the
- * playlist is allowed to do so. */
- msg_Info( p_input, "EOF reached" );
- p_input->b_eof = 1;
- }
- else
- {
- msg_Dbg( p_input, "repeating the same input (%d)", repeat.i_int );
- if( repeat.i_int > 0 )
- {
- repeat.i_int--;
- var_Set( p_input, "input-repeat", repeat );
- }
-
- p_input->stream.p_new_area = p_input->stream.pp_areas[0];
- p_input->stream.p_new_area->i_seek = 0;
- }
- }
- else if( i_count < 0 )
- {
- p_input->b_error = 1;
- }
+ XXXXX
if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
{
EndThread( p_input );
return 0;
+#endif
}
/*****************************************************************************
- * InitThread: init the input Thread
+ * Init: init the input Thread
*****************************************************************************/
-static int InitThread( input_thread_t * p_input )
+static int Init( input_thread_t * p_input )
{
- vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
-// float f_fps;
- double f_fps;
- mtime_t i_length;
-
- /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
- char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
- vlc_value_t val, val1;
- int64_t i_microsecondperframe;
-
- subtitle_demux_t *p_sub_toselect = NULL;
- char *psz_sub_file = NULL;
+ char *psz_dup = strdup( p_input->input.p_item->psz_uri );
+ char *psz_access = NULL;
+ char *psz_demux = NULL;
+ char *psz_path = NULL;
+ char *psz;
+ vlc_value_t val;
- /* Skip the plug-in names */
- while( *psz_parser && *psz_parser != ':' )
- {
- psz_parser++;
- }
+ /* Open access/stream/demux */
+ psz = strchr( psz_dup, ':' );
#if defined( WIN32 ) || defined( UNDER_CE )
- if( psz_parser - p_input->psz_dupsource == 1 )
- {
- msg_Warn( p_input, "drive letter %c: found in source string",
- p_input->psz_dupsource[0] ) ;
- psz_parser = "";
- }
-#endif
-
- if( !*psz_parser )
+ if( psz - psz_dup == 1 )
{
- p_input->psz_access = p_input->psz_demux = "";
- p_input->psz_name = p_input->psz_source;
- free( p_input->psz_dupsource );
- p_input->psz_dupsource = NULL;
+ msg_Warn( p_input, "drive letter %c: found in source string", psz_dup[0] );
}
else
+#endif
+ if( psz )
{
- *psz_parser++ = '\0';
-
- /* let's skip '//' */
- if( psz_parser[0] == '/' && psz_parser[1] == '/' )
- {
- psz_parser += 2 ;
- }
+ *psz++ = '\0';
+ if( psz[0] == '/' && psz[1] == '/' )
+ psz += 2;
- p_input->psz_name = psz_parser ;
+ psz_path = psz;
- /* Come back to parse the access and demux plug-ins */
- psz_parser = p_input->psz_dupsource;
-
- if( !*psz_parser )
- {
- /* No access */
- p_input->psz_access = "";
- }
- else if( *psz_parser == '/' )
- {
- /* No access */
- p_input->psz_access = "";
- psz_parser++;
- }
- else
+ psz = strchr( psz_dup, '/' );
+ if( psz )
{
- p_input->psz_access = psz_parser;
-
- while( *psz_parser && *psz_parser != '/' )
- {
- psz_parser++;
- }
-
- if( *psz_parser == '/' )
- {
- *psz_parser++ = '\0';
- }
+ *psz++ = '\0';
+ psz_demux = psz;
}
- if( !*psz_parser )
- {
- /* No demux */
- p_input->psz_demux = "";
- }
- else
- {
- p_input->psz_demux = psz_parser;
- }
+ psz_access = psz_dup;
}
-
- msg_Dbg( p_input, "access `%s', demux `%s', name `%s'",
- p_input->psz_access, p_input->psz_demux, p_input->psz_name );
-
- if( input_AccessInit( p_input ) == -1 )
+ else
{
- free( p_input->psz_source );
- if( p_input->psz_dupsource != NULL )
- {
- free( p_input->psz_dupsource );
- }
-
- return VLC_EGENERIC;
+ psz_path = psz_dup;
}
- /* Initialize optional stream output. (before demuxer)*/
- var_Get( p_input, "sout", &val );
- if( val.psz_string != NULL )
+ if( psz_access == NULL ) psz_access = "";
+ if( psz_demux == NULL ) psz_demux = "";
+ if( psz_path == NULL ) psz_path = "";
+
+ msg_Dbg( p_input, "`%s' gives access `%s' demux `%s' path `%s'",
+ p_input->input.p_item->psz_uri,
+ psz_access, psz_demux, psz_path );
+
+ /* Initialize optional stream output. (before access/demuxer) */
+ psz = var_GetString( p_input, "sout" );
+ if( *psz )
{
- if ( *val.psz_string && (p_input->stream.p_sout =
- sout_NewInstance( p_input, val.psz_string )) == NULL )
+ p_input->p_sout = sout_NewInstance( p_input, psz );
+ if( p_input->p_sout == NULL )
{
msg_Err( p_input, "cannot start stream output instance, aborting" );
- free( val.psz_string );
+ free( psz );
+ free( psz_dup );
- input_AccessEnd( p_input );
- free( p_input->psz_source );
- if( p_input->psz_dupsource != NULL )
- {
- free( p_input->psz_dupsource );
- }
return VLC_EGENERIC;
}
- free( val.psz_string );
}
+ free( psz );
+ /* Create es out */
p_input->p_es_out = input_EsOutNew( p_input );
es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE );
es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
- /* Find and open appropriate access module */
- p_input->p_access = module_Need( p_input, "access",
- p_input->psz_access, VLC_TRUE );
-
- /* Maybe we had an encoded url */
- if( !p_input->p_access && strchr( p_input->psz_name, '%' ) )
+ /* Try access_demux if no demux given */
+ if( *psz_access && *psz_demux == '\0' )
{
- DecodeUrl( p_input->psz_name );
+ p_input->input.p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
+ NULL, p_input->p_es_out );
+ }
- msg_Dbg( p_input, "retying with %s", p_input->psz_name );
- p_input->p_access = module_Need( p_input, "access",
- p_input->psz_access, VLC_TRUE );
+ if( p_input->input.p_demux )
+ {
+ /* Get infos from access_demux */
+ demux2_Control( p_input->input.p_demux,
+ DEMUX_GET_PTS_DELAY, &p_input->i_pts_delay );
+ p_input->input.b_title_demux = VLC_TRUE;
+ if( demux2_Control( p_input->input.p_demux,
+ DEMUX_GET_TITLE_INFO,
+ &p_input->input.title, &p_input->input.i_title ) )
+ {
+ p_input->input.i_title = 0;
+ p_input->input.title = NULL;
+ }
+ demux2_Control( p_input->input.p_demux, DEMUX_CAN_CONTROL_PACE,
+ &p_input->input.b_can_pace_control );
+ demux2_Control( p_input->input.p_demux, DEMUX_CAN_PAUSE,
+ &p_input->input.b_can_pause );
}
+ else
+ {
+ /* Now try a real access */
+ p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
+
+ /* Access failed, URL encoded ? */
+ if( p_input->input.p_access == NULL && strchr( psz_path, '%' ) )
+ {
+ DecodeUrl( psz_path );
+
+ msg_Dbg( p_input, "retying with access `%s' demux `%s' path `%s'",
+ psz_access, psz_demux, psz_path );
+
+ p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
+ }
#ifndef WIN32 /* Remove this gross hack from the win32 build as colons
- * are forbidden in filenames on Win32. */
+ * are forbidden in filenames on Win32. */
- /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
- if ( p_input->p_access == NULL
- && (*p_input->psz_demux || *p_input->psz_access) )
- {
- p_input->psz_access = p_input->psz_demux = "";
- p_input->psz_name = p_input->psz_source;
- free( p_input->psz_dupsource);
- p_input->psz_dupsource = NULL;
+ /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
+ if( p_input->input.p_access == NULL &&
+ *psz_access == '\0' && ( *psz_demux || *psz_path ) )
+ {
+ free( psz_dup );
+ psz_dup = strdup( p_input->input.p_item->psz_uri );
+ psz_access = "";
+ psz_demux = "";
+ psz_path = psz_dup;
- p_input->p_access = module_Need( p_input, "access",
- p_input->psz_access, VLC_TRUE );
- }
+ p_input->input.p_access = access2_New( p_input, psz_access, psz_demux, psz_path );
+ }
#endif
- if( p_input->p_access == NULL )
- {
- msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
- p_input->psz_access, p_input->psz_demux, p_input->psz_name );
- if ( p_input->stream.p_sout != NULL )
+
+ if( p_input->input.p_access == NULL )
{
- sout_DeleteInstance( p_input->stream.p_sout );
+ msg_Err( p_input, "no suitable access module for `%s'",
+ p_input->input.p_item->psz_uri );
+ goto error;
}
- input_AccessEnd( p_input );
- free( p_input->psz_source );
- if( p_input->psz_dupsource != NULL )
+ /* Get infos from access */
+ access2_Control( p_input->input.p_access,
+ ACCESS_GET_PTS_DELAY, &p_input->i_pts_delay );
+ p_input->input.b_title_demux = VLC_FALSE;
+ if( access2_Control( p_input->input.p_access,
+ ACCESS_GET_TITLE_INFO,
+ &p_input->input.title, &p_input->input.i_title ) )
{
- free( p_input->psz_dupsource );
+ p_input->input.i_title = 0;
+ p_input->input.title = NULL;
+ }
+ access2_Control( p_input->input.p_access, ACCESS_CAN_CONTROL_PACE,
+ &p_input->input.b_can_pace_control );
+ access2_Control( p_input->input.p_access, ACCESS_CAN_PAUSE,
+ &p_input->input.b_can_pace_control );
+
+ /* Create the stream_t */
+ p_input->input.p_stream = stream_AccessNew( p_input->input.p_access );
+ if( p_input->input.p_stream == NULL )
+ {
+ msg_Warn( p_input, "cannot create a stream_t from access" );
+ goto error;
}
- input_EsOutDelete( p_input->p_es_out );
- return VLC_EGENERIC;
- }
- /* Waiting for stream. */
- if( p_input->i_mtu )
- {
- p_input->i_bufsize = p_input->i_mtu;
+ /* Open a demuxer */
+ if( *psz_demux == '\0' && *p_input->input.p_access->psz_demux )
+ {
+ psz_demux = p_input->input.p_access->psz_demux;
+ }
+ p_input->input.p_demux = demux2_New( p_input, psz_access, psz_demux, psz_path,
+ p_input->input.p_stream,
+ p_input->p_es_out );
+ if( p_input->input.p_demux == NULL )
+ {
+ msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
+ psz_access, psz_demux, psz_path );
+ goto error;
+ }
+
+ /* TODO get title from demux */
+ if( p_input->input.i_title <= 0 )
+ {
+ if( demux2_Control( p_input->input.p_demux, DEMUX_GET_TITLE_INFO,
+ &p_input->input.title, &p_input->input.i_title ) )
+ {
+ p_input->input.i_title = 0;
+ p_input->input.title = NULL;
+ }
+ else
+ {
+ p_input->input.b_title_demux = VLC_TRUE;
+ }
+ }
}
- else
+ /* Create global title (for now, just a copy) */
+ p_input->i_title = p_input->input.i_title;
+ if( p_input->i_title > 0 )
{
- p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
+ int i;
+ p_input->title = malloc( sizeof( input_title_t *) * p_input->i_title );
+ for( i = 0; i < p_input->i_title; i++ )
+ {
+ p_input->title[i] = vlc_input_title_Duplicate( p_input->input.title[i] );
+ }
+
+ /* Setup variables */
+ input_ControlVarNavigation( p_input );
+ input_ControlVarTitle( p_input, 0 );
}
+ /* Global flag */
+ p_input->b_can_pace_control = p_input->input.b_can_pace_control;
+ p_input->b_can_pause = p_input->input.b_can_pause;
+
+ /* Fix pts delay */
+ if( p_input->i_pts_delay <= 0 )
+ p_input->i_pts_delay = DEFAULT_PTS_DELAY;
/* If the desynchronisation requested by the user is < 0, we need to
* cache more data. */
- var_Create( p_input, "audio-desync", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
var_Get( p_input, "audio-desync", &val );
if( val.i_int < 0 )
p_input->i_pts_delay -= (val.i_int * 1000);
- if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
- {
- while( !input_FillBuffer( p_input ) )
- {
- if( p_input->b_die || p_input->b_error || p_input->b_eof )
- {
- module_Unneed( p_input, p_input->p_access );
- if ( p_input->stream.p_sout != NULL )
- {
- sout_DeleteInstance( p_input->stream.p_sout );
- }
- input_AccessEnd( p_input );
- free( p_input->psz_source );
- if( p_input->psz_dupsource != NULL )
- {
- free( p_input->psz_dupsource );
- }
- input_EsOutDelete( p_input->p_es_out );
- return VLC_EGENERIC;
- }
- }
- }
+ /* Init input_thread_sys_t */
+ p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
+ p_input->p_sys->i_sub = 0;
+ p_input->p_sys->sub = NULL;
- /* Create the stream_t facilities */
- p_input->s = input_StreamNew( p_input );
- if( p_input->s == NULL )
- {
- /* should never occur yet */
+ /* TODO: check meta data from users */
- msg_Err( p_input, "cannot create stream_t" );
+ /* TODO: get meta data from demuxer */
- module_Unneed( p_input, p_input->p_access );
- if ( p_input->stream.p_sout != NULL )
+ /* Init length */
+ if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH, &val.i_time ) && val.i_time > 0 )
+ {
+ var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
+ /* TODO update playlist meta data */
+ }
+ /* Start time*/
+ /* Set start time */
+ p_input->i_start = (int64_t)var_GetInteger( p_input, "start-time" ) *
+ I64C(1000000);
+ p_input->i_stop = (int64_t)var_GetInteger( p_input, "stop-time" ) *
+ I64C(1000000);
+
+ if( p_input->i_start > 0 )
+ {
+ if( p_input->i_start >= val.i_time )
{
- sout_DeleteInstance( p_input->stream.p_sout );
+ msg_Warn( p_input, "invalid start-time ignored" );
}
- input_AccessEnd( p_input );
- free( p_input->psz_source );
- if( p_input->psz_dupsource != NULL )
+ else
{
- free( p_input->psz_dupsource );
+ vlc_value_t s;
+
+ msg_Dbg( p_input, "start-time: %ds",
+ (int)( p_input->i_start / I64C(1000000) ) );
+
+ s.i_time = p_input->i_start;
+ input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
}
- input_EsOutDelete( p_input->p_es_out );
- return VLC_EGENERIC;
+ }
+ if( p_input->i_stop > 0 && p_input->i_stop <= p_input->i_start )
+ {
+ msg_Warn( p_input, "invalid stop-time ignored" );
+ p_input->i_stop = 0;
}
- /* Find and open appropriate demux module */
- p_input->p_demux =
- module_Need( p_input, "demux",
- (p_input->psz_demux && *p_input->psz_demux) ?
- p_input->psz_demux : "$demux",
- (p_input->psz_demux && *p_input->psz_demux) ?
- VLC_TRUE : VLC_FALSE );
- if( p_input->p_demux == NULL )
- {
- msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
- p_input->psz_access, p_input->psz_demux, p_input->psz_name );
+ /* TODO: do subtitle loading */
- input_StreamDelete( p_input->s );
- module_Unneed( p_input, p_input->p_access );
- if ( p_input->stream.p_sout != NULL )
- {
- sout_DeleteInstance( p_input->stream.p_sout );
- }
- input_AccessEnd( p_input );
- free( p_input->psz_source );
- if( p_input->psz_dupsource != NULL )
- {
- free( p_input->psz_dupsource );
+
+ /* Set up es_out */
+ es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
+ val.b_bool = VLC_FALSE;
+ if( p_input->p_sout )
+ {
+ var_Get( p_input, "sout-all", &val );
+ }
+ es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE,
+ val.b_bool ? ES_OUT_MODE_ALL : ES_OUT_MODE_AUTO );
+
+ /* TODO select forced subs */
+#if 0
+ if( p_sub_toselect )
+ {
+ es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
+ p_sub_toselect->p_es, VLC_TRUE );
+ }
+#endif
+
+ if( p_input->p_sout )
+ {
+ if( p_input->p_sout->i_out_pace_nocontrol > 0 )
+ {
+ p_input->b_out_pace_control = VLC_FALSE;
}
- input_EsOutDelete( p_input->p_es_out );
- return VLC_EGENERIC;
+ else
+ {
+ p_input->b_out_pace_control = VLC_TRUE;
+ }
+ msg_Dbg( p_input, "starting in %s mode",
+ p_input->b_out_pace_control ? "asynch" : "synch" );
}
+ msg_Dbg( p_input, "`%s' sucessfully opened",
+ p_input->input.p_item->psz_uri );
+
+ /* initialization is complete */
+ p_input->i_state = PLAYING_S;
+
+ val.i_int = PLAYING_S;
+ var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
+
+ return VLC_SUCCESS;
+
+error:
+ if( p_input->input.p_demux )
+ demux2_Delete( p_input->input.p_demux );
+
+ if( p_input->input.p_stream )
+ stream_AccessDelete( p_input->input.p_stream );
+
+ if( p_input->input.p_access )
+ access2_Delete( p_input->input.p_access );
+
+ if( p_input->p_es_out )
+ input_EsOutDelete( p_input->p_es_out );
+
+ if( p_input->p_sout )
+ sout_DeleteInstance( p_input->p_sout );
+
+ /* Mark them deleted */
+ p_input->input.p_demux = NULL;
+ p_input->input.p_stream = NULL;
+ p_input->input.p_access = NULL;
+ p_input->p_es_out = NULL;
+ p_input->p_sout = NULL;
+
+ return VLC_EGENERIC;
+
+#if 0
+ vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
+// float f_fps;
+ double f_fps;
+ mtime_t i_length;
+
+ FIXME
+ p_input->input.i_cr_average = config_GetInt( p_input, "cr-average" );
+ p_input->stream.control.i_status = INIT_S;
+ p_input->stream.control.i_rate = DEFAULT_RATE;
+
+
/* Init input_thread_sys_t */
p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
p_input->p_sys->i_sub = 0;
p_input->p_sys->sub = NULL;
- p_input->p_sys->i_stop_time = 0;
-
/* Get meta information from user */
var_Create( p_input, "meta-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
var_Create( p_input, "meta-author", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
vlc_value_t val;
var_Get( p_input, "meta-title", &val );
- if( val.psz_string && *val.psz_string )
+ if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_TITLE, val.psz_string );
- if( val.psz_string ) free( val.psz_string );
+ free( val.psz_string );
var_Get( p_input, "meta-author", &val );
- if( val.psz_string && *val.psz_string )
+ if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_AUTHOR, val.psz_string );
- if( val.psz_string ) free( val.psz_string );
+ free( val.psz_string );
var_Get( p_input, "meta-artist", &val );
- if( val.psz_string && *val.psz_string )
+ if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_ARTIST, val.psz_string );
- if( val.psz_string ) free( val.psz_string );
+ free( val.psz_string );
var_Get( p_input, "meta-genre", &val );
- if( val.psz_string && *val.psz_string )
+ if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_GENRE, val.psz_string );
- if( val.psz_string ) free( val.psz_string );
+ free( val.psz_string );
var_Get( p_input, "meta-copyright", &val );
- if( val.psz_string && *val.psz_string )
+ if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_COPYRIGHT, val.psz_string );
- if( val.psz_string ) free( val.psz_string );
+ free( val.psz_string );
var_Get( p_input, "meta-description", &val );
- if( val.psz_string && *val.psz_string )
+ if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_DESCRIPTION, val.psz_string );
- if( val.psz_string ) free( val.psz_string );
+ free( val.psz_string );
var_Get( p_input, "meta-date", &val );
- if( val.psz_string && *val.psz_string )
+ if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_DATE, val.psz_string );
- if( val.psz_string ) free( val.psz_string );
+ free( val.psz_string );
var_Get( p_input, "meta-url", &val );
- if( val.psz_string && *val.psz_string )
+ if( *val.psz_string )
vlc_meta_Add( p_meta_user, VLC_META_URL, val.psz_string );
- if( val.psz_string ) free( val.psz_string );
+ free( val.psz_string );
}
/* Get meta informations from demuxer */
}
}
- /* Set stop-time and check validity */
- var_Get( p_input, "stop-time", &val );
- if( val.i_int > 0 )
- {
- vlc_value_t start;
-
- var_Get( p_input, "start-time", &start );
- if( start.i_int >= val.i_int )
- {
- msg_Warn( p_input, "invalid stop-time, ignored (stop-time < "
- "start-time)" );
- }
- else
- {
- p_input->p_sys->i_stop_time = (int64_t)val.i_int * I64C(1000000);
- msg_Dbg( p_input, "stop-time %ds", val.i_int );
- }
- }
-
/* Get fps */
if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
{
es_out_Control( p_input->p_es_out, ES_OUT_SET_ES,
p_sub_toselect->p_es, VLC_TRUE );
}
-
- if( p_input->stream.p_sout )
- {
- if( p_input->stream.p_sout->i_out_pace_nocontrol > 0 )
- {
- p_input->b_out_pace_control = VLC_FALSE;
- }
- else
- {
- p_input->b_out_pace_control = VLC_TRUE;
- }
- msg_Dbg( p_input, "starting in %s mode",
- p_input->b_out_pace_control ? "asynch" : "synch" );
- }
-
- return VLC_SUCCESS;
+#endif
}
/*****************************************************************************
- * ErrorThread: RunThread() error loop
+ * Error: RunThread() error loop
*****************************************************************************
* This function is called when an error occured during thread main's loop.
*****************************************************************************/
-static void ErrorThread( input_thread_t *p_input )
+static void Error( input_thread_t *p_input )
{
while( !p_input->b_die )
{
}
/*****************************************************************************
- * EndThread: end the input thread
+ * End: end the input thread
*****************************************************************************/
-static void EndThread( input_thread_t * p_input )
+static void End( input_thread_t * p_input )
{
- int i, j;
-#ifdef HAVE_SYS_TIMES_H
- /* Display statistics */
- struct tms cpu_usage;
- times( &cpu_usage );
-
- msg_Dbg( p_input, "%ld loops consuming user: %ld, system: %ld",
- p_input->c_loops, cpu_usage.tms_utime, cpu_usage.tms_stime );
-#else
- msg_Dbg( p_input, "%ld loops", p_input->c_loops );
-#endif
+ vlc_value_t val;
+ msg_Dbg( p_input, "closing `%s'",
+ p_input->input.p_item->psz_uri );
- /* DumpStream: printf some info for debugging purpose */
-#define S p_input->stream
- msg_Dbg( p_input, "dumping stream ID 0x%x [OK:%ld/D:%ld]", S.i_stream_id,
- S.c_packets_read, S.c_packets_trashed );
-#undef S
- for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
- {
-#define P p_input->stream.pp_programs[i]
- msg_Dbg( p_input, "dumping program 0x%x, version %d (%s)",
- P->i_number, P->i_version,
- P->b_is_ok ? "complete" : "partial" );
-#undef P
- for( j = 0; j < p_input->stream.pp_programs[i]->i_es_number; j++ )
- {
-#define ES p_input->stream.pp_programs[i]->pp_es[j]
- msg_Dbg( p_input, "ES 0x%x, "
- "stream 0x%x, fourcc `%4.4s', %s [OK:%ld/ERR:%ld]",
- ES->i_id, ES->i_stream_id, (char*)&ES->i_fourcc,
- ES->p_dec != NULL ? "selected" : "not selected",
- ES->c_packets, ES->c_invalid_packets );
-#undef ES
- }
- }
+ /* We are at the end */
+ p_input->i_state = END_S;
+
+ val.i_int = END_S;
+ var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
+
+ /* Clean control variables */
+ input_ControlVarClean( p_input );
- /* Free demultiplexer's data */
- if( p_input->p_demux ) module_Unneed( p_input, p_input->p_demux );
+ /* Unload all modules */
+ if( p_input->input.p_demux )
+ demux2_Delete( p_input->input.p_demux );
- /* Free all ES and destroy all decoder threads */
- input_EndStream( p_input );
+ if( p_input->input.p_stream )
+ stream_AccessDelete( p_input->input.p_stream );
+
+ if( p_input->input.p_access )
+ access2_Delete( p_input->input.p_access );
+
+ if( p_input->p_es_out )
+ input_EsOutDelete( p_input->p_es_out );
/* Close optional stream output instance */
- if( p_input->stream.p_sout )
+ if( p_input->p_sout )
{
vlc_object_t *p_pl =
vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
{
/* attach sout to the playlist */
msg_Warn( p_input, "keeping sout" );
- vlc_object_detach( p_input->stream.p_sout );
- vlc_object_attach( p_input->stream.p_sout, p_pl );
+ vlc_object_detach( p_input->p_sout );
+ vlc_object_attach( p_input->p_sout, p_pl );
}
else
{
msg_Warn( p_input, "destroying sout" );
- sout_DeleteInstance( p_input->stream.p_sout );
+ sout_DeleteInstance( p_input->p_sout );
}
if( p_pl )
- {
vlc_object_release( p_pl );
- }
}
+ /* TODO subs */
+#if 0
/* Destroy subtitles demuxers */
if( p_input->p_sys )
{
free( p_input->p_sys->sub );
}
- /* Free input_thread_sys_t */
- free( p_input->p_sys );
}
+#endif
+
+ /* Free input_thread_sys_t */
+ free( p_input->p_sys );
- /* Destroy the stream_t facilities */
- if( p_input->s ) input_StreamDelete( p_input->s );
+ /* Tell we're dead */
+ p_input->b_dead = VLC_TRUE;
+}
- /* Destroy es out */
- if( p_input->p_es_out ) input_EsOutDelete( p_input->p_es_out );
+/*****************************************************************************
+ * Control
+ *****************************************************************************/
+static inline int ControlPopNoLock( input_thread_t *p_input,
+ int *pi_type, vlc_value_t *p_val )
+{
+ if( p_input->i_control <= 0 )
+ {
+ return VLC_EGENERIC;
+ }
- /* Close the access plug-in */
- if( p_input->p_access ) module_Unneed( p_input, p_input->p_access );
+ *pi_type = p_input->control[0].i_type;
+ *p_val = p_input->control[0].val;
- input_AccessEnd( p_input );
+ p_input->i_control--;
+ if( p_input->i_control > 0 )
+ {
+ int i;
- /* Free info structures XXX destroy es before 'cause vorbis */
- msg_Dbg( p_input, "freeing info structures...");
+ for( i = 0; i < p_input->i_control; i++ )
+ {
+ p_input->control[i].i_type = p_input->control[i+1].i_type;
+ p_input->control[i].val = p_input->control[i+1].val;
+ }
+ }
- free( p_input->psz_source );
- if( p_input->psz_dupsource != NULL ) free( p_input->psz_dupsource );
+ return VLC_SUCCESS;
+}
- /* Tell we're dead */
- p_input->b_dead = 1;
+static void ControlReduce( input_thread_t *p_input )
+{
+ int i;
+ for( i = 1; i < p_input->i_control; i++ )
+ {
+ const int i_lt = p_input->control[i-1].i_type;
+ const int i_ct = p_input->control[i].i_type;
+
+ /* XXX We can't merge INPUT_CONTROL_SET_ES */
+ msg_Dbg( p_input, "[%d/%d] l=%d c=%d", i, p_input->i_control, i_lt, i_ct );
+ if( i_lt == i_ct &&
+ ( i_ct == INPUT_CONTROL_SET_STATE ||
+ i_ct == INPUT_CONTROL_SET_RATE ||
+ i_ct == INPUT_CONTROL_SET_POSITION ||
+ i_ct == INPUT_CONTROL_SET_TIME ||
+ i_ct == INPUT_CONTROL_SET_PROGRAM ||
+ i_ct == INPUT_CONTROL_SET_TITLE ||
+ i_ct == INPUT_CONTROL_SET_SEEKPOINT ||
+ i_ct == INPUT_CONTROL_SET_BOOKMARK ) )
+ {
+ int j;
+ msg_Dbg( p_input, "merged at %d", i );
+ /* Remove the i-1 */
+ for( j = i; j < p_input->i_control; j++ )
+ p_input->control[j-1] = p_input->control[j];
+ p_input->i_control--;
+ }
+ else
+ {
+ /* TODO but that's not that important
+ - merge SET_X with SET_X_CMD
+ - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
+ - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
+ - ?
+ */
+ }
+ }
}
+
+static vlc_bool_t Control( input_thread_t *p_input, int i_type, vlc_value_t val )
+{
+ vlc_bool_t b_force_update = VLC_FALSE;
+
+ switch( i_type )
+ {
+ case INPUT_CONTROL_SET_DIE:
+ msg_Dbg( p_input, "control: INPUT_CONTROL_SET_DIE proceed" );
+ /* Mark all submodules to die */
+ if( p_input->input.p_access )
+ p_input->input.p_access->b_die = VLC_TRUE;
+ if( p_input->input.p_stream )
+ p_input->input.p_stream->b_die = VLC_TRUE;
+ p_input->input.p_demux->b_die = VLC_TRUE;
+
+ p_input->b_die = VLC_TRUE;
+ break;
+
+ case INPUT_CONTROL_SET_POSITION:
+ case INPUT_CONTROL_SET_POSITION_OFFSET:
+ {
+ double f_pos;
+ if( i_type == INPUT_CONTROL_SET_POSITION )
+ {
+ f_pos = val.f_float;
+ }
+ else
+ {
+ /* Should not fail */
+ demux2_Control( p_input->input.p_demux, DEMUX_GET_POSITION, &f_pos );
+ f_pos += val.f_float;
+ }
+ if( f_pos < 0.0 ) f_pos = 0.0;
+ if( f_pos > 1.0 ) f_pos = 1.0;
+ if( demux2_Control( p_input->input.p_demux, DEMUX_SET_POSITION, f_pos ) )
+ {
+ msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) %2.1f%% failed",
+ f_pos * 100 );
+ }
+ else
+ {
+ input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+ es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+ b_force_update = VLC_TRUE;
+ }
+ break;
+ }
+
+ case INPUT_CONTROL_SET_TIME:
+ case INPUT_CONTROL_SET_TIME_OFFSET:
+ {
+ int64_t i_time;
+ int i_ret;
+
+ if( i_type == INPUT_CONTROL_SET_TIME )
+ {
+ i_time = val.i_time;
+ }
+ else
+ {
+ /* Should not fail */
+ demux2_Control( p_input->input.p_demux,
+ DEMUX_GET_TIME, &i_time );
+ i_time += val.i_time;
+ }
+ if( i_time < 0 ) i_time = 0;
+ i_ret = demux2_Control( p_input->input.p_demux,
+ DEMUX_SET_TIME, i_time );
+ if( i_ret )
+ {
+ int64_t i_length;
+ /* Emulate it with a SET_POS */
+
+ demux2_Control( p_input->input.p_demux,
+ DEMUX_GET_LENGTH, &i_length );
+ if( i_length > 0 )
+ {
+ double f_pos = (double)i_time / (double)i_length;
+ i_ret = demux2_Control( p_input->input.p_demux,
+ DEMUX_SET_POSITION, f_pos );
+ }
+ }
+ if( i_ret )
+ {
+ msg_Err( p_input, "INPUT_CONTROL_SET_TIME(_OFFSET) %lld failed",
+ i_time );
+ }
+ else
+ {
+ input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+
+ es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+ b_force_update = VLC_TRUE;
+ }
+ break;
+ }
+
+ case INPUT_CONTROL_SET_STATE:
+ if( ( val.i_int == PLAYING_S && p_input->i_state == PAUSE_S ) ||
+ ( val.i_int == PAUSE_S && p_input->i_state == PAUSE_S ) )
+ {
+ int i_ret;
+ if( p_input->input.p_access )
+ i_ret = access2_Control( p_input->input.p_access,
+ ACCESS_SET_PAUSE_STATE, VLC_FALSE );
+ else
+ i_ret = demux2_Control( p_input->input.p_demux,
+ DEMUX_SET_PAUSE_STATE, VLC_FALSE );
+
+ if( i_ret )
+ {
+ /* FIXME What to do ? */
+ msg_Warn( p_input, "cannot unset pause -> EOF" );
+ input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
+ }
+
+ b_force_update = VLC_TRUE;
+
+ /* Switch to play */
+ p_input->i_state = PLAYING_S;
+ val.i_int = PLAYING_S;
+ var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
+
+ /* Reset clock */
+ es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+ }
+ else if( val.i_int == PAUSE_S && p_input->i_state == PLAYING_S && p_input->b_can_pause )
+ {
+ int i_ret;
+ if( p_input->input.p_access )
+ i_ret = access2_Control( p_input->input.p_access,
+ ACCESS_SET_PAUSE_STATE, VLC_TRUE );
+ else
+ i_ret = demux2_Control( p_input->input.p_demux,
+ DEMUX_SET_PAUSE_STATE, VLC_TRUE );
+
+ b_force_update = VLC_TRUE;
+
+ if( i_ret )
+ {
+ msg_Warn( p_input, "cannot set pause state" );
+ val.i_int = p_input->i_state;
+ }
+ else
+ {
+ val.i_int = PAUSE_S;
+ }
+
+ /* Switch to new state */
+ p_input->i_state = val.i_int;
+ var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
+ }
+ else if( val.i_int == PAUSE_S && !p_input->b_can_pause )
+ {
+ b_force_update = VLC_TRUE;
+
+ /* Correct "state" value */
+ val.i_int = p_input->i_state;
+ var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
+ }
+ else if( val.i_int != PLAYING_S && val.i_int != PAUSE_S )
+ {
+ msg_Err( p_input, "invalid state in INPUT_CONTROL_SET_STATE" );
+ }
+ break;
+
+ case INPUT_CONTROL_SET_RATE:
+ case INPUT_CONTROL_SET_RATE_SLOWER:
+ case INPUT_CONTROL_SET_RATE_FASTER:
+ {
+ int i_rate;
+
+ if( i_type == INPUT_CONTROL_SET_RATE_SLOWER )
+ i_rate = p_input->i_rate * 2;
+ else if( i_type == INPUT_CONTROL_SET_RATE_FASTER )
+ i_rate = p_input->i_rate / 2;
+ else
+ i_rate = val.i_int;
+
+ if( i_rate < INPUT_RATE_MIN )
+ {
+ msg_Dbg( p_input, "cannot set rate faster" );
+ i_rate = INPUT_RATE_MIN;
+ }
+ else if( i_rate > INPUT_RATE_MAX )
+ {
+ msg_Dbg( p_input, "cannot set rate slower" );
+ i_rate = INPUT_RATE_MAX;
+ }
+ if( i_rate != INPUT_RATE_DEFAULT &&
+ ( !p_input->b_can_pace_control || !p_input->b_out_pace_control ) )
+ {
+ msg_Dbg( p_input, "cannot change rate" );
+ i_rate = INPUT_RATE_DEFAULT;
+ }
+ if( i_rate != p_input->i_rate )
+ {
+ p_input->i_rate = i_rate;
+ val.i_int = i_rate;
+ var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
+
+ /* We haven't send data to decoder when rate != default */
+ if( i_rate == INPUT_RATE_DEFAULT )
+ input_EsOutDiscontinuity( p_input->p_es_out, VLC_TRUE );
+
+ /* Reset clock */
+ es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+
+ b_force_update = VLC_TRUE;
+ }
+ break;
+ }
+
+ case INPUT_CONTROL_SET_PROGRAM:
+ /* No need to force update, es_out does it if needed */
+ es_out_Control( p_input->p_es_out,
+ ES_OUT_SET_GROUP, val.i_int );
+ break;
+
+ case INPUT_CONTROL_SET_ES:
+ /* No need to force update, es_out does it if needed */
+ es_out_Control( p_input->p_es_out,
+ ES_OUT_SET_ES, input_EsOutGetFromID( p_input->p_es_out, val.i_int ) );
+ break;
+
+ case INPUT_CONTROL_SET_TITLE:
+ case INPUT_CONTROL_SET_TITLE_NEXT:
+ case INPUT_CONTROL_SET_TITLE_PREV:
+ if( p_input->input.b_title_demux &&
+ p_input->input.i_title > 0 )
+ {
+ /* TODO */
+ /* FIXME handle demux title */
+ demux_t *p_demux = p_input->input.p_demux;
+ int i_title;
+
+ if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
+ i_title = p_demux->info.i_title - 1;
+ else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
+ i_title = p_demux->info.i_title + 1;
+ else
+ i_title = val.i_int;
+
+ if( i_title >= 0 && i_title < p_input->input.i_title )
+ {
+ demux2_Control( p_demux, DEMUX_SET_TITLE, i_title );
+
+ input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+ es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+
+ input_ControlVarTitle( p_input, i_title );
+ }
+ }
+ else if( p_input->input.i_title > 0 )
+ {
+ access_t *p_access = p_input->input.p_access;
+ int i_title;
+
+ if( i_type == INPUT_CONTROL_SET_TITLE_PREV )
+ i_title = p_access->info.i_title - 1;
+ else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
+ i_title = p_access->info.i_title + 1;
+ else
+ i_title = val.i_int;
+
+ if( i_title >= 0 && i_title < p_input->input.i_title )
+ {
+ access2_Control( p_access, ACCESS_SET_TITLE, i_title );
+ stream_AccessReset( p_input->input.p_stream );
+
+ input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+ es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+ }
+ }
+ break;
+ case INPUT_CONTROL_SET_SEEKPOINT:
+ case INPUT_CONTROL_SET_SEEKPOINT_NEXT:
+ case INPUT_CONTROL_SET_SEEKPOINT_PREV:
+ if( p_input->input.b_title_demux &&
+ p_input->input.i_title > 0 )
+ {
+ demux_t *p_demux = p_input->input.p_demux;
+ int i_seekpoint;
+
+ if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
+ i_seekpoint = p_demux->info.i_seekpoint - 1;
+ else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
+ i_seekpoint = p_demux->info.i_seekpoint + 1;
+ else
+ i_seekpoint = val.i_int;
+
+ if( i_seekpoint >= 0 &&
+ i_seekpoint < p_input->input.title[p_demux->info.i_title]->i_seekpoint )
+ {
+ demux2_Control( p_demux, DEMUX_SET_SEEKPOINT, i_seekpoint );
+
+ input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+ es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+ }
+ }
+ else if( p_input->input.i_title > 0 )
+ {
+ access_t *p_access = p_input->input.p_access;
+ int i_seekpoint;
+
+ if( i_type == INPUT_CONTROL_SET_SEEKPOINT_PREV )
+ i_seekpoint = p_access->info.i_seekpoint - 1;
+ else if( i_type == INPUT_CONTROL_SET_TITLE_NEXT )
+ i_seekpoint = p_access->info.i_seekpoint + 1;
+ else
+ i_seekpoint = val.i_int;
+
+ if( i_seekpoint >= 0 &&
+ i_seekpoint < p_input->input.title[p_access->info.i_title]->i_seekpoint )
+ {
+ access2_Control( p_access, ACCESS_SET_SEEKPOINT, i_seekpoint );
+ stream_AccessReset( p_input->input.p_stream );
+
+ input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
+ es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
+ }
+ }
+ break;
+
+ case INPUT_CONTROL_SET_BOOKMARK:
+ default:
+ msg_Err( p_input, "not yet implemented" );
+ break;
+ }
+
+ return b_force_update;
+}
+
+/*****************************************************************************
+ * UpdateFromDemux:
+ *****************************************************************************/
+static void UpdateFromDemux( input_thread_t *p_input )
+{
+ demux_t *p_demux = p_input->input.p_demux;
+ vlc_value_t v;
+
+ if( p_demux->info.i_update & INPUT_UPDATE_TITLE )
+ {
+ v.i_int = p_demux->info.i_title;
+ var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
+
+ input_ControlVarTitle( p_input, p_demux->info.i_title );
+
+ p_demux->info.i_update &= ~INPUT_UPDATE_TITLE;
+ }
+ if( p_demux->info.i_update & INPUT_UPDATE_SEEKPOINT )
+ {
+ v.i_int = p_demux->info.i_seekpoint;
+ var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
+
+ p_demux->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
+ }
+ p_demux->info.i_update &= ~INPUT_UPDATE_SIZE;
+}
+
+/*****************************************************************************
+ * UpdateFromAccess:
+ *****************************************************************************/
+static void UpdateFromAccess( input_thread_t *p_input )
+{
+ access_t *p_access = p_input->input.p_access;
+ vlc_value_t v;
+
+ if( p_access->info.i_update & INPUT_UPDATE_TITLE )
+ {
+ v.i_int = p_access->info.i_title;
+ var_Change( p_input, "title", VLC_VAR_SETVALUE, &v, NULL );
+
+ input_ControlVarTitle( p_input, p_access->info.i_title );
+
+ p_access->info.i_update &= ~INPUT_UPDATE_TITLE;
+ }
+ if( p_access->info.i_update & INPUT_UPDATE_SEEKPOINT )
+ {
+ v.i_int = p_access->info.i_seekpoint;
+ var_Change( p_input, "chapter", VLC_VAR_SETVALUE, &v, NULL);
+
+ p_access->info.i_update &= ~INPUT_UPDATE_SEEKPOINT;
+ }
+ p_access->info.i_update &= ~INPUT_UPDATE_SIZE;
+}
+
/*****************************************************************************
* DecodeUrl: decode a given encoded url
*****************************************************************************/
return;
}
-/*****************************************************************************
- * input_SetStatus: change the reading status
- *****************************************************************************/
-
-/* Status changing methods */
-enum
-{
- INPUT_STATUS_END = 0,
- INPUT_STATUS_PLAY = 1,
- INPUT_STATUS_PAUSE = 2,
- INPUT_STATUS_FASTER = 3,
- INPUT_STATUS_SLOWER = 4
-};
-
-static void input_SetStatus( input_thread_t *p_input, int i_mode )
-{
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- switch( i_mode )
- {
- case INPUT_STATUS_END:
- p_input->stream.i_new_status = PLAYING_S;
- p_input->b_eof = 1;
- msg_Dbg( p_input, "end of stream" );
- break;
-
- case INPUT_STATUS_PLAY:
- p_input->stream.i_new_status = PLAYING_S;
- msg_Dbg( p_input, "playing at normal rate" );
- break;
-
- case INPUT_STATUS_PAUSE:
- /* XXX: we don't need to check i_status, because input_clock.c
- * does it for us */
- p_input->stream.i_new_status = PAUSE_S;
- msg_Dbg( p_input, "toggling pause" );
- break;
-
- case INPUT_STATUS_FASTER:
- if( p_input->stream.control.i_rate * 4 <= DEFAULT_RATE )
- {
- msg_Dbg( p_input, "can not play any faster" );
- }
- else
- {
- p_input->stream.i_new_status = FORWARD_S;
- p_input->stream.i_new_rate =
- p_input->stream.control.i_rate / 2;
-
- if ( p_input->stream.i_new_rate < DEFAULT_RATE )
- {
- msg_Dbg( p_input, "playing at %i:1 fast forward",
- DEFAULT_RATE / p_input->stream.i_new_rate );
- }
- else if ( p_input->stream.i_new_rate > DEFAULT_RATE )
- {
- msg_Dbg( p_input, "playing at 1:%i slow motion",
- p_input->stream.i_new_rate / DEFAULT_RATE );
- }
- else if ( p_input->stream.i_new_rate == DEFAULT_RATE )
- {
- p_input->stream.i_new_status = PLAYING_S;
- msg_Dbg( p_input, "playing at normal rate" );
- }
- }
- break;
-
- case INPUT_STATUS_SLOWER:
- if( p_input->stream.control.i_rate >= 8 * DEFAULT_RATE )
- {
- msg_Dbg( p_input, "can not play any slower" );
- }
- else
- {
- p_input->stream.i_new_status = FORWARD_S;
- p_input->stream.i_new_rate =
- p_input->stream.control.i_rate * 2;
-
- if ( p_input->stream.i_new_rate < DEFAULT_RATE )
- {
- msg_Dbg( p_input, "playing at %i:1 fast forward",
- DEFAULT_RATE / p_input->stream.i_new_rate );
- }
- else if ( p_input->stream.i_new_rate > DEFAULT_RATE )
- {
- msg_Dbg( p_input, "playing at 1:%i slow motion",
- p_input->stream.i_new_rate / DEFAULT_RATE );
- }
- else if ( p_input->stream.i_new_rate == DEFAULT_RATE )
- {
- p_input->stream.i_new_status = PLAYING_S;
- msg_Dbg( p_input, "playing at normal rate" );
- }
- }
- break;
-
- default:
- break;
- }
-
- vlc_cond_signal( &p_input->stream.stream_wait );
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-}
-/*****************************************************************************
- * input_SetRate:
- *****************************************************************************/
-static void input_SetRate( input_thread_t *p_input, int i_rate )
-{
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- if( i_rate * 8 < DEFAULT_RATE )
- {
- msg_Dbg( p_input, "can not play faster than 8x" );
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- return;
- }
- if( i_rate > DEFAULT_RATE * 8 )
- {
- msg_Dbg( p_input, "can not play slower than 1/8x" );
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- return;
- }
- p_input->stream.i_new_status = FORWARD_S;
- p_input->stream.i_new_rate = i_rate;
-
- if ( p_input->stream.i_new_rate < DEFAULT_RATE )
- {
- msg_Dbg( p_input, "playing at %i:1 fast forward",
- DEFAULT_RATE / p_input->stream.i_new_rate );
- }
- else if ( p_input->stream.i_new_rate > DEFAULT_RATE )
- {
- msg_Dbg( p_input, "playing at 1:%i slow motion",
- p_input->stream.i_new_rate / DEFAULT_RATE );
- }
- else if ( p_input->stream.i_new_rate == DEFAULT_RATE )
- {
- p_input->stream.i_new_status = PLAYING_S;
- msg_Dbg( p_input, "playing at normal rate" );
- }
-
- vlc_cond_signal( &p_input->stream.stream_wait );
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-}
-
-/*****************************************************************************
- * Callbacks (position, time, state, rate )
- *****************************************************************************/
-static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval,
- void *p_data )
-{
- input_thread_t *p_input = (input_thread_t *)p_this;
-
- msg_Dbg( p_input, "cmd=%s old=%f new=%f", psz_cmd,
- oldval.f_float, newval.f_float );
-
- if( !strcmp( psz_cmd, "position-offset" ) )
- {
- vlc_value_t val;
- var_Get( p_input, "position", &val );
-
- newval.f_float += val.f_float;
- }
- var_Change( p_input, "position", VLC_VAR_SETVALUE, &newval, NULL );
- vlc_mutex_lock( &p_input->stream.stream_lock );
- p_input->stream.p_selected_area->i_seek =
- (int64_t)( newval.f_float *
- (double)p_input->stream.p_selected_area->i_size );
-
- if( p_input->stream.p_selected_area->i_seek < 0 )
- {
- p_input->stream.p_selected_area->i_seek = 0;
- }
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- return VLC_SUCCESS;
-}
-
-static int TimeCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
- input_thread_t *p_input = (input_thread_t *)p_this;
- vlc_value_t val;
-
- /* FIXME TODO FIXME */
- msg_Dbg( p_input, "cmd=%s old=%lld new=%lld", psz_cmd,
- oldval.i_time, newval.i_time );
-
- var_Get( p_input, "length", &val );
- if( val.i_time > 0 )
- {
- val.f_float = (double)newval.i_time / (double)val.i_time;
- if( !strcmp( psz_cmd, "time-offset" ) )
- {
- vlc_value_t t;
- var_Set( p_input, "position-offset", val );
-
- var_Get( p_input, "time", &t );
- t.i_time += newval.i_time;
- var_Change( p_input, "time", VLC_VAR_SETVALUE, &t, NULL );
- }
- else
- {
- var_Set( p_input, "position", val );
- var_Change( p_input, "time", VLC_VAR_SETVALUE, &newval, NULL );
- }
- }
- else
- {
- msg_Warn( p_input, "TimeCallback: length <= 0 -> can't seek" );
- }
- return VLC_SUCCESS;
-}
-
-static int StateCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval,
- void *p_data )
-{
- input_thread_t *p_input = (input_thread_t *)p_this;
-
- msg_Dbg( p_input, "cmd=%s old=%d new=%d",
- psz_cmd, oldval.i_int, newval.i_int );
-
- switch( newval.i_int )
- {
- case PLAYING_S:
- input_SetStatus( p_input, INPUT_STATUS_PLAY );
- return VLC_SUCCESS;
- case PAUSE_S:
- input_SetStatus( p_input, INPUT_STATUS_PAUSE );
- return VLC_SUCCESS;
- case END_S:
- input_SetStatus( p_input, INPUT_STATUS_END );
- return VLC_SUCCESS;
- default:
- msg_Err( p_input, "cannot set new state (invalid)" );
- return VLC_EGENERIC;
- }
-}
-
-static int RateCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
- input_thread_t *p_input = (input_thread_t *)p_this;
-
- if( !strcmp( psz_cmd, "rate-slower" ) )
- {
- input_SetStatus( p_input, INPUT_STATUS_SLOWER );
- }
- else if( !strcmp( psz_cmd, "rate-faster" ) )
- {
- input_SetStatus( p_input, INPUT_STATUS_FASTER );
- }
- else
- {
- msg_Dbg( p_input, "cmd=%s old=%d new=%d",
- psz_cmd, oldval.i_int, newval.i_int );
- input_SetRate( p_input, newval.i_int );
- }
- return VLC_SUCCESS;
-}
-
-static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
- input_thread_t *p_input = (input_thread_t *)p_this;
- return input_Control( p_input, INPUT_SET_BOOKMARK, newval );
-}
+++ /dev/null
-/*****************************************************************************
- * input_ext-plugins.c: useful functions for access and demux plug-ins
- *****************************************************************************
- * Copyright (C) 2001-2004 VideoLAN
- * $Id$
- *
- * 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.
- *
- * 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>
-#include <string.h>
-
-#include <vlc/vlc.h>
-
-#include "stream_control.h"
-#include "input_ext-intf.h"
-#include "input_ext-dec.h"
-#include "input_ext-plugins.h"
-
-
-/*
- * Buffers management : internal functions
- *
- * All functions are static, but exported versions with mutex protection
- * start with input_*. Not all of these exported functions are actually used,
- * but they are included here for completeness.
- */
-
-#define BUFFERS_CACHE_SIZE 500
-#define DATA_CACHE_SIZE 1000
-#define PES_CACHE_SIZE 1000
-
-/*****************************************************************************
- * data_buffer_t: shared data type
- *****************************************************************************/
-struct data_buffer_t
-{
- data_buffer_t * p_next;
-
- /* number of data packets this buffer is referenced from - when it falls
- * down to 0, the buffer is freed */
- int i_refcount;
-
- /* size of the current buffer (starting right after this byte) */
- size_t i_size;
-};
-
-/*****************************************************************************
- * input_buffers_t: defines a LIFO per data type to keep
- *****************************************************************************/
-#define PACKETS_LIFO( TYPE, NAME ) \
-struct \
-{ \
- TYPE * p_stack; \
- unsigned int i_depth; \
-} NAME;
-
-struct input_buffers_t
-{
- vlc_mutex_t lock;
- PACKETS_LIFO( pes_packet_t, pes )
- PACKETS_LIFO( data_packet_t, data )
- PACKETS_LIFO( data_buffer_t, buffers )
- size_t i_allocated;
-};
-
-
-/*****************************************************************************
- * input_BuffersInit: initialize the cache structures, return a pointer to it
- *****************************************************************************/
-void * __input_BuffersInit( vlc_object_t *p_this )
-{
- input_buffers_t * p_buffers = malloc( sizeof( input_buffers_t ) );
-
- if( p_buffers == NULL )
- {
- return NULL;
- }
-
- memset( p_buffers, 0, sizeof( input_buffers_t ) );
- vlc_mutex_init( p_this, &p_buffers->lock );
-
- return p_buffers;
-}
-
-/*****************************************************************************
- * input_BuffersEnd: free all cached structures
- *****************************************************************************/
-#define BUFFERS_END_PACKETS_LOOP \
- while( p_packet != NULL ) \
- { \
- p_next = p_packet->p_next; \
- free( p_packet ); \
- p_packet = p_next; \
- }
-
-void input_BuffersEnd( input_thread_t * p_input, input_buffers_t * p_buffers )
-{
- if( p_buffers != NULL )
- {
- msg_Dbg( p_input, "pes: %d packets", p_buffers->pes.i_depth );
- msg_Dbg( p_input, "data: %d packets", p_buffers->data.i_depth );
- msg_Dbg( p_input, "buffers: %d packets", p_buffers->buffers.i_depth );
-
- {
- /* Free PES */
- pes_packet_t * p_next, * p_packet = p_buffers->pes.p_stack;
- BUFFERS_END_PACKETS_LOOP;
- }
-
- {
- /* Free data packets */
- data_packet_t * p_next, * p_packet = p_buffers->data.p_stack;
- BUFFERS_END_PACKETS_LOOP;
- }
-
- {
- /* Free buffers */
- data_buffer_t * p_next, * p_buf = p_buffers->buffers.p_stack;
- while( p_buf != NULL )
- {
- p_next = p_buf->p_next;
- p_buffers->i_allocated -= p_buf->i_size;
- free( p_buf );
- p_buf = p_next;
- }
- }
-
- if( p_buffers->i_allocated )
- {
- msg_Warn( p_input, "%u bytes have not been freed, "
- "expect memory leak", p_buffers->i_allocated );
- }
-
- vlc_mutex_destroy( &p_buffers->lock );
- free( p_buffers );
- }
-}
-
-/*****************************************************************************
- * input_NewBuffer: return a pointer to a data buffer of the appropriate size
- *****************************************************************************/
-static inline data_buffer_t * NewBuffer( input_buffers_t * p_buffers,
- size_t i_size )
-{
- data_buffer_t * p_buf;
-
- /* Safety check */
- if( p_buffers->i_allocated > INPUT_MAX_ALLOCATION )
- {
- return NULL;
- }
-
- if( p_buffers->buffers.p_stack != NULL )
- {
- /* Take the buffer from the cache */
- p_buf = p_buffers->buffers.p_stack;
- p_buffers->buffers.p_stack = p_buf->p_next;
- p_buffers->buffers.i_depth--;
-
- /* Reallocate the packet if it is too small or too large */
- if( p_buf->i_size < i_size || p_buf->i_size > 3 * i_size )
- {
- p_buffers->i_allocated -= p_buf->i_size;
- free( p_buf );
- p_buf = malloc( sizeof(input_buffers_t) + i_size );
- if( p_buf == NULL )
- {
- return NULL;
- }
- p_buf->i_size = i_size;
- p_buffers->i_allocated += i_size;
- }
- }
- else
- {
- /* Allocate a new buffer */
- p_buf = malloc( sizeof(input_buffers_t) + i_size );
- if( p_buf == NULL )
- {
- return NULL;
- }
- p_buf->i_size = i_size;
- p_buffers->i_allocated += i_size;
- }
-
- /* Initialize data */
- p_buf->p_next = NULL;
- p_buf->i_refcount = 0;
-
- return p_buf;
-}
-
-data_buffer_t * input_NewBuffer( input_buffers_t * p_buffers, size_t i_size )
-{
- data_buffer_t * p_buf;
-
- vlc_mutex_lock( &p_buffers->lock );
- p_buf = NewBuffer( p_buffers, i_size );
- vlc_mutex_unlock( &p_buffers->lock );
-
- return p_buf;
-}
-
-/*****************************************************************************
- * input_ReleaseBuffer: put a buffer back into the cache
- *****************************************************************************/
-static inline void ReleaseBuffer( input_buffers_t * p_buffers,
- data_buffer_t * p_buf )
-{
- /* Decrement refcount */
- if( --p_buf->i_refcount > 0 )
- {
- return;
- }
-
- if( p_buffers->buffers.i_depth < BUFFERS_CACHE_SIZE )
- {
- /* Cache not full : store the buffer in it */
- p_buf->p_next = p_buffers->buffers.p_stack;
- p_buffers->buffers.p_stack = p_buf;
- p_buffers->buffers.i_depth++;
- }
- else
- {
- p_buffers->i_allocated -= p_buf->i_size;
- free( p_buf );
- }
-}
-
-void input_ReleaseBuffer( input_buffers_t * p_buffers, data_buffer_t * p_buf )
-{
- vlc_mutex_lock( &p_buffers->lock );
- ReleaseBuffer( p_buffers, p_buf );
- vlc_mutex_unlock( &p_buffers->lock );
-}
-
-/*****************************************************************************
- * input_ShareBuffer: allocate a data_packet_t pointing to a given buffer
- *****************************************************************************/
-static inline data_packet_t * ShareBuffer( input_buffers_t * p_buffers,
- data_buffer_t * p_buf )
-{
- data_packet_t * p_data;
-
- if( p_buffers->data.p_stack != NULL )
- {
- /* Take the packet from the cache */
- p_data = p_buffers->data.p_stack;
- p_buffers->data.p_stack = p_data->p_next;
- p_buffers->data.i_depth--;
- }
- else
- {
- /* Allocate a new packet */
- p_data = malloc( sizeof(data_packet_t) );
- if( p_data == NULL )
- {
- return NULL;
- }
- }
-
- p_data->p_buffer = p_buf;
- p_data->p_next = NULL;
- p_data->b_discard_payload = 0;
- p_data->p_payload_start = p_data->p_demux_start
- = (byte_t *)p_buf + sizeof(input_buffers_t);
- p_data->p_payload_end = p_data->p_demux_start + p_buf->i_size;
- p_buf->i_refcount++;
-
- return p_data;
-}
-
-data_packet_t * input_ShareBuffer( input_buffers_t * p_buffers,
- data_buffer_t * p_buf )
-{
- data_packet_t * p_data;
-
- vlc_mutex_lock( &p_buffers->lock );
- p_data = ShareBuffer( p_buffers, p_buf );
- vlc_mutex_unlock( &p_buffers->lock );
-
- return p_data;
-}
-
-/*****************************************************************************
- * input_NewPacket: allocate a packet along with a buffer
- *****************************************************************************/
-static inline data_packet_t * NewPacket( input_buffers_t * p_buffers,
- size_t i_size )
-{
- data_buffer_t * p_buf;
- data_packet_t * p_data;
-
- p_buf = NewBuffer( p_buffers, i_size );
-
- if( p_buf == NULL )
- {
- return NULL;
- }
-
- p_data = ShareBuffer( p_buffers, p_buf );
- if( p_data == NULL )
- {
- ReleaseBuffer( p_buffers, p_buf );
- }
- return p_data;
-}
-
-data_packet_t * input_NewPacket( input_buffers_t * p_buffers, size_t i_size )
-{
- data_packet_t * p_data;
-
- vlc_mutex_lock( &p_buffers->lock );
- p_data = NewPacket( p_buffers, i_size );
- vlc_mutex_unlock( &p_buffers->lock );
-
- return p_data;
-}
-
-/*****************************************************************************
- * input_DeletePacket: deallocate a packet and its buffers
- *****************************************************************************/
-static inline void DeletePacket( input_buffers_t * p_buffers,
- data_packet_t * p_data )
-{
- while( p_data != NULL )
- {
- data_packet_t * p_next = p_data->p_next;
-
- ReleaseBuffer( p_buffers, p_data->p_buffer );
-
- if( p_buffers->data.i_depth < DATA_CACHE_SIZE )
- {
- /* Cache not full : store the packet in it */
- p_data->p_next = p_buffers->data.p_stack;
- p_buffers->data.p_stack = p_data;
- p_buffers->data.i_depth++;
- }
- else
- {
- free( p_data );
- }
-
- p_data = p_next;
- }
-}
-
-void input_DeletePacket( input_buffers_t * p_buffers, data_packet_t * p_data )
-{
- vlc_mutex_lock( &p_buffers->lock );
- DeletePacket( p_buffers, p_data );
- vlc_mutex_unlock( &p_buffers->lock );
-}
-
-/*****************************************************************************
- * input_NewPES: return a pointer to a new PES packet
- *****************************************************************************/
-static inline pes_packet_t * NewPES( input_buffers_t * p_buffers )
-{
- pes_packet_t * p_pes;
-
- if( p_buffers->pes.p_stack != NULL )
- {
- /* Take the packet from the cache */
- p_pes = p_buffers->pes.p_stack;
- p_buffers->pes.p_stack = p_pes->p_next;
- p_buffers->pes.i_depth--;
- }
- else
- {
- /* Allocate a new packet */
- p_pes = malloc( sizeof(pes_packet_t) );
- if( p_pes == NULL )
- {
- return NULL;
- }
- }
-
- p_pes->p_next = NULL;
- p_pes->b_data_alignment = p_pes->b_discontinuity = VLC_FALSE;
- p_pes->i_pts = p_pes->i_dts = 0;
- p_pes->p_first = p_pes->p_last = NULL;
- p_pes->i_pes_size = 0;
- p_pes->i_nb_data = 0;
-
- return p_pes;
-}
-
-pes_packet_t * input_NewPES( input_buffers_t * p_buffers )
-{
- pes_packet_t * p_pes;
-
- vlc_mutex_lock( &p_buffers->lock );
- p_pes = NewPES( p_buffers );
- vlc_mutex_unlock( &p_buffers->lock );
-
- return p_pes;
-}
-
-/*****************************************************************************
- * input_DeletePES: put a pes and all data packets and all buffers back into
- * the cache
- *****************************************************************************/
-static inline void DeletePES( input_buffers_t * p_buffers,
- pes_packet_t * p_pes )
-{
- while( p_pes != NULL )
- {
- pes_packet_t * p_next = p_pes->p_next;
-
- /* Delete all data packets */
- if( p_pes->p_first != NULL )
- {
- DeletePacket( p_buffers, p_pes->p_first );
- }
-
- if( p_buffers->pes.i_depth < PES_CACHE_SIZE )
- {
- /* Cache not full : store the packet in it */
- p_pes->p_next = p_buffers->pes.p_stack;
- p_buffers->pes.p_stack = p_pes;
- p_buffers->pes.i_depth++;
- }
- else
- {
- free( p_pes );
- }
-
- p_pes = p_next;
- }
-}
-
-void input_DeletePES( input_buffers_t * p_buffers, pes_packet_t * p_pes )
-{
- vlc_mutex_lock( &p_buffers->lock );
- DeletePES( p_buffers, p_pes );
- vlc_mutex_unlock( &p_buffers->lock );
-}
-
-
-/*
- * Buffers management : external functions
- *
- * These functions make the glu between the access plug-in (pf_read) and
- * the demux plug-in (pf_demux). We fill in a large buffer (approx. 10s kB)
- * with a call to pf_read, then allow the demux plug-in to have a peep at
- * it (input_Peek), and to split it in data_packet_t (input_SplitBuffer).
- */
-/*****************************************************************************
- * input_FillBuffer: fill in p_data_buffer with data from pf_read
- *****************************************************************************/
-ssize_t input_FillBuffer( input_thread_t * p_input )
-{
- ptrdiff_t i_remains = p_input->p_last_data - p_input->p_current_data;
- data_buffer_t * p_buf = NULL;
- ssize_t i_ret;
-
- vlc_mutex_lock( &p_input->p_method_data->lock );
-
- while( p_buf == NULL )
- {
- p_buf = NewBuffer( p_input->p_method_data,
- i_remains + p_input->i_bufsize );
- if( p_buf == NULL )
- {
- vlc_mutex_unlock( &p_input->p_method_data->lock );
- msg_Err( p_input,
- "failed allocating a new buffer (decoder stuck?)" );
- msleep( INPUT_IDLE_SLEEP );
-
- if( p_input->b_die || p_input->b_error || p_input->b_eof )
- {
- return -1;
- }
- vlc_mutex_lock( &p_input->p_method_data->lock );
- }
- }
-
- p_buf->i_refcount = 1;
-
- if( p_input->p_data_buffer != NULL )
- {
- if( i_remains )
- {
- p_input->p_vlc->pf_memcpy( (byte_t *)p_buf + sizeof(data_buffer_t),
- p_input->p_current_data,
- (size_t)i_remains );
- }
- ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
- }
-
- p_input->p_data_buffer = p_buf;
- p_input->p_current_data = (byte_t *)p_buf + sizeof(data_buffer_t);
- p_input->p_last_data = p_input->p_current_data + i_remains;
-
- /* Do not hold the lock during pf_read (blocking call). */
- vlc_mutex_unlock( &p_input->p_method_data->lock );
-
- i_ret = p_input->pf_read( p_input,
- (byte_t *)p_buf + sizeof(data_buffer_t)
- + i_remains,
- p_input->i_bufsize );
- if( i_ret < 0 && i_remains == 0 )
- {
- /* Our internal buffers are empty, we can signal the error */
- return -1;
- }
-
- if( i_ret < 0 ) i_ret = 0;
-
- p_input->p_last_data += i_ret;
-
- return (ssize_t)i_remains + i_ret;
-}
-
-/*****************************************************************************
- * input_Peek: give a pointer to the next available bytes in the buffer
- * (min. i_size bytes)
- * Returns the number of bytes read, or -1 in case of error
- *****************************************************************************/
-ssize_t input_Peek( input_thread_t * p_input, byte_t ** pp_byte,
- size_t i_size )
-{
- ssize_t i_data = p_input->p_last_data - p_input->p_current_data;
-
- while( i_data < (ssize_t)i_size )
- {
- /* Go to the next buffer */
- ssize_t i_ret = input_FillBuffer( p_input );
-
- if( i_ret < 0 )
- {
- return -1;
- }
-
- if( i_ret == i_data )
- {
- /* We didn't get anymore data, must be the EOF */
- i_size = i_data;
- break;
- }
-
- i_data = i_ret;
- }
-
- *pp_byte = p_input->p_current_data;
- return i_size;
-}
-
-/*****************************************************************************
- * input_SplitBuffer: give a pointer to a data packet containing i_size bytes
- * Returns the number of bytes read, or -1 in case of error
- *****************************************************************************/
-ssize_t input_SplitBuffer( input_thread_t * p_input,
- data_packet_t ** pp_data, size_t i_size )
-{
- ssize_t i_data = p_input->p_last_data - p_input->p_current_data;
-
- while( i_data < (ssize_t)i_size )
- {
- /* Go to the next buffer */
- ssize_t i_ret = input_FillBuffer( p_input );
-
- if( i_ret < 0 )
- {
- return -1;
- }
-
- if( i_ret == i_data )
- {
- /* We didn't get anymore data, must be the EOF */
- i_size = i_data;
- break;
- }
-
- i_data = i_ret;
- }
-
- if( i_size < 0)
- {
- return 0;
- }
-
- *pp_data = input_ShareBuffer( p_input->p_method_data,
- p_input->p_data_buffer );
-
- (*pp_data)->p_demux_start = (*pp_data)->p_payload_start
- = p_input->p_current_data;
- (*pp_data)->p_payload_end = (*pp_data)->p_demux_start + i_size;
-
- p_input->p_current_data += i_size;
-
- /* Update stream position */
- vlc_mutex_lock( &p_input->stream.stream_lock );
- p_input->stream.p_selected_area->i_tell += i_size;
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- return i_size;
-}
-
-/*****************************************************************************
- * input_AccessInit: initialize access plug-in wrapper structures
- *****************************************************************************/
-int input_AccessInit( input_thread_t * p_input )
-{
- p_input->p_method_data = input_BuffersInit( p_input );
- if( p_input->p_method_data == NULL ) return -1;
- p_input->p_data_buffer = NULL;
- p_input->p_current_data = NULL;
- p_input->p_last_data = NULL;
- return 0;
-}
-
-/*****************************************************************************
- * input_AccessReinit: reinit structures before a random seek
- *****************************************************************************/
-void input_AccessReinit( input_thread_t * p_input )
-{
- if( p_input->p_data_buffer != NULL )
- {
- ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
- }
- p_input->p_data_buffer = NULL;
- p_input->p_current_data = NULL;
- p_input->p_last_data = NULL;
-}
-
-/*****************************************************************************
- * input_AccessEnd: free access plug-in wrapper structures
- *****************************************************************************/
-void input_AccessEnd( input_thread_t * p_input )
-{
- if( p_input->p_data_buffer != NULL )
- {
- ReleaseBuffer( p_input->p_method_data, p_input->p_data_buffer );
- }
-
- input_BuffersEnd( p_input, p_input->p_method_data );
-}
-
+++ /dev/null
-/*****************************************************************************
- * input_programs.c: es_descriptor_t, pgrm_descriptor_t management
- *****************************************************************************
- * Copyright (C) 1999-2004 VideoLAN
- * $Id$
- *
- * 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.
- *
- * 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>
-#include <string.h> /* memcpy(), memset() */
-
-#include <vlc/vlc.h>
-
-#include "stream_control.h"
-#include "input_ext-intf.h"
-#include "input_ext-dec.h"
-#include "input_ext-plugins.h"
-
-/*
- * NOTICE : all of these functions expect you to have taken the lock on
- * p_input->stream.lock
- */
-
-/* Navigation callbacks */
-static int ProgramCallback( vlc_object_t *, char const *,
- vlc_value_t, vlc_value_t, void * );
-static int TitleCallback( vlc_object_t *, char const *,
- vlc_value_t, vlc_value_t, void * );
-static int ChapterCallback( vlc_object_t *, char const *,
- vlc_value_t, vlc_value_t, void * );
-static int NavigationCallback( vlc_object_t *, char const *,
- vlc_value_t, vlc_value_t, void * );
-static int ESCallback( vlc_object_t *, char const *,
- vlc_value_t, vlc_value_t, void * );
-
-/*****************************************************************************
- * input_InitStream: init the stream descriptor of the given input
- *****************************************************************************/
-int input_InitStream( input_thread_t * p_input, size_t i_data_len )
-{
- vlc_value_t text,val;
-
- p_input->stream.i_stream_id = 0;
-
- /* initialized to 0 since we don't give the signal to the interface
- * before the end of input initialization */
- p_input->stream.b_changed = 0;
- p_input->stream.pp_es = NULL;
- p_input->stream.pp_selected_es = NULL;
- p_input->stream.p_removed_es = NULL;
- p_input->stream.p_newly_selected_es = NULL;
- p_input->stream.i_pgrm_number = 0;
- p_input->stream.pp_programs = NULL;
- p_input->stream.p_selected_program = NULL;
- p_input->stream.p_new_program = NULL;
-
- if( i_data_len )
- {
- if ( (p_input->stream.p_demux_data = malloc( i_data_len )) == NULL )
- {
- msg_Err( p_input, "out of memory" );
- return 1;
- }
- memset( p_input->stream.p_demux_data, 0, i_data_len );
- }
- else
- {
- p_input->stream.p_demux_data = NULL;
- }
-
- var_Create( p_input, "intf-change", VLC_VAR_BOOL );
- val.b_bool = VLC_TRUE;
- var_Set( p_input, "intf-change", val );
-
- /* Create a few object variables used for navigation in the interfaces */
- var_Create( p_input, "program", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE |
- VLC_VAR_DOINHERIT );
- var_Get( p_input, "program", &val );
- if( val.i_int <= 0 )
- var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
- text.psz_string = _("Program");
- var_Change( p_input, "program", VLC_VAR_SETTEXT, &text, NULL );
-
- var_Create( p_input, "title", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
- text.psz_string = _("Title");
- var_Change( p_input, "title", VLC_VAR_SETTEXT, &text, NULL );
-
- var_Create( p_input, "chapter", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
- text.psz_string = _("Chapter");
- var_Change( p_input, "chapter", VLC_VAR_SETTEXT, &text, NULL );
-
- var_Create( p_input, "navigation", VLC_VAR_VARIABLE | VLC_VAR_HASCHOICE );
- text.psz_string = _("Navigation");
- var_Change( p_input, "navigation", VLC_VAR_SETTEXT, &text, NULL );
-
- var_Create( p_input, "video-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
- text.psz_string = _("Video Track");
- var_Change( p_input, "video-es", VLC_VAR_SETTEXT, &text, NULL );
- var_Create( p_input, "audio-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
- text.psz_string = _("Audio Track");
- var_Change( p_input, "audio-es", VLC_VAR_SETTEXT, &text, NULL );
- var_Create( p_input, "spu-es", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE );
- text.psz_string = _("Subtitles Track");
- var_Change( p_input, "spu-es", VLC_VAR_SETTEXT, &text, NULL );
-
- var_AddCallback( p_input, "program", ProgramCallback, NULL );
- var_AddCallback( p_input, "title", TitleCallback, NULL );
- var_AddCallback( p_input, "chapter", ChapterCallback, NULL );
- var_AddCallback( p_input, "video-es", ESCallback, NULL );
- var_AddCallback( p_input, "audio-es", ESCallback, NULL );
- var_AddCallback( p_input, "spu-es", ESCallback, NULL );
-
- return VLC_SUCCESS;
-}
-
-/*****************************************************************************
- * input_EndStream: free all stream descriptors
- *****************************************************************************/
-void input_EndStream( input_thread_t * p_input )
-{
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- /* Free all programs and associated ES, and associated decoders. */
- while( p_input->stream.i_pgrm_number )
- {
- input_DelProgram( p_input, p_input->stream.pp_programs[0] );
- }
-
- /* Free standalone ES */
- while( p_input->stream.i_es_number )
- {
- input_DelES( p_input, p_input->stream.pp_es[0] );
- }
-
- /* Free all areas */
- while( p_input->stream.i_area_nb )
- {
- input_DelArea( p_input, p_input->stream.pp_areas[0] );
- }
-
- /* Free selected ES */
- if( p_input->stream.pp_selected_es != NULL )
- {
- free( p_input->stream.pp_selected_es );
- }
-
- if( p_input->stream.p_demux_data != NULL )
- {
- free( p_input->stream.p_demux_data );
- }
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- /* Free navigation variables */
- var_Destroy( p_input, "program" );
- var_Destroy( p_input, "title" );
- var_Destroy( p_input, "chapter" );
- var_Destroy( p_input, "video-es" );
- var_Destroy( p_input, "audio-es" );
- var_Destroy( p_input, "spu-es" );
- var_Destroy( p_input, "intf-change" );
-}
-
-/*****************************************************************************
- * input_FindProgram: returns a pointer to a program described by its ID
- *****************************************************************************/
-pgrm_descriptor_t * input_FindProgram( input_thread_t * p_input,
- uint16_t i_pgrm_id )
-{
- unsigned int i;
-
- for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
- {
- if( p_input->stream.pp_programs[i]->i_number == i_pgrm_id )
- {
- return p_input->stream.pp_programs[i];
- }
- }
-
- return NULL;
-}
-
-/*****************************************************************************
- * input_AddProgram: add and init a program descriptor
- *****************************************************************************
- * This program descriptor will be referenced in the given stream descriptor
- *****************************************************************************/
-pgrm_descriptor_t * input_AddProgram( input_thread_t * p_input,
- uint16_t i_pgrm_id, size_t i_data_len )
-{
- /* Where to add the pgrm */
- pgrm_descriptor_t * p_pgrm = malloc( sizeof(pgrm_descriptor_t) );
- vlc_value_t val;
-
- if( p_pgrm == NULL )
- {
- msg_Err( p_input, "out of memory" );
- return NULL;
- }
-
- /* Init this entry */
- p_pgrm->i_number = i_pgrm_id;
- p_pgrm->b_is_ok = 0;
- p_pgrm->i_version = 0;
-
- p_pgrm->i_es_number = 0;
- p_pgrm->pp_es = NULL;
-
- input_ClockInit( p_pgrm );
-
- p_pgrm->i_synchro_state = SYNCHRO_START;
-
- if( i_data_len )
- {
- p_pgrm->p_demux_data = malloc( i_data_len );
- if( p_pgrm->p_demux_data == NULL )
- {
- msg_Err( p_input, "out of memory" );
- return NULL;
- }
- memset( p_pgrm->p_demux_data, 0, i_data_len );
- }
- else
- {
- p_pgrm->p_demux_data = NULL;
- }
-
- /* Add an entry to the list of program associated with the stream */
- INSERT_ELEM( p_input->stream.pp_programs,
- p_input->stream.i_pgrm_number,
- p_input->stream.i_pgrm_number,
- p_pgrm );
-
- val.i_int = i_pgrm_id;
- var_Change( p_input, "program", VLC_VAR_ADDCHOICE, &val, NULL );
-
- return p_pgrm;
-}
-
-/*****************************************************************************
- * input_DelProgram: destroy a program descriptor
- *****************************************************************************
- * All ES descriptions referenced in the descriptor will be deleted.
- *****************************************************************************/
-void input_DelProgram( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm )
-{
- unsigned int i_pgrm_index;
- vlc_value_t val;
-
- /* Find the program in the programs table */
- for( i_pgrm_index = 0; i_pgrm_index < p_input->stream.i_pgrm_number;
- i_pgrm_index++ )
- {
- if( p_input->stream.pp_programs[i_pgrm_index] == p_pgrm )
- break;
- }
-
- /* If the program wasn't found, do nothing */
- if( i_pgrm_index == p_input->stream.i_pgrm_number )
- {
- msg_Err( p_input, "program does not belong to this input" );
- return;
- }
-
- val.i_int = p_input->stream.pp_programs[i_pgrm_index]->i_number;
- var_Change( p_input, "program", VLC_VAR_DELCHOICE, &val, NULL );
-
- /* Free the structures that describe the es that belongs to that program */
- while( p_pgrm->i_es_number )
- {
- input_DelES( p_input, p_pgrm->pp_es[0] );
- }
-
- /* Free the demux data */
- if( p_pgrm->p_demux_data != NULL )
- {
- free( p_pgrm->p_demux_data );
- }
-
- /* Remove this program from the stream's list of programs */
- REMOVE_ELEM( p_input->stream.pp_programs,
- p_input->stream.i_pgrm_number,
- i_pgrm_index );
-
- if( p_pgrm == p_input->stream.p_selected_program )
- p_input->stream.p_selected_program = NULL;
-
- /* Free the description of this program */
- free( p_pgrm );
-}
-
-/****************************************************************************
- * input_ChangeProgram: interface request a program change (internal)
- ****************************************************************************/
-static int input_ChangeProgram( input_thread_t * p_input, uint16_t i_program_number )
-{
- pgrm_descriptor_t * p_program;
- vlc_value_t val;
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- p_program = input_FindProgram( p_input, i_program_number );
-
- if ( p_program == NULL )
- {
- msg_Err( p_input, "could not find selected program" );
- return -1;
- }
-
- p_input->stream.p_new_program = p_program;
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- /* Update the navigation variables without triggering a callback */
- val.i_int = i_program_number;
- var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
-
- return 0;
-}
-
-/*****************************************************************************
- * input_AddArea: add and init an area descriptor
- *****************************************************************************
- * This area descriptor will be referenced in the given stream descriptor
- *****************************************************************************/
-input_area_t * input_AddArea( input_thread_t * p_input,
- uint16_t i_area_id, uint16_t i_part_nb )
-{
- /* Where to add the pgrm */
- input_area_t * p_area = malloc( sizeof(input_area_t) );
- vlc_value_t val;
- int i;
-
- if( p_area == NULL )
- {
- msg_Err( p_input, "out of memory" );
- return NULL;
- }
-
- /* Init this entry */
- p_area->i_id = i_area_id;
- p_area->i_part_nb = i_part_nb;
- p_area->i_part= 0;
- p_area->i_start = 0;
- p_area->i_size = 0;
- p_area->i_tell = 0;
- p_area->i_seek = NO_SEEK;
-
- /* Add an entry to the list of program associated with the stream */
- INSERT_ELEM( p_input->stream.pp_areas,
- p_input->stream.i_area_nb,
- p_input->stream.i_area_nb,
- p_area );
-
- /* Don't add empty areas */
- if( i_part_nb == 0 )
- return NULL;
-
- /* Take care of the navigation variables */
- val.i_int = i_area_id;
- var_Change( p_input, "title", VLC_VAR_ADDCHOICE, &val, NULL );
-
- val.psz_string = malloc( sizeof("title ") + 5 );
- if( val.psz_string )
- {
- vlc_value_t val2, text, text2;
-
- sprintf( val.psz_string, "title %2i", i_area_id );
- var_Destroy( p_input, val.psz_string );
- var_Create( p_input, val.psz_string, VLC_VAR_INTEGER |
- VLC_VAR_HASCHOICE | VLC_VAR_ISCOMMAND );
- var_AddCallback( p_input, val.psz_string, NavigationCallback,
- (void *)(int)i_area_id );
-
- text.psz_string = malloc( strlen( _("Title %i") ) + 20 );
- if( text.psz_string )
- sprintf( text.psz_string, _("Title %i"), i_area_id );
-
- var_Change( p_input, "navigation", VLC_VAR_ADDCHOICE, &val, &text );
-
- if( text.psz_string ) free( text.psz_string );
-
- text2.psz_string = malloc( strlen( _("Chapter %i") ) + 20 );
-
- for( i = 1; i <= i_part_nb; i++ )
- {
- val2.i_int = i;
-
- if( text2.psz_string )
- sprintf( text2.psz_string, _("Chapter %i"), i );
-
- var_Change( p_input, val.psz_string,
- VLC_VAR_ADDCHOICE, &val2, &text2 );
- }
-
- if( text2.psz_string ) free( text2.psz_string );
- free( val.psz_string );
- }
-
- if( p_input->stream.i_area_nb == 2 )
- {
- vlc_value_t text;
-
- /* Add another bunch of navigation object variables */
- var_Create( p_input, "next-title", VLC_VAR_VOID );
- text.psz_string = _("Next title");
- var_Change( p_input, "next-title", VLC_VAR_SETTEXT, &text, NULL );
- var_Create( p_input, "prev-title", VLC_VAR_VOID );
- text.psz_string = _("Previous title");
- var_Change( p_input, "prev-title", VLC_VAR_SETTEXT, &text, NULL );
- var_AddCallback( p_input, "next-title", TitleCallback, NULL );
- var_AddCallback( p_input, "prev-title", TitleCallback, NULL );
-
- var_Create( p_input, "next-chapter", VLC_VAR_VOID );
- text.psz_string = _("Next chapter");
- var_Change( p_input, "next-chapter", VLC_VAR_SETTEXT, &text, NULL );
- var_Create( p_input, "prev-chapter", VLC_VAR_VOID );
- text.psz_string = _("Previous chapter");
- var_Change( p_input, "prev-chapter", VLC_VAR_SETTEXT, &text, NULL );
- var_AddCallback( p_input, "next-chapter", ChapterCallback, NULL );
- var_AddCallback( p_input, "prev-chapter", ChapterCallback, NULL );
- }
-
- return p_area;
-}
-
-/*****************************************************************************
- * input_SetProgram: changes the current program
- *****************************************************************************/
-int input_SetProgram( input_thread_t * p_input, pgrm_descriptor_t * p_new_prg )
-{
- unsigned int i_es_index;
- int i_required_audio_es;
- int i_required_spu_es;
- int i_audio_es = 0;
- int i_spu_es = 0;
- vlc_value_t val;
-
- if ( p_input->stream.p_selected_program )
- {
- for ( i_es_index = 1 ; /* 0 should be the PMT */
- i_es_index < p_input->stream.p_selected_program->
- i_es_number ;
- i_es_index ++ )
- {
-#define p_es p_input->stream.p_selected_program->pp_es[i_es_index]
- if ( p_es->p_dec ) /* if the ES was selected */
- {
- input_UnselectES( p_input , p_es );
- }
-#undef p_es
- }
- }
-
- /* Get the number of the required audio stream */
- var_Get( p_input, "audio", &val );
- if( val.b_bool )
- {
- /* Default is the first one */
- var_Get( p_input, "audio-channel", &val );
- i_required_audio_es = val.i_int;
- if( i_required_audio_es < 0 )
- {
- i_required_audio_es = 1;
- }
- }
- else
- {
- i_required_audio_es = 0;
- }
-
- /* Same thing for subtitles */
- var_Get( p_input, "video", &val );
- if( val.b_bool )
- {
- /* for spu, default is none */
- var_Get( p_input, "spu-channel", &val );
- i_required_spu_es = val.i_int;
- if( i_required_spu_es < 0 )
- {
- i_required_spu_es = 0;
- }
- }
- else
- {
- i_required_spu_es = 0;
- }
-
- for( i_es_index = 0 ; i_es_index < p_new_prg->i_es_number ; i_es_index ++ )
- {
- switch( p_new_prg->pp_es[i_es_index]->i_cat )
- {
- case VIDEO_ES:
- msg_Dbg( p_input, "selecting video ES %x",
- p_new_prg->pp_es[i_es_index]->i_id );
- input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
- break;
- case AUDIO_ES:
- i_audio_es += 1;
- if( i_audio_es <= i_required_audio_es )
- {
- msg_Dbg( p_input, "selecting audio ES %x",
- p_new_prg->pp_es[i_es_index]->i_id );
- input_SelectES( p_input, p_new_prg->pp_es[i_es_index]);
- }
- break;
- /* Not sure this one is fully specification-compliant */
- case SPU_ES :
- i_spu_es += 1;
- if( i_spu_es <= i_required_spu_es )
- {
- msg_Dbg( p_input, "selecting spu ES %x",
- p_new_prg->pp_es[i_es_index]->i_id );
- input_SelectES( p_input, p_new_prg->pp_es[i_es_index] );
- }
- break;
- default :
- msg_Dbg( p_input, "ES %x has unknown type",
- p_new_prg->pp_es[i_es_index]->i_id );
- break;
- }
-
- }
-
- p_input->stream.p_selected_program = p_new_prg;
-
- /* Update the navigation variables without triggering a callback */
- val.i_int = p_new_prg->i_number;
- var_Change( p_input, "program", VLC_VAR_SETVALUE, &val, NULL );
-
- return( 0 );
-}
-
-/*****************************************************************************
- * input_DelArea: destroy a area descriptor
- *****************************************************************************
- * All ES descriptions referenced in the descriptor will be deleted.
- *****************************************************************************/
-void input_DelArea( input_thread_t * p_input, input_area_t * p_area )
-{
- unsigned int i_area_index;
- vlc_value_t val;
-
- /* Find the area in the areas table */
- for( i_area_index = 0; i_area_index < p_input->stream.i_area_nb;
- i_area_index++ )
- {
- if( p_input->stream.pp_areas[i_area_index] == p_area )
- break;
- }
-
- /* If the area wasn't found, do nothing */
- if( i_area_index == p_input->stream.i_area_nb )
- {
- msg_Err( p_input, "area does not belong to this input" );
- return;
- }
-
- /* Take care of the navigation variables */
- val.psz_string = malloc( sizeof("title ") + 5 );
- if( val.psz_string )
- {
- sprintf( val.psz_string, "title %i", p_area->i_id );
- var_Change( p_input, "navigation", VLC_VAR_DELCHOICE, &val, NULL );
- var_Destroy( p_input, val.psz_string );
-
- free( val.psz_string );
- }
-
- /* Remove this area from the stream's list of areas */
- REMOVE_ELEM( p_input->stream.pp_areas,
- p_input->stream.i_area_nb,
- i_area_index );
-
- /* Free the description of this area */
- free( p_area );
-
- if( p_input->stream.i_area_nb == 1 )
- {
- /* Del unneeded navigation object variables */
- var_Destroy( p_input, "next-title" );
- var_Destroy( p_input, "prev-title" );
- var_Destroy( p_input, "next-chapter" );
- var_Destroy( p_input, "prev-chapter" );
- }
-}
-
-/****************************************************************************
- * input_ChangeArea: interface request an area change (internal)
- ****************************************************************************/
-static int input_ChangeArea( input_thread_t * p_input, input_area_t * p_area )
-{
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- p_input->stream.p_new_area = p_area;
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- return 0;
-}
-
-/*****************************************************************************
- * input_FindES: returns a pointer to an ES described by its ID
- *****************************************************************************/
-es_descriptor_t * input_FindES( input_thread_t * p_input, uint16_t i_es_id )
-{
- unsigned int i;
-
- for( i = 0; i < p_input->stream.i_es_number; i++ )
- {
- if( p_input->stream.pp_es[i]->i_id == i_es_id )
- {
- return p_input->stream.pp_es[i];
- }
- }
-
- return NULL;
-}
-
-/*****************************************************************************
- * input_AddES:
- *****************************************************************************
- * Reserve a slot in the table of ES descriptors for the ES and add it to the
- * list of ES of p_pgrm. If p_pgrm if NULL, then the ES is considered as stand
- * alone (PSI ?)
- *****************************************************************************/
-es_descriptor_t * input_AddES( input_thread_t * p_input,
- pgrm_descriptor_t * p_pgrm, uint16_t i_es_id,
- int i_category, char const *psz_desc,
- size_t i_data_len )
-{
- es_descriptor_t * p_es;
- vlc_value_t val, text;
- char *psz_var = NULL;
-
- p_es = (es_descriptor_t *)malloc( sizeof(es_descriptor_t) );
- if( p_es == NULL )
- {
- msg_Err( p_input, "out of memory" );
- return( NULL);
- }
-
- INSERT_ELEM( p_input->stream.pp_es,
- p_input->stream.i_es_number,
- p_input->stream.i_es_number,
- p_es );
-
- /* Init its values */
- p_es->i_id = i_es_id;
- p_es->i_stream_id = 0;
- p_es->p_pes = NULL;
- p_es->p_dec = NULL;
- p_es->i_cat = i_category;
- p_es->i_demux_fd = 0;
- p_es->c_packets = 0;
- p_es->c_invalid_packets = 0;
- p_es->b_force_decoder = VLC_FALSE;
- es_format_Init( &p_es->fmt, UNKNOWN_ES, 0 );
- p_es->fmt.b_packetized = VLC_FALSE; /* Only there for old mpeg demuxers */
-
- if( i_data_len )
- {
- p_es->p_demux_data = malloc( i_data_len );
- if( p_es->p_demux_data == NULL )
- {
- msg_Err( p_input, "out of memory" );
- return( NULL );
- }
- memset( p_es->p_demux_data, 0, i_data_len );
- }
- else
- {
- p_es->p_demux_data = NULL;
- }
- p_es->p_waveformatex = NULL;
- p_es->p_bitmapinfoheader = NULL;
- p_es->p_spuinfo = NULL;
-
- /* Add this ES to the program definition if one is given */
- if( p_pgrm )
- {
- INSERT_ELEM( p_pgrm->pp_es,
- p_pgrm->i_es_number,
- p_pgrm->i_es_number,
- p_es );
- p_es->p_pgrm = p_pgrm;
- }
- else
- {
- p_es->p_pgrm = NULL;
- }
-
- switch( i_category )
- {
- case AUDIO_ES:
- psz_var = "audio-es";
- break;
- case SPU_ES:
- psz_var = "spu-es";
- break;
- case VIDEO_ES:
- psz_var = "video-es";
- break;
- }
-
- if( psz_var )
- {
- /* Get the number of ES already added */
- var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
- if( val.i_int == 0 )
- {
- vlc_value_t val2;
-
- /* First one, we need to add the "Disable" choice */
- val2.i_int = -1; text.psz_string = _("Disable");
- var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val2, &text );
- val.i_int++;
- }
-
- /* Take care of the ES description */
- if( psz_desc && *psz_desc )
- {
- p_es->psz_desc = strdup( psz_desc );
- }
- else
- {
- p_es->psz_desc = malloc( strlen( _("Track %i") ) + 20 );
- if( p_es->psz_desc )
- sprintf( p_es->psz_desc, _("Track %i"), val.i_int );
- }
-
- val.i_int = p_es->i_id;
- text.psz_string = p_es->psz_desc;
- var_Change( p_input, psz_var, VLC_VAR_ADDCHOICE, &val, &text );
- }
- else p_es->psz_desc = NULL;
-
- return p_es;
-}
-
-/*****************************************************************************
- * input_DelES:
- *****************************************************************************/
-void input_DelES( input_thread_t * p_input, es_descriptor_t * p_es )
-{
- unsigned int i_index, i_es_index;
- pgrm_descriptor_t * p_pgrm;
- char * psz_var = NULL;
- vlc_value_t val;
-
- /* Find the ES in the ES table */
- for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
- i_es_index++ )
- {
- if( p_input->stream.pp_es[i_es_index] == p_es )
- break;
- }
-
- /* If the ES wasn't found, do nothing */
- if( i_es_index == p_input->stream.i_es_number )
- {
- msg_Err( p_input, "ES does not belong to this input" );
- return;
- }
-
- /* Remove es from its associated variable */
- switch( p_es->i_cat )
- {
- case AUDIO_ES:
- psz_var = "audio-es";
- break;
- case SPU_ES:
- psz_var = "spu-es";
- break;
- case VIDEO_ES:
- psz_var = "video-es";
- break;
- }
-
- if( psz_var )
- {
- val.i_int = p_es->i_id;
- var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
-
- /* Remove the "Disable" entry if needed */
- var_Change( p_input, psz_var, VLC_VAR_CHOICESCOUNT, &val, NULL );
- if( val.i_int == 1 )
- {
- val.i_int = -1;
- var_Change( p_input, psz_var, VLC_VAR_DELCHOICE, &val, NULL );
- }
- }
-
- /* Kill associated decoder, if any. */
- if( p_es->p_dec != NULL )
- {
- input_UnselectES( p_input, p_es );
- }
-
- /* Remove this ES from the description of the program if it is associated
- * to one */
- p_pgrm = p_es->p_pgrm;
- if( p_pgrm )
- {
- for( i_index = 0; i_index < p_pgrm->i_es_number; i_index++ )
- {
- if( p_pgrm->pp_es[i_index] == p_es )
- {
- REMOVE_ELEM( p_pgrm->pp_es,
- p_pgrm->i_es_number,
- i_index );
- break;
- }
- }
- }
-
- /* Free the demux data */
- if( p_es->p_demux_data != NULL )
- {
- free( p_es->p_demux_data );
- }
- if( p_es->p_waveformatex )
- {
- free( p_es->p_waveformatex );
- }
- if( p_es->p_bitmapinfoheader )
- {
- free( p_es->p_bitmapinfoheader );
- }
- if( p_es->p_spuinfo )
- {
- free( p_es->p_spuinfo );
- }
-
- /* Free the description string */
- if( p_es->psz_desc != NULL )
- {
- free( p_es->psz_desc );
- }
-
- /* Clean the es format */
- es_format_Clean( &p_es->fmt );
-
- /* Find the ES in the ES table */
- for( i_es_index = 0; i_es_index < p_input->stream.i_es_number;
- i_es_index++ )
- {
- if( p_input->stream.pp_es[i_es_index] == p_es )
- break;
- }
-
- /* Remove this ES from the stream's list of ES */
- REMOVE_ELEM( p_input->stream.pp_es,
- p_input->stream.i_es_number,
- i_es_index );
-
- /* Free the ES */
- free( p_es );
-}
-
-/*****************************************************************************
- * input_SelectES: selects an ES and spawns the associated decoder
- *****************************************************************************
- * Remember we are still supposed to have stream_lock when entering this
- * function ?
- *****************************************************************************/
-int input_SelectES( input_thread_t * p_input, es_descriptor_t * p_es )
-{
- vlc_value_t val;
- char *psz_var = NULL;
-
- if( p_es == NULL )
- {
- msg_Err( p_input, "nothing to do in input_SelectES" );
- return -1;
- }
-
- if( p_es->i_cat == VIDEO_ES || p_es->i_cat == SPU_ES )
- {
- var_Get( p_input, "video", &val );
- if( val.b_bool && p_input->stream.p_sout )
- {
- var_Get( p_input, "sout-video", &val );
- }
- if( !val.b_bool )
- {
- msg_Dbg( p_input, "video is disabled, not selecting ES 0x%x",
- p_es->i_id );
- return -1;
- }
- }
-
- if( p_es->i_cat == AUDIO_ES )
- {
- var_Get( p_input, "audio", &val );
- if( val.b_bool && p_input->stream.p_sout )
- {
- var_Get( p_input, "sout-audio", &val );
- }
- if( !val.b_bool )
- {
- msg_Dbg( p_input, "audio is disabled, not selecting ES 0x%x",
- p_es->i_id );
- return -1;
- }
- }
-
- msg_Dbg( p_input, "selecting ES 0x%x", p_es->i_id );
-
- if( p_es->p_dec != NULL )
- {
- msg_Err( p_input, "ES 0x%x is already selected", p_es->i_id );
- return -1;
- }
-
- /* Release the lock, not to block the input thread during
- * the creation of the thread. */
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- p_es->p_dec = input_RunDecoder( p_input, p_es );
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- if( p_es->p_dec == NULL )
- {
- return -1;
- }
-
- /* Update the es variable without triggering a callback */
- switch( p_es->i_cat )
- {
- case AUDIO_ES:
- psz_var = "audio-es";
- break;
- case SPU_ES:
- psz_var = "spu-es";
- break;
- case VIDEO_ES:
- psz_var = "video-es";
- break;
- }
-
- if( psz_var )
- {
- val.i_int = p_es->i_id;
- var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
- }
-
- return 0;
-}
-
-/*****************************************************************************
- * input_UnselectES: removes an ES from the list of selected ES
- *****************************************************************************/
-int input_UnselectES( input_thread_t * p_input, es_descriptor_t * p_es )
-{
- unsigned int i_index = 0;
- vlc_value_t val;
- char *psz_var = NULL;
-
- if( p_es == NULL )
- {
- msg_Err( p_input, "nothing to do in input_UnselectES" );
- return -1;
- }
-
- msg_Dbg( p_input, "unselecting ES 0x%x", p_es->i_id );
-
- if( p_es->p_dec == NULL )
- {
- msg_Err( p_input, "ES 0x%x is not selected", p_es->i_id );
- return( -1 );
- }
-
- /* Update the es variable without triggering a callback */
- switch( p_es->i_cat )
- {
- case AUDIO_ES:
- psz_var = "audio-es";
- break;
- case SPU_ES:
- psz_var = "spu-es";
- break;
- case VIDEO_ES:
- psz_var = "video-es";
- break;
- }
-
- if( psz_var )
- {
- val.i_int = -1;
- var_Change( p_input, psz_var, VLC_VAR_SETVALUE, &val, NULL );
- }
-
- /* FIXME: input_UnselectES() shouldn't actually be entered with the
- * input lock, the locking should be done here and only where necessary. */
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- /* Actually unselect the ES */
- input_EndDecoder( p_input, p_es );
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- p_es->p_pes = NULL;
-
- if( ( p_es->p_dec == NULL ) &&
- ( p_input->stream.i_selected_es_number > 0 ) )
- {
- while( ( i_index < p_input->stream.i_selected_es_number - 1 ) &&
- ( p_input->stream.pp_selected_es[i_index] != p_es ) )
- {
- i_index++;
- }
-
- /* XXX: no need to memmove, we have unsorted data */
- REMOVE_ELEM( p_input->stream.pp_selected_es,
- p_input->stream.i_selected_es_number,
- i_index );
-
- if( p_input->stream.i_selected_es_number == 0 )
- {
- msg_Dbg( p_input, "no more selected ES" );
- return 1;
- }
- }
-
- return 0;
-}
-
-/*****************************************************************************
- * Navigation callback: a bunch of navigation variables are used as an
- * alternative to the navigation API.
- *****************************************************************************/
-static int ProgramCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
- input_thread_t *p_input = (input_thread_t *)p_this;
- vlc_value_t val;
-
- if( oldval.i_int == newval.i_int )
- return VLC_SUCCESS;
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
- if( ( newval.i_int > 0 ) )
- {
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- input_ChangeProgram( p_input, (uint16_t)newval.i_int );
- var_SetInteger( p_input, "state", PLAYING_S );
- vlc_mutex_lock( &p_input->stream.stream_lock );
- }
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- val.b_bool = VLC_TRUE;
- var_Set( p_input, "intf-change", val );
-
- return VLC_SUCCESS;
-}
-
-static int TitleCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
- input_thread_t *p_input = (input_thread_t *)p_this;
- input_area_t *p_area;
- vlc_value_t val, val_list;
- int i, i_step = 0;
-
- if( !strcmp( psz_cmd, "next-title" ) ) i_step++;
- else if( !strcmp( psz_cmd, "prev-title" ) ) i_step--;
-
- if( !i_step && oldval.i_int == newval.i_int ) return VLC_SUCCESS;
-
- /* Sanity check should have already been done by var_Set(). */
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- if( i_step )
- {
- var_Get( p_this, "title", &newval );
- var_Change( p_this, "title", VLC_VAR_GETCHOICES, &val_list, NULL );
- for( i = 0; i < val_list.p_list->i_count; i++ )
- {
- if( val_list.p_list->p_values[i].i_int == newval.i_int &&
- i + i_step >= 0 && i + i_step < val_list.p_list->i_count )
- {
- newval.i_int = val_list.p_list->p_values[i + i_step].i_int;
- break;
- }
- }
- var_Change( p_this, "title", VLC_VAR_FREELIST, &val_list, NULL );
- }
-
- p_area = p_input->stream.pp_areas[newval.i_int];
- p_area->i_part = 1;
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- input_ChangeArea( p_input, p_area );
- var_SetInteger( p_input, "state", PLAYING_S );
-
- val.b_bool = VLC_TRUE;
- var_Set( p_input, "intf-change", val );
-
- return VLC_SUCCESS;
-}
-
-static int ChapterCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
- input_thread_t *p_input = (input_thread_t *)p_this;
- input_area_t *p_area;
- vlc_value_t val, val_list;
- int i, i_step = 0;
-
- if( !strcmp( psz_cmd, "next-chapter" ) ) i_step++;
- else if( !strcmp( psz_cmd, "prev-chapter" ) ) i_step--;
-
- if( !i_step && oldval.i_int == newval.i_int ) return VLC_SUCCESS;
-
- /* Sanity check should have already been done by var_Set(). */
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- if( i_step )
- {
- var_Get( p_this, "chapter", &newval );
- var_Change( p_this, "chapter", VLC_VAR_GETCHOICES, &val_list, NULL );
- for( i = 0; i < val_list.p_list->i_count; i++ )
- {
- if( val_list.p_list->p_values[i].i_int == newval.i_int &&
- i + i_step >= 0 && i + i_step < val_list.p_list->i_count )
- {
- newval.i_int = val_list.p_list->p_values[i + i_step].i_int;
- break;
- }
- }
- var_Change( p_this, "chapter", VLC_VAR_FREELIST, &val_list, NULL );
- }
-
- p_area = p_input->stream.p_selected_area;
- p_input->stream.p_selected_area->i_part = newval.i_int;
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- input_ChangeArea( p_input, p_area );
- var_SetInteger( p_input, "state", PLAYING_S );
-
- val.b_bool = VLC_TRUE;
- var_Set( p_input, "intf-change", val );
-
- return VLC_SUCCESS;
-}
-
-static int NavigationCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
- input_thread_t *p_input = (input_thread_t *)p_this;
- uint16_t i_area_id = (int)p_data;
- vlc_value_t val;
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- if( p_input->stream.p_selected_area->i_id == i_area_id &&
- oldval.i_int == newval.i_int )
- {
- /* Nothing to do */
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- return VLC_SUCCESS;
- }
-
- if( ( i_area_id < p_input->stream.i_area_nb ) && ( newval.i_int > 0 ) &&
- ( (uint16_t)newval.i_int <=
- p_input->stream.pp_areas[i_area_id]->i_part_nb ) )
- {
- input_area_t *p_area = p_input->stream.pp_areas[i_area_id];
- p_area->i_part = newval.i_int;
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- input_ChangeArea( p_input, p_area );
- var_SetInteger( p_input, "state", PLAYING_S );
- vlc_mutex_lock( &p_input->stream.stream_lock );
- }
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- val.b_bool = VLC_TRUE;
- var_Set( p_input, "intf-change", val );
-
- return VLC_SUCCESS;
-}
-
-static int ESCallback( vlc_object_t *p_this, char const *psz_cmd,
- vlc_value_t oldval, vlc_value_t newval, void *p_data )
-{
- input_thread_t *p_input = (input_thread_t *)p_this;
- unsigned int i;
- vlc_value_t val;
- unsigned int i_cat = UNKNOWN_ES;
- es_descriptor_t *p_es = NULL;
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
-
- /* First search old es type */
- for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
- {
- if( p_input->stream.pp_es[i]->i_id == oldval.i_int )
- {
- i_cat = p_input->stream.pp_es[i]->i_cat;
- }
- }
-
- /* Unselect all old ES */
- for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
- {
- if( p_input->stream.pp_es[i]->i_cat == i_cat &&
- p_input->stream.pp_es[i]->i_id != newval.i_int &&
- p_input->stream.pp_es[i]->p_dec != NULL )
- {
- input_UnselectES( p_input, p_input->stream.pp_es[i] );
- }
- }
-
- /* Select new ES */
- for( i = 0 ; i < p_input->stream.i_es_number ; i++ )
- {
- if( p_input->stream.pp_es[i]->i_id == newval.i_int )
- {
- p_es = p_input->stream.pp_es[i];
- if( p_es->p_dec == NULL )
- {
- input_SelectES( p_input, p_es );
- }
- }
- }
-
- if( p_es )
- {
- /* Fix value (mainly for multiple selected ES */
- val.i_int = p_es->i_id;
- switch( p_es->i_cat )
- {
- case AUDIO_ES:
- var_Change( p_input, "audio-es", VLC_VAR_SETVALUE, &val, NULL );
- break;
- case SPU_ES:
- var_Change( p_input, "spu-es", VLC_VAR_SETVALUE, &val, NULL );
- break;
- case VIDEO_ES:
- var_Change( p_input, "video-es", VLC_VAR_SETVALUE, &val, NULL );
- break;
- }
- }
-
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- val.b_bool = VLC_TRUE;
- var_Set( p_input, "intf-change", val );
-
- return VLC_SUCCESS;
-}
#include <vlc/vlc.h>
#include <vlc/input.h>
-#include "ninput.h"
+#include "input_internal.h"
-/****************************************************************************
- * stream_ReadLine:
- ****************************************************************************/
-/**
- * Read from the stream untill first newline.
- * \param s Stream handle to read from
- * \return A null-terminated string. This must be freed,
+/* TODO:
+ * - tune the 2 methods
+ * - compute cost for seek
+ * - improve stream mode seeking with closest segments
+ * - ...
*/
-/* FIXME don't use stupid MAX_LINE -> do the same than net_ReadLine */
-#define MAX_LINE 1024
-char *stream_ReadLine( stream_t *s )
+
+/* Two methods:
+ * - using pf_block
+ * One linked list of data read
+ * - using pf_read
+ * More complex scheme using mutliple track to avoid seeking
+ */
+
+/* How many track we have, currently only used for stream mode */
+#define STREAM_CACHE_TRACK 3
+/* Max size of our cache 4Mo per track */
+#define STREAM_CACHE_SIZE (4*STREAM_CACHE_TRACK*1024*1024)
+ /* How many data we try to prebuffer */
+#define STREAM_CACHE_PREBUFFER_SIZE (32767)
+
+#define STREAM_CACHE_PREBUFFER_LENGTH (100*1000) /* Maximum time we take to pre-buffer */
+
+
+/* Method1: Simple, for pf_block.
+ * We get blocks and put them in the linked list.
+ * We release blocks once the total size is bigger than CACHE_BLOCK_SIZE
+ */
+#define STREAM_DATA_WAIT 40000 /* Time between before a pf_block retry */
+
+/* Method2: A bit more complex, for pf_read
+ * - We use ring buffers, only one if unseekable, all if seekable
+ * - Upon seek date current ring, then search if one ring match the pos,
+ * yes: switch to it, seek the access to match the end of the ring
+ * no: search the ring with i_end the closer to i_pos,
+ * if close enough, read data and use this ring
+ * else use the oldest ring, seek and use it.
+ *
+ * TODO: - with access non seekable: use all space available for only one ring, but
+ * we have to support seekable/non-seekable switch on the fly.
+ * - compute a good value for i_read_size
+ * - ?
+ */
+#define STREAM_READ_ATONCE 32767
+#define STREAM_CACHE_TRACK_SIZE (STREAM_CACHE_SIZE/STREAM_CACHE_TRACK)
+
+typedef struct
{
- uint8_t *p_data;
- char *p_line;
- int i_data;
- int i = 0;
- i_data = stream_Peek( s, &p_data, MAX_LINE );
+ int64_t i_date;
- while( i < i_data && p_data[i] != '\n' && p_data[i] != '\r' )
+ int64_t i_start;
+ int64_t i_end;
+
+ uint8_t *p_buffer;
+} stream_track_t;
+
+struct stream_sys_t
+{
+ access_t *p_access;
+
+ vlc_bool_t b_block; /* Block method (1) or stream */
+
+ int64_t i_pos; /* Current reading offset */
+
+ /* Method 1: pf_block */
+ struct
{
- i++;
- }
- if( i_data <= 0 )
+ int64_t i_start; /* Offset of block for p_first */
+ int i_offset; /* Offset for data in p_current */
+ block_t *p_current; /* Current block */
+
+ int i_size; /* Total amount of data in the list */
+ block_t *p_first;
+ block_t **pp_last;
+ } block;
+
+ /* Method 2: for pf_read */
+ struct
{
- return NULL;
- }
- else
+ int i_offset; /* Buffer ofset in the current track */
+ int i_tk; /* Current track */
+ stream_track_t tk[STREAM_CACHE_TRACK];
+
+ /* Global buffer */
+ uint8_t *p_buffer;
+
+ /* */
+ int i_used; /* Used since last read */
+ int i_read_size;
+ } stream;
+
+ /* Peek temporary buffer */
+ int i_peek;
+ uint8_t *p_peek;
+
+ /* Stat for both method */
+ struct
{
- p_line = malloc( i + 1 );
- if( p_line == NULL )
- {
- msg_Err( s, "out of memory" );
- return NULL;
- }
- i = stream_Read( s, p_line, i + 1 );
- p_line[ i - 1 ] = '\0';
+ vlc_bool_t b_fastseek; /* From access */
- return p_line;
- }
-}
+ /* Stat about reading data */
+ int64_t i_read_count;
+ int64_t i_bytes;
+ int64_t i_read_time;
+ /* Stat about seek */
+ int i_seek_count;
+ int64_t i_seek_time;
+ } stat;
+};
+/* Method 1: */
+static int AStreamReadBlock( stream_t *, void *p_read, int i_read );
+static int AStreamPeekBlock( stream_t *, uint8_t **p_peek, int i_read );
+static int AStreamSeekBlock( stream_t *s, int64_t i_pos );
+static void AStreamPrebufferBlock( stream_t * );
-/* TODO: one day we should create a special module stream
- * when we would have a access wrapper, and stream filter
- * (like caching, progessive, gunzip, ... )
- */
+/* Method 2 */
+static int AStreamReadStream( stream_t *, void *p_read, int i_read );
+static int AStreamPeekStream( stream_t *, uint8_t **pp_peek, int i_read );
+static int AStreamSeekStream( stream_t *s, int64_t i_pos );
+static void AStreamPrebufferStream( stream_t * );
-/* private stream_sys_t for input_Stream* */
-typedef struct
-{
- input_thread_t *p_input;
-} input_stream_sys_t;
+/* Common */
+static int AStreamControl( stream_t *, int i_query, va_list );
-/* private pf_* functions declarations */
-static int IStreamRead ( stream_t *, void *p_read, int i_read );
-static int IStreamPeek ( stream_t *, uint8_t **pp_peek, int i_peek );
-static int IStreamControl( stream_t *, int i_query, va_list );
/****************************************************************************
- * input_StreamNew: create a wrapper for p_input access
+ * stream_AccessNew: create a stream from a access
****************************************************************************/
-stream_t *input_StreamNew( input_thread_t *p_input )
+stream_t *stream_AccessNew( access_t *p_access )
{
- stream_t *s = vlc_object_create( p_input, sizeof( stream_t ) );
- input_stream_sys_t *p_sys;
- if( s )
+ stream_t *s = vlc_object_create( p_access, VLC_OBJECT_STREAM );
+ stream_sys_t *p_sys;
+
+ if( !s )
+ return NULL;
+
+ /* Attach it now, needed for b_die */
+ vlc_object_attach( s, p_access );
+
+ s->pf_block = NULL;
+ s->pf_read = NULL; /* Set up later */
+ s->pf_peek = NULL;
+ s->pf_control= AStreamControl;
+
+ s->p_sys = p_sys = malloc( sizeof( stream_sys_t ) );
+
+ /* Common field */
+ p_sys->p_access = p_access;
+ p_sys->b_block = p_access->pf_block ? VLC_TRUE : VLC_FALSE;
+ p_sys->i_pos = p_access->info.i_pos;
+
+ /* Stats */
+ access2_Control( p_access, ACCESS_CAN_FASTSEEK, &p_sys->stat.b_fastseek );
+ p_sys->stat.i_bytes = 0;
+ p_sys->stat.i_read_time = 0;
+ p_sys->stat.i_read_count = 0;
+ p_sys->stat.i_seek_count = 0;
+ p_sys->stat.i_seek_time = 0;
+
+ /* Peek */
+ p_sys->i_peek = 0;
+ p_sys->p_peek = NULL;
+
+ if( p_sys->b_block )
+ {
+ s->pf_read = AStreamReadBlock;
+ s->pf_peek = AStreamPeekBlock;
+
+ /* Init all fields of p_sys->block */
+ p_sys->block.i_start = p_sys->i_pos;
+ p_sys->block.i_offset = 0;
+ p_sys->block.p_current = NULL;
+ p_sys->block.i_size = 0;
+ p_sys->block.p_first = NULL;
+ p_sys->block.pp_last = &p_sys->block.p_first;
+
+ /* Do the prebuffering */
+ AStreamPrebufferBlock( s );
+
+ if( p_sys->block.i_size <= 0 )
+ {
+ msg_Err( s, "cannot pre fill buffer" );
+ goto error;
+ }
+ }
+ else
{
- s->pf_block = NULL;
- s->pf_read = IStreamRead;
- s->pf_peek = IStreamPeek;
- s->pf_control= IStreamControl;
+ int i;
+
+ s->pf_read = AStreamReadStream;
+ s->pf_peek = AStreamPeekStream;
+
+ /* Allocate/Setup our tracks */
+ p_sys->stream.i_offset = 0;
+ p_sys->stream.i_tk = 0;
+ p_sys->stream.p_buffer = malloc( STREAM_CACHE_SIZE );
+ p_sys->stream.i_used = 0;
+ access2_Control( p_access, ACCESS_GET_MTU, &p_sys->stream.i_read_size );
+ if( p_sys->stream.i_read_size <= 0 )
+ p_sys->stream.i_read_size = STREAM_READ_ATONCE;
+ else if( p_sys->stream.i_read_size <= 256 )
+ p_sys->stream.i_read_size = 256;
+
+ for( i = 0; i < STREAM_CACHE_TRACK; i++ )
+ {
+ p_sys->stream.tk[i].i_date = 0;
+ p_sys->stream.tk[i].i_start = p_sys->i_pos;
+ p_sys->stream.tk[i].i_end = p_sys->i_pos;
+ p_sys->stream.tk[i].p_buffer=
+ &p_sys->stream.p_buffer[i * STREAM_CACHE_TRACK_SIZE];
+ }
+
+ /* Do the prebuffering */
+ AStreamPrebufferStream( s );
- s->p_sys = malloc( sizeof( input_stream_sys_t ) );
- p_sys = (input_stream_sys_t*)s->p_sys;
- p_sys->p_input = p_input;
+ if( p_sys->stream.tk[p_sys->stream.i_tk].i_end <= 0 )
+ {
+ msg_Err( s, "cannot pre fill buffer" );
+ goto error;
+ }
}
+
+
return s;
+
+error:
+ if( p_sys->b_block )
+ {
+ /* Nothing yet */
+ }
+ else
+ {
+ free( p_sys->stream.p_buffer );
+ }
+ free( s->p_sys );
+ vlc_object_detach( s );
+ vlc_object_destroy( s );
+ return NULL;
}
/****************************************************************************
- * input_StreamDelete:
+ * stream_AccessDelete:
****************************************************************************/
-void input_StreamDelete( stream_t *s )
+void stream_AccessDelete( stream_t *s )
{
+ stream_sys_t *p_sys = s->p_sys;
+
+ vlc_object_detach( s );
+
+ if( p_sys->b_block )
+ {
+ block_ChainRelease( p_sys->block.p_first );
+ }
+ else
+ {
+ free( p_sys->stream.p_buffer );
+ }
+
+ if( p_sys->p_peek )
+ free( p_sys->p_peek );
+
free( s->p_sys );
vlc_object_destroy( s );
}
+/****************************************************************************
+ * stream_AccessReset:
+ ****************************************************************************/
+void stream_AccessReset( stream_t *s )
+{
+ stream_sys_t *p_sys = s->p_sys;
+
+ p_sys->i_pos = p_sys->p_access->info.i_pos;
+
+ if( p_sys->b_block )
+ {
+ block_ChainRelease( p_sys->block.p_first );
+
+ /* Init all fields of p_sys->block */
+ p_sys->block.i_start = p_sys->i_pos;
+ p_sys->block.i_offset = 0;
+ p_sys->block.p_current = NULL;
+ p_sys->block.i_size = 0;
+ p_sys->block.p_first = NULL;
+ p_sys->block.pp_last = &p_sys->block.p_first;
+
+ /* Do the prebuffering */
+ AStreamPrebufferBlock( s );
+ }
+ else
+ {
+ int i;
+
+ /* Setup our tracks */
+ p_sys->stream.i_offset = 0;
+ p_sys->stream.i_tk = 0;
+ p_sys->stream.i_used = 0;
+
+ for( i = 0; i < STREAM_CACHE_TRACK; i++ )
+ {
+ p_sys->stream.tk[i].i_date = 0;
+ p_sys->stream.tk[i].i_start = p_sys->i_pos;
+ p_sys->stream.tk[i].i_end = p_sys->i_pos;
+ }
+
+ /* Do the prebuffering */
+ AStreamPrebufferStream( s );
+ }
+}
/****************************************************************************
- * IStreamControl:
+ * AStreamControl:
****************************************************************************/
-static int IStreamControl( stream_t *s, int i_query, va_list args )
+static int AStreamControl( stream_t *s, int i_query, va_list args )
{
- input_stream_sys_t * p_sys = (input_stream_sys_t*)s->p_sys;
- input_thread_t *p_input = p_sys->p_input;
+ stream_sys_t *p_sys = s->p_sys;
+ access_t *p_access = p_sys->p_access;
- vlc_bool_t *p_b;
- int64_t *p_i64, i64;
- int *p_int;
+ vlc_bool_t *p_bool;
+ int64_t *pi_64, i_64;
+ int i_int;
switch( i_query )
{
case STREAM_GET_SIZE:
- p_i64 = (int64_t*) va_arg( args, int64_t * );
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
- *p_i64 = p_input->stream.p_selected_area->i_size;
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- return VLC_SUCCESS;
+ pi_64 = (int64_t*)va_arg( args, int64_t * );
+ *pi_64 = p_access->info.i_size;
+ break;
case STREAM_CAN_SEEK:
- p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
- *p_b = p_input->stream.b_seekable;
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- return VLC_SUCCESS;
+ p_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
+ access2_Control( p_access, ACCESS_CAN_SEEK, p_bool );
+ break;
case STREAM_CAN_FASTSEEK:
- p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
- *p_b = p_input->stream.b_seekable &&
- p_input->stream.i_method == INPUT_METHOD_FILE;
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- return VLC_SUCCESS;
+ p_bool = (vlc_bool_t*)va_arg( args, vlc_bool_t * );
+ access2_Control( p_access, ACCESS_CAN_FASTSEEK, p_bool );
+ break;
case STREAM_GET_POSITION:
- p_i64 = (int64_t*) va_arg( args, int64_t * );
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
- *p_i64 = p_input->stream.p_selected_area->i_tell;
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- return VLC_SUCCESS;
+ pi_64 = (int64_t*)va_arg( args, int64_t * );
+ *pi_64 = p_sys->i_pos;
+ break;
case STREAM_SET_POSITION:
- {
- int64_t i_skip;
- i64 = (int64_t) va_arg( args, int64_t );
-
- vlc_mutex_lock( &p_input->stream.stream_lock );
- if( i64 < 0 ||
- ( p_input->stream.p_selected_area->i_size > 0 &&
- p_input->stream.p_selected_area->i_size < i64 ) )
- {
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- msg_Warn( s, "seek out of bound" );
- return VLC_EGENERIC;
- }
-
- i_skip = i64 - p_input->stream.p_selected_area->i_tell;
-
- if( i_skip == 0 )
- {
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- return VLC_SUCCESS;
- }
-
- if( i_skip > 0 && i_skip < p_input->p_last_data -
- p_input->p_current_data - 1 )
- {
- /* We can skip without reading/seeking */
- p_input->p_current_data += i_skip;
- p_input->stream.p_selected_area->i_tell = i64;
- vlc_mutex_unlock( &p_input->stream.stream_lock );
- return VLC_SUCCESS;
- }
- vlc_mutex_unlock( &p_input->stream.stream_lock );
-
- if( p_input->stream.b_seekable &&
- ( p_input->stream.i_method == INPUT_METHOD_FILE ||
- i_skip < 0 || i_skip >= ( p_input->i_mtu > 0 ?
- p_input->i_mtu : 4096 ) ) )
- {
- input_AccessReinit( p_input );
- p_input->pf_seek( p_input, i64 );
- return VLC_SUCCESS;
- }
-
- if( i_skip > 0 )
- {
- data_packet_t *p_data;
-
- if( i_skip > 1000 )
- {
- msg_Warn( s, "will skip "I64Fd" bytes, slow", i_skip );
- }
-
- while( i_skip > 0 )
- {
- int i_read;
-
- i_read = input_SplitBuffer( p_input, &p_data,
- __MIN( (int)p_input->i_bufsize, i_skip ) );
- if( i_read < 0 )
- {
- return VLC_EGENERIC;
- }
- i_skip -= i_read;
-
- input_DeletePacket( p_input->p_method_data, p_data );
- if( i_read == 0 && i_skip > 0 )
- {
- return VLC_EGENERIC;
- }
- }
- }
- return VLC_SUCCESS;
- }
+ i_64 = (int64_t)va_arg( args, int64_t );
+ if( p_sys->b_block )
+ return AStreamSeekBlock( s, i_64 );
+ else
+ return AStreamSeekStream( s, i_64 );
case STREAM_GET_MTU:
- p_int = (int*) va_arg( args, int * );
- *p_int = p_input->i_mtu;
- return VLC_SUCCESS;
+ return VLC_EGENERIC;
case STREAM_CONTROL_ACCESS:
- {
- int i_int = (int) va_arg( args, int );
+ i_int = (int) va_arg( args, int );
if( i_int != ACCESS_SET_PRIVATE_ID_STATE )
{
msg_Err( s, "Hey, what are you thinking ?"
"DON'T USE STREAM_CONTROL_ACCESS !!!" );
return VLC_EGENERIC;
}
- if( p_input->pf_access_control )
- {
- return p_input->pf_access_control( p_input, i_int, args );
- }
- return VLC_EGENERIC;
- }
+ return access2_Control( p_access, i_int, args );
default:
msg_Err( s, "invalid stream_vaControl query=0x%x", i_query );
return VLC_EGENERIC;
}
+ return VLC_SUCCESS;
}
+
+
/****************************************************************************
- * IStreamRead:
+ * Method 1:
****************************************************************************/
-static int IStreamRead( stream_t *s, void *p_data, int i_data )
+static void AStreamPrebufferBlock( stream_t *s )
{
- input_stream_sys_t * p_sys = (input_stream_sys_t*)s->p_sys;
- input_thread_t *p_input = p_sys->p_input;
- uint8_t *p = (uint8_t*)p_data;
+ stream_sys_t *p_sys = s->p_sys;
+ access_t *p_access = p_sys->p_access;
- int i_read = 0;
+ int64_t i_first = 0;
+ int64_t i_start;
- if( p_data == NULL && i_data > 0 )
+ msg_Dbg( s, "pre buffering" );
+ i_start = mdate();
+ for( ;; )
{
- int64_t i_pos;
+ int64_t i_date = mdate();
+ block_t *b;
- stream_Control( s, STREAM_GET_POSITION, &i_pos );
+ if( s->b_die ||
+ p_sys->block.i_size > STREAM_CACHE_PREBUFFER_SIZE ||
+ ( i_first > 0 && i_first + STREAM_CACHE_PREBUFFER_LENGTH < i_date ) )
+ {
+ int64_t i_byterate;
+
+ /* Update stat */
+ p_sys->stat.i_bytes = p_sys->block.i_size;
+ p_sys->stat.i_read_time = i_date - i_start;
+ i_byterate = ( I64C(1000000) * p_sys->stat.i_bytes ) /
+ (p_sys->stat.i_read_time+1);
+
+ msg_Dbg( s, "prebuffering done %lld bytes in %llds - %lld kbytes/s",
+ p_sys->stat.i_bytes,
+ p_sys->stat.i_read_time / I64C(1000000),
+ i_byterate / 1024 );
+ break;
+ }
- i_pos += i_data;
- if( stream_Control( s, STREAM_SET_POSITION, i_pos ) )
+ /* Fetch a block */
+ if( ( b = p_access->pf_block( p_access ) ) == NULL )
{
- return 0;
+ if( p_access->info.b_eof )
+ break;
+
+ msleep( STREAM_DATA_WAIT );
+ continue;
}
- return i_data;
+
+ if( i_first == 0 )
+ i_first = mdate();
+
+ /* Append the block */
+ p_sys->block.i_size += b->i_buffer;
+ *p_sys->block.pp_last = b;
+ p_sys->block.pp_last = &b->p_next;
+
+ p_sys->stat.i_read_count++;
}
- while( i_data > 0 && !p_input->b_die )
+ p_sys->block.p_current = p_sys->block.p_first;
+}
+
+static int AStreamRefillBlock( stream_t *s );
+
+static int AStreamReadBlock( stream_t *s, void *p_read, int i_read )
+{
+ stream_sys_t *p_sys = s->p_sys;
+
+ uint8_t *p_data= (uint8_t*)p_read;
+ int i_data = 0;
+
+ /* It means EOF */
+ if( p_sys->block.p_current == NULL )
+ return 0;
+
+ while( i_data < i_read )
{
- ssize_t i_count = p_input->p_last_data - p_input->p_current_data;
+ int i_current = p_sys->block.p_current->i_buffer - p_sys->block.i_offset;
+ int i_copy = __MIN( i_current, i_read - i_data);
- if( i_count <= 0 )
+ /* Copy data */
+ if( p_data )
{
- /* Go to the next buffer */
- i_count = input_FillBuffer( p_input );
+ memcpy( p_data, &p_sys->block.p_current->p_buffer[p_sys->block.i_offset], i_copy );
+ p_data += i_copy;
+ }
+ i_data += i_copy;
- if( i_count < 0 ) return -1;
- else if( i_count == 0 )
+ p_sys->block.i_offset += i_copy;
+ if( p_sys->block.i_offset >= p_sys->block.p_current->i_buffer )
+ {
+ /* Current block is now empty, switch to next */
+ if( p_sys->block.p_current )
+ {
+ p_sys->block.i_offset = 0;
+ p_sys->block.p_current = p_sys->block.p_current->p_next;
+ }
+ /*Get a new block */
+ if( AStreamRefillBlock( s ) )
{
- /* We reached the EOF */
break;
}
}
-
- i_count = __MIN( i_data, i_count );
- memcpy( p, p_input->p_current_data, i_count );
- p_input->p_current_data += i_count;
- p += i_count;
- i_data -= i_count;
- i_read += i_count;
-
- /* Update stream position */
- vlc_mutex_lock( &p_input->stream.stream_lock );
- p_input->stream.p_selected_area->i_tell += i_count;
- vlc_mutex_unlock( &p_input->stream.stream_lock );
}
- return i_read;
+ p_sys->i_pos += i_data;
+ return i_data;
}
-/****************************************************************************
- * IStreamPeek:
- ****************************************************************************/
-static int IStreamPeek( stream_t *s, uint8_t **pp_peek, int i_peek )
+static int AStreamPeekBlock( stream_t *s, uint8_t **pp_peek, int i_read )
{
- input_stream_sys_t * p_sys = (input_stream_sys_t*)s->p_sys;
- return input_Peek( p_sys->p_input, pp_peek, i_peek );
+ stream_sys_t *p_sys = s->p_sys;
+ uint8_t *p_data;
+ int i_data = 0;
+ block_t *b;
+ int i_offset;
+
+ if( p_sys->block.p_current == NULL )
+ return 0; /* EOF */
+
+ /* We can directly give a pointer over our buffer */
+ if( i_read <= p_sys->block.p_current->i_buffer - p_sys->block.i_offset )
+ {
+ *pp_peek = &p_sys->block.p_current->p_buffer[p_sys->block.i_offset];
+ return i_read;
+ }
+
+ /* We need to create a local copy */
+ if( p_sys->i_peek < i_read )
+ {
+ if( p_sys->p_peek )
+ free( p_sys->p_peek );
+ p_sys->i_peek = i_read;
+ p_sys->p_peek = malloc( p_sys->i_peek );
+ }
+
+ /* Fill enough data */
+ while( p_sys->block.i_size - (p_sys->i_pos - p_sys->block.i_start) < i_read )
+ {
+ block_t **pp_last = p_sys->block.pp_last;
+
+ if( AStreamRefillBlock( s ) )
+ break;
+
+ /* Our buffer are probably filled enough, don't try anymore */
+ if( pp_last == p_sys->block.pp_last )
+ break;
+ }
+
+ /* Copy what we have */
+ b = p_sys->block.p_current;
+ i_offset = p_sys->block.i_offset;
+ p_data = p_sys->p_peek;
+
+ while( b && i_data < i_read )
+ {
+ int i_current = b->i_buffer - i_offset;
+ int i_copy = __MIN( i_current, i_read - i_data );
+
+ memcpy( p_data, &b->p_buffer[i_offset], i_copy );
+ i_data += i_copy;
+ p_data += i_copy;
+ i_offset += i_copy;
+
+ if( i_offset >= b->i_buffer )
+ {
+ i_offset = 0;
+ b = b->p_next;
+ }
+ }
+
+ *pp_peek = p_sys->p_peek;
+ return i_data;
}
-/****************************************************************************
- * stream_Demux*: create a demuxer for an outpout stream (allow demuxer chain)
- ****************************************************************************/
-typedef struct
+static int AStreamSeekBlock( stream_t *s, int64_t i_pos )
{
- /* Data buffer */
- vlc_mutex_t lock;
- int i_buffer;
- int i_buffer_size;
- uint8_t *p_buffer;
+ stream_sys_t *p_sys = s->p_sys;
+ access_t *p_access = p_sys->p_access;
+ int64_t i_offset = i_pos - p_sys->block.i_start;
+ vlc_bool_t b_seek;
- int64_t i_pos;
+ /* We already have thoses data, just update p_current/i_offset */
+ if( i_offset >= 0 && i_offset < p_sys->block.i_size )
+ {
+ block_t *b = p_sys->block.p_first;
+ int i_current = 0;
- /* Demuxer */
- char *psz_name;
- es_out_t *out;
- demux_t *p_demux;
-} d_stream_sys_t;
+ while( i_current + b->i_buffer < i_offset )
+ {
+ i_current += b->i_buffer;
+ b = b->p_next;
+ }
-static int DStreamRead ( stream_t *, void *p_read, int i_read );
-static int DStreamPeek ( stream_t *, uint8_t **pp_peek, int i_peek );
-static int DStreamControl( stream_t *, int i_query, va_list );
-static int DStreamThread ( stream_t * );
+ p_sys->block.p_current = b;
+ p_sys->block.i_offset = i_offset - i_current;
+ p_sys->i_pos = i_pos;
-stream_t *__stream_DemuxNew( vlc_object_t *p_obj, char *psz_demux, es_out_t *out )
-{
- /* We create a stream reader, and launch a thread */
- stream_t *s;
- d_stream_sys_t *p_sys;
+ return VLC_SUCCESS;
+ }
- if( psz_demux == NULL || *psz_demux == '\0' )
+ /* We may need to seek or to read data */
+ if( i_offset < 0 )
{
- return NULL;
+ vlc_bool_t b_aseek;
+ access2_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
+
+ if( !b_aseek )
+ {
+ msg_Err( s, "backward seek impossible (access non seekable)" );
+ return VLC_EGENERIC;
+ }
+
+ b_seek = VLC_TRUE;
}
+ else
+ {
+ vlc_bool_t b_aseek, b_aseekfast;
- s = vlc_object_create( p_obj, sizeof( stream_t ) );
- s->pf_block = NULL;
- s->pf_read = DStreamRead;
- s->pf_peek = DStreamPeek;
- s->pf_control= DStreamControl;
-
- s->p_sys = malloc( sizeof( d_stream_sys_t) );
- p_sys = (d_stream_sys_t*)s->p_sys;
-
- vlc_mutex_init( s, &p_sys->lock );
- p_sys->i_buffer = 0;
- p_sys->i_buffer_size = 1000000;
- p_sys->p_buffer = malloc( p_sys->i_buffer_size );
- p_sys->i_pos = 0;
- p_sys->psz_name = strdup( psz_demux );
- p_sys->out = out;
- p_sys->p_demux = NULL;
-
- if( vlc_thread_create( s, "stream out", DStreamThread, VLC_THREAD_PRIORITY_INPUT, VLC_FALSE ) )
- {
- vlc_mutex_destroy( &p_sys->lock );
- vlc_object_destroy( s );
- free( p_sys );
- return NULL;
+ access2_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
+ access2_Control( p_access, ACCESS_CAN_FASTSEEK, &b_aseekfast );
+
+ if( !b_aseek )
+ {
+ b_seek = VLC_FALSE;
+ msg_Warn( s, "%lld bytes need to be skipped (access non seekable)",
+ i_offset - p_sys->block.i_size );
+ }
+ else
+ {
+ int64_t i_skip = i_offset - p_sys->block.i_size;
+
+ /* Avg bytes per packets */
+ int i_avg = p_sys->stat.i_bytes / p_sys->stat.i_read_count;
+ /* TODO compute a seek cost instead of fixed threshold */
+ int i_th = b_aseekfast ? 1 : 5;
+
+ if( i_skip <= i_th * i_avg &&
+ i_skip < STREAM_CACHE_SIZE )
+ b_seek = VLC_FALSE;
+ else
+ b_seek = VLC_TRUE;
+
+ msg_Dbg( s, "b_seek=%d th*avg=%d skip=%lld",
+ b_seek, i_th*i_avg, i_skip );
+ }
}
- return s;
-}
+ if( b_seek )
+ {
+ int64_t i_start, i_end;
+ /* Do the access seek */
+ i_start = mdate();
+ if( p_access->pf_seek( p_access, i_pos ) )
+ return VLC_EGENERIC;
+ i_end = mdate();
-void stream_DemuxSend( stream_t *s, block_t *p_block )
-{
- d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+ /* Release data */
+ block_ChainRelease( p_sys->block.p_first );
+
+ /* Reinit */
+ p_sys->block.i_start = p_sys->i_pos = i_pos;
+ p_sys->block.i_offset = 0;
+ p_sys->block.p_current = NULL;
+ p_sys->block.i_size = 0;
+ p_sys->block.p_first = NULL;
+ p_sys->block.pp_last = &p_sys->block.p_first;
- if( p_block->i_buffer > 0 )
+ /* Refill a block */
+ if( AStreamRefillBlock( s ) )
+ {
+ msg_Err( s, "cannot re fill buffer" );
+ return VLC_EGENERIC;
+ }
+ /* Update stat */
+ p_sys->stat.i_seek_time += i_end - i_start;
+ p_sys->stat.i_seek_count++;
+ return VLC_SUCCESS;
+ }
+ else
{
- vlc_mutex_lock( &p_sys->lock );
- /* Realloc if needed */
- if( p_sys->i_buffer + p_block->i_buffer > p_sys->i_buffer_size )
+ /* Read enought data */
+ while( p_sys->block.i_start + p_sys->block.i_size < i_pos )
{
- if( p_sys->i_buffer_size > 5000000 )
+ if( AStreamRefillBlock( s ) )
+ {
+ msg_Err( s, "can't read enough data in seek" );
+ return VLC_EGENERIC;
+ }
+ while( p_sys->block.p_current &&
+ p_sys->i_pos + p_sys->block.p_current->i_buffer < i_pos )
{
- vlc_mutex_unlock( &p_sys->lock );
- msg_Err( s, "stream_DemuxSend: buffer size > 5000000" );
- block_Release( p_block );
- return;
+ p_sys->i_pos += p_sys->block.p_current->i_buffer;
+ p_sys->block.p_current = p_sys->block.p_current->p_next;
}
- /* I know, it's more than needed but that's perfect */
- p_sys->i_buffer_size += p_block->i_buffer;
- /* FIXME won't work with PEEK -> segfault */
- p_sys->p_buffer = realloc( p_sys->p_buffer, p_sys->i_buffer_size );
- msg_Dbg( s, "stream_DemuxSend: realloc to %d", p_sys->i_buffer_size );
}
- /* copy data */
- memcpy( &p_sys->p_buffer[p_sys->i_buffer], p_block->p_buffer, p_block->i_buffer );
- p_sys->i_buffer += p_block->i_buffer;
+ p_sys->block.i_offset = i_pos - p_sys->i_pos;
+ p_sys->i_pos = i_pos;
- vlc_mutex_unlock( &p_sys->lock );
+ /* TODO read data */
+ return VLC_SUCCESS;
}
- block_Release( p_block );
+ return VLC_EGENERIC;
}
-void stream_DemuxDelete( stream_t *s )
+static int AStreamRefillBlock( stream_t *s )
{
- d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
+ stream_sys_t *p_sys = s->p_sys;
+ access_t *p_access = p_sys->p_access;
+ int64_t i_start, i_stop;
+ block_t *b;
+
+ /* Release data */
+ while( p_sys->block.i_size >= STREAM_CACHE_SIZE &&
+ p_sys->block.p_first != p_sys->block.p_current )
+ {
+ block_t *b = p_sys->block.p_first;
- s->b_die = VLC_TRUE;
+ p_sys->block.i_start += b->i_buffer;
+ p_sys->block.i_size -= b->i_buffer;
+ p_sys->block.p_first = b->p_next;
- vlc_mutex_lock( &p_sys->lock );
- if( p_sys->p_demux )
+ block_Release( b );
+ }
+ if( p_sys->block.i_size >= STREAM_CACHE_SIZE &&
+ p_sys->block.p_current == p_sys->block.p_first &&
+ p_sys->block.p_current->p_next ) /* At least 2 packets */
{
- p_sys->p_demux->b_die = VLC_TRUE;
+ /* Enough data, don't read more */
+ return VLC_SUCCESS;
}
- vlc_mutex_unlock( &p_sys->lock );
-
- vlc_thread_join( s );
- if( p_sys->p_demux )
+ /* Now read a new block */
+ i_start = mdate();
+ for( ;; )
{
- demux2_Delete( p_sys->p_demux );
+ if( s->b_die )
+ return VLC_EGENERIC;
+
+
+ /* Fetch a block */
+ if( ( b = p_access->pf_block( p_access ) ) )
+ break;
+
+ if( p_access->info.b_eof )
+ return VLC_EGENERIC;
+
+ msleep( STREAM_DATA_WAIT );
}
- vlc_mutex_destroy( &p_sys->lock );
- free( p_sys->psz_name );
- free( p_sys->p_buffer );
- free( p_sys );
- vlc_object_destroy( s );
+ i_stop = mdate();
+
+ /* Append the block */
+ p_sys->block.i_size += b->i_buffer;
+ *p_sys->block.pp_last = b;
+ p_sys->block.pp_last = &b->p_next;
+
+ /* Fix p_current */
+ if( p_sys->block.p_current == NULL )
+ p_sys->block.p_current = b;
+
+ /* Update stat */
+ p_sys->stat.i_bytes += b->i_buffer;
+ p_sys->stat.i_read_time += i_stop - i_start;
+ p_sys->stat.i_read_count++;
+
+ return VLC_SUCCESS;
}
-static int DStreamRead ( stream_t *s, void *p_read, int i_read )
+/****************************************************************************
+ * Method 2:
+ ****************************************************************************/
+static int AStreamRefillStream( stream_t *s );
+
+static int AStreamReadStream( stream_t *s, void *p_read, int i_read )
{
- d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
- int i_copy;
+ stream_sys_t *p_sys = s->p_sys;
+ stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
- //msg_Dbg( s, "DStreamRead: wanted %d bytes", i_read );
- for( ;; )
- {
- vlc_mutex_lock( &p_sys->lock );
- //msg_Dbg( s, "DStreamRead: buffer %d", p_sys->i_buffer );
- if( p_sys->i_buffer >= i_read || s->b_die )
- {
- break;
- }
- vlc_mutex_unlock( &p_sys->lock );
- msleep( 10000 );
- }
+ uint8_t *p_data = (uint8_t*)p_read;
+ int i_data = 0;
- //msg_Dbg( s, "DStreamRead: read %d buffer %d", i_read, p_sys->i_buffer );
+ if( tk->i_start >= tk->i_end )
+ return 0; /* EOF */
- i_copy = __MIN( i_read, p_sys->i_buffer );
- if( i_copy > 0 )
+ /*msg_Dbg( s, "AStreamReadStream: %d pos=%lld tk=%d start=%lld offset=%d end=%lld",
+ i_read,
+ p_sys->i_pos,
+ p_sys->stream.i_tk,
+ tk->i_start, p_sys->stream.i_offset, tk->i_end );*/
+
+ while( i_data < i_read )
{
- if( p_read )
+ int i_off = (tk->i_start + p_sys->stream.i_offset) % STREAM_CACHE_TRACK_SIZE;
+ int i_current = __MIN( tk->i_end - tk->i_start - p_sys->stream.i_offset, STREAM_CACHE_TRACK_SIZE - i_off );
+ int i_copy = __MIN( i_current, i_read - i_data );
+
+ /* Copy data */
+ //msg_Dbg( s, "AStreamReadStream: copy %d", i_copy );
+ if( p_data )
{
- memcpy( p_read, p_sys->p_buffer, i_copy );
+ memcpy( p_data, &tk->p_buffer[i_off], i_copy );
+ p_data += i_copy;
}
- p_sys->i_buffer -= i_copy;
+ i_data += i_copy;
+ p_sys->stream.i_offset += i_copy;
+
+ /* Update pos now */
p_sys->i_pos += i_copy;
- if( p_sys->i_buffer > 0 )
+ /* */
+ p_sys->stream.i_used += i_copy;
+ if( tk->i_start + p_sys->stream.i_offset >= tk->i_end ||
+ p_sys->stream.i_used >= p_sys->stream.i_read_size )
{
- memmove( p_sys->p_buffer, &p_sys->p_buffer[i_copy], p_sys->i_buffer );
+ if( AStreamRefillStream( s ) )
+ {
+ /* Eof */
+ if( tk->i_start >= tk->i_end )
+ break;
+ }
}
-
}
- vlc_mutex_unlock( &p_sys->lock );
- return i_copy;
+ return i_data;
}
-static int DStreamPeek ( stream_t *s, uint8_t **pp_peek, int i_peek )
+
+static int AStreamPeekStream( stream_t *s, uint8_t **pp_peek, int i_read )
{
- d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
- int i_copy;
+ stream_sys_t *p_sys = s->p_sys;
+ stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
+ int64_t i_off;
- //msg_Dbg( s, "DStreamPeek: wanted %d bytes", i_peek );
- for( ;; )
+ if( tk->i_start >= tk->i_end )
+ return 0; /* EOF */
+
+ /*msg_Dbg( s, "AStreamPeekStream: %d pos=%lld tk=%d start=%lld offset=%d end=%lld",
+ i_read,
+ p_sys->i_pos,
+ p_sys->stream.i_tk,
+ tk->i_start, p_sys->stream.i_offset, tk->i_end );*/
+
+ /* Avoid problem, but that should *never* happen */
+ if( i_read > STREAM_CACHE_TRACK_SIZE / 2 )
+ i_read = STREAM_CACHE_TRACK_SIZE / 2;
+
+ while( tk->i_end - tk->i_start - p_sys->stream.i_offset < i_read )
{
- vlc_mutex_lock( &p_sys->lock );
- //msg_Dbg( s, "DStreamPeek: buffer %d", p_sys->i_buffer );
- if( p_sys->i_buffer >= i_peek || s->b_die )
- {
+ if( AStreamRefillStream( s ) )
break;
- }
- vlc_mutex_unlock( &p_sys->lock );
- msleep( 10000 );
}
- *pp_peek = p_sys->p_buffer;
- i_copy = __MIN( i_peek, p_sys->i_buffer );
- vlc_mutex_unlock( &p_sys->lock );
+ if( tk->i_end - tk->i_start - p_sys->stream.i_offset < i_read )
+ i_read = tk->i_end - tk->i_start - p_sys->stream.i_offset;
- return i_copy;
+ /* Now, direct pointer or a copy ? */
+ i_off = (tk->i_start + p_sys->stream.i_offset) % STREAM_CACHE_TRACK_SIZE;
+ if( i_off + i_read <= STREAM_CACHE_TRACK_SIZE )
+ {
+ *pp_peek = &tk->p_buffer[i_off];
+ return i_read;
+ }
+
+ if( p_sys->i_peek < i_read )
+ {
+ if( p_sys->p_peek ) free( p_sys->p_peek );
+ p_sys->i_peek = i_read;
+ p_sys->p_peek = malloc( i_read );
+ }
+
+ memcpy( p_sys->p_peek, &tk->p_buffer[i_off], STREAM_CACHE_TRACK_SIZE - i_off );
+ memcpy( &p_sys->p_peek[STREAM_CACHE_TRACK_SIZE - i_off], &tk->p_buffer[0], i_read - (STREAM_CACHE_TRACK_SIZE - i_off) );
+
+ *pp_peek = p_sys->p_peek;
+ return i_read;
}
-static int DStreamControl( stream_t *s, int i_query, va_list args )
+static int AStreamSeekStream( stream_t *s, int64_t i_pos )
{
- d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
- int64_t *p_i64;
- vlc_bool_t *p_b;
- int *p_int;
- switch( i_query )
+ stream_sys_t *p_sys = s->p_sys;
+ access_t *p_access = p_sys->p_access;
+ vlc_bool_t b_aseek;
+ vlc_bool_t b_afastseek;
+ int i_maxth;
+ int i_new;
+ int i;
+
+ /*
+ msg_Dbg( s, "AStreamSeekStream: to %lld pos=%lld tk=%d start=%lld offset=%d end=%lld",
+ i_pos,
+ p_sys->i_pos,
+ p_sys->stream.i_tk,
+ p_sys->stream.tk[p_sys->stream.i_tk].i_start, p_sys->stream.i_offset, p_sys->stream.tk[p_sys->stream.i_tk].i_end );*/
+
+
+ /* Seek in our current track ? */
+ if( i_pos >= p_sys->stream.tk[p_sys->stream.i_tk].i_start &&
+ i_pos < p_sys->stream.tk[p_sys->stream.i_tk].i_end )
{
- case STREAM_GET_SIZE:
- p_i64 = (int64_t*) va_arg( args, int64_t * );
- *p_i64 = 0;
- return VLC_SUCCESS;
+ //msg_Dbg( s, "AStreamSeekStream: current track" );
+ p_sys->i_pos = i_pos;
+ p_sys->stream.i_offset = i_pos - p_sys->stream.tk[p_sys->stream.i_tk].i_start;
+ return VLC_SUCCESS;
+ }
- case STREAM_CAN_SEEK:
- p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
- *p_b = VLC_FALSE;
- return VLC_SUCCESS;
+ access2_Control( p_access, ACCESS_CAN_SEEK, &b_aseek );
+ if( !b_aseek )
+ {
+ /* We can't do nothing */
+ return VLC_EGENERIC;
+ }
- case STREAM_CAN_FASTSEEK:
- p_b = (vlc_bool_t*) va_arg( args, vlc_bool_t * );
- *p_b = VLC_FALSE;
- return VLC_SUCCESS;
+ /* Date the current track */
+ p_sys->stream.tk[p_sys->stream.i_tk].i_date = mdate();
- case STREAM_GET_POSITION:
- p_i64 = (int64_t*) va_arg( args, int64_t * );
- *p_i64 = p_sys->i_pos;
- return VLC_SUCCESS;
+ /* Try to reuse already read data */
+ for( i = 0; i < STREAM_CACHE_TRACK; i++ )
+ {
+ stream_track_t *tk = &p_sys->stream.tk[i];
- case STREAM_SET_POSITION:
- return VLC_EGENERIC;
+ if( i_pos >= tk->i_start && i_pos <= tk->i_end )
+ {
+ /*msg_Dbg( s, "AStreamSeekStream: reusing %d start=%lld end=%lld",
+ i,
+ tk->i_start, tk->i_end );*/
+ /* Seek at the end of the buffer */
+ if( p_access->pf_seek( p_access, tk->i_end ) )
+ return VLC_EGENERIC;
+
+ /* That's it */
+ p_sys->i_pos = i_pos;
+ p_sys->stream.i_tk = i;
+ p_sys->stream.i_offset = i_pos - tk->i_start;
+
+ if( p_sys->stream.i_used < 1024 )
+ p_sys->stream.i_used = 1024;
+
+ if( AStreamRefillStream( s ) )
+ return VLC_EGENERIC;
- case STREAM_GET_MTU:
- p_int = (int*) va_arg( args, int * );
- *p_int = 0;
return VLC_SUCCESS;
+ }
+ }
- default:
- msg_Err( s, "invalid DStreamControl query=0x%x", i_query );
- return VLC_EGENERIC;
+ access2_Control( p_access, ACCESS_CAN_SEEK, &b_afastseek );
+ /* FIXME compute seek cost (instead of static 'stupid' value) */
+ i_maxth = __MIN( p_sys->stream.i_read_size, STREAM_READ_ATONCE / 2 );
+ if( !b_afastseek )
+ i_maxth *= 3;
+
+ /* FIXME TODO */
+#if 0
+ /* Search closest segment TODO */
+ for( i = 0; i < STREAM_CACHE_TRACK; i++ )
+ {
+ stream_track_t *tk = &p_sys->stream.tk[i];
+
+ if( i_pos + i_maxth >= tk->i_start )
+ {
+ msg_Dbg( s, "good segment before current pos, TODO" );
+ }
+ if( i_pos - i_maxth <= tk->i_end )
+ {
+ msg_Dbg( s, "good segment after current pos, TODO" );
+ }
}
+#endif
+
+ /* Nothing good, seek and choose oldest segment */
+ if( p_access->pf_seek( p_access, i_pos ) )
+ return VLC_EGENERIC;
+ p_sys->i_pos = i_pos;
+
+ i_new = 0;
+ for( i = 1; i < STREAM_CACHE_TRACK; i++ )
+ {
+ if( p_sys->stream.tk[i].i_date < p_sys->stream.tk[i_new].i_date )
+ i_new = i;
+ }
+
+ /* Reset the segment */
+ p_sys->stream.i_tk = i_new;
+ p_sys->stream.i_offset = 0;
+ p_sys->stream.tk[i_new].i_start = i_pos;
+ p_sys->stream.tk[i_new].i_end = i_pos;
+
+ /* Read data */
+ if( p_sys->stream.i_used < STREAM_READ_ATONCE / 2 )
+ p_sys->stream.i_used = STREAM_READ_ATONCE / 2;
+
+ if( AStreamRefillStream( s ) )
+ return VLC_EGENERIC;
+
+ return VLC_SUCCESS;
}
-static int DStreamThread ( stream_t *s )
+static int AStreamRefillStream( stream_t *s )
{
- d_stream_sys_t *p_sys = (d_stream_sys_t*)s->p_sys;
- demux_t *p_demux;
+ stream_sys_t *p_sys = s->p_sys;
+ access_t *p_access = p_sys->p_access;
+ stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
+ /* We read but won't increase i_start after initial start+offset */
+ int i_toread = __MIN( p_sys->stream.i_used, STREAM_CACHE_TRACK_SIZE - (tk->i_end - tk->i_start - p_sys->stream.i_offset ) );
+ int64_t i_start, i_stop;
- /* Create the demuxer */
+ //msg_Dbg( s, "AStreamRefillStream: toread=%d", i_toread );
- if( ( p_demux = demux2_New( s, "", p_sys->psz_name, "", s, p_sys->out ) ) == NULL )
+ i_start = mdate();
+ while( i_toread > 0 )
{
- return VLC_EGENERIC;
+ int i_off = tk->i_end % STREAM_CACHE_TRACK_SIZE;
+ int i_read;
+
+ if( s->b_die )
+ return VLC_EGENERIC;
+
+ i_read = __MIN( i_toread, STREAM_CACHE_TRACK_SIZE - i_off );
+ i_read = p_access->pf_read( p_access, &tk->p_buffer[i_off], i_read );
+ //msg_Dbg( s, "AStreamRefillStream: read=%d", i_read );
+ if( i_read < 0 )
+ {
+ msleep( STREAM_DATA_WAIT );
+ continue;
+ }
+ else if( i_read == 0 )
+ {
+ return VLC_EGENERIC;
+ }
+
+ /* Update end */
+ tk->i_end += i_read;
+
+ /* Windows of STREAM_CACHE_TRACK_SIZE */
+ if( tk->i_end - tk->i_start > STREAM_CACHE_TRACK_SIZE )
+ {
+ int i_invalid = tk->i_end - tk->i_start - STREAM_CACHE_TRACK_SIZE;
+
+ tk->i_start += i_invalid;
+ p_sys->stream.i_offset -= i_invalid;
+ }
+
+
+ i_toread -= i_read;
+ p_sys->stream.i_used -= i_read;
+
+ p_sys->stat.i_bytes += i_read;
+ p_sys->stat.i_read_count++;
}
+ i_stop = mdate();
+
+ p_sys->stat.i_read_time += i_stop - i_start;
+
+ return VLC_SUCCESS;
+}
+
+static void AStreamPrebufferStream( stream_t *s )
+{
+ stream_sys_t *p_sys = s->p_sys;
+ access_t *p_access = p_sys->p_access;
- vlc_mutex_lock( &p_sys->lock );
- p_sys->p_demux = p_demux;
- vlc_mutex_unlock( &p_sys->lock );
+ int64_t i_first = 0;
+ int64_t i_start;
- /* Main loop */
- while( !s->b_die && !p_demux->b_die )
+ msg_Dbg( s, "pre buffering" );
+ i_start = mdate();
+ for( ;; )
{
- if( p_demux->pf_demux( p_demux ) <= 0 )
+ stream_track_t *tk = &p_sys->stream.tk[p_sys->stream.i_tk];
+
+ int64_t i_date = mdate();
+ int i_read;
+
+ if( s->b_die ||
+ tk->i_end >= STREAM_CACHE_PREBUFFER_SIZE ||
+ ( i_first > 0 && i_first + STREAM_CACHE_PREBUFFER_LENGTH < i_date ) )
{
+ int64_t i_byterate;
+
+ /* Update stat */
+ p_sys->stat.i_bytes = tk->i_end - tk->i_start;
+ p_sys->stat.i_read_time = i_date - i_start;
+ i_byterate = ( I64C(1000000) * p_sys->stat.i_bytes ) /
+ (p_sys->stat.i_read_time+1);
+
+ msg_Dbg( s, "prebuffering done %lld bytes in %llds - %lld kbytes/s",
+ p_sys->stat.i_bytes,
+ p_sys->stat.i_read_time / I64C(1000000),
+ i_byterate / 1024 );
break;
}
+
+ /* */
+ i_read = __MIN( p_sys->stream.i_read_size, STREAM_CACHE_TRACK_SIZE - tk->i_end );
+ i_read = p_access->pf_read( p_access, &tk->p_buffer[tk->i_end], i_read );
+ if( i_read < 0 )
+ {
+ msleep( STREAM_DATA_WAIT );
+ continue;
+ }
+ else if( i_read == 0 )
+ {
+ /* EOF */
+ break;
+ }
+
+ if( i_first == 0 )
+ i_first = mdate();
+
+ tk->i_end += i_read;
+
+ p_sys->stat.i_read_count++;
}
- p_demux->b_die = VLC_TRUE;
- return VLC_SUCCESS;
}
+/****************************************************************************
+ * stream_ReadLine:
+ ****************************************************************************/
+/**
+ * Read from the stream untill first newline.
+ * \param s Stream handle to read from
+ * \return A null-terminated string. This must be freed,
+ */
+/* FIXME don't use stupid MAX_LINE -> do the same than net_ReadLine */
+#define MAX_LINE 1024
+char *stream_ReadLine( stream_t *s )
+{
+ uint8_t *p_data;
+ char *p_line;
+ int i_data;
+ int i = 0;
+ i_data = stream_Peek( s, &p_data, MAX_LINE );
+ while( i < i_data && p_data[i] != '\n' && p_data[i] != '\r' )
+ {
+ i++;
+ }
+ if( i_data <= 0 )
+ {
+ return NULL;
+ }
+ else
+ {
+ p_line = malloc( i + 1 );
+ if( p_line == NULL )
+ {
+ msg_Err( s, "out of memory" );
+ return NULL;
+ }
+ i = stream_Read( s, p_line, i + 1 );
+ p_line[ i - 1 ] = '\0';
+ return p_line;
+ }
+}
#include <vlc/vlc.h>
#include <vlc/input.h>
-#include "ninput.h"
-
#ifdef HAVE_DIRENT_H
# include <dirent.h>
#else