//------------------------------------------------------------------------------ // File: WinUtil.h // // Desc: DirectShow base classes - defines generic handler classes. // //@@BEGIN_MSINTERNAL // // December 1995 // //@@END_MSINTERNAL // Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved. //------------------------------------------------------------------------------ // Make sure that you call PrepareWindow to initialise the window after // the object has been constructed. It is a separate method so that // derived classes can override useful methods like MessageLoop. Also // any derived class must call DoneWithWindow in its destructor. If it // doesn't a message may be retrieved and call a derived class member // function while a thread is executing the base class destructor code #ifndef __WINUTIL__ #define __WINUTIL__ const int DEFWIDTH = 320; // Initial window width const int DEFHEIGHT = 240; // Initial window height const int CAPTION = 256; // Maximum length of caption const int TIMELENGTH = 50; // Maximum length of times const int PROFILESTR = 128; // Normal profile string const WORD PALVERSION = 0x300; // GDI palette version const LONG PALETTE_VERSION = (LONG) 1; // Initial palette version const COLORREF VIDEO_COLOUR = 0; // Defaults to black background const HANDLE hMEMORY = (HANDLE) (-1); // Says to open as memory file #define WIDTH(x) ((*(x)).right - (*(x)).left) #define HEIGHT(x) ((*(x)).bottom - (*(x)).top) #define SHOWSTAGE TEXT("WM_SHOWSTAGE") #define SHOWSTAGETOP TEXT("WM_SHOWSTAGETOP") #define REALIZEPALETTE TEXT("WM_REALIZEPALETTE") class AM_NOVTABLE CBaseWindow { protected: HINSTANCE m_hInstance; // Global module instance handle HWND m_hwnd; // Handle for our window HDC m_hdc; // Device context for the window LONG m_Width; // Client window width LONG m_Height; // Client window height BOOL m_bActivated; // Has the window been activated LPTSTR m_pClassName; // Static string holding class name DWORD m_ClassStyles; // Passed in to our constructor DWORD m_WindowStyles; // Likewise the initial window styles DWORD m_WindowStylesEx; // And the extended window styles UINT m_ShowStageMessage; // Have the window shown with focus UINT m_ShowStageTop; // Makes the window WS_EX_TOPMOST UINT m_RealizePalette; // Makes us realize our new palette HDC m_MemoryDC; // Used for fast BitBlt operations HPALETTE m_hPalette; // Handle to any palette we may have BYTE m_bNoRealize; // Don't realize palette now BYTE m_bBackground; // Should we realise in background BYTE m_bRealizing; // already realizing the palette CCritSec m_WindowLock; // Serialise window object access BOOL m_bDoGetDC; // Should this window get a DC bool m_bDoPostToDestroy; // Use PostMessage to destroy CCritSec m_PaletteLock; // This lock protects m_hPalette. // It should be held anytime the // program use the value of m_hPalette. // Maps windows message procedure into C++ methods friend LRESULT CALLBACK WndProc(HWND hwnd, // Window handle UINT uMsg, // Message ID WPARAM wParam, // First parameter LPARAM lParam); // Other parameter virtual LRESULT OnPaletteChange(HWND hwnd, UINT Message); public: CBaseWindow(BOOL bDoGetDC = TRUE, bool bPostToDestroy = false); #ifdef DEBUG virtual ~CBaseWindow(); #endif virtual HRESULT DoneWithWindow(); virtual HRESULT PrepareWindow(); virtual HRESULT InactivateWindow(); virtual HRESULT ActivateWindow(); virtual BOOL OnSize(LONG Width, LONG Height); virtual BOOL OnClose(); virtual RECT GetDefaultRect(); virtual HRESULT UninitialiseWindow(); virtual HRESULT InitialiseWindow(HWND hwnd); HRESULT CompleteConnect(); HRESULT DoCreateWindow(); HRESULT PerformanceAlignWindow(); HRESULT DoShowWindow(LONG ShowCmd); void PaintWindow(BOOL bErase); void DoSetWindowForeground(BOOL bFocus); virtual HRESULT SetPalette(HPALETTE hPalette); void SetRealize(BOOL bRealize) { m_bNoRealize = !bRealize; } // Jump over to the window thread to set the current palette HRESULT SetPalette(); void UnsetPalette(void); virtual HRESULT DoRealisePalette(BOOL bForceBackground = FALSE); void LockPaletteLock(); void UnlockPaletteLock(); virtual BOOL PossiblyEatMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) { return FALSE; }; // Access our window information bool WindowExists(); LONG GetWindowWidth(); LONG GetWindowHeight(); HWND GetWindowHWND(); HDC GetMemoryHDC(); HDC GetWindowHDC(); #ifdef DEBUG HPALETTE GetPalette(); #endif // DEBUG // This is the window procedure the derived object should override virtual LRESULT OnReceiveMessage(HWND hwnd, // Window handle UINT uMsg, // Message ID WPARAM wParam, // First parameter LPARAM lParam); // Other parameter // Must be overriden to return class and window styles virtual LPTSTR GetClassWindowStyles( DWORD *pClassStyles, // Class styles DWORD *pWindowStyles, // Window styles DWORD *pWindowStylesEx) PURE; // Extended styles }; // This helper class is entirely subservient to the owning CBaseWindow object // All this object does is to split out the actual drawing operation from the // main object (because it was becoming too large). We have a number of entry // points to set things like the draw device contexts, to implement the actual // drawing and to set the destination rectangle in the client window. We have // no critical section locking in this class because we are used exclusively // by the owning window object which looks after serialising calls into us // If you want to use this class make sure you call NotifyAllocator once the // allocate has been agreed, also call NotifyMediaType with a pointer to a // NON stack based CMediaType once that has been set (we keep a pointer to // the original rather than taking a copy). When the palette changes call // IncrementPaletteVersion (easiest thing to do is to also call this method // in the SetMediaType method most filters implement). Finally before you // start rendering anything call SetDrawContext so that we can get the HDCs // for drawing from the CBaseWindow object we are given during construction class CDrawImage { protected: CBaseWindow *m_pBaseWindow; // Owning video window object CRefTime m_StartSample; // Start time for the current sample CRefTime m_EndSample; // And likewise it's end sample time HDC m_hdc; // Main window device context HDC m_MemoryDC; // Offscreen draw device context RECT m_TargetRect; // Target destination rectangle RECT m_SourceRect; // Source image rectangle BOOL m_bStretch; // Do we have to stretch the images BOOL m_bUsingImageAllocator; // Are the samples shared DIBSECTIONs CMediaType *m_pMediaType; // Pointer to the current format int m_perfidRenderTime; // Time taken to render an image LONG m_PaletteVersion; // Current palette version cookie // Draw the video images in the window void SlowRender(IMediaSample *pMediaSample); void FastRender(IMediaSample *pMediaSample); void DisplaySampleTimes(IMediaSample *pSample); void UpdateColourTable(HDC hdc,BITMAPINFOHEADER *pbmi); void SetStretchMode(); public: // Used to control the image drawing CDrawImage(CBaseWindow *pBaseWindow); BOOL DrawImage(IMediaSample *pMediaSample); BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample, LPRECT lprcSrc, LPRECT lprcDst); void SetDrawContext(); void SetTargetRect(RECT *pTargetRect); void SetSourceRect(RECT *pSourceRect); void GetTargetRect(RECT *pTargetRect); void GetSourceRect(RECT *pSourceRect); virtual RECT ScaleSourceRect(const RECT *pSource); // Handle updating palettes as they change LONG GetPaletteVersion(); void ResetPaletteVersion(); void IncrementPaletteVersion(); // Tell us media types and allocator assignments void NotifyAllocator(BOOL bUsingImageAllocator); void NotifyMediaType(CMediaType *pMediaType); BOOL UsingImageAllocator(); // Called when we are about to draw an image void NotifyStartDraw() { MSR_START(m_perfidRenderTime); }; // Called when we complete an image rendering void NotifyEndDraw() { MSR_STOP(m_perfidRenderTime); }; }; // This is the structure used to keep information about each GDI DIB. All the // samples we create from our allocator will have a DIBSECTION allocated to // them. When we receive the sample we know we can BitBlt straight to an HDC typedef struct tagDIBDATA { LONG PaletteVersion; // Current palette version in use DIBSECTION DibSection; // Details of DIB section allocated HBITMAP hBitmap; // Handle to bitmap for drawing HANDLE hMapping; // Handle to shared memory block BYTE *pBase; // Pointer to base memory address } DIBDATA; // This class inherits from CMediaSample and uses all of it's methods but it // overrides the constructor to initialise itself with the DIBDATA structure // When we come to render an IMediaSample we will know if we are using our own // allocator, and if we are, we can cast the IMediaSample to a pointer to one // of these are retrieve the DIB section information and hence the HBITMAP class CImageSample : public CMediaSample { protected: DIBDATA m_DibData; // Information about the DIBSECTION BOOL m_bInit; // Is the DIB information setup public: // Constructor CImageSample(CBaseAllocator *pAllocator, TCHAR *pName, HRESULT *phr, LPBYTE pBuffer, LONG length); // Maintain the DIB/DirectDraw state void SetDIBData(DIBDATA *pDibData); DIBDATA *GetDIBData(); }; // This is an allocator based on the abstract CBaseAllocator base class that // allocates sample buffers in shared memory. The number and size of these // are determined when the output pin calls Prepare on us. The shared memory // blocks are used in subsequent calls to GDI CreateDIBSection, once that // has been done the output pin can fill the buffers with data which will // then be handed to GDI through BitBlt calls and thereby remove one copy class CImageAllocator : public CBaseAllocator { protected: CBaseFilter *m_pFilter; // Delegate reference counts to CMediaType *m_pMediaType; // Pointer to the current format // Used to create and delete samples HRESULT Alloc(); void Free(); // Manage the shared DIBSECTION and DCI/DirectDraw buffers HRESULT CreateDIB(LONG InSize,DIBDATA &DibData); STDMETHODIMP CheckSizes(ALLOCATOR_PROPERTIES *pRequest); virtual CImageSample *CreateImageSample(LPBYTE pData,LONG Length); public: // Constructor and destructor CImageAllocator(CBaseFilter *pFilter,TCHAR *pName,HRESULT *phr); #ifdef DEBUG ~CImageAllocator(); #endif STDMETHODIMP_(ULONG) NonDelegatingAddRef(); STDMETHODIMP_(ULONG) NonDelegatingRelease(); void NotifyMediaType(CMediaType *pMediaType); // Agree the number of buffers to be used and their size STDMETHODIMP SetProperties( ALLOCATOR_PROPERTIES *pRequest, ALLOCATOR_PROPERTIES *pActual); }; // This class is a fairly specialised helper class for image renderers that // have to create and manage palettes. The CBaseWindow class looks after // realising palettes once they have been installed. This class can be used // to create the palette handles from a media format (which must contain a // VIDEOINFO structure in the format block). We try to make the palette an // identity palette to maximise performance and also only change palettes // if actually required to (we compare palette colours before updating). // All the methods are virtual so that they can be overriden if so required class CImagePalette { protected: CBaseWindow *m_pBaseWindow; // Window to realise palette in CBaseFilter *m_pFilter; // Media filter to send events CDrawImage *m_pDrawImage; // Object who will be drawing HPALETTE m_hPalette; // The palette handle we own public: CImagePalette(CBaseFilter *pBaseFilter, CBaseWindow *pBaseWindow, CDrawImage *pDrawImage); #ifdef DEBUG virtual ~CImagePalette(); #endif static HPALETTE MakePalette(const VIDEOINFOHEADER *pVideoInfo, LPSTR szDevice); HRESULT RemovePalette(); static HRESULT MakeIdentityPalette(PALETTEENTRY *pEntry,INT iColours, LPSTR szDevice); HRESULT CopyPalette(const CMediaType *pSrc,CMediaType *pDest); BOOL ShouldUpdate(const VIDEOINFOHEADER *pNewInfo,const VIDEOINFOHEADER *pOldInfo); HRESULT PreparePalette(const CMediaType *pmtNew,const CMediaType *pmtOld,LPSTR szDevice); BOOL DrawVideoImageHere(HDC hdc, IMediaSample *pMediaSample, LPRECT lprcSrc, LPRECT lprcDst) { return m_pDrawImage->DrawVideoImageHere(hdc, pMediaSample, lprcSrc,lprcDst); } }; // Another helper class really for video based renderers. Most such renderers // need to know what the display format is to some degree or another. This // class initialises itself with the display format. The format can be asked // for through GetDisplayFormat and various other accessor functions. If a // filter detects a display format change (perhaps it gets a WM_DEVMODECHANGE // message then it can call RefreshDisplayType to reset that format). Also // many video renderers will want to check formats as they are proposed by // source filters. This class provides methods to check formats and only // accept those video formats that can be efficiently drawn using GDI calls class CImageDisplay : public CCritSec { protected: // This holds the display format; biSize should not be too big, so we can // safely use the VIDEOINFO structure VIDEOINFO m_Display; static DWORD CountSetBits(const DWORD Field); static DWORD CountPrefixBits(const DWORD Field); static BOOL CheckBitFields(const VIDEOINFO *pInput); public: // Constructor and destructor CImageDisplay(); // Used to manage BITMAPINFOHEADERs and the display format const VIDEOINFO *GetDisplayFormat(); HRESULT RefreshDisplayType(LPSTR szDeviceName); static BOOL CheckHeaderValidity(const VIDEOINFO *pInput); static BOOL CheckPaletteHeader(const VIDEOINFO *pInput); BOOL IsPalettised(); WORD GetDisplayDepth(); // Provide simple video format type checking HRESULT CheckMediaType(const CMediaType *pmtIn); HRESULT CheckVideoType(const VIDEOINFO *pInput); HRESULT UpdateFormat(VIDEOINFO *pVideoInfo); const DWORD *GetBitMasks(const VIDEOINFO *pVideoInfo); BOOL GetColourMask(DWORD *pMaskRed, DWORD *pMaskGreen, DWORD *pMaskBlue); }; // Convert a FORMAT_VideoInfo to FORMAT_VideoInfo2 STDAPI ConvertVideoInfoToVideoInfo2(AM_MEDIA_TYPE *pmt); #endif // __WINUTIL__