Main Page | Modules | Class Hierarchy | Class List | Directories | File List | Class Members | File Members | Related Pages

clock.c

00001 /*****************************************************************************
00002  * input_clock.c: Clock/System date convertions, stream management
00003  *****************************************************************************
00004  * Copyright (C) 1999-2004 the VideoLAN team
00005  * $Id: clock.c 13227 2005-11-13 18:32:16Z dionoea $
00006  *
00007  * Authors: Christophe Massiot <[email protected]>
00008  *
00009  * This program is free software; you can redistribute it and/or modify
00010  * it under the terms of the GNU General Public License as published by
00011  * the Free Software Foundation; either version 2 of the License, or
00012  * (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software
00021  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00022  *****************************************************************************/
00023 
00024 /*****************************************************************************
00025  * Preamble
00026  *****************************************************************************/
00027 #include <stdlib.h>
00028 #include <vlc/vlc.h>
00029 
00030 #include <vlc/input.h>
00031 #include "input_internal.h"
00032 
00033 /*
00034  * DISCUSSION : SYNCHRONIZATION METHOD
00035  *
00036  * In some cases we can impose the pace of reading (when reading from a
00037  * file or a pipe), and for the synchronization we simply sleep() until
00038  * it is time to deliver the packet to the decoders. When reading from
00039  * the network, we must be read at the same pace as the server writes,
00040  * otherwise the kernel's buffer will trash packets. The risk is now to
00041  * overflow the input buffers in case the server goes too fast, that is
00042  * why we do these calculations :
00043  *
00044  * We compute a mean for the pcr because we want to eliminate the
00045  * network jitter and keep the low frequency variations. The mean is
00046  * in fact a low pass filter and the jitter is a high frequency signal
00047  * that is why it is eliminated by the filter/average.
00048  *
00049  * The low frequency variations enable us to synchronize the client clock
00050  * with the server clock because they represent the time variation between
00051  * the 2 clocks. Those variations (ie the filtered pcr) are used to compute
00052  * the presentation dates for the audio and video frames. With those dates
00053  * we can decode (or trash) the MPEG2 stream at "exactly" the same rate
00054  * as it is sent by the server and so we keep the synchronization between
00055  * the server and the client.
00056  *
00057  * It is a very important matter if you want to avoid underflow or overflow
00058  * in all the FIFOs, but it may be not enough.
00059  */
00060 
00061 /* p_input->i_cr_average : Maximum number of samples used to compute the
00062  * dynamic average value.
00063  * We use the following formula :
00064  * new_average = (old_average * c_average + new_sample_value) / (c_average +1)
00065  */
00066 
00067 
00068 static void ClockNewRef( input_clock_t * p_pgrm,
00069                          mtime_t i_clock, mtime_t i_sysdate );
00070 
00071 /*****************************************************************************
00072  * Constants
00073  *****************************************************************************/
00074 
00075 /* Maximum gap allowed between two CRs. */
00076 #define CR_MAX_GAP 2000000
00077 
00078 /* Latency introduced on DVDs with CR == 0 on chapter change - this is from
00079  * my dice --Meuuh */
00080 #define CR_MEAN_PTS_GAP 300000
00081 
00082 /*****************************************************************************
00083  * ClockToSysdate: converts a movie clock to system date
00084  *****************************************************************************/
00085 static mtime_t ClockToSysdate( input_thread_t *p_input,
00086                                input_clock_t *cl, mtime_t i_clock )
00087 {
00088     mtime_t     i_sysdate = 0;
00089 
00090     if( cl->i_synchro_state == SYNCHRO_OK )
00091     {
00092         i_sysdate = (mtime_t)(i_clock - cl->cr_ref)
00093                         * (mtime_t)p_input->i_rate
00094                         * (mtime_t)300;
00095         i_sysdate /= 27;
00096         i_sysdate /= 1000;
00097         i_sysdate += (mtime_t)cl->sysdate_ref;
00098     }
00099 
00100     return( i_sysdate );
00101 }
00102 
00103 /*****************************************************************************
00104  * ClockCurrent: converts current system date to clock units
00105  *****************************************************************************
00106  * Caution : the synchro state must be SYNCHRO_OK for this to operate.
00107  *****************************************************************************/
00108 static mtime_t ClockCurrent( input_thread_t *p_input,
00109                              input_clock_t *cl )
00110 {
00111     return( (mdate() - cl->sysdate_ref) * 27 * INPUT_RATE_DEFAULT
00112              / p_input->i_rate / 300
00113              + cl->cr_ref );
00114 }
00115 
00116 /*****************************************************************************
00117  * ClockNewRef: writes a new clock reference
00118  *****************************************************************************/
00119 static void ClockNewRef( input_clock_t *cl,
00120                          mtime_t i_clock, mtime_t i_sysdate )
00121 {
00122     cl->cr_ref = i_clock;
00123     cl->sysdate_ref = i_sysdate ;
00124 }
00125 
00126 /*****************************************************************************
00127  * input_ClockInit: reinitializes the clock reference after a stream
00128  *                  discontinuity
00129  *****************************************************************************/
00130 void input_ClockInit( input_clock_t *cl, vlc_bool_t b_master, int i_cr_average )
00131 {
00132     cl->i_synchro_state = SYNCHRO_START;
00133 
00134     cl->last_cr = 0;
00135     cl->last_pts = 0;
00136     cl->last_sysdate = 0;
00137     cl->cr_ref = 0;
00138     cl->sysdate_ref = 0;
00139     cl->delta_cr = 0;
00140     cl->i_delta_cr_residue = 0;
00141 
00142     cl->i_cr_average = i_cr_average;
00143 
00144     cl->b_master = b_master;
00145 }
00146 
00147 #if 0
00148 /*****************************************************************************
00149  * input_ClockManageControl: handles the messages from the interface
00150  *****************************************************************************
00151  * Returns UNDEF_S if nothing happened, PAUSE_S if the stream was paused
00152  *****************************************************************************/
00153 int input_ClockManageControl( input_thread_t * p_input,
00154                                input_clock_t *cl, mtime_t i_clock )
00155 {
00156 #if 0
00157     vlc_value_t val;
00158     int i_return_value = UNDEF_S;
00159 
00160     vlc_mutex_lock( &p_input->stream.stream_lock );
00161 
00162     if( p_input->stream.i_new_status == PAUSE_S )
00163     {
00164         int i_old_status;
00165 
00166         vlc_mutex_lock( &p_input->stream.control.control_lock );
00167         i_old_status = p_input->stream.control.i_status;
00168         p_input->stream.control.i_status = PAUSE_S;
00169         vlc_mutex_unlock( &p_input->stream.control.control_lock );
00170 
00171         vlc_cond_wait( &p_input->stream.stream_wait,
00172                        &p_input->stream.stream_lock );
00173         ClockNewRef( p_pgrm, i_clock, p_pgrm->last_pts > mdate() ?
00174                                       p_pgrm->last_pts : mdate() );
00175 
00176         if( p_input->stream.i_new_status == PAUSE_S )
00177         {
00178             /* PAUSE_S undoes the pause state: Return to old state. */
00179             vlc_mutex_lock( &p_input->stream.control.control_lock );
00180             p_input->stream.control.i_status = i_old_status;
00181             vlc_mutex_unlock( &p_input->stream.control.control_lock );
00182 
00183             p_input->stream.i_new_status = UNDEF_S;
00184             p_input->stream.i_new_rate = UNDEF_S;
00185         }
00186 
00187         /* We handle i_new_status != PAUSE_S below... */
00188 
00189         i_return_value = PAUSE_S;
00190     }
00191 
00192     if( p_input->stream.i_new_status != UNDEF_S )
00193     {
00194         vlc_mutex_lock( &p_input->stream.control.control_lock );
00195 
00196         p_input->stream.control.i_status = p_input->stream.i_new_status;
00197 
00198         ClockNewRef( p_pgrm, i_clock,
00199                      ClockToSysdate( p_input, p_pgrm, i_clock ) );
00200 
00201         if( p_input->stream.control.i_status == PLAYING_S )
00202         {
00203             p_input->stream.control.i_rate = DEFAULT_RATE;
00204             p_input->stream.control.b_mute = 0;
00205         }
00206         else
00207         {
00208             p_input->stream.control.i_rate = p_input->stream.i_new_rate;
00209             p_input->stream.control.b_mute = 1;
00210 
00211             /* Feed the audio decoders with a NULL packet to avoid
00212              * discontinuities. */
00213             input_EscapeAudioDiscontinuity( p_input );
00214         }
00215 
00216         val.i_int = p_input->stream.control.i_rate;
00217         var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
00218 
00219         val.i_int = p_input->stream.control.i_status;
00220         var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
00221 
00222         p_input->stream.i_new_status = UNDEF_S;
00223         p_input->stream.i_new_rate = UNDEF_S;
00224 
00225         vlc_mutex_unlock( &p_input->stream.control.control_lock );
00226     }
00227 
00228     vlc_mutex_unlock( &p_input->stream.stream_lock );
00229 
00230     return( i_return_value );
00231 #endif
00232     return UNDEF_S;
00233 }
00234 #endif
00235 
00236 /*****************************************************************************
00237  * input_ClockSetPCR: manages a clock reference
00238  *****************************************************************************/
00239 void input_ClockSetPCR( input_thread_t *p_input,
00240                         input_clock_t *cl, mtime_t i_clock )
00241 {
00242     if( ( cl->i_synchro_state != SYNCHRO_OK ) ||
00243         ( i_clock == 0 && cl->last_cr != 0 ) )
00244     {
00245         /* Feed synchro with a new reference point. */
00246         ClockNewRef( cl, i_clock,
00247                      cl->last_pts + CR_MEAN_PTS_GAP > mdate() ?
00248                      cl->last_pts + CR_MEAN_PTS_GAP : mdate() );
00249         cl->i_synchro_state = SYNCHRO_OK;
00250 
00251         if( p_input->b_can_pace_control && cl->b_master )
00252         {
00253             cl->last_cr = i_clock;
00254             if( !p_input->b_out_pace_control )
00255             {
00256                 mtime_t i_wakeup = ClockToSysdate( p_input, cl, i_clock );
00257                 while( (i_wakeup - mdate()) / CLOCK_FREQ > 1 )
00258                 {
00259                     msleep( CLOCK_FREQ );
00260                     if( p_input->b_die ) i_wakeup = mdate();
00261                 }
00262                 mwait( i_wakeup );
00263             }
00264         }
00265         else
00266         {
00267             cl->last_cr = 0;
00268             cl->last_sysdate = 0;
00269             cl->delta_cr = 0;
00270             cl->i_delta_cr_residue = 0;
00271         }
00272     }
00273     else
00274     {
00275         if ( cl->last_cr != 0 &&
00276                (    (cl->last_cr - i_clock) > CR_MAX_GAP
00277                  || (cl->last_cr - i_clock) < - CR_MAX_GAP ) )
00278         {
00279             /* Stream discontinuity, for which we haven't received a
00280              * warning from the stream control facilities (dd-edited
00281              * stream ?). */
00282             msg_Warn( p_input, "clock gap, unexpected stream discontinuity" );
00283             input_ClockInit( cl, cl->b_master, cl->i_cr_average );
00284             /* FIXME needed ? */
00285 #if 0
00286             input_EscapeDiscontinuity( p_input );
00287 #endif
00288         }
00289 
00290         cl->last_cr = i_clock;
00291 
00292         if( p_input->b_can_pace_control && cl->b_master )
00293         {
00294             /* Wait a while before delivering the packets to the decoder.
00295              * In case of multiple programs, we arbitrarily follow the
00296              * clock of the selected program. */
00297             if( !p_input->b_out_pace_control )
00298             {
00299                 mtime_t i_wakeup = ClockToSysdate( p_input, cl, i_clock );
00300                 while( (i_wakeup - mdate()) / CLOCK_FREQ > 1 )
00301                 {
00302                     msleep( CLOCK_FREQ );
00303                     if( p_input->b_die ) i_wakeup = mdate();
00304                 }
00305                 mwait( i_wakeup );
00306             }
00307             /* FIXME Not needed anymore ? */
00308 #if 0
00309             /* Now take into account interface changes. */
00310             input_ClockManageControl( p_input, cl, i_clock );
00311 #endif
00312         }
00313         else if ( mdate() - cl->last_sysdate > 200000 )
00314         {
00315             /* Smooth clock reference variations. */
00316             mtime_t i_extrapoled_clock = ClockCurrent( p_input, cl );
00317             mtime_t delta_cr;
00318 
00319             /* Bresenham algorithm to smooth variations. */
00320             delta_cr = ( cl->delta_cr * (cl->i_cr_average - 1)
00321                                + ( i_extrapoled_clock - i_clock )
00322                                + cl->i_delta_cr_residue )
00323                            / cl->i_cr_average;
00324             cl->i_delta_cr_residue = ( cl->delta_cr * (cl->i_cr_average - 1)
00325                                        + ( i_extrapoled_clock - i_clock )
00326                                        + cl->i_delta_cr_residue )
00327                                     % cl->i_cr_average;
00328             cl->delta_cr = delta_cr;
00329             cl->last_sysdate = mdate();
00330         }
00331     }
00332 }
00333 
00334 /*****************************************************************************
00335  * input_ClockGetTS: manages a PTS or DTS
00336  *****************************************************************************/
00337 mtime_t input_ClockGetTS( input_thread_t * p_input,
00338                           input_clock_t *cl, mtime_t i_ts )
00339 {
00340     if( cl->i_synchro_state != SYNCHRO_OK )
00341         return 0;
00342 
00343     cl->last_pts = ClockToSysdate( p_input, cl, i_ts + cl->delta_cr );
00344     return cl->last_pts + p_input->i_pts_delay;
00345 }
00346 

Generated on Tue Dec 20 10:14:59 2005 for vlc-0.8.4a by  doxygen 1.4.2