blob: 3a1dc38f1a2125ffcb76dac7bc8e9ba35855348a [file] [log] [blame]
Tristan Matthews0a329cc2013-07-17 13:20:14 -04001//------------------------------------------------------------------------------
2// File: WXDebug.cpp
3//
4// Desc: DirectShow base classes - implements ActiveX system debugging
5// facilities.
6//
7// Copyright (c) 1992-2001 Microsoft Corporation. All rights reserved.
8//------------------------------------------------------------------------------
9
10#include <pjmedia-videodev/config.h>
11
12#if defined(PJMEDIA_VIDEO_DEV_HAS_DSHOW) && PJMEDIA_VIDEO_DEV_HAS_DSHOW != 0
13
14#define _WINDLL
15
16#include <streams.h>
17#include <stdarg.h>
18#include <stdio.h>
19#include <dvdmedia.h>
20
21#ifdef DEBUG
22#ifdef UNICODE
23#ifndef _UNICODE
24#define _UNICODE
25#endif // _UNICODE
26#endif // UNICODE
27#endif // DEBUG
28
29#include <tchar.h>
30#include <strsafe.h>
31
32#ifdef DEBUG
33static void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi);
34static void DisplayRECT(LPCTSTR szLabel, const RECT& rc);
35
36// The Win32 wsprintf() function writes a maximum of 1024 characters to it's output buffer.
37// See the documentation for wsprintf()'s lpOut parameter for more information.
38const INT iDEBUGINFO = 1024; // Used to format strings
39
40/* For every module and executable we store a debugging level for each of
41 the five categories (eg LOG_ERROR and LOG_TIMING). This makes it easy
42 to isolate and debug individual modules without seeing everybody elses
43 spurious debug output. The keys are stored in the registry under the
44 HKEY_LOCAL_MACHINE\SOFTWARE\Debug\<Module Name>\<KeyName> key values
45 NOTE these must be in the same order as their enumeration definition */
46
47const LPCTSTR pKeyNames[] = {
48 TEXT("TIMING"), // Timing and performance measurements
49 TEXT("TRACE"), // General step point call tracing
50 TEXT("MEMORY"), // Memory and object allocation/destruction
51 TEXT("LOCKING"), // Locking/unlocking of critical sections
52 TEXT("ERROR"), // Debug error notification
53 TEXT("CUSTOM1"),
54 TEXT("CUSTOM2"),
55 TEXT("CUSTOM3"),
56 TEXT("CUSTOM4"),
57 TEXT("CUSTOM5")
58 };
59
60const TCHAR CAutoTrace::_szEntering[] = TEXT("->: %s");
61const TCHAR CAutoTrace::_szLeaving[] = TEXT("<-: %s");
62
63const INT iMAXLEVELS = NUMELMS(pKeyNames); // Maximum debug categories
64
65HINSTANCE m_hInst; // Module instance handle
66TCHAR m_ModuleName[iDEBUGINFO]; // Cut down module name
67DWORD m_Levels[iMAXLEVELS]; // Debug level per category
68CRITICAL_SECTION m_CSDebug; // Controls access to list
69DWORD m_dwNextCookie; // Next active object ID
70ObjectDesc *pListHead = NULL; // First active object
71DWORD m_dwObjectCount; // Active object count
72BOOL m_bInit = FALSE; // Have we been initialised
73HANDLE m_hOutput = INVALID_HANDLE_VALUE; // Optional output written here
74DWORD dwWaitTimeout = INFINITE; // Default timeout value
75DWORD dwTimeOffset; // Time of first DbgLog call
76bool g_fUseKASSERT = false; // don't create messagebox
77bool g_fDbgInDllEntryPoint = false;
78bool g_fAutoRefreshLevels = false;
79
80LPCTSTR pBaseKey = TEXT("SOFTWARE\\Microsoft\\DirectShow\\Debug");
81LPCTSTR pGlobalKey = TEXT("GLOBAL");
82static CHAR *pUnknownName = "UNKNOWN";
83
84LPCTSTR TimeoutName = TEXT("TIMEOUT");
85
86/* This sets the instance handle that the debug library uses to find
87 the module's file name from the Win32 GetModuleFileName function */
88
89void WINAPI DbgInitialise(HINSTANCE hInst)
90{
91 InitializeCriticalSection(&m_CSDebug);
92 m_bInit = TRUE;
93
94 m_hInst = hInst;
95 DbgInitModuleName();
96 if (GetProfileInt(m_ModuleName, TEXT("BreakOnLoad"), 0))
97 DebugBreak();
98 DbgInitModuleSettings(false);
99 DbgInitGlobalSettings(true);
100 dwTimeOffset = timeGetTime();
101}
102
103
104/* This is called to clear up any resources the debug library uses - at the
105 moment we delete our critical section and the object list. The values we
106 retrieve from the registry are all done during initialisation but we don't
107 go looking for update notifications while we are running, if the values
108 are changed then the application has to be restarted to pick them up */
109
110void WINAPI DbgTerminate()
111{
112 if (m_hOutput != INVALID_HANDLE_VALUE) {
113 EXECUTE_ASSERT(CloseHandle(m_hOutput));
114 m_hOutput = INVALID_HANDLE_VALUE;
115 }
116 DeleteCriticalSection(&m_CSDebug);
117 m_bInit = FALSE;
118}
119
120
121/* This is called by DbgInitLogLevels to read the debug settings
122 for each logging category for this module from the registry */
123
124void WINAPI DbgInitKeyLevels(HKEY hKey, bool fTakeMax)
125{
126 LONG lReturn; // Create key return value
127 LONG lKeyPos; // Current key category
128 DWORD dwKeySize; // Size of the key value
129 DWORD dwKeyType; // Receives it's type
130 DWORD dwKeyValue; // This fields value
131
132 /* Try and read a value for each key position in turn */
133 for (lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) {
134
135 dwKeySize = sizeof(DWORD);
136 lReturn = RegQueryValueEx(
137 hKey, // Handle to an open key
138 pKeyNames[lKeyPos], // Subkey name derivation
139 NULL, // Reserved field
140 &dwKeyType, // Returns the field type
141 (LPBYTE) &dwKeyValue, // Returns the field's value
142 &dwKeySize ); // Number of bytes transferred
143
144 /* If either the key was not available or it was not a DWORD value
145 then we ensure only the high priority debug logging is output
146 but we try and update the field to a zero filled DWORD value */
147
148 if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) {
149
150 dwKeyValue = 0;
151 lReturn = RegSetValueEx(
152 hKey, // Handle of an open key
153 pKeyNames[lKeyPos], // Address of subkey name
154 (DWORD) 0, // Reserved field
155 REG_DWORD, // Type of the key field
156 (PBYTE) &dwKeyValue, // Value for the field
157 sizeof(DWORD)); // Size of the field buffer
158
159 if (lReturn != ERROR_SUCCESS) {
160 DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos]));
161 dwKeyValue = 0;
162 }
163 }
164 if(fTakeMax)
165 {
166 m_Levels[lKeyPos] = max(dwKeyValue,m_Levels[lKeyPos]);
167 }
168 else
169 {
170 if((m_Levels[lKeyPos] & LOG_FORCIBLY_SET) == 0) {
171 m_Levels[lKeyPos] = dwKeyValue;
172 }
173 }
174 }
175
176 /* Read the timeout value for catching hangs */
177 dwKeySize = sizeof(DWORD);
178 lReturn = RegQueryValueEx(
179 hKey, // Handle to an open key
180 TimeoutName, // Subkey name derivation
181 NULL, // Reserved field
182 &dwKeyType, // Returns the field type
183 (LPBYTE) &dwWaitTimeout, // Returns the field's value
184 &dwKeySize ); // Number of bytes transferred
185
186 /* If either the key was not available or it was not a DWORD value
187 then we ensure only the high priority debug logging is output
188 but we try and update the field to a zero filled DWORD value */
189
190 if (lReturn != ERROR_SUCCESS || dwKeyType != REG_DWORD) {
191
192 dwWaitTimeout = INFINITE;
193 lReturn = RegSetValueEx(
194 hKey, // Handle of an open key
195 TimeoutName, // Address of subkey name
196 (DWORD) 0, // Reserved field
197 REG_DWORD, // Type of the key field
198 (PBYTE) &dwWaitTimeout, // Value for the field
199 sizeof(DWORD)); // Size of the field buffer
200
201 if (lReturn != ERROR_SUCCESS) {
202 DbgLog((LOG_ERROR,1,TEXT("Could not create subkey %s"),pKeyNames[lKeyPos]));
203 dwWaitTimeout = INFINITE;
204 }
205 }
206}
207
208void WINAPI DbgOutString(LPCTSTR psz)
209{
210 if (m_hOutput != INVALID_HANDLE_VALUE) {
211 UINT cb = lstrlen(psz);
212 DWORD dw;
213#ifdef UNICODE
214 CHAR szDest[2048];
215 WideCharToMultiByte(CP_ACP, 0, psz, -1, szDest, NUMELMS(szDest), 0, 0);
216 WriteFile (m_hOutput, szDest, cb, &dw, NULL);
217#else
218 WriteFile (m_hOutput, psz, cb, &dw, NULL);
219#endif
220 } else {
221 OutputDebugString (psz);
222 }
223}
224
225
226
227
228HRESULT DbgUniqueProcessName(LPCTSTR inName, LPTSTR outName)
229{
230 HRESULT hr = S_OK;
231 const TCHAR *pIn = inName;
232 int dotPos = -1;
233
234 //scan the input and record the last '.' position
235 while (*pIn && (pIn - inName) < MAX_PATH)
236 {
237 if ( TEXT('.') == *pIn )
238 dotPos = (int)(pIn-inName);
239 ++pIn;
240 }
241
242 if (*pIn) //input should be zero-terminated within MAX_PATH
243 return E_INVALIDARG;
244
245 DWORD dwProcessId = GetCurrentProcessId();
246
247 if (dotPos < 0)
248 {
249 //no extension in the input, appending process id to the input
250 hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d"), inName, dwProcessId);
251 }
252 else
253 {
254 TCHAR pathAndBasename[MAX_PATH] = {0};
255
256 //there's an extension - zero-terminate the path and basename first by copying
257 hr = StringCchCopyN(pathAndBasename, MAX_PATH, inName, (size_t)dotPos);
258
259 //re-combine path, basename and extension with processId appended to a basename
260 if (SUCCEEDED(hr))
261 hr = StringCchPrintf(outName, MAX_PATH, TEXT("%s_%d%s"), pathAndBasename, dwProcessId, inName + dotPos);
262 }
263
264 return hr;
265}
266
267
268/* Called by DbgInitGlobalSettings to setup alternate logging destinations
269 */
270
271void WINAPI DbgInitLogTo (
272 HKEY hKey)
273{
274 LONG lReturn;
275 DWORD dwKeyType;
276 DWORD dwKeySize;
277 TCHAR szFile[MAX_PATH] = {0};
278 static const TCHAR cszKey[] = TEXT("LogToFile");
279
280 dwKeySize = MAX_PATH;
281 lReturn = RegQueryValueEx(
282 hKey, // Handle to an open key
283 cszKey, // Subkey name derivation
284 NULL, // Reserved field
285 &dwKeyType, // Returns the field type
286 (LPBYTE) szFile, // Returns the field's value
287 &dwKeySize); // Number of bytes transferred
288
289 // create an empty key if it does not already exist
290 //
291 if (lReturn != ERROR_SUCCESS || dwKeyType != REG_SZ)
292 {
293 dwKeySize = sizeof(TCHAR);
294 lReturn = RegSetValueEx(
295 hKey, // Handle of an open key
296 cszKey, // Address of subkey name
297 (DWORD) 0, // Reserved field
298 REG_SZ, // Type of the key field
299 (PBYTE)szFile, // Value for the field
300 dwKeySize); // Size of the field buffer
301 }
302
303 // if an output-to was specified. try to open it.
304 //
305 if (m_hOutput != INVALID_HANDLE_VALUE) {
306 EXECUTE_ASSERT(CloseHandle (m_hOutput));
307 m_hOutput = INVALID_HANDLE_VALUE;
308 }
309 if (szFile[0] != 0)
310 {
311 if (!lstrcmpi(szFile, TEXT("Console"))) {
312 m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE);
313 if (m_hOutput == INVALID_HANDLE_VALUE) {
314 AllocConsole ();
315 m_hOutput = GetStdHandle (STD_OUTPUT_HANDLE);
316 }
317 SetConsoleTitle (TEXT("ActiveX Debug Output"));
318 } else if (szFile[0] &&
319 lstrcmpi(szFile, TEXT("Debug")) &&
320 lstrcmpi(szFile, TEXT("Debugger")) &&
321 lstrcmpi(szFile, TEXT("Deb")))
322 {
323 m_hOutput = CreateFile(szFile, GENERIC_WRITE,
324 FILE_SHARE_READ,
325 NULL, OPEN_ALWAYS,
326 FILE_ATTRIBUTE_NORMAL,
327 NULL);
328
329 if (INVALID_HANDLE_VALUE == m_hOutput &&
330 GetLastError() == ERROR_SHARING_VIOLATION)
331 {
332 TCHAR uniqueName[MAX_PATH] = {0};
333 if (SUCCEEDED(DbgUniqueProcessName(szFile, uniqueName)))
334 {
335 m_hOutput = CreateFile(uniqueName, GENERIC_WRITE,
336 FILE_SHARE_READ,
337 NULL, OPEN_ALWAYS,
338 FILE_ATTRIBUTE_NORMAL,
339 NULL);
340 }
341 }
342
343 if (INVALID_HANDLE_VALUE != m_hOutput)
344 {
345 static const TCHAR cszBar[] = TEXT("\r\n\r\n=====DbgInitialize()=====\r\n\r\n");
346 SetFilePointer (m_hOutput, 0, NULL, FILE_END);
347 DbgOutString (cszBar);
348 }
349 }
350 }
351}
352
353
354
355/* This is called by DbgInitLogLevels to read the global debug settings for
356 each logging category for this module from the registry. Normally each
357 module has it's own values set for it's different debug categories but
358 setting the global SOFTWARE\Debug\Global applies them to ALL modules */
359
360void WINAPI DbgInitGlobalSettings(bool fTakeMax)
361{
362 LONG lReturn; // Create key return value
363 TCHAR szInfo[iDEBUGINFO]; // Constructs key names
364 HKEY hGlobalKey; // Global override key
365
366 /* Construct the global base key name */
367 (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,pGlobalKey);
368
369 /* Create or open the key for this module */
370 lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key
371 szInfo, // Address of subkey name
372 (DWORD) 0, // Reserved value
373 NULL, // Address of class name
374 (DWORD) 0, // Special options flags
375 GENERIC_READ | GENERIC_WRITE, // Desired security access
376 NULL, // Key security descriptor
377 &hGlobalKey, // Opened handle buffer
378 NULL); // What really happened
379
380 if (lReturn != ERROR_SUCCESS) {
381 lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key
382 szInfo, // Address of subkey name
383 (DWORD) 0, // Reserved value
384 NULL, // Address of class name
385 (DWORD) 0, // Special options flags
386 GENERIC_READ, // Desired security access
387 NULL, // Key security descriptor
388 &hGlobalKey, // Opened handle buffer
389 NULL); // What really happened
390 if (lReturn != ERROR_SUCCESS) {
391 DbgLog((LOG_ERROR,1,TEXT("Could not access GLOBAL module key")));
392 }
393 return;
394 }
395
396 DbgInitKeyLevels(hGlobalKey, fTakeMax);
397 RegCloseKey(hGlobalKey);
398}
399
400
401/* This sets the debugging log levels for the different categories. We start
402 by opening (or creating if not already available) the SOFTWARE\Debug key
403 that all these settings live under. We then look at the global values
404 set under SOFTWARE\Debug\Global which apply on top of the individual
405 module settings. We then load the individual module registry settings */
406
407void WINAPI DbgInitModuleSettings(bool fTakeMax)
408{
409 LONG lReturn; // Create key return value
410 TCHAR szInfo[iDEBUGINFO]; // Constructs key names
411 HKEY hModuleKey; // Module key handle
412
413 /* Construct the base key name */
414 (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%s\\%s"),pBaseKey,m_ModuleName);
415
416 /* Create or open the key for this module */
417 lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key
418 szInfo, // Address of subkey name
419 (DWORD) 0, // Reserved value
420 NULL, // Address of class name
421 (DWORD) 0, // Special options flags
422 GENERIC_READ | GENERIC_WRITE, // Desired security access
423 NULL, // Key security descriptor
424 &hModuleKey, // Opened handle buffer
425 NULL); // What really happened
426
427 if (lReturn != ERROR_SUCCESS) {
428 lReturn = RegCreateKeyEx(HKEY_LOCAL_MACHINE, // Handle of an open key
429 szInfo, // Address of subkey name
430 (DWORD) 0, // Reserved value
431 NULL, // Address of class name
432 (DWORD) 0, // Special options flags
433 GENERIC_READ, // Desired security access
434 NULL, // Key security descriptor
435 &hModuleKey, // Opened handle buffer
436 NULL); // What really happened
437 if (lReturn != ERROR_SUCCESS) {
438 DbgLog((LOG_ERROR,1,TEXT("Could not access module key")));
439 }
440 return;
441 }
442
443 DbgInitLogTo(hModuleKey);
444 DbgInitKeyLevels(hModuleKey, fTakeMax);
445 RegCloseKey(hModuleKey);
446}
447
448
449/* Initialise the module file name */
450
451void WINAPI DbgInitModuleName()
452{
453 TCHAR FullName[iDEBUGINFO]; // Load the full path and module name
454 LPTSTR pName; // Searches from the end for a backslash
455
456 GetModuleFileName(m_hInst,FullName,iDEBUGINFO);
457 pName = _tcsrchr(FullName,'\\');
458 if (pName == NULL) {
459 pName = FullName;
460 } else {
461 pName++;
462 }
463 (void)StringCchCopy(m_ModuleName,NUMELMS(m_ModuleName), pName);
464}
465
466struct MsgBoxMsg
467{
468 HWND hwnd;
469 LPCTSTR szTitle;
470 LPCTSTR szMessage;
471 DWORD dwFlags;
472 INT iResult;
473};
474
475//
476// create a thread to call MessageBox(). calling MessageBox() on
477// random threads at bad times can confuse the host (eg IE).
478//
479DWORD WINAPI MsgBoxThread(
480 __inout LPVOID lpParameter // thread data
481 )
482{
483 MsgBoxMsg *pmsg = (MsgBoxMsg *)lpParameter;
484 pmsg->iResult = MessageBox(
485 pmsg->hwnd,
486 pmsg->szTitle,
487 pmsg->szMessage,
488 pmsg->dwFlags);
489
490 return 0;
491}
492
493INT MessageBoxOtherThread(
494 HWND hwnd,
495 LPCTSTR szTitle,
496 LPCTSTR szMessage,
497 DWORD dwFlags)
498{
499 if(g_fDbgInDllEntryPoint)
500 {
501 // can't wait on another thread because we have the loader
502 // lock held in the dll entry point.
503 // This can crash sometimes so just skip it
504 // return MessageBox(hwnd, szTitle, szMessage, dwFlags);
505 return IDCANCEL;
506 }
507 else
508 {
509 MsgBoxMsg msg = {hwnd, szTitle, szMessage, dwFlags, 0};
510 DWORD dwid;
511 HANDLE hThread = CreateThread(
512 0, // security
513 0, // stack size
514 MsgBoxThread,
515 (void *)&msg, // arg
516 0, // flags
517 &dwid);
518 if(hThread)
519 {
520 WaitForSingleObject(hThread, INFINITE);
521 CloseHandle(hThread);
522 return msg.iResult;
523 }
524
525 // break into debugger on failure.
526 return IDCANCEL;
527 }
528}
529
530/* Displays a message box if the condition evaluated to FALSE */
531
532void WINAPI DbgAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine)
533{
534 if(g_fUseKASSERT)
535 {
536 DbgKernelAssert(pCondition, pFileName, iLine);
537 }
538 else
539 {
540
541 TCHAR szInfo[iDEBUGINFO];
542
543 (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"),
544 pCondition, iLine, pFileName);
545
546 INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"),
547 MB_SYSTEMMODAL |
548 MB_ICONHAND |
549 MB_YESNOCANCEL |
550 MB_SETFOREGROUND);
551 switch (MsgId)
552 {
553 case IDNO: /* Kill the application */
554
555 FatalAppExit(FALSE, TEXT("Application terminated"));
556 break;
557
558 case IDCANCEL: /* Break into the debugger */
559
560 DebugBreak();
561 break;
562
563 case IDYES: /* Ignore assertion continue execution */
564 break;
565 }
566 }
567}
568
569/* Displays a message box at a break point */
570
571void WINAPI DbgBreakPoint(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine)
572{
573 if(g_fUseKASSERT)
574 {
575 DbgKernelAssert(pCondition, pFileName, iLine);
576 }
577 else
578 {
579 TCHAR szInfo[iDEBUGINFO];
580
581 (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%s \nAt line %d of %s\nContinue? (Cancel to debug)"),
582 pCondition, iLine, pFileName);
583
584 INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"),
585 MB_SYSTEMMODAL |
586 MB_ICONHAND |
587 MB_YESNOCANCEL |
588 MB_SETFOREGROUND);
589 switch (MsgId)
590 {
591 case IDNO: /* Kill the application */
592
593 FatalAppExit(FALSE, TEXT("Application terminated"));
594 break;
595
596 case IDCANCEL: /* Break into the debugger */
597
598 DebugBreak();
599 break;
600
601 case IDYES: /* Ignore break point continue execution */
602 break;
603 }
604 }
605}
606
607void WINAPI DbgBreakPoint(LPCTSTR pFileName,INT iLine,__format_string LPCTSTR szFormatString,...)
608{
609 // A debug break point message can have at most 2000 characters if
610 // ANSI or UNICODE characters are being used. A debug break point message
611 // can have between 1000 and 2000 double byte characters in it. If a
612 // particular message needs more characters, then the value of this constant
613 // should be increased.
614 const DWORD MAX_BREAK_POINT_MESSAGE_SIZE = 2000;
615
616 TCHAR szBreakPointMessage[MAX_BREAK_POINT_MESSAGE_SIZE];
617
618 va_list va;
619 va_start( va, szFormatString );
620
621 HRESULT hr = StringCchVPrintf( szBreakPointMessage, NUMELMS(szBreakPointMessage), szFormatString, va );
622
623 va_end(va);
624
625 if( FAILED(hr) ) {
626 DbgBreak( "ERROR in DbgBreakPoint(). The variable length debug message could not be displayed because StringCchVPrintf() failed." );
627 return;
628 }
629
630 ::DbgBreakPoint( szBreakPointMessage, pFileName, iLine );
631}
632
633
634/* When we initialised the library we stored in the m_Levels array the current
635 debug output level for this module for each of the five categories. When
636 some debug logging is sent to us it can be sent with a combination of the
637 categories (if it is applicable to many for example) in which case we map
638 the type's categories into their current debug levels and see if any of
639 them can be accepted. The function looks at each bit position in turn from
640 the input type field and then compares it's debug level with the modules.
641
642 A level of 0 means that output is always sent to the debugger. This is
643 due to producing output if the input level is <= m_Levels.
644*/
645
646
647BOOL WINAPI DbgCheckModuleLevel(DWORD Type,DWORD Level)
648{
649 if(g_fAutoRefreshLevels)
650 {
651 // re-read the registry every second. We cannot use RegNotify() to
652 // notice registry changes because it's not available on win9x.
653 static DWORD g_dwLastRefresh = 0;
654 DWORD dwTime = timeGetTime();
655 if(dwTime - g_dwLastRefresh > 1000) {
656 g_dwLastRefresh = dwTime;
657
658 // there's a race condition: multiple threads could update the
659 // values. plus read and write not synchronized. no harm
660 // though.
661 DbgInitModuleSettings(false);
662 }
663 }
664
665
666 DWORD Mask = 0x01;
667
668 // If no valid bits are set return FALSE
669 if ((Type & ((1<<iMAXLEVELS)-1))) {
670
671 // speed up unconditional output.
672 if (0==Level)
673 return(TRUE);
674
675 for (LONG lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) {
676 if (Type & Mask) {
677 if (Level <= (m_Levels[lKeyPos] & ~LOG_FORCIBLY_SET)) {
678 return TRUE;
679 }
680 }
681 Mask <<= 1;
682 }
683 }
684 return FALSE;
685}
686
687
688/* Set debug levels to a given value */
689
690void WINAPI DbgSetModuleLevel(DWORD Type, DWORD Level)
691{
692 DWORD Mask = 0x01;
693
694 for (LONG lKeyPos = 0;lKeyPos < iMAXLEVELS;lKeyPos++) {
695 if (Type & Mask) {
696 m_Levels[lKeyPos] = Level | LOG_FORCIBLY_SET;
697 }
698 Mask <<= 1;
699 }
700}
701
702/* whether to check registry values periodically. this isn't turned
703 automatically because of the potential performance hit. */
704void WINAPI DbgSetAutoRefreshLevels(bool fAuto)
705{
706 g_fAutoRefreshLevels = fAuto;
707}
708
709#ifdef UNICODE
710//
711// warning -- this function is implemented twice for ansi applications
712// linking to the unicode library
713//
714void WINAPI DbgLogInfo(DWORD Type,DWORD Level,__format_string LPCSTR pFormat,...)
715{
716 /* Check the current level for this type combination */
717
718 BOOL bAccept = DbgCheckModuleLevel(Type,Level);
719 if (bAccept == FALSE) {
720 return;
721 }
722
723 TCHAR szInfo[2000];
724
725 /* Format the variable length parameter list */
726
727 va_list va;
728 va_start(va, pFormat);
729
730 (void)StringCchPrintf(szInfo, NUMELMS(szInfo),
731 TEXT("%s(tid %x) %8d : "),
732 m_ModuleName,
733 GetCurrentThreadId(), timeGetTime() - dwTimeOffset);
734
735 CHAR szInfoA[2000];
736 WideCharToMultiByte(CP_ACP, 0, szInfo, -1, szInfoA, NUMELMS(szInfoA), 0, 0);
737
738 (void)StringCchVPrintfA(szInfoA + lstrlenA(szInfoA), NUMELMS(szInfoA) - lstrlenA(szInfoA), pFormat, va);
739 (void)StringCchCatA(szInfoA, NUMELMS(szInfoA), "\r\n");
740
741 WCHAR wszOutString[2000];
742 MultiByteToWideChar(CP_ACP, 0, szInfoA, -1, wszOutString, NUMELMS(wszOutString));
743 DbgOutString(wszOutString);
744
745 va_end(va);
746}
747
748void WINAPI DbgAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine)
749{
750 if(g_fUseKASSERT)
751 {
752 DbgKernelAssert(pCondition, pFileName, iLine);
753 }
754 else
755 {
756
757 TCHAR szInfo[iDEBUGINFO];
758
759 (void)StringCchPrintf(szInfo, NUMELMS(szInfo), TEXT("%hs \nAt line %d of %hs\nContinue? (Cancel to debug)"),
760 pCondition, iLine, pFileName);
761
762 INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("ASSERT Failed"),
763 MB_SYSTEMMODAL |
764 MB_ICONHAND |
765 MB_YESNOCANCEL |
766 MB_SETFOREGROUND);
767 switch (MsgId)
768 {
769 case IDNO: /* Kill the application */
770
771 FatalAppExit(FALSE, TEXT("Application terminated"));
772 break;
773
774 case IDCANCEL: /* Break into the debugger */
775
776 DebugBreak();
777 break;
778
779 case IDYES: /* Ignore assertion continue execution */
780 break;
781 }
782 }
783}
784
785/* Displays a message box at a break point */
786
787void WINAPI DbgBreakPoint(LPCSTR pCondition,LPCSTR pFileName,INT iLine)
788{
789 if(g_fUseKASSERT)
790 {
791 DbgKernelAssert(pCondition, pFileName, iLine);
792 }
793 else
794 {
795 TCHAR szInfo[iDEBUGINFO];
796
797 (void)StringCchPrintf(szInfo, NUMELMS(szInfo),TEXT("%hs \nAt line %d of %hs\nContinue? (Cancel to debug)"),
798 pCondition, iLine, pFileName);
799
800 INT MsgId = MessageBoxOtherThread(NULL,szInfo,TEXT("Hard coded break point"),
801 MB_SYSTEMMODAL |
802 MB_ICONHAND |
803 MB_YESNOCANCEL |
804 MB_SETFOREGROUND);
805 switch (MsgId)
806 {
807 case IDNO: /* Kill the application */
808
809 FatalAppExit(FALSE, TEXT("Application terminated"));
810 break;
811
812 case IDCANCEL: /* Break into the debugger */
813
814 DebugBreak();
815 break;
816
817 case IDYES: /* Ignore break point continue execution */
818 break;
819 }
820 }
821}
822
823void WINAPI DbgKernelAssert(LPCSTR pCondition,LPCSTR pFileName,INT iLine)
824{
825 DbgLog((LOG_ERROR,0,TEXT("Assertion FAILED (%hs) at line %d in file %hs"),
826 pCondition, iLine, pFileName));
827 DebugBreak();
828}
829
830#endif
831
832/* Print a formatted string to the debugger prefixed with this module's name
833 Because the COMBASE classes are linked statically every module loaded will
834 have their own copy of this code. It therefore helps if the module name is
835 included on the output so that the offending code can be easily found */
836
837//
838// warning -- this function is implemented twice for ansi applications
839// linking to the unicode library
840//
841void WINAPI DbgLogInfo(DWORD Type,DWORD Level,LPCTSTR pFormat,...)
842{
843
844 /* Check the current level for this type combination */
845
846 BOOL bAccept = DbgCheckModuleLevel(Type,Level);
847 if (bAccept == FALSE) {
848 return;
849 }
850
851 TCHAR szInfo[2000];
852
853 /* Format the variable length parameter list */
854
855 va_list va;
856 va_start(va, pFormat);
857
858 (void)StringCchPrintf(szInfo, NUMELMS(szInfo),
859 TEXT("%s(tid %x) %8d : "),
860 m_ModuleName,
861 GetCurrentThreadId(), timeGetTime() - dwTimeOffset);
862
863 (void)StringCchVPrintf(szInfo + lstrlen(szInfo), NUMELMS(szInfo) - lstrlen(szInfo), pFormat, va);
864 (void)StringCchCat(szInfo, NUMELMS(szInfo), TEXT("\r\n"));
865 DbgOutString(szInfo);
866
867 va_end(va);
868}
869
870
871/* If we are executing as a pure kernel filter we cannot display message
872 boxes to the user, this provides an alternative which puts the error
873 condition on the debugger output with a suitable eye catching message */
874
875void WINAPI DbgKernelAssert(LPCTSTR pCondition,LPCTSTR pFileName,INT iLine)
876{
877 DbgLog((LOG_ERROR,0,TEXT("Assertion FAILED (%s) at line %d in file %s"),
878 pCondition, iLine, pFileName));
879 DebugBreak();
880}
881
882
883
884/* Each time we create an object derived from CBaseObject the constructor will
885 call us to register the creation of the new object. We are passed a string
886 description which we store away. We return a cookie that the constructor
887 uses to identify the object when it is destroyed later on. We update the
888 total number of active objects in the DLL mainly for debugging purposes */
889
890DWORD WINAPI DbgRegisterObjectCreation(LPCSTR szObjectName,
891 LPCWSTR wszObjectName)
892{
893 /* If this fires you have a mixed DEBUG/RETAIL build */
894
895 ASSERT(!!szObjectName ^ !!wszObjectName);
896
897 /* Create a place holder for this object description */
898
899 ObjectDesc *pObject = new ObjectDesc;
900 ASSERT(pObject);
901
902 /* It is valid to pass a NULL object name */
903 if (pObject == NULL) {
904 return FALSE;
905 }
906
907 /* Check we have been initialised - we may not be initialised when we are
908 being pulled in from an executable which has globally defined objects
909 as they are created by the C++ run time before WinMain is called */
910
911 if (m_bInit == FALSE) {
912 DbgInitialise(GetModuleHandle(NULL));
913 }
914
915 /* Grab the list critical section */
916 EnterCriticalSection(&m_CSDebug);
917
918 /* If no name then default to UNKNOWN */
919 if (!szObjectName && !wszObjectName) {
920 szObjectName = pUnknownName;
921 }
922
923 /* Put the new description at the head of the list */
924
925 pObject->m_szName = szObjectName;
926 pObject->m_wszName = wszObjectName;
927 pObject->m_dwCookie = ++m_dwNextCookie;
928 pObject->m_pNext = pListHead;
929
930 pListHead = pObject;
931 m_dwObjectCount++;
932
933 DWORD ObjectCookie = pObject->m_dwCookie;
934 ASSERT(ObjectCookie);
935
936 if(wszObjectName) {
937 DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%ls) %d Active"),
938 pObject->m_dwCookie, wszObjectName, m_dwObjectCount));
939 } else {
940 DbgLog((LOG_MEMORY,2,TEXT("Object created %d (%hs) %d Active"),
941 pObject->m_dwCookie, szObjectName, m_dwObjectCount));
942 }
943
944 LeaveCriticalSection(&m_CSDebug);
945 return ObjectCookie;
946}
947
948
949/* This is called by the CBaseObject destructor when an object is about to be
950 destroyed, we are passed the cookie we returned during construction that
951 identifies this object. We scan the object list for a matching cookie and
952 remove the object if successful. We also update the active object count */
953
954BOOL WINAPI DbgRegisterObjectDestruction(DWORD dwCookie)
955{
956 /* Grab the list critical section */
957 EnterCriticalSection(&m_CSDebug);
958
959 ObjectDesc *pObject = pListHead;
960 ObjectDesc *pPrevious = NULL;
961
962 /* Scan the object list looking for a cookie match */
963
964 while (pObject) {
965 if (pObject->m_dwCookie == dwCookie) {
966 break;
967 }
968 pPrevious = pObject;
969 pObject = pObject->m_pNext;
970 }
971
972 if (pObject == NULL) {
973 DbgBreak("Apparently destroying a bogus object");
974 LeaveCriticalSection(&m_CSDebug);
975 return FALSE;
976 }
977
978 /* Is the object at the head of the list */
979
980 if (pPrevious == NULL) {
981 pListHead = pObject->m_pNext;
982 } else {
983 pPrevious->m_pNext = pObject->m_pNext;
984 }
985
986 /* Delete the object and update the housekeeping information */
987
988 m_dwObjectCount--;
989
990 if(pObject->m_wszName) {
991 DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%ls) %d Active"),
992 pObject->m_dwCookie, pObject->m_wszName, m_dwObjectCount));
993 } else {
994 DbgLog((LOG_MEMORY,2,TEXT("Object destroyed %d (%hs) %d Active"),
995 pObject->m_dwCookie, pObject->m_szName, m_dwObjectCount));
996 }
997
998 delete pObject;
999 LeaveCriticalSection(&m_CSDebug);
1000 return TRUE;
1001}
1002
1003
1004/* This runs through the active object list displaying their details */
1005
1006void WINAPI DbgDumpObjectRegister()
1007{
1008 TCHAR szInfo[iDEBUGINFO];
1009
1010 /* Grab the list critical section */
1011
1012 EnterCriticalSection(&m_CSDebug);
1013 ObjectDesc *pObject = pListHead;
1014
1015 /* Scan the object list displaying the name and cookie */
1016
1017 DbgLog((LOG_MEMORY,2,TEXT("")));
1018 DbgLog((LOG_MEMORY,2,TEXT(" ID Object Description")));
1019 DbgLog((LOG_MEMORY,2,TEXT("")));
1020
1021 while (pObject) {
1022 if(pObject->m_wszName) {
1023 (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30ls"),pObject->m_dwCookie, &pObject, pObject->m_wszName);
1024 } else {
1025 (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("%5d (%p) %30hs"),pObject->m_dwCookie, &pObject, pObject->m_szName);
1026 }
1027 DbgLog((LOG_MEMORY,2,szInfo));
1028 pObject = pObject->m_pNext;
1029 }
1030
1031 (void)StringCchPrintf(szInfo,NUMELMS(szInfo),TEXT("Total object count %5d"),m_dwObjectCount);
1032 DbgLog((LOG_MEMORY,2,TEXT("")));
1033 DbgLog((LOG_MEMORY,1,szInfo));
1034 LeaveCriticalSection(&m_CSDebug);
1035}
1036
1037/* Debug infinite wait stuff */
1038DWORD WINAPI DbgWaitForSingleObject(HANDLE h)
1039{
1040 DWORD dwWaitResult;
1041 do {
1042 dwWaitResult = WaitForSingleObject(h, dwWaitTimeout);
1043 ASSERT(dwWaitResult == WAIT_OBJECT_0);
1044 } while (dwWaitResult == WAIT_TIMEOUT);
1045 return dwWaitResult;
1046}
1047DWORD WINAPI DbgWaitForMultipleObjects(DWORD nCount,
1048 __in_ecount(nCount) CONST HANDLE *lpHandles,
1049 BOOL bWaitAll)
1050{
1051 DWORD dwWaitResult;
1052 do {
1053 dwWaitResult = WaitForMultipleObjects(nCount,
1054 lpHandles,
1055 bWaitAll,
1056 dwWaitTimeout);
1057 ASSERT((DWORD)(dwWaitResult - WAIT_OBJECT_0) < MAXIMUM_WAIT_OBJECTS);
1058 } while (dwWaitResult == WAIT_TIMEOUT);
1059 return dwWaitResult;
1060}
1061
1062void WINAPI DbgSetWaitTimeout(DWORD dwTimeout)
1063{
1064 dwWaitTimeout = dwTimeout;
1065}
1066
1067#endif /* DEBUG */
1068
1069#ifdef _OBJBASE_H_
1070
1071 /* Stuff for printing out our GUID names */
1072
1073 GUID_STRING_ENTRY g_GuidNames[] = {
1074 #define OUR_GUID_ENTRY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
1075 { #name, { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } },
1076 #include <uuids.h>
1077 };
1078
1079 CGuidNameList GuidNames;
1080 int g_cGuidNames = sizeof(g_GuidNames) / sizeof(g_GuidNames[0]);
1081
1082 char *CGuidNameList::operator [] (const GUID &guid)
1083 {
1084 for (int i = 0; i < g_cGuidNames; i++) {
1085 if (g_GuidNames[i].guid == guid) {
1086 return g_GuidNames[i].szName;
1087 }
1088 }
1089 if (guid == GUID_NULL) {
1090 return "GUID_NULL";
1091 }
1092
1093 // !!! add something to print FOURCC guids?
1094
1095 // shouldn't this print the hex CLSID?
1096 return "Unknown GUID Name";
1097 }
1098
1099#endif /* _OBJBASE_H_ */
1100
1101/* CDisp class - display our data types */
1102
1103// clashes with REFERENCE_TIME
1104CDisp::CDisp(LONGLONG ll, int Format)
1105{
1106 // note: this could be combined with CDisp(LONGLONG) by
1107 // introducing a default format of CDISP_REFTIME
1108 LARGE_INTEGER li;
1109 li.QuadPart = ll;
1110 switch (Format) {
1111 case CDISP_DEC:
1112 {
1113 TCHAR temp[20];
1114 int pos=20;
1115 temp[--pos] = 0;
1116 int digit;
1117 // always output at least one digit
1118 do {
1119 // Get the rightmost digit - we only need the low word
1120 digit = li.LowPart % 10;
1121 li.QuadPart /= 10;
1122 temp[--pos] = (TCHAR) digit+L'0';
1123 } while (li.QuadPart);
1124 (void)StringCchCopy(m_String, NUMELMS(m_String), temp+pos);
1125 break;
1126 }
1127 case CDISP_HEX:
1128 default:
1129 (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("0x%X%8.8X"), li.HighPart, li.LowPart);
1130 }
1131};
1132
1133CDisp::CDisp(REFCLSID clsid)
1134{
1135#ifdef UNICODE
1136 (void)StringFromGUID2(clsid, m_String, NUMELMS(m_String));
1137#else
1138 WCHAR wszTemp[50];
1139 (void)StringFromGUID2(clsid, wszTemp, NUMELMS(wszTemp));
1140 (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%S"), wszTemp);
1141#endif
1142};
1143
1144#ifdef __STREAMS__
1145/* Display stuff */
1146CDisp::CDisp(CRefTime llTime)
1147{
1148 LONGLONG llDiv;
1149 if (llTime < 0) {
1150 llTime = -llTime;
1151 (void)StringCchCopy(m_String, NUMELMS(m_String), TEXT("-"));
1152 }
1153 llDiv = (LONGLONG)24 * 3600 * 10000000;
1154 if (llTime >= llDiv) {
1155 (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d days "), (LONG)(llTime / llDiv));
1156 llTime = llTime % llDiv;
1157 }
1158 llDiv = (LONGLONG)3600 * 10000000;
1159 if (llTime >= llDiv) {
1160 (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d hrs "), (LONG)(llTime / llDiv));
1161 llTime = llTime % llDiv;
1162 }
1163 llDiv = (LONGLONG)60 * 10000000;
1164 if (llTime >= llDiv) {
1165 (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d mins "), (LONG)(llTime / llDiv));
1166 llTime = llTime % llDiv;
1167 }
1168 (void)StringCchPrintf(m_String + lstrlen(m_String), NUMELMS(m_String) - lstrlen(m_String), TEXT("%d.%3.3d sec"),
1169 (LONG)llTime / 10000000,
1170 (LONG)((llTime % 10000000) / 10000));
1171};
1172
1173#endif // __STREAMS__
1174
1175
1176/* Display pin */
1177CDisp::CDisp(IPin *pPin)
1178{
1179 PIN_INFO pi;
1180 TCHAR str[MAX_PIN_NAME];
1181 CLSID clsid;
1182
1183 if (pPin) {
1184 pPin->QueryPinInfo(&pi);
1185 pi.pFilter->GetClassID(&clsid);
1186 QueryPinInfoReleaseFilter(pi);
1187 #ifndef UNICODE
1188 WideCharToMultiByte(GetACP(), 0, pi.achName, lstrlenW(pi.achName) + 1,
1189 str, MAX_PIN_NAME, NULL, NULL);
1190 #else
1191 (void)StringCchCopy(str, NUMELMS(str), pi.achName);
1192 #endif
1193 } else {
1194 (void)StringCchCopy(str, NUMELMS(str), TEXT("NULL IPin"));
1195 }
1196
1197 m_pString = (PTCHAR) new TCHAR[lstrlen(str)+64];
1198 if (!m_pString) {
1199 return;
1200 }
1201
1202 (void)StringCchPrintf(m_pString, lstrlen(str) + 64, TEXT("%hs(%s)"), GuidNames[clsid], str);
1203}
1204
1205/* Display filter or pin */
1206CDisp::CDisp(IUnknown *pUnk)
1207{
1208 IBaseFilter *pf;
1209 HRESULT hr = pUnk->QueryInterface(IID_IBaseFilter, (void **)&pf);
1210 if(SUCCEEDED(hr))
1211 {
1212 FILTER_INFO fi;
1213 hr = pf->QueryFilterInfo(&fi);
1214 if(SUCCEEDED(hr))
1215 {
1216 QueryFilterInfoReleaseGraph(fi);
1217
1218 size_t len = lstrlenW(fi.achName) + 1;
1219
1220 m_pString = new TCHAR[len];
1221 if(m_pString)
1222 {
1223#ifdef UNICODE
1224 (void)StringCchCopy(m_pString, len, fi.achName);
1225#else
1226 (void)StringCchPrintf(m_pString, len, "%S", fi.achName);
1227#endif
1228 }
1229 }
1230
1231 pf->Release();
1232
1233 return;
1234 }
1235
1236 IPin *pp;
1237 hr = pUnk->QueryInterface(IID_IPin, (void **)&pp);
1238 if(SUCCEEDED(hr))
1239 {
1240 CDisp::CDisp(pp);
1241 pp->Release();
1242 return;
1243 }
1244}
1245
1246
1247CDisp::~CDisp()
1248{
1249}
1250
1251CDispBasic::~CDispBasic()
1252{
1253 if (m_pString != m_String) {
1254 delete [] m_pString;
1255 }
1256}
1257
1258CDisp::CDisp(double d)
1259{
1260 (void)StringCchPrintf(m_String, NUMELMS(m_String), TEXT("%d.%03d"), (int) d, (int) ((d - (int) d) * 1000));
1261}
1262
1263
1264/* If built for debug this will display the media type details. We convert the
1265 major and subtypes into strings and also ask the base classes for a string
1266 description of the subtype, so MEDIASUBTYPE_RGB565 becomes RGB 565 16 bit
1267 We also display the fields in the BITMAPINFOHEADER structure, this should
1268 succeed as we do not accept input types unless the format is big enough */
1269
1270#ifdef DEBUG
1271void WINAPI DisplayType(LPCTSTR label, const AM_MEDIA_TYPE *pmtIn)
1272{
1273
1274 /* Dump the GUID types and a short description */
1275
1276 DbgLog((LOG_TRACE,5,TEXT("")));
1277 DbgLog((LOG_TRACE,2,TEXT("%s M type %hs S type %hs"), label,
1278 GuidNames[pmtIn->majortype],
1279 GuidNames[pmtIn->subtype]));
1280 DbgLog((LOG_TRACE,5,TEXT("Subtype description %s"),GetSubtypeName(&pmtIn->subtype)));
1281
1282 /* Dump the generic media types */
1283
1284 if (pmtIn->bTemporalCompression) {
1285 DbgLog((LOG_TRACE,5,TEXT("Temporally compressed")));
1286 } else {
1287 DbgLog((LOG_TRACE,5,TEXT("Not temporally compressed")));
1288 }
1289
1290 if (pmtIn->bFixedSizeSamples) {
1291 DbgLog((LOG_TRACE,5,TEXT("Sample size %d"),pmtIn->lSampleSize));
1292 } else {
1293 DbgLog((LOG_TRACE,5,TEXT("Variable size samples")));
1294 }
1295
1296 if (pmtIn->formattype == FORMAT_VideoInfo) {
1297
1298 VIDEOINFOHEADER *pVideoInfo = (VIDEOINFOHEADER *)pmtIn->pbFormat;
1299
1300 DisplayRECT(TEXT("Source rectangle"),pVideoInfo->rcSource);
1301 DisplayRECT(TEXT("Target rectangle"),pVideoInfo->rcTarget);
1302 DisplayBITMAPINFO(HEADER(pmtIn->pbFormat));
1303
1304 } if (pmtIn->formattype == FORMAT_VideoInfo2) {
1305
1306 VIDEOINFOHEADER2 *pVideoInfo2 = (VIDEOINFOHEADER2 *)pmtIn->pbFormat;
1307
1308 DisplayRECT(TEXT("Source rectangle"),pVideoInfo2->rcSource);
1309 DisplayRECT(TEXT("Target rectangle"),pVideoInfo2->rcTarget);
1310 DbgLog((LOG_TRACE, 5, TEXT("Aspect Ratio: %d:%d"),
1311 pVideoInfo2->dwPictAspectRatioX,
1312 pVideoInfo2->dwPictAspectRatioY));
1313 DisplayBITMAPINFO(&pVideoInfo2->bmiHeader);
1314
1315 } else if (pmtIn->majortype == MEDIATYPE_Audio) {
1316 DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"),
1317 GuidNames[pmtIn->formattype]));
1318 DbgLog((LOG_TRACE,2,TEXT(" Subtype %hs"),
1319 GuidNames[pmtIn->subtype]));
1320
1321 if ((pmtIn->subtype != MEDIASUBTYPE_MPEG1Packet)
1322 && (pmtIn->cbFormat >= sizeof(PCMWAVEFORMAT)))
1323 {
1324 /* Dump the contents of the WAVEFORMATEX type-specific format structure */
1325
1326 WAVEFORMATEX *pwfx = (WAVEFORMATEX *) pmtIn->pbFormat;
1327 DbgLog((LOG_TRACE,2,TEXT("wFormatTag %u"), pwfx->wFormatTag));
1328 DbgLog((LOG_TRACE,2,TEXT("nChannels %u"), pwfx->nChannels));
1329 DbgLog((LOG_TRACE,2,TEXT("nSamplesPerSec %lu"), pwfx->nSamplesPerSec));
1330 DbgLog((LOG_TRACE,2,TEXT("nAvgBytesPerSec %lu"), pwfx->nAvgBytesPerSec));
1331 DbgLog((LOG_TRACE,2,TEXT("nBlockAlign %u"), pwfx->nBlockAlign));
1332 DbgLog((LOG_TRACE,2,TEXT("wBitsPerSample %u"), pwfx->wBitsPerSample));
1333
1334 /* PCM uses a WAVEFORMAT and does not have the extra size field */
1335
1336 if (pmtIn->cbFormat >= sizeof(WAVEFORMATEX)) {
1337 DbgLog((LOG_TRACE,2,TEXT("cbSize %u"), pwfx->cbSize));
1338 }
1339 } else {
1340 }
1341
1342 } else {
1343 DbgLog((LOG_TRACE,2,TEXT(" Format type %hs"),
1344 GuidNames[pmtIn->formattype]));
1345 }
1346}
1347
1348
1349void DisplayBITMAPINFO(const BITMAPINFOHEADER* pbmi)
1350{
1351 DbgLog((LOG_TRACE,5,TEXT("Size of BITMAPINFO structure %d"),pbmi->biSize));
1352 if (pbmi->biCompression < 256) {
1353 DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit (%d)"),
1354 pbmi->biWidth, pbmi->biHeight,
1355 pbmi->biBitCount, pbmi->biCompression));
1356 } else {
1357 DbgLog((LOG_TRACE,2,TEXT("%dx%dx%d bit '%4.4hs'"),
1358 pbmi->biWidth, pbmi->biHeight,
1359 pbmi->biBitCount, &pbmi->biCompression));
1360 }
1361
1362 DbgLog((LOG_TRACE,2,TEXT("Image size %d"),pbmi->biSizeImage));
1363 DbgLog((LOG_TRACE,5,TEXT("Planes %d"),pbmi->biPlanes));
1364 DbgLog((LOG_TRACE,5,TEXT("X Pels per metre %d"),pbmi->biXPelsPerMeter));
1365 DbgLog((LOG_TRACE,5,TEXT("Y Pels per metre %d"),pbmi->biYPelsPerMeter));
1366 DbgLog((LOG_TRACE,5,TEXT("Colours used %d"),pbmi->biClrUsed));
1367}
1368
1369
1370void DisplayRECT(LPCTSTR szLabel, const RECT& rc)
1371{
1372 DbgLog((LOG_TRACE,5,TEXT("%s (Left %d Top %d Right %d Bottom %d)"),
1373 szLabel,
1374 rc.left,
1375 rc.top,
1376 rc.right,
1377 rc.bottom));
1378}
1379
1380
1381void WINAPI DumpGraph(IFilterGraph *pGraph, DWORD dwLevel)
1382{
1383 if( !pGraph )
1384 {
1385 return;
1386 }
1387
1388 IEnumFilters *pFilters;
1389
1390 DbgLog((LOG_TRACE,dwLevel,TEXT("DumpGraph [%x]"), pGraph));
1391
1392 if (FAILED(pGraph->EnumFilters(&pFilters))) {
1393 DbgLog((LOG_TRACE,dwLevel,TEXT("EnumFilters failed!")));
1394 }
1395
1396 IBaseFilter *pFilter;
1397 ULONG n;
1398 while (pFilters->Next(1, &pFilter, &n) == S_OK) {
1399 FILTER_INFO info;
1400
1401 if (FAILED(pFilter->QueryFilterInfo(&info))) {
1402 DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%p] -- failed QueryFilterInfo"), pFilter));
1403 } else {
1404 QueryFilterInfoReleaseGraph(info);
1405
1406 // !!! should QueryVendorInfo here!
1407
1408 DbgLog((LOG_TRACE,dwLevel,TEXT(" Filter [%p] '%ls'"), pFilter, info.achName));
1409
1410 IEnumPins *pins;
1411
1412 if (FAILED(pFilter->EnumPins(&pins))) {
1413 DbgLog((LOG_TRACE,dwLevel,TEXT("EnumPins failed!")));
1414 } else {
1415
1416 IPin *pPin;
1417 while (pins->Next(1, &pPin, &n) == S_OK) {
1418 PIN_INFO pinInfo;
1419
1420 if (FAILED(pPin->QueryPinInfo(&pinInfo))) {
1421 DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%x] -- failed QueryPinInfo"), pPin));
1422 } else {
1423 QueryPinInfoReleaseFilter(pinInfo);
1424
1425 IPin *pPinConnected = NULL;
1426
1427 HRESULT hr = pPin->ConnectedTo(&pPinConnected);
1428
1429 if (pPinConnected) {
1430 DbgLog((LOG_TRACE,dwLevel,TEXT(" Pin [%p] '%ls' [%sput]")
1431 TEXT(" Connected to pin [%p]"),
1432 pPin, pinInfo.achName,
1433 pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out"),
1434 pPinConnected));
1435
1436 pPinConnected->Release();
1437
1438 // perhaps we should really dump the type both ways as a sanity
1439 // check?
1440 if (pinInfo.dir == PINDIR_OUTPUT) {
1441 AM_MEDIA_TYPE mt;
1442
1443 hr = pPin->ConnectionMediaType(&mt);
1444
1445 if (SUCCEEDED(hr)) {
1446 DisplayType(TEXT("Connection type"), &mt);
1447
1448 FreeMediaType(mt);
1449 }
1450 }
1451 } else {
1452 DbgLog((LOG_TRACE,dwLevel,
1453 TEXT(" Pin [%x] '%ls' [%sput]"),
1454 pPin, pinInfo.achName,
1455 pinInfo.dir == PINDIR_INPUT ? TEXT("In") : TEXT("Out")));
1456
1457 }
1458 }
1459
1460 pPin->Release();
1461
1462 }
1463
1464 pins->Release();
1465 }
1466
1467 }
1468
1469 pFilter->Release();
1470 }
1471
1472 pFilters->Release();
1473
1474}
1475
1476#endif
1477
1478#endif /* PJMEDIA_VIDEO_DEV_HAS_DSHOW */