]> git.sesse.net Git - vlc/blob - src/input/input_pcr.c
Encore un commit venu tout droit des abysses de l'enfer, d�sol� pour
[vlc] / src / input / input_pcr.c
1 /*****************************************************************************
2  * pcr.c: PCR management
3  * Manages structures containing PCR information.
4  *****************************************************************************
5  * Copyright (C) 1999, 2000 VideoLAN
6  *
7  * Authors:
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public
20  * License along with this program; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  *****************************************************************************/
24
25 /*****************************************************************************
26  * Preamble
27  *****************************************************************************/
28 #include <sys/types.h>                        /* on BSD, uio.h needs types.h */
29 #include <sys/uio.h>                                            /* "input.h" */
30 #include <stdlib.h>                              /* atoi(), malloc(), free() */
31 #include <netinet/in.h>                                           /* ntohl() */
32
33 #include "config.h"
34 #include "common.h"
35 #include "mtime.h"
36 #include "threads.h"
37 #include "debug.h"
38 #include "input.h"
39 #include "intf_msg.h"
40 #include "input_pcr.h"
41
42 /* Note:
43  *
44  *   SYNCHRONIZATION METHOD
45  *
46  *   We compute an average for the pcr because we want to eliminate the
47  *   network jitter and keep the low frequency variations. The average is
48  *   in fact a low pass filter and the jitter is a high frequency signal
49  *   that is why it is eliminated by the filter/average.
50  *
51  *   The low frequency variations enable us to synchronize the client clock
52  *   with the server clock because they represent the time variation between
53  *   the 2 clocks. Those variations (ie the filtered pcr) are used to compute
54  *   the presentation dates for the audio and video frames. With those dates
55  *   we can decoding (or trashing) the MPEG2 stream at "exactly" the same rate
56  *   as it is sent by the server and so we keep the synchronization between
57  *   the server and the client.
58  *
59  *   It is a very important matter if you want to avoid underflow or overflow
60  *   in all the FIFOs, but it may be not enough.
61  *
62  */
63
64 /*****************************************************************************
65  * input_PcrReInit : Reinitialize the pcr_descriptor
66  *****************************************************************************/
67 void input_PcrReInit( input_thread_t *p_input )
68 {
69     ASSERT( p_input );
70
71     p_input->p_pcr->delta_pcr       = 0;
72     p_input->p_pcr->last_pcr        = 0;
73     p_input->p_pcr->c_average_count = 0;
74 }
75
76 /*****************************************************************************
77  * input_PcrInit : Initialize PCR decoder
78  *****************************************************************************/
79 int input_PcrInit( input_thread_t *p_input )
80 {
81     ASSERT( p_input );
82
83     if( (p_input->p_pcr = malloc(sizeof(pcr_descriptor_t))) == NULL )
84     {
85         return( -1 );
86     }
87     input_PcrReInit(p_input);
88     p_input->p_pcr->i_synchro_state = SYNCHRO_NOT_STARTED;
89
90     return( 0 );
91 }
92
93 /*****************************************************************************
94  * input_PcrDecode : Decode a PCR frame
95  *****************************************************************************/
96 void input_PcrDecode( input_thread_t *p_input, es_descriptor_t *p_es,
97                       u8* p_pcr_data )
98 {
99     mtime_t pcr_time, sys_time, delta_pcr;
100     pcr_descriptor_t *p_pcr;
101
102     ASSERT( p_pcr_data );
103     ASSERT( p_input );
104     ASSERT( p_es );
105
106     p_pcr = p_input->p_pcr;
107
108     /* Convert the PCR in microseconde
109      * WARNING: do not remove the casts in the following calculation ! */
110     pcr_time  = ( (( (mtime_t)U32_AT((u32*)p_pcr_data) << 1 ) | ( p_pcr_data[4] >> 7 )) * 300 ) / 27;
111     sys_time  = mdate();
112     delta_pcr = sys_time - pcr_time;
113
114     if( p_es->b_discontinuity ||
115         ( p_pcr->last_pcr != 0 &&
116               (    (p_pcr->last_pcr - pcr_time) > PCR_MAX_GAP
117                 || (p_pcr->last_pcr - pcr_time) < - PCR_MAX_GAP ) ) )
118     {
119         intf_DbgMsg("input debug: input_PcrReInit()\n");
120         input_PcrReInit(p_input);
121         p_pcr->i_synchro_state = SYNCHRO_REINIT;
122         p_es->b_discontinuity = 0;
123     }
124     p_pcr->last_pcr = pcr_time;
125
126     if( p_pcr->c_average_count == PCR_MAX_AVERAGE_COUNTER )
127     {
128         p_pcr->delta_pcr =
129             ( delta_pcr + (p_pcr->delta_pcr * (PCR_MAX_AVERAGE_COUNTER-1)) )
130             / PCR_MAX_AVERAGE_COUNTER;
131     }
132     else
133     {
134         p_pcr->delta_pcr =
135             ( delta_pcr + (p_pcr->delta_pcr * p_pcr->c_average_count) )
136             / ( p_pcr->c_average_count + 1 );
137         p_pcr->c_average_count++;
138     }
139
140     if( p_pcr->i_synchro_state == SYNCHRO_NOT_STARTED )
141     {
142         p_pcr->i_synchro_state = SYNCHRO_START;
143     }
144 }
145
146 /*****************************************************************************
147  * input_PcrEnd : Clean PCR structures before dying
148  *****************************************************************************/
149 void input_PcrEnd( input_thread_t *p_input )
150 {
151     ASSERT( p_input );
152
153     free( p_input->p_pcr );
154 }