1 | //////////////////////////////////////////////////////////// |
---|
2 | // Copyright (C) Roman Ryltsov, 2008-2012 |
---|
3 | // Created by Roman Ryltsov roman@alax.info |
---|
4 | // |
---|
5 | // $Id: ConfigureVideoResizerDmo.cpp 84 2012-08-04 08:50:37Z roman $ |
---|
6 | |
---|
7 | #include "stdafx.h" |
---|
8 | #include <dshow.h> |
---|
9 | #include <dmo.h> |
---|
10 | #include <dmodshow.h> |
---|
11 | #include <wmcodecdsp.h> |
---|
12 | #include <atlstr.h> |
---|
13 | #include <atlcoll.h> |
---|
14 | |
---|
15 | #pragma comment(lib, "strmiids.lib") |
---|
16 | #pragma comment(lib, "dmoguids.lib") |
---|
17 | #pragma comment(lib, "msdmo.lib") |
---|
18 | #pragma comment(lib, "wmcodecdspuuid.lib") |
---|
19 | |
---|
20 | #pragma region Re-Adding Removed from Windows SDK qedit.h |
---|
21 | |
---|
22 | struct __declspec(uuid("0579154a-2b53-4994-b0d0-e773148eff85")) |
---|
23 | ISampleGrabberCB : IUnknown |
---|
24 | { |
---|
25 | // |
---|
26 | // Raw methods provided by interface |
---|
27 | // |
---|
28 | |
---|
29 | virtual HRESULT __stdcall SampleCB ( |
---|
30 | double SampleTime, |
---|
31 | struct IMediaSample * pSample ) = 0; |
---|
32 | virtual HRESULT __stdcall BufferCB ( |
---|
33 | double SampleTime, |
---|
34 | unsigned char * pBuffer, |
---|
35 | long BufferLen ) = 0; |
---|
36 | }; |
---|
37 | |
---|
38 | struct __declspec(uuid("6b652fff-11fe-4fce-92ad-0266b5d7c78f")) |
---|
39 | ISampleGrabber : IUnknown |
---|
40 | { |
---|
41 | // |
---|
42 | // Raw methods provided by interface |
---|
43 | // |
---|
44 | |
---|
45 | virtual HRESULT __stdcall SetOneShot ( |
---|
46 | long OneShot ) = 0; |
---|
47 | virtual HRESULT __stdcall SetMediaType ( |
---|
48 | struct _AMMediaType * pType ) = 0; |
---|
49 | virtual HRESULT __stdcall GetConnectedMediaType ( |
---|
50 | struct _AMMediaType * pType ) = 0; |
---|
51 | virtual HRESULT __stdcall SetBufferSamples ( |
---|
52 | long BufferThem ) = 0; |
---|
53 | virtual HRESULT __stdcall GetCurrentBuffer ( |
---|
54 | /*[in,out]*/ long * pBufferSize, |
---|
55 | /*[out]*/ long * pBuffer ) = 0; |
---|
56 | virtual HRESULT __stdcall GetCurrentSample ( |
---|
57 | /*[out,retval]*/ struct IMediaSample * * ppSample ) = 0; |
---|
58 | virtual HRESULT __stdcall SetCallback ( |
---|
59 | struct ISampleGrabberCB * pCallback, |
---|
60 | long WhichMethodToCallback ) = 0; |
---|
61 | }; |
---|
62 | |
---|
63 | struct __declspec(uuid("c1f400a0-3f08-11d3-9f0b-006008039e37")) |
---|
64 | SampleGrabber; |
---|
65 | // [ default ] interface ISampleGrabber |
---|
66 | |
---|
67 | #pragma endregion |
---|
68 | |
---|
69 | typedef CAtlArray<CComPtr<IPin>> CPinArray; |
---|
70 | |
---|
71 | SIZE_T GetPins(IBaseFilter* pBaseFilter, CPinArray& PinArray) |
---|
72 | { |
---|
73 | ATLASSERT(pBaseFilter); |
---|
74 | ATLASSERT(PinArray.IsEmpty()); |
---|
75 | CComPtr<IEnumPins> pEnumPins; |
---|
76 | ATLENSURE_SUCCEEDED(pBaseFilter->EnumPins(&pEnumPins)); |
---|
77 | CComPtr<IPin> pPin; |
---|
78 | while(pEnumPins->Next(1, &pPin, NULL) == S_OK) |
---|
79 | { |
---|
80 | ATLVERIFY(PinArray.Add(pPin) >= 0); |
---|
81 | pPin.Release(); |
---|
82 | } |
---|
83 | return PinArray.GetCount(); |
---|
84 | } |
---|
85 | |
---|
86 | int _tmain(int argc, _TCHAR* argv[]) |
---|
87 | { |
---|
88 | _ATLTRY |
---|
89 | { |
---|
90 | ATLENSURE_THROW(argc > 1, E_INVALIDARG); |
---|
91 | CString sPath = argv[1]; |
---|
92 | ATLENSURE_SUCCEEDED(CoInitialize(NULL)); |
---|
93 | { |
---|
94 | #pragma region Prepare Graph |
---|
95 | CComPtr<IGraphBuilder> pGraphBuilder; |
---|
96 | ATLENSURE_SUCCEEDED(pGraphBuilder.CoCreateInstance(CLSID_FilterGraph)); |
---|
97 | CComPtr<IBaseFilter> pSourceBaseFilter; |
---|
98 | ATLENSURE_SUCCEEDED(pGraphBuilder->AddSourceFilter(CT2CW(sPath), NULL, &pSourceBaseFilter)); |
---|
99 | CPinArray SourcePinArray; |
---|
100 | ATLVERIFY(GetPins(pSourceBaseFilter, SourcePinArray) >= 1); |
---|
101 | CComPtr<IBaseFilter> pRendererBaseFilter; |
---|
102 | ATLENSURE_SUCCEEDED(pRendererBaseFilter.CoCreateInstance(CLSID_VideoMixingRenderer)); |
---|
103 | ATLENSURE_SUCCEEDED(pGraphBuilder->AddFilter(pRendererBaseFilter, CT2CW(_T("Renderer")))); |
---|
104 | CPinArray RendererPinArray; |
---|
105 | ATLVERIFY(GetPins(pRendererBaseFilter, RendererPinArray) >= 1); |
---|
106 | HRESULT nRenderExResult = E_FAIL; |
---|
107 | for(SIZE_T nIndex = 0; nIndex < SourcePinArray.GetCount(); nIndex++) |
---|
108 | { |
---|
109 | nRenderExResult = pGraphBuilder->Connect(SourcePinArray[nIndex], RendererPinArray[0]); |
---|
110 | if(SUCCEEDED(nRenderExResult)) |
---|
111 | break; |
---|
112 | } |
---|
113 | ATLENSURE_SUCCEEDED(nRenderExResult); |
---|
114 | #pragma endregion |
---|
115 | #pragma region Insert Resizer |
---|
116 | #pragma region Insertion Point, Automatic Media Type, Pins |
---|
117 | const CComPtr<IPin> pRendererInputPin = RendererPinArray[0]; |
---|
118 | CComPtr<IPin> pRendererInputPeerPin; |
---|
119 | ATLENSURE_SUCCEEDED(pRendererInputPin->ConnectedTo(&pRendererInputPeerPin)); |
---|
120 | AM_MEDIA_TYPE OriginalMediaType; |
---|
121 | ZeroMemory(&OriginalMediaType, sizeof OriginalMediaType); |
---|
122 | ATLENSURE_SUCCEEDED(pRendererInputPin->ConnectionMediaType(&OriginalMediaType)); |
---|
123 | CComHeapPtr<BYTE> pnOriginalMediaTypeFormat; |
---|
124 | pnOriginalMediaTypeFormat.Attach(OriginalMediaType.pbFormat); // To be automatically released later on |
---|
125 | // NOTE: Sover videos are decoded into other formats, these cases are not covered by this sample |
---|
126 | ATLASSERT(OriginalMediaType.formattype == FORMAT_VideoInfo); |
---|
127 | const VIDEOINFOHEADER* pOriginalVideoInfoHeader = (const VIDEOINFOHEADER*) OriginalMediaType.pbFormat; |
---|
128 | ATLENSURE_SUCCEEDED(pRendererInputPin->Disconnect()); |
---|
129 | ATLENSURE_SUCCEEDED(pRendererInputPeerPin->Disconnect()); |
---|
130 | #pragma endregion |
---|
131 | #pragma region Insert Sample Grabber |
---|
132 | // NOTE: In this sample we force video resize in 32-bit RGB domain |
---|
133 | CComPtr<IBaseFilter> pSgBaseFilter; |
---|
134 | ATLENSURE_SUCCEEDED(pSgBaseFilter.CoCreateInstance(__uuidof(SampleGrabber))); |
---|
135 | ATLENSURE_SUCCEEDED(pGraphBuilder->AddFilter(pSgBaseFilter, CT2CW(_T("32-Bit RGB Sample Grabber")))); |
---|
136 | const CComQIPtr<ISampleGrabber> pSampleGrabber = pSgBaseFilter; |
---|
137 | ATLENSURE_THROW(pSampleGrabber, E_NOINTERFACE); |
---|
138 | AM_MEDIA_TYPE Rgb32MediaType; |
---|
139 | ZeroMemory(&Rgb32MediaType, sizeof Rgb32MediaType); |
---|
140 | Rgb32MediaType.majortype = MEDIATYPE_Video; |
---|
141 | Rgb32MediaType.subtype = MEDIASUBTYPE_RGB32; |
---|
142 | ATLENSURE_SUCCEEDED(pSampleGrabber->SetMediaType(&Rgb32MediaType)); |
---|
143 | CPinArray SgPinArray; |
---|
144 | ATLVERIFY(GetPins(pSgBaseFilter, SgPinArray) >= 2); |
---|
145 | // ASSU: First pin is input, Second pin is output |
---|
146 | ATLENSURE_SUCCEEDED(pGraphBuilder->Connect(pRendererInputPeerPin, SgPinArray[0])); |
---|
147 | pRendererInputPeerPin = SgPinArray[1]; |
---|
148 | #pragma endregion |
---|
149 | #pragma region Insert Resizer Filter |
---|
150 | CComPtr<IBaseFilter> pBaseFilter; |
---|
151 | ATLENSURE_SUCCEEDED(pBaseFilter.CoCreateInstance(CLSID_DMOWrapperFilter)); |
---|
152 | const CComQIPtr<IDMOWrapperFilter> pDmoWrapperFilter = pBaseFilter; |
---|
153 | ATLENSURE_THROW(pDmoWrapperFilter, E_NOINTERFACE); |
---|
154 | ATLENSURE_SUCCEEDED(pDmoWrapperFilter->Init(CLSID_CResizerDMO, DMOCATEGORY_VIDEO_EFFECT)); |
---|
155 | ATLENSURE_SUCCEEDED(pGraphBuilder->AddFilter(pBaseFilter, CT2CW(_T("Resizer")))); |
---|
156 | CPinArray PinArray; |
---|
157 | ATLVERIFY(GetPins(pBaseFilter, PinArray) >= 2); |
---|
158 | // ASSU: First pin is input, Second pin is output |
---|
159 | #pragma endregion |
---|
160 | const CComPtr<IPin>& pInputPin = PinArray[0]; |
---|
161 | const CComPtr<IPin>& pOutputPin = PinArray[1]; |
---|
162 | #pragma endregion |
---|
163 | const CComQIPtr<IWMResizerProps> pWmResizerProps = pBaseFilter; |
---|
164 | ATLENSURE_THROW(pWmResizerProps, E_NOINTERFACE); |
---|
165 | ATLENSURE_SUCCEEDED(pWmResizerProps->SetFullCropRegion( |
---|
166 | 0, 0, pOriginalVideoInfoHeader->bmiHeader.biWidth, pOriginalVideoInfoHeader->bmiHeader.biHeight, |
---|
167 | 0, 0, pOriginalVideoInfoHeader->bmiHeader.biWidth, 2 * pOriginalVideoInfoHeader->bmiHeader.biHeight |
---|
168 | )); |
---|
169 | ATLENSURE_SUCCEEDED(pGraphBuilder->Connect(pRendererInputPeerPin, pInputPin)); |
---|
170 | #pragma region Input Pin Format |
---|
171 | AM_MEDIA_TYPE InputMediaType; |
---|
172 | ZeroMemory(&InputMediaType, sizeof InputMediaType); |
---|
173 | ATLENSURE_SUCCEEDED(pInputPin->ConnectionMediaType(&InputMediaType)); |
---|
174 | CComHeapPtr<BYTE> pnInputMediaTypeFormat; |
---|
175 | pnInputMediaTypeFormat.Attach(InputMediaType.pbFormat); // To be automatically released later on |
---|
176 | ATLASSERT(InputMediaType.formattype == FORMAT_VideoInfo); |
---|
177 | const VIDEOINFOHEADER* pInputVideoInfoHeader = (const VIDEOINFOHEADER*) InputMediaType.pbFormat; |
---|
178 | #pragma endregion |
---|
179 | #pragma region Prepare Output Media Type |
---|
180 | VIDEOINFOHEADER OutputVideoInfoHeader = *pInputVideoInfoHeader; |
---|
181 | SetRect(&OutputVideoInfoHeader.rcSource, 0, 0, pInputVideoInfoHeader->bmiHeader.biWidth, pInputVideoInfoHeader->bmiHeader.biHeight); |
---|
182 | OutputVideoInfoHeader.rcTarget = OutputVideoInfoHeader.rcSource; |
---|
183 | OutputVideoInfoHeader.dwBitRate = 0; |
---|
184 | OutputVideoInfoHeader.dwBitErrorRate = 0; |
---|
185 | ATLASSERT(OutputVideoInfoHeader.bmiHeader.biSize == sizeof OutputVideoInfoHeader.bmiHeader); |
---|
186 | // NOTE: Twice as high |
---|
187 | OutputVideoInfoHeader.bmiHeader.biHeight <<= 1; |
---|
188 | OutputVideoInfoHeader.bmiHeader.biSizeImage <<= 1; |
---|
189 | AM_MEDIA_TYPE OutputMediaType = InputMediaType; |
---|
190 | OutputMediaType.lSampleSize = OutputVideoInfoHeader.bmiHeader.biSizeImage; |
---|
191 | ATLASSERT(!OutputMediaType.pUnk); |
---|
192 | OutputMediaType.cbFormat = sizeof OutputVideoInfoHeader; |
---|
193 | OutputMediaType.pbFormat = (BYTE*) &OutputVideoInfoHeader; |
---|
194 | #pragma endregion |
---|
195 | const CComQIPtr<IMediaObject> pMediaObject = pBaseFilter; |
---|
196 | ATLENSURE_THROW(pMediaObject, E_NOINTERFACE); |
---|
197 | ATLENSURE_SUCCEEDED(pMediaObject->SetOutputType(0, (DMO_MEDIA_TYPE*) &OutputMediaType, 0)); |
---|
198 | #if !TRUE |
---|
199 | CComPtr<IBaseFilter> pCscBaseFilter; |
---|
200 | ATLENSURE_SUCCEEDED(pCscBaseFilter.CoCreateInstance(CLSID_Colour)); |
---|
201 | ATLENSURE_SUCCEEDED(pGraphBuilder->AddFilter(pCscBaseFilter, CT2CW(_T("Color Space Converter")))); |
---|
202 | CPinArray CscPinArray; |
---|
203 | ATLVERIFY(GetPins(pCscBaseFilter, CscPinArray) >= 2); |
---|
204 | // ASSU: First pin is input, Second pin is output |
---|
205 | ATLENSURE_SUCCEEDED(pGraphBuilder->ConnectDirect(pOutputPin, CscPinArray[0], &OutputMediaType)); |
---|
206 | ATLENSURE_SUCCEEDED(pGraphBuilder->Connect(CscPinArray[1], pRendererInputPin)); |
---|
207 | #else |
---|
208 | ATLENSURE_SUCCEEDED(pGraphBuilder->ConnectDirect(pOutputPin, pRendererInputPin, &OutputMediaType)); |
---|
209 | #endif |
---|
210 | #pragma region Run Graph |
---|
211 | const CComQIPtr<IMediaControl> pMediaControl = pGraphBuilder; |
---|
212 | ATLENSURE_THROW(pMediaControl, E_NOINTERFACE); |
---|
213 | ATLENSURE_SUCCEEDED(pMediaControl->Run()); |
---|
214 | //MessageBox(GetActiveWindow(), _T("Connect Remotely to the Graph"), _T("Debug"), MB_ICONINFORMATION | MB_OK); |
---|
215 | const CComQIPtr<IMediaEvent> pMediaEvent = pGraphBuilder; |
---|
216 | ATLENSURE_THROW(pMediaEvent, E_NOINTERFACE); |
---|
217 | LONG nEventCode; |
---|
218 | ATLENSURE_SUCCEEDED(pMediaEvent->WaitForCompletion(INFINITE, &nEventCode)); |
---|
219 | #pragma endregion |
---|
220 | } |
---|
221 | CoUninitialize(); |
---|
222 | } |
---|
223 | _ATLCATCH(Exception) |
---|
224 | { |
---|
225 | _tprintf(_T("Fatal Error 0x%08x\n"), (HRESULT) Exception); |
---|
226 | } |
---|
227 | _ATLCATCHALL() |
---|
228 | { |
---|
229 | _tprintf(_T("Fatal Error\n")); |
---|
230 | } |
---|
231 | return 0; |
---|
232 | } |
---|
233 | |
---|