From 52297817b2b13e1bac750ed1f0373d951994faea Mon Sep 17 00:00:00 2001
From: Brad Martin <mythtv@fatlxception.org>
Date: Mon, 13 Nov 2017 21:39:14 -0500
Subject: [PATCH] mythplayer: Fix issues with vsync
Vsync was broken with various combinations of:
* 2x deinterlacing
* High audio stretch factors (1.8x+)
* Video streams using repeat_pict
This was due to a combination of:
* avsync_predictor failing to predict the correct frame interval
* The vsync implementation trying to clamp the frame delay to a small
multiple of the wrong frame interval, due to getting out sync with
the interval and interlace setting at any given moment.
With this change, the vsync method no longer tries to independently
track the frame interval and interlace setting; instead, this is
passed on a frame-by-frame basis.
Additionally, the avsync_predictor is corrected to take into account
additional delays beyond the nominal frame interval.
---
mythtv/libs/libmythtv/mythplayer.cpp | 22 ++++-----
mythtv/libs/libmythtv/vsync.cpp | 88 ++++++++++++++++--------------------
mythtv/libs/libmythtv/vsync.h | 47 ++++++++-----------
3 files changed, 65 insertions(+), 92 deletions(-)
diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
index 3db086f..423f855 100644
a
|
b
|
void MythPlayer::SetVideoParams(int width, int height, double fps, |
843 | 843 | if (ffrew_skip != 0 && ffrew_skip != 1) |
844 | 844 | { |
845 | 845 | UpdateFFRewSkip(); |
846 | | videosync->setFrameInterval(frame_interval); |
847 | 846 | } |
848 | 847 | else |
849 | 848 | { |
… |
… |
void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) |
1902 | 1901 | |
1903 | 1902 | if (avsync_predictor_enabled) |
1904 | 1903 | { |
1905 | | avsync_predictor += frame_interval; |
| 1904 | avsync_predictor += frame_interval + avsync_adjustment + repeat_delay; |
1906 | 1905 | if (avsync_predictor >= refreshrate) |
1907 | 1906 | { |
1908 | 1907 | int refreshperiodsinframe = avsync_predictor/refreshrate; |
… |
… |
void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) |
1968 | 1967 | LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, |
1969 | 1968 | LOC + QString("AVSync waitforframe %1 %2") |
1970 | 1969 | .arg(avsync_adjustment).arg(m_double_framerate)); |
1971 | | vsync_delay_clock = videosync->WaitForFrame |
1972 | | (frameDelay + avsync_adjustment + repeat_delay); |
| 1970 | vsync_delay_clock = videosync->WaitForFrame(frameDelay, avsync_adjustment + repeat_delay); |
1973 | 1971 | } |
1974 | 1972 | else |
1975 | 1973 | { |
… |
… |
void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) |
2006 | 2004 | osdLock.unlock(); |
2007 | 2005 | // Display the second field |
2008 | 2006 | if (!player_ctx->IsPBP() || player_ctx->IsPrimaryPBP()) |
2009 | | vsync_delay_clock = videosync->WaitForFrame(frameDelay + |
2010 | | avsync_adjustment); |
| 2007 | vsync_delay_clock = videosync->WaitForFrame(frameDelay, avsync_adjustment); |
2011 | 2008 | videoOutput->Show(ps); |
2012 | 2009 | } |
2013 | 2010 | |
… |
… |
void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) |
2020 | 2017 | } |
2021 | 2018 | else |
2022 | 2019 | { |
2023 | | vsync_delay_clock = videosync->WaitForFrame(frameDelay); |
| 2020 | vsync_delay_clock = videosync->WaitForFrame(frameDelay, 0); |
2024 | 2021 | //currentaudiotime = AVSyncGetAudiotime(); |
2025 | 2022 | } |
2026 | 2023 | |
… |
… |
void MythPlayer::VideoStart(void) |
2466 | 2463 | |
2467 | 2464 | if (player_ctx->IsPIP() && FlagIsSet(kVideoIsNull)) |
2468 | 2465 | { |
2469 | | videosync = new DummyVideoSync(videoOutput, fr_int, 0, false); |
| 2466 | videosync = new DummyVideoSync(videoOutput, 0); |
2470 | 2467 | } |
2471 | 2468 | else if (FlagIsSet(kVideoIsNull)) |
2472 | 2469 | { |
2473 | | videosync = new USleepVideoSync(videoOutput, fr_int, 0, false); |
| 2470 | videosync = new USleepVideoSync(videoOutput, 0); |
2474 | 2471 | } |
2475 | 2472 | else if (videoOutput) |
2476 | 2473 | { |
… |
… |
void MythPlayer::VideoStart(void) |
2481 | 2478 | |
2482 | 2479 | m_double_process = videoOutput->IsExtraProcessingRequired(); |
2483 | 2480 | |
2484 | | videosync = VideoSync::BestMethod( |
2485 | | videoOutput, (uint)fr_int, (uint)rf_int, m_double_framerate); |
| 2481 | videosync = VideoSync::BestMethod(videoOutput, (uint)rf_int); |
2486 | 2482 | |
2487 | 2483 | // Make sure video sync can do it |
2488 | 2484 | if (videosync != NULL && m_double_framerate) |
… |
… |
void MythPlayer::VideoStart(void) |
2498 | 2494 | } |
2499 | 2495 | if (!videosync) |
2500 | 2496 | { |
2501 | | videosync = new BusyWaitVideoSync( |
2502 | | videoOutput, fr_int, rf_int, m_double_framerate); |
| 2497 | videosync = new BusyWaitVideoSync(videoOutput, rf_int); |
2503 | 2498 | } |
2504 | 2499 | |
2505 | 2500 | InitAVSync(); |
… |
… |
void MythPlayer::ChangeSpeed(void) |
3767 | 3762 | normal_speed = next_normal_speed; |
3768 | 3763 | |
3769 | 3764 | bool skip_changed = UpdateFFRewSkip(); |
3770 | | videosync->setFrameInterval(frame_interval); |
3771 | 3765 | |
3772 | 3766 | if (skip_changed && videoOutput) |
3773 | 3767 | { |
diff --git a/mythtv/libs/libmythtv/vsync.cpp b/mythtv/libs/libmythtv/vsync.cpp
index 1cb1164..5d0111f 100644
a
|
b
|
int VideoSync::m_forceskip = 0; |
57 | 57 | #define TESTVIDEOSYNC(NAME) \ |
58 | 58 | do { if (++m_forceskip > skip) \ |
59 | 59 | { \ |
60 | | trial = new NAME (video_output, frame_interval, \ |
61 | | refresh_interval, halve_frame_interval); \ |
| 60 | trial = new NAME (video_output, refresh_interval); \ |
62 | 61 | if (trial->TryInit()) \ |
63 | 62 | { \ |
64 | 63 | m_forceskip = skip; \ |
… |
… |
int VideoSync::m_forceskip = 0; |
70 | 69 | |
71 | 70 | #define LOC QString("VSYNC: ") |
72 | 71 | |
73 | | /** \fn VideoSync::BestMethod(VideoOutput*,uint,uint,bool) |
| 72 | /** \fn VideoSync::BestMethod(VideoOutput*,uint) |
74 | 73 | * \brief Returns the most sophisticated video sync method available. |
75 | 74 | */ |
76 | 75 | VideoSync *VideoSync::BestMethod(VideoOutput *video_output, |
77 | | uint frame_interval, uint refresh_interval, |
78 | | bool halve_frame_interval) |
| 76 | uint refresh_interval) |
79 | 77 | { |
80 | 78 | VideoSync *trial = NULL; |
81 | 79 | tryingVideoSync = true; |
… |
… |
VideoSync *VideoSync::BestMethod(VideoOutput *video_output, |
108 | 106 | return NULL; |
109 | 107 | } |
110 | 108 | |
111 | | /** \fn VideoSync::VideoSync(VideoOutput*,int,int,bool) |
112 | | * \brief Used by BestMethod(VideoOutput*,uint,uint,bool) to initialize |
| 109 | /** \fn VideoSync::VideoSync(VideoOutput*,int) |
| 110 | * \brief Used by BestMethod(VideoOutput*,uint) to initialize |
113 | 111 | * video synchronization method. |
114 | 112 | */ |
115 | | VideoSync::VideoSync(VideoOutput *video_output, |
116 | | int frameint, int refreshint, |
117 | | bool halve_frame_interval) : |
118 | | m_video_output(video_output), m_frame_interval(frameint), |
119 | | m_refresh_interval(refreshint), m_interlaced(halve_frame_interval), |
| 113 | VideoSync::VideoSync(VideoOutput *video_output, int refreshint) : |
| 114 | m_video_output(video_output), m_refresh_interval(refreshint), |
120 | 115 | m_nexttrigger(0), m_delay(-1) |
121 | 116 | { |
122 | 117 | } |
… |
… |
void VideoSync::Start(void) |
133 | 128 | m_nexttrigger = GetTime(); |
134 | 129 | } |
135 | 130 | |
136 | | /** \fn VideoSync::CalcDelay() |
| 131 | /** \fn VideoSync::CalcDelay(int) |
137 | 132 | * \brief Calculates the delay to the next frame. |
138 | 133 | * |
139 | 134 | * Regardless of the timing method, if delay is greater than four full |
… |
… |
void VideoSync::Start(void) |
144 | 139 | * Also prevent the nexttrigger from falling too far in the past in case |
145 | 140 | * we are trying to speed up video output faster than possible. |
146 | 141 | */ |
147 | | int VideoSync::CalcDelay() |
| 142 | int VideoSync::CalcDelay(int nominal_frame_interval) |
148 | 143 | { |
149 | 144 | int64_t now = GetTime(); |
150 | 145 | #if 0 |
… |
… |
int VideoSync::CalcDelay() |
158 | 153 | LOG(VB_GENERAL, LOG_DEBUG, QString("delay %1").arg(ret_val)); |
159 | 154 | #endif |
160 | 155 | |
161 | | if (ret_val > m_frame_interval * 4) |
| 156 | if (ret_val > nominal_frame_interval * 4) |
162 | 157 | { |
163 | | if (m_interlaced) |
164 | | ret_val = (m_frame_interval / 2) * 4; |
165 | | else |
166 | | ret_val = m_frame_interval * 4; |
| 158 | ret_val = nominal_frame_interval * 4; |
167 | 159 | |
168 | 160 | // set nexttrigger to our new target time |
169 | 161 | m_nexttrigger = now + ret_val; |
170 | 162 | } |
171 | 163 | |
172 | | if (ret_val < -m_frame_interval && m_frame_interval >= m_refresh_interval) |
| 164 | if (ret_val < -nominal_frame_interval && nominal_frame_interval >= m_refresh_interval) |
173 | 165 | { |
174 | | ret_val = -m_frame_interval; |
| 166 | ret_val = -nominal_frame_interval; |
175 | 167 | |
176 | 168 | // set nexttrigger to our new target time |
177 | 169 | m_nexttrigger = now + ret_val; |
… |
… |
static int drmWaitVBlank(int fd, drm_wait_vblank_t *vbl) |
240 | 232 | |
241 | 233 | const char *DRMVideoSync::sm_dri_dev = "/dev/dri/card0"; |
242 | 234 | |
243 | | DRMVideoSync::DRMVideoSync(VideoOutput *vo, int fr, int ri, bool intl) : |
244 | | VideoSync(vo, fr, ri, intl) |
| 235 | DRMVideoSync::DRMVideoSync(VideoOutput *vo, int ri) : |
| 236 | VideoSync(vo, ri) |
245 | 237 | { |
246 | 238 | m_dri_fd = -1; |
247 | 239 | } |
… |
… |
void DRMVideoSync::Start(void) |
289 | 281 | VideoSync::Start(); |
290 | 282 | } |
291 | 283 | |
292 | | int DRMVideoSync::WaitForFrame(int sync_delay) |
| 284 | int DRMVideoSync::WaitForFrame(int nominal_frame_interval, int extra_delay) |
293 | 285 | { |
294 | 286 | // Offset for externally-provided A/V sync delay |
295 | | m_nexttrigger += sync_delay; |
| 287 | m_nexttrigger += nominal_frame_interval + extra_delay; |
296 | 288 | |
297 | | m_delay = CalcDelay(); |
| 289 | m_delay = CalcDelay(nominal_frame_interval); |
298 | 290 | #if 0 |
299 | 291 | LOG(VB_GENERAL, LOG_DEBUG, QString("WaitForFrame at : %1").arg(m_delay)); |
300 | 292 | #endif |
… |
… |
int DRMVideoSync::WaitForFrame(int sync_delay) |
306 | 298 | blank.request.type = DRM_VBLANK_RELATIVE; |
307 | 299 | blank.request.sequence = 1; |
308 | 300 | drmWaitVBlank(m_dri_fd, &blank); |
309 | | m_delay = CalcDelay(); |
| 301 | m_delay = CalcDelay(nominal_frame_interval); |
310 | 302 | #if 0 |
311 | 303 | LOG(VB_GENERAL, LOG_DEBUG, QString("Delay at sync: %1").arg(m_delay)); |
312 | 304 | #endif |
… |
… |
int DRMVideoSync::WaitForFrame(int sync_delay) |
321 | 313 | blank.request.type = DRM_VBLANK_RELATIVE; |
322 | 314 | blank.request.sequence = n; |
323 | 315 | drmWaitVBlank(m_dri_fd, &blank); |
324 | | m_delay = CalcDelay(); |
| 316 | m_delay = CalcDelay(nominal_frame_interval); |
325 | 317 | #if 0 |
326 | 318 | LOG(VB_GENERAL, LOG_DEBUG, |
327 | 319 | QString("Wait %1 intervals. Count %2 Delay %3") |
… |
… |
int DRMVideoSync::WaitForFrame(int sync_delay) |
335 | 327 | |
336 | 328 | #ifdef __linux__ |
337 | 329 | #define RTCRATE 1024 |
338 | | RTCVideoSync::RTCVideoSync(VideoOutput *vo, int fi, int ri, bool intr) : |
339 | | VideoSync(vo, fi, ri, intr) |
| 330 | RTCVideoSync::RTCVideoSync(VideoOutput *vo, int ri) : |
| 331 | VideoSync(vo, ri) |
340 | 332 | { |
341 | 333 | m_rtcfd = -1; |
342 | 334 | } |
… |
… |
bool RTCVideoSync::TryInit(void) |
375 | 367 | return true; |
376 | 368 | } |
377 | 369 | |
378 | | int RTCVideoSync::WaitForFrame(int sync_delay) |
| 370 | int RTCVideoSync::WaitForFrame(int nominal_frame_interval, int extra_delay) |
379 | 371 | { |
380 | | m_nexttrigger += sync_delay; |
| 372 | m_nexttrigger += nominal_frame_interval + extra_delay; |
381 | 373 | |
382 | | m_delay = CalcDelay(); |
| 374 | m_delay = CalcDelay(nominal_frame_interval); |
383 | 375 | |
384 | 376 | unsigned long rtcdata; |
385 | 377 | while (m_delay > 0) |
386 | 378 | { |
387 | 379 | ssize_t val = read(m_rtcfd, &rtcdata, sizeof(rtcdata)); |
388 | | m_delay = CalcDelay(); |
| 380 | m_delay = CalcDelay(nominal_frame_interval); |
389 | 381 | |
390 | 382 | if ((val < 0) && (m_delay > 0)) |
391 | 383 | usleep(m_delay); |
… |
… |
int RTCVideoSync::WaitForFrame(int sync_delay) |
394 | 386 | } |
395 | 387 | #endif /* __linux__ */ |
396 | 388 | |
397 | | BusyWaitVideoSync::BusyWaitVideoSync(VideoOutput *vo, |
398 | | int fr, int ri, bool intl) : |
399 | | VideoSync(vo, fr, ri, intl) |
| 389 | BusyWaitVideoSync::BusyWaitVideoSync(VideoOutput *vo, int ri) : |
| 390 | VideoSync(vo, ri) |
400 | 391 | { |
401 | 392 | m_cheat = 5000; |
402 | 393 | m_fudge = 0; |
… |
… |
bool BusyWaitVideoSync::TryInit(void) |
411 | 402 | return true; |
412 | 403 | } |
413 | 404 | |
414 | | int BusyWaitVideoSync::WaitForFrame(int sync_delay) |
| 405 | int BusyWaitVideoSync::WaitForFrame(int nominal_frame_interval, int extra_delay) |
415 | 406 | { |
416 | 407 | // Offset for externally-provided A/V sync delay |
417 | | m_nexttrigger += sync_delay; |
| 408 | m_nexttrigger += nominal_frame_interval + extra_delay; |
418 | 409 | |
419 | | m_delay = CalcDelay(); |
| 410 | m_delay = CalcDelay(nominal_frame_interval); |
420 | 411 | |
421 | 412 | if (m_delay > 0) |
422 | 413 | { |
… |
… |
int BusyWaitVideoSync::WaitForFrame(int sync_delay) |
429 | 420 | |
430 | 421 | // If late, draw the frame ASAP. If early, hold the CPU until |
431 | 422 | // half as late as the previous frame (fudge). |
432 | | m_delay = CalcDelay(); |
433 | | m_fudge = min(m_fudge, m_frame_interval); |
| 423 | m_delay = CalcDelay(nominal_frame_interval); |
| 424 | m_fudge = min(m_fudge, nominal_frame_interval); |
434 | 425 | while (m_delay + m_fudge > 0) |
435 | 426 | { |
436 | | m_delay = CalcDelay(); |
| 427 | m_delay = CalcDelay(nominal_frame_interval); |
437 | 428 | cnt++; |
438 | 429 | } |
439 | 430 | m_fudge = abs(m_delay / 2); |
… |
… |
int BusyWaitVideoSync::WaitForFrame(int sync_delay) |
443 | 434 | return 0; |
444 | 435 | } |
445 | 436 | |
446 | | USleepVideoSync::USleepVideoSync(VideoOutput *vo, |
447 | | int fr, int ri, bool intl) : |
448 | | VideoSync(vo, fr, ri, intl) |
| 437 | USleepVideoSync::USleepVideoSync(VideoOutput *vo, int ri) : |
| 438 | VideoSync(vo, ri) |
449 | 439 | { |
450 | 440 | } |
451 | 441 | |
… |
… |
bool USleepVideoSync::TryInit(void) |
458 | 448 | return true; |
459 | 449 | } |
460 | 450 | |
461 | | int USleepVideoSync::WaitForFrame(int sync_delay) |
| 451 | int USleepVideoSync::WaitForFrame(int nominal_frame_interval, int extra_delay) |
462 | 452 | { |
463 | 453 | // Offset for externally-provided A/V sync delay |
464 | | m_nexttrigger += sync_delay; |
| 454 | m_nexttrigger += nominal_frame_interval + extra_delay; |
465 | 455 | |
466 | | m_delay = CalcDelay(); |
| 456 | m_delay = CalcDelay(nominal_frame_interval); |
467 | 457 | if (m_delay > 0) |
468 | 458 | usleep(m_delay); |
469 | 459 | return 0; |
diff --git a/mythtv/libs/libmythtv/vsync.h b/mythtv/libs/libmythtv/vsync.h
index 94cbd4e..2e0b79b 100644
a
|
b
|
class VideoSync |
46 | 46 | // virtual base class |
47 | 47 | { |
48 | 48 | public: |
49 | | VideoSync(VideoOutput*, int fi, int ri, bool intr); |
| 49 | VideoSync(VideoOutput*, int ri); |
50 | 50 | virtual ~VideoSync() {} |
51 | 51 | |
52 | 52 | /// \brief Returns name of instanciated VSync method. |
… |
… |
class VideoSync |
69 | 69 | * always be called from same thread, to prevent bad |
70 | 70 | * interactions with threads. |
71 | 71 | * |
72 | | * \param sync_delay time until the desired frame or field |
73 | | * \sa CalcDelay(void), KeepPhase(void) |
| 72 | * \param nominal_frame_interval the frame interval normally expected |
| 73 | * \param extra_delay extra time beyond nominal until the desired frame or field |
| 74 | * \sa CalcDelay(int), KeepPhase(void) |
74 | 75 | */ |
75 | | virtual int WaitForFrame(int sync_delay) = 0; |
| 76 | virtual int WaitForFrame(int nominal_frame_interval, int extra_delay) = 0; |
76 | 77 | |
77 | 78 | /// \brief Returns the (minimum) refresh interval of the output device. |
78 | 79 | int getRefreshInterval(void) const { return m_refresh_interval; } |
79 | 80 | /// \brief Sets the refresh interval of the output device. |
80 | 81 | void setRefreshInterval(int ri) { m_refresh_interval = ri; } |
81 | 82 | |
82 | | virtual void setFrameInterval(int fi) { m_frame_interval = fi; }; |
83 | | |
84 | 83 | /** \brief Stops VSync; must be called from main thread. |
85 | 84 | * |
86 | 85 | * Start(void), WaitForFrame(void), and Stop(void) should |
… |
… |
class VideoSync |
90 | 89 | virtual void Stop(void) {} |
91 | 90 | |
92 | 91 | // documented in vsync.cpp |
93 | | static VideoSync *BestMethod(VideoOutput*, |
94 | | uint frame_interval, uint refresh_interval, |
95 | | bool interlaced); |
| 92 | static VideoSync *BestMethod(VideoOutput *, uint refresh_interval); |
| 93 | |
96 | 94 | protected: |
97 | 95 | int64_t GetTime(void); |
98 | | int CalcDelay(void); |
| 96 | int CalcDelay(int nominal_frame_interval); |
99 | 97 | void KeepPhase(void) MDEPRECATED; |
100 | 98 | |
101 | 99 | VideoOutput *m_video_output; |
102 | | int m_frame_interval; // of video |
103 | 100 | int m_refresh_interval; // of display |
104 | | bool m_interlaced; |
105 | 101 | int64_t m_nexttrigger; |
106 | 102 | int m_delay; |
107 | 103 | |
… |
… |
class VideoSync |
118 | 114 | class DRMVideoSync : public VideoSync |
119 | 115 | { |
120 | 116 | public: |
121 | | DRMVideoSync(VideoOutput*, |
122 | | int frame_interval, int refresh_interval, bool interlaced); |
| 117 | DRMVideoSync(VideoOutput *, int refresh_interval); |
123 | 118 | ~DRMVideoSync(); |
124 | 119 | |
125 | 120 | QString getName(void) const { return QString("DRM"); } |
126 | 121 | bool TryInit(void); |
127 | 122 | void Start(void); |
128 | | int WaitForFrame(int sync_delay); |
| 123 | int WaitForFrame(int nominal_frame_interval, int extra_delay) override; |
129 | 124 | |
130 | 125 | private: |
131 | 126 | int m_dri_fd; |
… |
… |
class DRMVideoSync : public VideoSync |
148 | 143 | class RTCVideoSync : public VideoSync |
149 | 144 | { |
150 | 145 | public: |
151 | | RTCVideoSync(VideoOutput*, |
152 | | int frame_interval, int refresh_interval, bool interlaced); |
| 146 | RTCVideoSync(VideoOutput *, int refresh_interval); |
153 | 147 | ~RTCVideoSync(); |
154 | 148 | |
155 | 149 | QString getName(void) const { return QString("RTC"); } |
156 | 150 | bool TryInit(void); |
157 | | int WaitForFrame(int sync_delay); |
| 151 | int WaitForFrame(int nominal_frame_interval, int extra_delay) override; |
158 | 152 | |
159 | 153 | private: |
160 | 154 | int m_rtcfd; |
… |
… |
class RTCVideoSync : public VideoSync |
174 | 168 | class BusyWaitVideoSync : public VideoSync |
175 | 169 | { |
176 | 170 | public: |
177 | | BusyWaitVideoSync(VideoOutput*, |
178 | | int frame_interval, int refresh_interval, |
179 | | bool interlaced); |
| 171 | BusyWaitVideoSync(VideoOutput *, int refresh_interval); |
180 | 172 | ~BusyWaitVideoSync(); |
181 | 173 | |
182 | 174 | QString getName(void) const { return QString("USleep with busy wait"); } |
183 | 175 | bool TryInit(void); |
184 | | int WaitForFrame(int sync_delay); |
| 176 | int WaitForFrame(int nominal_frame_interval, int extra_delay) override; |
185 | 177 | |
186 | 178 | private: |
187 | 179 | int m_cheat; |
… |
… |
class BusyWaitVideoSync : public VideoSync |
201 | 193 | class USleepVideoSync : public VideoSync |
202 | 194 | { |
203 | 195 | public: |
204 | | USleepVideoSync(VideoOutput*, |
205 | | int frame_interval, int refresh_interval, |
206 | | bool interlaced); |
| 196 | USleepVideoSync(VideoOutput *, int refresh_interval); |
207 | 197 | ~USleepVideoSync(); |
208 | 198 | |
209 | 199 | QString getName(void) const { return QString("USleep"); } |
210 | 200 | bool TryInit(void); |
211 | | int WaitForFrame(int sync_delay); |
| 201 | int WaitForFrame(int nominal_frame_interval, int extra_delay) override; |
212 | 202 | }; |
213 | 203 | |
214 | 204 | class DummyVideoSync : public VideoSync |
215 | 205 | { |
216 | 206 | public: |
217 | | DummyVideoSync(VideoOutput* vo, int fr, int ri, bool intl) |
218 | | : VideoSync(vo, fr, ri, intl) { } |
| 207 | DummyVideoSync(VideoOutput* vo, int ri) : VideoSync(vo, ri) { } |
219 | 208 | ~DummyVideoSync() { } |
220 | 209 | |
221 | 210 | QString getName(void) const { return QString("Dummy"); } |
222 | 211 | bool TryInit(void) { return true; } |
223 | | int WaitForFrame(int sync_delay) { return 0; } |
| 212 | int WaitForFrame(int nominal_frame_interval, int extra_delay) override { return 0; } |
224 | 213 | }; |
225 | 214 | #endif /* VSYNC_H_INCLUDED */ |