00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 #include <stdlib.h>
00098 #include <string.h>
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
00108
00109
00110
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
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
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
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
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
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
00208
00209
00210
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
00255 b_decode = (pts - now > 0);
00256 }
00257 else
00258 {
00259 b_decode = (pts - now) > (TAU_PRIME(P_CODING_TYPE) + DELTA);
00260
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
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
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
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
00331
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
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
00351
00352 mtime_t vout_SynchroDate( vout_synchro_t * p_synchro )
00353 {
00354
00355 return p_synchro->current_pts;
00356 }
00357
00358
00359
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
00456
00457
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
00517 p_synchro->current_pts = next_dts;
00518 next_dts = 0;
00519 }
00520
00521 if( next_pts )
00522 {
00523
00524 p_synchro->backward_pts = next_pts;
00525 next_pts = 0;
00526 }
00527 }
00528 #undef PTS_THRESHOLD
00529
00530 #if 0
00531
00532 if( p_synchro->current_pts + DEFAULT_PTS_DELAY < now )
00533 {
00534
00535
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
00545 p_synchro->backward_pts = 0;
00546 }
00547 #endif
00548
00549 p_synchro->i_pic++;
00550 }