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