source: trunk/Utilities/RenderInterlacedVideo/MainPropertySheet.h @ 296

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

CVmr9Window::CMonitorInformation

  • Property svn:keywords set to Id
File size: 63.8 KB
Line 
1////////////////////////////////////////////////////////////
2// Copyright (C) Roman Ryltsov, 2008-2014
3// Created by Roman Ryltsov roman@alax.info
4
5#pragma once
6
7#include "AboutDialog.h"
8#include <dshow.h>
9#include <d3d9.h>
10#include <vmr9.h>
11#include <evr.h>
12#include <evr9.h>
13#include <dxva.h>
14#import "libid:B9EC374B-834B-4DA9-BFB5-C1872CE736FF" raw_interfaces_only // AlaxInfoDirectShowSpy
15#include "rodshow.h"
16
17////////////////////////////////////////////////////////////
18// CVrWindowT
19
20template <typename T>
21class CVrWindowT
22{
23public:
24// CVrWindowT
25        VOID DoHelperModal(IUnknown* pUnknown, LPCTSTR pszCaption = NULL)
26        {
27                T* pT = static_cast<T*>(this);
28                CComPtr<AlaxInfoDirectShowSpy::IFilterGraphHelper> pFilterGraphHelper;
29                const HRESULT nCoCreateInstanceResult = pFilterGraphHelper.CoCreateInstance(__uuidof(AlaxInfoDirectShowSpy::FilterGraphHelper));
30                if(SUCCEEDED(nCoCreateInstanceResult))
31                {
32                        __C(pFilterGraphHelper->put_FilterGraph(pUnknown));
33                        __C(pFilterGraphHelper->DoPropertyFrameModal((LONG) (LONG_PTR) pT->m_hWnd));
34                        return;
35                }
36                COlePropertyFrameDialog Dialog(pUnknown, pszCaption);
37                Dialog.SetObjectPages();
38                Dialog.DoModal(pT->m_hWnd);
39        }
40};
41
42////////////////////////////////////////////////////////////
43// CVmr7Window
44
45class CVmr7Window :
46        public CControlWindowT<CVmr7Window>,
47        public CVrWindowT<CVmr7Window>
48{
49public:
50
51BEGIN_MSG_MAP_EX(CVmr7Window)
52        //CHAIN_MSG_MAP(CControlWindowT<CVmr7Window>)
53        MSG_WM_ERASEBKGND(OnEraseBkgnd)
54        MSG_WM_PAINT(OnPaint)
55        MSG_WM_DISPLAYCHANGE(OnDisplayChange)
56        MSG_WM_SIZE(OnSize)
57        MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
58END_MSG_MAP()
59
60public:
61        CComPtr<IBaseFilter> m_pBaseFilter;
62        CComPtr<IVMRWindowlessControl> m_pVmrWindowlessControl;
63
64public:
65// CVmr7Window
66        static CLSID GetRendererClassIdentifier()
67        {
68                return CLSID_VideoMixingRenderer;
69        }
70        static CComPtr<IBaseFilter> CoCreateBaseFilterInstance()
71        {
72                CComPtr<IBaseFilter> pBaseFilter;
73                __C(pBaseFilter.CoCreateInstance(GetRendererClassIdentifier()));
74                return pBaseFilter;
75        }
76        VOID Initialize(IBaseFilter* pBaseFilter)
77        {
78                _A(pBaseFilter);
79                _A(!m_pBaseFilter && !m_pVmrWindowlessControl);
80                m_pBaseFilter = pBaseFilter;
81                CComQIPtr<IVMRFilterConfig> pVmrFilterConfig = pBaseFilter;
82                __D(pVmrFilterConfig, E_NOINTERFACE);
83                __C(pVmrFilterConfig->SetRenderingMode(VMRMode_Windowless));
84                // NOTE: Cause the VMR to load the mixer and compositor
85                //       See http://msdn.microsoft.com/en-us/library/windows/desktop/dd390448%28v=vs.85%29.aspx
86                __C(pVmrFilterConfig->SetNumberOfStreams(1));
87                m_pVmrWindowlessControl = CComQIPtr<IVMRWindowlessControl>(m_pBaseFilter);
88                __D(m_pVmrWindowlessControl, E_NOINTERFACE);
89                __C(m_pVmrWindowlessControl->SetVideoClippingWindow(m_hWnd));
90                UpdateVideoPosition();
91        }
92        VOID Terminate()
93        {
94                m_pBaseFilter = NULL;
95                m_pVmrWindowlessControl = NULL;
96        }
97        CRect GetVideoPosition() const
98        {
99                CRect Position;
100                _W(GetClientRect(Position));
101                return Position;
102        }
103        BOOL UpdateVideoPosition()
104        {
105                _A(m_pVmrWindowlessControl && IsWindow());
106                CRect VideoPosition = GetVideoPosition();
107                _Z4(atlTraceGeneral, 4, _T("m_pVmrWindowlessControl 0x%p, VideoPosition at (%d, %d) size (%d, %d)\n"), m_pVmrWindowlessControl, VideoPosition.left, VideoPosition.top, VideoPosition.Width(), VideoPosition.Height());
108                const HRESULT nSetVideoPositionResult = m_pVmrWindowlessControl->SetVideoPosition(NULL, VideoPosition);
109                __C(nSetVideoPositionResult); //_Z45_DSHRESULT(nSetVideoPositionResult);
110                return SUCCEEDED(nSetVideoPositionResult);
111        }
112
113// Window Message Handlers
114        LRESULT OnEraseBkgnd(CDCHandle Dc)
115        {
116                Dc;
117                if(m_pVmrWindowlessControl)
118                {
119                        return TRUE;
120                } else
121                        SetMsgHandled(FALSE);
122                return 0;
123        }
124        LRESULT OnPaint(CDCHandle)
125        {
126                if(m_pVmrWindowlessControl)
127                {
128                        CPaintDC Dc(m_hWnd);
129                        const HRESULT nRepaintVideoResult = m_pVmrWindowlessControl->RepaintVideo(m_hWnd, Dc);
130                        _Z45_DSHRESULT(nRepaintVideoResult);
131                } else
132                        SetMsgHandled(FALSE);
133                return 0;
134        }
135        LRESULT OnDisplayChange(UINT nDepth, CSize Extent)
136        {
137                if(m_pVmrWindowlessControl)
138                {
139                        const HRESULT nDisplayModeChangedResult = m_pVmrWindowlessControl->DisplayModeChanged();
140                        _Z4_DSHRESULT(nDisplayModeChangedResult);
141                }
142                return 0;
143        }
144        LRESULT OnSize(UINT nType, CSize)
145        {
146                if(nType != SIZE_MINIMIZED)
147                        if(m_pVmrWindowlessControl)
148                                UpdateVideoPosition();
149                return 0;
150        }
151        LRESULT OnLButtonDblClk(UINT, CPoint Position)
152        {
153                DoHelperModal(m_pBaseFilter, _T("VMR-7"));
154                return 0;
155        }
156};
157
158////////////////////////////////////////////////////////////
159// CVmr9Window
160
161class CVmr9Window :
162        public CControlWindowT<CVmr9Window>,
163        public CVrWindowT<CVmr9Window>
164{
165public:
166
167BEGIN_MSG_MAP_EX(CVmr9Window)
168        //CHAIN_MSG_MAP(CControlWindowT<CVmr9Window>)
169        MSG_WM_ERASEBKGND(OnEraseBkgnd)
170        MSG_WM_PAINT(OnPaint)
171        MSG_WM_DISPLAYCHANGE(OnDisplayChange)
172        MSG_WM_SIZE(OnSize)
173        MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
174END_MSG_MAP()
175
176public:
177
178        ////////////////////////////////////////////////////////
179        // CMonitorInformation
180
181        class CMonitorInformation
182        {
183        public:
184                CComPtr<IVMRMonitorConfig9> m_pVmrMonitorConfig;
185                CTempBufferT<VMR9MonitorInfo> m_pMonitorInformations;
186                SIZE_T m_nMonitorInformationCount;
187
188        public:
189        // CMonitorInformation
190                CMonitorInformation() :
191                        m_nMonitorInformationCount(0)
192                {
193                }
194                CMonitorInformation(IVMRMonitorConfig9* pVmrMonitorConfig)
195                {
196                        Initialize(pVmrMonitorConfig);
197                }
198                CMonitorInformation(IUnknown* pUnknown)
199                {
200                        Initialize(pUnknown);
201                }
202                VOID Initialize(IVMRMonitorConfig9* pVmrMonitorConfig)
203                {
204                        _A(pVmrMonitorConfig);
205                        m_pVmrMonitorConfig = pVmrMonitorConfig;
206                        DWORD nMonitorInformationCount = 0;
207                        m_pVmrMonitorConfig->GetAvailableMonitors(NULL, 0, &nMonitorInformationCount);
208                        if(nMonitorInformationCount < 32)
209                                nMonitorInformationCount = 32;
210                        m_pMonitorInformations.Free();
211                        _W(m_pMonitorInformations.Allocate(nMonitorInformationCount));
212                        __C(m_pVmrMonitorConfig->GetAvailableMonitors(m_pMonitorInformations, nMonitorInformationCount, &nMonitorInformationCount));
213                        m_nMonitorInformationCount = nMonitorInformationCount;
214                }
215                VOID Initialize(IUnknown* pUnknown)
216                {
217                        const CComQIPtr<IVMRMonitorConfig9> pVmrMonitorConfig = pUnknown;
218                        __D(pVmrMonitorConfig, E_NOINTERFACE);
219                        Initialize(pVmrMonitorConfig);
220                }
221                VOID TraceMonitor() const
222                {
223                        #if _DEVELOPMENT
224                                _A(m_pVmrMonitorConfig);
225                                UINT nMonitor, nDefaultMonitor;
226                                __C(m_pVmrMonitorConfig->GetMonitor(&nMonitor));
227                                __C(m_pVmrMonitorConfig->GetDefaultMonitor(&nDefaultMonitor));
228                                _Z4(atlTraceGeneral, 4, _T("nMonitor %d, nDefaultMonitor %d\n"), nMonitor, nDefaultMonitor);
229                        #endif // _DEVELOPMENT
230                }
231                BOOL SuggestMonitor(RECT Position, UINT& nSuggestMonitor) const
232                {
233                        BOOL bSuggestMonitorAvailable = FALSE;
234                        LONG nSuggestMonitorScore;
235                        for(DWORD nIndex = 0; nIndex < m_nMonitorInformationCount; nIndex++)
236                        {
237                                const VMR9MonitorInfo& MonitorInformation = m_pMonitorInformations[nIndex];
238                                const CRect& MonitorPosition = reinterpret_cast<const CRect&>(MonitorInformation.rcMonitor);
239                                _Z4(atlTraceGeneral, 4, _T("MonitorInformation.uDevID %d, .hMon 0x%08X, .dwFlags 0x%X, .szDevice \"%ls\", .szDescription \"%ls\"\n"), 
240                                        MonitorInformation.uDevID,
241                                        //MonitorInformation.rcMonitor.left, ...
242                                        MonitorInformation.hMon, MonitorInformation.dwFlags, 
243                                        MonitorInformation.szDevice, MonitorInformation.szDescription,
244                                        //MonitorInformation.liDriverVersion,
245                                        //MonitorInformation.dwVendorId, MonitorInformation.dwDeviceId, MonitorInformation.dwSubSysId, MonitorInformation.dwRevision,
246                                        0);
247                                CRect VisiblePosition;
248                                if(!VisiblePosition.IntersectRect(MonitorPosition, &Position))
249                                        continue;
250                                const LONG nScore = VisiblePosition.Height() * VisiblePosition.Width();
251                                if(bSuggestMonitorAvailable && nSuggestMonitorScore > nScore)
252                                        continue;
253                                nSuggestMonitor = MonitorInformation.uDevID;
254                                bSuggestMonitorAvailable = TRUE;
255                                nSuggestMonitorScore = nScore;
256                        }
257                        return bSuggestMonitorAvailable;
258                }
259        };
260
261public:
262        CComPtr<IBaseFilter> m_pBaseFilter;
263        CComPtr<IVMRWindowlessControl9> m_pVmrWindowlessControl;
264
265public:
266// CVmr9Window
267        static CLSID GetRendererClassIdentifier()
268        {
269                return CLSID_VideoMixingRenderer9;
270        }
271        static CComPtr<IBaseFilter> CoCreateBaseFilterInstance()
272        {
273                CComPtr<IBaseFilter> pBaseFilter;
274                __C(pBaseFilter.CoCreateInstance(GetRendererClassIdentifier()));
275                return pBaseFilter;
276        }
277        VOID Initialize(IBaseFilter* pBaseFilter)
278        {
279                _A(pBaseFilter);
280                _A(!m_pBaseFilter && !m_pVmrWindowlessControl);
281                m_pBaseFilter = pBaseFilter;
282                CComQIPtr<IVMRFilterConfig9> pVmrFilterConfig = pBaseFilter;
283                __D(pVmrFilterConfig, E_NOINTERFACE);
284                __C(pVmrFilterConfig->SetRenderingMode(VMR9Mode_Windowless));
285                m_pVmrWindowlessControl = CComQIPtr<IVMRWindowlessControl9>(m_pBaseFilter);
286                __D(m_pVmrWindowlessControl, E_NOINTERFACE);
287                __C(m_pVmrWindowlessControl->SetVideoClippingWindow(m_hWnd));
288                UpdateVideoPosition();
289        }
290        VOID Terminate()
291        {
292                m_pBaseFilter = NULL;
293                m_pVmrWindowlessControl = NULL;
294        }
295        CRect GetVideoPosition() const
296        {
297                CRect Position;
298                _W(GetClientRect(Position));
299                return Position;
300        }
301        BOOL UpdateVideoPosition()
302        {
303                _A(m_pVmrWindowlessControl && IsWindow());
304                CRect VideoPosition = GetVideoPosition();
305                _Z4(atlTraceGeneral, 4, _T("m_pVmrWindowlessControl 0x%p, VideoPosition at (%d, %d) size (%d, %d)\n"), m_pVmrWindowlessControl, VideoPosition.left, VideoPosition.top, VideoPosition.Width(), VideoPosition.Height());
306                const HRESULT nSetVideoPositionResult = m_pVmrWindowlessControl->SetVideoPosition(NULL, VideoPosition);
307                __C(nSetVideoPositionResult); //_Z45_DSHRESULT(nSetVideoPositionResult);
308                return SUCCEEDED(nSetVideoPositionResult);
309        }
310
311// Window Message Handlers
312        LRESULT OnEraseBkgnd(CDCHandle Dc)
313        {
314                Dc;
315                if(m_pVmrWindowlessControl)
316                {
317                        return TRUE;
318                } else
319                        SetMsgHandled(FALSE);
320                return 0;
321        }
322        LRESULT OnPaint(CDCHandle)
323        {
324                if(m_pVmrWindowlessControl)
325                {
326                        CPaintDC Dc(m_hWnd);
327                        const HRESULT nRepaintVideoResult = m_pVmrWindowlessControl->RepaintVideo(m_hWnd, Dc);
328                        _Z45_DSHRESULT(nRepaintVideoResult);
329                } else
330                        SetMsgHandled(FALSE);
331                return 0;
332        }
333        LRESULT OnDisplayChange(UINT nDepth, CSize Extent)
334        {
335                if(m_pVmrWindowlessControl)
336                {
337                        const HRESULT nDisplayModeChangedResult = m_pVmrWindowlessControl->DisplayModeChanged();
338                        _Z45_DSHRESULT(nDisplayModeChangedResult);
339                }
340                return 0;
341        }
342        LRESULT OnSize(UINT nType, CSize)
343        {
344                if(nType != SIZE_MINIMIZED)
345                        if(m_pVmrWindowlessControl)
346                                UpdateVideoPosition();
347                return 0;
348        }
349        LRESULT OnLButtonDblClk(UINT, CPoint Position)
350        {
351                DoHelperModal(m_pBaseFilter, _T("VMR-9"));
352                return 0;
353        }
354};
355
356////////////////////////////////////////////////////////////
357// CEvrWindow
358
359class CEvrWindow :
360        public CControlWindowT<CEvrWindow>,
361        public CVrWindowT<CEvrWindow>
362{
363public:
364
365BEGIN_MSG_MAP_EX(CEvrWindow)
366        //CHAIN_MSG_MAP(CControlWindowT<CEvrWindow>)
367        MSG_WM_ERASEBKGND(OnEraseBkgnd)
368        MSG_WM_PAINT(OnPaint)
369        MSG_WM_SIZE(OnSize)
370        MSG_WM_LBUTTONDBLCLK(OnLButtonDblClk)
371END_MSG_MAP()
372
373public:
374        CComPtr<IBaseFilter> m_pBaseFilter;
375        CComPtr<IMFVideoDisplayControl> m_pMfVideoDisplayControl;
376
377public:
378// CEvrWindow
379        static CLSID GetRendererClassIdentifier()
380        {
381                return CLSID_EnhancedVideoRenderer;
382        }
383        static CComPtr<IBaseFilter> CoCreateBaseFilterInstance()
384        {
385                CComPtr<IBaseFilter> pBaseFilter;
386                __C(pBaseFilter.CoCreateInstance(GetRendererClassIdentifier()));
387                return pBaseFilter;
388        }
389        VOID Initialize(IBaseFilter* pBaseFilter)
390        {
391                _A(pBaseFilter);
392                _A(!m_pBaseFilter && !m_pMfVideoDisplayControl);
393                m_pBaseFilter = pBaseFilter;
394                CComQIPtr<IMFGetService> pMfGetInterface = pBaseFilter;
395                CComPtr<IMFVideoDisplayControl> pMfVideoDisplayControl;
396                __C(pMfGetInterface->GetService(MR_VIDEO_RENDER_SERVICE, __uuidof(IMFVideoDisplayControl), (VOID**) &pMfVideoDisplayControl));
397                _A(pMfVideoDisplayControl);
398                m_pMfVideoDisplayControl = pMfVideoDisplayControl;
399                __C(pMfVideoDisplayControl->SetVideoWindow(m_hWnd));
400                UpdateVideoPosition();
401                //__C(pMfVideoDisplayControl->SetAspectRatioMode(MFVideoARMode_None)); // As opposed to default MFVideoARMode_Picture - disable letterboxing
402        }
403        VOID Terminate()
404        {
405                m_pBaseFilter = NULL;
406                m_pMfVideoDisplayControl = NULL;
407        }
408        CRect GetVideoPosition() const
409        {
410                CRect Position;
411                _W(GetClientRect(Position));
412                return Position;
413        }
414        BOOL UpdateVideoPosition()
415        {
416                _A(m_pMfVideoDisplayControl && IsWindow());
417                CRect VideoPosition = GetVideoPosition();
418                _Z4(atlTraceGeneral, 4, _T("m_pMfVideoDisplayControl 0x%p, VideoPosition at (%d, %d) size (%d, %d)\n"), m_pMfVideoDisplayControl, VideoPosition.left, VideoPosition.top, VideoPosition.Width(), VideoPosition.Height());
419                const HRESULT nSetVideoPositionResult = m_pMfVideoDisplayControl->SetVideoPosition(NULL, VideoPosition);
420                __C(nSetVideoPositionResult); //_Z45_DSHRESULT(nSetVideoPositionResult);
421                return SUCCEEDED(nSetVideoPositionResult);
422        }
423
424// Window Message Handlers
425        LRESULT OnEraseBkgnd(CDCHandle Dc)
426        {
427                Dc;
428                if(m_pMfVideoDisplayControl)
429                {
430                        return TRUE;
431                } else
432                        SetMsgHandled(FALSE);
433                return 0;
434        }
435        LRESULT OnPaint(CDCHandle)
436        {
437                if(m_pMfVideoDisplayControl)
438                {
439                        CPaintDC Dc(m_hWnd);
440                        const HRESULT nRepaintVideoResult = m_pMfVideoDisplayControl->RepaintVideo();
441                        _Z4(atlTraceUI, SUCCEEDED(nRepaintVideoResult) ? 6 : 4, _T("nRepaintVideoResult 0x%08x\n"), nRepaintVideoResult);
442                } else
443                        SetMsgHandled(FALSE);
444                return 0;
445        }
446        LRESULT OnSize(UINT nType, CSize)
447        {
448                if(nType != SIZE_MINIMIZED)
449                        if(m_pMfVideoDisplayControl)
450                                UpdateVideoPosition();
451                return 0;
452        }
453        LRESULT OnLButtonDblClk(UINT, CPoint Position)
454        {
455                DoHelperModal(m_pBaseFilter, _T("EVR"));
456                return 0;
457        }
458};
459
460////////////////////////////////////////////////////////////
461// CMainPropertySheet
462
463class CMainPropertySheet : 
464        public CSizablePropertySheetT<CMainPropertySheet>
465{
466public:
467
468BEGIN_MSG_MAP_EX(CMainPropertySheet)
469        CHAIN_MSG_MAP(CSizablePropertySheet)
470        MESSAGE_HANDLER_EX(WM_SETLARGERINITIALPOSITION, OnSetLargerInitialPosition)
471END_MSG_MAP()
472
473public:
474
475        ////////////////////////////////////////////////////////
476        // Window Message Identifiers
477
478        enum
479        {
480                MW_FIRST = WM_APP + 100,
481                WM_SETLARGERINITIALPOSITION,
482        };
483
484        ////////////////////////////////////////////////////////
485        // CSourceFilter
486
487        class ATL_NO_VTABLE CSourceFilter :
488                public CComObjectRootEx<CComMultiThreadModelNoCS>,
489                public CComCoClass<CSourceFilter>,
490                public CPushSourceFilterT<CSourceFilter>,
491                public CBasePersistT<CSourceFilter>,
492                public CAmFilterMiscFlagsT<CSourceFilter, AM_FILTER_MISC_FLAGS_IS_SOURCE>
493        {
494        public:
495
496        DECLARE_NO_REGISTRY()
497
498        DECLARE_PROTECT_FINAL_CONSTRUCT()
499
500        //DECLARE_QI_TRACE(CSourceFilter)
501
502        BEGIN_COM_MAP(CSourceFilter)
503                COM_INTERFACE_ENTRY(IBaseFilter)
504                COM_INTERFACE_ENTRY(IMediaFilter)
505                COM_INTERFACE_ENTRY_IID(__uuidof(IPersist), IBaseFilter)
506                COM_INTERFACE_ENTRY(IAMFilterMiscFlags)
507        END_COM_MAP()
508
509        public:
510
511                ////////////////////////////////////////////////////////
512                // CThreadContext
513
514                class CThreadContext :
515                        public CPushSourceFilter::CThreadContext
516                {
517                public:
518                        SIZE_T m_nMediaSampleIndex;
519
520                public:
521                // CThreadContext
522                        CThreadContext(CEvent& TerminationEvent) :
523                                CPushSourceFilter::CThreadContext(TerminationEvent),
524                                m_nMediaSampleIndex(0)
525                        {
526                        }
527                };
528
529                ////////////////////////////////////////////////////////
530                // COutputPin
531
532                class ATL_NO_VTABLE COutputPin :
533                        public CComObjectRootEx<CComMultiThreadModelNoCS>,
534                        public CPushSourceFilterT<CSourceFilter>::COutputPinT<COutputPin, CSourceFilter, CThreadContext>,
535                        public CAmPushSourceT<COutputPin, 0>
536                {
537                public:
538
539                //DECLARE_QI_TRACE(CSourceFilter::COutputPin)
540
541                BEGIN_COM_MAP(COutputPin)
542                        COM_INTERFACE_ENTRY(IPin)
543                        COM_INTERFACE_ENTRY(IAMPushSource)
544                        COM_INTERFACE_ENTRY(IAMLatency)
545                END_COM_MAP()
546
547                private:
548
549                        VOID Paint(BYTE* pnData, SSIZE_T nNextRowOffset, BYTE nColor)
550                        {
551                                // 400 px high from 40, 60 px wide from current, line step 2
552                                for(LONG nY = (480 - 2 * 40) / 2; nY > 0; nY--)
553                                {
554                                        for(LONG nX = 0; nX < 60; nX++)
555                                                pnData[nX * 2] = nColor;
556                                        pnData += 2 * nNextRowOffset;
557                                }
558                        }
559
560                public:
561                // COutputPin
562                        COutputPin()
563                        {
564                                _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
565                        }
566                        ~COutputPin()
567                        {
568                                _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
569                        }
570                        VOID EnumerateMediaTypes(CAtlList<CMediaType>& MediaTypeList)
571                        {
572                                //CRoCriticalSectionLock DataLock(GetDataCriticalSection());
573                                _W(MediaTypeList.AddTail(GetFilter()->m_pRequestedMediaType));
574                        }
575                        BOOL CheckMediaType(const CMediaType& pMediaType) const
576                        {
577                                _A(pMediaType);
578                                if(pMediaType->majortype != MEDIATYPE_Video)
579                                        return FALSE;
580                                //CRoCriticalSectionLock DataLock(GetDataCriticalSection());
581                                _A(GetFilter()->m_pRequestedMediaType);
582                                //if(GetFilter()->m_pRequestedMediaType.Compare(pMediaType))
583                                //      return TRUE;
584                                return CVideoInfoHeader::Compare(&GetFilter()->m_pRequestedMediaType.GetCompatibleVideoInfoHeader(), &pMediaType.GetCompatibleVideoInfoHeader(), FALSE);
585                        }
586                        BOOL DecideMemAllocatorProperties(IMemAllocator* pMemAllocator, ALLOCATOR_PROPERTIES Properties)
587                        {
588                                static const SIZE_T g_nMiminalBufferCount = 8;
589                                Properties.cBuffers = max(Properties.cBuffers, (LONG) g_nMiminalBufferCount);
590                                CRoCriticalSectionLock DataLock(GetDataCriticalSection());
591                                const CMediaType& pMediaType = GetMediaTypeReference();
592                                const CVideoInfoHeader VideoInfoHeader = pMediaType.GetCompatibleVideoInfoHeader();
593                                const CSize Extent = VideoInfoHeader.GetExtent();
594                                SIZE_T nBufferSize;
595                                if(Extent.cx >= 1080)
596                                {
597                                        // NOTE: At higher resolutions we are good to go with much smaller buffers
598                                        static const UINT g_nPixelBitCount = 7;
599                                        nBufferSize = Extent.cy * Extent.cx * g_nPixelBitCount / 8;
600                                } else
601                                {
602                                        static const UINT g_nPixelBitCount = 14;
603                                        nBufferSize = Extent.cy * Extent.cx * g_nPixelBitCount / 8;
604                                }
605                                return SetMemAllocatorBufferSize(pMemAllocator, Properties, nBufferSize);
606                        }
607                        BOOL ComposeMediaSample(CThreadContext& ThreadContext, IMediaSample* pMediaSample)
608                        {
609                                CMediaSampleProperties OutputProperties(pMediaSample);
610                                HandleMediaTypeChange(OutputProperties);
611                                const CMediaType pMediaType = GetMediaType();
612                                const CVideoInfoHeader2* pVideoInfoHeader2 = pMediaType.GetVideoInfoHeader2();
613                                OutputProperties.dwTypeSpecificFlags = (!(ThreadContext.m_nMediaSampleIndex & 1) ? AM_VIDEO_FLAG_FIELD2 : AM_VIDEO_FLAG_FIELD1);
614                                OutputProperties.dwSampleFlags = AM_SAMPLE_SPLICEPOINT | (ThreadContext.m_nMediaSampleIndex ? 0 : AM_SAMPLE_DATADISCONTINUITY) | AM_SAMPLE_TIMEVALID | AM_SAMPLE_STOPVALID;
615                                OutputProperties.lActual = GetMediaType().GetCompatibleVideoInfoHeader().GetDataSize();
616                                OutputProperties.tStart = ThreadContext.m_nMediaSampleIndex * pVideoInfoHeader2->AvgTimePerFrame / 2;
617                                OutputProperties.tStop = OutputProperties.tStart + 1;
618                                OutputProperties.dwStreamId = 0;
619                                #pragma region Data
620                                FillMemory(OutputProperties.pbBuffer, OutputProperties.lActual, 0x80);
621                                const CSize Extent = pVideoInfoHeader2->GetExtent();
622                                SSIZE_T nFirstRowOffset, nNextRowOffset;
623                                pVideoInfoHeader2->GetData(nFirstRowOffset, nNextRowOffset);
624                                BYTE* pnData = OutputProperties.pbBuffer;
625                                static const REFERENCE_TIME g_nPeriod = 3 * 1000 * 10000i64; // 3 seconds for the move back and forth
626                                REFERENCE_TIME nField2Time = (ThreadContext.m_nMediaSampleIndex & ~1) * pVideoInfoHeader2->AvgTimePerFrame / 2;
627                                REFERENCE_TIME nField1Time = ((ThreadContext.m_nMediaSampleIndex - 1) | 1) * pVideoInfoHeader2->AvgTimePerFrame / 2;
628                                _Z5(atlTraceGeneral, 5, _T("m_nMediaSampleIndex %d, OutputProperties.tStart %s, nField2Time %s, nField1Time %s\n"), 
629                                        ThreadContext.m_nMediaSampleIndex,
630                                        _FilterGraphHelper::FormatReferenceTime(OutputProperties.tStart),
631                                        _FilterGraphHelper::FormatReferenceTime(nField2Time), 
632                                        _FilterGraphHelper::FormatReferenceTime(nField1Time), 
633                                        0);
634                                REFERENCE_TIME nPositionA = nField2Time % g_nPeriod;
635                                LONG nPositionB = (LONG) (abs((g_nPeriod / 2) - nPositionA) * (600 - 60) / (g_nPeriod / 2));
636                                Paint(pnData + nFirstRowOffset + (40 + 1) * nNextRowOffset + (60 + nPositionB) * 2, nNextRowOffset, 0xFF);
637                                REFERENCE_TIME nPositionC = nField1Time % g_nPeriod;
638                                LONG nPositionD = (LONG) (abs((g_nPeriod / 2) - nPositionC) * (600 - 60) / (g_nPeriod / 2));
639                                Paint(pnData + nFirstRowOffset + (40 + 0) * nNextRowOffset + (60 + nPositionD) * 2, nNextRowOffset, GetFilter()->GetColorize() ? 0x00 : 0xFF);
640                                if(GetFilter()->GetWeave())
641                                        OutputProperties.dwTypeSpecificFlags |= AM_VIDEO_FLAG_WEAVE;
642                                #pragma endregion
643                                OutputProperties.Set();
644                                ThreadContext.m_nMediaSampleIndex++;
645                                return TRUE;
646                        }
647                };
648
649        private:
650                CObjectPtr<COutputPin> m_pOutputPin;
651                CMediaType m_pRequestedMediaType;
652                BOOL m_bWeave;
653                BOOL m_bColorize;
654
655        public:
656        // CSourceFilter
657                CSourceFilter() :
658                        CBasePersistT<CSourceFilter>(GetDataCriticalSection()),
659                        m_bWeave(FALSE),
660                        m_bColorize(FALSE)
661                {
662                        _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
663                }
664                ~CSourceFilter()
665                {
666                        _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
667                }
668                HRESULT FinalConstruct()
669                {
670                        _ATLTRY
671                        {
672                                m_pOutputPin.Construct()->Initialize(this, L"Output");
673                                AddPin(m_pOutputPin);
674                        }
675                        _ATLCATCH(Exception)
676                        {
677                                _C(Exception);
678                        }
679                        return S_OK;
680                }
681                VOID FinalRelease()
682                {
683                        m_pOutputPin = NULL;
684                }
685                VOID DeliverBeginFlush(IPin*)
686                {
687                        m_pOutputPin->DeliverBeginFlush();
688                }
689                VOID DeliverEndFlush(IPin*)
690                {
691                        m_pOutputPin->DeliverEndFlush();
692                }
693                VOID DeliverNewSegment(IPin*, REFERENCE_TIME nStartTime, REFERENCE_TIME nStopTime, DOUBLE fRate)
694                {
695                        m_pOutputPin->DeliverNewSegment(nStartTime, nStopTime, fRate);
696                }
697                static BOOL CanCue()
698                {
699                        return FALSE;
700                }
701                VOID CueFilter()
702                {
703                        m_pOutputPin->CuePin();
704                }
705                VOID RunFilter(REFERENCE_TIME nStartTime)
706                {
707                        m_pOutputPin->RunPin(nStartTime);
708                }
709                VOID PauseFilter()
710                {
711                        m_pOutputPin->PausePin();
712                }
713                VOID StopFilter()
714                {
715                        m_pOutputPin->StopPin();
716                }
717                const CObjectPtr<COutputPin>& GetOutputPin() const
718                {
719                        return m_pOutputPin;
720                }
721                VOID Initialize()
722                {
723                        _A(!m_pRequestedMediaType);
724                        CMediaType pMediaType;
725                        //pMediaType.AllocateVideoInfo(720, 480, 16, MAKEFOURCC('Y', 'U', 'Y', '2'), 1000 * 10000i64 / 30);
726                        pMediaType.Allocate(MEDIATYPE_Video, MEDIASUBTYPE_YUY2, FORMAT_VideoInfo2, sizeof (VIDEOINFOHEADER2));
727                        CVideoInfoHeader2* pVideoInfoHeader2 = pMediaType.GetVideoInfoHeader2();
728                        CBitmapInfoHeader* pBitmapInfoHeader = &pVideoInfoHeader2->GetBitmapInfoHeader();
729                        pBitmapInfoHeader->biSize = sizeof (BITMAPINFOHEADER);
730                        pBitmapInfoHeader->biWidth = 720;
731                        pBitmapInfoHeader->biHeight = 480;
732                        pBitmapInfoHeader->biPlanes = 1;
733                        pBitmapInfoHeader->biBitCount = 16;
734                        pBitmapInfoHeader->biCompression = MEDIASUBTYPE_YUY2.Data1;
735                        pBitmapInfoHeader->biSizeImage = pBitmapInfoHeader->GetDataSize();
736                        pVideoInfoHeader2->GetSourcePosition().SetRect(0, 0, pBitmapInfoHeader->biWidth, pBitmapInfoHeader->biHeight);
737                        pVideoInfoHeader2->GetTargetPosition().SetRect(0, 0, pBitmapInfoHeader->biWidth, pBitmapInfoHeader->biHeight);
738                        pVideoInfoHeader2->AvgTimePerFrame = 1001 * 10000i64 / 30;
739//                      pVideoInfoHeader2->AvgTimePerFrame *= 10; // Uncomment to slow down 10 times
740                        pVideoInfoHeader2->dwBitRate = (DWORD) (8.0 * pBitmapInfoHeader->biSizeImage * 10000000.0 / pVideoInfoHeader2->AvgTimePerFrame + 0.5 - 1E-6);
741                        pVideoInfoHeader2->dwInterlaceFlags = AMINTERLACE_IsInterlaced | AMINTERLACE_FieldPatBothRegular | AMINTERLACE_DisplayModeBobOrWeave;
742//                      pVideoInfoHeader2->dwInterlaceFlags = 0; // Uncomment to remove interlacing
743                        pVideoInfoHeader2->dwPictAspectRatioX = 720;
744                        pVideoInfoHeader2->dwPictAspectRatioY = 480;
745                        pMediaType->bFixedSizeSamples = TRUE;
746                        pMediaType->lSampleSize = pBitmapInfoHeader->biSizeImage;
747                        m_pRequestedMediaType = pMediaType;
748                }
749                const CMediaType& GetRequestedMediaType() const
750                {
751                        return m_pRequestedMediaType;
752                }
753                BOOL GetWeave() const
754                {
755                        CRoCriticalSectionLock DataLock(GetDataCriticalSection());
756                        return m_bWeave;
757                }
758                VOID SetWeave(BOOL bWeave)
759                {
760                        CRoCriticalSectionLock DataLock(GetDataCriticalSection());
761                        m_bWeave = bWeave;
762                }
763                BOOL GetColorize() const
764                {
765                        CRoCriticalSectionLock DataLock(GetDataCriticalSection());
766                        return m_bColorize;
767                }
768                VOID SetColorize(BOOL bColorize)
769                {
770                        CRoCriticalSectionLock DataLock(GetDataCriticalSection());
771                        m_bColorize = bColorize;
772                }
773        };
774
775        ////////////////////////////////////////////////////////////
776        // CAmGraphBuilderCallback
777
778        class ATL_NO_VTABLE CAmGraphBuilderCallback :
779                public CComObjectRootEx<CComMultiThreadModelNoCS>,
780                public IAMGraphBuilderCallback
781        {
782        public:
783
784        BEGIN_COM_MAP(CAmGraphBuilderCallback)
785                COM_INTERFACE_ENTRY(IAMGraphBuilderCallback)
786        END_COM_MAP()
787
788        public:
789        // CAmGraphBuilderCallback
790                CAmGraphBuilderCallback()
791                {
792                        _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
793                }
794                ~CAmGraphBuilderCallback()
795                {
796                        _Z4(atlTraceRefcount, 4, _T("this 0x%p\n"), this);
797                }
798                VOID SetGraphBuilder(IUnknown* pGraphBuilderUnknown)
799                {
800                        const CComQIPtr<IObjectWithSite> pObjectWithSite = pGraphBuilderUnknown;
801                        __D(pObjectWithSite, E_NOINTERFACE);
802                        __C(pObjectWithSite->SetSite(this));
803                }
804
805        // IAMGraphBuilderCallback
806                STDMETHOD(SelectedFilter)(IMoniker* pMoniker)
807                {
808                        _Z5(atlTraceCOM, 5, _T("...\n"));
809                        _ATLTRY
810                        {
811                                _A(pMoniker);
812                                CComPtr<IBindCtx> pBindCtx;
813                                __C(CreateBindCtx(0, &pBindCtx));
814                                if(_FilterGraphHelper::IsFilterNonGrata(pMoniker))
815                                        return E_FAIL;
816                                const CStringW sMonikerDisplayName = _FilterGraphHelper::GetMonikerDisplayName(pMoniker, pBindCtx);
817                                CComPtr<IPropertyBag> pPropertyBag;
818                                __C(pMoniker->BindToStorage(pBindCtx, NULL, __uuidof(IPropertyBag), (VOID**) &pPropertyBag));
819                                const CStringW sFriendlyName = _FilterGraphHelper::ReadPropertyBagString(pPropertyBag, OLESTR("FriendlyName"));
820                                const CStringW sClassIdentifierString = _FilterGraphHelper::ReadPropertyBagString(pPropertyBag, OLESTR("CLSID"));
821                                const CStringW sPath = _RegKeyHelper::QueryStringValue(HKEY_CLASSES_ROOT, AtlFormatString(_T("CLSID\\%ls\\InprocServer32"), sClassIdentifierString));
822                                _Z4(atlTraceGeneral, 4, _T("sMonikerDisplayName \"%ls\", sFriendlyName \"%ls\", sClassIdentifierString %ls, sPath \"%ls\"\n"), sMonikerDisplayName, sFriendlyName, sClassIdentifierString, sPath);
823                        }
824                        _ATLCATCH(Exception)
825                        {
826                                _C(Exception);
827                        }
828                        return S_OK;
829                }
830                STDMETHOD(CreatedFilter)(IBaseFilter* pBaseFilter)
831                {
832                        _Z5(atlTraceCOM, 5, _T("...\n"));
833                        _ATLTRY
834                        {
835                                _A(pBaseFilter);
836                                _Z4(atlTraceGeneral, 4, _T("pBaseFilter %ls \"%ls\"\n"), _FilterGraphHelper::GetFilterClassIdentifierString(pBaseFilter), _FilterGraphHelper::GetFilterName(pBaseFilter));
837                        }
838                        _ATLCATCH(Exception)
839                        {
840                                _C(Exception);
841                        }
842                        return S_OK;
843                }
844        };
845
846        ////////////////////////////////////////////////////
847        // CVrPropertyPageT
848
849        template <typename T>
850        class CVrPropertyPageT
851        {
852        public:
853        // CVrPropertyPageT
854                VOID HandleMediaEvent(LONG nEventCode, LONG_PTR nParameter1, LONG_PTR nParameter2)
855                {
856                        T* pT = static_cast<T*>(this);
857                        switch(nEventCode)
858                        {
859                        #pragma region EC_COMPLETE
860                        case EC_COMPLETE:
861                                _Z2(atlTraceGeneral, 2, _T("Filter Graph EC_COMPLETE (0x%X) Event, nParameter1 0x%08X, nParameter2 0x%08X\n"), nEventCode, nParameter1, nParameter2);
862                                break;
863                        #pragma endregion
864                        #pragma region EC_USERABORT
865                        case EC_USERABORT:
866                                _Z2(atlTraceGeneral, 2, _T("Filter Graph EC_USERABORT (0x%X) Event, nParameter1 0x%08X, nParameter2 0x%08X\n"), nEventCode, nParameter1, nParameter2);
867                                break;
868                        #pragma endregion
869                        #pragma region EC_ERRORABORT
870                        case EC_ERRORABORT:
871                                _Z2(atlTraceGeneral, 2, _T("Filter Graph EC_ERRORABORT (0x%X) Event, nParameter1 0x%08X, nParameter2 0x%08X\n"), nEventCode, nParameter1, nParameter2);
872                                _A(FAILED(nParameter1));
873                                AtlMessageBoxEx(pT->m_hWnd, (LPCTSTR) AtlFormatString(_T("EC_ERRORABORT Event: %s."), Ds::FormatResult((HRESULT) nParameter1).TrimRight(_T("\t\n\r ."))), IDS_ERROR, MB_ICONERROR | MB_OK);
874                                break;
875                        #pragma endregion
876                        #pragma region EC_PAUSED
877                        case EC_PAUSED:
878                                _Z2(atlTraceGeneral, 2, _T("Filter Graph EC_PAUSED (0x%X) Event, nParameter1 0x%08X, nParameter2 0x%08X\n"), nEventCode, nParameter1, nParameter2);
879                                break;
880                        #pragma endregion
881                        #pragma region EC_VMR_RENDERDEVICE_SET
882                        case EC_VMR_RENDERDEVICE_SET:
883                                {
884                                        CString sParameter1;
885                                        switch(nParameter1)
886                                        {
887                                        case VMR_RENDER_DEVICE_OVERLAY:
888                                                sParameter1 = AtlFormatString(_T("VMR_RENDER_DEVICE_OVERLAY (0x%02X)"), nParameter1);
889                                                break;
890                                        case VMR_RENDER_DEVICE_VIDMEM:
891                                                sParameter1 = AtlFormatString(_T("VMR_RENDER_DEVICE_VIDMEM (0x%02X)"), nParameter1);
892                                                break;
893                                        case VMR_RENDER_DEVICE_SYSMEM:
894                                                sParameter1 = AtlFormatString(_T("VMR_RENDER_DEVICE_SYSMEM (0x%02X)"), nParameter1);
895                                                break;
896                                        default:
897                                                sParameter1 = AtlFormatString(_T("0x%02X"), nParameter1);
898
899                                        }
900                                        _Z2(atlTraceGeneral, 2, _T("Filter Graph EC_VMR_RENDERDEVICE_SET (0x%X) Event, nParameter1 %s, nParameter2 0x%08X\n"), nEventCode, sParameter1, nParameter2);
901                                }
902                                break;
903                        #pragma endregion
904                        default:
905                                #pragma region EC_xxx (Development)
906                                #if _DEVELOPMENT
907                                        #define A(x) { x, #x },
908                                        static const struct
909                                        {
910                                                LONG nEventCode;
911                                                LPCSTR pszEventName;
912                                        } g_pMap[] = 
913                                        {
914                                                A(EC_COMPLETE)
915                                                A(EC_USERABORT)
916                                                A(EC_ERRORABORT)
917                                                A(EC_TIME)
918                                                A(EC_REPAINT)
919                                                A(EC_STREAM_ERROR_STOPPED)
920                                                A(EC_STREAM_ERROR_STILLPLAYING)
921                                                A(EC_ERROR_STILLPLAYING)
922                                                A(EC_PALETTE_CHANGED)
923                                                A(EC_VIDEO_SIZE_CHANGED)
924                                                A(EC_QUALITY_CHANGE)
925                                                A(EC_SHUTTING_DOWN)
926                                                A(EC_CLOCK_CHANGED)
927                                                A(EC_PAUSED)
928                                                A(EC_OPENING_FILE)
929                                                A(EC_BUFFERING_DATA)
930                                                A(EC_FULLSCREEN_LOST)
931                                                A(EC_ACTIVATE)
932                                                A(EC_NEED_RESTART)
933                                                A(EC_WINDOW_DESTROYED)
934                                                A(EC_DISPLAY_CHANGED)
935                                                A(EC_STARVATION)
936                                                A(EC_OLE_EVENT)
937                                                A(EC_NOTIFY_WINDOW)
938                                                A(EC_STREAM_CONTROL_STOPPED)
939                                                A(EC_STREAM_CONTROL_STARTED)
940                                                A(EC_END_OF_SEGMENT)
941                                                A(EC_SEGMENT_STARTED)
942                                                A(EC_LENGTH_CHANGED)
943                                                A(EC_DEVICE_LOST)
944                                                A(EC_SAMPLE_NEEDED)
945                                                A(EC_PROCESSING_LATENCY)
946                                                A(EC_SAMPLE_LATENCY)
947                                                A(EC_SCRUB_TIME)
948                                                A(EC_STEP_COMPLETE)
949                                                A(EC_WMT_INDEX_EVENT)
950                                                A(EC_WMT_EVENT)
951                                        };
952                                        #undef A
953                                        BOOL bFound = FALSE;
954                                        for(SIZE_T nIndex = 0; nIndex < DIM(g_pMap); nIndex++)
955                                                if(g_pMap[nIndex].nEventCode == nEventCode)
956                                                {
957                                                        _Z2(atlTraceGeneral, 2, _T("Filter Graph %hs Event, nEventCode 0x%X, nParameter1 0x%08X, nParameter2 0x%08X\n"), g_pMap[nIndex].pszEventName, nEventCode, nParameter1, nParameter2);
958                                                        bFound = TRUE;
959                                                        break;
960                                                }
961                                        if(!bFound)
962                                #endif // _DEVELOPMENT
963                                #pragma endregion
964                                _Z2(atlTraceGeneral, 2, _T("Filter Graph Event, nEventCode 0x%X, nParameter1 0x%08X, nParameter2 0x%08X\n"), nEventCode, nParameter1, nParameter2);
965                        }
966                }
967        };
968
969        ////////////////////////////////////////////////////
970        // CVmr7PropertyPage
971
972        class CVmr7PropertyPage :
973                public CPropertyPageT<CVmr7PropertyPage>,
974                public CDialogResize<CVmr7PropertyPage>,
975                public CVrPropertyPageT<CVmr7PropertyPage>
976        {
977        public:
978                enum { IDD = IDD_MAIN_VMR7 };
979
980        BEGIN_MSG_MAP_EX(CVmr7PropertyPage)
981                CHAIN_MSG_MAP(CPropertyPageT<CVmr7PropertyPage>)
982                CHAIN_MSG_MAP(CDialogResize<CVmr7PropertyPage>)
983                MSG_WM_INITDIALOG(OnInitDialog)
984                MSG_WM_DESTROY(OnDestroy)
985                COMMAND_ID_HANDLER_EX(IDC_MAIN_VMR7_RUN, OnRunButtonClicked)
986                COMMAND_ID_HANDLER_EX(IDC_MAIN_VMR7_PAUSE, OnPauseButtonClicked)
987                COMMAND_ID_HANDLER_EX(IDC_MAIN_VMR7_STOP, OnStopButtonClicked)
988                COMMAND_ID_HANDLER_EX(IDC_MAIN_VMR7_WEAVE, OnWeaveButtonClicked)
989                COMMAND_ID_HANDLER_EX(IDC_MAIN_VMR7_COLORIZE, OnColorizeButtonClicked)
990                MESSAGE_HANDLER_EX(WM_FILTERGRAPHEVENT, OnFilterGraphEvent)
991                REFLECT_NOTIFICATIONS()
992        END_MSG_MAP()
993
994        BEGIN_DLGRESIZE_MAP(CVmr7PropertyPage)
995                DLGRESIZE_CONTROL(IDC_MAIN_VMR7_VIDEO, DLSZ_SIZE_X | DLSZ_SIZE_Y)
996                DLGRESIZE_CONTROL(IDC_MAIN_VMR7_RUN, DLSZ_MOVE_X)
997                DLGRESIZE_CONTROL(IDC_MAIN_VMR7_PAUSE, DLSZ_MOVE_X)
998                DLGRESIZE_CONTROL(IDC_MAIN_VMR7_STOP, DLSZ_MOVE_X)
999                DLGRESIZE_CONTROL(IDC_MAIN_VMR7_WEAVE, DLSZ_MOVE_Y)
1000                DLGRESIZE_CONTROL(IDC_MAIN_VMR7_COLORIZE, DLSZ_MOVE_Y)
1001        END_DLGRESIZE_MAP()
1002
1003        public:
1004
1005                ////////////////////////////////////////////////////////
1006                // Window Message Identifiers
1007
1008                enum
1009                {
1010                        WM_FIRST = WM_APP,
1011                        WM_FILTERGRAPHEVENT,
1012                };
1013
1014        private:
1015                CMainPropertySheet& m_Owner;
1016                CStatic m_VideoStatic;
1017                CGenericFilterGraph m_FilterGraph;
1018                CObjectPtr<CSourceFilter> m_pSourceFilter;
1019                CVmr7Window m_RendererWindow;
1020                CButton m_RunButton;
1021                CButton m_PauseButton;
1022                CButton m_StopButton;
1023                CButton m_WeaveButton;
1024                CButton m_ColorizeButton;
1025
1026                VOID UpdateControls()
1027                {
1028                        OAFilterState State;
1029                        if(SUCCEEDED(m_FilterGraph.m_pMediaControl->GetState(0, &State)))
1030                        {
1031                                m_RunButton.EnableWindow(State != State_Running);
1032                                m_PauseButton.EnableWindow(State != State_Paused);
1033                                m_StopButton.EnableWindow(State != State_Stopped);
1034                        } else
1035                        {
1036                                m_RunButton.EnableWindow(FALSE);
1037                                m_PauseButton.EnableWindow(FALSE);
1038                                m_StopButton.EnableWindow(FALSE);
1039                        }
1040                }
1041
1042        public:
1043        // CVmr7PropertyPage
1044                CVmr7PropertyPage(CMainPropertySheet* pOwner) :
1045                        m_Owner(*pOwner)
1046                {
1047                }
1048
1049        // CDialogResize
1050                VOID DlgResize_UpdateLayout(INT nWidth, INT nHeight)
1051                {
1052                        __super::DlgResize_UpdateLayout(nWidth, nHeight);
1053                        CRect VideoPosition;
1054                        _W(m_VideoStatic.GetWindowRect(VideoPosition));
1055                        _W(ScreenToClient(VideoPosition));
1056                        _W(m_RendererWindow.MoveWindow(VideoPosition));
1057                }
1058
1059        // Window Message Handlers
1060                LRESULT OnInitDialog(HWND, LPARAM)
1061                {
1062                        m_VideoStatic = GetDlgItem(IDC_MAIN_VMR7_VIDEO);
1063                        m_VideoStatic.ShowWindow(SW_HIDE);
1064                        CRect VideoPosition;
1065                        _W(m_VideoStatic.GetWindowRect(VideoPosition));
1066                        _W(ScreenToClient(VideoPosition));
1067                        m_RunButton = GetDlgItem(IDC_MAIN_VMR7_RUN);
1068                        m_PauseButton = GetDlgItem(IDC_MAIN_VMR7_PAUSE);
1069                        m_StopButton = GetDlgItem(IDC_MAIN_VMR7_STOP);
1070                        m_WeaveButton = GetDlgItem(IDC_MAIN_VMR7_WEAVE);
1071                        m_ColorizeButton = GetDlgItem(IDC_MAIN_VMR7_COLORIZE);
1072                        DlgResize_Init(TRUE);
1073                        m_FilterGraph.CoCreateInstance();
1074                        CObjectPtr<CAmGraphBuilderCallback> pAmGraphBuilderCallback;
1075                        pAmGraphBuilderCallback.Construct();
1076                        pAmGraphBuilderCallback->SetGraphBuilder(m_FilterGraph.m_pFilterGraph);
1077                        const CComPtr<IBaseFilter> pBaseFilter = m_RendererWindow.CoCreateBaseFilterInstance();
1078                        __C(m_FilterGraph->AddFilter(pBaseFilter, CT2CW(_T("VMR-7"))));
1079                        m_RendererWindow.Create(m_hWnd);
1080                        _W(m_RendererWindow.MoveWindow(VideoPosition));
1081                        m_RendererWindow.ShowWindow(SW_SHOWNORMAL);
1082                        m_RendererWindow.Initialize(pBaseFilter);
1083                        CObjectPtr<CSourceFilter> pSourceFilter;
1084                        pSourceFilter.Construct()->Initialize();
1085                        pSourceFilter->SetWeave(m_WeaveButton.GetCheck());
1086                        pSourceFilter->SetColorize(m_ColorizeButton.GetCheck());
1087                        m_pSourceFilter = pSourceFilter;
1088                        __C(m_FilterGraph->AddFilter(pSourceFilter, CT2CW(_T("Source"))));
1089                        __C(m_FilterGraph->Connect(pSourceFilter->GetOutputPin(), _FilterGraphHelper::GetFilterPin(m_RendererWindow.m_pBaseFilter)));
1090                        __C(m_FilterGraph.m_pMediaEventEx->SetNotifyWindow((OAHWND) m_hWnd, WM_FILTERGRAPHEVENT, (LONG_PTR) this));
1091                        UpdateControls();
1092                        return 0;
1093                }
1094                LRESULT OnDestroy()
1095                {
1096                        if(m_FilterGraph.m_pMediaControl)
1097                                _V(m_FilterGraph.m_pMediaControl->Stop());
1098                        m_RendererWindow.Terminate();
1099                        m_pSourceFilter.Release();
1100                        m_FilterGraph.Release();
1101                        return 0;
1102                }
1103                LRESULT OnRunButtonClicked(UINT, INT, HWND)
1104                {
1105                        CWaitCursor WaitCursor;
1106                        __D(m_FilterGraph.m_pMediaControl, E_NOINTERFACE);
1107                        __C(m_FilterGraph.m_pMediaControl->Run());
1108                        UpdateControls();
1109                        #pragma region Capabilities
1110                        _ATLTRY
1111                        {
1112                                const CComQIPtr<IVMRDeinterlaceControl> pVmrDeinterlaceControl = m_RendererWindow.m_pBaseFilter;
1113                                VMRVideoDesc VideoDescription;
1114                                ZeroMemory(&VideoDescription, sizeof VideoDescription);
1115                                VideoDescription.dwSize = sizeof VideoDescription;
1116                                const CVideoInfoHeader2* pVideoInfoHeader2 = m_pSourceFilter->GetRequestedMediaType().GetVideoInfoHeader2();
1117                                _A(pVideoInfoHeader2);
1118                                const CSize Extent = pVideoInfoHeader2->GetExtent();
1119                                VideoDescription.dwSampleWidth = Extent.cx;
1120                                VideoDescription.dwSampleHeight = Extent.cy;
1121                                VideoDescription.SingleFieldPerSample = FALSE;
1122                                VideoDescription.dwFourCC = pVideoInfoHeader2->GetBitmapInfoHeader().biCompression;
1123                                VideoDescription.InputSampleFreq.dwNumerator = 30000;
1124                                VideoDescription.InputSampleFreq.dwDenominator = 1001;
1125                                VideoDescription.OutputFrameFreq.dwNumerator = 60000;
1126                                VideoDescription.OutputFrameFreq.dwDenominator = 1001;
1127                                DWORD nModeCount = 16;
1128                                CTempBufferT<GUID> pModes(nModeCount);
1129                                const HRESULT nGetNumberOfDeinterlaceModesResult = pVmrDeinterlaceControl->GetNumberOfDeinterlaceModes(&VideoDescription, &nModeCount, pModes);
1130                                _Z4(atlTraceGeneral, 4, _T("nGetNumberOfDeinterlaceModesResult 0x%08x, nModeCount %d\n"), nGetNumberOfDeinterlaceModesResult, nModeCount);
1131                                if(SUCCEEDED(nGetNumberOfDeinterlaceModesResult))
1132                                {
1133                                        for(DWORD nModeIndex = 0; nModeIndex < nModeCount; nModeIndex++)
1134                                        {
1135                                                const GUID& Mode = pModes[nModeIndex];
1136                                                _Z4(atlTraceGeneral, 4, _T("nModeIndex %d, Mode %s\n"), nModeIndex, FormatDeinterlaceMode(Mode));
1137                                                VMRDeinterlaceCaps Capabilities;
1138                                                ZeroMemory(&Capabilities, sizeof Capabilities);
1139                                                Capabilities.dwSize = sizeof Capabilities;
1140                                                const HRESULT nGetDeinterlaceModeCapsResult = pVmrDeinterlaceControl->GetDeinterlaceModeCaps(const_cast<GUID*>(&Mode), &VideoDescription, &Capabilities);
1141                                                _Z4(atlTraceGeneral, 4, _T("nGetDeinterlaceModeCapsResult 0x%08x, Capabilities.dwNumPreviousOutputFrames %d, .dwNumForwardRefSamples %d, .dwNumBackwardRefSamples %d, .DeinterlaceTechnology 0x%x\n"), nGetDeinterlaceModeCapsResult, Capabilities.dwNumPreviousOutputFrames, Capabilities.dwNumForwardRefSamples, Capabilities.dwNumBackwardRefSamples, Capabilities.DeinterlaceTechnology);
1142                                        }
1143                                }
1144                                GUID DeinterlaceMode = GUID_NULL;
1145                                const HRESULT nGetDeinterlaceModeResult = pVmrDeinterlaceControl->GetDeinterlaceMode(0, &DeinterlaceMode);
1146                                _Z4(atlTraceGeneral, 4, _T("nGetDeinterlaceModeResult 0x%08x\n"), nGetDeinterlaceModeResult);
1147                                if(SUCCEEDED(nGetDeinterlaceModeResult) && !(nGetDeinterlaceModeResult == S_FALSE && DeinterlaceMode == GUID_NULL))
1148                                        _Z4(atlTraceGeneral, 4, _T("DeinterlaceMode %s\n"), FormatDeinterlaceMode(DeinterlaceMode));
1149                                DWORD nPreferences = 0;
1150                                const HRESULT nGetDeinterlacePrefsResult = pVmrDeinterlaceControl->GetDeinterlacePrefs(&nPreferences);
1151                                _Z4(atlTraceGeneral, 4, _T("nGetDeinterlacePrefsResult 0x%08x, nPreferences 0x%x\n"), nGetDeinterlacePrefsResult, nPreferences);
1152                                GUID ActualDeinterlaceMode;
1153                                const HRESULT nGetActualDeinterlaceModeResult = pVmrDeinterlaceControl->GetActualDeinterlaceMode(0, &ActualDeinterlaceMode);
1154                                _Z4(atlTraceGeneral, 4, _T("nGetActualDeinterlaceModeResult 0x%08x\n"), nGetActualDeinterlaceModeResult);
1155                                if(SUCCEEDED(nGetActualDeinterlaceModeResult))
1156                                        _Z4(atlTraceGeneral, 4, _T("ActualDeinterlaceMode %s\n"), FormatDeinterlaceMode(ActualDeinterlaceMode));
1157                        }
1158                        _ATLCATCHALL()
1159                        {
1160                                _Z_EXCEPTION();
1161                        }
1162                        #pragma endregion
1163                        return 0;
1164                }
1165                LRESULT OnPauseButtonClicked(UINT, INT, HWND)
1166                {
1167                        CWaitCursor WaitCursor;
1168                        __D(m_FilterGraph.m_pMediaControl, E_NOINTERFACE);
1169                        __C(m_FilterGraph.m_pMediaControl->Pause());
1170                        UpdateControls();
1171                        return 0;
1172                }
1173                LRESULT OnStopButtonClicked(UINT, INT, HWND)
1174                {
1175                        CWaitCursor WaitCursor;
1176                        if(m_FilterGraph.m_pMediaControl)
1177                                _V(m_FilterGraph.m_pMediaControl->Stop());
1178                        UpdateControls();
1179                        return 0;
1180                }
1181                LRESULT OnWeaveButtonClicked(UINT, INT, HWND)
1182                {
1183                        if(m_pSourceFilter)
1184                                m_pSourceFilter->SetWeave(m_WeaveButton.GetCheck());
1185                        return 0;
1186                }
1187                LRESULT OnColorizeButtonClicked(UINT, INT, HWND)
1188                {
1189                        if(m_pSourceFilter)
1190                                m_pSourceFilter->SetColorize(m_ColorizeButton.GetCheck());
1191                        return 0;
1192                }
1193                LRESULT OnFilterGraphEvent(UINT, WPARAM, LPARAM)
1194                {
1195                        if(!m_FilterGraph.m_pMediaEventEx)
1196                                return 0;
1197                        _ATLTRY
1198                        {
1199                                for(; ; )
1200                                {
1201                                        LONG nEventCode;
1202                                        LONG_PTR nParameter1, nParameter2;
1203                                        const HRESULT nGetEventResult = m_FilterGraph.m_pMediaEventEx->GetEvent(&nEventCode, &nParameter1, &nParameter2, 0);
1204                                        if(nGetEventResult == E_ABORT)
1205                                                break;
1206                                        __C(nGetEventResult);
1207                                        _ATLTRY
1208                                        {
1209                                                HandleMediaEvent(nEventCode, nParameter1, nParameter2);
1210                                        }
1211                                        _ATLCATCHALL()
1212                                        {
1213                                                _V(m_FilterGraph.m_pMediaEventEx->FreeEventParams(nEventCode, nParameter1, nParameter2));
1214                                                _ATLRETHROW;
1215                                        }
1216                                        _V(m_FilterGraph.m_pMediaEventEx->FreeEventParams(nEventCode, nParameter1, nParameter2));
1217                                }
1218                        }
1219                        _ATLCATCHALL()
1220                        {
1221                                _Z_EXCEPTION();
1222                        }
1223                        return 0;
1224                }
1225                INT OnKillActive()
1226                {
1227                        m_StopButton.Click();
1228                        return 0;
1229                }
1230        };
1231
1232        ////////////////////////////////////////////////////
1233        // CVmr9PropertyPage
1234
1235        class CVmr9PropertyPage :
1236                public CPropertyPageT<CVmr9PropertyPage>,
1237                public CDialogResize<CVmr9PropertyPage>,
1238                public CVrPropertyPageT<CVmr9PropertyPage>
1239        {
1240        public:
1241                enum { IDD = IDD_MAIN_VMR9 };
1242
1243        BEGIN_MSG_MAP_EX(CVmr9PropertyPage)
1244                CHAIN_MSG_MAP(CPropertyPageT<CVmr9PropertyPage>)
1245                CHAIN_MSG_MAP(CDialogResize<CVmr9PropertyPage>)
1246                MSG_WM_INITDIALOG(OnInitDialog)
1247                MSG_WM_DESTROY(OnDestroy)
1248                COMMAND_ID_HANDLER_EX(IDC_MAIN_VMR9_RUN, OnRunButtonClicked)
1249                COMMAND_ID_HANDLER_EX(IDC_MAIN_VMR9_PAUSE, OnPauseButtonClicked)
1250                COMMAND_ID_HANDLER_EX(IDC_MAIN_VMR9_STOP, OnStopButtonClicked)
1251                COMMAND_ID_HANDLER_EX(IDC_MAIN_VMR9_WEAVE, OnWeaveButtonClicked)
1252                COMMAND_ID_HANDLER_EX(IDC_MAIN_VMR9_COLORIZE, OnColorizeButtonClicked)
1253                MESSAGE_HANDLER_EX(WM_FILTERGRAPHEVENT, OnFilterGraphEvent)
1254                REFLECT_NOTIFICATIONS()
1255        END_MSG_MAP()
1256
1257        BEGIN_DLGRESIZE_MAP(CVmr9PropertyPage)
1258                DLGRESIZE_CONTROL(IDC_MAIN_VMR9_VIDEO, DLSZ_SIZE_X | DLSZ_SIZE_Y)
1259                DLGRESIZE_CONTROL(IDC_MAIN_VMR9_RUN, DLSZ_MOVE_X)
1260                DLGRESIZE_CONTROL(IDC_MAIN_VMR9_PAUSE, DLSZ_MOVE_X)
1261                DLGRESIZE_CONTROL(IDC_MAIN_VMR9_STOP, DLSZ_MOVE_X)
1262                DLGRESIZE_CONTROL(IDC_MAIN_VMR9_WEAVE, DLSZ_MOVE_Y)
1263                DLGRESIZE_CONTROL(IDC_MAIN_VMR9_COLORIZE, DLSZ_MOVE_Y)
1264        END_DLGRESIZE_MAP()
1265
1266        public:
1267
1268                ////////////////////////////////////////////////////////
1269                // Window Message Identifiers
1270
1271                enum
1272                {
1273                        WM_FIRST = WM_APP,
1274                        WM_FILTERGRAPHEVENT,
1275                };
1276
1277        private:
1278                CMainPropertySheet& m_Owner;
1279                CStatic m_VideoStatic;
1280                CGenericFilterGraph m_FilterGraph;
1281                CObjectPtr<CSourceFilter> m_pSourceFilter;
1282                CVmr9Window m_RendererWindow;
1283                CButton m_RunButton;
1284                CButton m_PauseButton;
1285                CButton m_StopButton;
1286                CButton m_WeaveButton;
1287                CButton m_ColorizeButton;
1288
1289                VOID UpdateControls()
1290                {
1291                        OAFilterState State;
1292                        if(SUCCEEDED(m_FilterGraph.m_pMediaControl->GetState(0, &State)))
1293                        {
1294                                m_RunButton.EnableWindow(State != State_Running);
1295                                m_PauseButton.EnableWindow(State != State_Paused);
1296                                m_StopButton.EnableWindow(State != State_Stopped);
1297                        } else
1298                        {
1299                                m_RunButton.EnableWindow(FALSE);
1300                                m_PauseButton.EnableWindow(FALSE);
1301                                m_StopButton.EnableWindow(FALSE);
1302                        }
1303                }
1304
1305        public:
1306        // CVmr9PropertyPage
1307                CVmr9PropertyPage(CMainPropertySheet* pOwner) :
1308                        m_Owner(*pOwner)
1309                {
1310                }
1311
1312        // CDialogResize
1313                VOID DlgResize_UpdateLayout(INT nWidth, INT nHeight)
1314                {
1315                        __super::DlgResize_UpdateLayout(nWidth, nHeight);
1316                        CRect VideoPosition;
1317                        _W(m_VideoStatic.GetWindowRect(VideoPosition));
1318                        _W(ScreenToClient(VideoPosition));
1319                        _W(m_RendererWindow.MoveWindow(VideoPosition));
1320                }
1321
1322        // Window Message Handlers
1323                LRESULT OnInitDialog(HWND, LPARAM)
1324                {
1325                        m_VideoStatic = GetDlgItem(IDC_MAIN_VMR9_VIDEO);
1326                        m_VideoStatic.ShowWindow(SW_HIDE);
1327                        CRect VideoPosition;
1328                        _W(m_VideoStatic.GetWindowRect(VideoPosition));
1329                        _W(ScreenToClient(VideoPosition));
1330                        m_RunButton = GetDlgItem(IDC_MAIN_VMR9_RUN);
1331                        m_PauseButton = GetDlgItem(IDC_MAIN_VMR9_PAUSE);
1332                        m_StopButton = GetDlgItem(IDC_MAIN_VMR9_STOP);
1333                        m_WeaveButton = GetDlgItem(IDC_MAIN_VMR9_WEAVE);
1334                        m_ColorizeButton = GetDlgItem(IDC_MAIN_VMR9_COLORIZE);
1335                        DlgResize_Init(TRUE);
1336                        m_FilterGraph.CoCreateInstance();
1337                        CObjectPtr<CAmGraphBuilderCallback> pAmGraphBuilderCallback;
1338                        pAmGraphBuilderCallback.Construct();
1339                        pAmGraphBuilderCallback->SetGraphBuilder(m_FilterGraph.m_pFilterGraph);
1340
1341                        const CComPtr<IBaseFilter> pBaseFilter = m_RendererWindow.CoCreateBaseFilterInstance();
1342                        __C(m_FilterGraph->AddFilter(pBaseFilter, CT2CW(_T("VMR-9"))));
1343                        m_RendererWindow.Create(m_hWnd);
1344                        _W(m_RendererWindow.MoveWindow(VideoPosition));
1345                        m_RendererWindow.ShowWindow(SW_SHOWNORMAL);
1346                        m_RendererWindow.Initialize(pBaseFilter);
1347                        CObjectPtr<CSourceFilter> pSourceFilter;
1348                        pSourceFilter.Construct()->Initialize();
1349                        pSourceFilter->SetWeave(m_WeaveButton.GetCheck());
1350                        pSourceFilter->SetColorize(m_ColorizeButton.GetCheck());
1351                        m_pSourceFilter = pSourceFilter;
1352                        __C(m_FilterGraph->AddFilter(pSourceFilter, CT2CW(_T("Source"))));
1353                        __C(m_FilterGraph->Connect(pSourceFilter->GetOutputPin(), _FilterGraphHelper::GetFilterPin(m_RendererWindow.m_pBaseFilter)));
1354                        __C(m_FilterGraph.m_pMediaEventEx->SetNotifyWindow((OAHWND) m_hWnd, WM_FILTERGRAPHEVENT, (LONG_PTR) this));
1355                        #pragma region Simulate EC_DISPLAY_CHANGED (Development)
1356                        #if _DEVELOPMENT
1357                                __C(m_FilterGraph.m_pMediaEventEx->CancelDefaultHandling(EC_DISPLAY_CHANGED));
1358                                _W(GetParent().SetWindowPos(NULL, 1680 + 100, 100, 0, 0, SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE));
1359                                CRect RendererPosition;
1360                                _W(m_RendererWindow.GetWindowRect(RendererPosition));
1361                                CVmr9Window::CMonitorInformation MonitorInformation(pBaseFilter);
1362                                UINT nMonitor;
1363                                if(MonitorInformation.SuggestMonitor(RendererPosition, nMonitor))
1364                                {
1365                                        _Z4(atlTraceGeneral, 4, _T("nMonitor %d\n"), nMonitor);
1366                                        _A(MonitorInformation.m_pVmrMonitorConfig->SetMonitor(nMonitor) == VFW_E_WRONG_STATE);
1367                                        const CComPtr<IPin> pInputPin = _FilterGraphHelper::GetFilterPin(pBaseFilter, PINDIR_INPUT);
1368                                        const CComPtr<IPin> pOutputPin = _FilterGraphHelper::GetPeerPin(pInputPin);
1369                                        __D(pInputPin && pOutputPin, E_NOINTERFACE);
1370                                        const CMediaType pMediaType = _FilterGraphHelper::GetPinMediaType(pOutputPin);
1371                                        __C(m_FilterGraph.Disconnect(pOutputPin));
1372                                        __C(m_FilterGraph.Disconnect(pInputPin));
1373                                        const HRESULT nSetMonitorResult = MonitorInformation.m_pVmrMonitorConfig->SetMonitor(nMonitor);
1374                                        _Z45_DSHRESULT(nSetMonitorResult);
1375                                        m_RendererWindow.UpdateVideoPosition();
1376                                        const HRESULT nConnectResult = m_FilterGraph.ConnectDirect(pOutputPin, pInputPin, pMediaType);
1377                                        _Z45_DSHRESULT(nConnectResult);
1378                                        if(FAILED(nConnectResult))
1379                                                __C(m_FilterGraph.Connect(pOutputPin, pInputPin));
1380                                }
1381                        #endif // _DEVELOPMENT
1382                        #pragma endregion
1383                        UpdateControls();
1384                        return 0;
1385                }
1386                LRESULT OnDestroy()
1387                {
1388                        if(m_FilterGraph.m_pMediaControl)
1389                                _V(m_FilterGraph.m_pMediaControl->Stop());
1390                        m_RendererWindow.Terminate();
1391                        m_pSourceFilter.Release();
1392                        m_FilterGraph.Release();
1393                        return 0;
1394                }
1395                LRESULT OnRunButtonClicked(UINT, INT, HWND)
1396                {
1397                        CWaitCursor WaitCursor;
1398                        __D(m_FilterGraph.m_pMediaControl, E_NOINTERFACE);
1399                        __C(m_FilterGraph.m_pMediaControl->Run());
1400                        UpdateControls();
1401                        #pragma region Capabilities
1402                        _ATLTRY
1403                        {
1404                                const CComQIPtr<IVMRDeinterlaceControl9> pVmrDeinterlaceControl9 = m_RendererWindow.m_pBaseFilter;
1405                                VMR9VideoDesc VideoDescription;
1406                                ZeroMemory(&VideoDescription, sizeof VideoDescription);
1407                                VideoDescription.dwSize = sizeof VideoDescription;
1408                                const CVideoInfoHeader2* pVideoInfoHeader2 = m_pSourceFilter->GetRequestedMediaType().GetVideoInfoHeader2();
1409                                _A(pVideoInfoHeader2);
1410                                const CSize Extent = pVideoInfoHeader2->GetExtent();
1411                                VideoDescription.dwSampleWidth = Extent.cx;
1412                                VideoDescription.dwSampleHeight = Extent.cy;
1413                                VideoDescription.SampleFormat = VMR9_SampleFieldInterleavedEvenFirst;
1414                                VideoDescription.dwFourCC = pVideoInfoHeader2->GetBitmapInfoHeader().biCompression;
1415                                VideoDescription.InputSampleFreq.dwNumerator = 30000;
1416                                VideoDescription.InputSampleFreq.dwDenominator = 1001;
1417                                VideoDescription.OutputFrameFreq.dwNumerator = 60000;
1418                                VideoDescription.OutputFrameFreq.dwDenominator = 1001;
1419                                DWORD nModeCount = 16;
1420                                CTempBufferT<GUID> pModes(nModeCount);
1421                                const HRESULT nGetNumberOfDeinterlaceModesResult = pVmrDeinterlaceControl9->GetNumberOfDeinterlaceModes(&VideoDescription, &nModeCount, pModes);
1422                                _Z4(atlTraceGeneral, 4, _T("nGetNumberOfDeinterlaceModesResult 0x%08x, nModeCount %d\n"), nGetNumberOfDeinterlaceModesResult, nModeCount);
1423                                if(SUCCEEDED(nGetNumberOfDeinterlaceModesResult))
1424                                {
1425                                        for(DWORD nModeIndex = 0; nModeIndex < nModeCount; nModeIndex++)
1426                                        {
1427                                                const GUID& Mode = pModes[nModeIndex];
1428                                                _Z4(atlTraceGeneral, 4, _T("nModeIndex %d, Mode %s\n"), nModeIndex, FormatDeinterlaceMode(Mode));
1429                                                VMR9DeinterlaceCaps Capabilities;
1430                                                ZeroMemory(&Capabilities, sizeof Capabilities);
1431                                                Capabilities.dwSize = sizeof Capabilities;
1432                                                const HRESULT nGetDeinterlaceModeCapsResult = pVmrDeinterlaceControl9->GetDeinterlaceModeCaps(const_cast<GUID*>(&Mode), &VideoDescription, &Capabilities);
1433                                                _Z4(atlTraceGeneral, 4, _T("nGetDeinterlaceModeCapsResult 0x%08x, Capabilities.dwNumPreviousOutputFrames %d, .dwNumForwardRefSamples %d, .dwNumBackwardRefSamples %d, .DeinterlaceTechnology 0x%x\n"), nGetDeinterlaceModeCapsResult, Capabilities.dwNumPreviousOutputFrames, Capabilities.dwNumForwardRefSamples, Capabilities.dwNumBackwardRefSamples, Capabilities.DeinterlaceTechnology);
1434                                        }
1435                                }
1436                                GUID DeinterlaceMode = GUID_NULL;
1437                                const HRESULT nGetDeinterlaceModeResult = pVmrDeinterlaceControl9->GetDeinterlaceMode(0, &DeinterlaceMode);
1438                                _Z4(atlTraceGeneral, 4, _T("nGetDeinterlaceModeResult 0x%08x\n"), nGetDeinterlaceModeResult);
1439                                if(SUCCEEDED(nGetDeinterlaceModeResult) && !(nGetDeinterlaceModeResult == S_FALSE && DeinterlaceMode == GUID_NULL))
1440                                        _Z4(atlTraceGeneral, 4, _T("DeinterlaceMode %s\n"), FormatDeinterlaceMode(DeinterlaceMode));
1441                                DWORD nPreferences = 0;
1442                                const HRESULT nGetDeinterlacePrefsResult = pVmrDeinterlaceControl9->GetDeinterlacePrefs(&nPreferences);
1443                                _Z4(atlTraceGeneral, 4, _T("nGetDeinterlacePrefsResult 0x%08x, nPreferences 0x%x\n"), nGetDeinterlacePrefsResult, nPreferences);
1444                                GUID ActualDeinterlaceMode;
1445                                const HRESULT nGetActualDeinterlaceModeResult = pVmrDeinterlaceControl9->GetActualDeinterlaceMode(0, &ActualDeinterlaceMode);
1446                                _Z4(atlTraceGeneral, 4, _T("nGetActualDeinterlaceModeResult 0x%08x\n"), nGetActualDeinterlaceModeResult);
1447                                if(SUCCEEDED(nGetActualDeinterlaceModeResult))
1448                                        _Z4(atlTraceGeneral, 4, _T("ActualDeinterlaceMode %s\n"), FormatDeinterlaceMode(ActualDeinterlaceMode));
1449                        }
1450                        _ATLCATCHALL()
1451                        {
1452                                _Z_EXCEPTION();
1453                        }
1454                        #pragma endregion
1455                        return 0;
1456                }
1457                LRESULT OnPauseButtonClicked(UINT, INT, HWND)
1458                {
1459                        CWaitCursor WaitCursor;
1460                        __D(m_FilterGraph.m_pMediaControl, E_NOINTERFACE);
1461                        __C(m_FilterGraph.m_pMediaControl->Pause());
1462                        UpdateControls();
1463                        return 0;
1464                }
1465                LRESULT OnStopButtonClicked(UINT, INT, HWND)
1466                {
1467                        CWaitCursor WaitCursor;
1468                        if(m_FilterGraph.m_pMediaControl)
1469                                _V(m_FilterGraph.m_pMediaControl->Stop());
1470                        UpdateControls();
1471                        return 0;
1472                }
1473                LRESULT OnWeaveButtonClicked(UINT, INT, HWND)
1474                {
1475                        if(m_pSourceFilter)
1476                                m_pSourceFilter->SetWeave(m_WeaveButton.GetCheck());
1477                        return 0;
1478                }
1479                LRESULT OnColorizeButtonClicked(UINT, INT, HWND)
1480                {
1481                        if(m_pSourceFilter)
1482                                m_pSourceFilter->SetColorize(m_ColorizeButton.GetCheck());
1483                        return 0;
1484                }
1485                LRESULT OnFilterGraphEvent(UINT, WPARAM, LPARAM)
1486                {
1487                        if(!m_FilterGraph.m_pMediaEventEx)
1488                                return 0;
1489                        _ATLTRY
1490                        {
1491                                for(; ; )
1492                                {
1493                                        LONG nEventCode;
1494                                        LONG_PTR nParameter1, nParameter2;
1495                                        const HRESULT nGetEventResult = m_FilterGraph.m_pMediaEventEx->GetEvent(&nEventCode, &nParameter1, &nParameter2, 0);
1496                                        if(nGetEventResult == E_ABORT)
1497                                                break;
1498                                        __C(nGetEventResult);
1499                                        _ATLTRY
1500                                        {
1501                                                HandleMediaEvent(nEventCode, nParameter1, nParameter2);
1502                                        }
1503                                        _ATLCATCHALL()
1504                                        {
1505                                                _V(m_FilterGraph.m_pMediaEventEx->FreeEventParams(nEventCode, nParameter1, nParameter2));
1506                                                _ATLRETHROW;
1507                                        }
1508                                        _V(m_FilterGraph.m_pMediaEventEx->FreeEventParams(nEventCode, nParameter1, nParameter2));
1509                                }
1510                        }
1511                        _ATLCATCHALL()
1512                        {
1513                                _Z_EXCEPTION();
1514                        }
1515                        return 0;
1516                }
1517                INT OnKillActive()
1518                {
1519                        m_StopButton.Click();
1520                        return 0;
1521                }
1522        };
1523
1524        ////////////////////////////////////////////////////
1525        // CEvrPropertyPage
1526
1527        class CEvrPropertyPage :
1528                public CPropertyPageT<CEvrPropertyPage>,
1529                public CDialogResize<CEvrPropertyPage>,
1530                public CVrPropertyPageT<CEvrPropertyPage>
1531        {
1532        public:
1533                enum { IDD = IDD_MAIN_EVR };
1534
1535        BEGIN_MSG_MAP_EX(CEvrPropertyPage)
1536                CHAIN_MSG_MAP(CPropertyPageT<CEvrPropertyPage>)
1537                CHAIN_MSG_MAP(CDialogResize<CEvrPropertyPage>)
1538                MSG_WM_INITDIALOG(OnInitDialog)
1539                MSG_WM_DESTROY(OnDestroy)
1540                COMMAND_ID_HANDLER_EX(IDC_MAIN_EVR_RUN, OnRunButtonClicked)
1541                COMMAND_ID_HANDLER_EX(IDC_MAIN_EVR_PAUSE, OnPauseButtonClicked)
1542                COMMAND_ID_HANDLER_EX(IDC_MAIN_EVR_STOP, OnStopButtonClicked)
1543                COMMAND_ID_HANDLER_EX(IDC_MAIN_EVR_WEAVE, OnWeaveButtonClicked)
1544                COMMAND_ID_HANDLER_EX(IDC_MAIN_EVR_COLORIZE, OnColorizeButtonClicked)
1545                MESSAGE_HANDLER_EX(WM_FILTERGRAPHEVENT, OnFilterGraphEvent)
1546                REFLECT_NOTIFICATIONS()
1547        END_MSG_MAP()
1548
1549        BEGIN_DLGRESIZE_MAP(CEvrPropertyPage)
1550                DLGRESIZE_CONTROL(IDC_MAIN_EVR_VIDEO, DLSZ_SIZE_X | DLSZ_SIZE_Y)
1551                DLGRESIZE_CONTROL(IDC_MAIN_EVR_RUN, DLSZ_MOVE_X)
1552                DLGRESIZE_CONTROL(IDC_MAIN_EVR_PAUSE, DLSZ_MOVE_X)
1553                DLGRESIZE_CONTROL(IDC_MAIN_EVR_STOP, DLSZ_MOVE_X)
1554                DLGRESIZE_CONTROL(IDC_MAIN_EVR_WEAVE, DLSZ_MOVE_Y)
1555                DLGRESIZE_CONTROL(IDC_MAIN_EVR_COLORIZE, DLSZ_MOVE_Y)
1556        END_DLGRESIZE_MAP()
1557
1558        public:
1559
1560                ////////////////////////////////////////////////////////
1561                // Window Message Identifiers
1562
1563                enum
1564                {
1565                        WM_FIRST = WM_APP,
1566                        WM_FILTERGRAPHEVENT,
1567                };
1568
1569        private:
1570                CMainPropertySheet& m_Owner;
1571                CStatic m_VideoStatic;
1572                CGenericFilterGraph m_FilterGraph;
1573                CObjectPtr<CSourceFilter> m_pSourceFilter;
1574                CEvrWindow m_RendererWindow;
1575                CButton m_RunButton;
1576                CButton m_PauseButton;
1577                CButton m_StopButton;
1578                CButton m_WeaveButton;
1579                CButton m_ColorizeButton;
1580
1581                VOID UpdateControls()
1582                {
1583                        OAFilterState State;
1584                        if(SUCCEEDED(m_FilterGraph.m_pMediaControl->GetState(0, &State)))
1585                        {
1586                                m_RunButton.EnableWindow(State != State_Running);
1587                                m_PauseButton.EnableWindow(State != State_Paused);
1588                                m_StopButton.EnableWindow(State != State_Stopped);
1589                        } else
1590                        {
1591                                m_RunButton.EnableWindow(FALSE);
1592                                m_PauseButton.EnableWindow(FALSE);
1593                                m_StopButton.EnableWindow(FALSE);
1594                        }
1595                }
1596
1597        public:
1598        // CEvrPropertyPage
1599                CEvrPropertyPage(CMainPropertySheet* pOwner) :
1600                        m_Owner(*pOwner)
1601                {
1602                }
1603
1604        // CDialogResize
1605                VOID DlgResize_UpdateLayout(INT nWidth, INT nHeight)
1606                {
1607                        __super::DlgResize_UpdateLayout(nWidth, nHeight);
1608                        CRect VideoPosition;
1609                        _W(m_VideoStatic.GetWindowRect(VideoPosition));
1610                        _W(ScreenToClient(VideoPosition));
1611                        _W(m_RendererWindow.MoveWindow(VideoPosition));
1612                }
1613
1614        // Window Message Handlers
1615                LRESULT OnInitDialog(HWND, LPARAM)
1616                {
1617                        m_VideoStatic = GetDlgItem(IDC_MAIN_EVR_VIDEO);
1618                        m_VideoStatic.ShowWindow(SW_HIDE);
1619                        CRect VideoPosition;
1620                        _W(m_VideoStatic.GetWindowRect(VideoPosition));
1621                        _W(ScreenToClient(VideoPosition));
1622                        m_RunButton = GetDlgItem(IDC_MAIN_EVR_RUN);
1623                        m_PauseButton = GetDlgItem(IDC_MAIN_EVR_PAUSE);
1624                        m_StopButton = GetDlgItem(IDC_MAIN_EVR_STOP);
1625                        m_WeaveButton = GetDlgItem(IDC_MAIN_EVR_WEAVE);
1626                        m_ColorizeButton = GetDlgItem(IDC_MAIN_EVR_COLORIZE);
1627                        DlgResize_Init(TRUE);
1628                        m_FilterGraph.CoCreateInstance();
1629                        CObjectPtr<CAmGraphBuilderCallback> pAmGraphBuilderCallback;
1630                        pAmGraphBuilderCallback.Construct();
1631                        pAmGraphBuilderCallback->SetGraphBuilder(m_FilterGraph.m_pFilterGraph);
1632                        const CComPtr<IBaseFilter> pBaseFilter = m_RendererWindow.CoCreateBaseFilterInstance();
1633                        __C(m_FilterGraph->AddFilter(pBaseFilter, CT2CW(_T("EVR"))));
1634                        m_RendererWindow.Create(m_hWnd);
1635                        _W(m_RendererWindow.MoveWindow(VideoPosition));
1636                        m_RendererWindow.ShowWindow(SW_SHOWNORMAL);
1637                        m_RendererWindow.Initialize(pBaseFilter);
1638                        CObjectPtr<CSourceFilter> pSourceFilter;
1639                        pSourceFilter.Construct()->Initialize();
1640                        pSourceFilter->SetWeave(m_WeaveButton.GetCheck());
1641                        pSourceFilter->SetColorize(m_ColorizeButton.GetCheck());
1642                        m_pSourceFilter = pSourceFilter;
1643                        __C(m_FilterGraph->AddFilter(pSourceFilter, CT2CW(_T("Source"))));
1644                        __C(m_FilterGraph->Connect(pSourceFilter->GetOutputPin(), _FilterGraphHelper::GetFilterPin(m_RendererWindow.m_pBaseFilter)));
1645                        __C(m_FilterGraph.m_pMediaEventEx->SetNotifyWindow((OAHWND) m_hWnd, WM_FILTERGRAPHEVENT, (LONG_PTR) this));
1646                        UpdateControls();
1647                        return 0;
1648                }
1649                LRESULT OnDestroy()
1650                {
1651                        if(m_FilterGraph.m_pMediaControl)
1652                                _V(m_FilterGraph.m_pMediaControl->Stop());
1653                        m_RendererWindow.Terminate();
1654                        m_pSourceFilter.Release();
1655                        m_FilterGraph.Release();
1656                        return 0;
1657                }
1658                LRESULT OnRunButtonClicked(UINT, INT, HWND)
1659                {
1660                        CWaitCursor WaitCursor;
1661                        __D(m_FilterGraph.m_pMediaControl, E_NOINTERFACE);
1662                        __C(m_FilterGraph.m_pMediaControl->Run());
1663                        UpdateControls();
1664                        #pragma region Capabilities
1665                        _ATLTRY
1666                        {
1667                                const CComQIPtr<IMFGetService> pMfGetService = m_RendererWindow.m_pBaseFilter;
1668                                __D(pMfGetService, E_NOINTERFACE);
1669                                CComQIPtr<IMFVideoProcessor> pMfVideoProcessor;
1670                                __C(pMfGetService->GetService(MR_VIDEO_MIXER_SERVICE, __uuidof(IMFVideoProcessor), (VOID**) &pMfVideoProcessor));
1671                                __D(pMfVideoProcessor, E_NOINTERFACE);
1672                                UINT nModeCount = 0;
1673                                CComHeapPtr<GUID> pModes;
1674                                const HRESULT nGetAvailableVideoProcessorModesResult = pMfVideoProcessor->GetAvailableVideoProcessorModes(&nModeCount, &pModes);
1675                                _Z4(atlTraceGeneral, 4, _T("nGetAvailableVideoProcessorModesResult 0x%08x, nModeCount %d\n"), nGetAvailableVideoProcessorModesResult, nModeCount);
1676                                if(SUCCEEDED(nGetAvailableVideoProcessorModesResult))
1677                                {
1678                                        for(DWORD nModeIndex = 0; nModeIndex < nModeCount; nModeIndex++)
1679                                        {
1680                                                const GUID& Mode = pModes[nModeIndex];
1681                                                _Z4(atlTraceGeneral, 4, _T("nModeIndex %d, Mode %s\n"), nModeIndex, FormatDeinterlaceMode(Mode));
1682                                                DXVA2_VideoProcessorCaps Capabilities;
1683                                                ZeroMemory(&Capabilities, sizeof Capabilities);
1684                                                const HRESULT nGetVideoProcessorCapsResult = pMfVideoProcessor->GetVideoProcessorCaps(const_cast<GUID*>(&Mode), &Capabilities);
1685                                                _Z4(atlTraceGeneral, 4, _T("nGetVideoProcessorCapsResult 0x%08x") _T(", ") 
1686                                                        _T("Capabilities") 
1687                                                        _T(".NumForwardRefSamples %d") _T(", ") 
1688                                                        _T(".NumBackwardRefSamples %d") _T(", ") 
1689                                                        _T(".DeinterlaceTechnology %d") _T(", ") 
1690                                                        _T(".ProcAmpControlCaps %d") _T(", ") 
1691                                                        _T(".VideoProcessorOperations %d") _T(", ") 
1692                                                        _T(".NoiseFilterTechnology %d") _T(", ") 
1693                                                        _T(".DetailFilterTechnology %d") _T(", ") 
1694                                                        _T("\n"), 
1695                                                        nGetVideoProcessorCapsResult, 
1696                                                        Capabilities.DeviceCaps,
1697                                                        //Capabilities.InputPool,
1698                                                        Capabilities.NumForwardRefSamples,
1699                                                        Capabilities.NumBackwardRefSamples,
1700                                                        Capabilities.DeinterlaceTechnology,
1701                                                        Capabilities.ProcAmpControlCaps,
1702                                                        Capabilities.VideoProcessorOperations,
1703                                                        Capabilities.NoiseFilterTechnology,
1704                                                        Capabilities.DetailFilterTechnology,
1705                                                        0);
1706                                        }
1707                                }
1708                                GUID Mode = GUID_NULL;
1709                                const HRESULT nGetVideoProcessorModeResult = pMfVideoProcessor->GetVideoProcessorMode(&Mode);
1710                                _Z4(atlTraceGeneral, 4, _T("nGetVideoProcessorModeResult 0x%08x\n"), nGetVideoProcessorModeResult);
1711                                if(SUCCEEDED(nGetVideoProcessorModeResult) && !(nGetVideoProcessorModeResult == S_FALSE && Mode == GUID_NULL))
1712                                        _Z4(atlTraceGeneral, 4, _T("Mode %s\n"), FormatDeinterlaceMode(Mode));
1713                        }
1714                        _ATLCATCHALL()
1715                        {
1716                                _Z_EXCEPTION();
1717                        }
1718                        #pragma endregion
1719                        return 0;
1720                }
1721                LRESULT OnPauseButtonClicked(UINT, INT, HWND)
1722                {
1723                        CWaitCursor WaitCursor;
1724                        __D(m_FilterGraph.m_pMediaControl, E_NOINTERFACE);
1725                        __C(m_FilterGraph.m_pMediaControl->Pause());
1726                        UpdateControls();
1727                        return 0;
1728                }
1729                LRESULT OnStopButtonClicked(UINT, INT, HWND)
1730                {
1731                        CWaitCursor WaitCursor;
1732                        if(m_FilterGraph.m_pMediaControl)
1733                                _V(m_FilterGraph.m_pMediaControl->Stop());
1734                        UpdateControls();
1735                        return 0;
1736                }
1737                LRESULT OnWeaveButtonClicked(UINT, INT, HWND)
1738                {
1739                        if(m_pSourceFilter)
1740                                m_pSourceFilter->SetWeave(m_WeaveButton.GetCheck());
1741                        return 0;
1742                }
1743                LRESULT OnColorizeButtonClicked(UINT, INT, HWND)
1744                {
1745                        if(m_pSourceFilter)
1746                                m_pSourceFilter->SetColorize(m_ColorizeButton.GetCheck());
1747                        return 0;
1748                }
1749                LRESULT OnFilterGraphEvent(UINT, WPARAM, LPARAM)
1750                {
1751                        if(!m_FilterGraph.m_pMediaEventEx)
1752                                return 0;
1753                        _ATLTRY
1754                        {
1755                                for(; ; )
1756                                {
1757                                        LONG nEventCode;
1758                                        LONG_PTR nParameter1, nParameter2;
1759                                        const HRESULT nGetEventResult = m_FilterGraph.m_pMediaEventEx->GetEvent(&nEventCode, &nParameter1, &nParameter2, 0);
1760                                        if(nGetEventResult == E_ABORT)
1761                                                break;
1762                                        __C(nGetEventResult);
1763                                        _ATLTRY
1764                                        {
1765                                                HandleMediaEvent(nEventCode, nParameter1, nParameter2);
1766                                        }
1767                                        _ATLCATCHALL()
1768                                        {
1769                                                _V(m_FilterGraph.m_pMediaEventEx->FreeEventParams(nEventCode, nParameter1, nParameter2));
1770                                                _ATLRETHROW;
1771                                        }
1772                                        _V(m_FilterGraph.m_pMediaEventEx->FreeEventParams(nEventCode, nParameter1, nParameter2));
1773                                }
1774                        }
1775                        _ATLCATCHALL()
1776                        {
1777                                _Z_EXCEPTION();
1778                        }
1779                        return 0;
1780                }
1781                INT OnKillActive()
1782                {
1783                        m_StopButton.Click();
1784                        return 0;
1785                }
1786        };
1787
1788public:
1789        CVmr7PropertyPage m_Vmr7PropertyPage;
1790        CVmr9PropertyPage m_Vmr9PropertyPage;
1791        CEvrPropertyPage m_EvrPropertyPage;
1792
1793public:
1794// CMainPropertySheet
1795        CMainPropertySheet() :
1796                CSizablePropertySheetT<CMainPropertySheet>(_T("Render Interlaced Video")),
1797                m_Vmr7PropertyPage(this),
1798                m_Vmr9PropertyPage(this),
1799                m_EvrPropertyPage(this)
1800        {
1801                //AddPage(m_Vmr7PropertyPage);
1802                AddPage(m_Vmr9PropertyPage);
1803                //AddPage(m_EvrPropertyPage);
1804        }
1805        BOOL SetInitialPosition()
1806        {
1807                if(!__super::SetInitialPosition())
1808                        return FALSE;
1809                _W(PostMessage(WM_SETLARGERINITIALPOSITION));
1810                return TRUE;
1811        }
1812        static CString FormatDeinterlaceMode(const GUID& DeinterlaceMode)
1813        {
1814                // NOTE: Windows SDK does not provide a linkable identifier...
1815                #pragma region VMR-7/9
1816                struct __declspec(uuid("{335aa36e-7884-43a4-9c91-7f87faf3e37e}")) DXVA_DeinterlaceBobDevice;
1817                struct __declspec(uuid("{0e85cb93-3046-4ff0-aecc-d58cb5f035fd}")) DXVA_DeinterlaceContainerDevice;
1818                if(DeinterlaceMode == __uuidof(DXVA_DeinterlaceBobDevice))
1819                        return _T("DXVA_DeinterlaceBobDevice");
1820                if(DeinterlaceMode == __uuidof(DXVA_DeinterlaceContainerDevice))
1821                        return _T("DXVA_DeinterlaceContainerDevice");
1822                #pragma endregion
1823                #pragma region EVR, DXVA2
1824                struct __declspec(uuid("{5a54a0c9-c7ec-4bd9-8ede-f3c75dc4393b}")) DXVA2_VideoProcProgressiveDevice;
1825                struct __declspec(uuid("{335aa36e-7884-43a4-9c91-7f87faf3e37e}")) DXVA2_VideoProcBobDevice;
1826                struct __declspec(uuid("{4553d47f-ee7e-4e3f-9475-dbf1376c4810}")) DXVA2_VideoProcSoftwareDevice;
1827                if(DeinterlaceMode == __uuidof(DXVA2_VideoProcProgressiveDevice))
1828                        return _T("DXVA2_VideoProcProgressiveDevice");
1829                if(DeinterlaceMode == __uuidof(DXVA2_VideoProcBobDevice))
1830                        return _T("DXVA2_VideoProcBobDevice");
1831                if(DeinterlaceMode == __uuidof(DXVA2_VideoProcSoftwareDevice))
1832                        return _T("DXVA2_VideoProcSoftwareDevice");
1833                return CString(_PersistHelper::StringFromIdentifier(DeinterlaceMode));
1834        }
1835
1836// Window Message Handlers
1837        LRESULT OnSetLargerInitialPosition(UINT, WPARAM, LPARAM)
1838        {
1839                CRect Position;
1840                _W(GetWindowRect(Position));
1841                Position.right += Position.Width();
1842                Position.bottom += Position.Height() / 4;
1843                _W(SetWindowPos(NULL, Position, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE));
1844                _W(CenterWindow());
1845                return 0;
1846        }
1847};
Note: See TracBrowser for help on using the repository browser.