source: trunk/DirectShowSpy/RunPropertyBag.h @ 376

Last change on this file since 376 was 376, checked in by roman, 8 years ago

Changed year to 2015; Added Copy and Save As links in graph text, RunTime? property pages

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