Ticket #7067: t7067_avsync_improvements_rev2.diff
File t7067_avsync_improvements_rev2.diff, 12.7 KB (added by , 14 years ago) |
---|
-
libs/libmythtv/NuppelVideoPlayer.cpp
704 704 m_double_framerate = false; 705 705 m_double_process = false; 706 706 707 if (videosync)708 videosync->SetFrameInterval(frame_interval, false);709 710 707 if (videoOutput) 711 708 videoOutput->FallbackDeint(); 712 709 } … … 780 777 if (interlaced && !m_deint_possible) 781 778 { 782 779 m_scan = scan; 783 videosync->SetFrameInterval(frame_interval, false);784 780 return; 785 781 } 786 782 … … 796 792 if (videoOutput->NeedsDoubleFramerate()) 797 793 { 798 794 m_double_framerate = true; 799 videosync->SetFrameInterval(frame_interval, true); 800 // Make sure video sync can double frame rate 801 m_can_double = videosync->UsesFieldInterval(); 795 m_can_double = (frame_interval / 2 > videosync->getRefreshInterval() * 0.995); 802 796 if (!m_can_double) 803 797 { 804 798 VERBOSE(VB_IMPORTANT, LOC + "Video sync method can't support " … … 815 809 { 816 810 m_double_process = false; 817 811 m_double_framerate = false; 818 videosync->SetFrameInterval(frame_interval, false);819 812 videoOutput->SetDeinterlacingEnabled(false); 820 813 VERBOSE(VB_PLAYBACK, LOC + "Disabled deinterlacing"); 821 814 } … … 1571 1564 void NuppelVideoPlayer::AVSync(bool limit_delay) 1572 1565 { 1573 1566 float diverge = 0.0f; 1567 int frameDelay = m_double_framerate ? frame_interval / 2 : frame_interval; 1574 1568 // attempt to reduce fps for standalone PIP 1575 1569 if (player_ctx->IsPIP() && framesPlayed % 2) 1576 1570 { 1577 videosync->WaitForFrame(avsync_adjustment); 1578 videosync->AdvanceTrigger(); 1571 videosync->WaitForFrame(frameDelay + avsync_adjustment); 1579 1572 if (!using_null_videoout) 1580 1573 videoOutput->SetFramesPlayed(framesPlayed + 1); 1581 1574 return; … … 1606 1599 if (kScan_Detect == m_scan || kScan_Ignore == m_scan) 1607 1600 ps = kScan_Progressive; 1608 1601 1609 bool dropframe = false;1610 1602 if (diverge < -MAXDIVERGE) 1611 1603 { 1612 dropframe = true;1613 1604 // If video is way behind of audio, adjust for it... 1614 1605 QString dbg = QString("Video is %1 frames behind audio (too slow), ") 1615 1606 .arg(-diverge); … … 1643 1634 1644 1635 VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString("AVSync waitforframe %1 %2") 1645 1636 .arg(avsync_adjustment).arg(m_double_framerate)); 1646 videosync->WaitForFrame( avsync_adjustment + repeat_delay);1637 videosync->WaitForFrame(frameDelay + avsync_adjustment + repeat_delay); 1647 1638 VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, "AVSync show"); 1648 1639 videoOutput->Show(ps); 1649 1640 … … 1673 1664 videoOutput->PrepareFrame(buffer, ps, osd); 1674 1665 1675 1666 // Display the second field 1676 videosync->AdvanceTrigger(); 1677 videosync->WaitForFrame(avsync_adjustment); 1667 videosync->WaitForFrame(frameDelay + avsync_adjustment); 1678 1668 videoOutput->Show(ps); 1679 1669 } 1680 1670 … … 1686 1676 } 1687 1677 else 1688 1678 { 1689 videosync->WaitForFrame( 0);1679 videosync->WaitForFrame(frameDelay); 1690 1680 } 1691 1681 1692 1682 if (output_jmeter) 1693 1683 output_jmeter->RecordCycleTime(); 1694 1684 1695 if (!dropframe)1696 videosync->AdvanceTrigger();1697 1685 avsync_adjustment = 0; 1698 1686 1699 1687 if (diverge > MAXDIVERGE) … … 1728 1716 prevtc = buffer->timecode; 1729 1717 //cerr << delta << " "; 1730 1718 1719 avsync_delay = (buffer->timecode - currentaudiotime) * 1000;//usec 1720 // prevents major jitter when pts resets during dvd title 1721 if (avsync_delay > 2000000 && limit_delay) 1722 avsync_delay = 90000; 1723 avsync_avg = (avsync_delay + (avsync_avg * 3)) / 4; 1724 1731 1725 // If the timecode is off by a frame (dropped frame) wait to sync 1732 1726 if (delta > (int) frame_interval / 1200 && 1733 1727 delta < (int) frame_interval / 1000 * 3 && 1734 1728 prevrp == 0) 1735 1729 { 1736 //cerr << "+ "; 1737 videosync->AdvanceTrigger(); 1738 if (m_double_framerate) 1739 videosync->AdvanceTrigger(); 1730 // wait an extra frame interval 1731 avsync_adjustment = frame_interval; 1740 1732 } 1741 1733 prevrp = buffer->repeat_pict; 1742 1734 1743 avsync_delay = (buffer->timecode - currentaudiotime) * 1000;//usec1744 // prevents major jitter when pts resets during dvd title1745 if (avsync_delay > 2000000 && limit_delay)1746 avsync_delay = 90000;1747 avsync_avg = (avsync_delay + (avsync_avg * 3)) / 4;1748 1735 1749 1736 /* If the audio time codes and video diverge, shift 1750 1737 the video by one interlaced field (1/2 frame) */ … … 1752 1739 { 1753 1740 if (avsync_avg > frame_interval * 3 / 2) 1754 1741 { 1755 avsync_adjustment = refreshrate;1742 avsync_adjustment += refreshrate; 1756 1743 lastsync = true; 1757 1744 } 1758 1745 else if (avsync_avg < 0 - frame_interval * 3 / 2) 1759 1746 { 1760 avsync_adjustment = -refreshrate;1747 avsync_adjustment -= refreshrate; 1761 1748 lastsync = true; 1762 1749 } 1763 1750 } … … 1987 1974 // Make sure video sync can do it 1988 1975 if (videosync != NULL && m_double_framerate) 1989 1976 { 1990 videosync->SetFrameInterval(frame_interval, m_double_framerate); 1991 m_can_double = videosync->UsesFieldInterval(); 1977 m_can_double = (frame_interval / 2 > videosync->getRefreshInterval() * 0.995); 1992 1978 if (!m_can_double) 1993 1979 { 1994 1980 VERBOSE(VB_IMPORTANT, "Video sync method can't support double " … … 3007 2993 3008 2994 m_double_framerate = videoOutput->NeedsDoubleFramerate(); 3009 2995 m_double_process = videoOutput->IsExtraProcessingRequired(); 3010 videosync->SetFrameInterval(frame_interval, m_double_framerate);3011 2996 } 3012 2997 3013 2998 if (normal_speed && audio.HasAudioOut()) -
libs/libmythtv/vsync.cpp
128 128 m_delay(-1) 129 129 { 130 130 bzero(&m_nexttrigger, sizeof(m_nexttrigger)); 131 132 int tolerance = m_refresh_interval / 200;133 if (m_interlaced && m_refresh_interval > ((m_frame_interval/2) + tolerance))134 m_interlaced = false; // can't display both fields at 2x rate135 136 //cout << "Frame interval: " << m_frame_interval << endl;137 131 } 138 132 139 133 void VideoSync::Start(void) … … 141 135 gettimeofday(&m_nexttrigger, NULL); // now 142 136 } 143 137 144 /** \fn VideoSync::SetFrameInterval(int fr, bool intr)145 * \brief Change frame interval and interlacing attributes146 */147 void VideoSync::SetFrameInterval(int fr, bool intr)148 {149 m_frame_interval = fr;150 m_interlaced = intr;151 int tolerance = m_refresh_interval / 200;152 if (m_interlaced && m_refresh_interval > ((m_frame_interval/2) + tolerance))153 m_interlaced = false; // can't display both fields at 2x rate154 155 VERBOSE(VB_PLAYBACK, LOC + QString("Set video sync frame interval to %1")156 .arg(m_frame_interval));157 }158 159 138 void VideoSync::OffsetTimeval(struct timeval& tv, int offset) 160 139 { 161 140 tv.tv_usec += offset; … … 171 150 } 172 151 } 173 152 174 /** \fn VideoSync::UpdateNexttrigger()175 * \brief Internal method to tells video synchronization method to use176 * the next frame (or field, if interlaced) for CalcDelay()177 * and WaitForFrame().178 */179 void VideoSync::UpdateNexttrigger()180 {181 // Offset by frame interval -- if interlaced, only delay by half182 // frame interval183 if (m_interlaced)184 OffsetTimeval(m_nexttrigger, m_frame_interval/2);185 else186 OffsetTimeval(m_nexttrigger, m_frame_interval);187 }188 189 153 /** \fn VideoSync::CalcDelay() 190 154 * \brief Calculates the delay to the next frame. 191 155 * … … 372 336 //cerr << "Wait " << n << " intervals. Count " << blank.request.sequence; 373 337 //cerr << " Delay " << m_delay << endl; 374 338 } 375 }376 339 377 void DRMVideoSync::AdvanceTrigger(void)378 {379 340 KeepPhase(); 380 UpdateNexttrigger();381 341 } 382 342 #endif /* !_WIN32 */ 383 343 … … 480 440 m_context->WaitForVideoSync((n+1), (frameNum+n)%(n+1), &frameNum); 481 441 m_delay = CalcDelay(); 482 442 } 483 #endif /* USING_OPENGL_VSYNC */484 }485 443 486 void OpenGLVideoSync::AdvanceTrigger(void)487 {488 #ifdef USING_OPENGL_VSYNC489 490 444 KeepPhase(); 491 UpdateNexttrigger();492 445 #endif /* USING_OPENGL_VSYNC */ 493 446 } 494 447 #endif /* !_WIN32 */ … … 551 504 usleep(m_delay); 552 505 } 553 506 } 554 555 void RTCVideoSync::AdvanceTrigger(void)556 {557 UpdateNexttrigger();558 }559 507 #endif /* __linux__ */ 560 508 561 509 #ifdef USING_VDPAU … … 590 538 VideoOutputVDPAU *vo = (VideoOutputVDPAU *)(m_video_output); 591 539 vo->SetNextFrameDisplayTimeOffset(m_delay); 592 540 } 593 594 void VDPAUVideoSync::AdvanceTrigger(void)595 {596 UpdateNexttrigger();597 }598 599 541 #endif 600 542 601 543 BusyWaitVideoSync::BusyWaitVideoSync(VideoOutput *vo, … … 646 588 } 647 589 } 648 590 649 void BusyWaitVideoSync::AdvanceTrigger(void)650 {651 UpdateNexttrigger();652 }653 654 591 USleepVideoSync::USleepVideoSync(VideoOutput *vo, 655 592 int fr, int ri, bool intl) : 656 593 VideoSync(vo, fr, ri, intl) … … 676 613 usleep(m_delay); 677 614 } 678 615 679 void USleepVideoSync::AdvanceTrigger(void)680 {681 UpdateNexttrigger();682 } -
libs/libmythtv/vsync.h
39 39 * The factory method BestMethod tries subclasses in roughly quality 40 40 * order until one succeeds. 41 41 * 42 * A/V sync methods may supply an additonal delay per frame. Other42 * A/V sync methods may supply the nominal delay per frame. Other 43 43 * than that, video timing is entirely up to these classes. When 44 44 * WaitForFrame returns, it is time to show the frame. 45 *46 * There is some basic support for interlaced video timing where the47 * fields need to be displayed sequentially. Passing true for the48 * interlaced flags for the constructors, BestMethod, and49 * SetFrameInterval will cause us to wait for half the specified frame50 * interval, if the refresh rate is sufficient to do so.51 45 */ 52 46 class VideoSync 53 47 // virtual base class … … 80 74 */ 81 75 virtual void WaitForFrame(int sync_delay) = 0; 82 76 83 /// \brief Use the next frame or field for CalcDelay(void) 84 /// and WaitForFrame(int). 85 virtual void AdvanceTrigger(void) = 0; 77 /// \brief Returns the (minimum) refresh interval of the output device. 78 int getRefreshInterval(void) const { return m_refresh_interval; } 86 79 87 void SetFrameInterval(int fi, bool interlaced);88 89 /// \brief Returns true AdvanceTrigger(void) advances a field at a time.90 bool UsesFieldInterval(void) const { return m_interlaced; }91 /// \brief Returns true AdvanceTrigger(void) advances a frame at a time.92 bool UsesFrameInterval(void) const { return !m_interlaced; }93 94 80 /** \brief Stops VSync; must be called from main thread. 95 81 * 96 82 * Start(void), WaitForFrame(void), and Stop(void) should … … 105 91 bool interlaced); 106 92 protected: 107 93 static void OffsetTimeval(struct timeval& tv, int offset); 108 void UpdateNexttrigger(void);109 94 int CalcDelay(void); 110 95 void KeepPhase(void); 111 96 … … 137 122 bool TryInit(void); 138 123 void Start(void); 139 124 void WaitForFrame(int sync_delay); 140 void AdvanceTrigger(void);141 125 142 126 private: 143 127 int m_dri_fd; … … 179 163 bool TryInit(void); 180 164 void Start(void); 181 165 void WaitForFrame(int sync_delay); 182 void AdvanceTrigger(void);183 166 184 167 private: 185 168 MythRenderOpenGL *m_context; … … 208 191 QString getName(void) const { return QString("RTC"); } 209 192 bool TryInit(void); 210 193 void WaitForFrame(int sync_delay); 211 void AdvanceTrigger(void);212 194 213 195 private: 214 196 int m_rtcfd; … … 229 211 QString getName(void) const { return QString("VDPAU"); } 230 212 bool TryInit(void); 231 213 void WaitForFrame(int sync_delay); 232 void AdvanceTrigger(void);233 214 234 215 private: 235 216 }; … … 257 238 QString getName(void) const { return QString("USleep with busy wait"); } 258 239 bool TryInit(void); 259 240 void WaitForFrame(int sync_delay); 260 void AdvanceTrigger(void);261 241 262 242 private: 263 243 int m_cheat; … … 285 265 QString getName(void) const { return QString("USleep"); } 286 266 bool TryInit(void); 287 267 void WaitForFrame(int sync_delay); 288 void AdvanceTrigger(void);289 268 }; 290 269 #endif /* VSYNC_H_INCLUDED */