source: trunk/DirectShowSpy/RunPropertyBag.h @ 937

Last change on this file since 937 was 851, checked in by roman, 6 years ago

Added filter states and intermediate states; earlier minor fixes

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