home *** CD-ROM | disk | FTP | other *** search
/ Computer Shopper 275 / DPCS0111DVD.ISO / Toolkit / Audio-Visual / VirtualDub / Source / VirtualDub-1.9.10-src.7z / src / system / source / time.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  6.5 KB  |  271 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    System library component
  3. //    Copyright (C) 1998-2004 Avery Lee, All Rights Reserved.
  4. //
  5. //    Beginning with 1.6.0, the VirtualDub system library is licensed
  6. //    differently than the remainder of VirtualDub.  This particular file is
  7. //    thus licensed as follows (the "zlib" license):
  8. //
  9. //    This software is provided 'as-is', without any express or implied
  10. //    warranty.  In no event will the authors be held liable for any
  11. //    damages arising from the use of this software.
  12. //
  13. //    Permission is granted to anyone to use this software for any purpose,
  14. //    including commercial applications, and to alter it and redistribute it
  15. //    freely, subject to the following restrictions:
  16. //
  17. //    1.    The origin of this software must not be misrepresented; you must
  18. //        not claim that you wrote the original software. If you use this
  19. //        software in a product, an acknowledgment in the product
  20. //        documentation would be appreciated but is not required.
  21. //    2.    Altered source versions must be plainly marked as such, and must
  22. //        not be misrepresented as being the original software.
  23. //    3.    This notice may not be removed or altered from any source
  24. //        distribution.
  25.  
  26. #include "stdafx.h"
  27. #include <new>
  28.  
  29. #include <windows.h>
  30. #include <mmsystem.h>
  31.  
  32. #include <vd2/system/time.h>
  33. #include <vd2/system/thread.h>
  34. #include <vd2/system/thunk.h>
  35.  
  36. #ifdef _MSC_VER
  37.     #pragma comment(lib, "winmm")
  38. #endif
  39.  
  40. uint32 VDGetCurrentTick() {
  41.     return (uint32)GetTickCount();
  42. }
  43.  
  44. uint64 VDGetPreciseTick() {
  45.     LARGE_INTEGER li;
  46.     QueryPerformanceCounter(&li);
  47.     return li.QuadPart;
  48. }
  49.  
  50. namespace {
  51.     uint64 VDGetPreciseTicksPerSecondNowI() {
  52.         LARGE_INTEGER freq;
  53.         QueryPerformanceFrequency(&freq);
  54.         return freq.QuadPart;
  55.     }
  56.  
  57.     double VDGetPreciseTicksPerSecondNow() {
  58.         LARGE_INTEGER freq;
  59.         QueryPerformanceFrequency(&freq);
  60.         return (double)freq.QuadPart;
  61.     }
  62. }
  63.  
  64. uint64 VDGetPreciseTicksPerSecondI() {
  65.     static uint64 ticksPerSecond = VDGetPreciseTicksPerSecondNowI();
  66.  
  67.     return ticksPerSecond;
  68. }
  69.  
  70. double VDGetPreciseTicksPerSecond() {
  71.     static double ticksPerSecond = VDGetPreciseTicksPerSecondNow();
  72.  
  73.     return ticksPerSecond;
  74. }
  75.  
  76. double VDGetPreciseSecondsPerTick() {
  77.     static double secondsPerTick = 1.0 / VDGetPreciseTicksPerSecondNow();
  78.  
  79.     return secondsPerTick;
  80. }
  81.  
  82. uint32 VDGetAccurateTick() {
  83.     return timeGetTime();
  84. }
  85.  
  86. ///////////////////////////////////////////////////////////////////////////////
  87. VDCallbackTimer::VDCallbackTimer()
  88.     : mTimerAccuracy(0)
  89. {
  90. }
  91.  
  92. VDCallbackTimer::~VDCallbackTimer() {
  93.     Shutdown();
  94. }
  95.  
  96. bool VDCallbackTimer::Init(IVDTimerCallback *pCB, uint32 period_ms) {
  97.     return Init2(pCB, period_ms * 10000);
  98. }
  99.  
  100. bool VDCallbackTimer::Init2(IVDTimerCallback *pCB, uint32 period_100ns) {
  101.     return Init3(pCB, period_100ns, period_100ns >> 1, true);
  102. }
  103.  
  104. bool VDCallbackTimer::Init3(IVDTimerCallback *pCB, uint32 period_100ns, uint32 accuracy_100ns, bool precise) {
  105.     Shutdown();
  106.  
  107.     mpCB = pCB;
  108.     mbExit = false;
  109.     mbPrecise = precise;
  110.  
  111.     UINT accuracy = accuracy_100ns / 10000;
  112.     if (accuracy > 10)
  113.         accuracy = 10;
  114.  
  115.     TIMECAPS tc;
  116.     if (TIMERR_NOERROR == timeGetDevCaps(&tc, sizeof tc)) {
  117.         if (accuracy < tc.wPeriodMin)
  118.             accuracy = tc.wPeriodMin;
  119.         if (accuracy > tc.wPeriodMax)
  120.             accuracy = tc.wPeriodMax;
  121.     }
  122.  
  123.     if (TIMERR_NOERROR == timeBeginPeriod(accuracy)) {
  124.         mTimerAccuracy = accuracy;
  125.         mTimerPeriod = period_100ns;
  126.         mTimerPeriodAdjustment = 0;
  127.         mTimerPeriodDelta = 0;
  128.  
  129.         if (ThreadStart())
  130.             return true;
  131.     }
  132.  
  133.     Shutdown();
  134.  
  135.     return false;
  136. }
  137.  
  138. void VDCallbackTimer::Shutdown() {
  139.     if (isThreadActive()) {
  140.         mbExit = true;
  141.         msigExit.signal();
  142.         ThreadWait();
  143.     }
  144.  
  145.     if (mTimerAccuracy) {
  146.         timeEndPeriod(mTimerAccuracy);
  147.         mTimerAccuracy = 0;
  148.     }
  149. }
  150.  
  151. void VDCallbackTimer::SetRateDelta(int delta_100ns) {
  152.     mTimerPeriodDelta = delta_100ns;
  153. }
  154.  
  155. void VDCallbackTimer::AdjustRate(int adjustment_100ns) {
  156.     mTimerPeriodAdjustment += adjustment_100ns;
  157. }
  158.  
  159. bool VDCallbackTimer::IsTimerRunning() const {
  160.     return const_cast<VDCallbackTimer *>(this)->isThreadActive();
  161. }
  162.  
  163. void VDCallbackTimer::ThreadRun() {
  164.     uint32 timerPeriod = mTimerPeriod;
  165.     uint32 periodHi = timerPeriod / 10000;
  166.     uint32 periodLo = timerPeriod % 10000;
  167.     uint32 nextTimeHi = VDGetAccurateTick() + periodHi;
  168.     uint32 nextTimeLo = periodLo;
  169.  
  170.     uint32 maxDelay = mTimerPeriod / 2000;
  171.  
  172.     SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);
  173.  
  174.     HANDLE hExit = msigExit.getHandle();
  175.  
  176.     if (!mbPrecise) {
  177.         while(!mbExit) {
  178.             DWORD res = ::WaitForSingleObject(hExit, periodHi);
  179.  
  180.             if (res != WAIT_TIMEOUT)
  181.                 break;
  182.  
  183.             mpCB->TimerCallback();
  184.         }
  185.     } else {
  186.         while(!mbExit) {
  187.             uint32 currentTime = VDGetAccurateTick();
  188.             sint32 delta = nextTimeHi - currentTime;
  189.  
  190.             if (delta > 0) {
  191.                 // safety guard against the clock going nuts
  192.                 DWORD res;
  193.                 if ((uint32)delta > maxDelay)
  194.                     res = ::WaitForSingleObject(hExit, maxDelay);
  195.                 else
  196.                     res = ::WaitForSingleObject(hExit, nextTimeHi - currentTime);
  197.  
  198.                 if (res != WAIT_TIMEOUT)
  199.                     break;
  200.             }
  201.  
  202.             if ((uint32)abs(delta) > maxDelay) {
  203.                 nextTimeHi = currentTime + periodHi;
  204.                 nextTimeLo = periodLo;
  205.             } else {
  206.                 nextTimeLo += periodLo;
  207.                 nextTimeHi += periodHi;
  208.                 if (nextTimeLo >= 10000) {
  209.                     nextTimeLo -= 10000;
  210.                     ++nextTimeHi;
  211.                 }
  212.             }
  213.  
  214.             mpCB->TimerCallback();
  215.  
  216.             int adjust = mTimerPeriodAdjustment.xchg(0);
  217.             int perdelta = mTimerPeriodDelta;
  218.  
  219.             if (adjust || perdelta) {
  220.                 timerPeriod += adjust;
  221.                 periodHi = (timerPeriod+perdelta) / 10000;
  222.                 periodLo = (timerPeriod+perdelta) % 10000;
  223.             }
  224.         }
  225.     }
  226. }
  227.  
  228. ///////////////////////////////////////////////////////////////////////////////
  229.  
  230. VDLazyTimer::VDLazyTimer()
  231.     : mTimerId(NULL)
  232.     , mpCB(NULL)
  233. {
  234.     if (!VDInitThunkAllocator())
  235.         throw MyError("Unable to initialize thunk allocator.");
  236.  
  237.     mpThunk = VDCreateFunctionThunkFromMethod(this, &VDLazyTimer::StaticTimeCallback, true);
  238.     if (!mpThunk) {
  239.         VDShutdownThunkAllocator();
  240.         throw MyError("Unable to create timer thunk.");
  241.     }
  242. }
  243.  
  244. VDLazyTimer::~VDLazyTimer() {
  245.     Stop();
  246.  
  247.     VDDestroyFunctionThunk(mpThunk);
  248.     VDShutdownThunkAllocator();
  249. }
  250.  
  251. void VDLazyTimer::SetOneShot(IVDTimerCallback *pCB, uint32 delay) {
  252.     Stop();
  253.  
  254.     mpCB = pCB;
  255.     mTimerId = SetTimer(NULL, 0, delay, (TIMERPROC)mpThunk);
  256. }
  257.  
  258. void VDLazyTimer::Stop() {
  259.     if (mTimerId) {
  260.         KillTimer(NULL, mTimerId);
  261.         mTimerId = 0;
  262.     }
  263. }
  264.  
  265. void VDLazyTimer::StaticTimeCallback(VDZHWND hwnd, VDZUINT msg, VDZUINT_PTR id, VDZDWORD time) {
  266.     Stop();
  267.  
  268.     if (mpCB)
  269.         mpCB->TimerCallback();
  270. }
  271.