X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Finput%2Finput_clock.c;h=543cc62e92658ba6b2517662a71234a7efc6dab3;hb=3d6ee48d4aacb1fbd5c2741b7b319a62a47009d9;hp=1a7ef4357967fbe9156ded55fb714730b50c32c0;hpb=7d38f3f9974edfe5d54132d996b5bfa48c7b8bb6;p=vlc diff --git a/src/input/input_clock.c b/src/input/input_clock.c index 1a7ef43579..543cc62e92 100644 --- a/src/input/input_clock.c +++ b/src/input/input_clock.c @@ -1,8 +1,8 @@ /***************************************************************************** * input_clock.c: Clock/System date convertions, stream management ***************************************************************************** - * Copyright (C) 1999, 2000 VideoLAN - * $Id: input_clock.c,v 1.7 2001/02/22 17:00:20 massiot Exp $ + * Copyright (C) 1999-2001 VideoLAN + * $Id: input_clock.c,v 1.44 2003/12/04 16:49:45 sam Exp $ * * Authors: Christophe Massiot * @@ -10,7 +10,7 @@ * 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 @@ -24,19 +24,14 @@ /***************************************************************************** * Preamble *****************************************************************************/ -#include "defs.h" +#include /* memcpy(), memset() */ -#include "config.h" -#include "common.h" -#include "threads.h" -#include "mtime.h" -#include "intf_msg.h" +#include #include "stream_control.h" #include "input_ext-intf.h" #include "input_ext-dec.h" - -#include "input.h" +#include "input_ext-plugins.h" /* * DISCUSSION : SYNCHRONIZATION METHOD @@ -66,18 +61,25 @@ * in all the FIFOs, but it may be not enough. */ -/***************************************************************************** - * Constants - *****************************************************************************/ - -/* Maximum number of samples used to compute the dynamic average value. +/* p_input->i_cr_average : Maximum number of samples used to compute the + * dynamic average value. * We use the following formula : * new_average = (old_average * c_average + new_sample_value) / (c_average +1) */ -#define CR_MAX_AVERAGE_COUNTER 40 + +static void ClockNewRef( pgrm_descriptor_t * p_pgrm, + mtime_t i_clock, mtime_t i_sysdate ); + +/***************************************************************************** + * Constants + *****************************************************************************/ /* Maximum gap allowed between two CRs. */ -#define CR_MAX_GAP 1000000 +#define CR_MAX_GAP 2000000 + +/* Latency introduced on DVDs with CR == 0 on chapter change - this is from + * my dice --Meuuh */ +#define CR_MEAN_PTS_GAP 300000 /***************************************************************************** * ClockToSysdate: converts a movie clock to system date @@ -89,12 +91,12 @@ static mtime_t ClockToSysdate( input_thread_t * p_input, if( p_pgrm->i_synchro_state == SYNCHRO_OK ) { - i_sysdate = (i_clock - p_pgrm->cr_ref) - * p_input->stream.control.i_rate - * 300 - / 27 - / DEFAULT_RATE - + p_pgrm->sysdate_ref; + i_sysdate = (mtime_t)(i_clock - p_pgrm->cr_ref) + * (mtime_t)p_input->stream.control.i_rate + * (mtime_t)300; + i_sysdate /= 27; + i_sysdate /= 1000; + i_sysdate += (mtime_t)p_pgrm->sysdate_ref; } return( i_sysdate ); @@ -116,11 +118,11 @@ static mtime_t ClockCurrent( input_thread_t * p_input, /***************************************************************************** * ClockNewRef: writes a new clock reference *****************************************************************************/ -static void ClockNewRef( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm, +static void ClockNewRef( pgrm_descriptor_t * p_pgrm, mtime_t i_clock, mtime_t i_sysdate ) { p_pgrm->cr_ref = i_clock; - p_pgrm->sysdate_ref = i_sysdate; + p_pgrm->sysdate_ref = i_sysdate ; } /***************************************************************************** @@ -130,23 +132,130 @@ static void ClockNewRef( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm, void input_ClockInit( pgrm_descriptor_t * p_pgrm ) { 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; } +/***************************************************************************** + * 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 ) +{ + vlc_value_t val; + int i_return_value = UNDEF_S; + + vlc_mutex_lock( &p_input->stream.stream_lock ); + + if( p_input->stream.i_new_status == PAUSE_S ) + { + int i_old_status; + + vlc_mutex_lock( &p_input->stream.control.control_lock ); + i_old_status = p_input->stream.control.i_status; + p_input->stream.control.i_status = PAUSE_S; + vlc_mutex_unlock( &p_input->stream.control.control_lock ); + + vlc_cond_wait( &p_input->stream.stream_wait, + &p_input->stream.stream_lock ); + ClockNewRef( p_pgrm, i_clock, p_pgrm->last_pts > mdate() ? + p_pgrm->last_pts : mdate() ); + + if( p_input->stream.i_new_status == PAUSE_S ) + { + /* PAUSE_S undoes the pause state: Return to old state. */ + vlc_mutex_lock( &p_input->stream.control.control_lock ); + p_input->stream.control.i_status = i_old_status; + vlc_mutex_unlock( &p_input->stream.control.control_lock ); + + p_input->stream.i_new_status = UNDEF_S; + p_input->stream.i_new_rate = UNDEF_S; + } + + /* We handle i_new_status != PAUSE_S below... */ + + i_return_value = PAUSE_S; + } + + if( p_input->stream.i_new_status != UNDEF_S ) + { + vlc_mutex_lock( &p_input->stream.control.control_lock ); + + p_input->stream.control.i_status = p_input->stream.i_new_status; + + ClockNewRef( p_pgrm, i_clock, + ClockToSysdate( p_input, p_pgrm, i_clock ) ); + + if( p_input->stream.control.i_status == PLAYING_S ) + { + p_input->stream.control.i_rate = DEFAULT_RATE; + p_input->stream.control.b_mute = 0; + } + else + { + p_input->stream.control.i_rate = p_input->stream.i_new_rate; + p_input->stream.control.b_mute = 1; + + /* Feed the audio decoders with a NULL packet to avoid + * discontinuities. */ + input_EscapeAudioDiscontinuity( p_input ); + } + + val.i_int = p_input->stream.control.i_rate; + var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL ); + + val.i_int = p_input->stream.control.i_status; + var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL ); + + p_input->stream.i_new_status = UNDEF_S; + p_input->stream.i_new_rate = UNDEF_S; + + vlc_mutex_unlock( &p_input->stream.control.control_lock ); + } + + vlc_mutex_unlock( &p_input->stream.stream_lock ); + + return( i_return_value ); +} + /***************************************************************************** * input_ClockManageRef: manages a clock reference *****************************************************************************/ void input_ClockManageRef( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm, mtime_t i_clock ) { - if( p_pgrm->i_synchro_state != SYNCHRO_OK ) + /* 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 ) ) { /* Feed synchro with a new reference point. */ - ClockNewRef( p_input, p_pgrm, i_clock, mdate() ); + 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; + + if( p_input->stream.b_pace_control + && p_input->stream.p_selected_program == p_pgrm ) + { + p_pgrm->last_cr = i_clock; + mwait( ClockToSysdate( p_input, p_pgrm, i_clock ) ); + } + else + { + p_pgrm->last_cr = 0; + p_pgrm->delta_cr = 0; + p_pgrm->c_average_count = 0; + } } else { @@ -157,62 +266,24 @@ void input_ClockManageRef( input_thread_t * p_input, /* Stream discontinuity, for which we haven't received a * warning from the stream control facilities (dd-edited * stream ?). */ - intf_WarnMsg( 3, "Clock gap, unexpected stream discontinuity" ); + msg_Warn( p_input, "clock gap, unexpected stream discontinuity" ); input_ClockInit( p_pgrm ); p_pgrm->i_synchro_state = SYNCHRO_START; - input_EscapeDiscontinuity( p_input, p_pgrm ); + input_EscapeDiscontinuity( p_input ); } p_pgrm->last_cr = i_clock; if( p_input->stream.b_pace_control - && p_input->stream.pp_programs[0] == p_pgrm ) + && p_input->stream.p_selected_program == p_pgrm ) { /* Wait a while before delivering the packets to the decoder. * In case of multiple programs, we arbitrarily follow the - * clock of the first program. */ + * clock of the selected program. */ mwait( ClockToSysdate( p_input, p_pgrm, i_clock ) ); /* Now take into account interface changes. */ - vlc_mutex_lock( &p_input->stream.stream_lock ); - if( p_input->stream.i_new_status != UNDEF_S ) - { - if( p_input->stream.i_new_status == PAUSE_S ) - { - vlc_cond_wait( &p_input->stream.stream_wait, - &p_input->stream.stream_lock ); - ClockNewRef( p_input, p_pgrm, i_clock, mdate() ); - } - else - { - ClockNewRef( p_input, p_pgrm, i_clock, - ClockToSysdate( p_input, p_pgrm, i_clock ) ); - } - - vlc_mutex_lock( &p_input->stream.control.control_lock ); - p_input->stream.control.i_status = p_input->stream.i_new_status; - - if( p_input->stream.control.i_status != PLAYING_S - && p_input->stream.control.i_status != PAUSE_S ) - { - p_input->stream.control.i_rate = p_input->stream.i_new_rate; - p_input->stream.control.b_mute = 1; - - /* Feed the audio decoders with a NULL packet to avoid - * discontinuities. */ - input_EscapeAudioDiscontinuity( p_input, p_pgrm ); - } - else - { - p_input->stream.control.i_rate = DEFAULT_RATE; - p_input->stream.control.b_mute = 0; - } - vlc_mutex_unlock( &p_input->stream.control.control_lock ); - - p_input->stream.i_new_status = UNDEF_S; - p_input->stream.i_new_rate = UNDEF_S; - } - vlc_mutex_unlock( &p_input->stream.stream_lock ); + input_ClockManageControl( p_input, p_pgrm, i_clock ); } else { @@ -220,18 +291,18 @@ void input_ClockManageRef( input_thread_t * p_input, mtime_t i_extrapoled_clock = ClockCurrent( p_input, p_pgrm ); /* Bresenham algorithm to smooth variations. */ - if( p_pgrm->c_average_count == CR_MAX_AVERAGE_COUNTER ) + if( p_pgrm->c_average_count == p_input->i_cr_average ) { p_pgrm->delta_cr = ( p_pgrm->delta_cr - * (CR_MAX_AVERAGE_COUNTER - 1) - + i_extrapoled_clock ) - / CR_MAX_AVERAGE_COUNTER; + * (p_input->i_cr_average - 1) + + ( i_extrapoled_clock - i_clock ) ) + / p_input->i_cr_average; } else { p_pgrm->delta_cr = ( p_pgrm->delta_cr * p_pgrm->c_average_count - + i_extrapoled_clock ) + + ( i_extrapoled_clock - i_clock ) ) / (p_pgrm->c_average_count + 1); p_pgrm->c_average_count++; } @@ -245,10 +316,17 @@ void input_ClockManageRef( input_thread_t * p_input, mtime_t input_ClockGetTS( input_thread_t * p_input, pgrm_descriptor_t * p_pgrm, 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 ) { - return( ClockToSysdate( p_input, p_pgrm, i_ts + p_pgrm->delta_cr ) - + DEFAULT_PTS_DELAY ); + 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 {