2 * Implementation of MARU Virtual Camera device by PCI bus on Windows.
\r
4 * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd All Rights Reserved
\r
7 * JinHyung Jo <jinhyung.jo@samsung.com>
\r
8 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
\r
10 * This program is free software; you can redistribute it and/or
\r
11 * modify it under the terms of the GNU General Public License
\r
12 * as published by the Free Software Foundation; either version 2
\r
13 * of the License, or (at your option) any later version.
\r
15 * This program is distributed in the hope that it will be useful,
\r
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
18 * GNU General Public License for more details.
\r
20 * You should have received a copy of the GNU General Public License
\r
21 * along with this program; if not, write to the Free Software
\r
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
\r
30 #include "qemu-common.h"
\r
31 #include "maru_camera_common.h"
\r
32 #include "tizen/src/debug_ch.h"
\r
37 #include "errors.h" /* for VFW_E_XXXX */
\r
38 #include "mmsystem.h" /* for MAKEFOURCC macro */
\r
39 #include "maru_camera_win32_interface.h"
\r
41 MULTI_DEBUG_CHANNEL(tizen, camera_win32);
\r
43 extern int hax_enabled(void);
\r
46 * COM Interface implementations
\r
50 #define SAFE_RELEASE(x) \
\r
53 (x)->lpVtbl->Release(x); \
\r
58 typedef HRESULT (STDAPICALLTYPE *CallbackFn)(ULONG dwSize, BYTE *pBuffer);
\r
64 typedef struct HWCGrabCallback {
\r
65 IGrabCallback IGrabCallback_iface;
\r
67 CallbackFn m_pCallback;
\r
68 STDMETHODIMP (*SetCallback)(IGrabCallback *iface, CallbackFn pCallbackFn);
\r
71 static inline HWCGrabCallback *impl_from_IGrabCallback(IGrabCallback *iface)
\r
73 return CONTAINING_RECORD(iface, HWCGrabCallback, IGrabCallback_iface);
\r
76 static STDMETHODIMP HWCGrabCallback_QueryInterface(IGrabCallback *iface,
\r
77 REFIID riid, void **ppv)
\r
79 if (IsEqualIID(riid, &IID_IUnknown)) {
\r
80 *ppv = (IUnknown *)iface;
\r
81 } else if (IsEqualIID(riid, &IID_IGrabCallback)) {
\r
82 *ppv = (IGrabCallback *)iface;
\r
85 return E_NOINTERFACE;
\r
88 IGrabCallback_AddRef(iface);
\r
92 static STDMETHODIMP_(ULONG) HWCGrabCallback_AddRef(IGrabCallback *iface)
\r
94 HWCGrabCallback *This = impl_from_IGrabCallback(iface);
\r
96 return InterlockedIncrement(&This->m_cRef);
\r
99 static STDMETHODIMP_(ULONG) HWCGrabCallback_Release(IGrabCallback *iface)
\r
101 HWCGrabCallback *This = impl_from_IGrabCallback(iface);
\r
103 if (InterlockedDecrement(&This->m_cRef) == 0) {
\r
104 This->m_pCallback = NULL;
\r
105 g_free((void *)This);
\r
110 return This->m_cRef;
\r
113 static STDMETHODIMP HWCGrabCallback_Grab(IGrabCallback *iface,
\r
114 ULONG dwSize, BYTE *pBuffer)
\r
116 HWCGrabCallback *This = impl_from_IGrabCallback(iface);
\r
118 if (This->m_pCallback) {
\r
119 HRESULT hr = This->m_pCallback(dwSize, pBuffer);
\r
130 static STDMETHODIMP HWCGrabCallback_SetCallback(IGrabCallback *iface,
\r
131 CallbackFn pCallbackFn)
\r
133 HWCGrabCallback *This = impl_from_IGrabCallback(iface);
\r
135 This->m_pCallback = pCallbackFn;
\r
139 static IGrabCallbackVtbl HWCGrabCallback_Vtbl = {
\r
140 HWCGrabCallback_QueryInterface,
\r
141 HWCGrabCallback_AddRef,
\r
142 HWCGrabCallback_Release,
\r
143 HWCGrabCallback_Grab
\r
146 static STDMETHODIMP HWCGrabCallback_Construct(IGrabCallback **ppv)
\r
148 HWCGrabCallback *This =
\r
149 (HWCGrabCallback *)g_malloc0(sizeof(HWCGrabCallback));
\r
152 ERR("failed to HWCGrabCallback_Construct, E_OUTOFMEMORY\n");
\r
153 return E_OUTOFMEMORY;
\r
156 This->IGrabCallback_iface.lpVtbl = &HWCGrabCallback_Vtbl;
\r
158 This->m_pCallback = NULL;
\r
159 This->SetCallback = HWCGrabCallback_SetCallback;
\r
160 *ppv = &This->IGrabCallback_iface;
\r
168 typedef struct HWCInPin {
\r
170 IMemInputPin IMemInputPin_iface;
\r
171 IBaseFilter *m_pCFilter;
\r
172 IPin *m_pConnectedPin;
\r
173 IGrabCallback *m_pCallback;
\r
174 IMemAllocator *m_pAllocator;
\r
177 STDMETHODIMP (*SetGrabCallbackIF)(IPin *iface, IGrabCallback *pCaptureCB);
\r
180 static inline HWCInPin *impl_from_IPin(IPin *iface)
\r
182 return CONTAINING_RECORD(iface, HWCInPin, IPin_iface);
\r
185 static inline HWCInPin *impl_from_IMemInputPin(IMemInputPin *iface)
\r
187 return CONTAINING_RECORD(iface, HWCInPin, IMemInputPin_iface);
\r
190 static STDMETHODIMP HWCPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
\r
192 HWCInPin *This = impl_from_IPin(iface);
\r
194 if (IsEqualIID(riid, &IID_IUnknown)) {
\r
195 *ppv = (IUnknown *)(&This->IPin_iface);
\r
196 IPin_AddRef((IPin *)*ppv);
\r
197 } else if (IsEqualIID(riid, &IID_IPin)) {
\r
198 *ppv = (IPin *)(&This->IPin_iface);
\r
199 IPin_AddRef((IPin *)*ppv);
\r
200 } else if (IsEqualIID(riid, &IID_IMemInputPin)) {
\r
201 *ppv = (IMemInputPin *)(&This->IMemInputPin_iface);
\r
202 IPin_AddRef((IMemInputPin *)*ppv);
\r
205 return E_NOINTERFACE;
\r
211 static STDMETHODIMP_(ULONG) HWCPin_AddRef(IPin *iface)
\r
213 HWCInPin *This = impl_from_IPin(iface);
\r
215 return InterlockedIncrement(&This->m_cRef);
\r
218 static STDMETHODIMP_(ULONG) HWCPin_Release(IPin *iface)
\r
220 HWCInPin *This = impl_from_IPin(iface);
\r
222 if (InterlockedDecrement(&This->m_cRef) == 0) {
\r
223 if (This->m_pCallback) {
\r
224 SAFE_RELEASE(This->m_pCallback);
\r
226 if (This->m_pConnectedPin) {
\r
227 SAFE_RELEASE(This->m_pConnectedPin);
\r
229 if (This->m_pAllocator) {
\r
230 IMemAllocator_Decommit(This->m_pAllocator);
\r
231 SAFE_RELEASE(This->m_pAllocator);
\r
233 g_free((void *)This);
\r
237 return This->m_cRef;
\r
240 static STDMETHODIMP HWCPin_Connect(IPin *iface,
\r
242 const AM_MEDIA_TYPE *pmt)
\r
244 HWCInPin *This = impl_from_IPin(iface);
\r
246 if (!pReceivePin) {
\r
250 if (This->m_pConnectedPin) {
\r
251 return VFW_E_ALREADY_CONNECTED;
\r
260 static STDMETHODIMP HWCPin_ReceiveConnection(IPin *iface, IPin *pConnector,
\r
261 const AM_MEDIA_TYPE *pmt)
\r
265 HWCInPin *This = impl_from_IPin(iface);
\r
267 if (pConnector == NULL || pmt == NULL) {
\r
271 if (This->m_pConnectedPin) {
\r
272 return VFW_E_ALREADY_CONNECTED;
\r
274 IBaseFilter_GetState(This->m_pCFilter, 0, &fs);
\r
275 if (fs != State_Stopped) {
\r
276 return VFW_E_NOT_STOPPED;
\r
278 IPin_QueryDirection(pConnector, &pd);
\r
279 if (pd == PINDIR_INPUT) {
\r
280 return VFW_E_INVALID_DIRECTION;
\r
283 This->m_pConnectedPin = pConnector;
\r
284 IPin_AddRef(This->m_pConnectedPin);
\r
288 static STDMETHODIMP HWCPin_Disconnect(IPin *iface)
\r
290 HWCInPin *This = impl_from_IPin(iface);
\r
294 IBaseFilter_GetState(This->m_pCFilter, 0, &fs);
\r
295 if (fs != State_Stopped) {
\r
296 return VFW_E_NOT_STOPPED;
\r
298 if (This->m_pConnectedPin == NULL) {
\r
301 if (This->m_pAllocator) {
\r
302 hr = IMemAllocator_Decommit(This->m_pAllocator);
\r
306 SAFE_RELEASE(This->m_pAllocator);
\r
308 SAFE_RELEASE(This->m_pConnectedPin);
\r
314 static STDMETHODIMP HWCPin_ConnectedTo(IPin *iface, IPin **ppPin)
\r
316 HWCInPin *This = impl_from_IPin(iface);
\r
318 if (ppPin == NULL) {
\r
322 if (This->m_pConnectedPin == NULL) {
\r
324 return VFW_E_NOT_CONNECTED;
\r
326 *ppPin = This->m_pConnectedPin;
\r
327 IPin_AddRef(This->m_pConnectedPin);
\r
332 static STDMETHODIMP HWCPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)
\r
337 return VFW_E_NOT_CONNECTED;
\r
340 static STDMETHODIMP HWCPin_QueryPinInfo(IPin *iface, PIN_INFO *pInfo)
\r
342 HWCInPin *This = impl_from_IPin(iface);
\r
344 if (pInfo == NULL) {
\r
348 pInfo->pFilter = This->m_pCFilter;
\r
349 if (This->m_pCFilter) {
\r
350 IBaseFilter_AddRef(This->m_pCFilter);
\r
352 memcpy((void *)pInfo->achName, (void *)HWCPinName, sizeof(HWCPinName));
\r
353 pInfo->dir = PINDIR_INPUT;
\r
357 static STDMETHODIMP HWCPin_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir)
\r
359 if (pPinDir == NULL) {
\r
362 *pPinDir = PINDIR_INPUT;
\r
366 static STDMETHODIMP HWCPin_QueryId(IPin *iface, LPWSTR *Id)
\r
372 pId = CoTaskMemAlloc(sizeof(HWCPinName));
\r
373 memcpy((void *)pId, (void *)HWCPinName, sizeof(HWCPinName));
\r
378 static STDMETHODIMP HWCPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)
\r
386 static STDMETHODIMP HWCPin_EnumMediaTypes(IPin *iface,
\r
387 IEnumMediaTypes **ppEnum)
\r
389 if (ppEnum == NULL) {
\r
395 static STDMETHODIMP HWCPin_QueryInternalConnections(IPin *iface,
\r
402 static STDMETHODIMP HWCPin_EndOfStream(IPin *iface)
\r
407 static STDMETHODIMP HWCPin_BeginFlush(IPin *iface)
\r
412 static STDMETHODIMP HWCPin_EndFlush(IPin *iface)
\r
417 static STDMETHODIMP HWCPin_NewSegment(IPin *iface, REFERENCE_TIME tStart,
\r
418 REFERENCE_TIME tStop, double dRate)
\r
423 static STDMETHODIMP HWCMemInputPin_QueryInterface(IMemInputPin *iface,
\r
424 REFIID riid, void **ppv)
\r
426 HWCInPin *This = impl_from_IMemInputPin(iface);
\r
428 if (IsEqualIID(riid, &IID_IUnknown)) {
\r
429 *ppv = (IUnknown *)(&This->IMemInputPin_iface);
\r
430 IPin_AddRef((IPin *)*ppv);
\r
431 } else if (IsEqualIID(riid, &IID_IPin)) {
\r
432 *ppv = (IPin *)(&This->IPin_iface);
\r
433 IPin_AddRef((IPin *)*ppv);
\r
434 } else if (IsEqualIID(riid, &IID_IMemInputPin)) {
\r
435 *ppv = (IMemInputPin *)(&This->IMemInputPin_iface);
\r
436 IPin_AddRef((IMemInputPin *)*ppv);
\r
439 return E_NOINTERFACE;
\r
445 static STDMETHODIMP_(ULONG) HWCMemInputPin_AddRef(IMemInputPin *iface)
\r
447 HWCInPin *This = impl_from_IMemInputPin(iface);
\r
449 return InterlockedIncrement(&This->m_cRef);
\r
452 static STDMETHODIMP_(ULONG) HWCMemInputPin_Release(IMemInputPin *iface)
\r
454 HWCInPin *This = impl_from_IMemInputPin(iface);
\r
456 if (InterlockedDecrement(&This->m_cRef) == 0) {
\r
457 if (This->m_pCallback) {
\r
458 SAFE_RELEASE(This->m_pCallback);
\r
460 if (This->m_pConnectedPin) {
\r
461 SAFE_RELEASE(This->m_pConnectedPin);
\r
463 if (This->m_pAllocator) {
\r
464 IMemAllocator_Decommit(This->m_pAllocator);
\r
465 SAFE_RELEASE(This->m_pAllocator);
\r
467 g_free((void *)This);
\r
471 return This->m_cRef;
\r
474 static STDMETHODIMP HWCMemInputPin_GetAllocator(IMemInputPin *iface,
\r
475 IMemAllocator **ppAllocator)
\r
477 HWCInPin *This = impl_from_IMemInputPin(iface);
\r
479 if (ppAllocator == NULL) {
\r
483 if (This->m_pAllocator == NULL) {
\r
484 HRESULT hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL,
\r
485 CLSCTX_INPROC_SERVER,
\r
486 &IID_IMemAllocator,
\r
487 (void **)&(This->m_pAllocator));
\r
489 ERR("Failed to CoCreateInstance for retrieving MemoryAllocator\n");
\r
493 ASSERT(This->m_pAllocator != NULL);
\r
494 *ppAllocator = This->m_pAllocator;
\r
495 IMemAllocator_AddRef(This->m_pAllocator);
\r
500 static STDMETHODIMP HWCMemInputPin_NotifyAllocator(IMemInputPin *iface,
\r
501 IMemAllocator *pAllocator,
\r
504 HWCInPin *This = impl_from_IMemInputPin(iface);
\r
506 if (pAllocator == NULL) {
\r
510 IMemAllocator *pOldAllocator = This->m_pAllocator;
\r
511 IMemAllocator_AddRef(pAllocator);
\r
512 This->m_pAllocator = pAllocator;
\r
514 if (pOldAllocator != NULL) {
\r
515 SAFE_RELEASE(pOldAllocator);
\r
518 This->m_bReadOnly = bReadOnly;
\r
523 static STDMETHODIMP HWCMemInputPin_GetAllocatorRequirements(
\r
524 IMemInputPin *iface,
\r
525 ALLOCATOR_PROPERTIES *pProps)
\r
530 static STDMETHODIMP HWCMemInputPin_Receive(IMemInputPin *iface,
\r
531 IMediaSample *pSample)
\r
533 HWCInPin *This = impl_from_IMemInputPin(iface);
\r
535 if (pSample == NULL) {
\r
536 ERR("pSample is NULL\n");
\r
539 if (This->m_pCallback != NULL) {
\r
541 BYTE *pBuffer = NULL;
\r
543 dwSize = IMediaSample_GetSize(pSample);
\r
544 hr = IMediaSample_GetPointer(pSample, &pBuffer);
\r
546 ERR("Receive function : "
\r
547 "failed to IMediaSample_GetPointer, 0x%ld\n", hr);
\r
550 hr = IGrabCallback_Grab(This->m_pCallback, dwSize, pBuffer);
\r
552 ERR("Receive function : failed to IGrabCallback_Grab, 0x%ld\n",
\r
560 static STDMETHODIMP HWCMemInputPin_ReceiveMultiple(IMemInputPin *iface,
\r
561 IMediaSample **pSamples,
\r
563 long *nSamplesProcessed)
\r
567 if (pSamples == NULL) {
\r
571 *nSamplesProcessed = 0;
\r
573 while (nSamples-- > 0) {
\r
574 hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
\r
578 (*nSamplesProcessed)++;
\r
583 static STDMETHODIMP HWCMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
\r
588 static STDMETHODIMP HWCPin_SetCallback(IPin *iface, IGrabCallback *pCaptureCB)
\r
590 HWCInPin *This = impl_from_IPin(iface);
\r
592 if (pCaptureCB == NULL) {
\r
593 SAFE_RELEASE(This->m_pCallback);
\r
595 This->m_pCallback = pCaptureCB;
\r
596 IGrabCallback_AddRef(This->m_pCallback);
\r
603 static IPinVtbl HWCPin_Vtbl = {
\r
604 HWCPin_QueryInterface,
\r
608 HWCPin_ReceiveConnection,
\r
610 HWCPin_ConnectedTo,
\r
611 HWCPin_ConnectionMediaType,
\r
612 HWCPin_QueryPinInfo,
\r
613 HWCPin_QueryDirection,
\r
615 HWCPin_QueryAccept,
\r
616 HWCPin_EnumMediaTypes,
\r
617 HWCPin_QueryInternalConnections,
\r
618 HWCPin_EndOfStream,
\r
624 static IMemInputPinVtbl HWCMemInputPin_Vtbl = {
\r
625 HWCMemInputPin_QueryInterface,
\r
626 HWCMemInputPin_AddRef,
\r
627 HWCMemInputPin_Release,
\r
628 HWCMemInputPin_GetAllocator,
\r
629 HWCMemInputPin_NotifyAllocator,
\r
630 HWCMemInputPin_GetAllocatorRequirements,
\r
631 HWCMemInputPin_Receive,
\r
632 HWCMemInputPin_ReceiveMultiple,
\r
633 HWCMemInputPin_ReceiveCanBlock
\r
636 static STDMETHODIMP HWCInPin_Construct(IBaseFilter *pFilter, IPin **ppv)
\r
638 HWCInPin *This = (HWCInPin *)g_malloc0(sizeof(HWCInPin));
\r
641 ERR("failed to HWCInPin_Construct, E_OUTOFMEMORY\n");
\r
642 return E_OUTOFMEMORY;
\r
645 This->IPin_iface.lpVtbl = &HWCPin_Vtbl;
\r
646 This->IMemInputPin_iface.lpVtbl = &HWCMemInputPin_Vtbl;
\r
647 This->m_bReadOnly = FALSE;
\r
648 This->m_pCFilter = pFilter;
\r
649 This->m_pConnectedPin = NULL;
\r
650 This->m_pCallback = NULL;
\r
651 This->m_pAllocator = NULL;
\r
653 This->SetGrabCallbackIF = HWCPin_SetCallback;
\r
654 *ppv = &This->IPin_iface;
\r
663 typedef struct HWCEnumPins {
\r
664 IEnumPins IEnumPins_iface;
\r
665 IBaseFilter *m_pFilter;
\r
670 static inline HWCEnumPins *impl_from_IEnumPins(IEnumPins *iface)
\r
672 return CONTAINING_RECORD(iface, HWCEnumPins, IEnumPins_iface);
\r
675 static STDMETHODIMP HWCEnumPins_QueryInterface(IEnumPins *iface,
\r
676 REFIID riid, void **ppv)
\r
682 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumPins)) {
\r
686 return E_NOINTERFACE;
\r
689 IEnumPins_AddRef(iface);
\r
693 static STDMETHODIMP_(ULONG) HWCEnumPins_AddRef(IEnumPins *iface)
\r
695 HWCEnumPins *This = impl_from_IEnumPins(iface);
\r
697 return InterlockedIncrement(&This->m_cRef);
\r
700 static STDMETHODIMP_(ULONG) HWCEnumPins_Release(IEnumPins *iface)
\r
702 HWCEnumPins *This = impl_from_IEnumPins(iface);
\r
704 if (InterlockedDecrement(&This->m_cRef) == 0) {
\r
705 if (This->m_pFilter) {
\r
706 SAFE_RELEASE(This->m_pFilter);
\r
709 g_free((void *)This);
\r
713 return This->m_cRef;
\r
716 static STDMETHODIMP HWCEnumPins_Next(IEnumPins *iface, ULONG cPins,
\r
717 IPin **ppPins, ULONG *pcFetched)
\r
720 HWCEnumPins *This = impl_from_IEnumPins(iface);
\r
722 if (ppPins == NULL) {
\r
726 if (This->m_nPos < 1 && cPins > 0) {
\r
728 IBaseFilter_FindPin(This->m_pFilter, HWCPinName, &pPin);
\r
736 if (pcFetched != NULL) {
\r
737 *pcFetched = fetched;
\r
740 return (fetched == cPins) ? S_OK : S_FALSE;
\r
743 static STDMETHODIMP HWCEnumPins_Skip(IEnumPins *iface, ULONG cPins)
\r
745 HWCEnumPins *This = impl_from_IEnumPins(iface);
\r
746 This->m_nPos += cPins;
\r
747 return (This->m_nPos >= 1) ? S_FALSE : S_OK;
\r
750 static STDMETHODIMP HWCEnumPins_Reset(IEnumPins *iface)
\r
752 HWCEnumPins *This = impl_from_IEnumPins(iface);
\r
757 static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter,
\r
758 int nPos, IEnumPins **ppv);
\r
760 static STDMETHODIMP HWCEnumPins_Clone(IEnumPins *iface, IEnumPins **ppEnum)
\r
762 HWCEnumPins *This = impl_from_IEnumPins(iface);
\r
764 if (ppEnum == NULL) {
\r
768 HWCEnumPins_Construct(This->m_pFilter, This->m_nPos, ppEnum);
\r
769 if (*ppEnum == NULL) {
\r
770 ERR("failed to HWCEnumPins_Construct in clone, E_OUTOFMEMORY\n");
\r
771 return E_OUTOFMEMORY;
\r
777 static IEnumPinsVtbl HWCEnumPins_Vtbl = {
\r
778 HWCEnumPins_QueryInterface,
\r
779 HWCEnumPins_AddRef,
\r
780 HWCEnumPins_Release,
\r
788 static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter,
\r
789 int nPos, IEnumPins **ppv)
\r
791 HWCEnumPins *This = (HWCEnumPins *)g_malloc0(sizeof(HWCEnumPins));
\r
794 ERR("failed to HWCEnumPins_Construct, E_OUTOFMEMORY\n");
\r
795 return E_OUTOFMEMORY;
\r
798 This->IEnumPins_iface.lpVtbl = &HWCEnumPins_Vtbl;
\r
799 This->m_pFilter = pFilter;
\r
800 if (This->m_pFilter) {
\r
801 IBaseFilter_AddRef(This->m_pFilter);
\r
804 This->m_nPos = nPos;
\r
805 *ppv = &This->IEnumPins_iface;
\r
814 typedef struct HWCFilter {
\r
815 IBaseFilter IBaseFilter_iface;
\r
817 IFilterGraph *m_pFilterGraph;
\r
818 FILTER_STATE m_state;
\r
822 static inline HWCFilter *impl_from_IBaseFilter(IBaseFilter *iface)
\r
824 return CONTAINING_RECORD(iface, HWCFilter, IBaseFilter_iface);
\r
827 static STDMETHODIMP HWCFilter_QueryInterface(IBaseFilter *iface,
\r
828 REFIID riid, void **ppv)
\r
830 if (IsEqualIID(riid, &IID_IUnknown)) {
\r
831 *ppv = (IUnknown *)iface;
\r
832 } else if (IsEqualIID(riid, &IID_IPersist)) {
\r
833 *ppv = (IPersist *)iface;
\r
834 } else if (IsEqualIID(riid, &IID_IMediaFilter)) {
\r
835 *ppv = (IMediaFilter *)iface;
\r
836 } else if (IsEqualIID(riid, &IID_IBaseFilter)) {
\r
837 *ppv = (IBaseFilter *)iface;
\r
840 return E_NOINTERFACE;
\r
843 IBaseFilter_AddRef(iface);
\r
847 static STDMETHODIMP_(ULONG) HWCFilter_AddRef(IBaseFilter *iface)
\r
849 HWCFilter *This = impl_from_IBaseFilter(iface);
\r
851 return InterlockedIncrement(&This->m_cRef);
\r
854 static STDMETHODIMP_(ULONG) HWCFilter_Release(IBaseFilter *iface)
\r
856 HWCFilter *This = impl_from_IBaseFilter(iface);
\r
858 if (InterlockedDecrement(&This->m_cRef) == 0) {
\r
859 if (This->m_pPin) {
\r
860 SAFE_RELEASE(This->m_pPin);
\r
862 g_free((void *)This);
\r
866 return This->m_cRef;
\r
869 static STDMETHODIMP HWCFilter_GetClassID(IBaseFilter *iface, CLSID *pClsID)
\r
871 if (pClsID == NULL) {
\r
877 static STDMETHODIMP HWCFilter_GetState(IBaseFilter *iface, DWORD dwMSecs,
\r
878 FILTER_STATE *State)
\r
880 HWCFilter *This = impl_from_IBaseFilter(iface);
\r
881 *State = This->m_state;
\r
885 static STDMETHODIMP HWCFilter_SetSyncSource(IBaseFilter *iface,
\r
886 IReferenceClock *pClock)
\r
891 static STDMETHODIMP HWCFilter_GetSyncSource(IBaseFilter *iface,
\r
892 IReferenceClock **pClock)
\r
898 static STDMETHODIMP HWCFilter_Stop(IBaseFilter *iface)
\r
900 HWCFilter *This = impl_from_IBaseFilter(iface);
\r
902 IPin_EndFlush(This->m_pPin);
\r
903 This->m_state = State_Stopped;
\r
907 static STDMETHODIMP HWCFilter_Pause(IBaseFilter *iface)
\r
909 HWCFilter *This = impl_from_IBaseFilter(iface);
\r
910 This->m_state = State_Paused;
\r
914 static STDMETHODIMP HWCFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
\r
916 HWCFilter *This = impl_from_IBaseFilter(iface);
\r
918 if (This->m_state == State_Stopped) {
\r
920 hr = IBaseFilter_Pause(iface);
\r
922 ERR("HWCFilter_Run : Failed to IBaseFilter_Pause, ret=0xld%\n", hr);
\r
927 This->m_state = State_Running;
\r
931 static STDMETHODIMP HWCFilter_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum)
\r
933 if (ppEnum == NULL) {
\r
937 HWCEnumPins_Construct(iface, 0, ppEnum);
\r
938 return *ppEnum == NULL ? E_OUTOFMEMORY : S_OK;
\r
941 static STDMETHODIMP HWCFilter_FindPin(IBaseFilter *iface, LPCWSTR Id,
\r
944 HWCFilter *This = impl_from_IBaseFilter(iface);
\r
946 if (ppPin == NULL) {
\r
950 if (memcmp((void *)Id, (void *)HWCPinName, sizeof(HWCPinName))) {
\r
951 return VFW_E_NOT_FOUND;
\r
954 if (!This->m_pPin) {
\r
955 HWCInPin_Construct(iface, &This->m_pPin);
\r
957 *ppPin = This->m_pPin;
\r
959 IPin_AddRef(This->m_pPin);
\r
963 static STDMETHODIMP HWCFilter_QueryFilterInfo(IBaseFilter *iface,
\r
964 FILTER_INFO *pInfo)
\r
966 HWCFilter *This = impl_from_IBaseFilter(iface);
\r
968 if (pInfo == NULL) {
\r
972 memcpy((void *)pInfo->achName,
\r
973 (void *)HWCFilterName,
\r
974 sizeof(HWCFilterName));
\r
975 pInfo->pGraph = This->m_pFilterGraph;
\r
976 if (This->m_pFilterGraph) {
\r
977 IFilterGraph_AddRef(This->m_pFilterGraph);
\r
982 static STDMETHODIMP HWCFilter_JoinFilterGraph(IBaseFilter *iface,
\r
983 IFilterGraph *pGraph,
\r
986 HWCFilter *This = impl_from_IBaseFilter(iface);
\r
988 This->m_pFilterGraph = pGraph;
\r
992 static STDMETHODIMP HWCFilter_QueryVendorInfo(IBaseFilter *iface,
\r
993 LPWSTR *pVendorInfo)
\r
998 static IBaseFilterVtbl HWCFilter_Vtbl = {
\r
999 HWCFilter_QueryInterface,
\r
1001 HWCFilter_Release,
\r
1002 HWCFilter_GetClassID,
\r
1006 HWCFilter_GetState,
\r
1007 HWCFilter_SetSyncSource,
\r
1008 HWCFilter_GetSyncSource,
\r
1009 HWCFilter_EnumPins,
\r
1010 HWCFilter_FindPin,
\r
1011 HWCFilter_QueryFilterInfo,
\r
1012 HWCFilter_JoinFilterGraph,
\r
1013 HWCFilter_QueryVendorInfo
\r
1016 static STDMETHODIMP HWCFilter_Construct(IBaseFilter **ppv)
\r
1018 HWCFilter *This = (HWCFilter *)g_malloc0(sizeof(HWCFilter));
\r
1021 ERR("failed to HWCFilter_Construct, E_OUTOFMEMORY\n");
\r
1022 return E_OUTOFMEMORY;
\r
1025 This->IBaseFilter_iface.lpVtbl = &HWCFilter_Vtbl;
\r
1026 This->m_pFilterGraph = NULL;
\r
1027 This->m_state = State_Stopped;
\r
1029 HWCInPin_Construct(&This->IBaseFilter_iface, &This->m_pPin);
\r
1030 *ppv = &This->IBaseFilter_iface;
\r
1035 /**********************************************************
\r
1037 * Virtual device implementations
\r
1039 **********************************************************/
\r
1043 * Declaration global variables for Win32 COM Interfaces
\r
1045 IGraphBuilder *g_pGB ;
\r
1046 ICaptureGraphBuilder2 *g_pCGB;
\r
1047 IMediaControl *g_pMediaControl;
\r
1049 IPin *g_pOutputPin;
\r
1050 IPin *g_pInputPin;
\r
1051 IBaseFilter *g_pDstFilter;
\r
1052 IBaseFilter *g_pSrcFilter;
\r
1054 IGrabCallback *g_pCallback;
\r
1056 /* V4L2 defines copy from videodev2.h */
\r
1057 #define V4L2_CTRL_FLAG_SLIDER 0x0020
\r
1059 #define V4L2_CTRL_CLASS_USER 0x00980000
\r
1060 #define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900)
\r
1061 #define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0)
\r
1062 #define V4L2_CID_CONTRAST (V4L2_CID_BASE+1)
\r
1063 #define V4L2_CID_SATURATION (V4L2_CID_BASE+2)
\r
1064 #define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27)
\r
1066 #define V4L2_PIX_FMT_YUYV MAKEFOURCC('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */
\r
1067 #define V4L2_PIX_FMT_YUV420 MAKEFOURCC('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */
\r
1068 #define V4L2_PIX_FMT_YVU420 MAKEFOURCC('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */
\r
1069 #define V4L2_PIX_FMT_RGB24 MAKEFOURCC('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */
\r
1071 typedef struct tagMaruCamConvertPixfmt {
\r
1072 uint32_t fmt; /* fourcc */
\r
1073 uint32_t bpp; /* bits per pixel, 0 for compressed formats */
\r
1074 uint32_t needs_conversion;
\r
1075 } MaruCamConvertPixfmt;
\r
1077 static MaruCamConvertPixfmt supported_dst_pixfmts[] = {
\r
1078 { V4L2_PIX_FMT_YUYV, 16, 0 },
\r
1079 { V4L2_PIX_FMT_YUV420, 12, 0 },
\r
1080 { V4L2_PIX_FMT_YVU420, 12, 0 },
\r
1083 typedef struct tagMaruCamConvertFrameInfo {
\r
1086 } MaruCamConvertFrameInfo;
\r
1088 static MaruCamConvertFrameInfo supported_dst_frames[] = {
\r
1096 #define MARUCAM_CTRL_VALUE_MAX 20
\r
1097 #define MARUCAM_CTRL_VALUE_MIN 1
\r
1098 #define MARUCAM_CTRL_VALUE_MID 10
\r
1099 #define MARUCAM_CTRL_VALUE_STEP 1
\r
1101 struct marucam_qctrl {
\r
1110 static struct marucam_qctrl qctrl_tbl[] = {
\r
1111 { V4L2_CID_BRIGHTNESS, 0, },
\r
1112 { V4L2_CID_CONTRAST, 0, },
\r
1113 { V4L2_CID_SATURATION, 0, },
\r
1114 { V4L2_CID_SHARPNESS, 0, },
\r
1117 static MaruCamState *g_state;
\r
1119 static uint32_t ready_count;
\r
1120 static uint32_t cur_fmt_idx;
\r
1121 static uint32_t cur_frame_idx;
\r
1122 static void *grab_buf;
\r
1123 static uint32_t g_dwSrcFmt;
\r
1127 * Helper functions - converting image formats, converting values
\r
1130 static uint32_t get_bytesperline(uint32_t pixfmt, uint32_t width)
\r
1132 uint32_t bytesperline;
\r
1135 case V4L2_PIX_FMT_YUV420:
\r
1136 case V4L2_PIX_FMT_YVU420:
\r
1137 bytesperline = (width * 12) >> 3;
\r
1139 case V4L2_PIX_FMT_YUYV:
\r
1141 bytesperline = width * 2;
\r
1145 return bytesperline;
\r
1148 static uint32_t get_sizeimage(uint32_t pixfmt, uint32_t width, uint32_t height)
\r
1150 return get_bytesperline(pixfmt, width) * height;
\r
1153 void yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
\r
1154 uint32_t width, uint32_t height, uint32_t yvu);
\r
1155 void rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,
\r
1156 uint32_t width, uint32_t height, uint32_t yvu);
\r
1157 void rgb24_to_yuyv(unsigned char *src, unsigned char *dest,
\r
1158 uint32_t width, uint32_t height);
\r
1159 void yuv420_to_yvu420(unsigned char *src, unsigned char *dest,
\r
1160 uint32_t width, uint32_t height);
\r
1161 void yuv420_to_yuyv(unsigned char *src, unsigned char *dest,
\r
1162 uint32_t width, uint32_t height);
\r
1164 static long value_convert_from_guest(long min, long max, long value)
\r
1166 double rate = 0.0;
\r
1167 long dist = 0, ret = 0;
\r
1171 if (dist < MARUCAM_CTRL_VALUE_MAX) {
\r
1172 rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
\r
1173 ret = min + (int32_t)(value / rate);
\r
1175 rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
\r
1176 ret = min + (int32_t)(rate * value);
\r
1181 static long value_convert_to_guest(long min, long max, long value)
\r
1183 double rate = 0.0;
\r
1184 long dist = 0, ret = 0;
\r
1188 if (dist < MARUCAM_CTRL_VALUE_MAX) {
\r
1189 rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
\r
1190 ret = (int32_t)((double)(value - min) * rate);
\r
1192 rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
\r
1193 ret = (int32_t)((double)(value - min) / rate);
\r
1200 * Callback function for grab frames
\r
1202 static STDMETHODIMP marucam_device_callbackfn(ULONG dwSize, BYTE *pBuffer)
\r
1205 uint32_t width, height, fmt, imgsize;
\r
1207 width = supported_dst_frames[cur_frame_idx].width;
\r
1208 height = supported_dst_frames[cur_frame_idx].height;
\r
1209 fmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
\r
1210 imgsize = get_sizeimage(fmt, width, height);
\r
1212 if (imgsize > (uint32_t)dwSize) {
\r
1213 ERR("Image size is mismatched\n");
\r
1217 switch (g_dwSrcFmt) {
\r
1218 case V4L2_PIX_FMT_YUYV:
\r
1220 case V4L2_PIX_FMT_YUV420:
\r
1221 yuyv_to_yuv420(pBuffer, grab_buf, width, height, 0);
\r
1223 case V4L2_PIX_FMT_YVU420:
\r
1224 yuyv_to_yuv420(pBuffer, grab_buf, width, height, 1);
\r
1226 case V4L2_PIX_FMT_YUYV:
\r
1227 memcpy(grab_buf, (void *)pBuffer, (size_t)dwSize);
\r
1230 ERR("Invalid pixel format\n");
\r
1234 case V4L2_PIX_FMT_RGB24:
\r
1236 case V4L2_PIX_FMT_YUV420:
\r
1237 rgb24_to_yuv420(pBuffer, grab_buf, width, height, 0);
\r
1239 case V4L2_PIX_FMT_YVU420:
\r
1240 rgb24_to_yuv420(pBuffer, grab_buf, width, height, 1);
\r
1242 case V4L2_PIX_FMT_YUYV:
\r
1243 rgb24_to_yuyv(pBuffer, grab_buf, width, height);
\r
1246 ERR("Invalid pixel format\n");
\r
1250 case V4L2_PIX_FMT_YUV420:
\r
1252 case V4L2_PIX_FMT_YUV420:
\r
1253 memcpy(grab_buf, (void *)pBuffer, (size_t)dwSize);
\r
1255 case V4L2_PIX_FMT_YVU420:
\r
1256 yuv420_to_yvu420(pBuffer, grab_buf, width, height);
\r
1258 case V4L2_PIX_FMT_YUYV:
\r
1259 yuv420_to_yuyv(pBuffer, grab_buf, width, height);
\r
1262 ERR("Invalid pixel format\n");
\r
1267 ERR("Invalid pixel format\n");
\r
1271 qemu_mutex_lock(&g_state->thread_mutex);
\r
1272 if (g_state->streamon) {
\r
1273 if (ready_count < MARUCAM_SKIPFRAMES) {
\r
1274 /* skip a frame cause first some frame are distorted */
\r
1276 TRACE("skip %d frame\n", ready_count);
\r
1277 qemu_mutex_unlock(&g_state->thread_mutex);
\r
1280 if (g_state->req_frame == 0) {
\r
1281 TRACE("there is no request\n");
\r
1282 qemu_mutex_unlock(&g_state->thread_mutex);
\r
1285 tmp_buf = g_state->vaddr + g_state->buf_size * (g_state->req_frame - 1);
\r
1286 memcpy(tmp_buf, grab_buf, g_state->buf_size);
\r
1287 g_state->req_frame = 0; /* clear request */
\r
1288 g_state->isr |= 0x01; /* set a flag of rasing a interrupt */
\r
1289 qemu_bh_schedule(g_state->tx_bh);
\r
1291 qemu_mutex_unlock(&g_state->thread_mutex);
\r
1296 * Internal functions for manipulate interfaces
\r
1299 static STDMETHODIMP_(void) CloseInterfaces(void)
\r
1301 if (g_pMediaControl) {
\r
1302 g_pMediaControl->lpVtbl->Stop(g_pMediaControl);
\r
1305 if (g_pOutputPin) {
\r
1306 g_pOutputPin->lpVtbl->Disconnect(g_pOutputPin);
\r
1309 SAFE_RELEASE(g_pGB);
\r
1310 SAFE_RELEASE(g_pCGB);
\r
1311 SAFE_RELEASE(g_pMediaControl);
\r
1312 SAFE_RELEASE(g_pOutputPin);
\r
1313 SAFE_RELEASE(g_pInputPin);
\r
1314 SAFE_RELEASE(g_pDstFilter);
\r
1315 SAFE_RELEASE(g_pSrcFilter);
\r
1316 SAFE_RELEASE(g_pCallback);
\r
1319 static STDMETHODIMP_(void) DeleteMediaType(AM_MEDIA_TYPE *pmt)
\r
1321 if (pmt == NULL) {
\r
1325 if (pmt->cbFormat != 0) {
\r
1326 CoTaskMemFree((PVOID)pmt->pbFormat);
\r
1327 pmt->cbFormat = 0;
\r
1328 pmt->pbFormat = NULL;
\r
1330 if (pmt->pUnk != NULL) {
\r
1331 pmt->pUnk->lpVtbl->Release(pmt->pUnk);
\r
1335 CoTaskMemFree((PVOID)pmt);
\r
1338 static STDMETHODIMP GetPin(IBaseFilter *pFilter,
\r
1339 PIN_DIRECTION PinDir, IPin **ppPin)
\r
1342 IEnumPins *pEnum = NULL;
\r
1343 IPin *pPin = NULL;
\r
1345 if (ppPin == NULL) {
\r
1349 hr = pFilter->lpVtbl->EnumPins(pFilter, &pEnum);
\r
1354 while (pEnum->lpVtbl->Next(pEnum, 1, &pPin, 0) == S_OK) {
\r
1355 PIN_DIRECTION PinDirThis;
\r
1356 hr = pPin->lpVtbl->QueryDirection(pPin, &PinDirThis);
\r
1358 SAFE_RELEASE(pPin);
\r
1359 SAFE_RELEASE(pEnum);
\r
1362 if (PinDir == PinDirThis) {
\r
1364 SAFE_RELEASE(pEnum);
\r
1367 SAFE_RELEASE(pPin);
\r
1370 SAFE_RELEASE(pEnum);
\r
1374 static STDMETHODIMP GraphBuilder_Init(void)
\r
1378 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC,
\r
1379 &IID_IGraphBuilder, (void **)&g_pGB);
\r
1381 ERR("Failed to create instance of GraphBuilder, 0x%x\n", hr);
\r
1385 hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,
\r
1386 &IID_ICaptureGraphBuilder2, (void **)&g_pCGB);
\r
1388 ERR("Failed to create instance of CaptureGraphBuilder2, 0x%x\n", hr);
\r
1392 hr = g_pCGB->lpVtbl->SetFiltergraph(g_pCGB, g_pGB);
\r
1394 ERR("Failed to SetFiltergraph, 0x%x\n", hr);
\r
1398 hr = g_pGB->lpVtbl->QueryInterface(g_pGB, &IID_IMediaControl,
\r
1399 (void **)&g_pMediaControl);
\r
1401 ERR("Failed to QueryInterface for IMediaControl, 0x%x\n", hr);
\r
1405 hr = HWCGrabCallback_Construct(&g_pCallback);
\r
1406 if (g_pCallback == NULL) {
\r
1407 hr = E_OUTOFMEMORY;
\r
1410 hr = ((HWCGrabCallback *)g_pCallback)->SetCallback(g_pCallback,
\r
1411 (CallbackFn)marucam_device_callbackfn);
\r
1416 static STDMETHODIMP BindSourceFilter(void)
\r
1419 ICreateDevEnum *pCreateDevEnum = NULL;
\r
1420 IEnumMoniker *pEnumMK = NULL;
\r
1421 IMoniker *pMoniKer;
\r
1423 hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
\r
1424 &IID_ICreateDevEnum,
\r
1425 (void **)&pCreateDevEnum);
\r
1427 ERR("Failed to create instance of CreateDevEnum, 0x%x\n", hr);
\r
1431 hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum,
\r
1432 &CLSID_VideoInputDeviceCategory,
\r
1435 ERR("Failed to get VideoInputDeviceCategory, 0x%x\n", hr);
\r
1436 SAFE_RELEASE(pCreateDevEnum);
\r
1441 ERR("ClassEnumerator moniker is NULL\n");
\r
1442 SAFE_RELEASE(pCreateDevEnum);
\r
1445 pEnumMK->lpVtbl->Reset(pEnumMK);
\r
1447 hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL);
\r
1448 if (hr == S_FALSE) {
\r
1451 if (SUCCEEDED(hr)) {
\r
1452 IPropertyBag *pBag = NULL;
\r
1453 hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0,
\r
1454 &IID_IPropertyBag,
\r
1456 if (SUCCEEDED(hr)) {
\r
1459 hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);
\r
1460 if (hr == NOERROR) {
\r
1461 hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL,
\r
1463 (void **)&g_pSrcFilter);
\r
1465 ERR("Counldn't bind moniker to filter object!!\n");
\r
1467 g_pSrcFilter->lpVtbl->AddRef(g_pSrcFilter);
\r
1469 SysFreeString(var.bstrVal);
\r
1471 SAFE_RELEASE(pBag);
\r
1473 SAFE_RELEASE(pMoniKer);
\r
1476 if (SUCCEEDED(hr)) {
\r
1477 hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pSrcFilter, L"Video Capture");
\r
1478 if (hr != S_OK && hr != S_FALSE) {
\r
1479 ERR("Counldn't add Video Capture filter to our graph!\n");
\r
1480 SAFE_RELEASE(g_pSrcFilter);
\r
1483 SAFE_RELEASE(pEnumMK);
\r
1484 SAFE_RELEASE(pCreateDevEnum);
\r
1489 static STDMETHODIMP BindTargetFilter(void)
\r
1492 hr = HWCFilter_Construct(&g_pDstFilter);
\r
1494 if (SUCCEEDED(hr) && g_pDstFilter) {
\r
1495 hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pDstFilter, L"HWCFilter");
\r
1497 ERR("Counldn't add HWCFilterr to our graph!\n");
\r
1498 SAFE_RELEASE(g_pDstFilter);
\r
1504 static STDMETHODIMP ConnectFilters(void)
\r
1508 hr = GetPin(g_pSrcFilter, PINDIR_OUTPUT , &g_pOutputPin);
\r
1510 ERR("Failed to get output pin. 0x%x\n", hr);
\r
1514 hr = GetPin(g_pDstFilter, PINDIR_INPUT , &g_pInputPin);
\r
1516 ERR("Failed to get input pin. 0x%x\n", hr);
\r
1520 hr = g_pGB->lpVtbl->Connect(g_pGB, g_pOutputPin, g_pInputPin);
\r
1522 ERR("Failed to connect pins. 0x%x\n", hr);
\r
1527 static STDMETHODIMP DisconnectPins(void)
\r
1531 hr = g_pGB->lpVtbl->Disconnect(g_pGB, g_pOutputPin);
\r
1533 ERR("Failed to disconnect output pin. 0x%x\n", hr);
\r
1537 hr = g_pGB->lpVtbl->Disconnect(g_pGB, g_pInputPin);
\r
1539 ERR("Failed to disconnect input pin. 0x%x\n", hr);
\r
1545 static STDMETHODIMP RemoveFilters(void)
\r
1549 hr = g_pGB->lpVtbl->RemoveFilter(g_pGB, g_pSrcFilter);
\r
1551 ERR("Failed to remove source filer. 0x%x\n", hr);
\r
1555 hr = g_pGB->lpVtbl->RemoveFilter(g_pGB, g_pDstFilter);
\r
1557 ERR("Failed to remove destination filer. 0x%x\n", hr);
\r
1563 /* default fps is 15 */
\r
1564 #define MARUCAM_DEFAULT_FRAMEINTERVAL 666666
\r
1566 static STDMETHODIMP SetFormat(uint32_t dwWidth, uint32_t dwHeight,
\r
1567 uint32_t dwDstFmt, uint32_t *dwSrcFmt)
\r
1570 IAMStreamConfig *pSConfig;
\r
1571 int iCount = 0, iSize = 0;
\r
1572 DWORD dwYUY2 = MAKEFOURCC('Y', 'U', 'Y', '2');
\r
1573 DWORD dwI420 = MAKEFOURCC('I', '4', '2', '0');
\r
1575 if (dwSrcFmt == NULL) {
\r
1576 ERR("invalid the source format pointer\n");
\r
1580 hr = g_pCGB->lpVtbl->FindInterface(g_pCGB, &PIN_CATEGORY_CAPTURE, 0,
\r
1581 g_pSrcFilter, &IID_IAMStreamConfig,
\r
1582 (void **)&pSConfig);
\r
1584 ERR("failed to FindInterface method\n");
\r
1588 hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);
\r
1590 ERR("failed to GetNumberOfCapabilities method\n");
\r
1591 SAFE_RELEASE(pSConfig);
\r
1595 if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
\r
1597 for (iFormat = 0; iFormat < iCount; iFormat++) {
\r
1598 VIDEO_STREAM_CONFIG_CAPS scc;
\r
1599 AM_MEDIA_TYPE *pmtConfig;
\r
1601 hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat,
\r
1602 &pmtConfig, (BYTE *)&scc);
\r
1604 if (IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo)) {
\r
1605 VIDEOINFOHEADER *pvi =
\r
1606 (VIDEOINFOHEADER *)pmtConfig->pbFormat;
\r
1607 if ((pvi->bmiHeader.biWidth == (LONG)dwWidth) &&
\r
1608 (pvi->bmiHeader.biHeight == (LONG)dwHeight)) {
\r
1609 if (pvi->bmiHeader.biCompression == dwYUY2) {
\r
1610 *dwSrcFmt = V4L2_PIX_FMT_YUYV;
\r
1611 } else if ((pvi->bmiHeader.biCompression == BI_RGB) &&
\r
1612 (pvi->bmiHeader.biBitCount == 24)) {
\r
1613 *dwSrcFmt = V4L2_PIX_FMT_RGB24;
\r
1614 } else if (pvi->bmiHeader.biCompression == dwI420) {
\r
1615 *dwSrcFmt = V4L2_PIX_FMT_YUV420;
\r
1616 } else { /* not support format */
\r
1617 DeleteMediaType(pmtConfig);
\r
1620 /* use minimum FPS(maximum frameinterval)
\r
1621 with non-VT system */
\r
1623 if (!hax_enabled()) {
\r
1624 pvi->AvgTimePerFrame =
\r
1625 (REFERENCE_TIME)scc.MaxFrameInterval;
\r
1627 pvi->AvgTimePerFrame =
\r
1628 (REFERENCE_TIME)MARUCAM_DEFAULT_FRAMEINTERVAL;
\r
1631 pvi->AvgTimePerFrame =
\r
1632 (REFERENCE_TIME)scc.MaxFrameInterval;
\r
1634 hr = pSConfig->lpVtbl->SetFormat(pSConfig, pmtConfig);
\r
1635 DeleteMediaType(pmtConfig);
\r
1639 DeleteMediaType(pmtConfig);
\r
1642 if (iFormat >= iCount) {
\r
1643 ERR("Failed to Set format. "
\r
1644 "Maybe connected webcam does not support the (%ldx%ld) "
\r
1645 "resolution or image formats(YUY2, RGB24, I420).\n",
\r
1646 dwWidth, dwHeight);
\r
1650 SAFE_RELEASE(pSConfig);
\r
1654 static STDMETHODIMP QueryVideoProcAmp(long nProperty, long *pMin, long *pMax,
\r
1655 long *pStep, long *pDefault)
\r
1659 IAMVideoProcAmp *pProcAmp = NULL;
\r
1661 hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
\r
1662 &IID_IAMVideoProcAmp,
\r
1663 (void **)&pProcAmp);
\r
1668 hr = pProcAmp->lpVtbl->GetRange(pProcAmp, nProperty, pMin, pMax,
\r
1669 pStep, pDefault, &Flags);
\r
1671 SAFE_RELEASE(pProcAmp);
\r
1675 static STDMETHODIMP GetVideoProcAmp(long nProperty, long *pValue)
\r
1679 IAMVideoProcAmp *pProcAmp = NULL;
\r
1681 hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
\r
1682 &IID_IAMVideoProcAmp,
\r
1683 (void **)&pProcAmp);
\r
1688 hr = pProcAmp->lpVtbl->Get(pProcAmp, nProperty, pValue, &Flags);
\r
1690 ERR("Failed to get property for video\n");
\r
1693 SAFE_RELEASE(pProcAmp);
\r
1697 static STDMETHODIMP SetVideoProcAmp(long nProperty, long value)
\r
1701 IAMVideoProcAmp *pProcAmp = NULL;
\r
1702 hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
\r
1703 &IID_IAMVideoProcAmp,
\r
1704 (void **)&pProcAmp);
\r
1709 hr = pProcAmp->lpVtbl->Set(pProcAmp, nProperty, value,
\r
1710 VideoProcAmp_Flags_Manual);
\r
1712 ERR("Failed to set property for video\n");
\r
1714 SAFE_RELEASE(pProcAmp);
\r
1718 static char *__wchar_to_char(const WCHAR *pwstr)
\r
1720 char *pstr = NULL;
\r
1723 len = wcslen(pwstr) + 1;
\r
1724 pstr = (char *)g_malloc0(sizeof(char) * len);
\r
1725 wcstombs(pstr, pwstr, len + 1);
\r
1730 int marucam_device_check(int log_flag)
\r
1732 struct timeval t1, t2;
\r
1734 char *device_name = NULL;
\r
1735 HRESULT hr = E_FAIL;
\r
1736 ICreateDevEnum *pCreateDevEnum = NULL;
\r
1737 IGraphBuilder *pGB = NULL;
\r
1738 ICaptureGraphBuilder2 *pCGB = NULL;
\r
1739 IBaseFilter *pSrcFilter = NULL;
\r
1740 IEnumMoniker *pEnumMK = NULL;
\r
1741 IMoniker *pMoniKer = NULL;
\r
1742 IAMStreamConfig *pSConfig = NULL;
\r
1743 int iCount = 0, iSize = 0;
\r
1745 gettimeofday(&t1, NULL);
\r
1746 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
\r
1748 fprintf(stdout, "[Webcam] failed to CoInitailizeEx\n");
\r
1749 gettimeofday(&t2, NULL);
\r
1750 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
1751 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
1755 hr = CoCreateInstance(&CLSID_FilterGraph, NULL,
\r
1757 &IID_IGraphBuilder,
\r
1760 fprintf(stdout, "[Webcam] Failed to create GraphBuilder, 0x%x\n", hr);
\r
1762 gettimeofday(&t2, NULL);
\r
1763 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
1764 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
1768 hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL,
\r
1770 &IID_ICaptureGraphBuilder2,
\r
1774 "[Webcam] Failed to create CaptureGraphBuilder2, 0x%x\n", hr);
\r
1775 SAFE_RELEASE(pGB);
\r
1777 gettimeofday(&t2, NULL);
\r
1778 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
1779 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
1783 hr = pCGB->lpVtbl->SetFiltergraph(pCGB, pGB);
\r
1785 fprintf(stdout, "[Webcam] Failed to SetFiltergraph, 0x%x\n", hr);
\r
1786 SAFE_RELEASE(pCGB);
\r
1787 SAFE_RELEASE(pGB);
\r
1789 gettimeofday(&t2, NULL);
\r
1790 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
1791 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
1795 hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL,
\r
1797 &IID_ICreateDevEnum,
\r
1798 (void **)&pCreateDevEnum);
\r
1801 "[Webcam] failed to create instance of CLSID_SystemDeviceEnum\n");
\r
1802 SAFE_RELEASE(pCGB);
\r
1803 SAFE_RELEASE(pGB);
\r
1805 gettimeofday(&t2, NULL);
\r
1806 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
1807 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
1811 hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum,
\r
1812 &CLSID_VideoInputDeviceCategory, &pEnumMK, 0);
\r
1814 fprintf(stdout, "[Webcam] failed to create class enumerator\n");
\r
1815 SAFE_RELEASE(pCreateDevEnum);
\r
1816 SAFE_RELEASE(pCGB);
\r
1817 SAFE_RELEASE(pGB);
\r
1819 gettimeofday(&t2, NULL);
\r
1820 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
1821 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
1826 fprintf(stdout, "[Webcam] class enumerator is NULL!!\n");
\r
1827 SAFE_RELEASE(pCreateDevEnum);
\r
1828 SAFE_RELEASE(pCGB);
\r
1829 SAFE_RELEASE(pGB);
\r
1831 gettimeofday(&t2, NULL);
\r
1832 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
1833 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
1836 pEnumMK->lpVtbl->Reset(pEnumMK);
\r
1838 hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL);
\r
1839 if (FAILED(hr) || (hr == S_FALSE)) {
\r
1840 fprintf(stdout, "[Webcam] enum moniker returns a invalid value.\n");
\r
1841 SAFE_RELEASE(pEnumMK);
\r
1842 SAFE_RELEASE(pCreateDevEnum);
\r
1843 SAFE_RELEASE(pCGB);
\r
1844 SAFE_RELEASE(pGB);
\r
1846 gettimeofday(&t2, NULL);
\r
1847 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
1848 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
1852 IPropertyBag *pBag = NULL;
\r
1853 hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0,
\r
1854 &IID_IPropertyBag,
\r
1857 fprintf(stdout, "[Webcam] failed to bind to storage.\n");
\r
1858 SAFE_RELEASE(pEnumMK);
\r
1859 SAFE_RELEASE(pCreateDevEnum);
\r
1860 SAFE_RELEASE(pCGB);
\r
1861 SAFE_RELEASE(pGB);
\r
1863 gettimeofday(&t2, NULL);
\r
1864 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
1865 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
1870 hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);
\r
1874 SysFreeString(var.bstrVal);
\r
1875 SAFE_RELEASE(pBag);
\r
1876 SAFE_RELEASE(pMoniKer);
\r
1877 SAFE_RELEASE(pEnumMK);
\r
1878 SAFE_RELEASE(pCreateDevEnum);
\r
1879 SAFE_RELEASE(pCGB);
\r
1880 SAFE_RELEASE(pGB);
\r
1882 gettimeofday(&t2, NULL);
\r
1883 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
1884 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
1887 device_name = __wchar_to_char(var.bstrVal);
\r
1888 fprintf(stdout, "[Webcam] Device name : %s\n", device_name);
\r
1889 g_free(device_name);
\r
1890 hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL,
\r
1892 (void **)&pSrcFilter);
\r
1895 "[Webcam] Counldn't bind moniker to filter object!!\n");
\r
1896 SysFreeString(var.bstrVal);
\r
1897 SAFE_RELEASE(pBag);
\r
1898 SAFE_RELEASE(pMoniKer);
\r
1899 SAFE_RELEASE(pEnumMK);
\r
1900 SAFE_RELEASE(pCreateDevEnum);
\r
1901 SAFE_RELEASE(pCGB);
\r
1902 SAFE_RELEASE(pGB);
\r
1904 gettimeofday(&t2, NULL);
\r
1905 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
1906 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
1909 pSrcFilter->lpVtbl->AddRef(pSrcFilter);
\r
1911 SysFreeString(var.bstrVal);
\r
1913 SAFE_RELEASE(pBag);
\r
1915 SAFE_RELEASE(pMoniKer);
\r
1917 hr = pGB->lpVtbl->AddFilter(pGB, pSrcFilter, L"Video Capture");
\r
1918 if (hr != S_OK && hr != S_FALSE) {
\r
1920 "[Webcam] Counldn't add Video Capture filter to our graph!\n");
\r
1921 SAFE_RELEASE(pSrcFilter);
\r
1922 SAFE_RELEASE(pEnumMK);
\r
1923 SAFE_RELEASE(pCreateDevEnum);
\r
1924 SAFE_RELEASE(pCGB);
\r
1925 SAFE_RELEASE(pGB);
\r
1927 gettimeofday(&t2, NULL);
\r
1928 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
1929 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
1933 hr = pCGB->lpVtbl->FindInterface(pCGB, &PIN_CATEGORY_CAPTURE, 0,
\r
1934 pSrcFilter, &IID_IAMStreamConfig,
\r
1935 (void **)&pSConfig);
\r
1937 fprintf(stdout, "[Webcam] failed to FindInterface method\n");
\r
1938 SAFE_RELEASE(pSrcFilter);
\r
1939 SAFE_RELEASE(pEnumMK);
\r
1940 SAFE_RELEASE(pCreateDevEnum);
\r
1941 SAFE_RELEASE(pCGB);
\r
1942 SAFE_RELEASE(pGB);
\r
1944 gettimeofday(&t2, NULL);
\r
1945 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
1946 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
1950 hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);
\r
1952 fprintf(stdout, "[Webcam] failed to GetNumberOfCapabilities method\n");
\r
1953 SAFE_RELEASE(pSConfig);
\r
1954 SAFE_RELEASE(pSrcFilter);
\r
1955 SAFE_RELEASE(pEnumMK);
\r
1956 SAFE_RELEASE(pCreateDevEnum);
\r
1957 SAFE_RELEASE(pCGB);
\r
1958 SAFE_RELEASE(pGB);
\r
1960 gettimeofday(&t2, NULL);
\r
1961 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
1962 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
1966 if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
\r
1968 for (iFormat = 0; iFormat < iCount; iFormat++) {
\r
1969 VIDEO_STREAM_CONFIG_CAPS scc;
\r
1970 AM_MEDIA_TYPE *pmtConfig;
\r
1972 hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat, &pmtConfig,
\r
1975 if (IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo)) {
\r
1976 VIDEOINFOHEADER *pvi =
\r
1977 (VIDEOINFOHEADER *)pmtConfig->pbFormat;
\r
1978 if (pvi->bmiHeader.biCompression == BI_RGB) {
\r
1979 fprintf(stdout, "[Webcam] RGB BitCount: %d, %ux%u\n",
\r
1980 pvi->bmiHeader.biBitCount,
\r
1981 pvi->bmiHeader.biWidth,
\r
1982 pvi->bmiHeader.biHeight);
\r
1985 "[Webcam] PixelFormat: %c%c%c%c, %ux%u\n",
\r
1986 (char)(pvi->bmiHeader.biCompression),
\r
1987 (char)(pvi->bmiHeader.biCompression >> 8),
\r
1988 (char)(pvi->bmiHeader.biCompression >> 16),
\r
1989 (char)(pvi->bmiHeader.biCompression >> 24),
\r
1990 pvi->bmiHeader.biWidth,
\r
1991 pvi->bmiHeader.biHeight);
\r
1994 DeleteMediaType(pmtConfig);
\r
1999 hr = pGB->lpVtbl->RemoveFilter(pGB, pSrcFilter);
\r
2001 fprintf(stdout, "[Webcam] Failed to remove source filer. 0x%x\n", hr);
\r
2004 SAFE_RELEASE(pSConfig);
\r
2005 SAFE_RELEASE(pSrcFilter);
\r
2006 SAFE_RELEASE(pCGB);
\r
2007 SAFE_RELEASE(pGB);
\r
2008 SAFE_RELEASE(pEnumMK);
\r
2009 SAFE_RELEASE(pCreateDevEnum);
\r
2011 gettimeofday(&t2, NULL);
\r
2012 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
\r
2013 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
\r
2018 /* MARUCAM_CMD_INIT */
\r
2019 void marucam_device_init(MaruCamState *state)
\r
2024 void marucam_device_exit(MaruCamState *state)
\r
2028 /* MARUCAM_CMD_OPEN */
\r
2029 void marucam_device_open(MaruCamState *state)
\r
2032 uint32_t dwHeight, dwWidth, dwDstFmt;
\r
2033 MaruCamParam *param = state->param;
\r
2036 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
\r
2038 ERR("CoInitailizeEx\n");
\r
2039 ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
\r
2040 param->errCode = EINVAL;
\r
2044 hr = GraphBuilder_Init();
\r
2046 ERR("GraphBuilder_Init\n");
\r
2049 CloseInterfaces();
\r
2051 param->errCode = EINVAL;
\r
2052 ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
\r
2056 hr = BindSourceFilter();
\r
2058 ERR("BindSourceFilter\n");
\r
2061 CloseInterfaces();
\r
2063 param->errCode = EINVAL;
\r
2064 ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
\r
2068 hr = BindTargetFilter();
\r
2070 ERR("BindTargetFilter\n");
\r
2073 CloseInterfaces();
\r
2075 param->errCode = EINVAL;
\r
2076 ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
\r
2080 hr = ConnectFilters();
\r
2082 ERR("ConnectFilters\n");
\r
2085 CloseInterfaces();
\r
2087 param->errCode = EINVAL;
\r
2088 ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
\r
2092 cur_frame_idx = 0;
\r
2095 dwHeight = supported_dst_frames[cur_frame_idx].height;
\r
2096 dwWidth = supported_dst_frames[cur_frame_idx].width;
\r
2097 dwDstFmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
\r
2098 hr = SetFormat(dwWidth, dwHeight, dwDstFmt, &g_dwSrcFmt);
\r
2100 ERR("failed to Set default values\n");
\r
2103 CloseInterfaces();
\r
2105 param->errCode = EINVAL;
\r
2106 ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
\r
2114 /* MARUCAM_CMD_CLOSE */
\r
2115 void marucam_device_close(MaruCamState *state)
\r
2117 MaruCamParam *param = state->param;
\r
2122 CloseInterfaces();
\r
2127 /* MARUCAM_CMD_START_PREVIEW */
\r
2128 void marucam_device_start_preview(MaruCamState *state)
\r
2131 uint32_t pixfmt, width, height;
\r
2132 MaruCamParam *param = state->param;
\r
2136 width = supported_dst_frames[cur_frame_idx].width;
\r
2137 height = supported_dst_frames[cur_frame_idx].height;
\r
2138 pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
\r
2139 state->buf_size = get_sizeimage(pixfmt, width, height);
\r
2141 INFO("Pixfmt(%c%c%c%c), W:H(%d:%d), buf size(%u)\n",
\r
2142 (char)(pixfmt), (char)(pixfmt >> 8),
\r
2143 (char)(pixfmt >> 16), (char)(pixfmt >> 24),
\r
2144 width, height, state->buf_size);
\r
2145 INFO("Starting preview\n");
\r
2147 assert(g_pCallback != NULL);
\r
2148 hr = ((HWCInPin *)g_pInputPin)->SetGrabCallbackIF(g_pInputPin,
\r
2151 ERR("Failed to set IGrabCallback interface.\n");
\r
2152 param->errCode = EINVAL;
\r
2160 grab_buf = (void *)g_malloc0(state->buf_size);
\r
2161 if (grab_buf == NULL) {
\r
2162 param->errCode = ENOMEM;
\r
2166 hr = g_pMediaControl->lpVtbl->Run(g_pMediaControl);
\r
2168 ERR("Failed to run media control. hr=0x%x\n", hr);
\r
2169 param->errCode = EINVAL;
\r
2173 qemu_mutex_lock(&state->thread_mutex);
\r
2174 state->streamon = 1;
\r
2175 qemu_mutex_unlock(&state->thread_mutex);
\r
2177 INFO("Streaming on ......\n");
\r
2180 /* MARUCAM_CMD_STOP_PREVIEW */
\r
2181 void marucam_device_stop_preview(MaruCamState *state)
\r
2184 MaruCamParam *param = state->param;
\r
2187 INFO("...... Streaming off\n");
\r
2188 qemu_mutex_lock(&state->thread_mutex);
\r
2189 state->streamon = 0;
\r
2190 qemu_mutex_unlock(&state->thread_mutex);
\r
2192 hr = ((HWCInPin *)g_pInputPin)->SetGrabCallbackIF(g_pInputPin, NULL);
\r
2194 ERR("Failed to set IGrabCallback interface.\n");
\r
2195 param->errCode = EINVAL;
\r
2199 hr = g_pMediaControl->lpVtbl->Stop(g_pMediaControl);
\r
2201 ERR("Failed to stop media control.\n");
\r
2202 param->errCode = EINVAL;
\r
2210 state->buf_size = 0;
\r
2212 INFO("Stopping preview\n");
\r
2215 /* MARUCAM_CMD_S_PARAM */
\r
2216 void marucam_device_s_param(MaruCamState *state)
\r
2218 MaruCamParam *param = state->param;
\r
2220 /* We use default FPS of the webcam */
\r
2224 /* MARUCAM_CMD_G_PARAM */
\r
2225 void marucam_device_g_param(MaruCamState *state)
\r
2227 MaruCamParam *param = state->param;
\r
2229 /* We use default FPS of the webcam
\r
2230 * return a fixed value on guest ini file (1/30).
\r
2233 param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */
\r
2234 param->stack[1] = 1; /* numerator */
\r
2235 param->stack[2] = 30; /* denominator */
\r
2238 /* MARUCAM_CMD_S_FMT */
\r
2239 void marucam_device_s_fmt(MaruCamState *state)
\r
2241 uint32_t width, height, pixfmt, pidx, fidx;
\r
2242 MaruCamParam *param = state->param;
\r
2245 width = param->stack[0];
\r
2246 height = param->stack[1];
\r
2247 pixfmt = param->stack[2];
\r
2249 for (fidx = 0; fidx < ARRAY_SIZE(supported_dst_frames); fidx++) {
\r
2250 if ((supported_dst_frames[fidx].width == width) &&
\r
2251 (supported_dst_frames[fidx].height == height)) {
\r
2255 if (fidx == ARRAY_SIZE(supported_dst_frames)) {
\r
2256 param->errCode = EINVAL;
\r
2259 for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) {
\r
2260 if (supported_dst_pixfmts[pidx].fmt == pixfmt) {
\r
2264 if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {
\r
2265 param->errCode = EINVAL;
\r
2269 if ((supported_dst_frames[cur_frame_idx].width != width) &&
\r
2270 (supported_dst_frames[cur_frame_idx].height != height)) {
\r
2271 HRESULT hr = SetFormat(width, height, pixfmt, &g_dwSrcFmt);
\r
2273 param->errCode = EINVAL;
\r
2278 cur_frame_idx = fidx;
\r
2279 cur_fmt_idx = pidx;
\r
2281 pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
\r
2282 width = supported_dst_frames[cur_frame_idx].width;
\r
2283 height = supported_dst_frames[cur_frame_idx].height;
\r
2285 param->stack[0] = width;
\r
2286 param->stack[1] = height;
\r
2287 param->stack[2] = 1; /* V4L2_FIELD_NONE */
\r
2288 param->stack[3] = pixfmt;
\r
2289 param->stack[4] = get_bytesperline(pixfmt, width);
\r
2290 param->stack[5] = get_sizeimage(pixfmt, width, height);
\r
2291 param->stack[6] = 0;
\r
2292 param->stack[7] = 0;
\r
2294 TRACE("Set format...\n");
\r
2297 /* MARUCAM_CMD_G_FMT */
\r
2298 void marucam_device_g_fmt(MaruCamState *state)
\r
2300 uint32_t width, height, pixfmt;
\r
2301 MaruCamParam *param = state->param;
\r
2304 pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
\r
2305 width = supported_dst_frames[cur_frame_idx].width;
\r
2306 height = supported_dst_frames[cur_frame_idx].height;
\r
2308 param->stack[0] = width;
\r
2309 param->stack[1] = height;
\r
2310 param->stack[2] = 1; /* V4L2_FIELD_NONE */
\r
2311 param->stack[3] = pixfmt;
\r
2312 param->stack[4] = get_bytesperline(pixfmt, width);
\r
2313 param->stack[5] = get_sizeimage(pixfmt, width, height);
\r
2314 param->stack[6] = 0;
\r
2315 param->stack[7] = 0;
\r
2317 TRACE("Get format...\n");
\r
2320 void marucam_device_try_fmt(MaruCamState *state)
\r
2322 uint32_t width, height, pixfmt, i;
\r
2323 MaruCamParam *param = state->param;
\r
2326 width = param->stack[0];
\r
2327 height = param->stack[1];
\r
2328 pixfmt = param->stack[2];
\r
2330 for (i = 0; i < ARRAY_SIZE(supported_dst_frames); i++) {
\r
2331 if ((supported_dst_frames[i].width == width) &&
\r
2332 (supported_dst_frames[i].height == height)) {
\r
2336 if (i == ARRAY_SIZE(supported_dst_frames)) {
\r
2337 param->errCode = EINVAL;
\r
2340 for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
\r
2341 if (supported_dst_pixfmts[i].fmt == pixfmt) {
\r
2345 if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
\r
2346 param->errCode = EINVAL;
\r
2350 param->stack[0] = width;
\r
2351 param->stack[1] = height;
\r
2352 param->stack[2] = 1; /* V4L2_FIELD_NONE */
\r
2353 param->stack[3] = pixfmt;
\r
2354 param->stack[4] = get_bytesperline(pixfmt, width);
\r
2355 param->stack[5] = get_sizeimage(pixfmt, width, height);
\r
2356 param->stack[6] = 0;
\r
2357 param->stack[7] = 0;
\r
2360 void marucam_device_enum_fmt(MaruCamState *state)
\r
2363 MaruCamParam *param = state->param;
\r
2366 index = param->stack[0];
\r
2368 if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
\r
2369 param->errCode = EINVAL;
\r
2372 param->stack[1] = 0; /* flags = NONE */
\r
2373 param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */
\r
2374 /* set description */
\r
2375 switch (supported_dst_pixfmts[index].fmt) {
\r
2376 case V4L2_PIX_FMT_YUYV:
\r
2377 memcpy(¶m->stack[3], "YUYV", 32);
\r
2379 case V4L2_PIX_FMT_YUV420:
\r
2380 memcpy(¶m->stack[3], "YU12", 32);
\r
2382 case V4L2_PIX_FMT_YVU420:
\r
2383 memcpy(¶m->stack[3], "YV12", 32);
\r
2386 ERR("Invalid pixel format\n");
\r
2387 param->errCode = EINVAL;
\r
2392 void marucam_device_qctrl(MaruCamState *state)
\r
2396 long property, min, max, step, def_val, set_val;
\r
2397 char name[32] = {0,};
\r
2398 MaruCamParam *param = state->param;
\r
2401 id = param->stack[0];
\r
2404 case V4L2_CID_BRIGHTNESS:
\r
2405 TRACE("V4L2_CID_BRIGHTNESS\n");
\r
2406 property = VideoProcAmp_Brightness;
\r
2407 memcpy((void *)name, (void *)"brightness", 32);
\r
2410 case V4L2_CID_CONTRAST:
\r
2411 TRACE("V4L2_CID_CONTRAST\n");
\r
2412 property = VideoProcAmp_Contrast;
\r
2413 memcpy((void *)name, (void *)"contrast", 32);
\r
2416 case V4L2_CID_SATURATION:
\r
2417 TRACE("V4L2_CID_SATURATION\n");
\r
2418 property = VideoProcAmp_Saturation;
\r
2419 memcpy((void *)name, (void *)"saturation", 32);
\r
2422 case V4L2_CID_SHARPNESS:
\r
2423 TRACE("V4L2_CID_SHARPNESS\n");
\r
2424 property = VideoProcAmp_Sharpness;
\r
2425 memcpy((void *)name, (void *)"sharpness", 32);
\r
2429 ERR("Invalid control ID\n");
\r
2430 param->errCode = EINVAL;
\r
2433 hr = QueryVideoProcAmp(property, &min, &max, &step, &def_val);
\r
2435 param->errCode = EINVAL;
\r
2436 ERR("failed to query video controls [HRESULT : 0x%x]\n", hr);
\r
2439 qctrl_tbl[i].hit = 1;
\r
2440 qctrl_tbl[i].min = min;
\r
2441 qctrl_tbl[i].max = max;
\r
2442 qctrl_tbl[i].step = step;
\r
2443 qctrl_tbl[i].init_val = def_val;
\r
2445 if ((qctrl_tbl[i].min + qctrl_tbl[i].max) == 0) {
\r
2448 set_val = (qctrl_tbl[i].min + qctrl_tbl[i].max) / 2;
\r
2450 hr = SetVideoProcAmp(property, set_val);
\r
2452 param->errCode = EINVAL;
\r
2453 ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
\r
2458 param->stack[0] = id;
\r
2459 param->stack[1] = MARUCAM_CTRL_VALUE_MIN; /* minimum */
\r
2460 param->stack[2] = MARUCAM_CTRL_VALUE_MAX; /* maximum */
\r
2461 param->stack[3] = MARUCAM_CTRL_VALUE_STEP; /* step */
\r
2462 param->stack[4] = MARUCAM_CTRL_VALUE_MID; /* default_value */
\r
2463 param->stack[5] = V4L2_CTRL_FLAG_SLIDER;
\r
2464 /* name field setting */
\r
2465 memcpy(¶m->stack[6], (void *)name, sizeof(name)/sizeof(name[0]));
\r
2468 void marucam_device_s_ctrl(MaruCamState *state)
\r
2472 long property, set_val;
\r
2473 MaruCamParam *param = state->param;
\r
2477 switch (param->stack[0]) {
\r
2478 case V4L2_CID_BRIGHTNESS:
\r
2480 property = VideoProcAmp_Brightness;
\r
2482 case V4L2_CID_CONTRAST:
\r
2484 property = VideoProcAmp_Contrast;
\r
2486 case V4L2_CID_SATURATION:
\r
2488 property = VideoProcAmp_Saturation;
\r
2490 case V4L2_CID_SHARPNESS:
\r
2492 property = VideoProcAmp_Sharpness;
\r
2495 param->errCode = EINVAL;
\r
2498 set_val = value_convert_from_guest(qctrl_tbl[i].min,
\r
2499 qctrl_tbl[i].max, (long)param->stack[1]);
\r
2500 hr = SetVideoProcAmp(property, set_val);
\r
2502 param->errCode = EINVAL;
\r
2503 ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
\r
2508 void marucam_device_g_ctrl(MaruCamState *state)
\r
2512 long property, get_val;
\r
2513 MaruCamParam *param = state->param;
\r
2516 switch (param->stack[0]) {
\r
2517 case V4L2_CID_BRIGHTNESS:
\r
2519 property = VideoProcAmp_Brightness;
\r
2521 case V4L2_CID_CONTRAST:
\r
2523 property = VideoProcAmp_Contrast;
\r
2525 case V4L2_CID_SATURATION:
\r
2527 property = VideoProcAmp_Saturation;
\r
2529 case V4L2_CID_SHARPNESS:
\r
2531 property = VideoProcAmp_Sharpness;
\r
2534 param->errCode = EINVAL;
\r
2538 hr = GetVideoProcAmp(property, &get_val);
\r
2540 param->errCode = EINVAL;
\r
2541 ERR("failed to get video control value!!!, [HRESULT : 0x%x]\n", hr);
\r
2544 param->stack[0] = (uint32_t)value_convert_to_guest(qctrl_tbl[i].min,
\r
2545 qctrl_tbl[i].max, get_val);
\r
2548 void marucam_device_enum_fsizes(MaruCamState *state)
\r
2550 uint32_t index, pixfmt, i;
\r
2551 MaruCamParam *param = state->param;
\r
2554 index = param->stack[0];
\r
2555 pixfmt = param->stack[1];
\r
2557 if (index >= ARRAY_SIZE(supported_dst_frames)) {
\r
2558 param->errCode = EINVAL;
\r
2561 for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
\r
2562 if (supported_dst_pixfmts[i].fmt == pixfmt) {
\r
2567 if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
\r
2568 param->errCode = EINVAL;
\r
2572 param->stack[0] = supported_dst_frames[index].width;
\r
2573 param->stack[1] = supported_dst_frames[index].height;
\r
2576 void marucam_device_enum_fintv(MaruCamState *state)
\r
2578 MaruCamParam *param = state->param;
\r
2582 /* switch by index(param->stack[0]) */
\r
2583 switch (param->stack[0]) {
\r
2585 param->stack[1] = 30; /* denominator */
\r
2588 param->errCode = EINVAL;
\r
2591 param->stack[0] = 1; /* numerator */
\r
2594 void yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
\r
2595 uint32_t width, uint32_t height, uint32_t yvu)
\r
2598 const unsigned char *src1;
\r
2599 unsigned char *udest, *vdest;
\r
2601 /* copy the Y values */
\r
2603 for (i = 0; i < height; i++) {
\r
2604 for (j = 0; j < width; j += 2) {
\r
2605 *dest++ = src1[0];
\r
2606 *dest++ = src1[2];
\r
2611 /* copy the U and V values */
\r
2612 src++; /* point to V */
\r
2613 src1 = src + width * 2; /* next line */
\r
2616 udest = dest + width * height / 4;
\r
2619 vdest = dest + width * height / 4;
\r
2621 for (i = 0; i < height; i += 2) {
\r
2622 for (j = 0; j < width; j += 2) {
\r
2623 *udest++ = ((int) src[0] + src1[0]) / 2; /* U */
\r
2624 *vdest++ = ((int) src[2] + src1[2]) / 2; /* V */
\r
2629 src1 += width * 2;
\r
2633 #define RGB2Y(r, g, b, y) \
\r
2634 (y) = ((8453 * (r) + 16594 * (g) + 3223 * (b) + 524288) >> 15)
\r
2636 #define RGB2UV(r, g, b, u, v) \
\r
2638 (u) = ((-4878 * (r) - 9578 * (g) + 14456 * (b) + 4210688) >> 15); \
\r
2639 (v) = ((14456 * (r) - 12105 * (g) - 2351 * (b) + 4210688) >> 15); \
\r
2642 #define CLIP(color) \
\r
2643 (unsigned char)(((color) > 0xFF) ? 0xff : (((color) < 0) ? 0 : (color)))
\r
2645 void rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,
\r
2646 uint32_t width, uint32_t height, uint32_t yvu)
\r
2649 unsigned char *udest, *vdest;
\r
2650 uint32_t bytesperline = width * 3;
\r
2653 for (y = 0; y < height; y++) {
\r
2654 for (x = 0; x < width; x++) {
\r
2655 RGB2Y(src[2], src[1], src[0], *dest++);
\r
2658 src += bytesperline - 3 * width;
\r
2660 src -= height * bytesperline;
\r
2665 udest = dest + width * height / 4;
\r
2668 vdest = dest + width * height / 4;
\r
2671 for (y = 0; y < height / 2; y++) {
\r
2672 for (x = 0; x < width / 2; x++) {
\r
2673 uint32_t avg_src[3];
\r
2675 avg_src[0] = (src[0] + src[3] + src[bytesperline] +
\r
2676 src[bytesperline + 3]) / 4;
\r
2677 avg_src[1] = (src[1] + src[4] + src[bytesperline + 1] +
\r
2678 src[bytesperline + 4]) / 4;
\r
2679 avg_src[2] = (src[2] + src[5] + src[bytesperline + 2] +
\r
2680 src[bytesperline + 5]) / 4;
\r
2681 RGB2UV(avg_src[2], avg_src[1], avg_src[0], *udest++, *vdest++);
\r
2684 src += 2 * bytesperline - 3 * width;
\r
2688 void rgb24_to_yuyv(unsigned char *src, unsigned char *dest,
\r
2689 uint32_t width, uint32_t height)
\r
2693 for (i = 0; i < (width * height * 3); i = i + 6) {
\r
2695 *dest++ = CLIP(0.299 * (src[i + 2] - 128) +
\r
2696 0.587 * (src[i + 1] - 128) +
\r
2697 0.114 * (src[i] - 128) + 128);
\r
2699 *dest++ = CLIP(((-0.147 * (src[i + 2] - 128) -
\r
2700 0.289 * (src[i + 1] - 128) +
\r
2701 0.436 * (src[i] - 128) + 128) +
\r
2702 (-0.147 * (src[i + 5] - 128) -
\r
2703 0.289 * (src[i + 4] - 128) +
\r
2704 0.436 * (src[i + 3] - 128) + 128)) / 2);
\r
2706 *dest++ = CLIP(0.299 * (src[i + 5] - 128) +
\r
2707 0.587 * (src[i + 4] - 128) +
\r
2708 0.114 * (src[i + 3] - 128) + 128);
\r
2710 *dest++ = CLIP(((0.615 * (src[i + 2] - 128) -
\r
2711 0.515 * (src[i + 1] - 128) -
\r
2712 0.100 * (src[i] - 128) + 128) +
\r
2713 (0.615 * (src[i + 5] - 128) -
\r
2714 0.515 * (src[i + 4] - 128) -
\r
2715 0.100 * (src[i + 3] - 128) + 128)) / 2);
\r
2719 void yuv420_to_yvu420(unsigned char *src, unsigned char *dest,
\r
2720 uint32_t width, uint32_t height)
\r
2722 unsigned char *psrc_y, *pdst_y;
\r
2723 unsigned char *psrc_u, *pdst_u;
\r
2724 unsigned char *psrc_v, *pdst_v;
\r
2727 psrc_u = psrc_y + (width * height);
\r
2728 psrc_v = psrc_u + (width * height / 4);
\r
2731 pdst_v = pdst_y + (width * height);
\r
2732 pdst_u = pdst_v + (width * height / 4);
\r
2734 memcpy(pdst_y, psrc_y, width * height);
\r
2735 memcpy(pdst_v, psrc_v, width * height / 4);
\r
2736 memcpy(pdst_u, psrc_u, width * height / 4);
\r
2739 void yuv420_to_yuyv(unsigned char *src, unsigned char *dest,
\r
2740 uint32_t width, uint32_t height)
\r
2742 unsigned char *py;
\r
2743 unsigned char *pu;
\r
2744 unsigned char *pv;
\r
2746 uint32_t linesize = width * 2;
\r
2747 uint32_t uvlinesize = width / 2;
\r
2748 uint32_t offset = 0;
\r
2749 uint32_t offset1 = 0;
\r
2750 uint32_t offsety = 0;
\r
2751 uint32_t offsety1 = 0;
\r
2752 uint32_t offsetuv = 0;
\r
2760 pu = py + (width * height);
\r
2761 pv = pu + (width * height / 4);
\r
2763 for (h = 0; h < height; h += 2) {
\r
2766 offset = h * linesize;
\r
2767 offset1 = (h + 1) * linesize;
\r
2768 offsety = h * width;
\r
2769 offsety1 = (h + 1) * width;
\r
2770 offsetuv = huv * uvlinesize;
\r
2772 for (w = 0; w < linesize; w += 4) {
\r
2774 dest[w + offset] = py[wy + offsety];
\r
2776 dest[(w + 1) + offset] = pu[wuv + offsetuv];
\r
2778 dest[(w + 2) + offset] = py[(wy + 1) + offsety];
\r
2780 dest[(w + 3) + offset] = pv[wuv + offsetuv];
\r
2783 dest[w + offset1] = py[wy + offsety1];
\r
2785 dest[(w + 1) + offset1] = pu[wuv + offsetuv];
\r
2787 dest[(w + 2) + offset1] = py[(wy + 1) + offsety1];
\r
2789 dest[(w + 3) + offset1] = pv[wuv + offsetuv];
\r