527 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			527 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //------------------------------------------------------------------------------
 | |
| // File: WXUtil.h
 | |
| //
 | |
| // Desc: DirectShow base classes - defines helper classes and functions for
 | |
| //       building multimedia filters.
 | |
| //
 | |
| // Copyright (c) 1992-2001 Microsoft Corporation.  All rights reserved.
 | |
| //------------------------------------------------------------------------------
 | |
| 
 | |
| 
 | |
| #ifndef __WXUTIL__
 | |
| #define __WXUTIL__
 | |
| 
 | |
| // eliminate spurious "statement has no effect" warnings.
 | |
| #pragma warning(disable: 4705)
 | |
| 
 | |
| // wrapper for whatever critical section we have
 | |
| class CCritSec {
 | |
| 
 | |
|     // make copy constructor and assignment operator inaccessible
 | |
| 
 | |
|     CCritSec(const CCritSec &refCritSec);
 | |
|     CCritSec &operator=(const CCritSec &refCritSec);
 | |
| 
 | |
|     CRITICAL_SECTION m_CritSec;
 | |
| 
 | |
| #ifdef DEBUG
 | |
| public:
 | |
|     DWORD   m_currentOwner;
 | |
|     DWORD   m_lockCount;
 | |
|     BOOL    m_fTrace;        // Trace this one
 | |
| public:
 | |
|     CCritSec();
 | |
|     ~CCritSec();
 | |
|     void Lock();
 | |
|     void Unlock();
 | |
| #else
 | |
| 
 | |
| public:
 | |
|     CCritSec() {
 | |
|         InitializeCriticalSection(&m_CritSec);
 | |
|     };
 | |
| 
 | |
|     ~CCritSec() {
 | |
|         DeleteCriticalSection(&m_CritSec);
 | |
|     };
 | |
| 
 | |
|     void Lock() {
 | |
|         EnterCriticalSection(&m_CritSec);
 | |
|     };
 | |
| 
 | |
|     void Unlock() {
 | |
|         LeaveCriticalSection(&m_CritSec);
 | |
|     };
 | |
| #endif
 | |
| };
 | |
| 
 | |
| //
 | |
| // To make deadlocks easier to track it is useful to insert in the
 | |
| // code an assertion that says whether we own a critical section or
 | |
| // not.  We make the routines that do the checking globals to avoid
 | |
| // having different numbers of member functions in the debug and
 | |
| // retail class implementations of CCritSec.  In addition we provide
 | |
| // a routine that allows usage of specific critical sections to be
 | |
| // traced.  This is NOT on by default - there are far too many.
 | |
| //
 | |
| 
 | |
| #ifdef DEBUG
 | |
|     BOOL WINAPI CritCheckIn(CCritSec * pcCrit);
 | |
|     BOOL WINAPI CritCheckIn(const CCritSec * pcCrit);
 | |
|     BOOL WINAPI CritCheckOut(CCritSec * pcCrit);
 | |
|     BOOL WINAPI CritCheckOut(const CCritSec * pcCrit);
 | |
|     void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace);
 | |
| #else
 | |
|     #define CritCheckIn(x) TRUE
 | |
|     #define CritCheckOut(x) TRUE
 | |
|     #define DbgLockTrace(pc, fT)
 | |
| #endif
 | |
| 
 | |
| 
 | |
| // locks a critical section, and unlocks it automatically
 | |
| // when the lock goes out of scope
 | |
| class CAutoLock {
 | |
| 
 | |
|     // make copy constructor and assignment operator inaccessible
 | |
| 
 | |
|     CAutoLock(const CAutoLock &refAutoLock);
 | |
|     CAutoLock &operator=(const CAutoLock &refAutoLock);
 | |
| 
 | |
| protected:
 | |
|     CCritSec * m_pLock;
 | |
| 
 | |
| public:
 | |
|     CAutoLock(CCritSec * plock)
 | |
|     {
 | |
|         m_pLock = plock;
 | |
|         m_pLock->Lock();
 | |
|     };
 | |
| 
 | |
|     ~CAutoLock() {
 | |
|         m_pLock->Unlock();
 | |
|     };
 | |
| };
 | |
| 
 | |
| 
 | |
| 
 | |
| // wrapper for event objects
 | |
| class CAMEvent
 | |
| {
 | |
| 
 | |
|     // make copy constructor and assignment operator inaccessible
 | |
| 
 | |
|     CAMEvent(const CAMEvent &refEvent);
 | |
|     CAMEvent &operator=(const CAMEvent &refEvent);
 | |
| 
 | |
| protected:
 | |
|     HANDLE m_hEvent;
 | |
| public:
 | |
|     CAMEvent(BOOL fManualReset = FALSE, __inout_opt HRESULT *phr = NULL);
 | |
|     CAMEvent(__inout_opt HRESULT *phr);
 | |
|     ~CAMEvent();
 | |
| 
 | |
|     // Cast to HANDLE - we don't support this as an lvalue
 | |
|     operator HANDLE () const { return m_hEvent; };
 | |
| 
 | |
|     void Set() {EXECUTE_ASSERT(SetEvent(m_hEvent));};
 | |
|     BOOL Wait(DWORD dwTimeout = INFINITE) {
 | |
| 	return (WaitForSingleObject(m_hEvent, dwTimeout) == WAIT_OBJECT_0);
 | |
|     };
 | |
|     void Reset() { ResetEvent(m_hEvent); };
 | |
|     BOOL Check() { return Wait(0); };
 | |
| };
 | |
| 
 | |
| 
 | |
| // wrapper for event objects that do message processing
 | |
| // This adds ONE method to the CAMEvent object to allow sent
 | |
| // messages to be processed while waiting
 | |
| 
 | |
| class CAMMsgEvent : public CAMEvent
 | |
| {
 | |
| 
 | |
| public:
 | |
| 
 | |
|     CAMMsgEvent(__inout_opt HRESULT *phr = NULL);
 | |
| 
 | |
|     // Allow SEND messages to be processed while waiting
 | |
|     BOOL WaitMsg(DWORD dwTimeout = INFINITE);
 | |
| };
 | |
| 
 | |
| // old name supported for the time being
 | |
| #define CTimeoutEvent CAMEvent
 | |
| 
 | |
| // support for a worker thread
 | |
| 
 | |
| #ifdef AM_NOVTABLE
 | |
| // simple thread class supports creation of worker thread, synchronization
 | |
| // and communication. Can be derived to simplify parameter passing
 | |
| class AM_NOVTABLE CAMThread {
 | |
| 
 | |
|     // make copy constructor and assignment operator inaccessible
 | |
| 
 | |
|     CAMThread(const CAMThread &refThread);
 | |
|     CAMThread &operator=(const CAMThread &refThread);
 | |
| 
 | |
|     CAMEvent m_EventSend;
 | |
|     CAMEvent m_EventComplete;
 | |
| 
 | |
|     DWORD m_dwParam;
 | |
|     DWORD m_dwReturnVal;
 | |
| 
 | |
| protected:
 | |
|     HANDLE m_hThread;
 | |
| 
 | |
|     // thread will run this function on startup
 | |
|     // must be supplied by derived class
 | |
|     virtual DWORD ThreadProc() = 0;
 | |
| 
 | |
| public:
 | |
|     CAMThread(__inout_opt HRESULT *phr = NULL);
 | |
|     virtual ~CAMThread();
 | |
| 
 | |
|     CCritSec m_AccessLock;	// locks access by client threads
 | |
|     CCritSec m_WorkerLock;	// locks access to shared objects
 | |
| 
 | |
|     // thread initially runs this. param is actually 'this'. function
 | |
|     // just gets this and calls ThreadProc
 | |
|     static DWORD WINAPI InitialThreadProc(__inout LPVOID pv);
 | |
| 
 | |
|     // start thread running  - error if already running
 | |
|     BOOL Create();
 | |
| 
 | |
|     // signal the thread, and block for a response
 | |
|     //
 | |
|     DWORD CallWorker(DWORD);
 | |
| 
 | |
|     // accessor thread calls this when done with thread (having told thread
 | |
|     // to exit)
 | |
|     void Close() {
 | |
|         HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hThread, 0);
 | |
|         if (hThread) {
 | |
|             WaitForSingleObject(hThread, INFINITE);
 | |
|             CloseHandle(hThread);
 | |
|         }
 | |
|     };
 | |
| 
 | |
|     // ThreadExists
 | |
|     // Return TRUE if the thread exists. FALSE otherwise
 | |
|     BOOL ThreadExists(void) const
 | |
|     {
 | |
|         if (m_hThread == 0) {
 | |
|             return FALSE;
 | |
|         } else {
 | |
|             return TRUE;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // wait for the next request
 | |
|     DWORD GetRequest();
 | |
| 
 | |
|     // is there a request?
 | |
|     BOOL CheckRequest(__out_opt DWORD * pParam);
 | |
| 
 | |
|     // reply to the request
 | |
|     void Reply(DWORD);
 | |
| 
 | |
|     // If you want to do WaitForMultipleObjects you'll need to include
 | |
|     // this handle in your wait list or you won't be responsive
 | |
|     HANDLE GetRequestHandle() const { return m_EventSend; };
 | |
| 
 | |
|     // Find out what the request was
 | |
|     DWORD GetRequestParam() const { return m_dwParam; };
 | |
| 
 | |
|     // call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if
 | |
|     // available. S_FALSE means it's not available.
 | |
|     static HRESULT CoInitializeHelper();
 | |
| };
 | |
| #endif // AM_NOVTABLE
 | |
| 
 | |
| 
 | |
| // CQueue
 | |
| //
 | |
| // Implements a simple Queue ADT.  The queue contains a finite number of
 | |
| // objects, access to which is controlled by a semaphore.  The semaphore
 | |
| // is created with an initial count (N).  Each time an object is added
 | |
| // a call to WaitForSingleObject is made on the semaphore's handle.  When
 | |
| // this function returns a slot has been reserved in the queue for the new
 | |
| // object.  If no slots are available the function blocks until one becomes
 | |
| // available.  Each time an object is removed from the queue ReleaseSemaphore
 | |
| // is called on the semaphore's handle, thus freeing a slot in the queue.
 | |
| // If no objects are present in the queue the function blocks until an
 | |
| // object has been added.
 | |
| 
 | |
| #define DEFAULT_QUEUESIZE   2
 | |
| 
 | |
| template <class T> class CQueue {
 | |
| private:
 | |
|     HANDLE          hSemPut;        // Semaphore controlling queue "putting"
 | |
|     HANDLE          hSemGet;        // Semaphore controlling queue "getting"
 | |
|     CRITICAL_SECTION CritSect;      // Thread seriallization
 | |
|     int             nMax;           // Max objects allowed in queue
 | |
|     int             iNextPut;       // Array index of next "PutMsg"
 | |
|     int             iNextGet;       // Array index of next "GetMsg"
 | |
|     T              *QueueObjects;   // Array of objects (ptr's to void)
 | |
| 
 | |
|     void Initialize(int n) {
 | |
|         iNextPut = iNextGet = 0;
 | |
|         nMax = n;
 | |
|         InitializeCriticalSection(&CritSect);
 | |
|         hSemPut = CreateSemaphore(NULL, n, n, NULL);
 | |
|         hSemGet = CreateSemaphore(NULL, 0, n, NULL);
 | |
|         QueueObjects = new T[n];
 | |
|     }
 | |
| 
 | |
| 
 | |
| public:
 | |
|     CQueue(int n) {
 | |
|         Initialize(n);
 | |
|     }
 | |
| 
 | |
|     CQueue() {
 | |
|         Initialize(DEFAULT_QUEUESIZE);
 | |
|     }
 | |
| 
 | |
|     ~CQueue() {
 | |
|         delete [] QueueObjects;
 | |
|         DeleteCriticalSection(&CritSect);
 | |
|         CloseHandle(hSemPut);
 | |
|         CloseHandle(hSemGet);
 | |
|     }
 | |
| 
 | |
|     T GetQueueObject() {
 | |
|         int iSlot;
 | |
|         T Object;
 | |
|         LONG lPrevious;
 | |
| 
 | |
|         // Wait for someone to put something on our queue, returns straight
 | |
|         // away is there is already an object on the queue.
 | |
|         //
 | |
|         WaitForSingleObject(hSemGet, INFINITE);
 | |
| 
 | |
|         EnterCriticalSection(&CritSect);
 | |
|         iSlot = iNextGet++ % nMax;
 | |
|         Object = QueueObjects[iSlot];
 | |
|         LeaveCriticalSection(&CritSect);
 | |
| 
 | |
|         // Release anyone waiting to put an object onto our queue as there
 | |
|         // is now space available in the queue.
 | |
|         //
 | |
|         ReleaseSemaphore(hSemPut, 1L, &lPrevious);
 | |
|         return Object;
 | |
|     }
 | |
| 
 | |
|     void PutQueueObject(T Object) {
 | |
|         int iSlot;
 | |
|         LONG lPrevious;
 | |
| 
 | |
|         // Wait for someone to get something from our queue, returns straight
 | |
|         // away is there is already an empty slot on the queue.
 | |
|         //
 | |
|         WaitForSingleObject(hSemPut, INFINITE);
 | |
| 
 | |
|         EnterCriticalSection(&CritSect);
 | |
|         iSlot = iNextPut++ % nMax;
 | |
|         QueueObjects[iSlot] = Object;
 | |
|         LeaveCriticalSection(&CritSect);
 | |
| 
 | |
|         // Release anyone waiting to remove an object from our queue as there
 | |
|         // is now an object available to be removed.
 | |
|         //
 | |
|         ReleaseSemaphore(hSemGet, 1L, &lPrevious);
 | |
|     }
 | |
| };
 | |
| 
 | |
| // Ensures that memory is not read past the length source buffer
 | |
| // and that memory is not written past the length of the dst buffer
 | |
| //   dst - buffer to copy to
 | |
| //   dst_size - total size of destination buffer
 | |
| //   cb_dst_offset - offset, first byte copied to dst+cb_dst_offset
 | |
| //   src - buffer to copy from
 | |
| //   src_size - total size of source buffer
 | |
| //   cb_src_offset - offset, first byte copied from src+cb_src_offset
 | |
| //   count - number of bytes to copy
 | |
| //
 | |
| // Returns:
 | |
| //    S_OK          - no error
 | |
| //    E_INVALIDARG  - values passed would lead to overrun
 | |
| HRESULT AMSafeMemMoveOffset(
 | |
|     __in_bcount(dst_size) void * dst,
 | |
|     __in size_t dst_size,
 | |
|     __in DWORD cb_dst_offset,
 | |
|     __in_bcount(src_size) const void * src,
 | |
|     __in size_t src_size,
 | |
|     __in DWORD cb_src_offset,
 | |
|     __in size_t count);
 | |
| 
 | |
| extern "C"
 | |
| void * __stdcall memmoveInternal(void *, const void *, size_t);
 | |
| 
 | |
| inline void * __cdecl memchrInternal(const void *buf, int chr, size_t cnt)
 | |
| {
 | |
| #ifdef _X86_
 | |
|     void *pRet = NULL;
 | |
| 
 | |
|     _asm {
 | |
|         cld                 // make sure we get the direction right
 | |
|         mov     ecx, cnt    // num of bytes to scan
 | |
|         mov     edi, buf    // pointer byte stream
 | |
|         mov     eax, chr    // byte to scan for
 | |
|         repne   scasb       // look for the byte in the byte stream
 | |
|         jnz     exit_memchr // Z flag set if byte found
 | |
|         dec     edi         // scasb always increments edi even when it
 | |
|                             // finds the required byte
 | |
|         mov     pRet, edi
 | |
| exit_memchr:
 | |
|     }
 | |
|     return pRet;
 | |
| 
 | |
| #else
 | |
|     while ( cnt && (*(unsigned char *)buf != (unsigned char)chr) ) {
 | |
|         buf = (unsigned char *)buf + 1;
 | |
|         cnt--;
 | |
|     }
 | |
| 
 | |
|     return(cnt ? (void *)buf : NULL);
 | |
| #endif
 | |
| }
 | |
| 
 | |
| void WINAPI IntToWstr(int i, __out_ecount(12) LPWSTR wstr);
 | |
| 
 | |
| #define WstrToInt(sz) _wtoi(sz)
 | |
| #define atoiW(sz) _wtoi(sz)
 | |
| #define atoiA(sz) atoi(sz)
 | |
| 
 | |
| // These are available to help managing bitmap VIDEOINFOHEADER media structures
 | |
| 
 | |
| extern const DWORD bits555[3];
 | |
| extern const DWORD bits565[3];
 | |
| extern const DWORD bits888[3];
 | |
| 
 | |
| // These help convert between VIDEOINFOHEADER and BITMAPINFO structures
 | |
| 
 | |
| STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader);
 | |
| STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader);
 | |
| STDAPI_(WORD) GetBitCount(const GUID *pSubtype);
 | |
| 
 | |
| // strmbase.lib implements this for compatibility with people who
 | |
| // managed to link to this directly.  we don't want to advertise it.
 | |
| //
 | |
| // STDAPI_(/* T */ CHAR *) GetSubtypeName(const GUID *pSubtype);
 | |
| 
 | |
| STDAPI_(const CHAR *) GetSubtypeNameA(const GUID *pSubtype);
 | |
| STDAPI_(const WCHAR *) GetSubtypeNameW(const GUID *pSubtype);
 | |
| 
 | |
| #ifdef UNICODE
 | |
| #define GetSubtypeName GetSubtypeNameW
 | |
| #else
 | |
| #define GetSubtypeName GetSubtypeNameA
 | |
| #endif
 | |
| 
 | |
| STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader);
 | |
| STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader);
 | |
| 
 | |
| #ifdef __AMVIDEO__
 | |
| STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo);
 | |
| STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo);
 | |
| #endif // __AMVIDEO__
 | |
| 
 | |
| 
 | |
| // Compares two interfaces and returns TRUE if they are on the same object
 | |
| BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond);
 | |
| 
 | |
| // This is for comparing pins
 | |
| #define EqualPins(pPin1, pPin2) IsEqualObject(pPin1, pPin2)
 | |
| 
 | |
| 
 | |
| // Arithmetic helper functions
 | |
| 
 | |
| // Compute (a * b + rnd) / c
 | |
| LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG rnd);
 | |
| LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG rnd);
 | |
| 
 | |
| 
 | |
| // Avoids us dyna-linking to SysAllocString to copy BSTR strings
 | |
| STDAPI WriteBSTR(__deref_out BSTR * pstrDest, LPCWSTR szSrc);
 | |
| STDAPI FreeBSTR(__deref_in BSTR* pstr);
 | |
| 
 | |
| // Return a wide string - allocating memory for it
 | |
| // Returns:
 | |
| //    S_OK          - no error
 | |
| //    E_POINTER     - ppszReturn == NULL
 | |
| //    E_OUTOFMEMORY - can't allocate memory for returned string
 | |
| STDAPI AMGetWideString(LPCWSTR pszString, __deref_out LPWSTR *ppszReturn);
 | |
| 
 | |
| // Special wait for objects owning windows
 | |
| DWORD WINAPI WaitDispatchingMessages(
 | |
|     HANDLE hObject,
 | |
|     DWORD dwWait,
 | |
|     HWND hwnd = NULL,
 | |
|     UINT uMsg = 0,
 | |
|     HANDLE hEvent = NULL);
 | |
| 
 | |
| // HRESULT_FROM_WIN32 converts ERROR_SUCCESS to a success code, but in
 | |
| // our use of HRESULT_FROM_WIN32, it typically means a function failed
 | |
| // to call SetLastError(), and we still want a failure code.
 | |
| //
 | |
| #define AmHresultFromWin32(x) (MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, x))
 | |
| 
 | |
| // call GetLastError and return an HRESULT value that will fail the
 | |
| // SUCCEEDED() macro.
 | |
| HRESULT AmGetLastErrorToHResult(void);
 | |
| 
 | |
| // duplicate of ATL's CComPtr to avoid linker conflicts.
 | |
| 
 | |
| IUnknown* QzAtlComPtrAssign(__deref_inout_opt IUnknown** pp, __in_opt IUnknown* lp);
 | |
| 
 | |
| template <class T>
 | |
| class QzCComPtr
 | |
| {
 | |
| public:
 | |
| 	typedef T _PtrClass;
 | |
| 	QzCComPtr() {p=NULL;}
 | |
| 	QzCComPtr(T* lp)
 | |
| 	{
 | |
| 		if ((p = lp) != NULL)
 | |
| 			p->AddRef();
 | |
| 	}
 | |
| 	QzCComPtr(const QzCComPtr<T>& lp)
 | |
| 	{
 | |
| 		if ((p = lp.p) != NULL)
 | |
| 			p->AddRef();
 | |
| 	}
 | |
| 	~QzCComPtr() {if (p) p->Release();}
 | |
| 	void Release() {if (p) p->Release(); p=NULL;}
 | |
| 	operator T*() {return (T*)p;}
 | |
| 	T& operator*() {ASSERT(p!=NULL); return *p; }
 | |
| 	//The assert on operator& usually indicates a bug.  If this is really
 | |
| 	//what is needed, however, take the address of the p member explicitly.
 | |
| 	T** operator&() { ASSERT(p==NULL); return &p; }
 | |
| 	T* operator->() { ASSERT(p!=NULL); return p; }
 | |
| 	T* operator=(T* lp){return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp);}
 | |
| 	T* operator=(const QzCComPtr<T>& lp)
 | |
| 	{
 | |
| 		return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp.p);
 | |
| 	}
 | |
| #if _MSC_VER>1020
 | |
| 	bool operator!(){return (p == NULL);}
 | |
| #else
 | |
| 	BOOL operator!(){return (p == NULL) ? TRUE : FALSE;}
 | |
| #endif
 | |
| 	T* p;
 | |
| };
 | |
| 
 | |
| MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, __in LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent );
 | |
| bool TimeKillSynchronousFlagAvailable( void );
 | |
| 
 | |
| //  Helper to replace lstrcpmi
 | |
| __inline int lstrcmpiLocaleIndependentW(LPCWSTR lpsz1, LPCWSTR lpsz2)
 | |
| {
 | |
|     return  CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, lpsz1, -1, lpsz2, -1) - CSTR_EQUAL;
 | |
| }
 | |
| __inline int lstrcmpiLocaleIndependentA(LPCSTR lpsz1, LPCSTR lpsz2)
 | |
| {
 | |
|     return  CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, lpsz1, -1, lpsz2, -1) - CSTR_EQUAL;
 | |
| }
 | |
| 
 | |
| #endif /* __WXUTIL__ */
 |