1 /*****************************************************************************
2 * synchro.c : frame dropping routines
3 *****************************************************************************
4 * Copyright (C) 1999-2005 VLC authors and VideoLAN
6 * Authors: Christophe Massiot <massiot@via.ecp.fr>
7 * Samuel Hocevar <sam@via.ecp.fr>
8 * Jean-Marc Dressler <polux@via.ecp.fr>
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU Lesser General Public License as published by
12 * the Free Software Foundation; either version 2.1 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software Foundation,
22 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23 *****************************************************************************/
26 * DISCUSSION : How to Write an efficient Frame-Dropping Algorithm
29 * This implementation is based on mathematical and statistical
30 * developments. Older implementations used an enslavement, considering
31 * that if we're late when reading an I picture, we will decode one frame
32 * less. It had a tendency to derive, and wasn't responsive enough, which
33 * would have caused trouble with the stream control stuff.
35 * 1. Structure of a picture stream
36 * =============================
37 * Between 2 I's, we have for instance :
38 * I B P B P B P B P B P B I
39 * t0 t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12
40 * Please bear in mind that B's and IP's will be inverted when displaying
41 * (decoding order != presentation order). Thus, t1 < t0.
45 * t[0..12] : Presentation timestamps of pictures 0..12.
46 * t : Current timestamp, at the moment of the decoding.
47 * T : Picture period, T = 1/frame_rate.
48 * tau[I,P,B] : Mean time to decode an [I,P,B] picture.
49 * tauYUV : Mean time to render a picture (given by the video_output).
50 * tau´[I,P,B] = 2 * tau[I,P,B] + tauYUV
51 * : Mean time + typical difference (estimated to tau/2, that
52 * needs to be confirmed) + render time.
53 * DELTA : A given error margin.
55 * 3. General considerations
56 * ======================
57 * We define three types of machines :
58 * 14T > tauI : machines capable of decoding all I pictures
59 * 2T > tauP : machines capable of decoding all P pictures
60 * T > tauB : machines capable of decoding all B pictures
62 * 4. Decoding of an I picture
63 * ========================
64 * On fast machines, we decode all I's.
66 * We can decode an I picture if we simply have enough time to decode it
68 * t0 - t > tau´I + DELTA
70 * 5. Decoding of a P picture
71 * =======================
72 * On fast machines, we decode all P's.
74 * First criterion : have time to decode it.
75 * t2 - t > tau´P + DELTA
77 * Second criterion : it shouldn't prevent us from displaying the forthcoming
78 * I picture, which is more important.
79 * t12 - t > tau´P + tau´I + DELTA
81 * 6. Decoding of a B picture
82 * =======================
83 * On fast machines, we decode all B's. Otherwise :
84 * t1 - t > tau´B + DELTA
85 * Since the next displayed I or P is already decoded, we don't have to
88 * I hope you will have a pleasant flight and do not forget your life
90 * --Meuuh (2000-12-29)
93 /*****************************************************************************
95 *****************************************************************************/
100 #include <vlc_common.h>
101 #include <vlc_codec.h>
109 * Print a debug log message if not silenced
110 * using the `quiet-synchro` option
112 #define synchro_msg_Dbg(p_this, ...) do { \
113 if( !p_this->b_quiet ) \
114 msg_Generic(p_this->p_dec, VLC_MSG_DBG, __VA_ARGS__); \
118 * Print a warning log message if not silenced
119 * using the `quiet-synchro` option
121 #define synchro_msg_Warn(p_this, ...) do { \
122 if( !p_this->b_quiet ) \
123 msg_Generic(p_this->p_dec, VLC_MSG_WARN, __VA_ARGS__); \
130 #define MAX_PIC_AVERAGE 8
132 struct decoder_synchro_t
142 /* date of the beginning of the decoding of the current picture */
143 vlc_tick_t decoding_start
;
145 /* stream properties */
146 unsigned int i_n_p
, i_n_b
;
148 /* decoding values */
149 vlc_tick_t p_tau
[4]; /* average decoding durations */
150 unsigned int pi_meaningful
[4]; /* number of durations read */
152 /* render_time filled by SynchroChoose() */
153 vlc_tick_t i_render_time
;
156 int i_nb_ref
; /* Number of reference pictures */
157 int i_dec_nb_ref
; /* Number of reference pictures we'll *
158 * have if we decode the current pic */
159 int i_trash_nb_ref
; /* Number of reference pictures we'll *
160 * have if we trash the current pic */
161 unsigned int i_eta_p
, i_eta_b
;
162 vlc_tick_t backward_pts
, current_pts
;
163 int i_current_period
; /* period to add to the next picture */
164 int i_backward_period
; /* period to add after the next
166 * (backward_period * period / 2) */
169 unsigned int i_trashed_pic
, i_not_chosen_pic
, i_pic
;
173 #define DELTA VLC_TICK_FROM_MS(75) /* 3s/40 */
174 #define MAX_VALID_TAU VLC_TICK_FROM_MS(300)
176 #define DEFAULT_NB_P 5
177 #define DEFAULT_NB_B 1
179 /*****************************************************************************
180 * decoder_SynchroInit : You know what ?
181 *****************************************************************************/
182 decoder_synchro_t
* decoder_SynchroInit( decoder_t
*p_dec
, int i_frame_rate
)
184 decoder_synchro_t
* p_synchro
= calloc( 1, sizeof(*p_synchro
) );
188 p_synchro
->p_dec
= p_dec
;
189 p_synchro
->b_no_skip
= !var_InheritBool( p_dec
, "skip-frames" );
190 p_synchro
->b_quiet
= var_InheritBool( p_dec
, "quiet-synchro" );
192 /* We use a fake stream pattern, which is often right. */
193 p_synchro
->i_n_p
= p_synchro
->i_eta_p
= DEFAULT_NB_P
;
194 p_synchro
->i_n_b
= p_synchro
->i_eta_b
= DEFAULT_NB_B
;
195 memset( p_synchro
->p_tau
, 0, 4 * sizeof(vlc_tick_t
) );
196 memset( p_synchro
->pi_meaningful
, 0, 4 * sizeof(unsigned int) );
197 p_synchro
->i_nb_ref
= 0;
198 p_synchro
->i_trash_nb_ref
= p_synchro
->i_dec_nb_ref
= 0;
199 p_synchro
->current_pts
= 1,
200 p_synchro
->backward_pts
= VLC_TICK_INVALID
;
201 p_synchro
->i_current_period
= p_synchro
->i_backward_period
= 0;
202 p_synchro
->i_trashed_pic
= p_synchro
->i_not_chosen_pic
=
203 p_synchro
->i_pic
= 0;
205 p_synchro
->i_frame_rate
= i_frame_rate
;
210 /*****************************************************************************
211 * decoder_SynchroRelease : You know what ?
212 *****************************************************************************/
213 void decoder_SynchroRelease( decoder_synchro_t
* p_synchro
)
218 /*****************************************************************************
219 * decoder_SynchroReset : Reset the reference picture counter
220 *****************************************************************************/
221 void decoder_SynchroReset( decoder_synchro_t
* p_synchro
)
223 p_synchro
->i_nb_ref
= 0;
224 p_synchro
->i_trash_nb_ref
= p_synchro
->i_dec_nb_ref
= 0;
227 /*****************************************************************************
228 * decoder_SynchroChoose : Decide whether we will decode a picture or not
229 *****************************************************************************/
230 bool decoder_SynchroChoose( decoder_synchro_t
* p_synchro
, int i_coding_type
,
231 vlc_tick_t i_render_time
, bool b_low_delay
)
233 #define TAU_PRIME( coding_type ) (p_synchro->p_tau[(coding_type)] \
234 + (p_synchro->p_tau[(coding_type)] >> 1) \
235 + p_synchro->i_render_time)
236 #define S (*p_synchro)
237 vlc_tick_t now
, period
;
240 float i_current_rate
;
242 if ( p_synchro
->b_no_skip
)
245 i_current_rate
= decoder_GetDisplayRate( p_synchro
->p_dec
);
247 now
= vlc_tick_now();
248 period
= vlc_tick_from_samples(1001, p_synchro
->i_frame_rate
) * i_current_rate
;
250 p_synchro
->i_render_time
= i_render_time
;
252 switch( i_coding_type
)
257 pts
= decoder_GetDisplayDate( p_synchro
->p_dec
, now
, S
.current_pts
);
259 else if( S
.backward_pts
!= VLC_TICK_INVALID
)
261 pts
= decoder_GetDisplayDate( p_synchro
->p_dec
, now
, S
.backward_pts
);
265 /* displaying order : B B P B B I
267 * | +- current picture
270 pts
= decoder_GetDisplayDate( p_synchro
->p_dec
, now
, S
.current_pts
) + period
* (S
.i_n_b
+ 2);
273 if( (1 + S
.i_n_p
* (S
.i_n_b
+ 1)) * period
> S
.p_tau
[I_CODING_TYPE
] )
279 b_decode
= (pts
- now
) > (TAU_PRIME(I_CODING_TYPE
) + DELTA
);
281 if( pts
== VLC_TICK_INVALID
)
286 synchro_msg_Warn( p_synchro
,
287 "synchro trashing I (%"PRId64
")", pts
- now
);
294 pts
= decoder_GetDisplayDate( p_synchro
->p_dec
, now
, S
.current_pts
);
296 else if( S
.backward_pts
!= VLC_TICK_INVALID
)
298 pts
= decoder_GetDisplayDate( p_synchro
->p_dec
, now
, S
.backward_pts
);
302 pts
= decoder_GetDisplayDate( p_synchro
->p_dec
, now
, S
.current_pts
+ period
* (S
.i_n_b
+ 1) );
305 if( p_synchro
->i_nb_ref
< 1 )
309 else if( (1 + S
.i_n_p
* (S
.i_n_b
+ 1)) * period
>
310 S
.p_tau
[I_CODING_TYPE
] )
312 if( (S
.i_n_b
+ 1) * period
> S
.p_tau
[P_CODING_TYPE
] )
314 /* Security in case we're _really_ late */
315 b_decode
= (pts
- now
> 0);
319 b_decode
= (pts
- now
) > (TAU_PRIME(P_CODING_TYPE
) + DELTA
);
321 b_decode
&= (pts
- now
323 * ( (S
.i_n_p
- S
.i_eta_p
) * (1 + S
.i_n_b
) - 1 ))
324 > (TAU_PRIME(P_CODING_TYPE
)
325 + TAU_PRIME(I_CODING_TYPE
) + DELTA
);
332 if( p_synchro
->i_nb_ref
>= 1 && pts
== VLC_TICK_INVALID
)
337 pts
= decoder_GetDisplayDate( p_synchro
->p_dec
, now
, S
.current_pts
);
339 if( p_synchro
->i_nb_ref
< 2 )
343 else if( (S
.i_n_b
+ 1) * period
> S
.p_tau
[P_CODING_TYPE
] )
345 b_decode
= (pts
- now
) > (TAU_PRIME(B_CODING_TYPE
) + DELTA
);
351 if( p_synchro
->i_nb_ref
>= 2 && pts
== VLC_TICK_INVALID
)
358 S
.i_not_chosen_pic
++;
365 /*****************************************************************************
366 * decoder_SynchroTrash : Update counters when we trash a picture
367 *****************************************************************************/
368 void decoder_SynchroTrash( decoder_synchro_t
* p_synchro
)
370 p_synchro
->i_trashed_pic
++;
371 p_synchro
->i_nb_ref
= p_synchro
->i_trash_nb_ref
;
374 /*****************************************************************************
375 * decoder_SynchroDecode : Update timers when we decide to decode a picture
376 *****************************************************************************/
377 void decoder_SynchroDecode( decoder_synchro_t
* p_synchro
)
379 p_synchro
->decoding_start
= vlc_tick_now();
380 p_synchro
->i_nb_ref
= p_synchro
->i_dec_nb_ref
;
383 /*****************************************************************************
384 * decoder_SynchroEnd : Called when the image is totally decoded
385 *****************************************************************************/
386 void decoder_SynchroEnd( decoder_synchro_t
* p_synchro
, int i_coding_type
,
394 tau
= vlc_tick_now() - p_synchro
->decoding_start
;
396 /* If duration too high, something happened (pause ?), so don't
397 * take it into account. */
398 if( tau
< 3 * p_synchro
->p_tau
[i_coding_type
] ||
399 ( !p_synchro
->pi_meaningful
[i_coding_type
] && tau
< MAX_VALID_TAU
) )
401 /* Mean with average tau, to ensure stability. */
402 p_synchro
->p_tau
[i_coding_type
] =
403 (p_synchro
->pi_meaningful
[i_coding_type
]
404 * p_synchro
->p_tau
[i_coding_type
] + tau
)
405 / (p_synchro
->pi_meaningful
[i_coding_type
] + 1);
406 if( p_synchro
->pi_meaningful
[i_coding_type
] < MAX_PIC_AVERAGE
)
408 p_synchro
->pi_meaningful
[i_coding_type
]++;
413 /*****************************************************************************
414 * decoder_SynchroDate : When an image has been decoded, ask for its date
415 *****************************************************************************/
416 vlc_tick_t
decoder_SynchroDate( decoder_synchro_t
* p_synchro
)
418 /* No need to lock, since PTS are only used by the video parser. */
419 return p_synchro
->current_pts
;
422 /*****************************************************************************
423 * decoder_SynchroNewPicture: Update stream structure and PTS
424 *****************************************************************************/
425 void decoder_SynchroNewPicture( decoder_synchro_t
* p_synchro
, int i_coding_type
,
426 int i_repeat_field
, vlc_tick_t next_pts
,
427 vlc_tick_t next_dts
, bool b_low_delay
)
429 vlc_tick_t period
= vlc_tick_from_samples(1001, p_synchro
->i_frame_rate
);
431 vlc_tick_t now
= vlc_tick_now();
434 switch( i_coding_type
)
437 if( p_synchro
->i_eta_p
&& p_synchro
->i_eta_p
!= p_synchro
->i_n_p
)
440 synchro_msg_Dbg( p_synchro
,
441 "stream periodicity changed from P[%d] to P[%d]",
442 p_synchro
->i_n_p
, p_synchro
->i_eta_p
);
444 p_synchro
->i_n_p
= p_synchro
->i_eta_p
;
446 p_synchro
->i_eta_p
= p_synchro
->i_eta_b
= 0;
447 p_synchro
->i_trash_nb_ref
= 0;
448 if( p_synchro
->i_nb_ref
< 2 )
449 p_synchro
->i_dec_nb_ref
= p_synchro
->i_nb_ref
+ 1;
451 p_synchro
->i_dec_nb_ref
= p_synchro
->i_nb_ref
;
454 synchro_msg_Dbg( p_synchro
, "I(%"PRId64
") P(%"PRId64
")[%d] B(%"PRId64
")"
455 "[%d] YUV(%"PRId64
") : trashed %d:%d/%d",
456 p_synchro
->p_tau
[I_CODING_TYPE
],
457 p_synchro
->p_tau
[P_CODING_TYPE
],
459 p_synchro
->p_tau
[B_CODING_TYPE
],
461 p_synchro
->i_render_time
,
462 p_synchro
->i_not_chosen_pic
,
463 p_synchro
->i_trashed_pic
-
464 p_synchro
->i_not_chosen_pic
,
466 p_synchro
->i_trashed_pic
= p_synchro
->i_not_chosen_pic
467 = p_synchro
->i_pic
= 0;
469 if( p_synchro
->i_pic
>= 100 )
471 if( p_synchro
->i_trashed_pic
!= 0 )
472 synchro_msg_Dbg( p_synchro
, "decoded %d/%d pictures",
474 - p_synchro
->i_trashed_pic
,
476 p_synchro
->i_trashed_pic
= p_synchro
->i_not_chosen_pic
477 = p_synchro
->i_pic
= 0;
483 p_synchro
->i_eta_p
++;
484 if( p_synchro
->i_eta_b
485 && p_synchro
->i_eta_b
!= p_synchro
->i_n_b
)
488 synchro_msg_Dbg( p_synchro
,
489 "stream periodicity changed from B[%d] to B[%d]",
490 p_synchro
->i_n_b
, p_synchro
->i_eta_b
);
492 p_synchro
->i_n_b
= p_synchro
->i_eta_b
;
494 p_synchro
->i_eta_b
= 0;
495 p_synchro
->i_dec_nb_ref
= 2;
496 p_synchro
->i_trash_nb_ref
= 0;
500 p_synchro
->i_eta_b
++;
501 p_synchro
->i_dec_nb_ref
= p_synchro
->i_trash_nb_ref
502 = p_synchro
->i_nb_ref
;
506 p_synchro
->current_pts
+= p_synchro
->i_current_period
509 #define PTS_THRESHOLD (period >> 2)
510 if( i_coding_type
== B_CODING_TYPE
|| b_low_delay
)
512 /* A video frame can be displayed 1, 2 or 3 times, according to
513 * repeat_first_field, top_field_first, progressive_sequence and
514 * progressive_frame. */
515 p_synchro
->i_current_period
= i_repeat_field
;
517 if( next_pts
!= VLC_TICK_INVALID
)
519 if( next_pts
- p_synchro
->current_pts
521 || p_synchro
->current_pts
- next_pts
524 synchro_msg_Warn( p_synchro
, "decoder synchro warning: pts != "
525 "current_date (%"PRId64
")",
526 p_synchro
->current_pts
529 p_synchro
->current_pts
= next_pts
;
534 p_synchro
->i_current_period
= p_synchro
->i_backward_period
;
535 p_synchro
->i_backward_period
= i_repeat_field
;
537 if( p_synchro
->backward_pts
!= VLC_TICK_INVALID
)
539 if( next_dts
!= VLC_TICK_INVALID
&&
540 (next_dts
- p_synchro
->backward_pts
542 || p_synchro
->backward_pts
- next_dts
545 synchro_msg_Warn( p_synchro
, "backward_pts != dts (%"PRId64
")",
547 - p_synchro
->backward_pts
);
549 if( p_synchro
->backward_pts
- p_synchro
->current_pts
551 || p_synchro
->current_pts
- p_synchro
->backward_pts
554 synchro_msg_Warn( p_synchro
,
555 "backward_pts != current_pts (%"PRId64
")",
556 p_synchro
->current_pts
557 - p_synchro
->backward_pts
);
559 p_synchro
->current_pts
= p_synchro
->backward_pts
;
560 p_synchro
->backward_pts
= VLC_TICK_INVALID
;
562 else if( next_dts
!= VLC_TICK_INVALID
)
564 if( next_dts
- p_synchro
->current_pts
566 || p_synchro
->current_pts
- next_dts
569 synchro_msg_Warn( p_synchro
, "dts != current_pts (%"PRId64
")",
570 p_synchro
->current_pts
573 /* By definition of a DTS. */
574 p_synchro
->current_pts
= next_dts
;
577 if( next_pts
!= VLC_TICK_INVALID
)
579 /* Store the PTS for the next time we have to date an I picture. */
580 p_synchro
->backward_pts
= next_pts
;
586 /* Removed for incompatibility with slow motion */
587 if( p_synchro
->current_pts
+ DEFAULT_PTS_DELAY
< now
)
589 /* We cannot be _that_ late, something must have happened, reinit
591 synchro_msg_Warn( p_synchro
, "PTS << now (%"PRId64
"), resetting",
592 now
- p_synchro
->current_pts
- DEFAULT_PTS_DELAY
);
593 p_synchro
->current_pts
= now
+ DEFAULT_PTS_DELAY
;
595 if( p_synchro
->backward_pts
!= VLC_TICK_INVALID
596 && p_synchro
->backward_pts
+ DEFAULT_PTS_DELAY
< now
)
599 p_synchro
->backward_pts
= VLC_TICK_INVALID
;