blob: 305974a5f50c757bc3c0621980c6abcbf6abb082 [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001//------------------------------------------------------------------------------
2// File: WXUtil.h
3//
4// Desc: DirectShow base classes - defines helper classes and functions for
5// building multimedia filters.
6//
7// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8//------------------------------------------------------------------------------
9
10
11#ifndef __WXUTIL__
12#define __WXUTIL__
13
14// eliminate spurious "statement has no effect" warnings.
15#pragma warning(disable: 4705)
16
17// wrapper for whatever critical section we have
18class CCritSec {
19
20 // make copy constructor and assignment operator inaccessible
21
22 CCritSec(const CCritSec &refCritSec);
23 CCritSec &operator=(const CCritSec &refCritSec);
24
25 CRITICAL_SECTION m_CritSec;
26
27#ifdef DEBUG
28public:
29 DWORD m_currentOwner;
30 DWORD m_lockCount;
31 BOOL m_fTrace; // Trace this one
32public:
33 CCritSec();
34 ~CCritSec();
35 void Lock();
36 void Unlock();
37#else
38
39public:
40 CCritSec() {
41 InitializeCriticalSection(&m_CritSec);
42 };
43
44 ~CCritSec() {
45 DeleteCriticalSection(&m_CritSec);
46 };
47
48 void Lock() {
49 EnterCriticalSection(&m_CritSec);
50 };
51
52 void Unlock() {
53 LeaveCriticalSection(&m_CritSec);
54 };
55#endif
56};
57
58//
59// To make deadlocks easier to track it is useful to insert in the
60// code an assertion that says whether we own a critical section or
61// not. We make the routines that do the checking globals to avoid
62// having different numbers of member functions in the debug and
63// retail class implementations of CCritSec. In addition we provide
64// a routine that allows usage of specific critical sections to be
65// traced. This is NOT on by default - there are far too many.
66//
67
68#ifdef DEBUG
69 BOOL WINAPI CritCheckIn(CCritSec * pcCrit);
70 BOOL WINAPI CritCheckIn(const CCritSec * pcCrit);
71 BOOL WINAPI CritCheckOut(CCritSec * pcCrit);
72 BOOL WINAPI CritCheckOut(const CCritSec * pcCrit);
73 void WINAPI DbgLockTrace(CCritSec * pcCrit, BOOL fTrace);
74#else
75 #define CritCheckIn(x) TRUE
76 #define CritCheckOut(x) TRUE
77 #define DbgLockTrace(pc, fT)
78#endif
79
80
81// locks a critical section, and unlocks it automatically
82// when the lock goes out of scope
83class CAutoLock {
84
85 // make copy constructor and assignment operator inaccessible
86
87 CAutoLock(const CAutoLock &refAutoLock);
88 CAutoLock &operator=(const CAutoLock &refAutoLock);
89
90protected:
91 CCritSec * m_pLock;
92
93public:
94 CAutoLock(CCritSec * plock)
95 {
96 m_pLock = plock;
97 m_pLock->Lock();
98 };
99
100 ~CAutoLock() {
101 m_pLock->Unlock();
102 };
103};
104
105
106
107// wrapper for event objects
108class CAMEvent
109{
110
111 // make copy constructor and assignment operator inaccessible
112
113 CAMEvent(const CAMEvent &refEvent);
114 CAMEvent &operator=(const CAMEvent &refEvent);
115
116protected:
117 HANDLE m_hEvent;
118public:
119 CAMEvent(BOOL fManualReset = FALSE, __inout_opt HRESULT *phr = NULL);
120 CAMEvent(__inout_opt HRESULT *phr);
121 ~CAMEvent();
122
123 // Cast to HANDLE - we don't support this as an lvalue
124 operator HANDLE () const { return m_hEvent; };
125
126 void Set() {EXECUTE_ASSERT(SetEvent(m_hEvent));};
127 BOOL Wait(DWORD dwTimeout = INFINITE) {
128 return (WaitForSingleObject(m_hEvent, dwTimeout) == WAIT_OBJECT_0);
129 };
130 void Reset() { ResetEvent(m_hEvent); };
131 BOOL Check() { return Wait(0); };
132};
133
134
135// wrapper for event objects that do message processing
136// This adds ONE method to the CAMEvent object to allow sent
137// messages to be processed while waiting
138
139class CAMMsgEvent : public CAMEvent
140{
141
142public:
143
144 CAMMsgEvent(__inout_opt HRESULT *phr = NULL);
145
146 // Allow SEND messages to be processed while waiting
147 BOOL WaitMsg(DWORD dwTimeout = INFINITE);
148};
149
150// old name supported for the time being
151#define CTimeoutEvent CAMEvent
152
153// support for a worker thread
154
155#ifdef AM_NOVTABLE
156// simple thread class supports creation of worker thread, synchronization
157// and communication. Can be derived to simplify parameter passing
158class AM_NOVTABLE CAMThread {
159
160 // make copy constructor and assignment operator inaccessible
161
162 CAMThread(const CAMThread &refThread);
163 CAMThread &operator=(const CAMThread &refThread);
164
165 CAMEvent m_EventSend;
166 CAMEvent m_EventComplete;
167
168 DWORD m_dwParam;
169 DWORD m_dwReturnVal;
170
171protected:
172 HANDLE m_hThread;
173
174 // thread will run this function on startup
175 // must be supplied by derived class
176 virtual DWORD ThreadProc() = 0;
177
178public:
179 CAMThread(__inout_opt HRESULT *phr = NULL);
180 virtual ~CAMThread();
181
182 CCritSec m_AccessLock; // locks access by client threads
183 CCritSec m_WorkerLock; // locks access to shared objects
184
185 // thread initially runs this. param is actually 'this'. function
186 // just gets this and calls ThreadProc
187 static DWORD WINAPI InitialThreadProc(__inout LPVOID pv);
188
189 // start thread running - error if already running
190 BOOL Create();
191
192 // signal the thread, and block for a response
193 //
194 DWORD CallWorker(DWORD);
195
196 // accessor thread calls this when done with thread (having told thread
197 // to exit)
198 void Close() {
199
200 // Disable warning: Conversion from LONG to PVOID of greater size
201#pragma warning(push)
202#pragma warning(disable: 4312)
203 HANDLE hThread = (HANDLE)InterlockedExchangePointer(&m_hThread, 0);
204#pragma warning(pop)
205
206 if (hThread) {
207 WaitForSingleObject(hThread, INFINITE);
208 CloseHandle(hThread);
209 }
210 };
211
212 // ThreadExists
213 // Return TRUE if the thread exists. FALSE otherwise
214 BOOL ThreadExists(void) const
215 {
216 if (m_hThread == 0) {
217 return FALSE;
218 } else {
219 return TRUE;
220 }
221 }
222
223 // wait for the next request
224 DWORD GetRequest();
225
226 // is there a request?
227 BOOL CheckRequest(__out_opt DWORD * pParam);
228
229 // reply to the request
230 void Reply(DWORD);
231
232 // If you want to do WaitForMultipleObjects you'll need to include
233 // this handle in your wait list or you won't be responsive
234 HANDLE GetRequestHandle() const { return m_EventSend; };
235
236 // Find out what the request was
237 DWORD GetRequestParam() const { return m_dwParam; };
238
239 // call CoInitializeEx (COINIT_DISABLE_OLE1DDE) if
240 // available. S_FALSE means it's not available.
241 static HRESULT CoInitializeHelper();
242};
243#endif // AM_NOVTABLE
244
245
246// CQueue
247//
248// Implements a simple Queue ADT. The queue contains a finite number of
249// objects, access to which is controlled by a semaphore. The semaphore
250// is created with an initial count (N). Each time an object is added
251// a call to WaitForSingleObject is made on the semaphore's handle. When
252// this function returns a slot has been reserved in the queue for the new
253// object. If no slots are available the function blocks until one becomes
254// available. Each time an object is removed from the queue ReleaseSemaphore
255// is called on the semaphore's handle, thus freeing a slot in the queue.
256// If no objects are present in the queue the function blocks until an
257// object has been added.
258
259#define DEFAULT_QUEUESIZE 2
260
261template <class T> class CQueue {
262private:
263 HANDLE hSemPut; // Semaphore controlling queue "putting"
264 HANDLE hSemGet; // Semaphore controlling queue "getting"
265 CRITICAL_SECTION CritSect; // Thread seriallization
266 int nMax; // Max objects allowed in queue
267 int iNextPut; // Array index of next "PutMsg"
268 int iNextGet; // Array index of next "GetMsg"
269 T *QueueObjects; // Array of objects (ptr's to void)
270
271 void Initialize(int n) {
272 iNextPut = iNextGet = 0;
273 nMax = n;
274 InitializeCriticalSection(&CritSect);
275 hSemPut = CreateSemaphore(NULL, n, n, NULL);
276 hSemGet = CreateSemaphore(NULL, 0, n, NULL);
277 QueueObjects = new T[n];
278 }
279
280
281public:
282 CQueue(int n) {
283 Initialize(n);
284 }
285
286 CQueue() {
287 Initialize(DEFAULT_QUEUESIZE);
288 }
289
290 ~CQueue() {
291 delete [] QueueObjects;
292 DeleteCriticalSection(&CritSect);
293 CloseHandle(hSemPut);
294 CloseHandle(hSemGet);
295 }
296
297 T GetQueueObject() {
298 int iSlot;
299 T Object;
300 LONG lPrevious;
301
302 // Wait for someone to put something on our queue, returns straight
303 // away is there is already an object on the queue.
304 //
305 WaitForSingleObject(hSemGet, INFINITE);
306
307 EnterCriticalSection(&CritSect);
308 iSlot = iNextGet++ % nMax;
309 Object = QueueObjects[iSlot];
310 LeaveCriticalSection(&CritSect);
311
312 // Release anyone waiting to put an object onto our queue as there
313 // is now space available in the queue.
314 //
315 ReleaseSemaphore(hSemPut, 1L, &lPrevious);
316 return Object;
317 }
318
319 void PutQueueObject(T Object) {
320 int iSlot;
321 LONG lPrevious;
322
323 // Wait for someone to get something from our queue, returns straight
324 // away is there is already an empty slot on the queue.
325 //
326 WaitForSingleObject(hSemPut, INFINITE);
327
328 EnterCriticalSection(&CritSect);
329 iSlot = iNextPut++ % nMax;
330 QueueObjects[iSlot] = Object;
331 LeaveCriticalSection(&CritSect);
332
333 // Release anyone waiting to remove an object from our queue as there
334 // is now an object available to be removed.
335 //
336 ReleaseSemaphore(hSemGet, 1L, &lPrevious);
337 }
338};
339
340// Ensures that memory is not read past the length source buffer
341// and that memory is not written past the length of the dst buffer
342// dst - buffer to copy to
343// dst_size - total size of destination buffer
344// cb_dst_offset - offset, first byte copied to dst+cb_dst_offset
345// src - buffer to copy from
346// src_size - total size of source buffer
347// cb_src_offset - offset, first byte copied from src+cb_src_offset
348// count - number of bytes to copy
349//
350// Returns:
351// S_OK - no error
352// E_INVALIDARG - values passed would lead to overrun
353HRESULT AMSafeMemMoveOffset(
354 __in_bcount(dst_size) void * dst,
355 __in size_t dst_size,
356 __in DWORD cb_dst_offset,
357 __in_bcount(src_size) const void * src,
358 __in size_t src_size,
359 __in DWORD cb_src_offset,
360 __in size_t count);
361
362extern "C"
363void * __stdcall memmoveInternal(void *, const void *, size_t);
364
365inline void * __cdecl memchrInternal(const void *buf, int chr, size_t cnt)
366{
367#ifdef _X86_
368 void *pRet = NULL;
369
370 _asm {
371 cld // make sure we get the direction right
372 mov ecx, cnt // num of bytes to scan
373 mov edi, buf // pointer byte stream
374 mov eax, chr // byte to scan for
375 repne scasb // look for the byte in the byte stream
376 jnz exit_memchr // Z flag set if byte found
377 dec edi // scasb always increments edi even when it
378 // finds the required byte
379 mov pRet, edi
380exit_memchr:
381 }
382 return pRet;
383
384#else
385 while ( cnt && (*(unsigned char *)buf != (unsigned char)chr) ) {
386 buf = (unsigned char *)buf + 1;
387 cnt--;
388 }
389
390 return(cnt ? (void *)buf : NULL);
391#endif
392}
393
394void WINAPI IntToWstr(int i, __out_ecount(12) LPWSTR wstr);
395
396#define WstrToInt(sz) _wtoi(sz)
397#define atoiW(sz) _wtoi(sz)
398#define atoiA(sz) atoi(sz)
399
400// These are available to help managing bitmap VIDEOINFOHEADER media structures
401
402extern const DWORD bits555[3];
403extern const DWORD bits565[3];
404extern const DWORD bits888[3];
405
406// These help convert between VIDEOINFOHEADER and BITMAPINFO structures
407
408STDAPI_(const GUID) GetTrueColorType(const BITMAPINFOHEADER *pbmiHeader);
409STDAPI_(const GUID) GetBitmapSubtype(const BITMAPINFOHEADER *pbmiHeader);
410STDAPI_(WORD) GetBitCount(const GUID *pSubtype);
411
412// strmbase.lib implements this for compatibility with people who
413// managed to link to this directly. we don't want to advertise it.
414//
415// STDAPI_(/* T */ CHAR *) GetSubtypeName(const GUID *pSubtype);
416
417STDAPI_(CHAR *) GetSubtypeNameA(const GUID *pSubtype);
418STDAPI_(WCHAR *) GetSubtypeNameW(const GUID *pSubtype);
419
420#ifdef UNICODE
421#define GetSubtypeName GetSubtypeNameW
422#else
423#define GetSubtypeName GetSubtypeNameA
424#endif
425
426STDAPI_(LONG) GetBitmapFormatSize(const BITMAPINFOHEADER *pHeader);
427STDAPI_(DWORD) GetBitmapSize(const BITMAPINFOHEADER *pHeader);
428
429#ifdef __AMVIDEO__
430STDAPI_(BOOL) ContainsPalette(const VIDEOINFOHEADER *pVideoInfo);
431STDAPI_(const RGBQUAD *) GetBitmapPalette(const VIDEOINFOHEADER *pVideoInfo);
432#endif // __AMVIDEO__
433
434
435// Compares two interfaces and returns TRUE if they are on the same object
436BOOL WINAPI IsEqualObject(IUnknown *pFirst, IUnknown *pSecond);
437
438// This is for comparing pins
439#define EqualPins(pPin1, pPin2) IsEqualObject(pPin1, pPin2)
440
441
442// Arithmetic helper functions
443
444// Compute (a * b + rnd) / c
445LONGLONG WINAPI llMulDiv(LONGLONG a, LONGLONG b, LONGLONG c, LONGLONG rnd);
446LONGLONG WINAPI Int64x32Div32(LONGLONG a, LONG b, LONG c, LONG rnd);
447
448
449// Avoids us dyna-linking to SysAllocString to copy BSTR strings
450STDAPI WriteBSTR(__deref_out BSTR * pstrDest, LPCWSTR szSrc);
451STDAPI FreeBSTR(__deref_in BSTR* pstr);
452
453// Return a wide string - allocating memory for it
454// Returns:
455// S_OK - no error
456// E_POINTER - ppszReturn == NULL
457// E_OUTOFMEMORY - can't allocate memory for returned string
458STDAPI AMGetWideString(LPCWSTR pszString, __deref_out LPWSTR *ppszReturn);
459
460// Special wait for objects owning windows
461DWORD WINAPI WaitDispatchingMessages(
462 HANDLE hObject,
463 DWORD dwWait,
464 HWND hwnd = NULL,
465 UINT uMsg = 0,
466 HANDLE hEvent = NULL);
467
468// HRESULT_FROM_WIN32 converts ERROR_SUCCESS to a success code, but in
469// our use of HRESULT_FROM_WIN32, it typically means a function failed
470// to call SetLastError(), and we still want a failure code.
471//
472#define AmHresultFromWin32(x) (MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, x))
473
474// call GetLastError and return an HRESULT value that will fail the
475// SUCCEEDED() macro.
476HRESULT AmGetLastErrorToHResult(void);
477
478// duplicate of ATL's CComPtr to avoid linker conflicts.
479
480IUnknown* QzAtlComPtrAssign(__deref_inout_opt IUnknown** pp, __in_opt IUnknown* lp);
481
482template <class T>
483class QzCComPtr
484{
485public:
486 typedef T _PtrClass;
487 QzCComPtr() {p=NULL;}
488 QzCComPtr(T* lp)
489 {
490 if ((p = lp) != NULL)
491 p->AddRef();
492 }
493 QzCComPtr(const QzCComPtr<T>& lp)
494 {
495 if ((p = lp.p) != NULL)
496 p->AddRef();
497 }
498 ~QzCComPtr() {if (p) p->Release();}
499 void Release() {if (p) p->Release(); p=NULL;}
500 operator T*() {return (T*)p;}
501 T& operator*() {ASSERT(p!=NULL); return *p; }
502 //The assert on operator& usually indicates a bug. If this is really
503 //what is needed, however, take the address of the p member explicitly.
504 T** operator&() { ASSERT(p==NULL); return &p; }
505 T* operator->() { ASSERT(p!=NULL); return p; }
506 T* operator=(T* lp){return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp);}
507 T* operator=(const QzCComPtr<T>& lp)
508 {
509 return (T*)QzAtlComPtrAssign((IUnknown**)&p, lp.p);
510 }
511#if _MSC_VER>1020
512 bool operator!(){return (p == NULL);}
513#else
514 BOOL operator!(){return (p == NULL) ? TRUE : FALSE;}
515#endif
516 T* p;
517};
518
519MMRESULT CompatibleTimeSetEvent( UINT uDelay, UINT uResolution, __in LPTIMECALLBACK lpTimeProc, DWORD_PTR dwUser, UINT fuEvent );
520bool TimeKillSynchronousFlagAvailable( void );
521
522// Helper to replace lstrcpmi
523__inline int lstrcmpiLocaleIndependentW(LPCWSTR lpsz1, LPCWSTR lpsz2)
524{
525 return CompareStringW(LOCALE_INVARIANT, NORM_IGNORECASE, lpsz1, -1, lpsz2, -1) - CSTR_EQUAL;
526}
527__inline int lstrcmpiLocaleIndependentA(LPCSTR lpsz1, LPCSTR lpsz2)
528{
529 return CompareStringA(LOCALE_INVARIANT, NORM_IGNORECASE, lpsz1, -1, lpsz2, -1) - CSTR_EQUAL;
530}
531
532#endif /* __WXUTIL__ */