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

  1. //    VirtualDub - Video processing and capture application
  2. //    A/V interface library
  3. //    Copyright (C) 1998-2007 Avery Lee
  4. //
  5. //    This program is free software; you can redistribute it and/or modify
  6. //    it under the terms of the GNU General Public License as published by
  7. //    the Free Software Foundation; either version 2 of the License, or
  8. //    (at your option) any later version.
  9. //
  10. //    This program is distributed in the hope that it will be useful,
  11. //    but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. //    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. //    GNU General Public License for more details.
  14. //
  15. //    You should have received a copy of the GNU General Public License
  16. //    along with this program; if not, write to the Free Software
  17. //    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19. #include <windows.h>
  20. #include <vd2/system/w32assist.h>
  21. #include "displaymgr.h"
  22.  
  23. ///////////////////////////////////////////////////////////////////////////
  24. VDVideoDisplayClient::VDVideoDisplayClient()
  25.     : mpManager(NULL)
  26.     , mbPreciseMode(false)
  27.     , mbTicksEnabled(false)
  28.     , mbRequiresFullScreen(false)
  29. {
  30. }
  31.  
  32. VDVideoDisplayClient::~VDVideoDisplayClient() {
  33. }
  34.  
  35. void VDVideoDisplayClient::Attach(VDVideoDisplayManager *pManager) {
  36.     VDASSERT(!mpManager);
  37.     mpManager = pManager;
  38.     if (mbTicksEnabled)
  39.         mpManager->ModifyTicksEnabled(true);
  40.     if (mbPreciseMode)
  41.         mpManager->ModifyPreciseMode(true);
  42. }
  43.  
  44. void VDVideoDisplayClient::Detach(VDVideoDisplayManager *pManager) {
  45.     VDASSERT(mpManager == pManager);
  46.     if (mbPreciseMode)
  47.         mpManager->ModifyPreciseMode(false);
  48.     if (mbTicksEnabled)
  49.         mpManager->ModifyTicksEnabled(false);
  50.     mpManager = NULL;
  51. }
  52.  
  53. void VDVideoDisplayClient::SetPreciseMode(bool enabled) {
  54.     if (mbPreciseMode == enabled)
  55.         return;
  56.  
  57.     mbPreciseMode = enabled;
  58.     mpManager->ModifyPreciseMode(enabled);
  59. }
  60.  
  61. void VDVideoDisplayClient::SetTicksEnabled(bool enabled) {
  62.     if (mbTicksEnabled == enabled)
  63.         return;
  64.  
  65.     mbTicksEnabled = enabled;
  66.     mpManager->ModifyTicksEnabled(enabled);
  67. }
  68.  
  69. void VDVideoDisplayClient::SetRequiresFullScreen(bool enabled) {
  70.     if (mbRequiresFullScreen == enabled)
  71.         return;
  72.  
  73.     mbRequiresFullScreen = enabled;
  74. }
  75.  
  76. const uint8 *VDVideoDisplayClient::GetLogicalPalette() const {
  77.     return mpManager->GetLogicalPalette();
  78. }
  79.  
  80. HPALETTE VDVideoDisplayClient::GetPalette() const {
  81.     return mpManager->GetPalette();
  82. }
  83.  
  84. void VDVideoDisplayClient::RemapPalette() {
  85.     mpManager->RemapPalette();
  86. }
  87.  
  88. ///////////////////////////////////////////////////////////////////////////
  89.  
  90. VDVideoDisplayManager::VDVideoDisplayManager()
  91.     : mTicksEnabledCount(0)
  92.     , mPreciseModeCount(0)
  93.     , mPreciseModePeriod(0)
  94.     , mhPalette(NULL)
  95.     , mWndClass(NULL)
  96.     , mhwnd(NULL)
  97.     , mbMultithreaded(false)
  98.     , mbAppActive(false)
  99.     , mbBackgroundFallbackEnabled(true)
  100.     , mThreadID(0)
  101.     , mOutstandingTicks(0)
  102. {
  103. }
  104.  
  105. VDVideoDisplayManager::~VDVideoDisplayManager() {
  106.     Shutdown();
  107. }
  108.  
  109. bool VDVideoDisplayManager::Init() {
  110.     if (!mbMultithreaded) {
  111.         if (!RegisterWindowClass()) {
  112.             Shutdown();
  113.             return false;
  114.         }
  115.  
  116.         mhwnd = CreateWindowEx(WS_EX_NOPARENTNOTIFY, (LPCTSTR)mWndClass, "", WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, VDGetLocalModuleHandleW32(), this);
  117.         if (!mhwnd) {
  118.             Shutdown();
  119.             return false;
  120.         }
  121.  
  122.         mThreadID = VDGetCurrentThreadID();
  123.     }
  124.  
  125.     if (!ThreadStart()) {
  126.         Shutdown();
  127.         return false;
  128.     }
  129.  
  130.     mStarted.wait();
  131.  
  132.     if (mbMultithreaded) {
  133.         mThreadID = getThreadID();
  134.     }
  135.  
  136.     return true;
  137. }
  138.  
  139. void VDVideoDisplayManager::Shutdown() {
  140.     VDASSERT(mClients.empty());
  141.  
  142.     if (isThreadAttached()) {
  143.         PostThreadMessage(getThreadID(), WM_QUIT, 0, 0);
  144.         ThreadWait();
  145.     }
  146.  
  147.     if (!mbMultithreaded) {
  148.         if (mhwnd) {
  149.             DestroyWindow(mhwnd);
  150.             mhwnd = NULL;
  151.         }
  152.  
  153.         UnregisterWindowClass();
  154.         mThreadID = 0;
  155.     }
  156. }
  157.  
  158. void VDVideoDisplayManager::SetBackgroundFallbackEnabled(bool enabled) {
  159.     if (mhwnd)
  160.         PostMessage(mhwnd, WM_USER+101, enabled, 0);
  161. }
  162.  
  163. void VDVideoDisplayManager::RemoteCall(void (*function)(void *), void *data) {
  164.     if (VDGetCurrentThreadID() == mThreadID) {
  165.         function(data);
  166.         return;
  167.     }
  168.  
  169.     RemoteCallNode node;
  170.     node.mpFunction = function;
  171.     node.mpData = data;
  172.  
  173.     vdsynchronized(mMutex) {
  174.         mRemoteCalls.push_back(&node);
  175.     }
  176.  
  177.     PostThreadMessage(getThreadID(), WM_NULL, 0, 0);
  178.  
  179.     HANDLE h = node.mSignal.getHandle();
  180.     for(;;) {
  181.         DWORD dwResult = MsgWaitForMultipleObjects(1, &h, FALSE, INFINITE, QS_SENDMESSAGE);
  182.  
  183.         if (dwResult != WAIT_OBJECT_0+1)
  184.             break;
  185.  
  186.         MSG msg;
  187.         while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE | PM_QS_SENDMESSAGE)) {
  188.             TranslateMessage(&msg);
  189.             DispatchMessage(&msg);
  190.         }
  191.     }
  192. }
  193.  
  194. void VDVideoDisplayManager::AddClient(VDVideoDisplayClient *pClient) {
  195.     VDASSERT(VDGetCurrentThreadID() == mThreadID);
  196.     mClients.push_back(pClient);
  197.     pClient->Attach(this);
  198. }
  199.  
  200. void VDVideoDisplayManager::RemoveClient(VDVideoDisplayClient *pClient) {
  201.     VDASSERT(VDGetCurrentThreadID() == mThreadID);
  202.     pClient->Detach(this);
  203.     mClients.erase(mClients.fast_find(pClient));
  204. }
  205.  
  206. void VDVideoDisplayManager::ModifyPreciseMode(bool enabled) {
  207.     VDASSERT(VDGetCurrentThreadID() == mThreadID);
  208.     if (enabled) {
  209.         int rc = ++mPreciseModeCount;
  210.         VDASSERT(rc < 100000);
  211.         if (rc == 1) {
  212.             TIMECAPS tc;
  213.             if (!mPreciseModePeriod &&
  214.                 TIMERR_NOERROR == ::timeGetDevCaps(&tc, sizeof tc) &&
  215.                 TIMERR_NOERROR == ::timeBeginPeriod(tc.wPeriodMin))
  216.             {
  217.                 mPreciseModePeriod = tc.wPeriodMin;
  218.                 SetThreadPriority(getThreadHandle(), THREAD_PRIORITY_HIGHEST);
  219.             }
  220.         }
  221.     } else {
  222.         int rc = --mPreciseModeCount;
  223.         VDASSERT(rc >= 0);
  224.         if (!rc) {
  225.             if (mPreciseModePeriod) {
  226.                 timeEndPeriod(mPreciseModePeriod);
  227.                 mPreciseModePeriod = 0;
  228.             }
  229.         }
  230.     }
  231. }
  232.  
  233. void VDVideoDisplayManager::ModifyTicksEnabled(bool enabled) {
  234.     VDASSERT(VDGetCurrentThreadID() == mThreadID);
  235.     if (enabled) {
  236.         int rc = ++mTicksEnabledCount;
  237.         VDASSERT(rc < 100000);
  238.  
  239.         if (rc == 1) {
  240.             PostThreadMessage(getThreadID(), WM_NULL, 0, 0);
  241.             if (!mbMultithreaded)
  242.                 mTickTimerId = SetTimer(mhwnd, kTimerID_Tick, 10, NULL);
  243.         }
  244.     } else {
  245.         int rc = --mTicksEnabledCount;
  246.         VDASSERT(rc >= 0);
  247.  
  248.         if (!rc) {
  249.             if (!mbMultithreaded && mTickTimerId) {
  250.                 KillTimer(mhwnd, mTickTimerId);
  251.                 mTickTimerId = 0;
  252.             }
  253.         }
  254.     }
  255. }
  256.  
  257. void VDVideoDisplayManager::ThreadRun() {
  258.     if (mbMultithreaded)
  259.         ThreadRunFullRemote();
  260.     else
  261.         ThreadRunTimerOnly();
  262. }
  263.  
  264. void VDVideoDisplayManager::ThreadRunFullRemote() {
  265.     if (RegisterWindowClass()) {
  266.         mhwnd = CreateWindowEx(WS_EX_NOPARENTNOTIFY, (LPCTSTR)mWndClass, "", WS_OVERLAPPEDWINDOW, 0, 0, 0, 0, NULL, NULL, VDGetLocalModuleHandleW32(), this);
  267.  
  268.         if (mhwnd) {
  269.             MSG msg;
  270.             PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  271.             mThreadID = VDGetCurrentThreadID();
  272.             mStarted.signal();
  273.  
  274.             bool timerActive = false;
  275.             for(;;) {
  276.                 DWORD ret = MsgWaitForMultipleObjects(0, NULL, TRUE, 1, QS_ALLINPUT);
  277.  
  278.                 if (ret == WAIT_OBJECT_0) {
  279.                     bool success = false;
  280.                     while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  281.                         if (msg.message == WM_QUIT)
  282.                             goto xit;
  283.                         success = true;
  284.                         TranslateMessage(&msg);
  285.                         DispatchMessage(&msg);
  286.                     }
  287.  
  288.                     DispatchRemoteCalls();
  289.  
  290.                     if (success)
  291.                         continue;
  292.  
  293.                     ret = WAIT_TIMEOUT;
  294.                     ::Sleep(1);
  295.                 }
  296.                 
  297.                 if (ret == WAIT_TIMEOUT) {
  298.                     if (mTicksEnabledCount > 0) {
  299.                         if (!timerActive) {
  300.                             timerActive = true;
  301.                             mTickTimerId = SetTimer(mhwnd, kTimerID_Tick, 10, NULL);
  302.                         }
  303.                         DispatchTicks();
  304.                     } else {
  305.                         if (timerActive) {
  306.                             timerActive = false;
  307.                             if (mTickTimerId) {
  308.                                 KillTimer(mhwnd, mTickTimerId);
  309.                                 mTickTimerId = 0;
  310.                             }
  311.                         }
  312.                         WaitMessage();
  313.                     }
  314.                 } else
  315.                     break;
  316.             }
  317. xit:
  318.             DestroyWindow(mhwnd);
  319.             mhwnd = NULL;
  320.         }
  321.     }
  322.     UnregisterWindowClass();
  323. }
  324.  
  325. void VDVideoDisplayManager::ThreadRunTimerOnly() {
  326.     MSG msg;
  327.     PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  328.     mStarted.signal();
  329.  
  330.     for(;;) {
  331.         DWORD ret = MsgWaitForMultipleObjects(0, NULL, TRUE, 1, QS_ALLINPUT);
  332.  
  333.         if (ret == WAIT_OBJECT_0) {
  334.             bool success = false;
  335.             while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
  336.                 if (msg.message == WM_QUIT)
  337.                     return;
  338.                 success = true;
  339.                 TranslateMessage(&msg);
  340.                 DispatchMessage(&msg);
  341.             }
  342.  
  343.             if (success)
  344.                 continue;
  345.  
  346.             ret = WAIT_TIMEOUT;
  347.             ::Sleep(1);
  348.         }
  349.         
  350.         if (ret == WAIT_TIMEOUT) {
  351.             if (mTicksEnabledCount > 0)
  352.                 PostTick();
  353.             else
  354.                 WaitMessage();
  355.         } else
  356.             break;
  357.     }
  358. }
  359.  
  360. void VDVideoDisplayManager::DispatchTicks() {
  361.     Clients::iterator it(mClients.begin()), itEnd(mClients.end());
  362.     for(; it!=itEnd; ++it) {
  363.         VDVideoDisplayClient *pClient = *it;
  364.  
  365.         if (pClient->mbTicksEnabled)
  366.             pClient->OnTick();
  367.     }
  368. }
  369.  
  370. void VDVideoDisplayManager::PostTick() {
  371.     if (!mOutstandingTicks.xchg(1)) {
  372.         PostMessage(mhwnd, WM_TIMER, kTimerID_Tick, 0);
  373.     }
  374. }
  375.  
  376. void VDVideoDisplayManager::DispatchRemoteCalls() {
  377.     vdsynchronized(mMutex) {
  378.         while(!mRemoteCalls.empty()) {
  379.             RemoteCallNode *rcn = mRemoteCalls.back();
  380.             mRemoteCalls.pop_back();
  381.             rcn->mpFunction(rcn->mpData);
  382.             rcn->mSignal.signal();
  383.         }
  384.     }
  385. }
  386.  
  387. ///////////////////////////////////////////////////////////////////////////////
  388.  
  389. bool VDVideoDisplayManager::RegisterWindowClass() {
  390.     WNDCLASS wc;
  391.     HMODULE hInst = VDGetLocalModuleHandleW32();
  392.  
  393.     wc.style            = 0;
  394.     wc.lpfnWndProc        = StaticWndProc;
  395.     wc.cbClsExtra        = 0;
  396.     wc.cbWndExtra        = sizeof(VDVideoDisplayManager *);
  397.     wc.hInstance        = hInst;
  398.     wc.hIcon            = 0;
  399.     wc.hCursor            = 0;
  400.     wc.hbrBackground    = 0;
  401.     wc.lpszMenuName        = 0;
  402.  
  403.     char buf[64];
  404.     sprintf(buf, "VDVideoDisplayManager(%p)", this);
  405.     wc.lpszClassName    = buf;
  406.  
  407.     mWndClass = RegisterClass(&wc);
  408.  
  409.     return mWndClass != NULL;
  410. }
  411.  
  412. void VDVideoDisplayManager::UnregisterWindowClass() {
  413.     if (mWndClass) {
  414.         HMODULE hInst = VDGetLocalModuleHandleW32();
  415.         UnregisterClass((LPCTSTR)mWndClass, hInst);
  416.         mWndClass = NULL;
  417.     }
  418. }
  419.  
  420. void VDVideoDisplayManager::RemapPalette() {
  421.     PALETTEENTRY pal[216];
  422.     struct {
  423.         LOGPALETTE hdr;
  424.         PALETTEENTRY palext[255];
  425.     } physpal;
  426.  
  427.     physpal.hdr.palVersion = 0x0300;
  428.     physpal.hdr.palNumEntries = 256;
  429.  
  430.     int i;
  431.  
  432.     for(i=0; i<216; ++i) {
  433.         pal[i].peRed    = (BYTE)((i / 36) * 51);
  434.         pal[i].peGreen    = (BYTE)(((i%36) / 6) * 51);
  435.         pal[i].peBlue    = (BYTE)((i%6) * 51);
  436.     }
  437.  
  438.     for(i=0; i<256; ++i) {
  439.         physpal.hdr.palPalEntry[i].peRed    = 0;
  440.         physpal.hdr.palPalEntry[i].peGreen    = 0;
  441.         physpal.hdr.palPalEntry[i].peBlue    = (BYTE)i;
  442.         physpal.hdr.palPalEntry[i].peFlags    = PC_EXPLICIT;
  443.     }
  444.  
  445.     if (HDC hdc = GetDC(0)) {
  446.         GetSystemPaletteEntries(hdc, 0, 256, physpal.hdr.palPalEntry);
  447.         ReleaseDC(0, hdc);
  448.     }
  449.  
  450.     if (HPALETTE hpal = CreatePalette(&physpal.hdr)) {
  451.         for(i=0; i<216; ++i) {
  452.             mLogicalPalette[i] = (uint8)GetNearestPaletteIndex(hpal, RGB(pal[i].peRed, pal[i].peGreen, pal[i].peBlue));
  453.         }
  454.  
  455.         DeleteObject(hpal);
  456.     }
  457. }
  458.  
  459. bool VDVideoDisplayManager::IsDisplayPaletted() {
  460.     bool bPaletted = false;
  461.  
  462.     if (HDC hdc = GetDC(0)) {
  463.         if (GetDeviceCaps(hdc, BITSPIXEL) <= 8)        // RC_PALETTE doesn't seem to be set if you switch to 8-bit in Win98 without rebooting.
  464.             bPaletted = true;
  465.         ReleaseDC(0, hdc);
  466.     }
  467.  
  468.     return bPaletted;
  469. }
  470.  
  471. void VDVideoDisplayManager::CreateDitheringPalette() {
  472.     if (mhPalette)
  473.         return;
  474.  
  475.     struct {
  476.         LOGPALETTE hdr;
  477.         PALETTEENTRY palext[255];
  478.     } pal;
  479.  
  480.     pal.hdr.palVersion = 0x0300;
  481.     pal.hdr.palNumEntries = 216;
  482.  
  483.     for(int i=0; i<216; ++i) {
  484.         pal.hdr.palPalEntry[i].peRed    = (BYTE)((i / 36) * 51);
  485.         pal.hdr.palPalEntry[i].peGreen    = (BYTE)(((i%36) / 6) * 51);
  486.         pal.hdr.palPalEntry[i].peBlue    = (BYTE)((i%6) * 51);
  487.         pal.hdr.palPalEntry[i].peFlags    = 0;
  488.     }
  489.  
  490.     mhPalette = CreatePalette(&pal.hdr);
  491. }
  492.  
  493. void VDVideoDisplayManager::DestroyDitheringPalette() {
  494.     if (mhPalette) {
  495.         DeleteObject(mhPalette);
  496.         mhPalette = NULL;
  497.     }
  498. }
  499.  
  500. void VDVideoDisplayManager::CheckForegroundState() {
  501.     bool appActive = true;
  502.     
  503.     if (mbBackgroundFallbackEnabled)
  504.         appActive = VDIsForegroundTaskW32();
  505.  
  506.     if (mbAppActive != appActive) {
  507.         mbAppActive = appActive;
  508.  
  509.         // Don't handle this synchronously in case we're handling a message in the minidriver!
  510.         PostMessage(mhwnd, WM_USER + 100, 0, 0);
  511.     }
  512. }
  513.  
  514. LRESULT CALLBACK VDVideoDisplayManager::StaticWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  515.     if (msg == WM_NCCREATE) {
  516.         const CREATESTRUCT& cs = *(const CREATESTRUCT *)lParam;
  517.  
  518.         SetWindowLongPtr(hwnd, 0, (LONG_PTR)cs.lpCreateParams);
  519.     } else {
  520.         VDVideoDisplayManager *pThis = (VDVideoDisplayManager *)GetWindowLongPtr(hwnd, 0);
  521.  
  522.         if (pThis)
  523.             return pThis->WndProc(hwnd, msg, wParam, lParam);
  524.     }
  525.  
  526.     return DefWindowProc(hwnd, msg, wParam, lParam);
  527. }
  528.  
  529. LRESULT CALLBACK VDVideoDisplayManager::WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  530.     switch(msg) {
  531.         case WM_CREATE:
  532.             if (mbMultithreaded)
  533.                 SetTimer(hwnd, kTimerID_ForegroundPoll, 500, NULL);
  534.             break;
  535.  
  536.         case WM_ACTIVATEAPP:
  537.             CheckForegroundState();
  538.             break;
  539.  
  540.         case WM_TIMER:
  541.             switch(wParam) {
  542.             case kTimerID_ForegroundPoll:
  543.                 CheckForegroundState();
  544.                 break;
  545.  
  546.             case kTimerID_Tick:
  547.                 if (mOutstandingTicks.xchg(0))
  548.                     DispatchTicks();
  549.                 break;
  550.             }
  551.             break;
  552.  
  553.         case WM_DISPLAYCHANGE:
  554.             {
  555.                 bool bPaletted = IsDisplayPaletted();
  556.  
  557.                 if (bPaletted)
  558.                     CreateDitheringPalette();
  559.  
  560.                 for(Clients::iterator it(mClients.begin()), itEnd(mClients.end()); it!=itEnd; ++it) {
  561.                     VDVideoDisplayClient *p = *it;
  562.  
  563.                     if (!p->mbRequiresFullScreen)
  564.                         p->OnDisplayChange();
  565.                 }
  566.  
  567.                 if (!bPaletted)
  568.                     DestroyDitheringPalette();
  569.             }
  570.             break;
  571.  
  572.         // Yes, believe it or not, we still support palettes, even when DirectDraw is active.
  573.         // Why?  Very occasionally, people still have to run in 8-bit mode, and a program
  574.         // should still display something half-decent in that case.  Besides, it's kind of
  575.         // neat to be able to dither in safe mode.
  576.         case WM_PALETTECHANGED:
  577.             {
  578.                 DWORD dwProcess;
  579.  
  580.                 GetWindowThreadProcessId((HWND)wParam, &dwProcess);
  581.  
  582.                 if (dwProcess != GetCurrentProcessId()) {
  583.                     for(Clients::iterator it(mClients.begin()), itEnd(mClients.end()); it!=itEnd; ++it) {
  584.                         VDVideoDisplayClient *p = *it;
  585.  
  586.                         if (!p->mbRequiresFullScreen)
  587.                             p->OnRealizePalette();
  588.                     }
  589.                 }
  590.             }
  591.             break;
  592.  
  593.         case WM_USER+100:
  594.             {
  595.                 for(Clients::iterator it(mClients.begin()), itEnd(mClients.end()); it!=itEnd; ++it) {
  596.                     VDVideoDisplayClient *p = *it;
  597.  
  598.                     p->OnForegroundChange(mbAppActive);
  599.                 }
  600.             }
  601.             break;
  602.  
  603.         case WM_USER+101:
  604.             {
  605.                 bool enabled = wParam != 0;
  606.  
  607.                 if (mbBackgroundFallbackEnabled != enabled) {
  608.                     mbBackgroundFallbackEnabled = enabled;
  609.  
  610.                     CheckForegroundState();
  611.                 }
  612.             }
  613.             break;
  614.     }
  615.  
  616.     return DefWindowProc(hwnd, msg, wParam, lParam);
  617. }
  618.  
  619.