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

vout_synchro.c

00001 /*****************************************************************************
00002  * vout_synchro.c : frame dropping routines
00003  *****************************************************************************
00004  * Copyright (C) 1999-2005 the VideoLAN team
00005  * $Id: vout_synchro.c 11664 2005-07-09 06:17:09Z courmisch $
00006  *
00007  * Authors: Christophe Massiot <[email protected]>
00008  *          Samuel Hocevar <[email protected]>
00009  *          Jean-Marc Dressler <[email protected]>
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
00024  *****************************************************************************/
00025 
00026 /*
00027  * DISCUSSION : How to Write an efficient Frame-Dropping Algorithm
00028  * ==========
00029  *
00030  * This implementation is based on mathematical and statistical
00031  * developments. Older implementations used an enslavement, considering
00032  * that if we're late when reading an I picture, we will decode one frame
00033  * less. It had a tendancy to derive, and wasn't responsive enough, which
00034  * would have caused trouble with the stream control stuff.
00035  *
00036  * 1. Structure of a picture stream
00037  *    =============================
00038  * Between 2 I's, we have for instance :
00039  *    I   B   P   B   P   B   P   B   P   B   P   B   I
00040  *    t0  t1  t2  t3  t4  t5  t6  t7  t8  t9  t10 t11 t12
00041  * Please bear in mind that B's and IP's will be inverted when displaying
00042  * (decoding order != presentation order). Thus, t1 < t0.
00043  *
00044  * 2. Definitions
00045  *    ===========
00046  * t[0..12]     : Presentation timestamps of pictures 0..12.
00047  * t            : Current timestamp, at the moment of the decoding.
00048  * T            : Picture period, T = 1/frame_rate.
00049  * tau[I,P,B]   : Mean time to decode an [I,P,B] picture.
00050  * tauYUV       : Mean time to render a picture (given by the video_output).
00051  * tauŽ[I,P,B] = 2 * tau[I,P,B] + tauYUV
00052  *              : Mean time + typical difference (estimated to tau/2, that
00053  *                needs to be confirmed) + render time.
00054  * DELTA        : A given error margin.
00055  *
00056  * 3. General considerations
00057  *    ======================
00058  * We define three types of machines :
00059  *      14T > tauI : machines capable of decoding all I pictures
00060  *      2T > tauP  : machines capable of decoding all P pictures
00061  *      T > tauB   : machines capable of decoding all B pictures
00062  *
00063  * 4. Decoding of an I picture
00064  *    ========================
00065  * On fast machines, we decode all I's.
00066  * Otherwise :
00067  * We can decode an I picture if we simply have enough time to decode it
00068  * before displaying :
00069  *      t0 - t > tauŽI + DELTA
00070  *
00071  * 5. Decoding of a P picture
00072  *    =======================
00073  * On fast machines, we decode all P's.
00074  * Otherwise :
00075  * First criterion : have time to decode it.
00076  *      t2 - t > tauŽP + DELTA
00077  *
00078  * Second criterion : it shouldn't prevent us from displaying the forthcoming
00079  * I picture, which is more important.
00080  *      t12 - t > tauŽP + tauŽI + DELTA
00081  *
00082  * 6. Decoding of a B picture
00083  *    =======================
00084  * On fast machines, we decode all B's. Otherwise :
00085  *      t1 - t > tauŽB + DELTA
00086  * Since the next displayed I or P is already decoded, we don't have to
00087  * worry about it.
00088  *
00089  * I hope you will have a pleasant flight and do not forget your life
00090  * jacket.
00091  *                                                  --Meuuh (2000-12-29)
00092  */
00093 
00094 /*****************************************************************************
00095  * Preamble
00096  *****************************************************************************/
00097 #include <stdlib.h>                                                /* free() */
00098 #include <string.h>                                    /* memcpy(), memset() */
00099 
00100 #include <vlc/vlc.h>
00101 #include <vlc/vout.h>
00102 #include <vlc/input.h>
00103 
00104 #include "vout_synchro.h"
00105 
00106 /*
00107  * Local prototypes
00108  */
00109 
00110 /* Error margins */
00111 #define DELTA                   (int)(0.075*CLOCK_FREQ)
00112 #define MAX_VALID_TAU           (int)(0.3*CLOCK_FREQ)
00113 
00114 #define DEFAULT_NB_P            5
00115 #define DEFAULT_NB_B            1
00116 
00117 /*****************************************************************************
00118  * vout_SynchroInit : You know what ?
00119  *****************************************************************************/
00120 vout_synchro_t * __vout_SynchroInit( vlc_object_t * p_object,
00121                                      int i_frame_rate )
00122 {
00123     vout_synchro_t * p_synchro = vlc_object_create( p_object,
00124                                                   sizeof(vout_synchro_t) );
00125     if ( p_synchro == NULL )
00126     {
00127         msg_Err( p_object, "out of memory" );
00128         return NULL;
00129     }
00130     vlc_object_attach( p_synchro, p_object );
00131 
00132     p_synchro->b_no_skip = !config_GetInt( p_object, "skip-frames" );
00133     p_synchro->b_quiet = config_GetInt( p_object, "quiet-synchro" );
00134 
00135     /* We use a fake stream pattern, which is often right. */
00136     p_synchro->i_n_p = p_synchro->i_eta_p = DEFAULT_NB_P;
00137     p_synchro->i_n_b = p_synchro->i_eta_b = DEFAULT_NB_B;
00138     memset( p_synchro->p_tau, 0, 4 * sizeof(mtime_t) );
00139     memset( p_synchro->pi_meaningful, 0, 4 * sizeof(unsigned int) );
00140     p_synchro->i_nb_ref = 0;
00141     p_synchro->i_trash_nb_ref = p_synchro->i_dec_nb_ref = 0;
00142     p_synchro->current_pts = mdate() + DEFAULT_PTS_DELAY;
00143     p_synchro->backward_pts = 0;
00144     p_synchro->i_current_period = p_synchro->i_backward_period = 0;
00145     p_synchro->i_trashed_pic = p_synchro->i_not_chosen_pic =
00146         p_synchro->i_pic = 0;
00147 
00148     p_synchro->i_frame_rate = i_frame_rate;
00149 
00150     return p_synchro;
00151 }
00152 
00153 /*****************************************************************************
00154  * vout_SynchroRelease : You know what ?
00155  *****************************************************************************/
00156 void vout_SynchroRelease( vout_synchro_t * p_synchro )
00157 {
00158     vlc_object_detach( p_synchro );
00159     vlc_object_destroy( p_synchro );
00160 }
00161 
00162 /*****************************************************************************
00163  * vout_SynchroReset : Reset the reference picture counter
00164  *****************************************************************************/
00165 void vout_SynchroReset( vout_synchro_t * p_synchro )
00166 {
00167     p_synchro->i_nb_ref = 0;
00168     p_synchro->i_trash_nb_ref = p_synchro->i_dec_nb_ref = 0;
00169 }
00170 
00171 /*****************************************************************************
00172  * vout_SynchroChoose : Decide whether we will decode a picture or not
00173  *****************************************************************************/
00174 vlc_bool_t vout_SynchroChoose( vout_synchro_t * p_synchro, int i_coding_type,
00175                                int i_render_time, vlc_bool_t b_low_delay )
00176 {
00177 #define TAU_PRIME( coding_type )    (p_synchro->p_tau[(coding_type)] \
00178                                     + (p_synchro->p_tau[(coding_type)] >> 1) \
00179                                     + p_synchro->i_render_time)
00180 #define S (*p_synchro)
00181     mtime_t         now, period;
00182     mtime_t         pts = 0;
00183     vlc_bool_t      b_decode = 0;
00184 
00185     if ( p_synchro->b_no_skip )
00186         return 1;
00187 
00188     now = mdate();
00189     period = 1000000 * 1001 / p_synchro->i_frame_rate
00190                      * p_synchro->i_current_rate / INPUT_RATE_DEFAULT;
00191 
00192     p_synchro->i_render_time = i_render_time;
00193 
00194     switch( i_coding_type )
00195     {
00196     case I_CODING_TYPE:
00197         if( b_low_delay )
00198         {
00199             pts = S.current_pts;
00200         }
00201         else if( S.backward_pts )
00202         {
00203             pts = S.backward_pts;
00204         }
00205         else
00206         {
00207             /* displaying order : B B P B B I
00208              *                      ^       ^
00209              *                      |       +- current picture
00210              *                      +- current PTS
00211              */
00212             pts = S.current_pts + period * (S.i_n_b + 2);
00213         }
00214 
00215         if( (1 + S.i_n_p * (S.i_n_b + 1)) * period >
00216                 S.p_tau[I_CODING_TYPE] )
00217         {
00218             b_decode = 1;
00219         }
00220         else
00221         {
00222             b_decode = (pts - now) > (TAU_PRIME(I_CODING_TYPE) + DELTA);
00223         }
00224         if( !b_decode && !p_synchro->b_quiet )
00225         {
00226             msg_Warn( p_synchro,
00227                       "synchro trashing I ("I64Fd")", pts - now );
00228         }
00229         break;
00230 
00231     case P_CODING_TYPE:
00232         if( b_low_delay )
00233         {
00234             pts = S.current_pts;
00235         }
00236         else if( S.backward_pts )
00237         {
00238             pts = S.backward_pts;
00239         }
00240         else
00241         {
00242             pts = S.current_pts + period * (S.i_n_b + 1);
00243         }
00244 
00245         if( p_synchro->i_nb_ref < 1 )
00246         {
00247             b_decode = 0;
00248         }
00249         else if( (1 + S.i_n_p * (S.i_n_b + 1)) * period >
00250                 S.p_tau[I_CODING_TYPE] )
00251         {
00252             if( (S.i_n_b + 1) * period > S.p_tau[P_CODING_TYPE] )
00253             {
00254                 /* Security in case we're _really_ late */
00255                 b_decode = (pts - now > 0);
00256             }
00257             else
00258             {
00259                 b_decode = (pts - now) > (TAU_PRIME(P_CODING_TYPE) + DELTA);
00260                 /* next I */
00261                 b_decode &= (pts - now
00262                               + period
00263                           * ( (S.i_n_p - S.i_eta_p) * (1 + S.i_n_b) - 1 ))
00264                             > (TAU_PRIME(P_CODING_TYPE)
00265                                 + TAU_PRIME(I_CODING_TYPE) + DELTA);
00266             }
00267         }
00268         else
00269         {
00270             b_decode = 0;
00271         }
00272         break;
00273 
00274     case B_CODING_TYPE:
00275         pts = S.current_pts;
00276 
00277         if( p_synchro->i_nb_ref < 2 )
00278         {
00279             b_decode = 0;
00280         }
00281         else if( (S.i_n_b + 1) * period > S.p_tau[P_CODING_TYPE] )
00282         {
00283             b_decode = (pts - now) > (TAU_PRIME(B_CODING_TYPE) + DELTA);
00284         }
00285         else
00286         {
00287             b_decode = 0;
00288         }
00289     }
00290 
00291     if( !b_decode )
00292     {
00293         S.i_not_chosen_pic++;
00294     }
00295     return( b_decode );
00296 #undef S
00297 #undef TAU_PRIME
00298 }
00299 
00300 /*****************************************************************************
00301  * vout_SynchroTrash : Update counters when we trash a picture
00302  *****************************************************************************/
00303 void vout_SynchroTrash( vout_synchro_t * p_synchro )
00304 {
00305     p_synchro->i_trashed_pic++;
00306     p_synchro->i_nb_ref = p_synchro->i_trash_nb_ref;
00307 }
00308 
00309 /*****************************************************************************
00310  * vout_SynchroDecode : Update timers when we decide to decode a picture
00311  *****************************************************************************/
00312 void vout_SynchroDecode( vout_synchro_t * p_synchro )
00313 {
00314     p_synchro->decoding_start = mdate();
00315     p_synchro->i_nb_ref = p_synchro->i_dec_nb_ref;
00316 }
00317 
00318 /*****************************************************************************
00319  * vout_SynchroEnd : Called when the image is totally decoded
00320  *****************************************************************************/
00321 void vout_SynchroEnd( vout_synchro_t * p_synchro, int i_coding_type,
00322                       vlc_bool_t b_garbage )
00323 {
00324     mtime_t     tau;
00325 
00326     if( !b_garbage )
00327     {
00328         tau = mdate() - p_synchro->decoding_start;
00329 
00330         /* If duration too high, something happened (pause ?), so don't
00331          * take it into account. */
00332         if( tau < 3 * p_synchro->p_tau[i_coding_type]
00333              || ( !p_synchro->pi_meaningful[i_coding_type]
00334                    && tau < MAX_VALID_TAU ) )
00335         {
00336             /* Mean with average tau, to ensure stability. */
00337             p_synchro->p_tau[i_coding_type] =
00338                 (p_synchro->pi_meaningful[i_coding_type]
00339                  * p_synchro->p_tau[i_coding_type] + tau)
00340                 / (p_synchro->pi_meaningful[i_coding_type] + 1);
00341             if( p_synchro->pi_meaningful[i_coding_type] < MAX_PIC_AVERAGE )
00342             {
00343                 p_synchro->pi_meaningful[i_coding_type]++;
00344             }
00345         }
00346     }
00347 }
00348 
00349 /*****************************************************************************
00350  * vout_SynchroDate : When an image has been decoded, ask for its date
00351  *****************************************************************************/
00352 mtime_t vout_SynchroDate( vout_synchro_t * p_synchro )
00353 {
00354     /* No need to lock, since PTS are only used by the video parser. */
00355     return p_synchro->current_pts;
00356 }
00357 
00358 /*****************************************************************************
00359  * vout_SynchroNewPicture: Update stream structure and PTS
00360  *****************************************************************************/
00361 void vout_SynchroNewPicture( vout_synchro_t * p_synchro, int i_coding_type,
00362                              int i_repeat_field, mtime_t next_pts,
00363                              mtime_t next_dts, int i_current_rate,
00364                              vlc_bool_t b_low_delay )
00365 {
00366     mtime_t         period = 1000000 * 1001 / p_synchro->i_frame_rate
00367                               * i_current_rate / INPUT_RATE_DEFAULT;
00368 #if 0
00369     mtime_t         now = mdate();
00370 #endif
00371     p_synchro->i_current_rate = i_current_rate;
00372 
00373     switch( i_coding_type )
00374     {
00375     case I_CODING_TYPE:
00376         if( p_synchro->i_eta_p
00377              && p_synchro->i_eta_p != p_synchro->i_n_p )
00378         {
00379 #if 0
00380             if( !p_synchro->b_quiet )
00381                 msg_Dbg( p_synchro,
00382                          "stream periodicity changed from P[%d] to P[%d]",
00383                          p_synchro->i_n_p, p_synchro->i_eta_p );
00384 #endif
00385             p_synchro->i_n_p = p_synchro->i_eta_p;
00386         }
00387         p_synchro->i_eta_p = p_synchro->i_eta_b = 0;
00388         p_synchro->i_trash_nb_ref = 0;
00389         if( p_synchro->i_nb_ref < 2 )
00390             p_synchro->i_dec_nb_ref = p_synchro->i_nb_ref + 1;
00391         else
00392             p_synchro->i_dec_nb_ref = p_synchro->i_nb_ref;
00393 
00394 #if 0
00395         if( !p_synchro->b_quiet )
00396             msg_Dbg( p_synchro, "I("I64Fd") P("I64Fd")[%d] B("I64Fd")"
00397                   "[%d] YUV("I64Fd") : trashed %d:%d/%d",
00398                   p_synchro->p_tau[I_CODING_TYPE],
00399                   p_synchro->p_tau[P_CODING_TYPE],
00400                   p_synchro->i_n_p,
00401                   p_synchro->p_tau[B_CODING_TYPE],
00402                   p_synchro->i_n_b,
00403                   p_synchro->i_render_time,
00404                   p_synchro->i_not_chosen_pic,
00405                   p_synchro->i_trashed_pic -
00406                   p_synchro->i_not_chosen_pic,
00407                   p_synchro->i_pic );
00408         p_synchro->i_trashed_pic = p_synchro->i_not_chosen_pic
00409             = p_synchro->i_pic = 0;
00410 #else
00411         if( p_synchro->i_pic >= 100 )
00412         {
00413             if( !p_synchro->b_quiet && p_synchro->i_trashed_pic != 0 )
00414                 msg_Dbg( p_synchro, "decoded %d/%d pictures",
00415                          p_synchro->i_pic
00416                            - p_synchro->i_trashed_pic,
00417                          p_synchro->i_pic );
00418             p_synchro->i_trashed_pic = p_synchro->i_not_chosen_pic
00419                 = p_synchro->i_pic = 0;
00420         }
00421 #endif
00422         break;
00423 
00424     case P_CODING_TYPE:
00425         p_synchro->i_eta_p++;
00426         if( p_synchro->i_eta_b
00427              && p_synchro->i_eta_b != p_synchro->i_n_b )
00428         {
00429 #if 0
00430             if( !p_synchro->b_quiet )
00431                 msg_Dbg( p_synchro,
00432                          "stream periodicity changed from B[%d] to B[%d]",
00433                          p_synchro->i_n_b, p_synchro->i_eta_b );
00434 #endif
00435             p_synchro->i_n_b = p_synchro->i_eta_b;
00436         }
00437         p_synchro->i_eta_b = 0;
00438         p_synchro->i_dec_nb_ref = 2;
00439         p_synchro->i_trash_nb_ref = 0;
00440         break;
00441 
00442     case B_CODING_TYPE:
00443         p_synchro->i_eta_b++;
00444         p_synchro->i_dec_nb_ref = p_synchro->i_trash_nb_ref
00445             = p_synchro->i_nb_ref;
00446         break;
00447     }
00448 
00449     p_synchro->current_pts += p_synchro->i_current_period
00450                                         * (period >> 1);
00451 
00452 #define PTS_THRESHOLD   (period >> 2)
00453     if( i_coding_type == B_CODING_TYPE || b_low_delay )
00454     {
00455         /* A video frame can be displayed 1, 2 or 3 times, according to
00456          * repeat_first_field, top_field_first, progressive_sequence and
00457          * progressive_frame. */
00458         p_synchro->i_current_period = i_repeat_field;
00459 
00460         if( next_pts )
00461         {
00462             if( (next_pts - p_synchro->current_pts
00463                     > PTS_THRESHOLD
00464                   || p_synchro->current_pts - next_pts
00465                     > PTS_THRESHOLD) && !p_synchro->b_quiet )
00466             {
00467                 msg_Warn( p_synchro, "vout synchro warning: pts != "
00468                           "current_date ("I64Fd")",
00469                           p_synchro->current_pts
00470                               - next_pts );
00471             }
00472             p_synchro->current_pts = next_pts;
00473         }
00474     }
00475     else
00476     {
00477         p_synchro->i_current_period = p_synchro->i_backward_period;
00478         p_synchro->i_backward_period = i_repeat_field;
00479 
00480         if( p_synchro->backward_pts )
00481         {
00482             if( next_dts &&
00483                 (next_dts - p_synchro->backward_pts
00484                     > PTS_THRESHOLD
00485                   || p_synchro->backward_pts - next_dts
00486                     > PTS_THRESHOLD) && !p_synchro->b_quiet )
00487             {
00488                 msg_Warn( p_synchro, "backward_pts != dts ("I64Fd")",
00489                            next_dts
00490                                - p_synchro->backward_pts );
00491             }
00492             if( (p_synchro->backward_pts - p_synchro->current_pts
00493                     > PTS_THRESHOLD
00494                   || p_synchro->current_pts - p_synchro->backward_pts
00495                     > PTS_THRESHOLD) && !p_synchro->b_quiet )
00496             {
00497                 msg_Warn( p_synchro,
00498                           "backward_pts != current_pts ("I64Fd")",
00499                           p_synchro->current_pts
00500                               - p_synchro->backward_pts );
00501             }
00502             p_synchro->current_pts = p_synchro->backward_pts;
00503             p_synchro->backward_pts = 0;
00504         }
00505         else if( next_dts )
00506         {
00507             if( (next_dts - p_synchro->current_pts
00508                     > PTS_THRESHOLD
00509                   || p_synchro->current_pts - next_dts
00510                     > PTS_THRESHOLD) && !p_synchro->b_quiet )
00511             {
00512                 msg_Warn( p_synchro, "dts != current_pts ("I64Fd")",
00513                           p_synchro->current_pts
00514                               - next_dts );
00515             }
00516             /* By definition of a DTS. */
00517             p_synchro->current_pts = next_dts;
00518             next_dts = 0;
00519         }
00520 
00521         if( next_pts )
00522         {
00523             /* Store the PTS for the next time we have to date an I picture. */
00524             p_synchro->backward_pts = next_pts;
00525             next_pts = 0;
00526         }
00527     }
00528 #undef PTS_THRESHOLD
00529 
00530 #if 0
00531     /* Removed for incompatibility with slow motion */
00532     if( p_synchro->current_pts + DEFAULT_PTS_DELAY < now )
00533     {
00534         /* We cannot be _that_ late, something must have happened, reinit
00535          * the dates. */
00536         if( !p_synchro->b_quiet )
00537             msg_Warn( p_synchro, "PTS << now ("I64Fd"), resetting",
00538                       now - p_synchro->current_pts - DEFAULT_PTS_DELAY );
00539         p_synchro->current_pts = now + DEFAULT_PTS_DELAY;
00540     }
00541     if( p_synchro->backward_pts
00542          && p_synchro->backward_pts + DEFAULT_PTS_DELAY < now )
00543     {
00544         /* The same. */
00545         p_synchro->backward_pts = 0;
00546     }
00547 #endif
00548 
00549     p_synchro->i_pic++;
00550 }

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