diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
index 1b976ff..d6f4670 100644
a
|
b
|
void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) |
1708 | 1708 | |
1709 | 1709 | float diverge = 0.0f; |
1710 | 1710 | int frameDelay = m_double_framerate ? frame_interval / 2 : frame_interval; |
| 1711 | int vsync_delay_clock = 0; |
1711 | 1712 | int64_t currentaudiotime = 0; |
1712 | 1713 | |
1713 | 1714 | // attempt to reduce fps for standalone PIP |
… |
… |
void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) |
1798 | 1799 | osdLock.unlock(); |
1799 | 1800 | VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + QString("AVSync waitforframe %1 %2") |
1800 | 1801 | .arg(avsync_adjustment).arg(m_double_framerate)); |
1801 | | videosync->WaitForFrame(frameDelay + avsync_adjustment + repeat_delay); |
| 1802 | vsync_delay_clock = videosync->WaitForFrame |
| 1803 | (frameDelay + avsync_adjustment + repeat_delay); |
1802 | 1804 | currentaudiotime = AVSyncGetAudiotime(); |
1803 | 1805 | VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, LOC + "AVSync show"); |
1804 | 1806 | videoOutput->Show(ps); |
… |
… |
void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) |
1828 | 1830 | videoOutput->PrepareFrame(buffer, ps, osd); |
1829 | 1831 | osdLock.unlock(); |
1830 | 1832 | // Display the second field |
1831 | | videosync->WaitForFrame(frameDelay + avsync_adjustment); |
| 1833 | vsync_delay_clock = videosync->WaitForFrame(frameDelay + avsync_adjustment); |
1832 | 1834 | videoOutput->Show(ps); |
1833 | 1835 | } |
1834 | 1836 | |
… |
… |
void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) |
1840 | 1842 | } |
1841 | 1843 | else |
1842 | 1844 | { |
1843 | | videosync->WaitForFrame(frameDelay); |
| 1845 | vsync_delay_clock = videosync->WaitForFrame(frameDelay); |
1844 | 1846 | currentaudiotime = AVSyncGetAudiotime(); |
1845 | 1847 | } |
1846 | 1848 | |
… |
… |
void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) |
1869 | 1871 | |
1870 | 1872 | if (audio.HasAudioOut() && normal_speed) |
1871 | 1873 | { |
| 1874 | // must be sampled here due to Show delays |
1872 | 1875 | int64_t currentaudiotime = audio.GetAudioTime(); |
1873 | | VERBOSE(VB_TIMESTAMP, LOC + QString( |
| 1876 | VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC + QString( |
1874 | 1877 | "A/V timecodes audio %1 video %2 frameinterval %3 " |
1875 | 1878 | "avdel %4 avg %5 tcoffset %6 " |
1876 | | "avp %7 avpen %8") |
| 1879 | "avp %7 avpen %8 avdc %9") |
1877 | 1880 | .arg(currentaudiotime) |
1878 | 1881 | .arg(timecode) |
1879 | 1882 | .arg(frame_interval) |
1880 | | .arg(timecode - currentaudiotime) |
| 1883 | .arg(timecode - currentaudiotime - |
| 1884 | (int)(vsync_delay_clock*audio.GetStretchFactor()+500)/1000) |
1881 | 1885 | .arg(avsync_avg) |
1882 | 1886 | .arg(tc_wrap[TC_AUDIO]) |
1883 | 1887 | .arg(avsync_predictor) |
1884 | 1888 | .arg(avsync_predictor_enabled) |
| 1889 | .arg(vsync_delay_clock) |
1885 | 1890 | ); |
1886 | 1891 | if (currentaudiotime != 0 && timecode != 0) |
1887 | 1892 | { // currentaudiotime == 0 after a seek |
… |
… |
void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay) |
1903 | 1908 | prevtc = timecode; |
1904 | 1909 | prevrp = repeat_pict; |
1905 | 1910 | |
1906 | | avsync_delay = (timecode - currentaudiotime) * 1000;//usec |
| 1911 | avsync_delay = (timecode - currentaudiotime) * 1000 - |
| 1912 | (int)(vsync_delay_clock*audio.GetStretchFactor()); //usec |
1907 | 1913 | // prevents major jitter when pts resets during dvd title |
1908 | 1914 | if (avsync_delay > 2000000 && limit_delay) |
1909 | 1915 | avsync_delay = 90000; |
diff --git a/mythtv/libs/libmythtv/vsync.cpp b/mythtv/libs/libmythtv/vsync.cpp
index 6e1b891..9d0a005 100644
a
|
b
|
int VideoSync::CalcDelay() |
178 | 178 | m_nexttrigger = now + ret_val; |
179 | 179 | } |
180 | 180 | |
181 | | if (ret_val < -m_frame_interval) |
| 181 | if (ret_val < -m_frame_interval && m_frame_interval >= m_refresh_interval) |
182 | 182 | { |
183 | 183 | ret_val = -m_frame_interval; |
184 | 184 | |
… |
… |
void DRMVideoSync::Start(void) |
293 | 293 | VideoSync::Start(); |
294 | 294 | } |
295 | 295 | |
296 | | void DRMVideoSync::WaitForFrame(int sync_delay) |
| 296 | int DRMVideoSync::WaitForFrame(int sync_delay) |
297 | 297 | { |
298 | 298 | // Offset for externally-provided A/V sync delay |
299 | 299 | m_nexttrigger += sync_delay; |
… |
… |
void DRMVideoSync::WaitForFrame(int sync_delay) |
316 | 316 | if (m_delay > 0) |
317 | 317 | { |
318 | 318 | // Wait for any remaining retrace intervals in one pass. |
319 | | int n = m_delay / m_refresh_interval + 1; |
| 319 | int n = (m_delay + m_refresh_interval - 1) / m_refresh_interval; |
320 | 320 | |
321 | 321 | drm_wait_vblank_t blank; |
322 | 322 | blank.request.type = DRM_VBLANK_RELATIVE; |
… |
… |
void DRMVideoSync::WaitForFrame(int sync_delay) |
327 | 327 | //cerr << " Delay " << m_delay << endl; |
328 | 328 | } |
329 | 329 | |
| 330 | return m_delay; |
| 331 | |
330 | 332 | KeepPhase(); |
331 | 333 | } |
332 | 334 | #endif /* !_WIN32 */ |
… |
… |
void OpenGLVideoSync::Start(void) |
397 | 399 | #endif /* USING_OPENGL_VSYNC */ |
398 | 400 | } |
399 | 401 | |
400 | | void OpenGLVideoSync::WaitForFrame(int sync_delay) |
| 402 | int OpenGLVideoSync::WaitForFrame(int sync_delay) |
401 | 403 | { |
402 | 404 | (void) sync_delay; |
403 | 405 | #ifdef USING_OPENGL_VSYNC |
… |
… |
void OpenGLVideoSync::WaitForFrame(int sync_delay) |
409 | 411 | m_delay = CalcDelay(); |
410 | 412 | if (m_delay > 0) |
411 | 413 | usleep(m_delay); |
412 | | return; |
| 414 | return 0; |
413 | 415 | } |
414 | 416 | |
415 | 417 | if (!m_context) |
416 | | return; |
| 418 | return 0; |
417 | 419 | |
418 | 420 | unsigned int frameNum = m_context->GetVideoSyncCount(); |
419 | 421 | |
… |
… |
void OpenGLVideoSync::WaitForFrame(int sync_delay) |
427 | 429 | // Wait for any remaining retrace intervals in one pass. |
428 | 430 | if (m_delay > 0) |
429 | 431 | { |
430 | | uint n = m_delay / m_refresh_interval + 1; |
| 432 | uint n = (m_delay + m_refresh_interval - 1) / m_refresh_interval; |
431 | 433 | m_context->WaitForVideoSync((n+1), (frameNum+n)%(n+1), &frameNum); |
432 | 434 | m_delay = CalcDelay(); |
433 | 435 | } |
434 | 436 | |
| 437 | return m_delay; |
| 438 | |
435 | 439 | KeepPhase(); |
436 | 440 | #endif /* USING_OPENGL_VSYNC */ |
437 | 441 | } |
… |
… |
bool RTCVideoSync::TryInit(void) |
479 | 483 | return true; |
480 | 484 | } |
481 | 485 | |
482 | | void RTCVideoSync::WaitForFrame(int sync_delay) |
| 486 | int RTCVideoSync::WaitForFrame(int sync_delay) |
483 | 487 | { |
484 | 488 | m_nexttrigger += sync_delay; |
485 | 489 | |
… |
… |
void RTCVideoSync::WaitForFrame(int sync_delay) |
494 | 498 | if ((val < 0) && (m_delay > 0)) |
495 | 499 | usleep(m_delay); |
496 | 500 | } |
| 501 | return 0; |
497 | 502 | } |
498 | 503 | #endif /* __linux__ */ |
499 | 504 | |
… |
… |
bool VDPAUVideoSync::TryInit(void) |
517 | 522 | return true; |
518 | 523 | } |
519 | 524 | |
520 | | void VDPAUVideoSync::WaitForFrame(int sync_delay) |
| 525 | int VDPAUVideoSync::WaitForFrame(int sync_delay) |
521 | 526 | { |
522 | 527 | // Offset for externally-provided A/V sync delay |
523 | 528 | m_nexttrigger += sync_delay; |
… |
… |
void VDPAUVideoSync::WaitForFrame(int sync_delay) |
528 | 533 | |
529 | 534 | VideoOutputVDPAU *vo = (VideoOutputVDPAU *)(m_video_output); |
530 | 535 | vo->SetNextFrameDisplayTimeOffset(m_delay); |
| 536 | return 0; |
531 | 537 | } |
532 | 538 | #endif |
533 | 539 | |
… |
… |
bool BusyWaitVideoSync::TryInit(void) |
548 | 554 | return true; |
549 | 555 | } |
550 | 556 | |
551 | | void BusyWaitVideoSync::WaitForFrame(int sync_delay) |
| 557 | int BusyWaitVideoSync::WaitForFrame(int sync_delay) |
552 | 558 | { |
553 | 559 | // Offset for externally-provided A/V sync delay |
554 | 560 | m_nexttrigger += sync_delay; |
… |
… |
void BusyWaitVideoSync::WaitForFrame(int sync_delay) |
577 | 583 | if (cnt > 1) |
578 | 584 | m_cheat -= 200; |
579 | 585 | } |
| 586 | return 0; |
580 | 587 | } |
581 | 588 | |
582 | 589 | USleepVideoSync::USleepVideoSync(VideoOutput *vo, |
… |
… |
bool USleepVideoSync::TryInit(void) |
594 | 601 | return true; |
595 | 602 | } |
596 | 603 | |
597 | | void USleepVideoSync::WaitForFrame(int sync_delay) |
| 604 | int USleepVideoSync::WaitForFrame(int sync_delay) |
598 | 605 | { |
599 | 606 | // Offset for externally-provided A/V sync delay |
600 | 607 | m_nexttrigger += sync_delay; |
… |
… |
void USleepVideoSync::WaitForFrame(int sync_delay) |
602 | 609 | m_delay = CalcDelay(); |
603 | 610 | if (m_delay > 0) |
604 | 611 | usleep(m_delay); |
| 612 | return 0; |
605 | 613 | } |
606 | 614 | |
diff --git a/mythtv/libs/libmythtv/vsync.h b/mythtv/libs/libmythtv/vsync.h
index 310d866..3db298b 100644
a
|
b
|
class VideoSync |
64 | 64 | virtual void Start(void); |
65 | 65 | |
66 | 66 | /** \brief Waits for next a frame or field. |
| 67 | * Returns delay to real frame timing in usec |
67 | 68 | * |
68 | 69 | * Start(void), WaitForFrame(void), and Stop(void) should |
69 | 70 | * always be called from same thread, to prevent bad |
… |
… |
class VideoSync |
72 | 73 | * \param sync_delay time until the desired frame or field |
73 | 74 | * \sa CalcDelay(void), KeepPhase(void) |
74 | 75 | */ |
75 | | virtual void WaitForFrame(int sync_delay) = 0; |
| 76 | virtual int WaitForFrame(int sync_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; } |
… |
… |
class DRMVideoSync : public VideoSync |
123 | 124 | QString getName(void) const { return QString("DRM"); } |
124 | 125 | bool TryInit(void); |
125 | 126 | void Start(void); |
126 | | void WaitForFrame(int sync_delay); |
| 127 | int WaitForFrame(int sync_delay); |
127 | 128 | |
128 | 129 | private: |
129 | 130 | int m_dri_fd; |
… |
… |
class OpenGLVideoSync : public VideoSync |
164 | 165 | QString getName(void) const { return QString("SGI OpenGL"); } |
165 | 166 | bool TryInit(void); |
166 | 167 | void Start(void); |
167 | | void WaitForFrame(int sync_delay); |
| 168 | int WaitForFrame(int sync_delay); |
168 | 169 | |
169 | 170 | private: |
170 | 171 | MythRenderOpenGL *m_context; |
… |
… |
class RTCVideoSync : public VideoSync |
192 | 193 | |
193 | 194 | QString getName(void) const { return QString("RTC"); } |
194 | 195 | bool TryInit(void); |
195 | | void WaitForFrame(int sync_delay); |
| 196 | int WaitForFrame(int sync_delay); |
196 | 197 | |
197 | 198 | private: |
198 | 199 | int m_rtcfd; |
… |
… |
class VDPAUVideoSync : public VideoSync |
212 | 213 | |
213 | 214 | QString getName(void) const { return QString("VDPAU"); } |
214 | 215 | bool TryInit(void); |
215 | | void WaitForFrame(int sync_delay); |
| 216 | int WaitForFrame(int sync_delay); |
216 | 217 | |
217 | 218 | private: |
218 | 219 | }; |
… |
… |
class BusyWaitVideoSync : public VideoSync |
239 | 240 | |
240 | 241 | QString getName(void) const { return QString("USleep with busy wait"); } |
241 | 242 | bool TryInit(void); |
242 | | void WaitForFrame(int sync_delay); |
| 243 | int WaitForFrame(int sync_delay); |
243 | 244 | |
244 | 245 | private: |
245 | 246 | int m_cheat; |
… |
… |
class USleepVideoSync : public VideoSync |
266 | 267 | |
267 | 268 | QString getName(void) const { return QString("USleep"); } |
268 | 269 | bool TryInit(void); |
269 | | void WaitForFrame(int sync_delay); |
| 270 | int WaitForFrame(int sync_delay); |
270 | 271 | }; |
271 | 272 | #endif /* VSYNC_H_INCLUDED */ |