1 /* Webcamoid, webcam capture application.
2 * Copyright (C) 2018 Gonzalo Exequiel Pedone
3 *
4 * Webcamoid is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * Webcamoid is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with Webcamoid. If not, see <http://www.gnu.org/licenses/>.
16 *
17 * Web-Site: http://webcamoid.github.io/
18 */
19
20 #include <algorithm>
21 #include <dshow.h>
22
23 #include "basefilter.h"
24 #include "enumpins.h"
25 #include "filtermiscflags.h"
26 #include "pin.h"
27 #include "referenceclock.h"
28 #include "specifypropertypages.h"
29 #include "videocontrol.h"
30 #include "videoprocamp.h"
31 #include "ipcbridge.h"
32 #include "PlatformUtils/src/utils.h"
33 #include "VCamUtils/src/image/videoformat.h"
34 #include "VCamUtils/src/utils.h"
35
36 #define AK_CUR_INTERFACE "BaseFilter"
37
38 #define AkBaseFilterPrivateLog() \
39 AkLoggerLog("BaseFilterPrivate::", __FUNCTION__, "()")
40
41 #define AkVCamPinCall(pins, func, ...) \
42 pins->Reset(); \
43 Pin *pin = nullptr; \
44 \
45 while (pins->Next(1, reinterpret_cast<IPin **>(&pin), nullptr) == S_OK) { \
46 pin->func(__VA_ARGS__); \
47 pin->Release(); \
48 }
49
50 #define AkVCamDevicePinCall(deviceId, where, func, ...) \
51 if (auto pins = where->pinsForDevice(deviceId)) { \
52 AkVCamPinCall(pins, func, __VA_ARGS__) \
53 pins->Release(); \
54 }
55
56 namespace AkVCam
57 {
58 class BaseFilterPrivate
59 {
60 public:
61 BaseFilter *self;
62 EnumPins *m_pins;
63 VideoProcAmp *m_videoProcAmp;
64 ReferenceClock *m_referenceClock;
65 std::wstring m_vendor;
66 std::wstring m_filterName;
67 IFilterGraph *m_filterGraph;
68 IpcBridge m_ipcBridge;
69
70 BaseFilterPrivate(BaseFilter *self,
71 const std::wstring &filterName,
72 const std::wstring &vendor);
73 BaseFilterPrivate(const BaseFilterPrivate &other) = delete;
74 ~BaseFilterPrivate();
75 IEnumPins *pinsForDevice(const std::string &deviceId);
76 void updatePins();
77 static void serverStateChanged(void *userData,
78 IpcBridge::ServerState state);
79 static void frameReady(void *userData,
80 const std::string &deviceId,
81 const VideoFrame &frame);
82 static void setBroadcasting(void *userData,
83 const std::string &deviceId,
84 const std::string &broadcasting);
85 static void setMirror(void *userData,
86 const std::string &deviceId,
87 bool horizontalMirror,
88 bool verticalMirror);
89 static void setScaling(void *userData,
90 const std::string &deviceId,
91 Scaling scaling);
92 static void setAspectRatio(void *userData,
93 const std::string &deviceId,
94 AspectRatio aspectRatio);
95 static void setSwapRgb(void *userData,
96 const std::string &deviceId,
97 bool swap);
98 };
99 }
100
BaseFilter(const GUID & clsid,const std::wstring & filterName,const std::wstring & vendor)101 AkVCam::BaseFilter::BaseFilter(const GUID &clsid,
102 const std::wstring &filterName,
103 const std::wstring &vendor):
104 MediaFilter(clsid, this)
105 {
106 this->setParent(this, &IID_IBaseFilter);
107 this->d = new BaseFilterPrivate(this, filterName, vendor);
108 }
109
~BaseFilter()110 AkVCam::BaseFilter::~BaseFilter()
111 {
112 delete this->d;
113 }
114
addPin(const std::vector<AkVCam::VideoFormat> & formats,const std::wstring & pinName,bool changed)115 void AkVCam::BaseFilter::addPin(const std::vector<AkVCam::VideoFormat> &formats,
116 const std::wstring &pinName,
117 bool changed)
118 {
119 AkLogMethod();
120 this->d->m_pins->addPin(new Pin(this, formats, pinName), changed);
121
122 if (this->d->m_pins->count() == 1)
123 this->d->m_ipcBridge.connectService(true);
124 }
125
removePin(IPin * pin,bool changed)126 void AkVCam::BaseFilter::removePin(IPin *pin, bool changed)
127 {
128 AkLogMethod();
129 this->d->m_ipcBridge.disconnectService();
130 this->d->m_pins->removePin(pin, changed);
131 }
132
create(const GUID & clsid)133 AkVCam::BaseFilter *AkVCam::BaseFilter::create(const GUID &clsid)
134 {
135 AkLoggerLog("BaseFilter::create()");
136 auto camera = cameraFromId(clsid);
137 AkLoggerLog("CLSID: ", stringFromClsid(clsid));
138 AkLoggerLog("ID: ", camera);
139
140 if (camera < 0)
141 return nullptr;
142
143 auto description = cameraDescription(DWORD(camera));
144 AkLoggerLog("Description: ", std::string(description.begin(),
145 description.end()));
146 auto baseFilter = new BaseFilter(clsid,
147 description,
148 DSHOW_PLUGIN_VENDOR_L);
149 auto formats = cameraFormats(DWORD(camera));
150 baseFilter->addPin(formats, L"Video", false);
151
152 return baseFilter;
153 }
154
filterGraph() const155 IFilterGraph *AkVCam::BaseFilter::filterGraph() const
156 {
157 return this->d->m_filterGraph;
158 }
159
referenceClock() const160 IReferenceClock *AkVCam::BaseFilter::referenceClock() const
161 {
162 return this->d->m_referenceClock;
163 }
164
QueryInterface(const IID & riid,void ** ppvObject)165 HRESULT AkVCam::BaseFilter::QueryInterface(const IID &riid, void **ppvObject)
166 {
167 AkLogMethod();
168 AkLoggerLog("IID: ", AkVCam::stringFromClsid(riid));
169
170 if (!ppvObject)
171 return E_POINTER;
172
173 *ppvObject = nullptr;
174
175 if (IsEqualIID(riid, IID_IUnknown)
176 || IsEqualIID(riid, IID_IBaseFilter)
177 || IsEqualIID(riid, IID_IMediaFilter)) {
178 AkLogInterface(IBaseFilter, this);
179 this->AddRef();
180 *ppvObject = this;
181
182 return S_OK;
183 } else if (IsEqualIID(riid, IID_IAMFilterMiscFlags)) {
184 auto filterMiscFlags = new FilterMiscFlags;
185 AkLogInterface(IAMFilterMiscFlags, filterMiscFlags);
186 filterMiscFlags->AddRef();
187 *ppvObject = filterMiscFlags;
188
189 return S_OK;
190 } else if (IsEqualIID(riid, IID_IAMVideoControl)) {
191 IEnumPins *pins = nullptr;
192 this->d->m_pins->Clone(&pins);
193 auto videoControl = new VideoControl(pins);
194 pins->Release();
195 AkLogInterface(IAMVideoControl, videoControl);
196 videoControl->AddRef();
197 *ppvObject = videoControl;
198
199 return S_OK;
200 } else if (IsEqualIID(riid, IID_IAMVideoProcAmp)) {
201 auto videoProcAmp = this->d->m_videoProcAmp;
202 AkLogInterface(IAMVideoProcAmp, videoProcAmp);
203 videoProcAmp->AddRef();
204 *ppvObject = videoProcAmp;
205
206 return S_OK;
207 } else if (IsEqualIID(riid, IID_IReferenceClock)) {
208 auto referenceClock = this->d->m_referenceClock;
209 AkLogInterface(IReferenceClock, referenceClock);
210 referenceClock->AddRef();
211 *ppvObject = referenceClock;
212
213 return S_OK;
214 } else if (IsEqualIID(riid, IID_ISpecifyPropertyPages)) {
215 this->d->m_pins->Reset();
216 IPin *pin = nullptr;
217 this->d->m_pins->Next(1, &pin, nullptr);
218 auto specifyPropertyPages = new SpecifyPropertyPages(pin);
219 pin->Release();
220 AkLogInterface(ISpecifyPropertyPages, specifyPropertyPages);
221 specifyPropertyPages->AddRef();
222 *ppvObject = specifyPropertyPages;
223
224 return S_OK;
225 } else {
226 this->d->m_pins->Reset();
227 IPin *pin = nullptr;
228 this->d->m_pins->Next(1, &pin, nullptr);
229 auto result = pin->QueryInterface(riid, ppvObject);
230 pin->Release();
231
232 if (SUCCEEDED(result))
233 return result;
234 }
235
236 return MediaFilter::QueryInterface(riid, ppvObject);
237 }
238
EnumPins(IEnumPins ** ppEnum)239 HRESULT AkVCam::BaseFilter::EnumPins(IEnumPins **ppEnum)
240 {
241 AkLogMethod();
242
243 if (!this->d->m_pins)
244 return E_FAIL;
245
246 auto result = this->d->m_pins->Clone(ppEnum);
247
248 if (SUCCEEDED(result))
249 (*ppEnum)->Reset();
250
251 return result;
252 }
253
FindPin(LPCWSTR Id,IPin ** ppPin)254 HRESULT AkVCam::BaseFilter::FindPin(LPCWSTR Id, IPin **ppPin)
255 {
256 AkLogMethod();
257
258 if (!ppPin)
259 return E_POINTER;
260
261 *ppPin = nullptr;
262
263 if (!Id)
264 return VFW_E_NOT_FOUND;
265
266 IPin *pin = nullptr;
267 HRESULT result = VFW_E_NOT_FOUND;
268 this->d->m_pins->Reset();
269
270 while (this->d->m_pins->Next(1, &pin, nullptr) == S_OK) {
271 WCHAR *pinId = nullptr;
272 auto ok = pin->QueryId(&pinId);
273
274 if (ok == S_OK && wcscmp(pinId, Id) == 0) {
275 *ppPin = pin;
276 (*ppPin)->AddRef();
277 result = S_OK;
278 }
279
280 CoTaskMemFree(pinId);
281 pin->Release();
282 pin = nullptr;
283
284 if (result == S_OK)
285 break;
286 }
287
288 return result;
289 }
290
QueryFilterInfo(FILTER_INFO * pInfo)291 HRESULT AkVCam::BaseFilter::QueryFilterInfo(FILTER_INFO *pInfo)
292 {
293 AkLogMethod();
294
295 if (!pInfo)
296 return E_POINTER;
297
298 memset(pInfo->achName, 0, MAX_FILTER_NAME * sizeof(WCHAR));
299
300 if (this->d->m_filterName.size() > 0) {
301 memcpy(pInfo->achName,
302 this->d->m_filterName.c_str(),
303 std::max<size_t>(this->d->m_filterName.size() * sizeof(WCHAR),
304 MAX_FILTER_NAME));
305 }
306
307 pInfo->pGraph = this->d->m_filterGraph;
308
309 if (pInfo->pGraph)
310 pInfo->pGraph->AddRef();
311
312 return S_OK;
313 }
314
JoinFilterGraph(IFilterGraph * pGraph,LPCWSTR pName)315 HRESULT AkVCam::BaseFilter::JoinFilterGraph(IFilterGraph *pGraph, LPCWSTR pName)
316 {
317 AkLogMethod();
318
319 this->d->m_filterGraph = pGraph;
320 this->d->m_filterName = std::wstring(pName? pName: L"");
321
322 AkLoggerLog("Filter graph: ", this->d->m_filterGraph);
323 AkLoggerLog("Name: ", std::string(this->d->m_filterName.begin(),
324 this->d->m_filterName.end()));
325
326 return S_OK;
327 }
328
QueryVendorInfo(LPWSTR * pVendorInfo)329 HRESULT AkVCam::BaseFilter::QueryVendorInfo(LPWSTR *pVendorInfo)
330 {
331 AkLogMethod();
332
333 if (this->d->m_vendor.size() < 1)
334 return E_NOTIMPL;
335
336 if (!pVendorInfo)
337 return E_POINTER;
338
339 *pVendorInfo = wcharStrFromWStr(this->d->m_vendor);
340
341 return S_OK;
342 }
343
stateChanged(FILTER_STATE state)344 void AkVCam::BaseFilter::stateChanged(FILTER_STATE state)
345 {
346 CLSID clsid;
347 this->GetClassID(&clsid);
348 auto path = cameraPath(clsid);
349 std::string deviceId(path.begin(), path.end());
350
351 if (state == State_Running)
352 this->d->m_ipcBridge.addListener(deviceId);
353 else
354 this->d->m_ipcBridge.removeListener(deviceId);
355 }
356
BaseFilterPrivate(AkVCam::BaseFilter * self,const std::wstring & filterName,const std::wstring & vendor)357 AkVCam::BaseFilterPrivate::BaseFilterPrivate(AkVCam::BaseFilter *self,
358 const std::wstring &filterName,
359 const std::wstring &vendor):
360 self(self),
361 m_pins(new AkVCam::EnumPins),
362 m_videoProcAmp(new VideoProcAmp),
363 m_referenceClock(new ReferenceClock),
364 m_vendor(vendor),
365 m_filterName(filterName),
366 m_filterGraph(nullptr)
367 {
368 this->m_pins->AddRef();
369 this->m_videoProcAmp->AddRef();
370 this->m_referenceClock->AddRef();
371
372 this->m_ipcBridge.connectServerStateChanged(this,
373 &BaseFilterPrivate::serverStateChanged);
374 this->m_ipcBridge.connectFrameReady(this,
375 &BaseFilterPrivate::frameReady);
376 this->m_ipcBridge.connectBroadcastingChanged(this,
377 &BaseFilterPrivate::setBroadcasting);
378 this->m_ipcBridge.connectMirrorChanged(this,
379 &BaseFilterPrivate::setMirror);
380 this->m_ipcBridge.connectScalingChanged(this,
381 &BaseFilterPrivate::setScaling);
382 this->m_ipcBridge.connectAspectRatioChanged(this,
383 &BaseFilterPrivate::setAspectRatio);
384 this->m_ipcBridge.connectSwapRgbChanged(this,
385 &BaseFilterPrivate::setSwapRgb);
386 }
387
~BaseFilterPrivate()388 AkVCam::BaseFilterPrivate::~BaseFilterPrivate()
389 {
390 this->m_ipcBridge.disconnectService();
391 this->m_pins->setBaseFilter(nullptr);
392 this->m_pins->Release();
393 this->m_videoProcAmp->Release();
394 this->m_referenceClock->Release();
395 }
396
pinsForDevice(const std::string & deviceId)397 IEnumPins *AkVCam::BaseFilterPrivate::pinsForDevice(const std::string &deviceId)
398 {
399 AkLogMethod();
400
401 CLSID clsid;
402 self->GetClassID(&clsid);
403 auto path = cameraPath(clsid);
404
405 if (path.empty() || std::string(path.begin(), path.end()) != deviceId)
406 return nullptr;
407
408 IEnumPins *pins = nullptr;
409 self->EnumPins(&pins);
410
411 return pins;
412 }
413
updatePins()414 void AkVCam::BaseFilterPrivate::updatePins()
415 {
416 CLSID clsid;
417 this->self->GetClassID(&clsid);
418 auto path = cameraPath(clsid);
419 std::string deviceId(path.begin(), path.end());
420
421 auto broadcaster = this->m_ipcBridge.broadcaster(deviceId);
422 AkVCamDevicePinCall(deviceId,
423 this,
424 setBroadcasting,
425 broadcaster);
426 auto hmirror = this->m_ipcBridge.isHorizontalMirrored(deviceId);
427 auto vmirror = this->m_ipcBridge.isVerticalMirrored(deviceId);
428 AkVCamDevicePinCall(deviceId,
429 this,
430 setMirror,
431 hmirror,
432 vmirror);
433 auto scaling = this->m_ipcBridge.scalingMode(deviceId);
434 AkVCamDevicePinCall(deviceId,
435 this,
436 setScaling,
437 scaling);
438 auto aspect = this->m_ipcBridge.aspectRatioMode(deviceId);
439 AkVCamDevicePinCall(deviceId,
440 this,
441 setAspectRatio,
442 aspect);
443 auto swap = this->m_ipcBridge.swapRgb(deviceId);
444 AkVCamDevicePinCall(deviceId,
445 this,
446 setSwapRgb,
447 swap);
448 }
449
serverStateChanged(void * userData,IpcBridge::ServerState state)450 void AkVCam::BaseFilterPrivate::serverStateChanged(void *userData,
451 IpcBridge::ServerState state)
452 {
453 AkBaseFilterPrivateLog();
454 auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
455 IEnumPins *pins = nullptr;
456 self->self->EnumPins(&pins);
457
458 if (pins) {
459 AkVCamPinCall(pins, serverStateChanged, state)
460 pins->Release();
461 }
462
463 if (state == IpcBridge::ServerStateAvailable)
464 self->updatePins();
465 }
466
frameReady(void * userData,const std::string & deviceId,const VideoFrame & frame)467 void AkVCam::BaseFilterPrivate::frameReady(void *userData,
468 const std::string &deviceId,
469 const VideoFrame &frame)
470 {
471 AkBaseFilterPrivateLog();
472 auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
473 AkVCamDevicePinCall(deviceId, self, frameReady, frame);
474 }
475
setBroadcasting(void * userData,const std::string & deviceId,const std::string & broadcaster)476 void AkVCam::BaseFilterPrivate::setBroadcasting(void *userData,
477 const std::string &deviceId,
478 const std::string &broadcaster)
479 {
480 AkBaseFilterPrivateLog();
481 auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
482 AkVCamDevicePinCall(deviceId, self, setBroadcasting, broadcaster);
483 }
484
setMirror(void * userData,const std::string & deviceId,bool horizontalMirror,bool verticalMirror)485 void AkVCam::BaseFilterPrivate::setMirror(void *userData,
486 const std::string &deviceId,
487 bool horizontalMirror,
488 bool verticalMirror)
489 {
490 AkBaseFilterPrivateLog();
491 auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
492 AkVCamDevicePinCall(deviceId,
493 self,
494 setMirror,
495 horizontalMirror,
496 verticalMirror);
497 }
498
setScaling(void * userData,const std::string & deviceId,Scaling scaling)499 void AkVCam::BaseFilterPrivate::setScaling(void *userData,
500 const std::string &deviceId,
501 Scaling scaling)
502 {
503 AkBaseFilterPrivateLog();
504 auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
505 AkVCamDevicePinCall(deviceId, self, setScaling, scaling);
506 }
507
setAspectRatio(void * userData,const std::string & deviceId,AspectRatio aspectRatio)508 void AkVCam::BaseFilterPrivate::setAspectRatio(void *userData,
509 const std::string &deviceId,
510 AspectRatio aspectRatio)
511 {
512 AkBaseFilterPrivateLog();
513 auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
514 AkVCamDevicePinCall(deviceId, self, setAspectRatio, aspectRatio);
515 }
516
setSwapRgb(void * userData,const std::string & deviceId,bool swap)517 void AkVCam::BaseFilterPrivate::setSwapRgb(void *userData,
518 const std::string &deviceId,
519 bool swap)
520 {
521 AkBaseFilterPrivateLog();
522 auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
523 AkVCamDevicePinCall(deviceId, self, setSwapRgb, swap);
524 }
525