source: trunk/DirectShowSpy/RunPropertyBag.h @ 545

Last change on this file since 545 was 493, checked in by roman, 9 years ago

Avoid unneeded exceptions while logging IQualProp, IAMAudioRendererStats

File size: 14.7 KB
Line 
1////////////////////////////////////////////////////////////
2// Copyright (C) Roman Ryltsov, 2008-2015
3// Created by Roman Ryltsov roman@alax.info, http://alax.info
4//
5// This source code is published to complement DirectShowSpy developer powertoy
6// and demonstrate the internal use of APIs and tricks powering the tool. It is
7// allowed to freely re-use the portions of the code in other projects, commercial
8// or otherwise (provided that you don’t pretend that you wrote the original tool).
9//
10// Please keep in mind that DirectShowSpy is a developer tool, it is strongly recommended
11// that it is not shipped with release grade software. It is allowed to distribute
12// DirectShowSpy if only it is not registered with Windows by default and either
13// used privately, or registered on specific throubleshooting request. The advice applies
14// to hooking methods used by DirectShowSpy in general as well.
15
16#pragma once
17
18#include "Module_i.h"
19#include "Common.h"
20
21////////////////////////////////////////////////////////////
22// CRunPropertyBagHelper
23
24class CRunPropertyBagHelper
25{
26public:
27
28        ////////////////////////////////////////////////////////
29        // CSimpleSortTraitsT
30
31        class CNameSortTraits :
32                public CSimpleSortTraitsT<CString>
33        {
34        public:
35        // CNameSortTraits
36                static INT_PTR CompareElements(const CString& sElementA, const CString& sElementB, PARAMETERARGUMENT Parameter)
37                {
38                        return _tcsicmp(sElementA, sElementB);
39                }
40        };
41
42protected:
43        static CObjectPtr<CMemoryPropertyBag>& PropertyBagNeeded(CObjectPtr<CMemoryPropertyBag>& pPropertyBag)
44        {
45                if(!pPropertyBag)
46                        pPropertyBag.Construct();
47                return pPropertyBag;
48        }
49
50public:
51// CRunPropertyBagHelper
52        static CComVariantArray ReadRunPropertyBag(IUnknown* pBaseFilterUnknown, BOOL bAllowExtension = TRUE)
53        {
54                CComVariantArray vValue;
55                CRoArrayT<CComVariantArray> Array;
56                const CComQIPtr<DIRECTSHOWSPY_NAMESPACE_PREFIX IRunPropertyBagAware> pRunPropertyBagAware = pBaseFilterUnknown;
57                CComQIPtr<IPropertyBag2> pPropertyBag2;
58                #pragma region Extension
59                if(!pRunPropertyBagAware && bAllowExtension)
60                {
61                        CObjectPtr<CMemoryPropertyBag> pPropertyBag;
62                        #pragma region IQualProp
63                        const CComQIPtr<IQualProp, &IID_IQualProp> pQualProp = pBaseFilterUnknown;
64                        if(pQualProp)
65                                _ATLTRY
66                                {
67                                        PropertyBagNeeded(pPropertyBag);
68                                        // NOTE: IQualProp methods are not implemented on EVR even though the interface itself is exposed
69                                        INT nFramesDroppedInRenderer, nFramesDrawn, nAvgFrameRate, nJitter, nAvgSyncOffset, nDevSyncOffset;
70                                        if(SUCCEEDED(pQualProp->get_FramesDroppedInRenderer(&nFramesDroppedInRenderer)))
71                                                pPropertyBag->WriteValue(_T("FramesDroppedInRenderer"), CComVariant((LONG) nFramesDroppedInRenderer));
72                                        if(SUCCEEDED(pQualProp->get_FramesDrawn(&nFramesDrawn)))
73                                                pPropertyBag->WriteValue(_T("FramesDrawn"), CComVariant((LONG) nFramesDrawn));
74                                        if(SUCCEEDED(pQualProp->get_AvgFrameRate(&nAvgFrameRate)))
75                                                pPropertyBag->WriteValue(_T("AvgFrameRate"), CComVariant((DOUBLE) nAvgFrameRate / 100));
76                                        if(SUCCEEDED(pQualProp->get_Jitter(&nJitter)))
77                                                pPropertyBag->WriteValue(_T("Jitter"), CComVariant((LONG) nJitter));
78                                        if(SUCCEEDED(pQualProp->get_AvgSyncOffset(&nAvgSyncOffset)))
79                                                pPropertyBag->WriteValue(_T("AvgSyncOffset"), CComVariant((LONG) nAvgSyncOffset));
80                                        if(SUCCEEDED(pQualProp->get_DevSyncOffset(&nDevSyncOffset)))
81                                                pPropertyBag->WriteValue(_T("DevSyncOffset"), CComVariant((LONG) nDevSyncOffset));
82                                }
83                                _ATLCATCHALL()
84                                {
85                                        _Z_EXCEPTION();
86                                }
87                        #pragma endregion
88                        #pragma region IAMAudioRendererStats
89                        const CComQIPtr<IAMAudioRendererStats> pAmAudioRendererStats = pBaseFilterUnknown;
90                        if(pAmAudioRendererStats)
91                                _ATLTRY
92                                {
93                                        PropertyBagNeeded(pPropertyBag);
94                                        DWORD nDummy;
95                                        DWORD nBreakCount, nSlaveMode, nSilenceDuration, nLastBufferDuration, nDiscontinuityCount, nSlaveRate, nDropWriteDuration;
96                                        DWORD nHighestSlaveError, nLowestSlaveError, nLastHighSlaveError, nLastLowSlaveError;
97                                        DWORD nAccumulatedError, nBufferFullness;
98                                        DWORD nJitter;
99                                        if(SUCCEEDED(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_BREAK_COUNT, &nBreakCount, &nDummy)))
100                                                pPropertyBag->WriteValue(_T("BreakCount"), CComVariant((LONG) nBreakCount));
101                                        if(SUCCEEDED(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_MODE, &nSlaveMode, &nDummy)))
102                                        {
103                                                pPropertyBag->WriteValue(_T("SlaveMode"), CComVariant((LONG) nSlaveMode));
104                                                if(nSlaveMode)
105                                                {
106                                                        if(SUCCEEDED(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_RATE, &nSlaveRate, &nDummy)))
107                                                                pPropertyBag->WriteValue(_T("SlaveRate"), CComVariant((LONG) nSlaveRate));
108                                                        if(SUCCEEDED(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_DROPWRITE_DUR, &nDropWriteDuration, &nDummy)))
109                                                                pPropertyBag->WriteValue(_T("DropWriteDuration"), CComVariant((LONG) nDropWriteDuration));
110                                                        if(SUCCEEDED(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_HIGHLOWERROR, &nHighestSlaveError, &nLowestSlaveError)))
111                                                        {
112                                                                pPropertyBag->WriteValue(_T("HighestSlaveError"), CComVariant((LONG) nHighestSlaveError));
113                                                                pPropertyBag->WriteValue(_T("LowestSlaveError"), CComVariant((LONG) nLowestSlaveError));
114                                                        }
115                                                        if(SUCCEEDED(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_LASTHIGHLOWERROR, &nLastHighSlaveError, &nLastLowSlaveError)))
116                                                        {
117                                                                pPropertyBag->WriteValue(_T("LastHighSlaveError"), CComVariant((LONG) nLastHighSlaveError));
118                                                                pPropertyBag->WriteValue(_T("LastLowSlaveError"), CComVariant((LONG) nLastLowSlaveError));
119                                                        }
120                                                        if(SUCCEEDED(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_SLAVE_ACCUMERROR, &nAccumulatedError, &nDummy)))
121                                                                pPropertyBag->WriteValue(_T("AccumulatedError"), CComVariant((LONG) nAccumulatedError));
122                                                }
123                                        }
124                                        if(SUCCEEDED(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_SILENCE_DUR, &nSilenceDuration, &nDummy)))
125                                                pPropertyBag->WriteValue(_T("SilenceDuration"), CComVariant((LONG) nSilenceDuration));
126                                        if(SUCCEEDED(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_LAST_BUFFER_DUR, &nLastBufferDuration, &nDummy)))
127                                                pPropertyBag->WriteValue(_T("LastBufferDuration"), CComVariant((LONG) nLastBufferDuration));
128                                        if(SUCCEEDED(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_DISCONTINUITIES, &nDiscontinuityCount, &nDummy)))
129                                                pPropertyBag->WriteValue(_T("DiscontinuityCount"), CComVariant((LONG) nDiscontinuityCount));
130                                        if(SUCCEEDED(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_BUFFERFULLNESS, &nBufferFullness, &nDummy)))
131                                                pPropertyBag->WriteValue(_T("BufferFullness"), CComVariant((LONG) nBufferFullness));
132                                        if(SUCCEEDED(pAmAudioRendererStats->GetStatParam(AM_AUDREND_STAT_PARAM_JITTER, &nJitter, &nDummy)))
133                                                pPropertyBag->WriteValue(_T("Jitter"), CComVariant((LONG) nJitter));
134                                }
135                                _ATLCATCHALL()
136                                {
137                                        _Z_EXCEPTION();
138                                }
139                        #pragma endregion
140                        if(pPropertyBag)
141                                pPropertyBag2 = pPropertyBag;
142                }
143                #pragma endregion
144                if(!pPropertyBag2 && pRunPropertyBagAware)
145                {
146                        CComPtr<IUnknown> pPropertyBagUnknown;
147                        __C(pRunPropertyBagAware->get_Value(&pPropertyBagUnknown));
148                        pPropertyBag2 = pPropertyBagUnknown;
149                }
150                if(pPropertyBag2)
151                {
152                        ULONG nPropertyCount = 0;
153                        __C(pPropertyBag2->CountProperties(&nPropertyCount));
154                        _Z4(atlTraceGeneral, 4, _T("nPropertyCount %d\n"), nPropertyCount);
155                        if(nPropertyCount)
156                        {
157                                CTempBufferT<PROPBAG2> pPropBags(nPropertyCount);
158                                ZeroMemory((PROPBAG2*) pPropBags, nPropertyCount * sizeof *pPropBags);
159                                ULONG nPropBagCount = 0;
160                                __C(pPropertyBag2->GetPropertyInfo(0, nPropertyCount, pPropBags, &nPropBagCount));
161                                _Z4(atlTraceGeneral, 4, _T("nPropBagCount %d\n"), nPropBagCount);
162                                CRoListT<CComHeapPtr<OLECHAR>> NameList;
163                                for(ULONG nIndex = 0; nIndex < nPropBagCount; nIndex++)
164                                        NameList.GetAt(NameList.AddTail()).Attach(pPropBags[nIndex].pstrName);
165                                CRoArrayT<CComVariantArray> ValueArray;
166                                __D(ValueArray.SetCount(nPropBagCount), E_OUTOFMEMORY);
167                                CTempBufferT<HRESULT> pnResults(nPropBagCount);
168                                __C(pPropertyBag2->Read(nPropBagCount, pPropBags, NULL, ValueArray.GetData(), pnResults));
169                                for(ULONG nIndex = 0; nIndex < nPropBagCount; nIndex++)
170                                        if(SUCCEEDED(pnResults[nIndex]))
171                                        {
172                                                CString sName(pPropBags[nIndex].pstrName);
173                                                _Z4(atlTraceGeneral, 4, _T("sName \"%s\"\n"), sName);
174                                                CComVariantArray vPropertyValue;
175                                                Array.Add(vPropertyValue.FromElements(2, CComVariant(sName), ValueArray[nIndex]));
176                                        }
177                                vValue.FromElementArray(Array);
178                        }
179                }
180                return vValue;
181        }
182        static CString GetPropertyBagText(CRoArrayT<CString>& NameArray, CRoMapT<CString, CComVariantArray>& Map)
183        {
184                CString sText;
185                _SortHelper::QuickSort<CNameSortTraits>(NameArray);
186                // SUGG: Nicer similar names, taking prefix at dot separator, also changing Foo-A-B into Foo (A; B)
187                for(SIZE_T nIndex = 0; nIndex < NameArray.GetCount(); nIndex++)
188                {
189                        const CString& sName = NameArray[nIndex];
190                        _Z4(atlTraceGeneral, 4, _T("sName \"%s\"\n"), sName);
191                        CString sValue;
192                        CComVariantArray vValue;
193                        if(!Map.Lookup(sName, vValue))
194                                continue;
195                        CString sComment;
196                        #pragma region Friendly Comment
197                        switch(vValue.vt)
198                        {
199                        #pragma region VT_I4
200                        case VT_I4:
201                                if(vValue.lVal < -999 || vValue.lVal > 999)
202                                        sComment = _StringHelper::FormatNumber(vValue.lVal);
203                                break;
204                        #pragma endregion
205                        #pragma region VT_R8
206                        case VT_R8:
207                                if(vValue.dblVal > -0.001 || vValue.dblVal < 0.001)
208                                        sComment = _StringHelper::FormatNumber(vValue.dblVal, 6);
209                                else 
210                                if(vValue.lVal < -999.0 || vValue.lVal > 999.0)
211                                        sComment = _StringHelper::FormatNumber(vValue.dblVal, 1);
212                                break;
213                        #pragma endregion
214                        }
215                        #pragma endregion
216                        const HRESULT nChangeTypeResult = vValue.ChangeType(VT_BSTR);
217                        _Z45_HRESULT(nChangeTypeResult);
218                        if(FAILED(nChangeTypeResult))
219                                continue;
220                        sText.AppendFormat(_T(" * ") _T("`%s`: `%s`"), sName, CString(vValue.bstrVal));
221                        if(!sComment.IsEmpty())
222                                sText.AppendFormat(_T(" // %s"), sComment);
223                        sText.Append(_T("\r\n"));
224                }
225                return sText;
226        }
227        static ATL_DEPRECATED("Convert IPropertyBag2 into VARIANT using ISpy or CSpy instead") CString GetPropertyBagText(IPropertyBag2* pPropertyBag2)
228        {
229                _A(pPropertyBag2);
230                CString sText;
231                ULONG nPropertyCount = 0;
232                __C(pPropertyBag2->CountProperties(&nPropertyCount));
233                _Z4(atlTraceGeneral, 4, _T("nPropertyCount %d\n"), nPropertyCount);
234                if(!nPropertyCount)
235                        return sText;
236                #pragma region Read
237                CTempBufferT<PROPBAG2> pPropBags(nPropertyCount);
238                ZeroMemory((PROPBAG2*) pPropBags, nPropertyCount * sizeof *pPropBags);
239                ULONG nPropBagCount = 0;
240                __C(pPropertyBag2->GetPropertyInfo(0, nPropertyCount, pPropBags, &nPropBagCount));
241                _Z4(atlTraceGeneral, 4, _T("nPropBagCount %d\n"), nPropBagCount);
242                CRoListT<CComHeapPtr<OLECHAR>> NameList;
243                for(ULONG nIndex = 0; nIndex < nPropBagCount; nIndex++)
244                        NameList.GetAt(NameList.AddTail()).Attach(pPropBags[nIndex].pstrName);
245                CRoArrayT<CComVariantArray> ValueArray;
246                __D(ValueArray.SetCount(nPropBagCount), E_OUTOFMEMORY);
247                CTempBufferT<HRESULT> pnResults(nPropBagCount);
248                __C(pPropertyBag2->Read(nPropBagCount, pPropBags, NULL, ValueArray.GetData(), pnResults));
249                #pragma endregion
250                CRoMapT<CString, CComVariantArray> Map;
251                CRoArrayT<CString> NameArray;
252                for(ULONG nIndex = 0; nIndex < nPropBagCount; nIndex++)
253                        if(SUCCEEDED(pnResults[nIndex]))
254                        {
255                                CString sName(pPropBags[nIndex].pstrName);
256                                _Z4(atlTraceGeneral, 4, _T("sName \"%s\"\n"), sName);
257                                NameArray.Add(sName);
258                                _W(Map.SetAt(sName, ValueArray[nIndex]));
259                        }
260                return GetPropertyBagText(NameArray, Map);
261        }
262        static CString GetPropertyBagText(CComVariantArray& vValue)
263        {
264                if(vValue.vt <= VT_NULL)
265                        return _T("");
266                CRoArrayT<CComVariantArray> Array;
267                vValue.ToElementArray(Array);
268                CRoMapT<CString, CComVariantArray> Map;
269                CRoArrayT<CString> NameArray;
270                for(SIZE_T nIndex = 0; nIndex < Array.GetCount(); nIndex++)
271                {
272                        CComVariantArray vPropertyName, vPropertyValue;
273                        Array[nIndex].ToElements(2, &vPropertyName, &vPropertyValue);
274                        __C(vPropertyName.ChangeType(VT_BSTR));
275                        CString sName(vPropertyName.bstrVal);
276                        _Z4(atlTraceGeneral, 4, _T("sName \"%s\"\n"), sName);
277                        NameArray.Add(sName);
278                        _W(Map.SetAt(sName, vPropertyValue));
279                }
280                return GetPropertyBagText(NameArray, Map);
281        }
282        static CString GetPropertyBagText(VARIANT vValue)
283        {
284                return GetPropertyBagText(reinterpret_cast<CComVariantArray&>(vValue));
285        }
286        __if_exists(ISpy)
287        {
288                static CString GetPropertyBagText(IRunPropertyBagAware* pRunPropertyBagAware, ISpy* pSpy = NULL)
289                {
290                        if(!pRunPropertyBagAware)
291                                return _T("");
292                        return GetPropertyBagText(ReadRunPropertyBag(pRunPropertyBagAware));
293                }
294                static CString GetPropertyBagText(IUnknown* pBaseFilterUnknown, ISpy* pSpy = NULL)
295                {
296                        CComQIPtr<ISpy> pEffectiveSpy = pSpy;
297                        if(!pEffectiveSpy && pBaseFilterUnknown)
298                                pEffectiveSpy = _FilterGraphHelper::GetFilterGraph(CComQIPtr<IBaseFilter>(pBaseFilterUnknown));
299                        if(pEffectiveSpy && pBaseFilterUnknown)
300                        {
301                                CComVariantArray vValue;
302                                __C(pEffectiveSpy->ReadRunPropertyBag(pBaseFilterUnknown, ATL_VARIANT_TRUE, &vValue));
303                                return GetPropertyBagText(vValue);
304                        }
305                        const CComQIPtr<IRunPropertyBagAware> pRunPropertyBagAware = pBaseFilterUnknown;
306                        return GetPropertyBagText(pRunPropertyBagAware, pEffectiveSpy);
307                }
308                static CString GetPropertyBagText(IFilterGraph* pFilterGraph, ISpy* pSpy = NULL)
309                {
310                        const CComQIPtr<IServiceProvider> pServiceProvider = pFilterGraph;
311                        if(pServiceProvider)
312                        {
313                                CComPtr<IRunPropertyBagAware> pRunPropertyBagAware;
314                                pServiceProvider->QueryService<IRunPropertyBagAware>(__uuidof(IRunPropertyBagAware), &pRunPropertyBagAware);
315                                if(pRunPropertyBagAware)
316                                        return GetPropertyBagText(pRunPropertyBagAware, pSpy);
317                        }
318                        return _T("");
319                }
320        }
321};
322
323#if !defined(DIRECTSHOWSPY)
324
325////////////////////////////////////////////////////////////
326// CRunPropertyBagAwareT
327
328template <typename T>
329class ATL_NO_VTABLE CRunPropertyBagAwareT :
330        public IDispatchImpl<DIRECTSHOWSPY_NAMESPACE_PREFIX IRunPropertyBagAware, &__uuidof(DIRECTSHOWSPY_NAMESPACE_PREFIX IRunPropertyBagAware), &__uuidof(DIRECTSHOWSPY_NAMESPACE_PREFIX __AlaxInfoDirectShowSpy)>
331{
332public:
333// CRunPropertyBagAwareT
334
335// AlaxInfoDirectShowSpy::IRunPropertyBagAware
336        STDMETHOD(get_Value)(IUnknown** ppPropertyBagUnknown)
337        {
338                _Z5(atlTraceCOM, 5, _T("...\n"));
339                _ATLTRY
340                {
341                        __D(ppPropertyBagUnknown, E_POINTER);
342                        T* pT = static_cast<T*>(this);
343                        *ppPropertyBagUnknown = (IPropertyBag*) pT->CreatePerformancePropertyBag().Detach();
344                }
345                _ATLCATCH(Exception)
346                {
347                        _C(Exception);
348                }
349                return S_OK;
350        }
351};
352
353#endif // !defined(DIRECTSHOWSPY)
Note: See TracBrowser for help on using the repository browser.