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 / cap_screen.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2009-09-14  |  86.5 KB  |  2,857 lines

  1. //    VirtualDub - Video processing and capture application
  2. //    A/V interface library
  3. //    Copyright (C) 1998-2006 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. #ifdef _MSC_VER
  20.     #pragma warning(disable: 4786)        // STFU
  21. #endif
  22.  
  23. #include <vd2/Riza/capdriver.h>
  24. #include <vd2/Riza/opengl.h>
  25. #include <vd2/system/binary.h>
  26. #include <vd2/system/vdstring.h>
  27. #include <vd2/system/error.h>
  28. #include <vd2/system/time.h>
  29. #include <vd2/system/profile.h>
  30. #include <vd2/system/registry.h>
  31. #include <windows.h>
  32. #include <vector>
  33. #include "resource.h"
  34.  
  35. using namespace nsVDCapture;
  36.  
  37. extern HINSTANCE g_hInst;
  38.  
  39. namespace {
  40.     #include "cap_screen_glshaders.inl"
  41.  
  42.     DWORD AutodetectCaptureBltMode() {
  43.         OSVERSIONINFOA verinfo={sizeof(OSVERSIONINFOA)};
  44.  
  45.         if (GetVersionEx(&verinfo)) {
  46.             if (verinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  47.                 // Windows 2000 or newer
  48.                 if (verinfo.dwMajorVersion >= 5)
  49.                     return SRCCOPY | CAPTUREBLT;
  50.             } else if (verinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
  51.                 // Test for Windows 98 or newer
  52.                 if (verinfo.dwMajorVersion >= 5 || (verinfo.dwMajorVersion == 4 && verinfo.dwMinorVersion >= 10))
  53.                     return SRCCOPY | CAPTUREBLT;
  54.             }
  55.  
  56.         }
  57.  
  58.         return SRCCOPY;
  59.     }
  60. }
  61.  
  62. class VDCaptureDriverScreen : public IVDCaptureDriver, public IVDTimerCallback {
  63.     VDCaptureDriverScreen(const VDCaptureDriverScreen&);
  64.     VDCaptureDriverScreen& operator=(const VDCaptureDriverScreen&);
  65. public:
  66.     VDCaptureDriverScreen();
  67.     ~VDCaptureDriverScreen();
  68.  
  69.     void    *AsInterface(uint32 id) { return NULL; }
  70.  
  71.     bool    Init(VDGUIHandle hParent);
  72.     void    Shutdown();
  73.  
  74.     void    SetCallback(IVDCaptureDriverCallback *pCB);
  75.  
  76.     void    LockUpdates() {}
  77.     void    UnlockUpdates() {}
  78.  
  79.     bool    IsHardwareDisplayAvailable();
  80.  
  81.     void    SetDisplayMode(nsVDCapture::DisplayMode m);
  82.     nsVDCapture::DisplayMode        GetDisplayMode();
  83.  
  84.     void    SetDisplayRect(const vdrect32& r);
  85.     vdrect32    GetDisplayRectAbsolute();
  86.     void    SetDisplayVisibility(bool vis);
  87.  
  88.     void    SetFramePeriod(sint32 ms);
  89.     sint32    GetFramePeriod();
  90.  
  91.     uint32    GetPreviewFrameCount();
  92.  
  93.     bool    GetVideoFormat(vdstructex<BITMAPINFOHEADER>& vformat);
  94.     bool    SetVideoFormat(const BITMAPINFOHEADER *pbih, uint32 size);
  95.  
  96.     bool    SetTunerChannel(int channel) { return false; }
  97.     int        GetTunerChannel() { return -1; }
  98.     bool    GetTunerChannelRange(int& minChannel, int& maxChannel) { return false; }
  99.     uint32    GetTunerFrequencyPrecision() { return 0; }
  100.     uint32    GetTunerExactFrequency() { return 0; }
  101.     bool    SetTunerExactFrequency(uint32 freq) { return false; }
  102.     nsVDCapture::TunerInputMode    GetTunerInputMode() { return kTunerInputUnknown; }
  103.     void    SetTunerInputMode(nsVDCapture::TunerInputMode tunerMode) {}
  104.  
  105.     int        GetAudioDeviceCount();
  106.     const wchar_t *GetAudioDeviceName(int idx);
  107.     bool    SetAudioDevice(int idx);
  108.     int        GetAudioDeviceIndex();
  109.     bool    IsAudioDeviceIntegrated(int idx) { return false; }
  110.  
  111.     int        GetVideoSourceCount();
  112.     const wchar_t *GetVideoSourceName(int idx);
  113.     bool    SetVideoSource(int idx);
  114.     int        GetVideoSourceIndex();
  115.  
  116.     int        GetAudioSourceCount();
  117.     const wchar_t *GetAudioSourceName(int idx);
  118.     bool    SetAudioSource(int idx);
  119.     int        GetAudioSourceIndex();
  120.  
  121.     int        GetAudioInputCount();
  122.     const wchar_t *GetAudioInputName(int idx);
  123.     bool    SetAudioInput(int idx);
  124.     int        GetAudioInputIndex();
  125.  
  126.     int        GetAudioSourceForVideoSource(int idx) { return -2; }
  127.  
  128.     bool    IsAudioCapturePossible();
  129.     bool    IsAudioCaptureEnabled();
  130.     bool    IsAudioPlaybackPossible() { return false; }
  131.     bool    IsAudioPlaybackEnabled() { return false; }
  132.     void    SetAudioCaptureEnabled(bool b);
  133.     void    SetAudioAnalysisEnabled(bool b);
  134.     void    SetAudioPlaybackEnabled(bool b) {}
  135.  
  136.     void    GetAvailableAudioFormats(std::list<vdstructex<WAVEFORMATEX> >& aformats);
  137.  
  138.     bool    GetAudioFormat(vdstructex<WAVEFORMATEX>& aformat);
  139.     bool    SetAudioFormat(const WAVEFORMATEX *pwfex, uint32 size);
  140.  
  141.     bool    IsDriverDialogSupported(nsVDCapture::DriverDialog dlg);
  142.     void    DisplayDriverDialog(nsVDCapture::DriverDialog dlg);
  143.  
  144.     bool    IsPropertySupported(uint32 id) { return false; }
  145.     sint32    GetPropertyInt(uint32 id, bool *pAutomatic) { if (pAutomatic) *pAutomatic = true; return 0; }
  146.     void    SetPropertyInt(uint32 id, sint32 value, bool automatic) {}
  147.     void    GetPropertyInfoInt(uint32 id, sint32& minVal, sint32& maxVal, sint32& step, sint32& defaultVal, bool& automatic, bool& manual) {}
  148.  
  149.     bool    CaptureStart();
  150.     void    CaptureStop();
  151.     void    CaptureAbort();
  152.  
  153. protected:
  154.     void    SyncCaptureStop();
  155.     void    SyncCaptureAbort();
  156.     void    InitMixerSupport();
  157.     void    ShutdownMixerSupport();
  158.     bool    InitWaveAnalysis();
  159.     void    ShutdownWaveAnalysis();
  160.     bool    InitVideoBuffer();
  161.     void    ShutdownVideoBuffer();
  162.     void    FlushFrameQueue();
  163.     sint64    ComputeGlobalTime();
  164.     void    DoFrame();
  165.     void    DispatchFrame(const void *data, uint32 size, sint64 timestamp);
  166.  
  167.     void    TimerCallback();
  168.  
  169.     void    ConvertToYV12_GL_NV1x(int w, int h, float u, float v);
  170.     void    ConvertToYV12_GL_NV2x(int w, int h, float u, float v);
  171.     void    ConvertToYV12_GL_ATIFS(int w, int h, float u, float v);
  172.     void    ConvertToYUY2_GL_NV1x(int w, int h, float u, float v);
  173.     void    ConvertToYUY2_GL_NV2x_ATIFS(int w, int h, float u, float v, bool atifs);
  174.     GLuint    GetOcclusionQueryPixelCountSafe(GLuint query);
  175.  
  176.     void    LoadSettings();
  177.     void    SaveSettings();
  178.  
  179.     static LRESULT CALLBACK StaticWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  180.     static LRESULT CALLBACK StaticWndProcGL(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  181.     static INT_PTR CALLBACK VideoSourceDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam);
  182.  
  183.     enum { kPreviewTimerID = 100 };
  184.  
  185.     HWND    mhwndParent;
  186.     HWND    mhwnd;
  187.     HWND    mhwndGL;
  188.     HWND    mhwndGLDraw;
  189.  
  190.     bool    mbCapBuffersInited;
  191.     HDC        mhdcOffscreen;
  192.     HBITMAP    mhbmOffscreen;
  193.     void    *mpOffscreenData;
  194.     uint32    mOffscreenSize;
  195.  
  196.     VDOpenGLBinding        mGL;
  197.     bool    mbOpenGLMode;
  198.     GLuint    mGLBuffers[2];
  199.     GLuint    mGLShaderBase;
  200.     GLuint    mGLTextures[2];
  201.     int        mGLTextureW;
  202.     int        mGLTextureH;
  203.     vdblock<uint32> mGLReadBuffer;
  204.     GLuint    mGLOcclusionQueries[2];
  205.     bool    mbFrameValid[2];
  206.     bool    mbGLOcclusionValid[2];
  207.     bool    mbGLOcclusionPrevFrameValid;
  208.     sint64    mTimestampQueue[4];
  209.     int        mTimestampDelay;
  210.     int        mTimestampIndex;
  211.  
  212.     GLuint    mGLCursorCacheTexture;
  213.     float    mGLCursorCacheTextureInvW;
  214.     float    mGLCursorCacheTextureInvH;
  215.     HCURSOR    mCachedCursor;
  216.     int        mCachedCursorWidth;
  217.     int        mCachedCursorHeight;
  218.     int        mCachedCursorHotspotX;
  219.     int        mCachedCursorHotspotY;
  220.     bool    mbCachedCursorXORMode;
  221.  
  222.     HDC        mhdcCursorBuffer;
  223.     HBITMAP    mhbmCursorBuffer;
  224.     HGDIOBJ    mhbmCursorBufferOld;
  225.     uint32    *mpCursorBuffer;
  226.  
  227.     VDAtomicInt    mbCaptureFramePending;
  228.     bool    mbCapturing;
  229.     bool    mbCaptureSetup;
  230.     bool    mbVisible;
  231.     bool    mbAudioHardwarePresent;
  232.     bool    mbAudioHardwareEnabled;
  233.     bool    mbAudioCaptureEnabled;
  234.     bool    mbAudioAnalysisEnabled;
  235.     bool    mbAudioAnalysisActive;
  236.  
  237.     bool    mbTrackCursor;
  238.     bool    mbTrackActiveWindow;
  239.     bool    mbTrackActiveWindowClient;
  240.     int        mTrackX;
  241.     int        mTrackY;
  242.     int        mTrackOffsetX;
  243.     int        mTrackOffsetY;
  244.  
  245.     bool    mbRescaleImage;
  246.     int        mRescaleW;
  247.     int        mRescaleH;
  248.  
  249.     bool    mbDrawMousePointer;
  250.     bool    mbRemoveDuplicates;
  251.  
  252.     uint32    mFramePeriod;
  253.  
  254.     vdstructex<BITMAPINFOHEADER>    mVideoFormat;
  255.     vdstructex<WAVEFORMATEX>        mAudioFormat;
  256.  
  257.     IVDCaptureDriverCallback    *mpCB;
  258.     DisplayMode            mDisplayMode;
  259.     uint32    mGlobalTimeBase;
  260.  
  261.     UINT    mPreviewFrameTimer;
  262.     VDAtomicInt    mPreviewFrameCount;
  263.  
  264.     VDCallbackTimer    mCaptureTimer;
  265.  
  266.     HMIXER    mhMixer;
  267.     int        mMixerInput;
  268.     MIXERCONTROL    mMixerInputControl;
  269.     typedef std::vector<VDStringW>    MixerInputs;
  270.     MixerInputs    mMixerInputs;
  271.  
  272.     HWAVEIN mhWaveIn;
  273.     WAVEHDR    mWaveBufHdrs[2];
  274.     vdblock<char>    mWaveBuffer;
  275.  
  276.     MyError    mCaptureError;
  277.  
  278.     VDRTProfileChannel mProfileChannel;
  279.  
  280.     static ATOM sWndClass;
  281.     static ATOM sWndClassGL;
  282. };
  283.  
  284. ATOM VDCaptureDriverScreen::sWndClass;
  285. ATOM VDCaptureDriverScreen::sWndClassGL;
  286.  
  287. VDCaptureDriverScreen::VDCaptureDriverScreen()
  288.     : mhwndParent(NULL)
  289.     , mhwnd(NULL)
  290.     , mhwndGL(NULL)
  291.     , mhwndGLDraw(NULL)
  292.     , mbCapBuffersInited(false)
  293.     , mhdcOffscreen(NULL)
  294.     , mhbmOffscreen(NULL)
  295.     , mpOffscreenData(NULL)
  296.     , mOffscreenSize(0)
  297.     , mbOpenGLMode(true)
  298.     , mGLShaderBase(0)
  299.     , mGLTextureW(1)
  300.     , mGLTextureH(1)
  301.     , mGLCursorCacheTexture(0)
  302.     , mCachedCursor(NULL)
  303.     , mCachedCursorHotspotX(0)
  304.     , mCachedCursorHotspotY(0)
  305.     , mhdcCursorBuffer(NULL)
  306.     , mhbmCursorBuffer(NULL)
  307.     , mhbmCursorBufferOld(NULL)
  308.     , mpCursorBuffer(NULL)
  309.     , mbCaptureFramePending(false)
  310.     , mbCapturing(false)
  311.     , mbCaptureSetup(false)
  312.     , mbVisible(false)
  313.     , mbAudioAnalysisEnabled(false)
  314.     , mbAudioAnalysisActive(false)
  315.     , mbTrackCursor(false)
  316.     , mbTrackActiveWindow(false)
  317.     , mbTrackActiveWindowClient(false)
  318.     , mTrackX(0)
  319.     , mTrackY(0)
  320.     , mTrackOffsetX(0)
  321.     , mTrackOffsetY(0)
  322.     , mbRescaleImage(false)
  323.     , mRescaleW(GetSystemMetrics(SM_CXSCREEN))
  324.     , mRescaleH(GetSystemMetrics(SM_CYSCREEN))
  325.     , mbDrawMousePointer(true)
  326.     , mbRemoveDuplicates(true)
  327.     , mFramePeriod(10000000 / 30)
  328.     , mpCB(NULL)
  329.     , mDisplayMode(kDisplayNone)
  330.     , mPreviewFrameTimer(0)
  331.     , mhMixer(NULL)
  332.     , mhWaveIn(NULL)
  333.     , mProfileChannel("Capture driver")
  334. {
  335.     memset(mWaveBufHdrs, 0, sizeof mWaveBufHdrs);
  336.  
  337.     mVideoFormat.resize(sizeof(BITMAPINFOHEADER));
  338.     mVideoFormat->biSize        = sizeof(BITMAPINFOHEADER);
  339.     mVideoFormat->biWidth        = 320;
  340.     mVideoFormat->biHeight        = 240;
  341.     mVideoFormat->biPlanes        = 1;
  342.     mVideoFormat->biCompression    = BI_RGB;
  343.     mVideoFormat->biBitCount    = 32;
  344.     mVideoFormat->biSizeImage    = 320*240*4;
  345.     mVideoFormat->biXPelsPerMeter    = 0;
  346.     mVideoFormat->biYPelsPerMeter    = 0;
  347.     mVideoFormat->biClrUsed            = 0;
  348.     mVideoFormat->biClrImportant    = 0;
  349.  
  350.     mAudioFormat.resize(sizeof(WAVEFORMATEX));
  351.     mAudioFormat->wFormatTag        = WAVE_FORMAT_PCM;
  352.     mAudioFormat->nSamplesPerSec    = 44100;
  353.     mAudioFormat->nAvgBytesPerSec    = 44100*4;
  354.     mAudioFormat->nChannels            = 2;
  355.     mAudioFormat->nBlockAlign        = 4;
  356.     mAudioFormat->wBitsPerSample    = 16;
  357.     mAudioFormat->cbSize            = 0;
  358.  
  359.     mOffscreenSize = mVideoFormat->biSizeImage;
  360.  
  361.     mGLOcclusionQueries[0] = 0;
  362.     mGLOcclusionQueries[1] = 0;
  363.     mbGLOcclusionValid[0] = false;
  364.     mbGLOcclusionValid[1] = false;
  365.     mbGLOcclusionPrevFrameValid = false;
  366.  
  367.     memset(mGLTextures, 0, sizeof mGLTextures);
  368.     memset(mGLBuffers, 0, sizeof mGLBuffers);
  369.     memset(mbFrameValid, 0, sizeof mbFrameValid);
  370. }
  371.  
  372. VDCaptureDriverScreen::~VDCaptureDriverScreen() {
  373.     Shutdown();
  374. }
  375.  
  376. void VDCaptureDriverScreen::SetCallback(IVDCaptureDriverCallback *pCB) {
  377.     mpCB = pCB;
  378. }
  379.  
  380. bool VDCaptureDriverScreen::Init(VDGUIHandle hParent) {
  381.     mhwndParent = (HWND)hParent;
  382.  
  383.     if (!sWndClass) {
  384.         WNDCLASS wc = { 0, StaticWndProc, 0, sizeof(VDCaptureDriverScreen *), g_hInst, NULL, NULL, NULL, NULL, "Riza screencap window" };
  385.  
  386.         sWndClass = RegisterClass(&wc);
  387.  
  388.         if (!sWndClass)
  389.             return false;
  390.  
  391.         WNDCLASS wcgl = { CS_OWNDC, StaticWndProcGL, 0, sizeof(VDCaptureDriverScreen *), g_hInst, NULL, NULL, NULL, NULL, "Riza screencap GL window" };
  392.  
  393.         sWndClassGL = RegisterClass(&wcgl);
  394.  
  395.         if (!sWndClassGL)
  396.             return false;
  397.     }
  398.  
  399.     // Attempt to open mixer device. It is OK for this to fail. Note that we
  400.     // have a bit of a problem in that (a) the mixer API doesn't take
  401.     // WAVE_MAPPER, and (b) we can't get access to the handle that the
  402.     // capture window creates. For now, we sort of fake it.
  403.     InitMixerSupport();
  404.  
  405.     // Create message sink.
  406.     if (!(mhwnd = CreateWindow((LPCTSTR)sWndClass, "", WS_CHILD, 0, 0, 0, 0, mhwndParent, NULL, g_hInst, this))) {
  407.         Shutdown();
  408.         return false;
  409.     }
  410.  
  411.     mPreviewFrameCount = 0;
  412.  
  413.     mbAudioHardwarePresent = false;
  414.     mbAudioHardwarePresent = true;
  415.     mbAudioHardwareEnabled = mbAudioHardwarePresent;
  416.     mbAudioCaptureEnabled = true;
  417.  
  418.     LoadSettings();
  419.  
  420.     InitVideoBuffer();
  421.  
  422.     return true;
  423. }
  424.  
  425. void VDCaptureDriverScreen::Shutdown() {
  426.     ShutdownWaveAnalysis();
  427.  
  428.     if (mPreviewFrameTimer) {
  429.         KillTimer(mhwnd, mPreviewFrameTimer);
  430.         mPreviewFrameTimer = 0;
  431.     }
  432.  
  433.     ShutdownVideoBuffer();
  434.  
  435.     SaveSettings();
  436.  
  437.     if (mhwnd) {
  438.         DestroyWindow(mhwnd);
  439.         mhwnd = NULL;
  440.     }
  441.  
  442.     if (mhMixer) {
  443.         mixerClose(mhMixer);
  444.         mhMixer = NULL;
  445.     }
  446. }
  447.  
  448. bool VDCaptureDriverScreen::IsHardwareDisplayAvailable() {
  449.     return true;
  450. }
  451.  
  452. void VDCaptureDriverScreen::SetDisplayMode(DisplayMode mode) {
  453.     if (mode == mDisplayMode)
  454.         return;
  455.  
  456.     if (mDisplayMode == kDisplayAnalyze) {
  457.         if (mPreviewFrameTimer) {
  458.             KillTimer(mhwnd, mPreviewFrameTimer);
  459.             mPreviewFrameTimer = 0;
  460.         }
  461.     }
  462.  
  463.     mDisplayMode = mode;
  464.  
  465.     if (mPreviewFrameTimer) {
  466.         KillTimer(mhwnd, mPreviewFrameTimer);
  467.         mPreviewFrameTimer = 0;
  468.     }
  469.  
  470.     switch(mode) {
  471.     case kDisplayNone:
  472.         ShowWindow(mhwnd, SW_HIDE);
  473.         break;
  474.     case kDisplayHardware:
  475.         mPreviewFrameTimer = SetTimer(mhwnd, kPreviewTimerID, mFramePeriod / 10000, NULL);
  476.  
  477.         if (mbVisible)
  478.             ShowWindow(mhwnd, SW_SHOWNA);
  479.         break;
  480.     case kDisplaySoftware:
  481.         mPreviewFrameTimer = SetTimer(mhwnd, kPreviewTimerID, mFramePeriod / 10000, NULL);
  482.  
  483.         if (mbVisible)
  484.             ShowWindow(mhwnd, SW_SHOWNA);
  485.         break;
  486.     case kDisplayAnalyze:
  487.         mPreviewFrameTimer = SetTimer(mhwnd, kPreviewTimerID, mFramePeriod / 10000, NULL);
  488.  
  489.         if (mbVisible)
  490.             ShowWindow(mhwnd, SW_HIDE);
  491.         break;
  492.     }
  493. }
  494.  
  495. DisplayMode VDCaptureDriverScreen::GetDisplayMode() {
  496.     return mDisplayMode;
  497. }
  498.  
  499. void VDCaptureDriverScreen::SetDisplayRect(const vdrect32& r) {
  500.     SetWindowPos(mhwnd, NULL, r.left, r.top, r.width(), r.height(), SWP_NOZORDER|SWP_NOACTIVATE);
  501. }
  502.  
  503. vdrect32 VDCaptureDriverScreen::GetDisplayRectAbsolute() {
  504.     RECT r;
  505.     GetWindowRect(mhwnd, &r);
  506.     MapWindowPoints(GetParent(mhwnd), NULL, (LPPOINT)&r, 2);
  507.     return vdrect32(r.left, r.top, r.right, r.bottom);
  508. }
  509.  
  510. void VDCaptureDriverScreen::SetDisplayVisibility(bool vis) {
  511.     if (vis == mbVisible)
  512.         return;
  513.  
  514.     mbVisible = vis;
  515.     ShowWindow(mhwnd, vis && mDisplayMode != kDisplayAnalyze ? SW_SHOWNA : SW_HIDE);
  516. }
  517.  
  518. void VDCaptureDriverScreen::SetFramePeriod(sint32 ms) {
  519.     mFramePeriod = ms;
  520.  
  521.     if (mpCB)
  522.         mpCB->CapEvent(kEventVideoFrameRateChanged, 0);
  523. }
  524.  
  525. sint32 VDCaptureDriverScreen::GetFramePeriod() {
  526.     return mFramePeriod;
  527. }
  528.  
  529. uint32 VDCaptureDriverScreen::GetPreviewFrameCount() {
  530.     if (mDisplayMode == kDisplaySoftware || mDisplayMode == kDisplayAnalyze)
  531.         return mPreviewFrameCount;
  532.  
  533.     return 0;
  534. }
  535.  
  536. bool VDCaptureDriverScreen::GetVideoFormat(vdstructex<BITMAPINFOHEADER>& vformat) {
  537.     vformat = mVideoFormat;
  538.     return true;
  539. }
  540.  
  541. bool VDCaptureDriverScreen::SetVideoFormat(const BITMAPINFOHEADER *pbih, uint32 size) {
  542.     bool success = false;
  543.  
  544.     if (pbih->biCompression == VDMAKEFOURCC('Y', 'U', 'Y', '2')) {
  545.         if (!mbOpenGLMode)
  546.             return false;
  547.  
  548.         if ((pbih->biWidth & 1))
  549.             return false;
  550.  
  551.         mOffscreenSize = pbih->biWidth * abs(pbih->biHeight) * 2;
  552.     } else if (pbih->biCompression == VDMAKEFOURCC('Y', 'V', '1', '2')) {
  553.         if (!mbOpenGLMode)
  554.             return false;
  555.  
  556.         if ((pbih->biWidth & 7) || (pbih->biHeight & 1))
  557.             return false;
  558.         mOffscreenSize = pbih->biWidth * abs(pbih->biHeight) * 3 / 2;
  559.     } else if (pbih->biCompression == BI_RGB) {
  560.         if (pbih->biBitCount != 32)
  561.             return false;
  562.  
  563.         mOffscreenSize = pbih->biWidth * abs(pbih->biHeight) * 4;
  564.     } else {
  565.         return false;
  566.     }
  567.  
  568.     ShutdownVideoBuffer();
  569.     mVideoFormat.assign(pbih, size);
  570.     if (mpCB)
  571.         mpCB->CapEvent(kEventVideoFormatChanged, 0);
  572.     InitVideoBuffer();
  573.     success = true;
  574.     return success;
  575. }
  576.  
  577. int VDCaptureDriverScreen::GetAudioDeviceCount() {
  578.     return mbAudioHardwarePresent ? 1 : 0;
  579. }
  580.  
  581. const wchar_t *VDCaptureDriverScreen::GetAudioDeviceName(int idx) {
  582.     if (idx || !mbAudioHardwarePresent)
  583.         return NULL;
  584.  
  585.     return L"Wave Mapper";
  586. }
  587.  
  588. bool VDCaptureDriverScreen::SetAudioDevice(int idx) {
  589.     if (idx < -1 || idx >= 1)
  590.         return false;
  591.     
  592.     if (!idx && !mbAudioHardwarePresent)
  593.         return false;
  594.  
  595.     bool enable = !idx;
  596.  
  597.     if (enable == mbAudioHardwareEnabled)
  598.         return true;
  599.  
  600.     ShutdownWaveAnalysis();
  601.     mbAudioHardwareEnabled = enable;
  602.     InitWaveAnalysis();
  603.  
  604.     return true;
  605. }
  606.  
  607. int VDCaptureDriverScreen::GetAudioDeviceIndex() {
  608.     return mbAudioHardwareEnabled ? 0 : -1;
  609. }
  610.  
  611. int VDCaptureDriverScreen::GetVideoSourceCount() {
  612.     return 0;
  613. }
  614.  
  615. const wchar_t *VDCaptureDriverScreen::GetVideoSourceName(int idx) {
  616.     return NULL;
  617. }
  618.  
  619. bool VDCaptureDriverScreen::SetVideoSource(int idx) {
  620.     return idx == -1;
  621. }
  622.  
  623. int VDCaptureDriverScreen::GetVideoSourceIndex() {
  624.     return -1;
  625. }
  626.  
  627. int VDCaptureDriverScreen::GetAudioSourceCount() {
  628.     return 0;
  629. }
  630.  
  631. const wchar_t *VDCaptureDriverScreen::GetAudioSourceName(int idx) {
  632.     return NULL;
  633. }
  634.  
  635. bool VDCaptureDriverScreen::SetAudioSource(int idx) {
  636.     return idx == -1;
  637. }
  638.  
  639. int VDCaptureDriverScreen::GetAudioSourceIndex() {
  640.     return -1;
  641. }
  642.  
  643. int VDCaptureDriverScreen::GetAudioInputCount() {
  644.     return mbAudioHardwareEnabled ? mMixerInputs.size() : 0;
  645. }
  646.  
  647. const wchar_t *VDCaptureDriverScreen::GetAudioInputName(int idx) {
  648.     if (!mbAudioHardwareEnabled || (unsigned)idx >= mMixerInputs.size())
  649.         return NULL;
  650.  
  651.     MixerInputs::const_iterator it(mMixerInputs.begin());
  652.  
  653.     std::advance(it, idx);
  654.  
  655.     return (*it).c_str();
  656. }
  657.  
  658. bool VDCaptureDriverScreen::SetAudioInput(int idx) {
  659.     if (!mbAudioHardwareEnabled || !mhMixer)
  660.         return idx == -1;
  661.  
  662.     VDASSERT(mMixerInputs.size() == mMixerInputControl.cMultipleItems);
  663.  
  664.     if (idx != -1 && (unsigned)idx >= mMixerInputControl.cMultipleItems)
  665.         return false;
  666.  
  667.     // attempt to set the appropriate mixer input
  668.  
  669.     vdblock<MIXERCONTROLDETAILS_BOOLEAN> vals(mMixerInputControl.cMultipleItems);
  670.  
  671.     for(unsigned i=0; i<mMixerInputControl.cMultipleItems; ++i)
  672.         vals[i].fValue = (i == idx);
  673.  
  674.     MIXERCONTROLDETAILS details = {sizeof(MIXERCONTROLDETAILS)};
  675.  
  676.     details.dwControlID        = mMixerInputControl.dwControlID;
  677.     details.cChannels        = 1;
  678.     details.cMultipleItems    = mMixerInputControl.cMultipleItems;
  679.     details.cbDetails        = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
  680.     details.paDetails        = vals.data();
  681.  
  682.     if (MMSYSERR_NOERROR != mixerSetControlDetails((HMIXEROBJ)mhMixer, &details, MIXER_SETCONTROLDETAILSF_VALUE))
  683.         return false;
  684.  
  685.     mMixerInput = idx;
  686.  
  687.     return true;
  688. }
  689.  
  690. int VDCaptureDriverScreen::GetAudioInputIndex() {
  691.     return mbAudioHardwareEnabled ? mMixerInput : -1;
  692. }
  693.  
  694. bool VDCaptureDriverScreen::IsAudioCapturePossible() {
  695.     return mbAudioHardwareEnabled;
  696. }
  697.  
  698. bool VDCaptureDriverScreen::IsAudioCaptureEnabled() {
  699.     return mbAudioHardwareEnabled && mbAudioCaptureEnabled;
  700. }
  701.  
  702. void VDCaptureDriverScreen::SetAudioCaptureEnabled(bool b) {
  703.     mbAudioCaptureEnabled = b;
  704. }
  705.  
  706. void VDCaptureDriverScreen::SetAudioAnalysisEnabled(bool b) {
  707.     if (mbAudioAnalysisEnabled == b)
  708.         return;
  709.  
  710.     mbAudioAnalysisEnabled = b;
  711.  
  712.     if (mbAudioAnalysisEnabled)
  713.         InitWaveAnalysis();
  714.     else
  715.         ShutdownWaveAnalysis();
  716. }
  717.  
  718. void VDCaptureDriverScreen::GetAvailableAudioFormats(std::list<vdstructex<WAVEFORMATEX> >& aformats) {
  719.     static const int kSamplingRates[]={
  720.         8000,
  721.         11025,
  722.         12000,
  723.         16000,
  724.         22050,
  725.         24000,
  726.         32000,
  727.         44100,
  728.         48000,
  729.         96000,
  730.         192000
  731.     };
  732.  
  733.     static const int kChannelCounts[]={
  734.         1,
  735.         2
  736.     };
  737.  
  738.     static const int kSampleDepths[]={
  739.         8,
  740.         16
  741.     };
  742.  
  743.     for(int sridx=0; sridx < sizeof kSamplingRates / sizeof kSamplingRates[0]; ++sridx)
  744.         for(int chidx=0; chidx < sizeof kChannelCounts / sizeof kChannelCounts[0]; ++chidx)
  745.             for(int sdidx=0; sdidx < sizeof kSampleDepths / sizeof kSampleDepths[0]; ++sdidx) {
  746.                 WAVEFORMATEX wfex={
  747.                     WAVE_FORMAT_PCM,
  748.                     kChannelCounts[chidx],
  749.                     kSamplingRates[sridx],
  750.                     0,
  751.                     0,
  752.                     kSampleDepths[sdidx],
  753.                     0
  754.                 };
  755.  
  756.                 wfex.nBlockAlign = wfex.nChannels * (wfex.wBitsPerSample >> 3);
  757.                 wfex.nAvgBytesPerSec = wfex.nBlockAlign * wfex.nSamplesPerSec;
  758.  
  759.                 if (MMSYSERR_NOERROR ==waveInOpen(NULL, WAVE_MAPPER, &wfex, 0, 0, WAVE_FORMAT_QUERY | WAVE_FORMAT_DIRECT)) {
  760.                     aformats.push_back(vdstructex<WAVEFORMATEX>(&wfex, sizeof wfex));
  761.                 }
  762.             }
  763. }
  764.  
  765. bool VDCaptureDriverScreen::GetAudioFormat(vdstructex<WAVEFORMATEX>& aformat) {
  766.     aformat = mAudioFormat;
  767.     return true;
  768. }
  769.  
  770. bool VDCaptureDriverScreen::SetAudioFormat(const WAVEFORMATEX *pwfex, uint32 size) {
  771.     if (!mbAudioHardwareEnabled)
  772.         return false;
  773.  
  774.     ShutdownWaveAnalysis();
  775.     mAudioFormat.assign(pwfex, size);
  776.     if (mbAudioAnalysisEnabled)
  777.         InitWaveAnalysis();
  778.     return true;
  779. }
  780.  
  781. bool VDCaptureDriverScreen::IsDriverDialogSupported(DriverDialog dlg) {
  782.     if (dlg == kDialogVideoSource)
  783.         return true;
  784.  
  785.     return false;
  786. }
  787.  
  788. void VDCaptureDriverScreen::DisplayDriverDialog(DriverDialog dlg) {
  789.     VDASSERT(IsDriverDialogSupported(dlg));
  790.  
  791.     switch(dlg) {
  792.     case kDialogVideoFormat:
  793.         break;
  794.     case kDialogVideoSource:
  795.         ShutdownVideoBuffer();
  796.         DialogBoxParam(g_hInst, MAKEINTRESOURCE(IDD_SCREENCAP_OPTS), mhwnd, VideoSourceDlgProc, (LPARAM)this);
  797.  
  798.         SaveSettings();
  799.  
  800.         // without OpenGL, we can only do 32-bit RGB
  801.         if (!mbOpenGLMode && mVideoFormat->biCompression != BI_RGB) {
  802.             mVideoFormat->biCompression = BI_RGB;
  803.             mVideoFormat->biSizeImage = mVideoFormat->biWidth * abs(mVideoFormat->biHeight) * 4;
  804.             mVideoFormat->biBitCount = 32;
  805.             mpCB->CapEvent(kEventVideoFormatChanged, 0);
  806.         }
  807.  
  808.         InitVideoBuffer();
  809.         break;
  810.     case kDialogVideoDisplay:
  811.         break;
  812.     }
  813. }
  814.  
  815. bool VDCaptureDriverScreen::CaptureStart() {
  816.     ShutdownWaveAnalysis();
  817.  
  818.     if (!VDINLINEASSERTFALSE(mbCapturing)) {
  819.         if (mbOpenGLMode) {
  820.             HDC hdc = GetDC(mhwndGL);
  821.             if (hdc) {
  822.                 if (mGL.Begin(hdc)) {
  823.                     FlushFrameQueue();
  824.                     mGL.End();
  825.                 }
  826.  
  827.                 ReleaseDC(mhwndGL, hdc);
  828.             }
  829.         }
  830.  
  831.         if (mpCB->CapEvent(kEventPreroll, 0)) {
  832.             mpCB->CapBegin(0);
  833.             if (mbAudioCaptureEnabled)
  834.                 InitWaveAnalysis();
  835.  
  836.             mGlobalTimeBase = VDGetAccurateTick();
  837.             mbCapturing = true;
  838.             mbCaptureSetup = true;
  839.             mCaptureTimer.Init2(this, mFramePeriod);
  840.         } else {
  841.             if (mbAudioAnalysisEnabled)
  842.                 InitWaveAnalysis();
  843.         }
  844.     }
  845.  
  846.     return mbCapturing;
  847. }
  848.  
  849. void VDCaptureDriverScreen::CaptureStop() {
  850.     SendMessage(mhwnd, WM_APP+16, 0, 0);
  851. }
  852.  
  853. void VDCaptureDriverScreen::CaptureAbort() {
  854.     SendMessage(mhwnd, WM_APP+17, 0, 0);
  855.     mbCapturing = false;
  856. }
  857.  
  858. void VDCaptureDriverScreen::SyncCaptureStop() {
  859.     if (VDINLINEASSERT(mbCaptureSetup)) {
  860.         mCaptureTimer.Shutdown();
  861.         mbCapturing = false;
  862.         mbCaptureSetup = false;
  863.  
  864.         if (mCaptureError.gets()) {
  865.             mpCB->CapEnd(&mCaptureError);
  866.             mCaptureError.discard();
  867.         } else
  868.             mpCB->CapEnd(NULL);
  869.  
  870.         if (mbAudioCaptureEnabled)
  871.             ShutdownWaveAnalysis();
  872.  
  873.         if (mbAudioAnalysisEnabled)
  874.             InitWaveAnalysis();
  875.     }
  876. }
  877.  
  878. void VDCaptureDriverScreen::SyncCaptureAbort() {
  879.     SyncCaptureStop();
  880. }
  881.  
  882. void VDCaptureDriverScreen::InitMixerSupport() {
  883.     WAVEINCAPS wcaps={0};
  884.     if (MMSYSERR_NOERROR == waveInGetDevCaps(WAVE_MAPPER, &wcaps, sizeof wcaps) && wcaps.dwFormats) {
  885.         WAVEFORMATEX wfex;
  886.  
  887.         // create lowest-common denominator format for device
  888.         wfex.wFormatTag            = WAVE_FORMAT_PCM;
  889.  
  890.         if (wcaps.dwFormats & (WAVE_FORMAT_4M08 | WAVE_FORMAT_4M16 | WAVE_FORMAT_4S08 | WAVE_FORMAT_4S16))
  891.             wfex.nSamplesPerSec = 11025;
  892.         else if (wcaps.dwFormats & (WAVE_FORMAT_2M08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_2S08 | WAVE_FORMAT_2S16))
  893.             wfex.nSamplesPerSec = 22050;
  894.         else
  895.             wfex.nSamplesPerSec = 44100;
  896.  
  897.         if (wcaps.dwFormats & (WAVE_FORMAT_1M08 | WAVE_FORMAT_1M16 | WAVE_FORMAT_2M08 | WAVE_FORMAT_2M16 | WAVE_FORMAT_4M08 | WAVE_FORMAT_4M16))
  898.             wfex.nChannels = 1;
  899.         else
  900.             wfex.nChannels = 2;
  901.  
  902.         if (wcaps.dwFormats & (WAVE_FORMAT_1M08 | WAVE_FORMAT_1S08 | WAVE_FORMAT_2M08 | WAVE_FORMAT_2S08 | WAVE_FORMAT_4M08 | WAVE_FORMAT_4S08))
  903.             wfex.wBitsPerSample = 8;
  904.         else
  905.             wfex.wBitsPerSample = 16;
  906.  
  907.         wfex.nBlockAlign        = wfex.wBitsPerSample >> 3;
  908.         wfex.nAvgBytesPerSec    = wfex.nSamplesPerSec * wfex.nBlockAlign;
  909.         wfex.cbSize                = 0;
  910.  
  911.         // create the device
  912.         HWAVEIN hwi;
  913.         if (MMSYSERR_NOERROR == waveInOpen(&hwi, WAVE_MAPPER, &wfex, 0, 0, CALLBACK_NULL)) {
  914.             // create mixer based on device
  915.  
  916.             if (MMSYSERR_NOERROR == mixerOpen(&mhMixer, (UINT)hwi, 0, 0, MIXER_OBJECTF_HWAVEIN)) {
  917.                 MIXERLINE mixerLine = {sizeof(MIXERLINE)};
  918.  
  919.                 mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_WAVEIN;
  920.  
  921.                 if (MMSYSERR_NOERROR == mixerGetLineInfo((HMIXEROBJ)mhMixer, &mixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE)) {
  922.  
  923.                     // Try to find a MIXER or MUX control
  924.                     MIXERLINECONTROLS lineControls = {sizeof(MIXERLINECONTROLS)};
  925.  
  926.                     mMixerInputControl.cbStruct = sizeof(MIXERCONTROL);
  927.                     mMixerInputControl.dwControlType = 0;
  928.  
  929.                     lineControls.dwLineID = mixerLine.dwLineID;
  930.                     lineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_MUX;
  931.                     lineControls.cControls = 1;
  932.                     lineControls.pamxctrl = &mMixerInputControl;
  933.                     lineControls.cbmxctrl = sizeof(MIXERCONTROL);
  934.  
  935.                     MMRESULT res;
  936.  
  937.                     res = mixerGetLineControls((HMIXEROBJ)mhMixer, &lineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE);
  938.  
  939.                     if (MMSYSERR_NOERROR != res) {
  940.                         lineControls.dwControlType = MIXERCONTROL_CONTROLTYPE_MIXER;
  941.  
  942.                         res = mixerGetLineControls((HMIXEROBJ)mhMixer, &lineControls, MIXER_GETLINECONTROLSF_ONEBYTYPE);
  943.                     }
  944.  
  945.                     // The mux/mixer control must be of MULTIPLE type; otherwise, we reject it.
  946.                     if (!(mMixerInputControl.fdwControl & MIXERCONTROL_CONTROLF_MULTIPLE))
  947.                         res = MMSYSERR_ERROR;
  948.  
  949.                     // If we were successful, then enumerate all source lines and push them into the map.
  950.                     if (MMSYSERR_NOERROR != res) {
  951.                         mixerClose(mhMixer);
  952.                         mhMixer = NULL;
  953.                     } else {
  954.                         // Enumerate control inputs and populate the name array
  955.                         vdblock<MIXERCONTROLDETAILS_LISTTEXT> names(mMixerInputControl.cMultipleItems);
  956.  
  957.                         MIXERCONTROLDETAILS details = {sizeof(MIXERCONTROLDETAILS)};
  958.  
  959.                         details.dwControlID        = mMixerInputControl.dwControlID;
  960.                         details.cChannels        = 1;
  961.                         details.cMultipleItems    = mMixerInputControl.cMultipleItems;
  962.                         details.cbDetails        = sizeof(MIXERCONTROLDETAILS_LISTTEXT);
  963.                         details.paDetails        = names.data();
  964.  
  965.                         mMixerInput = -1;
  966.  
  967.                         if (MMSYSERR_NOERROR == mixerGetControlDetails((HMIXEROBJ)mhMixer, &details, MIXER_GETCONTROLDETAILSF_LISTTEXT)) {
  968.                             mMixerInputs.reserve(details.cMultipleItems);
  969.  
  970.                             for(unsigned i=0; i<details.cMultipleItems; ++i)
  971.                                 mMixerInputs.push_back(MixerInputs::value_type(VDTextAToW(names[i].szName)));
  972.  
  973.                             vdblock<MIXERCONTROLDETAILS_BOOLEAN> vals(mMixerInputControl.cMultipleItems);
  974.  
  975.                             details.cbDetails = sizeof(MIXERCONTROLDETAILS_BOOLEAN);
  976.                             details.paDetails = vals.data();
  977.  
  978.                             if (MMSYSERR_NOERROR == mixerGetControlDetails((HMIXEROBJ)mhMixer, &details, MIXER_GETCONTROLDETAILSF_VALUE)) {
  979.                                 // Attempt to find a mixer input that is set. Note that for
  980.                                 // a multiple-select type (MIXER) this will pick the first
  981.                                 // enabled input.
  982.                                 for(unsigned i=0; i<details.cMultipleItems; ++i)
  983.                                     if (vals[i].fValue) {
  984.                                         mMixerInput = i;
  985.                                         break;
  986.                                     }
  987.                             }
  988.                         }
  989.                     }
  990.                 }
  991.  
  992.                 // We don't close the mixer here; it is left open while we have the
  993.                 // capture device opened.
  994.             }
  995.  
  996.             waveInClose(hwi);
  997.         }
  998.     }
  999. }
  1000.  
  1001. void VDCaptureDriverScreen::ShutdownMixerSupport() {
  1002.     if (mhMixer) {
  1003.         mixerClose(mhMixer);
  1004.         mhMixer = NULL;
  1005.     }
  1006. }
  1007.  
  1008. bool VDCaptureDriverScreen::InitWaveAnalysis() {
  1009.     if (!mbAudioHardwareEnabled)
  1010.         return false;
  1011.  
  1012.     vdstructex<WAVEFORMATEX> aformat;
  1013.  
  1014.     if (!GetAudioFormat(aformat))
  1015.         return false;
  1016.  
  1017.     uint32    blockSize = (aformat->nAvgBytesPerSec + 9) / 10 + aformat->nBlockAlign - 1;
  1018.     blockSize -= blockSize % aformat->nBlockAlign;
  1019.  
  1020.     mWaveBuffer.resize(blockSize*2);
  1021.  
  1022.     if (MMSYSERR_NOERROR != waveInOpen(&mhWaveIn, WAVE_MAPPER, aformat.data(), (DWORD_PTR)mhwnd, 0, CALLBACK_WINDOW | WAVE_FORMAT_DIRECT))
  1023.         return false;
  1024.  
  1025.     mbAudioAnalysisActive = true;
  1026.     for(int i=0; i<2; ++i) {
  1027.         WAVEHDR& hdr = mWaveBufHdrs[i];
  1028.  
  1029.         hdr.lpData            = &mWaveBuffer[blockSize*i];
  1030.         hdr.dwBufferLength    = blockSize;
  1031.         hdr.dwBytesRecorded    = 0;
  1032.         hdr.dwFlags            = 0;
  1033.         hdr.dwLoops            = 0;
  1034.         if (MMSYSERR_NOERROR != waveInPrepareHeader(mhWaveIn, &hdr, sizeof(WAVEHDR))) {
  1035.             ShutdownWaveAnalysis();
  1036.             return false;
  1037.         }
  1038.  
  1039.         if (MMSYSERR_NOERROR != waveInAddBuffer(mhWaveIn, &hdr, sizeof(WAVEHDR))) {
  1040.             ShutdownWaveAnalysis();
  1041.             return false;
  1042.         }
  1043.     }
  1044.  
  1045.     if (MMSYSERR_NOERROR != waveInStart(mhWaveIn)) {
  1046.         ShutdownWaveAnalysis();
  1047.         return false;
  1048.     }
  1049.  
  1050.     return true;
  1051. }
  1052.  
  1053. void VDCaptureDriverScreen::ShutdownWaveAnalysis() {
  1054.     if (mhWaveIn) {
  1055.         mbAudioAnalysisActive = false;
  1056.         waveInReset(mhWaveIn);
  1057.  
  1058.         for(int i=0; i<2; ++i) {
  1059.             if (mWaveBufHdrs[i].dwFlags & WHDR_PREPARED)
  1060.                 waveInUnprepareHeader(mhWaveIn, &mWaveBufHdrs[i], sizeof(WAVEHDR));
  1061.         }
  1062.  
  1063.         waveInClose(mhWaveIn);
  1064.         mhWaveIn = NULL;
  1065.     }
  1066.  
  1067.     mWaveBuffer.clear();
  1068. }
  1069.  
  1070. bool VDCaptureDriverScreen::InitVideoBuffer() {
  1071.     ShutdownVideoBuffer();
  1072.  
  1073.     if (!mbOpenGLMode) {
  1074.         HDC hdc = GetDC(NULL);
  1075.         if (!hdc)
  1076.             return false;
  1077.  
  1078.         mhdcOffscreen = CreateCompatibleDC(hdc);
  1079.         mhbmOffscreen = CreateDIBSection(hdc, (const BITMAPINFO *)mVideoFormat.data(), DIB_PAL_COLORS, &mpOffscreenData, NULL, 0);
  1080.         ReleaseDC(NULL, hdc);
  1081.  
  1082.         if (!mhbmOffscreen || !mhdcOffscreen) {
  1083.             ShutdownVideoBuffer();
  1084.             return false;
  1085.         }
  1086.  
  1087.         DeleteObject(SelectObject(mhdcOffscreen, mhbmOffscreen));
  1088.  
  1089.         mOffscreenSize = mVideoFormat->biSizeImage;
  1090.     } else {
  1091.         if (!mGL.Init()) {
  1092.             mbOpenGLMode = false;
  1093.             return InitVideoBuffer();
  1094.         }
  1095.  
  1096.         if (!(mhwndGL = CreateWindow((LPCTSTR)sWndClassGL, "VirtualDub OpenGL support", WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), NULL, NULL, g_hInst, this))) {
  1097.             mbOpenGLMode = false;
  1098.             return InitVideoBuffer();
  1099.         }
  1100.  
  1101.         RECT r;
  1102.         GetClientRect(mhwnd, &r);
  1103.         if (!(mhwndGLDraw = CreateWindow((LPCTSTR)sWndClassGL, "VirtualDub OpenGL support", WS_CHILD|WS_VISIBLE, 0, 0, r.right, r.bottom, mhwnd, NULL, g_hInst, this))) {
  1104.             mbOpenGLMode = false;
  1105.             return InitVideoBuffer();
  1106.         }
  1107.  
  1108.         HDC hdc = GetDC(mhwndGL);
  1109.         if (!mGL.Attach(hdc, 24, 8, 0, 0, true)) {
  1110.             ReleaseDC(mhwndGL, hdc);
  1111.             mbOpenGLMode = false;
  1112.             return InitVideoBuffer();
  1113.         }
  1114.  
  1115.         HDC hdc2 = GetDC(mhwndGLDraw);
  1116.         mGL.AttachAux(hdc2, 24, 8, 0, 0, true);
  1117.         ReleaseDC(mhwndGLDraw, hdc2);
  1118.  
  1119.         int buffersize = mVideoFormat->biWidth * abs(mVideoFormat->biHeight) * 4;
  1120.  
  1121.         mGL.Begin(hdc);
  1122.  
  1123.         if (mGL.EXT_pixel_buffer_object) {
  1124.             mGL.glGenBuffersARB(2, mGLBuffers);
  1125.             mGL.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mGLBuffers[0]);
  1126.             mGL.glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, buffersize, NULL, GL_STREAM_READ_ARB);
  1127.             mGL.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mGLBuffers[1]);
  1128.             mGL.glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB, buffersize, NULL, GL_STREAM_READ_ARB);
  1129.         } else {
  1130.             mGLReadBuffer.resize((buffersize + 3) >> 2);
  1131.         }
  1132.  
  1133.         VDASSERT(!mGL.glGetError());
  1134.  
  1135.         mGL.glGenTextures(2, mGLTextures);
  1136.         mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  1137.  
  1138.         int srcw = mVideoFormat->biWidth;
  1139.         int srch = abs(mVideoFormat->biHeight);
  1140.  
  1141.         if (mbRescaleImage) {
  1142.             if (srcw < mRescaleW)
  1143.                 srcw = mRescaleW;
  1144.             if (srch < mRescaleH)
  1145.                 srch = mRescaleH;
  1146.         }
  1147.  
  1148.         int w = srcw * 2 - 1;
  1149.         int h = srch * 2 - 1;
  1150.  
  1151.         while(int t = w & (w-1))
  1152.             w = t;
  1153.  
  1154.         while(int t = h & (h-1))
  1155.             h = t;
  1156.  
  1157.         mGLTextureW = w;
  1158.         mGLTextureH = h;
  1159.  
  1160.         mGL.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, w, h, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
  1161.         VDASSERT(!mGL.glGetError());
  1162.  
  1163.         mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[1]);
  1164.         mGL.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, w, h, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
  1165.         VDASSERT(!mGL.glGetError());
  1166.  
  1167.         int cxcursor = GetSystemMetrics(SM_CXCURSOR);
  1168.         int cycursor = GetSystemMetrics(SM_CYCURSOR);
  1169.  
  1170.         mCachedCursorWidth = cxcursor;
  1171.         mCachedCursorHeight = cycursor;
  1172.  
  1173.         HDC hdcScreen = GetDC(NULL);
  1174.         mhdcCursorBuffer = CreateCompatibleDC(hdcScreen);
  1175.         const BITMAPINFOHEADER bihCursor={
  1176.             sizeof(BITMAPINFOHEADER),
  1177.             cxcursor,
  1178.             cycursor * 2,
  1179.             1,
  1180.             32,
  1181.             BI_RGB,
  1182.             0,
  1183.             0,
  1184.             0,
  1185.             0,
  1186.             0
  1187.         };
  1188.         ReleaseDC(NULL, hdcScreen);
  1189.  
  1190.         mhbmCursorBuffer = CreateDIBSection(mhdcCursorBuffer, (const BITMAPINFO *)&bihCursor, DIB_RGB_COLORS, (void **)&mpCursorBuffer, NULL, 0);
  1191.         mhbmCursorBufferOld = SelectObject(mhdcCursorBuffer, mhbmCursorBuffer);
  1192.  
  1193.         cxcursor = cxcursor * 2 - 1;
  1194.         while(int t = cxcursor & (cxcursor - 1))
  1195.             cxcursor = t;
  1196.  
  1197.         cycursor = cycursor * 2 - 1;
  1198.         while(int t = cycursor & (cycursor - 1))
  1199.             cycursor = t;
  1200.  
  1201.         mCachedCursor = NULL;
  1202.         mGLCursorCacheTextureInvW = 1.0f / (float)cxcursor;
  1203.         mGLCursorCacheTextureInvH = 1.0f / (float)cycursor;
  1204.  
  1205.         mGL.glGenTextures(1, &mGLCursorCacheTexture);
  1206.         mGL.glBindTexture(GL_TEXTURE_2D, mGLCursorCacheTexture);
  1207.         mGL.glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, cxcursor, cycursor, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
  1208.  
  1209.         if (mGL.NV_occlusion_query && mGL.ARB_multitexture && mbRemoveDuplicates)
  1210.             mGL.glGenOcclusionQueriesNV(2, mGLOcclusionQueries);
  1211.  
  1212.         // initialize shaders
  1213.         mGLShaderBase = mGL.InitTechniques(g_techniques, sizeof g_techniques / sizeof g_techniques[0]);
  1214.  
  1215.         VDASSERT(!mGL.glGetError());
  1216.  
  1217.         mbOpenGLMode = true;
  1218.  
  1219.         FlushFrameQueue();
  1220.  
  1221.         mGL.End();
  1222.  
  1223.         ReleaseDC(mhwndGL, hdc);
  1224.  
  1225.         mTimestampIndex = 0;
  1226.         mTimestampDelay = 0;
  1227.         if (mGL.EXT_pixel_buffer_object)
  1228.             ++mTimestampDelay;
  1229.         if (mGL.NV_occlusion_query && mGL.ARB_multitexture && mbRemoveDuplicates)
  1230.             ++mTimestampDelay;
  1231.     }
  1232.  
  1233.     mbCapBuffersInited = true;
  1234.     return true;
  1235. }
  1236.  
  1237. void VDCaptureDriverScreen::ShutdownVideoBuffer() {
  1238.     mbCapBuffersInited = false;
  1239.  
  1240.     if (mhbmCursorBufferOld) {
  1241.         SelectObject(mhdcCursorBuffer, mhbmCursorBufferOld);
  1242.         mhbmCursorBufferOld = NULL;
  1243.     }
  1244.  
  1245.     if (mhbmCursorBuffer) {
  1246.         DeleteObject(mhbmCursorBuffer);
  1247.         mhbmCursorBuffer = NULL;
  1248.     }
  1249.  
  1250.     if (mhdcCursorBuffer) {
  1251.         DeleteDC(mhdcCursorBuffer);
  1252.         mhdcCursorBuffer = NULL;
  1253.     }
  1254.  
  1255.     if (mGL.IsInited()) {
  1256.         if (HDC hdc = GetDC(mhwndGL)) {
  1257.             if (mGL.Begin(hdc)) {
  1258.                 if (mGL.NV_occlusion_query) {
  1259.                     for(int i=0; i<2; ++i) {
  1260.                         if (mbGLOcclusionValid[i]) {
  1261.                             GetOcclusionQueryPixelCountSafe(mGLOcclusionQueries[i]);
  1262.                             mbGLOcclusionValid[i] = false;
  1263.                         }
  1264.                     }
  1265.                     mGL.glDeleteOcclusionQueriesNV(2, mGLOcclusionQueries);
  1266.                 }
  1267.                 mGL.End();
  1268.             }
  1269.             ReleaseDC(mhwndGL, hdc);
  1270.         }
  1271.  
  1272.         mGL.glDeleteLists(mGLShaderBase, sizeof g_techniques / sizeof g_techniques[0]);
  1273.  
  1274.         if (mGLTextures[0]) {
  1275.             mGL.glDeleteTextures(2, mGLTextures);
  1276.             mGLTextures[0] = 0;
  1277.         }
  1278.  
  1279.         if (mGLCursorCacheTexture) {
  1280.             mGL.glDeleteTextures(1, &mGLCursorCacheTexture);
  1281.             mGLCursorCacheTexture = 0;
  1282.             mCachedCursor = NULL;
  1283.         }
  1284.  
  1285.         if (mGL.EXT_pixel_buffer_object)
  1286.             mGL.glDeleteBuffersARB(2, mGLBuffers);
  1287.  
  1288.         mGL.Shutdown();
  1289.     }
  1290.  
  1291.     if (mhwndGLDraw) {
  1292.         DestroyWindow(mhwndGLDraw);
  1293.         mhwndGLDraw = NULL;
  1294.     }
  1295.  
  1296.     if (mhwndGL) {
  1297.         DestroyWindow(mhwndGL);
  1298.         mhwndGL = NULL;
  1299.     }
  1300.  
  1301.     if (mhdcOffscreen) {
  1302.         DeleteDC(mhdcOffscreen);
  1303.         mhdcOffscreen = NULL;
  1304.     }
  1305.  
  1306.     if (mhbmOffscreen) {
  1307.         DeleteObject(mhbmOffscreen);
  1308.         mhbmOffscreen = NULL;
  1309.     }
  1310. }
  1311.  
  1312. void VDCaptureDriverScreen::FlushFrameQueue() {
  1313.     if (mbOpenGLMode) {
  1314.         for(int i=0; i<2; ++i) {
  1315.             if (mbGLOcclusionValid[i]) {
  1316.                 GetOcclusionQueryPixelCountSafe(mGLOcclusionQueries[i]);
  1317.                 mbGLOcclusionValid[i] = false;
  1318.             }
  1319.         }
  1320.  
  1321.         for(int i=0; i<sizeof(mTimestampQueue)/sizeof(mTimestampQueue[0]); ++i)
  1322.             mTimestampQueue[i] = -1;
  1323.  
  1324.         mbFrameValid[0] = mbFrameValid[1] = false;
  1325.         mbGLOcclusionValid[0] = mbGLOcclusionValid[1] = false;
  1326.         mbGLOcclusionPrevFrameValid = false;
  1327.     }
  1328. }
  1329.  
  1330. sint64 VDCaptureDriverScreen::ComputeGlobalTime() {
  1331.     sint64 tickDelta = (sint64)VDGetAccurateTick() - (sint64)mGlobalTimeBase;
  1332.     if (tickDelta < 0)
  1333.         tickDelta = 0;
  1334.     return (sint64)((uint64)tickDelta * 1000);
  1335. }
  1336.  
  1337. void VDCaptureDriverScreen::DoFrame() {
  1338.     if (!mbCapBuffersInited)
  1339.         return;
  1340.  
  1341.     sint64 globalTime;
  1342.  
  1343.     int w = mVideoFormat->biWidth;
  1344.     int h = abs(mVideoFormat->biHeight);
  1345.     int srcw = w;
  1346.     int srch = h;
  1347.  
  1348.     if (mbRescaleImage) {
  1349.         srcw = mRescaleW;
  1350.         srch = mRescaleH;
  1351.     }
  1352.  
  1353.     if (mbTrackCursor) {
  1354.         POINT pt;
  1355.  
  1356.         if (GetCursorPos(&pt)) {
  1357.             mTrackX = pt.x - ((w+1) >> 1);
  1358.             mTrackY = pt.y - ((h+1) >> 1);
  1359.         }
  1360.     } else {
  1361.         mTrackX = mTrackOffsetX;
  1362.         mTrackY = mTrackOffsetY;
  1363.     }
  1364.  
  1365.     if (mbTrackActiveWindow) {
  1366.         HWND hwndFore = GetForegroundWindow();
  1367.  
  1368.         if (hwndFore) {
  1369.             RECT r;
  1370.             bool success = false;
  1371.  
  1372.             if (mbTrackActiveWindowClient) {
  1373.                 if (GetClientRect(hwndFore, &r)) {
  1374.                     if (MapWindowPoints(hwndFore, NULL, (LPPOINT)&r, 2))
  1375.                         success = true;
  1376.                 }
  1377.             } else {
  1378.                 if (GetWindowRect(hwndFore, &r))
  1379.                     success = true;
  1380.             }
  1381.  
  1382.             if (success) {
  1383.                 if (!mbTrackCursor) {
  1384.                     mTrackX = r.left + mTrackOffsetX;
  1385.                     mTrackY = r.left + mTrackOffsetY;
  1386.                 }
  1387.  
  1388.                 if (mTrackX > r.right - srcw)
  1389.                     mTrackX = r.right - srcw;
  1390.                 if (mTrackX < r.left)
  1391.                     mTrackX = r.left;
  1392.                 if (mTrackY > r.bottom - srch)
  1393.                     mTrackY = r.bottom - srch;
  1394.                 if (mTrackY < r.top)
  1395.                     mTrackY = r.top;
  1396.             }
  1397.         }
  1398.     }
  1399.  
  1400.     globalTime = ComputeGlobalTime();
  1401.     if (mbCapturing || mDisplayMode) {
  1402.         // Check for cursor update.
  1403.         CURSORINFO ci = {sizeof(CURSORINFO)};
  1404.         bool cursorImageUpdated = false;
  1405.  
  1406.         if (mbDrawMousePointer) {
  1407.             if (!::GetCursorInfo(&ci)) {
  1408.                 ci.hCursor = NULL;
  1409.             }
  1410.  
  1411.             if (ci.hCursor) {
  1412.                 if (mCachedCursor != ci.hCursor) {
  1413.                     mCachedCursor = ci.hCursor;
  1414.  
  1415.                     ICONINFO ii;
  1416.                     if (::GetIconInfo(ci.hCursor, &ii)) {
  1417.                         mCachedCursorHotspotX = ii.xHotspot;
  1418.                         mCachedCursorHotspotY = ii.yHotspot;
  1419.  
  1420.                         if (mbOpenGLMode) {
  1421.                             bool mergeMask = false;
  1422.  
  1423.                             HDC hdc = GetDC(NULL);
  1424.                             if (hdc) {
  1425.                                 mbCachedCursorXORMode = false;
  1426.  
  1427.                                 if (!ii.hbmColor) {
  1428.                                     mbCachedCursorXORMode = true;
  1429.  
  1430.                                     // Query bitmap format.
  1431.                                     BITMAPINFOHEADER maskFormat = {sizeof(BITMAPINFOHEADER)};
  1432.                                     if (::GetDIBits(hdc, ii.hbmMask, 0, 0, NULL, (LPBITMAPINFO)&maskFormat, DIB_RGB_COLORS)) {
  1433.                                         // Validate cursor size. This shouldn't change since SM_CXCURSOR and SM_CYCURSOR are constant.
  1434.                                         if (maskFormat.biWidth == mCachedCursorWidth && maskFormat.biHeight == mCachedCursorHeight * 2) {
  1435.                                             // Retrieve bitmap bits.
  1436.                                             BITMAPINFOHEADER hdr = {};
  1437.                                             hdr.biSize            = sizeof(BITMAPINFOHEADER);
  1438.                                             hdr.biWidth            = maskFormat.biWidth;
  1439.                                             hdr.biHeight        = maskFormat.biHeight;
  1440.                                             hdr.biPlanes        = 1;
  1441.                                             hdr.biBitCount        = 32;
  1442.                                             hdr.biCompression    = BI_RGB;
  1443.                                             hdr.biSizeImage        = maskFormat.biWidth * maskFormat.biHeight * 4;
  1444.                                             hdr.biXPelsPerMeter    = 0;
  1445.                                             hdr.biYPelsPerMeter    = 0;
  1446.                                             hdr.biClrUsed        = 0;
  1447.                                             hdr.biClrImportant    = 0;
  1448.  
  1449.                                             ::GetDIBits(hdc, ii.hbmMask, 0, maskFormat.biHeight, mpCursorBuffer, (LPBITMAPINFO)&hdr, DIB_RGB_COLORS);
  1450.                                         }
  1451.                                     }
  1452.  
  1453.                                     uint32 numPixels = mCachedCursorWidth * mCachedCursorHeight;
  1454.                                     uint32 *pXORMask = mpCursorBuffer;
  1455.                                     uint32 *pANDMask = pXORMask + numPixels;
  1456.  
  1457.                                     for(uint32 i=0; i<numPixels; ++i)
  1458.                                         pXORMask[i] = (pXORMask[i] & 0xFFFFFF) + (~pANDMask[i] << 24);
  1459.                                 } else {
  1460.                                     RECT r1 = {0, 0, mCachedCursorWidth, mCachedCursorHeight};
  1461.                                     RECT r2 = {0, mCachedCursorHeight, mCachedCursorWidth, mCachedCursorHeight*2};
  1462.                                     FillRect(mhdcCursorBuffer, &r1, (HBRUSH)GetStockObject(BLACK_BRUSH));
  1463.                                     FillRect(mhdcCursorBuffer, &r2, (HBRUSH)GetStockObject(WHITE_BRUSH));
  1464.                                     DrawIcon(mhdcCursorBuffer, 0, 0, ci.hCursor);
  1465.                                     DrawIcon(mhdcCursorBuffer, 0, mCachedCursorHeight, ci.hCursor);
  1466.                                     GdiFlush();
  1467.  
  1468.                                     uint32 numPixels = mCachedCursorWidth * mCachedCursorHeight;
  1469.                                     uint32 *pWhiteMask = mpCursorBuffer;
  1470.                                     uint32 *pBlackMask = pWhiteMask + numPixels;
  1471.  
  1472.                                     for(uint32 i=0; i<numPixels; ++i) {
  1473.                                         uint32 pixelOnWhite = pWhiteMask[i];
  1474.                                         uint32 pixelOnBlack = pBlackMask[i];
  1475.                                         int alpha = 255 - (int)(pWhiteMask[i] & 255) + (int)(pBlackMask[i] & 255);
  1476.                                         if ((unsigned)alpha >= 256)
  1477.                                             alpha = ~alpha >> 31;
  1478.                                         pWhiteMask[i] = (pBlackMask[i] & 0xffffff) + (alpha << 24);
  1479.                                     }
  1480.                                 }
  1481.  
  1482.                                 cursorImageUpdated = true;
  1483.                                 ReleaseDC(NULL, hdc);
  1484.                             }
  1485.                         }
  1486.  
  1487.                         if (ii.hbmColor)
  1488.                             VDVERIFY(::DeleteObject(ii.hbmColor));
  1489.                         if (ii.hbmMask)
  1490.                             VDVERIFY(::DeleteObject(ii.hbmMask));
  1491.                     }
  1492.                 }
  1493.  
  1494.                 ci.ptScreenPos.x -= mCachedCursorHotspotX;
  1495.                 ci.ptScreenPos.y -= mCachedCursorHotspotY;
  1496.             }
  1497.         }
  1498.  
  1499.         if (mbOpenGLMode) {
  1500.             RECT r = {0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN)};
  1501.  
  1502.             GetWindowRect(mhwndGL, &r);
  1503.  
  1504.             if (HDC hdc = GetDC(mhwndGL)) {
  1505.                 if (mGL.Begin(hdc)) {
  1506.                     // init state
  1507.                     VDASSERT(!mGL.glGetError());
  1508.                     mGL.glDrawBuffer(GL_BACK);
  1509.                     mGL.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  1510.  
  1511.                     // update cursor if necessary
  1512.                     if (cursorImageUpdated) {
  1513.                         mGL.glBindTexture(GL_TEXTURE_2D, mGLCursorCacheTexture);
  1514.                         mGL.glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mCachedCursorWidth, mCachedCursorHeight, GL_BGRA_EXT, GL_UNSIGNED_BYTE, mpCursorBuffer);
  1515.                     }
  1516.  
  1517.                     // read screen into texture
  1518.                     if (mGL.ARB_multitexture)
  1519.                         mGL.glActiveTextureARB(GL_TEXTURE0_ARB);
  1520.                     mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  1521.  
  1522.                     int srcx = mTrackX - r.left;
  1523.                     int srcy = r.bottom - (mTrackY + srch);
  1524.  
  1525.                     if (srcx > r.right - r.left - srcw)
  1526.                         srcx = r.right - r.left - srcw;
  1527.                     if (srcy > r.bottom - r.top - srch)
  1528.                         srcy = r.bottom - r.top - srch;
  1529.                     if (srcx < 0)
  1530.                         srcx = 0;
  1531.                     if (srcy < 0)
  1532.                         srcy = 0;
  1533.  
  1534.                     // Enable depth test. We don't actually want the depth test, but we need it
  1535.                     // on for occlusion query to work on ATI.
  1536.                     mGL.glEnable(GL_DEPTH_TEST);
  1537.                     mGL.glDepthFunc(GL_ALWAYS);
  1538.                     mGL.glDepthMask(GL_FALSE);
  1539.  
  1540.                     // shrink image
  1541.                     VDASSERT(!mGL.glGetError());
  1542.                     mGL.glDisable(GL_LIGHTING);
  1543.                     mGL.glDisable(GL_CULL_FACE);
  1544.                     mGL.glDisable(GL_BLEND);
  1545.                     mGL.glDisable(GL_ALPHA_TEST);
  1546.                     mGL.glDisable(GL_STENCIL_TEST);
  1547.                     mGL.glDisable(GL_SCISSOR_TEST);
  1548.                     mGL.glEnable(GL_TEXTURE_2D);
  1549.  
  1550.                     mGL.DisableFragmentShaders();
  1551.  
  1552.                     int fbw = srcw < w ? w : srcw;
  1553.                     int fbh = srch < h ? h : srch;
  1554.  
  1555.                     mGL.glViewport(0, 0, fbw, fbh);
  1556.                     mGL.glMatrixMode(GL_MODELVIEW);
  1557.                     mGL.glLoadIdentity();
  1558.                     mGL.glMatrixMode(GL_PROJECTION);
  1559.                     mGL.glLoadIdentity();
  1560.                     mGL.glOrtho(0, fbw, 0, fbh, -1.0f, 1.0f);
  1561.  
  1562.                     VDASSERT(!mGL.glGetError());
  1563.                     mGL.glReadBuffer(GL_FRONT);
  1564.  
  1565.                     mProfileChannel.Begin(0xd0e0f0, "GL:ReadScreen");
  1566.                     if (!mbRescaleImage || mbDrawMousePointer) {
  1567.                         mGL.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, srcx, srcy, srcw, srch);
  1568.                         mGL.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1569.  
  1570.                         float u = (float)srcw / (float)mGLTextureW;
  1571.                         float v = (float)srch / (float)mGLTextureH;
  1572.  
  1573.                         mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  1574.                         mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  1575.                         mGL.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  1576.                         mGL.glBegin(GL_QUADS);
  1577.                             mGL.glTexCoord2f(0.0f, 0.0f);
  1578.                             mGL.glVertex2f(0, 0);
  1579.                             mGL.glTexCoord2f(u, 0.0f);
  1580.                             mGL.glVertex2f((float)srcw, 0);
  1581.                             mGL.glTexCoord2f(u, v);
  1582.                             mGL.glVertex2f((float)srcw, (float)srch);
  1583.                             mGL.glTexCoord2f(0.0f, v);
  1584.                             mGL.glVertex2f(0, (float)srch);
  1585.                         mGL.glEnd();
  1586.                         mGL.glReadBuffer(GL_BACK);
  1587.  
  1588.                         if (ci.hCursor) {
  1589.                             mGL.glBindTexture(GL_TEXTURE_2D, mGLCursorCacheTexture);
  1590.                             mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
  1591.                             mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
  1592.                             mGL.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  1593.  
  1594.                             int curx = ci.ptScreenPos.x - srcx;
  1595.                             int cury = (r.bottom - (ci.ptScreenPos.y + mCachedCursorHeight)) - srcy;
  1596.                             float curu = (float)mCachedCursorWidth * mGLCursorCacheTextureInvW;
  1597.                             float curv = (float)mCachedCursorHeight * mGLCursorCacheTextureInvH;
  1598.                             mGL.glEnable(GL_BLEND);
  1599.  
  1600.                             if (mbCachedCursorXORMode && mGL.EXT_texture_env_combine) {
  1601.                                 mGL.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT);
  1602.                                 mGL.glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE);
  1603.                                 mGL.glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE);
  1604.                                 mGL.glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_EXT, GL_ONE_MINUS_SRC_ALPHA);
  1605.                                 mGL.glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_TEXTURE);
  1606.                                 mGL.glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB_EXT, GL_SRC_COLOR);
  1607.                                 mGL.glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE);
  1608.                                 mGL.glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE);
  1609.                                 mGL.glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_EXT, GL_SRC_ALPHA);
  1610.                                 mGL.glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1);
  1611.                                 mGL.glTexEnvi(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);
  1612.                                 mGL.glBlendFunc(GL_ONE_MINUS_DST_COLOR, GL_ONE_MINUS_SRC_COLOR);
  1613.                                 mGL.glBegin(GL_QUADS);
  1614.                                     mGL.glTexCoord2f(0.0f, 0.0f);
  1615.                                     mGL.glVertex2i(curx, cury);
  1616.                                     mGL.glTexCoord2f(curu, 0.0f);
  1617.                                     mGL.glVertex2i(curx + mCachedCursorWidth, cury);
  1618.                                     mGL.glTexCoord2f(curu, curv);
  1619.                                     mGL.glVertex2i(curx + mCachedCursorWidth, cury + mCachedCursorHeight);
  1620.                                     mGL.glTexCoord2f(0.0f, curv);
  1621.                                     mGL.glVertex2i(curx, cury + mCachedCursorHeight);
  1622.                                 mGL.glEnd();
  1623.                                 mGL.glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  1624.                                 mGL.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1625.                             } else
  1626.                                 mGL.glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
  1627.  
  1628.                             mGL.glBegin(GL_QUADS);
  1629.                                 mGL.glTexCoord2f(0.0f, 0.0f);
  1630.                                 mGL.glVertex2i(curx, cury);
  1631.                                 mGL.glTexCoord2f(curu, 0.0f);
  1632.                                 mGL.glVertex2i(curx + mCachedCursorWidth, cury);
  1633.                                 mGL.glTexCoord2f(curu, curv);
  1634.                                 mGL.glVertex2i(curx + mCachedCursorWidth, cury + mCachedCursorHeight);
  1635.                                 mGL.glTexCoord2f(0.0f, curv);
  1636.                                 mGL.glVertex2i(curx, cury + mCachedCursorHeight);
  1637.                             mGL.glEnd();
  1638.                             mGL.glDisable(GL_BLEND);
  1639.                             mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  1640.                         }
  1641.  
  1642.                         srcx = 0;
  1643.                         srcy = 0;
  1644.                     }
  1645.  
  1646.                     if (mbRescaleImage) {
  1647.                         do {
  1648.                             int dstw = std::max<int>(w, (srcw+1) >> 1);
  1649.                             int dsth = std::max<int>(h, (srch+1) >> 1);
  1650.  
  1651.                             mGL.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, srcx, srcy, srcw, srch);
  1652.                             srcx = 0;
  1653.                             srcy = 0;
  1654.  
  1655.                             mGL.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1656.  
  1657.                             float u = (float)srcw / (float)mGLTextureW;
  1658.                             float v = (float)srch / (float)mGLTextureH;
  1659.  
  1660.                             mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  1661.                             mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  1662.                             mGL.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  1663.                             mGL.glBegin(GL_QUADS);
  1664.                                 mGL.glTexCoord2f(0.0f, 0.0f);
  1665.                                 mGL.glVertex2f(0, 0);
  1666.                                 mGL.glTexCoord2f(u, 0.0f);
  1667.                                 mGL.glVertex2f((float)dstw, 0);
  1668.                                 mGL.glTexCoord2f(u, v);
  1669.                                 mGL.glVertex2f((float)dstw, (float)dsth);
  1670.                                 mGL.glTexCoord2f(0.0f, v);
  1671.                                 mGL.glVertex2f(0, (float)dsth);
  1672.                             mGL.glEnd();
  1673.  
  1674.                             mGL.glReadBuffer(GL_BACK);
  1675.                             srcw = dstw;
  1676.                             srch = dsth;
  1677.                         } while(srcw != w || srch != h);
  1678.                     }
  1679.                     mProfileChannel.End();
  1680.  
  1681.                     VDASSERT(!mGL.glGetError());
  1682.  
  1683.                     // compute texturing parameters
  1684.                     float u = (float)w / (float)mGLTextureW;
  1685.                     float v = (float)h / (float)mGLTextureH;
  1686.  
  1687.                     bool removeDuplicates = mGL.NV_occlusion_query && mGL.ARB_multitexture && mbRemoveDuplicates;
  1688.                     if (mVideoFormat->biCompression || removeDuplicates || mDisplayMode == kDisplaySoftware || mDisplayMode == kDisplayHardware) {
  1689.                         mGL.glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, w, h);
  1690.  
  1691.                         if (removeDuplicates) {
  1692.                             if (!mbGLOcclusionPrevFrameValid) {
  1693.                                 mbGLOcclusionPrevFrameValid = true;
  1694.                                 mbFrameValid[0] = true;
  1695.                             } else {
  1696.                                 mProfileChannel.Begin(0xa0c0f0, "GL:OcclusionQuery");
  1697.                                 mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  1698.                                 mGL.glEnable(GL_TEXTURE_2D);
  1699.                                 mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[1]);
  1700.  
  1701.                                 mGL.glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
  1702.                                 mGL.glEnable(GL_ALPHA_TEST);
  1703.                                 mGL.glAlphaFunc(GL_GREATER, 0.0f);
  1704.                                 
  1705.                                 mGL.glBeginOcclusionQueryNV(mGLOcclusionQueries[0]);
  1706.                                 if (mGL.NV_register_combiners)
  1707.                                     mGL.glCallList(mGLShaderBase + kVDOpenGLTechIndex_difference_NV1x);
  1708.                                 else if (mGL.ATI_fragment_shader)
  1709.                                     mGL.glCallList(mGLShaderBase + kVDOpenGLTechIndex_difference_ATIFS);
  1710.  
  1711.                                 mGL.glBegin(GL_QUADS);
  1712.                                     mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0f, 0.0f);
  1713.                                     mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0f, 0.0f);
  1714.                                     mGL.glVertex2f(0, 0);
  1715.                                     mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u, 0.0f);
  1716.                                     mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u, 0.0f);
  1717.                                     mGL.glVertex2f((float)w, 0);
  1718.                                     mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u, v);
  1719.                                     mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u, v);
  1720.                                     mGL.glVertex2f((float)w, (float)h);
  1721.                                     mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.0f, v);
  1722.                                     mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.0f, v);
  1723.                                     mGL.glVertex2f(0, (float)h);
  1724.                                 mGL.glEnd();
  1725.                                 mGL.glEndOcclusionQueryNV();
  1726.                                 mGL.glFlush();
  1727.  
  1728.                                 mbGLOcclusionValid[0] = true;
  1729.  
  1730.                                 mGL.glDisable(GL_ALPHA_TEST);
  1731.                                 mGL.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  1732.  
  1733.                                 std::swap(mGLTextures[0], mGLTextures[1]);
  1734.                                 std::swap(mGLOcclusionQueries[0], mGLOcclusionQueries[1]);
  1735.                                 std::swap(mbGLOcclusionValid[0], mbGLOcclusionValid[1]);
  1736.                                 mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  1737.                                 mGL.glDisable(GL_TEXTURE_2D);
  1738.                                 mGL.glActiveTextureARB(GL_TEXTURE0_ARB);
  1739.                                 mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  1740.  
  1741.                                 GLint pixelCount = 0;
  1742.  
  1743.                                 if (mbGLOcclusionValid[0]) {
  1744.                                     pixelCount = GetOcclusionQueryPixelCountSafe(mGLOcclusionQueries[0]);
  1745.                                     mbGLOcclusionValid[0] = false;
  1746.                                 }
  1747.  
  1748.                                 mbFrameValid[0] = (pixelCount > 0);
  1749.  
  1750.                                 VDASSERT(!mGL.glGetError());
  1751.                                 std::swap(mbFrameValid[0], mbFrameValid[1]);
  1752.                                 mProfileChannel.End();
  1753.                             }
  1754.                         } else
  1755.                             mbFrameValid[0] = mbFrameValid[1] = true;
  1756.                     } else
  1757.                         mbFrameValid[0] = mbFrameValid[1] = true;
  1758.  
  1759.                     mProfileChannel.Begin(0xa0ffa0, "GL:ConvertAndRead");
  1760.                     switch(mVideoFormat->biCompression) {
  1761.                     case VDMAKEFOURCC('Y', 'V', '1', '2'):
  1762.                         if (mGL.ATI_fragment_shader)
  1763.                             ConvertToYV12_GL_ATIFS(w, h, u, v);
  1764.                         else if (mGL.NV_register_combiners) {
  1765.                             if (mGL.NV_register_combiners2)
  1766.                                 ConvertToYV12_GL_NV2x(w, h, u, v);
  1767.                             else
  1768.                                 ConvertToYV12_GL_NV1x(w, h, u, v);
  1769.                         }
  1770.                         break;
  1771.                     case VDMAKEFOURCC('Y', 'U', 'Y', '2'):
  1772.                         if (mGL.ATI_fragment_shader)
  1773.                             ConvertToYUY2_GL_NV2x_ATIFS(w, h, u, v, true);
  1774.                         else if (mGL.NV_register_combiners) {
  1775.                             if (mGL.NV_register_combiners2)
  1776.                                 ConvertToYUY2_GL_NV2x_ATIFS(w, h, u, v, false);
  1777.                             else
  1778.                                 ConvertToYUY2_GL_NV1x(w, h, u, v);
  1779.                         }
  1780.                         break;
  1781.                     default:
  1782.                         mGL.glReadBuffer(GL_BACK);
  1783.                         if (mGL.EXT_pixel_buffer_object) {
  1784.                             mGL.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mGLBuffers[0]);
  1785.                             mGL.glReadPixels(0, 0, w, h, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void *)0);
  1786.                         } else
  1787.                             mGL.glReadPixels(0, 0, w, h, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void *)mGLReadBuffer.data());
  1788.  
  1789.                         break;
  1790.                     }
  1791.                     mProfileChannel.End();
  1792.  
  1793.                     // readback!
  1794.  
  1795.                     mTimestampQueue[mTimestampIndex & 3] = globalTime;
  1796.                     globalTime = mTimestampQueue[(mTimestampIndex + mTimestampDelay) & 3];
  1797.                     ++mTimestampIndex;
  1798.  
  1799.                     if (globalTime >= 0) {
  1800.                         if (mGL.EXT_pixel_buffer_object) {
  1801.                             if (mbFrameValid[0]) {
  1802.                                 mGL.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mGLBuffers[1]);
  1803.                                 mProfileChannel.Begin(0xa0a0ff, "GL:MapBuffer");
  1804.                                 void *p = mGL.glMapBufferARB(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
  1805.                                 mProfileChannel.End();
  1806.                                 DispatchFrame(p, mOffscreenSize, globalTime);
  1807.                                 mGL.glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB);
  1808.                             } else
  1809.                                 DispatchFrame(NULL, 0, globalTime);
  1810.  
  1811.                             std::swap(mGLBuffers[0], mGLBuffers[1]);
  1812.                         } else {
  1813.                             if (mbFrameValid[0])
  1814.                                 DispatchFrame(mGLReadBuffer.data(), mOffscreenSize, globalTime);
  1815.                             else
  1816.                                 DispatchFrame(NULL, 0, globalTime);
  1817.                         }
  1818.                     }
  1819.  
  1820.                     VDASSERT(!mGL.glGetError());
  1821.  
  1822.                     // necessary for ATI to work
  1823.                     if (mGL.ATI_fragment_shader) {
  1824.                         if (mGL.EXT_swap_control)
  1825.                             mGL.wglSwapIntervalEXT(0);
  1826.                         mGL.wglSwapBuffers(hdc);
  1827.                     }
  1828.  
  1829.                     mGL.End();
  1830.                 }
  1831.                 ReleaseDC(mhwndGL, hdc);
  1832.             }
  1833.         } else {
  1834.             mProfileChannel.Begin(0xf0d0d0, "Capture (GDI)");
  1835.             if (HDC hdc = GetDC(NULL)) {
  1836.                 static DWORD sBitBltMode = AutodetectCaptureBltMode();
  1837.  
  1838.                 int srcx = mTrackX;
  1839.                 int srcy = mTrackY;
  1840.  
  1841.                 int limitx = GetSystemMetrics(SM_CXSCREEN) - w;
  1842.                 int limity = GetSystemMetrics(SM_CYSCREEN) - h;
  1843.  
  1844.                 if (srcx > limitx)
  1845.                     srcx = limitx;
  1846.  
  1847.                 if (srcx < 0)
  1848.                     srcx = 0;
  1849.  
  1850.                 if (srcy > limity)
  1851.                     srcy = limity;
  1852.  
  1853.                 if (srcy < 0)
  1854.                     srcy = 0;
  1855.  
  1856.                 BitBlt(mhdcOffscreen, 0, 0, w, h, hdc, srcx, srcy, sBitBltMode);
  1857.                 if (ci.hCursor)
  1858.                     DrawIcon(mhdcOffscreen, ci.ptScreenPos.x - srcx, ci.ptScreenPos.y - srcy, ci.hCursor);
  1859.                 ReleaseDC(NULL, hdc);
  1860.             }
  1861.             mProfileChannel.End();
  1862.  
  1863.             if (mDisplayMode == kDisplaySoftware || mDisplayMode == kDisplayAnalyze) {
  1864.                 mProfileChannel.Begin(0xe0e0e0, "Preview (GDI)");
  1865.                 if (HDC hdc = GetDC(mhwnd)) {
  1866.                     BitBlt(hdc, 0, 0, w, h, mhdcOffscreen, 0, 0, SRCCOPY);
  1867.                     ReleaseDC(mhwnd, hdc);
  1868.                 }
  1869.                 mProfileChannel.End();
  1870.             }
  1871.  
  1872.             GdiFlush();
  1873.             DispatchFrame(mpOffscreenData, mOffscreenSize, globalTime);
  1874.         }
  1875.     }
  1876.     
  1877.     if (mbVisible) {
  1878.         if (mbOpenGLMode) {
  1879.             if (mDisplayMode == kDisplayHardware || mDisplayMode == kDisplaySoftware) {
  1880.                 RECT rdraw;
  1881.                 GetClientRect(mhwndGLDraw, &rdraw);
  1882.  
  1883.                 if (rdraw.right && rdraw.bottom) {
  1884.                     mProfileChannel.Begin(0xe0e0e0, "Overlay (OpenGL)");
  1885.                     if (HDC hdcDraw = GetDC(mhwndGLDraw)) {
  1886.                         if (mGL.Begin(hdcDraw)) {
  1887.                             VDASSERT(!mGL.glGetError());
  1888.                             mGL.glDisable(GL_LIGHTING);
  1889.                             mGL.glDisable(GL_CULL_FACE);
  1890.                             mGL.glDisable(GL_BLEND);
  1891.                             mGL.glDisable(GL_ALPHA_TEST);
  1892.                             mGL.glDisable(GL_DEPTH_TEST);
  1893.                             mGL.glDisable(GL_STENCIL_TEST);
  1894.                             mGL.glDisable(GL_SCISSOR_TEST);
  1895.                             mGL.glEnable(GL_TEXTURE_2D);
  1896.  
  1897.                             VDASSERT(!mGL.glGetError());
  1898.                             mGL.DisableFragmentShaders();
  1899.  
  1900.                             float dstw = (float)rdraw.right;
  1901.                             float dsth = (float)rdraw.bottom;
  1902.  
  1903.                             VDASSERT(!mGL.glGetError());
  1904.                             mGL.glViewport(0, 0, rdraw.right, rdraw.bottom);
  1905.                             mGL.glMatrixMode(GL_MODELVIEW);
  1906.                             mGL.glLoadIdentity();
  1907.                             mGL.glMatrixMode(GL_PROJECTION);
  1908.                             mGL.glLoadIdentity();
  1909.                             mGL.glOrtho(0, dstw, 0, dsth, -1.0f, 1.0f);
  1910.  
  1911.                             mGL.glDrawBuffer(GL_BACK);
  1912.                             mGL.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  1913.                             mGL.glClearColor(0.5f, 0.0f, 0.0f, 0.0f);
  1914.                             mGL.glClear(GL_COLOR_BUFFER_BIT);
  1915.                             VDASSERT(!mGL.glGetError());
  1916.  
  1917.                             mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  1918.                             VDASSERT(!mGL.glGetError());
  1919.  
  1920.                             mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  1921.                             mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  1922.                             mGL.glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
  1923.                             mGL.glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
  1924.  
  1925.                             float u = (float)srcw / (float)mGLTextureW;
  1926.                             float v = (float)srch / (float)mGLTextureH;
  1927.  
  1928.                             VDASSERT(!mGL.glGetError());
  1929.                             mGL.glBegin(GL_QUADS);
  1930.                                 mGL.glTexCoord2f(0.0f, 0.0f);
  1931.                                 mGL.glVertex2f(0, 0);
  1932.                                 mGL.glTexCoord2f(u, 0.0f);
  1933.                                 mGL.glVertex2f(dstw, 0);
  1934.                                 mGL.glTexCoord2f(u, v);
  1935.                                 mGL.glVertex2f(dstw, dsth);
  1936.                                 mGL.glTexCoord2f(0.0f, v);
  1937.                                 mGL.glVertex2f(0, dsth);
  1938.                             mGL.glEnd();
  1939.                             VDASSERT(!mGL.glGetError());
  1940.  
  1941.                             if (mGL.EXT_swap_control)
  1942.                                 mGL.wglSwapIntervalEXT(0);
  1943.  
  1944.                             mGL.wglSwapBuffers(hdcDraw);
  1945.                             mGL.End();
  1946.                         }
  1947.                         ReleaseDC(mhwndGLDraw, hdcDraw);
  1948.                     }
  1949.                     mProfileChannel.End();
  1950.                 }
  1951.             }
  1952.         } else {
  1953.             if (mDisplayMode == kDisplayHardware) {
  1954.                 mProfileChannel.Begin(0xe0e0e0, "Overlay (GDI)");
  1955.                 if (HDC hdcScreen = GetDC(NULL)) {
  1956.                     if (HDC hdc = GetDC(mhwnd)) {
  1957.                         int srcx = mTrackX;
  1958.                         int srcy = mTrackY;
  1959.  
  1960.                         int limitx = GetSystemMetrics(SM_CXSCREEN) - w;
  1961.                         int limity = GetSystemMetrics(SM_CYSCREEN) - h;
  1962.  
  1963.                         if (srcx > limitx)
  1964.                             srcx = limitx;
  1965.  
  1966.                         if (srcx < 0)
  1967.                             srcx = 0;
  1968.  
  1969.                         if (srcy > limity)
  1970.                             srcy = limity;
  1971.  
  1972.                         if (srcy < 0)
  1973.                             srcy = 0;
  1974.  
  1975.                         BitBlt(hdc, 0, 0, w, h, hdcScreen, srcx, srcy, SRCCOPY);
  1976.                         ReleaseDC(mhwnd, hdc);
  1977.                     }
  1978.                     ReleaseDC(NULL, hdcScreen);
  1979.                 }
  1980.                 mProfileChannel.End();
  1981.             }
  1982.         }
  1983.     }
  1984.  
  1985.     if (mDisplayMode)
  1986.         ++mPreviewFrameCount;
  1987. }
  1988.  
  1989. void VDCaptureDriverScreen::DispatchFrame(const void *data, uint32 size, sint64 timestamp) {
  1990.     if (!mpCB)
  1991.         return;
  1992.  
  1993.     if (mDisplayMode == kDisplayAnalyze && size) {
  1994.         try {
  1995.             mpCB->CapProcessData(-1, data, size, 0, true, 0);
  1996.         } catch(MyError&) {
  1997.             // Eat preview errors.
  1998.         }
  1999.     }
  2000.  
  2001.     if (mbCapturing) {
  2002.         try {
  2003.             if (mpCB->CapEvent(kEventCapturing, 0))
  2004.                 mpCB->CapProcessData(0, data, size, timestamp, true, timestamp);
  2005.             else {
  2006.                 mbCapturing = false;
  2007.                 CaptureAbort();
  2008.             }
  2009.  
  2010.         } catch(MyError& e) {
  2011.             mCaptureError.TransferFrom(e);
  2012.             CaptureAbort();
  2013.             mbCapturing = false;
  2014.         }
  2015.     }
  2016. }
  2017.  
  2018. void VDCaptureDriverScreen::ConvertToYV12_GL_NV1x(int w, int h, float u, float v) {
  2019.     // YV12 conversion - NV_register_combiners path
  2020.     mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  2021.     mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  2022.     mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  2023.     mGL.glEnable(GL_TEXTURE_2D);
  2024.     mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  2025.     mGL.glActiveTextureARB(GL_TEXTURE0_ARB);
  2026.  
  2027.     float y = 0.0f;
  2028.     float w4 = (float)w * 0.25f;
  2029.     for(int phase=0; phase<4; phase += 2) {
  2030.         float u0 = ((float)phase - 1.5f) / (float)mGLTextureW;
  2031.         float v0 = 0;
  2032.         float u1 = u0 + u;
  2033.         float v1 = v0 + v;
  2034.  
  2035.         float u2 = ((float)phase - 0.5f) / (float)mGLTextureW;
  2036.         float u3 = u2 + u;
  2037.  
  2038.         mGL.glCallList(mGLShaderBase + (phase ? kVDOpenGLTechIndex_YV12_NV1x_Y_ra : kVDOpenGLTechIndex_YV12_NV1x_Y_gb));
  2039.         mGL.glColorMask(GL_TRUE, phase==0, phase==0, GL_TRUE);
  2040.  
  2041.         float y0 = y;
  2042.         float y1 = y + (float)h;
  2043.  
  2044.         mGL.glColor4f(0.0f, 0.0f, 1.0f, 0.0f);
  2045.  
  2046.         mGL.glBegin(GL_QUADS);
  2047.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v1);    mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2, v1);    mGL.glVertex2f(0.0f, y0);
  2048.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1, v1);    mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v1);    mGL.glVertex2f(w4, y0);
  2049.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1, v0);    mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v0);    mGL.glVertex2f(w4, y1);
  2050.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v0);    mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2, v0);    mGL.glVertex2f(0.0f, y1);
  2051.         mGL.glEnd();
  2052.         VDASSERT(!mGL.glGetError());
  2053.     }
  2054.  
  2055.     y = 0.0f;
  2056.  
  2057.     float w8 = (float)w * 0.125f;
  2058.     int h2 = h >> 1;
  2059.     for(int cmode=0; cmode<2; ++cmode) {
  2060.         mGL.glCallList(mGLShaderBase + (cmode ? kVDOpenGLTechIndex_YV12_NV1x_Cb : kVDOpenGLTechIndex_YV12_NV1x_Cr));
  2061.         for(int phase=0; phase<4; phase += 2) {
  2062.             float u0 = (float)(phase * 2 - 3.0f) / (float)mGLTextureW;
  2063.             float v0 = 0;
  2064.             float u1 = u0 + u;
  2065.             float v1 = v0 + v;
  2066.  
  2067.             float u2 = (float)(phase * 2 - 1.0f) / (float)mGLTextureW;
  2068.             float u3 = u0 + u;
  2069.  
  2070.             mGL.glColorMask(GL_TRUE, phase==0, phase==0, GL_TRUE);
  2071.  
  2072.             float y0 = y;
  2073.             float y1 = y + (float)h2;
  2074.  
  2075.             mGL.glBegin(GL_QUADS);
  2076.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v1);    mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2, v1);    mGL.glVertex2f(w4, y0);
  2077.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1, v1);    mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v1);    mGL.glVertex2f(w4+w8, y0);
  2078.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1, v0);    mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v0);    mGL.glVertex2f(w4+w8, y1);
  2079.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v0);    mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2, v0);    mGL.glVertex2f(w4, y1);
  2080.             mGL.glEnd();
  2081.             VDASSERT(!mGL.glGetError());
  2082.         }
  2083.  
  2084.         y += h2;
  2085.     }
  2086.  
  2087.     mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  2088.     mGL.glDisable(GL_TEXTURE_2D);
  2089.     mGL.glActiveTextureARB(GL_TEXTURE0_ARB);
  2090.  
  2091.     // readback!
  2092.     VDASSERT(!mGL.glGetError());
  2093.     mGL.glReadBuffer(GL_BACK);
  2094.  
  2095.     if (mGL.EXT_pixel_buffer_object) {
  2096.         mGL.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mGLBuffers[0]);
  2097.         mGL.glReadPixels(0, 0, w >> 2, h, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void *)0);
  2098.         mGL.glReadPixels(w >> 2, 0, w >> 3, h >> 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void *)(w * h));
  2099.         mGL.glReadPixels(w >> 2, h >> 1, w >> 3, h >> 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void *)(w * h * 5 / 4));
  2100.     } else {
  2101.         char *dst = (char *)mGLReadBuffer.data();
  2102.         mGL.glReadPixels(0, 0, w >> 2, h, GL_BGRA_EXT, GL_UNSIGNED_BYTE, dst);
  2103.         mGL.glReadPixels(w >> 2, 0, w >> 3, h >> 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, dst + (w * h));
  2104.         mGL.glReadPixels(w >> 2, h >> 1, w >> 3, h >> 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, dst + (w * h * 5 / 4));
  2105.     }
  2106. }
  2107.  
  2108. void VDCaptureDriverScreen::ConvertToYV12_GL_NV2x(int w, int h, float u, float v) {
  2109.     // YV12 conversion - NV_register_combiners2 path
  2110.     mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  2111.     mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  2112.     mGL.glActiveTextureARB(GL_TEXTURE3_ARB);
  2113.     mGL.glEnable(GL_TEXTURE_2D);
  2114.     mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  2115.     mGL.glActiveTextureARB(GL_TEXTURE2_ARB);
  2116.     mGL.glEnable(GL_TEXTURE_2D);
  2117.     mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  2118.     mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  2119.     mGL.glEnable(GL_TEXTURE_2D);
  2120.     mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  2121.     mGL.glActiveTextureARB(GL_TEXTURE0_ARB);
  2122.  
  2123.     float y = 0.0f;
  2124.     float w4 = (float)w * 0.25f;
  2125.     {
  2126.         float u0 = -1.5f / (float)mGLTextureW;
  2127.         float v0 = 0;
  2128.         float u1 = u0 + u;
  2129.         float v1 = v0 + v;
  2130.  
  2131.         float u2 = -0.5f / (float)mGLTextureW;
  2132.         float u3 = u2 + u;
  2133.  
  2134.         float u4 = +0.5f / (float)mGLTextureW;
  2135.         float u5 = u4 + u;
  2136.  
  2137.         float u6 = +1.5f / (float)mGLTextureW;
  2138.         float u7 = u6 + u;
  2139.  
  2140.         mGL.glCallList(mGLShaderBase + kVDOpenGLTechIndex_YV12_NV2x_Y);
  2141.         mGL.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  2142.  
  2143.         float y0 = y;
  2144.         float y1 = y + (float)h;
  2145.  
  2146.         mGL.glColor4f(0.0f, 0.0f, 1.0f, 0.0f);
  2147.  
  2148.         mGL.glBegin(GL_QUADS);
  2149.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v1);
  2150.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2, v1);
  2151.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u4, v1);
  2152.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u6, v1);
  2153.             mGL.glVertex2f(0.0f, y0);
  2154.  
  2155.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1, v1);
  2156.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v1);
  2157.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u5, v1);
  2158.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u7, v1);
  2159.             mGL.glVertex2f(w4, y0);
  2160.  
  2161.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1, v0);
  2162.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v0);
  2163.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u5, v0);
  2164.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u7, v0);
  2165.             mGL.glVertex2f(w4, y1);
  2166.  
  2167.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v0);
  2168.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2, v0);
  2169.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u4, v0);
  2170.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u6, v0);
  2171.             mGL.glVertex2f(0.0f, y1);
  2172.         mGL.glEnd();
  2173.         VDASSERT(!mGL.glGetError());
  2174.     }
  2175.  
  2176.     mGL.glActiveTextureARB(GL_TEXTURE3_ARB);
  2177.     mGL.glDisable(GL_TEXTURE_2D);
  2178.  
  2179.     y = 0.0f;
  2180.  
  2181.     float w8 = (float)w * 0.125f;
  2182.     int h2 = h >> 1;
  2183.     for(int cmode=0; cmode<2; ++cmode) {
  2184.         mGL.glCallList(mGLShaderBase + (cmode ? kVDOpenGLTechIndex_YV12_NV2x_Cb : kVDOpenGLTechIndex_YV12_NV2x_Cr));
  2185.         for(int phase=0; phase<4; phase += 2) {
  2186.             float u0 = (float)(phase * 2 - 4.0f) / (float)mGLTextureW;
  2187.             float v0 = 0;
  2188.             float u1 = u0 + u;
  2189.             float v1 = v0 + v;
  2190.  
  2191.             float u2 = (float)(phase * 2 - 2.0f) / (float)mGLTextureW;
  2192.             float u3 = u2 + u;
  2193.  
  2194.             float u4 = (float)(phase * 2 - 0.0f) / (float)mGLTextureW;
  2195.             float u5 = u4 + u;
  2196.  
  2197.             mGL.glColorMask(GL_TRUE, phase==0, phase==0, GL_TRUE);
  2198.  
  2199.             float y0 = y;
  2200.             float y1 = y + (float)h2;
  2201.  
  2202.             mGL.glBegin(GL_QUADS);
  2203.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v1);
  2204.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2, v1);
  2205.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u4, v1);
  2206.                 mGL.glVertex2f(w4, y0);
  2207.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1, v1);
  2208.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v1);
  2209.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u5, v1);
  2210.                 mGL.glVertex2f(w4+w8, y0);
  2211.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1, v0);
  2212.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v0);
  2213.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u5, v0);
  2214.                 mGL.glVertex2f(w4+w8, y1);
  2215.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v0);
  2216.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2, v0);
  2217.                 mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u4, v0);
  2218.                 mGL.glVertex2f(w4, y1);
  2219.             mGL.glEnd();
  2220.             VDASSERT(!mGL.glGetError());
  2221.         }
  2222.  
  2223.         y += h2;
  2224.     }
  2225.  
  2226.     mGL.glActiveTextureARB(GL_TEXTURE2_ARB);
  2227.     mGL.glDisable(GL_TEXTURE_2D);
  2228.     mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  2229.     mGL.glDisable(GL_TEXTURE_2D);
  2230.     mGL.glActiveTextureARB(GL_TEXTURE0_ARB);
  2231.  
  2232.     // readback!
  2233.     VDASSERT(!mGL.glGetError());
  2234.     mGL.glReadBuffer(GL_BACK);
  2235.  
  2236.     if (mGL.EXT_pixel_buffer_object) {
  2237.         mGL.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mGLBuffers[0]);
  2238.         mGL.glReadPixels(0, 0, w >> 2, h, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void *)0);
  2239.         mGL.glReadPixels(w >> 2, 0, w >> 3, h >> 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void *)(w * h));
  2240.         mGL.glReadPixels(w >> 2, h >> 1, w >> 3, h >> 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void *)(w * h * 5 / 4));
  2241.     } else {
  2242.         char *dst = (char *)mGLReadBuffer.data();
  2243.         mGL.glReadPixels(0, 0, w >> 2, h, GL_BGRA_EXT, GL_UNSIGNED_BYTE, dst);
  2244.         mGL.glReadPixels(w >> 2, 0, w >> 3, h >> 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, dst + (w * h));
  2245.         mGL.glReadPixels(w >> 2, h >> 1, w >> 3, h >> 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, dst + (w * h * 5 / 4));
  2246.     }
  2247. }
  2248.  
  2249. void VDCaptureDriverScreen::ConvertToYV12_GL_ATIFS(int w, int h, float u, float v) {
  2250.     // YV12 conversion - NV_register_combiners2 path
  2251.     mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  2252.     mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  2253.     mGL.glActiveTextureARB(GL_TEXTURE3_ARB);
  2254.     mGL.glEnable(GL_TEXTURE_2D);
  2255.     mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  2256.     mGL.glActiveTextureARB(GL_TEXTURE2_ARB);
  2257.     mGL.glEnable(GL_TEXTURE_2D);
  2258.     mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  2259.     mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  2260.     mGL.glEnable(GL_TEXTURE_2D);
  2261.     mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  2262.     mGL.glActiveTextureARB(GL_TEXTURE0_ARB);
  2263.  
  2264.     float y = 0.0f;
  2265.     float w4 = (float)w * 0.25f;
  2266.     {
  2267.         float u0 = -1.5f / (float)mGLTextureW;
  2268.         float v0 = 0;
  2269.         float u1 = u0 + u;
  2270.         float v1 = v0 + v;
  2271.  
  2272.         float u2 = -0.5f / (float)mGLTextureW;
  2273.         float u3 = u2 + u;
  2274.  
  2275.         float u4 = +0.5f / (float)mGLTextureW;
  2276.         float u5 = u4 + u;
  2277.  
  2278.         float u6 = +1.5f / (float)mGLTextureW;
  2279.         float u7 = u6 + u;
  2280.  
  2281.         mGL.glCallList(mGLShaderBase + kVDOpenGLTechIndex_YV12_ATIFS_Y);
  2282.         mGL.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  2283.  
  2284.         float y0 = y;
  2285.         float y1 = y + (float)h;
  2286.  
  2287.         mGL.glColor4f(0.0f, 0.0f, 1.0f, 0.0f);
  2288.  
  2289.         mGL.glBegin(GL_QUADS);
  2290.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v1);
  2291.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2, v1);
  2292.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u4, v1);
  2293.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u6, v1);
  2294.             mGL.glVertex2f(0.0f, y0);
  2295.  
  2296.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1, v1);
  2297.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v1);
  2298.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u5, v1);
  2299.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u7, v1);
  2300.             mGL.glVertex2f(w4, y0);
  2301.  
  2302.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1, v0);
  2303.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v0);
  2304.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u5, v0);
  2305.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u7, v0);
  2306.             mGL.glVertex2f(w4, y1);
  2307.  
  2308.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v0);
  2309.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2, v0);
  2310.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u4, v0);
  2311.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u6, v0);
  2312.             mGL.glVertex2f(0.0f, y1);
  2313.         mGL.glEnd();
  2314.         VDASSERT(!mGL.glGetError());
  2315.     }
  2316.  
  2317.     mGL.glActiveTextureARB(GL_TEXTURE4_ARB);
  2318.     mGL.glEnable(GL_TEXTURE_2D);
  2319.     mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  2320.  
  2321.     y = 0.0f;
  2322.  
  2323.     float w8 = (float)w * 0.125f;
  2324.     int h2 = h >> 1;
  2325.     mGL.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  2326.     for(int cmode=0; cmode<2; ++cmode) {
  2327.         mGL.glCallList(mGLShaderBase + (cmode ? kVDOpenGLTechIndex_YV12_ATIFS_Cb : kVDOpenGLTechIndex_YV12_ATIFS_Cr));
  2328.         float u0 = -4.5f / (float)mGLTextureW;        float u1 = u0 + u;
  2329.         float u2 = -2.5f / (float)mGLTextureW;        float u3 = u2 + u;
  2330.         float u4 = -0.5f / (float)mGLTextureW;        float u5 = u4 + u;
  2331.         float u6 = +0.5f / (float)mGLTextureW;        float u7 = u6 + u;
  2332.         float u8 = +2.5f / (float)mGLTextureW;        float u9 = u8 + u;
  2333.  
  2334.         float v0 = 0;
  2335.         float v1 = v0 + v;
  2336.  
  2337.         float y0 = y;
  2338.         float y1 = y + (float)h2;
  2339.  
  2340.         mGL.glBegin(GL_QUADS);
  2341.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v1);
  2342.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2, v1);
  2343.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u4, v1);
  2344.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u6, v1);
  2345.             mGL.glMultiTexCoord2fARB(GL_TEXTURE4_ARB, u8, v1);
  2346.             mGL.glVertex2f(w4, y0);
  2347.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1, v1);
  2348.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v1);
  2349.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u5, v1);
  2350.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u7, v1);
  2351.             mGL.glMultiTexCoord2fARB(GL_TEXTURE4_ARB, u9, v1);
  2352.             mGL.glVertex2f(w4+w8, y0);
  2353.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1, v0);
  2354.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v0);
  2355.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u5, v0);
  2356.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u7, v0);
  2357.             mGL.glMultiTexCoord2fARB(GL_TEXTURE4_ARB, u9, v0);
  2358.             mGL.glVertex2f(w4+w8, y1);
  2359.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v0);
  2360.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2, v0);
  2361.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u4, v0);
  2362.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u6, v0);
  2363.             mGL.glMultiTexCoord2fARB(GL_TEXTURE4_ARB, u8, v0);
  2364.             mGL.glVertex2f(w4, y1);
  2365.         mGL.glEnd();
  2366.         VDASSERT(!mGL.glGetError());
  2367.  
  2368.         y += h2;
  2369.     }
  2370.  
  2371.     mGL.glActiveTextureARB(GL_TEXTURE4_ARB);
  2372.     mGL.glDisable(GL_TEXTURE_2D);
  2373.     mGL.glActiveTextureARB(GL_TEXTURE3_ARB);
  2374.     mGL.glDisable(GL_TEXTURE_2D);
  2375.     mGL.glActiveTextureARB(GL_TEXTURE2_ARB);
  2376.     mGL.glDisable(GL_TEXTURE_2D);
  2377.     mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  2378.     mGL.glDisable(GL_TEXTURE_2D);
  2379.     mGL.glActiveTextureARB(GL_TEXTURE0_ARB);
  2380.  
  2381.     // readback!
  2382.     VDASSERT(!mGL.glGetError());
  2383.     mGL.glReadBuffer(GL_BACK);
  2384.  
  2385.     if (mGL.EXT_pixel_buffer_object) {
  2386.         mGL.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mGLBuffers[0]);
  2387.         mGL.glReadPixels(0, 0, w >> 2, h, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void *)0);
  2388.         mGL.glReadPixels(w >> 2, 0, w >> 3, h >> 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void *)(w * h));
  2389.         mGL.glReadPixels(w >> 2, h >> 1, w >> 3, h >> 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void *)(w * h * 5 / 4));
  2390.     } else {
  2391.         char *dst = (char *)mGLReadBuffer.data();
  2392.         mGL.glReadPixels(0, 0, w >> 2, h, GL_BGRA_EXT, GL_UNSIGNED_BYTE, dst);
  2393.         mGL.glReadPixels(w >> 2, 0, w >> 3, h >> 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, dst + (w * h));
  2394.         mGL.glReadPixels(w >> 2, h >> 1, w >> 3, h >> 1, GL_BGRA_EXT, GL_UNSIGNED_BYTE, dst + (w * h * 5 / 4));
  2395.     }
  2396. }
  2397.  
  2398. void VDCaptureDriverScreen::ConvertToYUY2_GL_NV1x(int w, int h, float u, float v) {
  2399.     // YUY2 conversion - NV_register_combiners path
  2400.     mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  2401.     mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  2402.     mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  2403.     mGL.glEnable(GL_TEXTURE_2D);
  2404.     mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  2405.     mGL.glActiveTextureARB(GL_TEXTURE0_ARB);
  2406.     mGL.glCallList(mGLShaderBase + kVDOpenGLTechIndex_YUY2_NV1x_Y);
  2407.     VDASSERT(!mGL.glGetError());
  2408.  
  2409.     float y = 0.0f;
  2410.     float w2 = (float)w * 0.5f;
  2411.     {
  2412.         float u0 = -0.5f / (float)mGLTextureW;
  2413.         float v0 = 0;
  2414.         float u1 = u0 + u;
  2415.         float v1 = v0 + v;
  2416.  
  2417.         float u2 = +0.5f / (float)mGLTextureW;
  2418.         float u3 = u2 + u;
  2419.  
  2420.         mGL.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  2421.  
  2422.         float y0 = y;
  2423.         float y1 = y + (float)h;
  2424.  
  2425.         mGL.glColor4f(0.0f, 0.0f, 1.0f, 0.0f);
  2426.         mGL.glBegin(GL_QUADS);
  2427.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v1);    mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2, v1);    mGL.glVertex2f(0.0f, y0);
  2428.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1, v1);    mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v1);    mGL.glVertex2f(w2, y0);
  2429.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u1, v0);    mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u3, v0);    mGL.glVertex2f(w2, y1);
  2430.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v0);    mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u2, v0);    mGL.glVertex2f(0.0f, y1);
  2431.         mGL.glEnd();
  2432.         VDASSERT(!mGL.glGetError());
  2433.     }
  2434.  
  2435.     mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  2436.     mGL.glDisable(GL_TEXTURE_2D);
  2437.     mGL.glActiveTextureARB(GL_TEXTURE0_ARB);
  2438.  
  2439.     {
  2440.         mGL.glCallList(mGLShaderBase + kVDOpenGLTechIndex_YUY2_NV1x_C);
  2441.  
  2442.         float u0 = 0;
  2443.         float v0 = 0;
  2444.         float u1 = u0 + u;
  2445.         float v1 = v0 + v;
  2446.  
  2447.         mGL.glColorMask(GL_FALSE, GL_TRUE, GL_FALSE, GL_TRUE);
  2448.  
  2449.         float y0 = 0;
  2450.         float y1 = (float)h;
  2451.  
  2452.         mGL.glBegin(GL_QUADS);
  2453.             mGL.glTexCoord2f(u0, v1);    mGL.glVertex2f(0, y0);
  2454.             mGL.glTexCoord2f(u1, v1);    mGL.glVertex2f(w2, y0);
  2455.             mGL.glTexCoord2f(u1, v0);    mGL.glVertex2f(w2, y1);
  2456.             mGL.glTexCoord2f(u0, v0);    mGL.glVertex2f(0, y1);
  2457.         mGL.glEnd();
  2458.         VDASSERT(!mGL.glGetError());
  2459.     }
  2460.  
  2461.     VDASSERT(!mGL.glGetError());
  2462.     mGL.glReadBuffer(GL_BACK);
  2463.     if (mGL.EXT_pixel_buffer_object) {
  2464.         mGL.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mGLBuffers[0]);
  2465.         mGL.glReadPixels(0, 0, w >> 1, h, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void *)0);
  2466.     } else {
  2467.         char *dst = (char *)mGLReadBuffer.data();
  2468.         mGL.glReadPixels(0, 0, w >> 1, h, GL_BGRA_EXT, GL_UNSIGNED_BYTE, dst);
  2469.     }
  2470. }
  2471.  
  2472. void VDCaptureDriverScreen::ConvertToYUY2_GL_NV2x_ATIFS(int w, int h, float u, float v, bool atifs) {
  2473.     mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  2474.     mGL.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  2475.     mGL.glActiveTextureARB(GL_TEXTURE3_ARB);
  2476.     mGL.glEnable(GL_TEXTURE_2D);
  2477.     mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  2478.     mGL.glActiveTextureARB(GL_TEXTURE2_ARB);
  2479.     mGL.glEnable(GL_TEXTURE_2D);
  2480.     mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  2481.     mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  2482.     mGL.glEnable(GL_TEXTURE_2D);
  2483.     mGL.glBindTexture(GL_TEXTURE_2D, mGLTextures[0]);
  2484.     mGL.glActiveTextureARB(GL_TEXTURE0_ARB);
  2485.     mGL.glCallList(mGLShaderBase + (atifs ? kVDOpenGLTechIndex_YUY2_ATIFS : kVDOpenGLTechIndex_YUY2_NV2x));
  2486.     VDASSERT(!mGL.glGetError());
  2487.  
  2488.     float y = 0.0f;
  2489.     float w2 = (float)w * 0.5f;
  2490.  
  2491.     mGL.glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
  2492.  
  2493.     {
  2494.         float u0 = -0.5f / (float)mGLTextureW;        // Y1
  2495.         float u1 = +0.5f / (float)mGLTextureW;        // Y2
  2496.         float u2 = -1.0f / (float)mGLTextureW;        // chroma left
  2497.         float u3 =  0.0f / (float)mGLTextureW;        // chroma right
  2498.         float v0 = 0;
  2499.         float v1 = v0 + v;
  2500.  
  2501.         float y0 = y;
  2502.         float y1 = y + (float)h;
  2503.  
  2504.         mGL.glBegin(GL_QUADS);
  2505.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v1);
  2506.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u1, v1);
  2507.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u2, v1);
  2508.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u3, v1);
  2509.             mGL.glVertex2f(0.0f, y0);
  2510.  
  2511.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0+u, v1);
  2512.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u1+u, v1);
  2513.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u2+u, v1);
  2514.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u3+u, v1);
  2515.             mGL.glVertex2f(w2, y0);
  2516.  
  2517.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0+u, v0);
  2518.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u1+u, v0);
  2519.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u2+u, v0);
  2520.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u3+u, v0);
  2521.             mGL.glVertex2f(w2, y1);
  2522.  
  2523.             mGL.glMultiTexCoord2fARB(GL_TEXTURE0_ARB, u0, v0);
  2524.             mGL.glMultiTexCoord2fARB(GL_TEXTURE1_ARB, u1, v0);
  2525.             mGL.glMultiTexCoord2fARB(GL_TEXTURE2_ARB, u2, v0);
  2526.             mGL.glMultiTexCoord2fARB(GL_TEXTURE3_ARB, u3, v0);
  2527.             mGL.glVertex2f(0.0f, y1);
  2528.         mGL.glEnd();
  2529.         VDASSERT(!mGL.glGetError());
  2530.     }
  2531.  
  2532.     mGL.glActiveTextureARB(GL_TEXTURE3_ARB);
  2533.     mGL.glDisable(GL_TEXTURE_2D);
  2534.     mGL.glActiveTextureARB(GL_TEXTURE2_ARB);
  2535.     mGL.glDisable(GL_TEXTURE_2D);
  2536.     mGL.glActiveTextureARB(GL_TEXTURE1_ARB);
  2537.     mGL.glDisable(GL_TEXTURE_2D);
  2538.     mGL.glActiveTextureARB(GL_TEXTURE0_ARB);
  2539.  
  2540.     VDASSERT(!mGL.glGetError());
  2541.     mGL.glReadBuffer(GL_BACK);
  2542.     if (mGL.EXT_pixel_buffer_object) {
  2543.         mGL.glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, mGLBuffers[0]);
  2544.         mGL.glReadPixels(0, 0, w >> 1, h, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void *)0);
  2545.     } else {
  2546.         char *dst = (char *)mGLReadBuffer.data();
  2547.         mGL.glReadPixels(0, 0, w >> 1, h, GL_BGRA_EXT, GL_UNSIGNED_BYTE, dst);
  2548.     }
  2549. }
  2550.  
  2551. GLuint VDCaptureDriverScreen::GetOcclusionQueryPixelCountSafe(GLuint query) {
  2552.     GLint rv;
  2553.     mGL.glFlush();
  2554.  
  2555.     int iters = 1000;
  2556.     for(;;) {
  2557.         mGL.glGetOcclusionQueryivNV(query, GL_PIXEL_COUNT_AVAILABLE_NV, &rv);
  2558.         if (rv)
  2559.             break;
  2560.  
  2561.         if (iters)
  2562.             --iters;
  2563.         else
  2564.             ::Sleep(1);
  2565.     }
  2566.  
  2567.     mGL.glGetOcclusionQueryivNV(query, GL_PIXEL_COUNT_NV, &rv);
  2568.     return rv;
  2569. }
  2570.  
  2571. void VDCaptureDriverScreen::LoadSettings() {
  2572.     VDRegistryAppKey key("Capture\\Screen capture");
  2573.  
  2574.     mbTrackCursor = key.getBool("Track cursor", mbTrackCursor);
  2575.     mbTrackActiveWindow = key.getBool("Track active window", mbTrackActiveWindow);
  2576.     mbTrackActiveWindowClient = key.getBool("Track active window client", mbTrackActiveWindowClient);
  2577.     mbDrawMousePointer = key.getBool("Draw mouse pointer", mbDrawMousePointer);
  2578.     mbRescaleImage = key.getBool("Rescale image", mbRescaleImage);
  2579.     mbOpenGLMode = key.getBool("OpenGL mode", mbOpenGLMode);
  2580.     mbRemoveDuplicates = key.getBool("Remove duplicates", mbRemoveDuplicates);
  2581.     mRescaleW = key.getInt("Rescale width", mRescaleW);
  2582.     mRescaleH = key.getInt("Rescale height", mRescaleH);
  2583.  
  2584.     if (mRescaleW < 1)
  2585.         mRescaleW = 1;
  2586.  
  2587.     if (mRescaleW > 32768)
  2588.         mRescaleW = 32768;
  2589.  
  2590.     if (mRescaleH < 1)
  2591.         mRescaleH = 1;
  2592.  
  2593.     if (mRescaleH > 32768)
  2594.         mRescaleH = 32768;
  2595.  
  2596.     mTrackOffsetX = key.getInt("Position X", mTrackOffsetX);
  2597.     mTrackOffsetY = key.getInt("Position Y", mTrackOffsetY);
  2598. }
  2599.  
  2600. void VDCaptureDriverScreen::SaveSettings() {
  2601.     VDRegistryAppKey key("Capture\\Screen capture");
  2602.  
  2603.     key.setBool("Track cursor", mbTrackCursor);
  2604.     key.setBool("Track active window", mbTrackActiveWindow);
  2605.     key.setBool("Track active window client", mbTrackActiveWindowClient);
  2606.     key.setBool("Draw mouse pointer", mbDrawMousePointer);
  2607.     key.setBool("Rescale image", mbRescaleImage);
  2608.     key.setBool("OpenGL mode", mbOpenGLMode);
  2609.     key.setBool("Remove duplicates", mbRemoveDuplicates);
  2610.     key.setInt("Rescale width", mRescaleW);
  2611.     key.setInt("Rescale height", mRescaleH);
  2612.     key.setInt("Position X", mTrackOffsetX);
  2613.     key.setInt("Position Y", mTrackOffsetY);
  2614. }
  2615.  
  2616. void VDCaptureDriverScreen::TimerCallback() {
  2617.     mbCaptureFramePending = true;
  2618.     PostMessage(mhwnd, WM_APP+18, 0, 0);
  2619. }
  2620.  
  2621. LRESULT CALLBACK VDCaptureDriverScreen::StaticWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  2622.     switch(msg) {
  2623.         case WM_NCCREATE:
  2624.             SetWindowLongPtr(hwnd, 0, (LONG_PTR)((LPCREATESTRUCT)lParam)->lpCreateParams);
  2625.             break;
  2626.         case WM_SIZE:
  2627.             {
  2628.                 VDCaptureDriverScreen *pThis = (VDCaptureDriverScreen *)GetWindowLongPtr(hwnd, 0);
  2629.                 if (pThis->mhwndGLDraw)
  2630.                     SetWindowPos(pThis->mhwndGLDraw, NULL, 0, 0, LOWORD(lParam), HIWORD(lParam), SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  2631.             }
  2632.             break;
  2633.         case MM_WIM_DATA:
  2634.             {
  2635.                 VDCaptureDriverScreen *pThis = (VDCaptureDriverScreen *)GetWindowLongPtr(hwnd, 0);
  2636.  
  2637.                 if (pThis->mpCB) {
  2638.                     WAVEHDR& hdr = *(WAVEHDR *)lParam;
  2639.  
  2640.                     if (pThis->mbCapturing) {
  2641.                         if (pThis->mbAudioCaptureEnabled) {
  2642.                             try {
  2643.                                 pThis->mpCB->CapProcessData(1, hdr.lpData, hdr.dwBytesRecorded, -1, false, pThis->ComputeGlobalTime());
  2644.                             } catch(MyError& e) {
  2645.                                 pThis->mCaptureError.TransferFrom(e);
  2646.                                 pThis->CaptureAbort();
  2647.                             }
  2648.  
  2649.                             waveInAddBuffer(pThis->mhWaveIn, &hdr, sizeof(WAVEHDR));
  2650.                         }
  2651.                     } else if (pThis->mbAudioAnalysisActive) {
  2652.                         // For some reason this is sometimes called after reset. Don't know why yet.
  2653.                         if (hdr.dwBytesRecorded) {
  2654.                             try {
  2655.                                 pThis->mpCB->CapProcessData(-2, hdr.lpData, hdr.dwBytesRecorded, -1, false, 0);
  2656.                             } catch(const MyError&) {
  2657.                                 // eat the error
  2658.                             }
  2659.                         }
  2660.  
  2661.                         waveInAddBuffer(pThis->mhWaveIn, &hdr, sizeof(WAVEHDR));
  2662.                     }
  2663.                 }
  2664.             }
  2665.             return 0;
  2666.         case WM_APP+16:
  2667.             {
  2668.                 VDCaptureDriverScreen *pThis = (VDCaptureDriverScreen *)GetWindowLongPtr(hwnd, 0);
  2669.                 pThis->SyncCaptureStop();
  2670.             }
  2671.             return 0;
  2672.         case WM_APP+17:
  2673.             {
  2674.                 VDCaptureDriverScreen *pThis = (VDCaptureDriverScreen *)GetWindowLongPtr(hwnd, 0);
  2675.                 pThis->SyncCaptureAbort();
  2676.             }
  2677.             return 0;
  2678.         case WM_APP+18:
  2679.             {
  2680.                 VDCaptureDriverScreen *pThis = (VDCaptureDriverScreen *)GetWindowLongPtr(hwnd, 0);
  2681.                 if (pThis->mbCaptureFramePending && pThis->mbCapturing) {
  2682.                     pThis->mbCaptureFramePending = false;
  2683.                     pThis->DoFrame();
  2684.                 }
  2685.             }
  2686.             return 0;
  2687.         case WM_TIMER:
  2688.             {
  2689.                 VDCaptureDriverScreen *pThis = (VDCaptureDriverScreen *)GetWindowLongPtr(hwnd, 0);
  2690.                 if (!pThis->mbCapturing)
  2691.                     pThis->DoFrame();
  2692.             }
  2693.             return 0;
  2694.     }
  2695.  
  2696.     return DefWindowProc(hwnd, msg, wParam, lParam);
  2697. }
  2698.  
  2699. LRESULT CALLBACK VDCaptureDriverScreen::StaticWndProcGL(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
  2700.     return DefWindowProc(hwnd, msg, wParam, lParam);
  2701. }
  2702.  
  2703. INT_PTR CALLBACK VDCaptureDriverScreen::VideoSourceDlgProc(HWND hdlg, UINT msg, WPARAM wParam, LPARAM lParam) {
  2704.     VDCaptureDriverScreen *pThis = (VDCaptureDriverScreen *)GetWindowLongPtr(hdlg, DWLP_USER);
  2705.  
  2706.     switch(msg) {
  2707.     case WM_INITDIALOG:
  2708.         SetWindowLongPtr(hdlg, DWLP_USER, (LONG_PTR)lParam);
  2709.         pThis = (VDCaptureDriverScreen *)lParam;
  2710.         CheckDlgButton(hdlg, IDC_POSITION_TRACKMOUSE, pThis->mbTrackCursor);
  2711.         CheckDlgButton(hdlg, IDC_POSITION_FIXED, !pThis->mbTrackCursor);
  2712.  
  2713.         CheckDlgButton(hdlg, IDC_PANNING_DESKTOP, !pThis->mbTrackActiveWindow);
  2714.         CheckDlgButton(hdlg, IDC_PANNING_ACTIVEWINDOW, pThis->mbTrackActiveWindow && !pThis->mbTrackActiveWindowClient);
  2715.         CheckDlgButton(hdlg, IDC_PANNING_ACTIVECLIENT, pThis->mbTrackActiveWindow && pThis->mbTrackActiveWindowClient);
  2716.  
  2717.         CheckDlgButton(hdlg, IDC_DRAW_CURSOR, pThis->mbDrawMousePointer);
  2718.         CheckDlgButton(hdlg, IDC_RESCALE_IMAGE, pThis->mbRescaleImage);
  2719.         CheckDlgButton(hdlg, IDC_USE_OPENGL, pThis->mbOpenGLMode);
  2720.         CheckDlgButton(hdlg, IDC_REMOVE_DUPES, pThis->mbRemoveDuplicates);
  2721.         SetDlgItemInt(hdlg, IDC_WIDTH, pThis->mRescaleW, FALSE);
  2722.         SetDlgItemInt(hdlg, IDC_HEIGHT, pThis->mRescaleH, FALSE);
  2723.         SetDlgItemInt(hdlg, IDC_POSITION_X, pThis->mTrackOffsetX, TRUE);
  2724.         SetDlgItemInt(hdlg, IDC_POSITION_Y, pThis->mTrackOffsetY, TRUE);
  2725. reenable:
  2726.         {
  2727.             bool enableOpenGL = !!IsDlgButtonChecked(hdlg, IDC_USE_OPENGL);
  2728.             EnableWindow(GetDlgItem(hdlg, IDC_STATIC_OPENGL), enableOpenGL);
  2729.             EnableWindow(GetDlgItem(hdlg, IDC_RESCALE_IMAGE), enableOpenGL);
  2730.             EnableWindow(GetDlgItem(hdlg, IDC_REMOVE_DUPES), enableOpenGL);
  2731.  
  2732.             bool rescale = enableOpenGL && IsDlgButtonChecked(hdlg, IDC_RESCALE_IMAGE);
  2733.             EnableWindow(GetDlgItem(hdlg, IDC_STATIC_WIDTH), rescale);
  2734.             EnableWindow(GetDlgItem(hdlg, IDC_STATIC_HEIGHT), rescale);
  2735.             EnableWindow(GetDlgItem(hdlg, IDC_WIDTH), rescale);
  2736.             EnableWindow(GetDlgItem(hdlg, IDC_HEIGHT), rescale);
  2737.         }
  2738.         return TRUE;
  2739.     case WM_COMMAND:
  2740.         switch(LOWORD(wParam)) {
  2741.         case IDOK:
  2742.             {
  2743.                 BOOL success;
  2744.                 UINT w = GetDlgItemInt(hdlg, IDC_WIDTH, &success, FALSE);
  2745.                 if (w <= 0 || !success) {
  2746.                     MessageBeep(MB_ICONEXCLAMATION);
  2747.                     SetFocus(GetDlgItem(hdlg, IDC_WIDTH));
  2748.                     return TRUE;
  2749.                 }
  2750.                 UINT h = GetDlgItemInt(hdlg, IDC_HEIGHT, &success, FALSE);
  2751.                 if (h <= 0 || !success) {
  2752.                     MessageBeep(MB_ICONEXCLAMATION);
  2753.                     SetFocus(GetDlgItem(hdlg, IDC_HEIGHT));
  2754.                     return TRUE;
  2755.                 }
  2756.  
  2757.                 if (!IsDlgButtonChecked(hdlg, IDC_POSITION_TRACKMOUSE)) {
  2758.                     int x = GetDlgItemInt(hdlg, IDC_POSITION_X, &success, TRUE);
  2759.                     if (!success) {
  2760.                         MessageBeep(MB_ICONEXCLAMATION);
  2761.                         SetFocus(GetDlgItem(hdlg, IDC_POSITION_X));
  2762.                         return TRUE;
  2763.                     }
  2764.  
  2765.                     int y = GetDlgItemInt(hdlg, IDC_POSITION_Y, &success, TRUE);
  2766.                     if (!success) {
  2767.                         MessageBeep(MB_ICONEXCLAMATION);
  2768.                         SetFocus(GetDlgItem(hdlg, IDC_POSITION_X));
  2769.                         return TRUE;
  2770.                     }
  2771.  
  2772.                     pThis->mTrackOffsetX = x;
  2773.                     pThis->mTrackOffsetY = y;
  2774.                     pThis->mbTrackCursor = false;
  2775.                 } else {
  2776.                     pThis->mbTrackCursor = true;
  2777.                 }
  2778.  
  2779.                 pThis->mRescaleW = w;
  2780.                 pThis->mRescaleH = h;
  2781.  
  2782.                 if (IsDlgButtonChecked(hdlg, IDC_PANNING_DESKTOP)) {
  2783.                     pThis->mbTrackActiveWindow = false;
  2784.                     pThis->mbTrackActiveWindowClient = false;
  2785.                 } else if (IsDlgButtonChecked(hdlg, IDC_PANNING_ACTIVEWINDOW)) {
  2786.                     pThis->mbTrackActiveWindow = true;
  2787.                     pThis->mbTrackActiveWindowClient = false;
  2788.                 } else if (IsDlgButtonChecked(hdlg, IDC_PANNING_ACTIVECLIENT)) {
  2789.                     pThis->mbTrackActiveWindow = true;
  2790.                     pThis->mbTrackActiveWindowClient = true;
  2791.                 }
  2792.  
  2793.                 pThis->mbDrawMousePointer = !!IsDlgButtonChecked(hdlg, IDC_DRAW_CURSOR);
  2794.                 pThis->mbRescaleImage = !!IsDlgButtonChecked(hdlg, IDC_RESCALE_IMAGE);
  2795.                 pThis->mbOpenGLMode = !!IsDlgButtonChecked(hdlg, IDC_USE_OPENGL);
  2796.                 pThis->mbRemoveDuplicates = !!IsDlgButtonChecked(hdlg, IDC_REMOVE_DUPES);
  2797.             }
  2798.             EndDialog(hdlg, TRUE);
  2799.             return TRUE;
  2800.         case IDCANCEL:
  2801.             EndDialog(hdlg, FALSE);
  2802.             return TRUE;
  2803.         case IDC_USE_OPENGL:
  2804.         case IDC_RESCALE_IMAGE:
  2805.             if (HIWORD(wParam) == BN_CLICKED)
  2806.                 goto reenable;
  2807.             break;
  2808.         }
  2809.         break;
  2810.     }
  2811.     return FALSE;
  2812. }
  2813.  
  2814. ///////////////////////////////////////////////////////////////////////////
  2815.  
  2816. class VDCaptureSystemScreen : public IVDCaptureSystem {
  2817. public:
  2818.     VDCaptureSystemScreen();
  2819.     ~VDCaptureSystemScreen();
  2820.  
  2821.     void EnumerateDrivers();
  2822.  
  2823.     int GetDeviceCount();
  2824.     const wchar_t *GetDeviceName(int index);
  2825.  
  2826.     IVDCaptureDriver *CreateDriver(int deviceIndex);
  2827. };
  2828.  
  2829. IVDCaptureSystem *VDCreateCaptureSystemScreen() {
  2830.     return new VDCaptureSystemScreen;
  2831. }
  2832.  
  2833. VDCaptureSystemScreen::VDCaptureSystemScreen()
  2834. {
  2835. }
  2836.  
  2837. VDCaptureSystemScreen::~VDCaptureSystemScreen() {
  2838. }
  2839.  
  2840. void VDCaptureSystemScreen::EnumerateDrivers() {
  2841. }
  2842.  
  2843. int VDCaptureSystemScreen::GetDeviceCount() {
  2844.     return 1;
  2845. }
  2846.  
  2847. const wchar_t *VDCaptureSystemScreen::GetDeviceName(int index) {
  2848.     return !index ? L"Screen capture" : NULL;
  2849. }
  2850.  
  2851. IVDCaptureDriver *VDCaptureSystemScreen::CreateDriver(int index) {
  2852.     if (index)
  2853.         return NULL;
  2854.  
  2855.     return new VDCaptureDriverScreen();
  2856. }
  2857.