update source for tizen_2.1
[sdk/emulator/qemu.git] / tizen / src / hw / maru_camera_win32_pci.c
index 312f86a..f2a0445 100644 (file)
-/*\r
- * Implementation of MARU Virtual Camera device by PCI bus on Windows.\r
- *\r
- * Copyright (c) 2011 - 2012 Samsung Electronics Co., Ltd All Rights Reserved\r
- *\r
- * Contact:\r
- * JinHyung Jo <jinhyung.jo@samsung.com>\r
- * YeongKyoon Lee <yeongkyoon.lee@samsung.com>\r
- *\r
- * This program is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU General Public License\r
- * as published by the Free Software Foundation; either version 2\r
- * of the License, or (at your option) any later version.\r
- *\r
- * This program is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
- * GNU General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU General Public License\r
- * along with this program; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.\r
- *\r
- * Contributors:\r
- * - S-Core Co., Ltd\r
- *\r
- */\r
-\r
-\r
-#include "qemu-common.h"\r
-#include "maru_camera_common.h"\r
-#include "tizen/src/debug_ch.h"\r
-\r
-#define CINTERFACE\r
-#define COBJMACROS\r
-#include "ocidl.h"\r
-#include "errors.h"      /* for VFW_E_XXXX */\r
-#include "mmsystem.h"    /* for MAKEFOURCC macro */\r
-#include "maru_camera_win32_interface.h"\r
-\r
-MULTI_DEBUG_CHANNEL(tizen, camera_win32);\r
-\r
-extern int hax_enabled(void);\r
-\r
-/*\r
- * COM Interface implementations\r
- *\r
- */\r
-\r
-#define SAFE_RELEASE(x) \\r
-    do { \\r
-        if (x) { \\r
-            (x)->lpVtbl->Release(x); \\r
-            x = NULL; \\r
-        } \\r
-    } while (0)\r
-\r
-typedef HRESULT (STDAPICALLTYPE *CallbackFn)(ULONG dwSize, BYTE *pBuffer);\r
-\r
-/*\r
- * HWCGrabCallback\r
- */\r
-\r
-typedef struct HWCGrabCallback {\r
-    IGrabCallback IGrabCallback_iface;\r
-    long m_cRef;\r
-    CallbackFn m_pCallback;\r
-    STDMETHODIMP (*SetCallback)(IGrabCallback *iface, CallbackFn pCallbackFn);\r
-} HWCGrabCallback;\r
-\r
-static inline HWCGrabCallback *impl_from_IGrabCallback(IGrabCallback *iface)\r
-{\r
-    return CONTAINING_RECORD(iface, HWCGrabCallback, IGrabCallback_iface);\r
-}\r
-\r
-static STDMETHODIMP HWCGrabCallback_QueryInterface(IGrabCallback *iface,\r
-                                                   REFIID riid, void **ppv)\r
-{\r
-    if (IsEqualIID(riid, &IID_IUnknown)) {\r
-        *ppv = (IUnknown *)iface;\r
-    } else if (IsEqualIID(riid, &IID_IGrabCallback)) {\r
-        *ppv = (IGrabCallback *)iface;\r
-    } else {\r
-        *ppv = NULL;\r
-        return E_NOINTERFACE;\r
-    }\r
-\r
-    IGrabCallback_AddRef(iface);\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP_(ULONG) HWCGrabCallback_AddRef(IGrabCallback *iface)\r
-{\r
-    HWCGrabCallback *This = impl_from_IGrabCallback(iface);\r
-\r
-    return InterlockedIncrement(&This->m_cRef);\r
-}\r
-\r
-static STDMETHODIMP_(ULONG) HWCGrabCallback_Release(IGrabCallback *iface)\r
-{\r
-    HWCGrabCallback *This = impl_from_IGrabCallback(iface);\r
-\r
-    if (InterlockedDecrement(&This->m_cRef) == 0) {\r
-        This->m_pCallback = NULL;\r
-        g_free((void *)This);\r
-        This = NULL;\r
-        return 0;\r
-    }\r
-\r
-    return This->m_cRef;\r
-}\r
-\r
-static STDMETHODIMP HWCGrabCallback_Grab(IGrabCallback *iface,\r
-                                         ULONG dwSize, BYTE *pBuffer)\r
-{\r
-    HWCGrabCallback *This = impl_from_IGrabCallback(iface);\r
-\r
-    if (This->m_pCallback) {\r
-        HRESULT hr = This->m_pCallback(dwSize, pBuffer);\r
-        if (FAILED(hr)) {\r
-            return E_FAIL;\r
-        } else {\r
-            return S_OK;\r
-        }\r
-    }\r
-\r
-    return E_FAIL;\r
-}\r
-\r
-static STDMETHODIMP HWCGrabCallback_SetCallback(IGrabCallback *iface,\r
-                                                CallbackFn pCallbackFn)\r
-{\r
-    HWCGrabCallback *This = impl_from_IGrabCallback(iface);\r
-\r
-    This->m_pCallback = pCallbackFn;\r
-    return S_OK;\r
-}\r
-\r
-static IGrabCallbackVtbl HWCGrabCallback_Vtbl = {\r
-        HWCGrabCallback_QueryInterface,\r
-        HWCGrabCallback_AddRef,\r
-        HWCGrabCallback_Release,\r
-        HWCGrabCallback_Grab\r
-};\r
-\r
-static STDMETHODIMP HWCGrabCallback_Construct(IGrabCallback **ppv)\r
-{\r
-    HWCGrabCallback *This =\r
-            (HWCGrabCallback *)g_malloc0(sizeof(HWCGrabCallback));\r
-\r
-    if (!This) {\r
-        ERR("failed to HWCGrabCallback_Construct, E_OUTOFMEMORY\n");\r
-        return E_OUTOFMEMORY;\r
-    }\r
-\r
-    This->IGrabCallback_iface.lpVtbl = &HWCGrabCallback_Vtbl;\r
-    This->m_cRef = 1;\r
-    This->m_pCallback = NULL;\r
-    This->SetCallback = HWCGrabCallback_SetCallback;\r
-    *ppv = &This->IGrabCallback_iface;\r
-    return S_OK;\r
-}\r
-\r
-/*\r
- * HWCPin\r
- */\r
-\r
-typedef struct HWCInPin {\r
-    IPin IPin_iface;\r
-    IMemInputPin IMemInputPin_iface;\r
-    IBaseFilter *m_pCFilter;\r
-    IPin *m_pConnectedPin;\r
-    IGrabCallback *m_pCallback;\r
-    IMemAllocator *m_pAllocator;\r
-    BOOL m_bReadOnly;\r
-    long m_cRef;\r
-    STDMETHODIMP (*SetGrabCallbackIF)(IPin *iface, IGrabCallback *pCaptureCB);\r
-} HWCInPin;\r
-\r
-static inline HWCInPin *impl_from_IPin(IPin *iface)\r
-{\r
-    return CONTAINING_RECORD(iface, HWCInPin, IPin_iface);\r
-}\r
-\r
-static inline HWCInPin *impl_from_IMemInputPin(IMemInputPin *iface)\r
-{\r
-    return CONTAINING_RECORD(iface, HWCInPin, IMemInputPin_iface);\r
-}\r
-\r
-static STDMETHODIMP HWCPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)\r
-{\r
-    HWCInPin *This = impl_from_IPin(iface);\r
-\r
-    if (IsEqualIID(riid, &IID_IUnknown)) {\r
-        *ppv = (IUnknown *)(&This->IPin_iface);\r
-        IPin_AddRef((IPin *)*ppv);\r
-    } else if (IsEqualIID(riid, &IID_IPin)) {\r
-        *ppv = (IPin *)(&This->IPin_iface);\r
-        IPin_AddRef((IPin *)*ppv);\r
-    } else if (IsEqualIID(riid, &IID_IMemInputPin)) {\r
-        *ppv = (IMemInputPin *)(&This->IMemInputPin_iface);\r
-        IPin_AddRef((IMemInputPin *)*ppv);\r
-    } else {\r
-        *ppv = NULL;\r
-        return E_NOINTERFACE;\r
-    }\r
-\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP_(ULONG) HWCPin_AddRef(IPin *iface)\r
-{\r
-    HWCInPin *This = impl_from_IPin(iface);\r
-\r
-    return InterlockedIncrement(&This->m_cRef);\r
-}\r
-\r
-static STDMETHODIMP_(ULONG) HWCPin_Release(IPin *iface)\r
-{\r
-    HWCInPin *This = impl_from_IPin(iface);\r
-\r
-    if (InterlockedDecrement(&This->m_cRef) == 0) {\r
-        if (This->m_pCallback) {\r
-            SAFE_RELEASE(This->m_pCallback);\r
-        }\r
-        if (This->m_pConnectedPin) {\r
-            SAFE_RELEASE(This->m_pConnectedPin);\r
-        }\r
-        if (This->m_pAllocator) {\r
-            IMemAllocator_Decommit(This->m_pAllocator);\r
-            SAFE_RELEASE(This->m_pAllocator);\r
-        }\r
-        g_free((void *)This);\r
-        This = NULL;\r
-        return 0;\r
-    }\r
-    return This->m_cRef;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_Connect(IPin *iface,\r
-                                   IPin *pReceivePin,\r
-                                   const AM_MEDIA_TYPE *pmt)\r
-{\r
-    HWCInPin *This = impl_from_IPin(iface);\r
-\r
-    if (!pReceivePin) {\r
-        return E_POINTER;\r
-    }\r
-\r
-    if (This->m_pConnectedPin) {\r
-        return VFW_E_ALREADY_CONNECTED;\r
-    }\r
-\r
-    if (!pmt) {\r
-        return S_OK;\r
-    }\r
-    return S_FALSE;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_ReceiveConnection(IPin *iface, IPin *pConnector,\r
-                                             const AM_MEDIA_TYPE *pmt)\r
-{\r
-    PIN_DIRECTION pd;\r
-    FILTER_STATE fs;\r
-    HWCInPin *This = impl_from_IPin(iface);\r
-\r
-    if (pConnector == NULL || pmt == NULL) {\r
-        return E_POINTER;\r
-    }\r
-\r
-    if (This->m_pConnectedPin) {\r
-        return VFW_E_ALREADY_CONNECTED;\r
-    }\r
-    IBaseFilter_GetState(This->m_pCFilter, 0, &fs);\r
-    if (fs != State_Stopped) {\r
-        return VFW_E_NOT_STOPPED;\r
-    }\r
-    IPin_QueryDirection(pConnector, &pd);\r
-    if (pd == PINDIR_INPUT) {\r
-        return VFW_E_INVALID_DIRECTION;\r
-    }\r
-\r
-    This->m_pConnectedPin = pConnector;\r
-    IPin_AddRef(This->m_pConnectedPin);\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_Disconnect(IPin *iface)\r
-{\r
-    HWCInPin *This = impl_from_IPin(iface);\r
-\r
-    HRESULT hr;\r
-    FILTER_STATE fs;\r
-    IBaseFilter_GetState(This->m_pCFilter, 0, &fs);\r
-    if (fs != State_Stopped) {\r
-        return VFW_E_NOT_STOPPED;\r
-    }\r
-    if (This->m_pConnectedPin == NULL) {\r
-        hr = S_FALSE;\r
-    } else {\r
-        if (This->m_pAllocator) {\r
-            hr = IMemAllocator_Decommit(This->m_pAllocator);\r
-            if (FAILED(hr)) {\r
-                return hr;\r
-            }\r
-            SAFE_RELEASE(This->m_pAllocator);\r
-        }\r
-        SAFE_RELEASE(This->m_pConnectedPin);\r
-        hr = S_OK;\r
-    }\r
-    return hr;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_ConnectedTo(IPin *iface, IPin **ppPin)\r
-{\r
-    HWCInPin *This = impl_from_IPin(iface);\r
-\r
-    if (ppPin == NULL) {\r
-        return E_POINTER;\r
-    }\r
-\r
-    if (This->m_pConnectedPin == NULL) {\r
-        *ppPin = NULL;\r
-        return VFW_E_NOT_CONNECTED;\r
-    } else {\r
-        *ppPin = This->m_pConnectedPin;\r
-        IPin_AddRef(This->m_pConnectedPin);\r
-    }\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)\r
-{\r
-    if (pmt == NULL) {\r
-        return E_POINTER;\r
-    }\r
-    return VFW_E_NOT_CONNECTED;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_QueryPinInfo(IPin *iface, PIN_INFO *pInfo)\r
-{\r
-    HWCInPin *This = impl_from_IPin(iface);\r
-\r
-    if (pInfo == NULL) {\r
-        return E_POINTER;\r
-    }\r
-\r
-    pInfo->pFilter = This->m_pCFilter;\r
-    if (This->m_pCFilter) {\r
-        IBaseFilter_AddRef(This->m_pCFilter);\r
-    }\r
-    memcpy((void *)pInfo->achName, (void *)HWCPinName, sizeof(HWCPinName));\r
-    pInfo->dir = PINDIR_INPUT;\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir)\r
-{\r
-    if (pPinDir == NULL) {\r
-        return E_POINTER;\r
-    }\r
-    *pPinDir = PINDIR_INPUT;\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_QueryId(IPin *iface, LPWSTR *Id)\r
-{\r
-    PVOID pId;\r
-    if (Id == NULL) {\r
-        return E_POINTER;\r
-    }\r
-    pId = CoTaskMemAlloc(sizeof(HWCPinName));\r
-    memcpy((void *)pId, (void *)HWCPinName, sizeof(HWCPinName));\r
-    *Id = (LPWSTR)pId;\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)\r
-{\r
-    if (pmt == NULL) {\r
-        return E_POINTER;\r
-    }\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_EnumMediaTypes(IPin *iface,\r
-                                          IEnumMediaTypes **ppEnum)\r
-{\r
-    if (ppEnum == NULL) {\r
-            return E_POINTER;\r
-    }\r
-    return E_NOTIMPL;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_QueryInternalConnections(IPin *iface,\r
-                                                    IPin **ppPin,\r
-                                                    ULONG *nPin)\r
-{\r
-    return E_NOTIMPL;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_EndOfStream(IPin *iface)\r
-{\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_BeginFlush(IPin *iface)\r
-{\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_EndFlush(IPin *iface)\r
-{\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_NewSegment(IPin *iface, REFERENCE_TIME tStart,\r
-                                      REFERENCE_TIME tStop, double dRate)\r
-{\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCMemInputPin_QueryInterface(IMemInputPin *iface,\r
-                                                  REFIID riid, void **ppv)\r
-{\r
-    HWCInPin *This = impl_from_IMemInputPin(iface);\r
-\r
-    if (IsEqualIID(riid, &IID_IUnknown)) {\r
-        *ppv = (IUnknown *)(&This->IMemInputPin_iface);\r
-        IPin_AddRef((IPin *)*ppv);\r
-    } else if (IsEqualIID(riid, &IID_IPin)) {\r
-        *ppv = (IPin *)(&This->IPin_iface);\r
-        IPin_AddRef((IPin *)*ppv);\r
-    } else if (IsEqualIID(riid, &IID_IMemInputPin)) {\r
-        *ppv = (IMemInputPin *)(&This->IMemInputPin_iface);\r
-        IPin_AddRef((IMemInputPin *)*ppv);\r
-    } else {\r
-        *ppv = NULL;\r
-        return E_NOINTERFACE;\r
-    }\r
-\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP_(ULONG) HWCMemInputPin_AddRef(IMemInputPin *iface)\r
-{\r
-    HWCInPin *This = impl_from_IMemInputPin(iface);\r
-\r
-    return InterlockedIncrement(&This->m_cRef);\r
-}\r
-\r
-static STDMETHODIMP_(ULONG) HWCMemInputPin_Release(IMemInputPin *iface)\r
-{\r
-    HWCInPin *This = impl_from_IMemInputPin(iface);\r
-\r
-    if (InterlockedDecrement(&This->m_cRef) == 0) {\r
-        if (This->m_pCallback) {\r
-            SAFE_RELEASE(This->m_pCallback);\r
-        }\r
-        if (This->m_pConnectedPin) {\r
-            SAFE_RELEASE(This->m_pConnectedPin);\r
-        }\r
-        if (This->m_pAllocator) {\r
-            IMemAllocator_Decommit(This->m_pAllocator);\r
-            SAFE_RELEASE(This->m_pAllocator);\r
-        }\r
-        g_free((void *)This);\r
-        This = NULL;\r
-        return 0;\r
-    }\r
-    return This->m_cRef;\r
-}\r
-\r
-static STDMETHODIMP HWCMemInputPin_GetAllocator(IMemInputPin *iface,\r
-                                                IMemAllocator **ppAllocator)\r
-{\r
-    HWCInPin *This = impl_from_IMemInputPin(iface);\r
-\r
-    if (ppAllocator == NULL) {\r
-        return E_POINTER;\r
-    }\r
-\r
-    if (This->m_pAllocator == NULL) {\r
-        HRESULT hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL,\r
-                                        CLSCTX_INPROC_SERVER,\r
-                                        &IID_IMemAllocator,\r
-                                        (void **)&(This->m_pAllocator));\r
-        if (FAILED(hr)) {\r
-            ERR("Failed to CoCreateInstance for retrieving MemoryAllocator\n");\r
-            return hr;\r
-        }\r
-    }\r
-    ASSERT(This->m_pAllocator != NULL);\r
-    *ppAllocator = This->m_pAllocator;\r
-    IMemAllocator_AddRef(This->m_pAllocator);\r
-\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCMemInputPin_NotifyAllocator(IMemInputPin *iface,\r
-                                                   IMemAllocator *pAllocator,\r
-                                                   BOOL bReadOnly)\r
-{\r
-    HWCInPin *This = impl_from_IMemInputPin(iface);\r
-\r
-    if (pAllocator == NULL) {\r
-        return E_POINTER;\r
-    }\r
-\r
-    IMemAllocator *pOldAllocator = This->m_pAllocator;\r
-    IMemAllocator_AddRef(pAllocator);\r
-    This->m_pAllocator = pAllocator;\r
-\r
-    if (pOldAllocator != NULL) {\r
-        SAFE_RELEASE(pOldAllocator);\r
-    }\r
-\r
-    This->m_bReadOnly = bReadOnly;\r
-\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCMemInputPin_GetAllocatorRequirements(\r
-                                   IMemInputPin *iface,\r
-                                   ALLOCATOR_PROPERTIES *pProps)\r
-{\r
-    return E_NOTIMPL;\r
-}\r
-\r
-static STDMETHODIMP HWCMemInputPin_Receive(IMemInputPin *iface,\r
-                                           IMediaSample *pSample)\r
-{\r
-    HWCInPin *This = impl_from_IMemInputPin(iface);\r
-\r
-    if (pSample == NULL) {\r
-        ERR("pSample is NULL\n");\r
-        return E_POINTER;\r
-    }\r
-    if (This->m_pCallback != NULL) {\r
-        HRESULT hr;\r
-        BYTE *pBuffer = NULL;\r
-        DWORD dwSize = 0;\r
-        dwSize = IMediaSample_GetSize(pSample);\r
-        hr = IMediaSample_GetPointer(pSample, &pBuffer);\r
-        if (FAILED(hr)) {\r
-            ERR("Receive function : "\r
-                "failed to IMediaSample_GetPointer, 0x%ld\n", hr);\r
-            return hr;\r
-        }\r
-        hr = IGrabCallback_Grab(This->m_pCallback, dwSize, pBuffer);\r
-        if (FAILED(hr)) {\r
-            ERR("Receive function : failed to IGrabCallback_Grab, 0x%ld\n",\r
-                hr);\r
-            return hr;\r
-        }\r
-    }\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCMemInputPin_ReceiveMultiple(IMemInputPin *iface,\r
-                                                   IMediaSample **pSamples,\r
-                                                   long nSamples,\r
-                                                   long *nSamplesProcessed)\r
-{\r
-    HRESULT hr = S_OK;\r
-\r
-    if (pSamples == NULL) {\r
-        return E_POINTER;\r
-    }\r
-\r
-    *nSamplesProcessed = 0;\r
-\r
-    while (nSamples-- > 0) {\r
-        hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);\r
-        if (hr != S_OK) {\r
-            break;\r
-        }\r
-        (*nSamplesProcessed)++;\r
-    }\r
-    return hr;\r
-}\r
-\r
-static STDMETHODIMP HWCMemInputPin_ReceiveCanBlock(IMemInputPin *iface)\r
-{\r
-    return S_FALSE;\r
-}\r
-\r
-static STDMETHODIMP HWCPin_SetCallback(IPin *iface, IGrabCallback *pCaptureCB)\r
-{\r
-    HWCInPin *This = impl_from_IPin(iface);\r
-\r
-    if (pCaptureCB == NULL) {\r
-        SAFE_RELEASE(This->m_pCallback);\r
-    } else {\r
-        This->m_pCallback = pCaptureCB;\r
-        IGrabCallback_AddRef(This->m_pCallback);\r
-    }\r
-\r
-    return S_OK;\r
-}\r
-\r
-\r
-static IPinVtbl HWCPin_Vtbl = {\r
-    HWCPin_QueryInterface,\r
-    HWCPin_AddRef,\r
-    HWCPin_Release,\r
-    HWCPin_Connect,\r
-    HWCPin_ReceiveConnection,\r
-    HWCPin_Disconnect,\r
-    HWCPin_ConnectedTo,\r
-    HWCPin_ConnectionMediaType,\r
-    HWCPin_QueryPinInfo,\r
-    HWCPin_QueryDirection,\r
-    HWCPin_QueryId,\r
-    HWCPin_QueryAccept,\r
-    HWCPin_EnumMediaTypes,\r
-    HWCPin_QueryInternalConnections,\r
-    HWCPin_EndOfStream,\r
-    HWCPin_BeginFlush,\r
-    HWCPin_EndFlush,\r
-    HWCPin_NewSegment\r
-};\r
-\r
-static IMemInputPinVtbl HWCMemInputPin_Vtbl = {\r
-    HWCMemInputPin_QueryInterface,\r
-    HWCMemInputPin_AddRef,\r
-    HWCMemInputPin_Release,\r
-    HWCMemInputPin_GetAllocator,\r
-    HWCMemInputPin_NotifyAllocator,\r
-    HWCMemInputPin_GetAllocatorRequirements,\r
-    HWCMemInputPin_Receive,\r
-    HWCMemInputPin_ReceiveMultiple,\r
-    HWCMemInputPin_ReceiveCanBlock\r
-};\r
-\r
-static STDMETHODIMP HWCInPin_Construct(IBaseFilter *pFilter, IPin **ppv)\r
-{\r
-    HWCInPin *This = (HWCInPin *)g_malloc0(sizeof(HWCInPin));\r
-\r
-    if (!This) {\r
-        ERR("failed to HWCInPin_Construct, E_OUTOFMEMORY\n");\r
-        return E_OUTOFMEMORY;\r
-    }\r
-\r
-    This->IPin_iface.lpVtbl = &HWCPin_Vtbl;\r
-    This->IMemInputPin_iface.lpVtbl = &HWCMemInputPin_Vtbl;\r
-    This->m_bReadOnly = FALSE;\r
-    This->m_pCFilter = pFilter;\r
-    This->m_pConnectedPin = NULL;\r
-    This->m_pCallback = NULL;\r
-    This->m_pAllocator = NULL;\r
-    This->m_cRef = 1;\r
-    This->SetGrabCallbackIF = HWCPin_SetCallback;\r
-    *ppv = &This->IPin_iface;\r
-\r
-    return S_OK;\r
-}\r
-\r
-/*\r
- * HWCEnumPins\r
- */\r
-\r
-typedef struct HWCEnumPins {\r
-    IEnumPins IEnumPins_iface;\r
-    IBaseFilter *m_pFilter;\r
-    int m_nPos;\r
-    long m_cRef;\r
-} HWCEnumPins;\r
-\r
-static inline HWCEnumPins *impl_from_IEnumPins(IEnumPins *iface)\r
-{\r
-    return CONTAINING_RECORD(iface, HWCEnumPins, IEnumPins_iface);\r
-}\r
-\r
-static STDMETHODIMP HWCEnumPins_QueryInterface(IEnumPins *iface,\r
-                                               REFIID riid, void **ppv)\r
-{\r
-    if (ppv == NULL) {\r
-        return E_POINTER;\r
-    }\r
-\r
-    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumPins)) {\r
-        *ppv = iface;\r
-    } else {\r
-        *ppv = NULL;\r
-        return E_NOINTERFACE;\r
-    }\r
-\r
-    IEnumPins_AddRef(iface);\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP_(ULONG) HWCEnumPins_AddRef(IEnumPins *iface)\r
-{\r
-    HWCEnumPins *This = impl_from_IEnumPins(iface);\r
-\r
-    return InterlockedIncrement(&This->m_cRef);\r
-}\r
-\r
-static STDMETHODIMP_(ULONG) HWCEnumPins_Release(IEnumPins *iface)\r
-{\r
-    HWCEnumPins *This = impl_from_IEnumPins(iface);\r
-\r
-    if (InterlockedDecrement(&This->m_cRef) == 0) {\r
-        if (This->m_pFilter) {\r
-            SAFE_RELEASE(This->m_pFilter);\r
-        }\r
-        This->m_nPos = 0;\r
-        g_free((void *)This);\r
-        This = NULL;\r
-        return 0;\r
-    }\r
-    return This->m_cRef;\r
-}\r
-\r
-static STDMETHODIMP HWCEnumPins_Next(IEnumPins *iface, ULONG cPins,\r
-                                     IPin **ppPins, ULONG *pcFetched)\r
-{\r
-    ULONG fetched;\r
-    HWCEnumPins *This = impl_from_IEnumPins(iface);\r
-\r
-    if (ppPins == NULL) {\r
-        return E_POINTER;\r
-    }\r
-\r
-    if (This->m_nPos < 1 && cPins > 0) {\r
-        IPin *pPin;\r
-        IBaseFilter_FindPin(This->m_pFilter, HWCPinName, &pPin);\r
-        *ppPins = pPin;\r
-        fetched = 1;\r
-        This->m_nPos++;\r
-    } else {\r
-        fetched = 0;\r
-    }\r
-\r
-    if (pcFetched != NULL) {\r
-        *pcFetched = fetched;\r
-    }\r
-\r
-    return (fetched == cPins) ? S_OK : S_FALSE;\r
-}\r
-\r
-static STDMETHODIMP HWCEnumPins_Skip(IEnumPins *iface, ULONG cPins)\r
-{\r
-    HWCEnumPins *This = impl_from_IEnumPins(iface);\r
-    This->m_nPos += cPins;\r
-    return (This->m_nPos >= 1) ? S_FALSE : S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCEnumPins_Reset(IEnumPins *iface)\r
-{\r
-    HWCEnumPins *This = impl_from_IEnumPins(iface);\r
-    This->m_nPos = 0;\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter,\r
-                                          int nPos, IEnumPins **ppv);\r
-\r
-static STDMETHODIMP HWCEnumPins_Clone(IEnumPins *iface, IEnumPins **ppEnum)\r
-{\r
-    HWCEnumPins *This = impl_from_IEnumPins(iface);\r
-\r
-    if (ppEnum == NULL) {\r
-        return E_POINTER;\r
-    }\r
-\r
-    HWCEnumPins_Construct(This->m_pFilter, This->m_nPos, ppEnum);\r
-    if (*ppEnum == NULL) {\r
-        ERR("failed to HWCEnumPins_Construct in clone, E_OUTOFMEMORY\n");\r
-        return E_OUTOFMEMORY;\r
-    }\r
-\r
-    return S_OK;\r
-}\r
-\r
-static IEnumPinsVtbl HWCEnumPins_Vtbl = {\r
-    HWCEnumPins_QueryInterface,\r
-    HWCEnumPins_AddRef,\r
-    HWCEnumPins_Release,\r
-    HWCEnumPins_Next,\r
-    HWCEnumPins_Skip,\r
-    HWCEnumPins_Reset,\r
-    HWCEnumPins_Clone\r
-};\r
-\r
-\r
-static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter,\r
-                                          int nPos, IEnumPins **ppv)\r
-{\r
-    HWCEnumPins *This = (HWCEnumPins *)g_malloc0(sizeof(HWCEnumPins));\r
-\r
-    if (!This) {\r
-        ERR("failed to HWCEnumPins_Construct, E_OUTOFMEMORY\n");\r
-        return E_OUTOFMEMORY;\r
-    }\r
-\r
-    This->IEnumPins_iface.lpVtbl = &HWCEnumPins_Vtbl;\r
-    This->m_pFilter = pFilter;\r
-    if (This->m_pFilter) {\r
-        IBaseFilter_AddRef(This->m_pFilter);\r
-    }\r
-    This->m_cRef = 1;\r
-    This->m_nPos = nPos;\r
-    *ppv = &This->IEnumPins_iface;\r
-\r
-    return S_OK;\r
-}\r
-\r
-/*\r
- * HWCFilter\r
- */\r
-\r
-typedef struct HWCFilter {\r
-    IBaseFilter IBaseFilter_iface;\r
-    IPin *m_pPin;\r
-    IFilterGraph *m_pFilterGraph;\r
-    FILTER_STATE m_state;\r
-    long m_cRef;\r
-} HWCFilter;\r
-\r
-static inline HWCFilter *impl_from_IBaseFilter(IBaseFilter *iface)\r
-{\r
-    return CONTAINING_RECORD(iface, HWCFilter, IBaseFilter_iface);\r
-}\r
-\r
-static STDMETHODIMP HWCFilter_QueryInterface(IBaseFilter *iface,\r
-                                             REFIID riid, void **ppv)\r
-{\r
-    if (IsEqualIID(riid, &IID_IUnknown)) {\r
-        *ppv = (IUnknown *)iface;\r
-    } else if (IsEqualIID(riid, &IID_IPersist)) {\r
-        *ppv = (IPersist *)iface;\r
-    } else if (IsEqualIID(riid, &IID_IMediaFilter)) {\r
-        *ppv = (IMediaFilter *)iface;\r
-    } else if (IsEqualIID(riid, &IID_IBaseFilter)) {\r
-        *ppv = (IBaseFilter *)iface;\r
-    } else {\r
-        *ppv = NULL;\r
-        return E_NOINTERFACE;\r
-    }\r
-\r
-    IBaseFilter_AddRef(iface);\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP_(ULONG) HWCFilter_AddRef(IBaseFilter *iface)\r
-{\r
-    HWCFilter *This = impl_from_IBaseFilter(iface);\r
-\r
-    return InterlockedIncrement(&This->m_cRef);\r
-}\r
-\r
-static STDMETHODIMP_(ULONG) HWCFilter_Release(IBaseFilter *iface)\r
-{\r
-    HWCFilter *This = impl_from_IBaseFilter(iface);\r
-\r
-    if (InterlockedDecrement(&This->m_cRef) == 0) {\r
-        if (This->m_pPin) {\r
-            SAFE_RELEASE(This->m_pPin);\r
-        }\r
-        g_free((void *)This);\r
-        This = NULL;\r
-        return 0;\r
-    }\r
-    return This->m_cRef;\r
-}\r
-\r
-static STDMETHODIMP HWCFilter_GetClassID(IBaseFilter *iface, CLSID *pClsID)\r
-{\r
-    if (pClsID == NULL) {\r
-        return E_POINTER;\r
-    }\r
-    return E_NOTIMPL;\r
-}\r
-\r
-static STDMETHODIMP HWCFilter_GetState(IBaseFilter *iface, DWORD dwMSecs,\r
-                                       FILTER_STATE *State)\r
-{\r
-    HWCFilter *This = impl_from_IBaseFilter(iface);\r
-    *State = This->m_state;\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCFilter_SetSyncSource(IBaseFilter *iface,\r
-                                            IReferenceClock *pClock)\r
-{\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCFilter_GetSyncSource(IBaseFilter *iface,\r
-                                            IReferenceClock **pClock)\r
-{\r
-    *pClock = NULL;\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCFilter_Stop(IBaseFilter *iface)\r
-{\r
-    HWCFilter *This = impl_from_IBaseFilter(iface);\r
-\r
-    IPin_EndFlush(This->m_pPin);\r
-    This->m_state = State_Stopped;\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCFilter_Pause(IBaseFilter *iface)\r
-{\r
-    HWCFilter *This = impl_from_IBaseFilter(iface);\r
-    This->m_state = State_Paused;\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)\r
-{\r
-    HWCFilter *This = impl_from_IBaseFilter(iface);\r
-\r
-    if (This->m_state == State_Stopped) {\r
-        HRESULT hr;\r
-        hr = IBaseFilter_Pause(iface);\r
-        if (FAILED(hr)) {\r
-            ERR("HWCFilter_Run : Failed to IBaseFilter_Pause, ret=0xld%\n", hr);\r
-            return hr;\r
-        }\r
-    }\r
-\r
-    This->m_state = State_Running;\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCFilter_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum)\r
-{\r
-    if (ppEnum == NULL) {\r
-        return E_POINTER;\r
-    }\r
-\r
-    HWCEnumPins_Construct(iface, 0, ppEnum);\r
-    return *ppEnum == NULL ? E_OUTOFMEMORY : S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCFilter_FindPin(IBaseFilter *iface, LPCWSTR Id,\r
-                                      IPin **ppPin)\r
-{\r
-    HWCFilter *This = impl_from_IBaseFilter(iface);\r
-\r
-    if (ppPin == NULL) {\r
-        return E_POINTER;\r
-    }\r
-\r
-    if (memcmp((void *)Id, (void *)HWCPinName, sizeof(HWCPinName))) {\r
-        return VFW_E_NOT_FOUND;\r
-    }\r
-\r
-    if (!This->m_pPin) {\r
-        HWCInPin_Construct(iface, &This->m_pPin);\r
-    }\r
-    *ppPin = This->m_pPin;\r
-\r
-    IPin_AddRef(This->m_pPin);\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCFilter_QueryFilterInfo(IBaseFilter *iface,\r
-                                              FILTER_INFO *pInfo)\r
-{\r
-    HWCFilter *This = impl_from_IBaseFilter(iface);\r
-\r
-    if (pInfo == NULL) {\r
-        return E_POINTER;\r
-    }\r
-\r
-    memcpy((void *)pInfo->achName,\r
-           (void *)HWCFilterName,\r
-           sizeof(HWCFilterName));\r
-    pInfo->pGraph = This->m_pFilterGraph;\r
-    if (This->m_pFilterGraph) {\r
-        IFilterGraph_AddRef(This->m_pFilterGraph);\r
-    }\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCFilter_JoinFilterGraph(IBaseFilter *iface,\r
-                                              IFilterGraph *pGraph,\r
-                                              LPCWSTR pName)\r
-{\r
-    HWCFilter *This = impl_from_IBaseFilter(iface);\r
-\r
-    This->m_pFilterGraph = pGraph;\r
-    return S_OK;\r
-}\r
-\r
-static STDMETHODIMP HWCFilter_QueryVendorInfo(IBaseFilter *iface,\r
-                                              LPWSTR *pVendorInfo)\r
-{\r
-    return E_NOTIMPL;\r
-}\r
-\r
-static IBaseFilterVtbl HWCFilter_Vtbl = {\r
-    HWCFilter_QueryInterface,\r
-    HWCFilter_AddRef,\r
-    HWCFilter_Release,\r
-    HWCFilter_GetClassID,\r
-    HWCFilter_Stop,\r
-    HWCFilter_Pause,\r
-    HWCFilter_Run,\r
-    HWCFilter_GetState,\r
-    HWCFilter_SetSyncSource,\r
-    HWCFilter_GetSyncSource,\r
-    HWCFilter_EnumPins,\r
-    HWCFilter_FindPin,\r
-    HWCFilter_QueryFilterInfo,\r
-    HWCFilter_JoinFilterGraph,\r
-    HWCFilter_QueryVendorInfo\r
-};\r
-\r
-static STDMETHODIMP HWCFilter_Construct(IBaseFilter **ppv)\r
-{\r
-    HWCFilter *This = (HWCFilter *)g_malloc0(sizeof(HWCFilter));\r
-\r
-    if (!This) {\r
-        ERR("failed to HWCFilter_Construct, E_OUTOFMEMORY\n");\r
-        return E_OUTOFMEMORY;\r
-    }\r
-\r
-    This->IBaseFilter_iface.lpVtbl = &HWCFilter_Vtbl;\r
-    This->m_pFilterGraph = NULL;\r
-    This->m_state = State_Stopped;\r
-    This->m_cRef = 1;\r
-    HWCInPin_Construct(&This->IBaseFilter_iface, &This->m_pPin);\r
-    *ppv = &This->IBaseFilter_iface;\r
-\r
-    return S_OK;\r
-}\r
-\r
-/**********************************************************\r
- *\r
- * Virtual device implementations\r
- *\r
- **********************************************************/\r
-\r
-\r
-/*\r
- * Declaration global variables for Win32 COM Interfaces\r
- */\r
-IGraphBuilder *g_pGB ;\r
-ICaptureGraphBuilder2 *g_pCGB;\r
-IMediaControl *g_pMediaControl;\r
-\r
-IPin *g_pOutputPin;\r
-IPin *g_pInputPin;\r
-IBaseFilter *g_pDstFilter;\r
-IBaseFilter *g_pSrcFilter;\r
-\r
-IGrabCallback *g_pCallback;\r
-\r
-/* V4L2 defines copy from videodev2.h */\r
-#define V4L2_CTRL_FLAG_SLIDER       0x0020\r
-\r
-#define V4L2_CTRL_CLASS_USER        0x00980000\r
-#define V4L2_CID_BASE               (V4L2_CTRL_CLASS_USER | 0x900)\r
-#define V4L2_CID_BRIGHTNESS         (V4L2_CID_BASE+0)\r
-#define V4L2_CID_CONTRAST           (V4L2_CID_BASE+1)\r
-#define V4L2_CID_SATURATION         (V4L2_CID_BASE+2)\r
-#define V4L2_CID_SHARPNESS          (V4L2_CID_BASE+27)\r
-\r
-#define V4L2_PIX_FMT_YUYV    MAKEFOURCC('Y', 'U', 'Y', 'V') /* 16  YUV 4:2:2 */\r
-#define V4L2_PIX_FMT_YUV420  MAKEFOURCC('Y', 'U', '1', '2') /* 12  YUV 4:2:0 */\r
-#define V4L2_PIX_FMT_YVU420  MAKEFOURCC('Y', 'V', '1', '2') /* 12  YVU 4:2:0 */\r
-#define V4L2_PIX_FMT_RGB24   MAKEFOURCC('R', 'G', 'B', '3') /* 24  RGB-8-8-8 */\r
-\r
-typedef struct tagMaruCamConvertPixfmt {\r
-    uint32_t fmt;   /* fourcc */\r
-    uint32_t bpp;   /* bits per pixel, 0 for compressed formats */\r
-    uint32_t needs_conversion;\r
-} MaruCamConvertPixfmt;\r
-\r
-static MaruCamConvertPixfmt supported_dst_pixfmts[] = {\r
-        { V4L2_PIX_FMT_YUYV, 16, 0 },\r
-        { V4L2_PIX_FMT_YUV420, 12, 0 },\r
-        { V4L2_PIX_FMT_YVU420, 12, 0 },\r
-};\r
-\r
-typedef struct tagMaruCamConvertFrameInfo {\r
-    uint32_t width;\r
-    uint32_t height;\r
-} MaruCamConvertFrameInfo;\r
-\r
-static MaruCamConvertFrameInfo supported_dst_frames[] = {\r
-        { 640, 480 },\r
-        { 352, 288 },\r
-        { 320, 240 },\r
-        { 176, 144 },\r
-        { 160, 120 },\r
-};\r
-\r
-#define MARUCAM_CTRL_VALUE_MAX      20\r
-#define MARUCAM_CTRL_VALUE_MIN      1\r
-#define MARUCAM_CTRL_VALUE_MID      10\r
-#define MARUCAM_CTRL_VALUE_STEP     1\r
-\r
-struct marucam_qctrl {\r
-    uint32_t id;\r
-    uint32_t hit;\r
-    long min;\r
-    long max;\r
-    long step;\r
-    long init_val;\r
-};\r
-\r
-static struct marucam_qctrl qctrl_tbl[] = {\r
-    { V4L2_CID_BRIGHTNESS, 0, },\r
-    { V4L2_CID_CONTRAST, 0, },\r
-    { V4L2_CID_SATURATION, 0, },\r
-    { V4L2_CID_SHARPNESS, 0, },\r
-};\r
-\r
-static MaruCamState *g_state;\r
-\r
-static uint32_t ready_count;\r
-static uint32_t cur_fmt_idx;\r
-static uint32_t cur_frame_idx;\r
-static void *grab_buf;\r
-static uint32_t g_dwSrcFmt;\r
-\r
-\r
-/*\r
- * Helper functions - converting image formats, converting values\r
- */\r
-\r
-static uint32_t get_bytesperline(uint32_t pixfmt, uint32_t width)\r
-{\r
-    uint32_t bytesperline;\r
-\r
-    switch (pixfmt) {\r
-    case V4L2_PIX_FMT_YUV420:\r
-    case V4L2_PIX_FMT_YVU420:\r
-        bytesperline = (width * 12) >> 3;\r
-        break;\r
-    case V4L2_PIX_FMT_YUYV:\r
-    default:\r
-        bytesperline = width * 2;\r
-        break;\r
-    }\r
-\r
-    return bytesperline;\r
-}\r
-\r
-static uint32_t get_sizeimage(uint32_t pixfmt, uint32_t width, uint32_t height)\r
-{\r
-    return get_bytesperline(pixfmt, width) * height;\r
-}\r
-\r
-void yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,\r
-        uint32_t width, uint32_t height, uint32_t yvu);\r
-void rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,\r
-        uint32_t width, uint32_t height, uint32_t yvu);\r
-void rgb24_to_yuyv(unsigned char *src, unsigned char *dest,\r
-        uint32_t width, uint32_t height);\r
-void yuv420_to_yvu420(unsigned char *src, unsigned char *dest,\r
-        uint32_t width, uint32_t height);\r
-void yuv420_to_yuyv(unsigned char *src, unsigned char *dest,\r
-        uint32_t width, uint32_t height);\r
-\r
-static long value_convert_from_guest(long min, long max, long value)\r
-{\r
-    double rate = 0.0;\r
-    long dist = 0, ret = 0;\r
-\r
-    dist = max - min;\r
-\r
-    if (dist < MARUCAM_CTRL_VALUE_MAX) {\r
-        rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;\r
-        ret = min + (int32_t)(value / rate);\r
-    } else {\r
-        rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;\r
-        ret = min + (int32_t)(rate * value);\r
-    }\r
-    return ret;\r
-}\r
-\r
-static long value_convert_to_guest(long min, long max, long value)\r
-{\r
-    double rate  = 0.0;\r
-    long dist = 0, ret = 0;\r
-\r
-    dist = max - min;\r
-\r
-    if (dist < MARUCAM_CTRL_VALUE_MAX) {\r
-        rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;\r
-        ret = (int32_t)((double)(value - min) * rate);\r
-    } else {\r
-        rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;\r
-        ret = (int32_t)((double)(value - min) / rate);\r
-    }\r
-\r
-    return ret;\r
-}\r
-\r
-/*\r
- * Callback function for grab frames\r
- */\r
-static STDMETHODIMP marucam_device_callbackfn(ULONG dwSize, BYTE *pBuffer)\r
-{\r
-    void *tmp_buf;\r
-    uint32_t width, height, fmt, imgsize;\r
-\r
-    width = supported_dst_frames[cur_frame_idx].width;\r
-    height = supported_dst_frames[cur_frame_idx].height;\r
-    fmt = supported_dst_pixfmts[cur_fmt_idx].fmt;\r
-    imgsize = get_sizeimage(fmt, width, height);\r
-\r
-    if (imgsize > (uint32_t)dwSize) {\r
-        ERR("Image size is mismatched\n");\r
-        return E_FAIL;\r
-    }\r
-\r
-    switch (g_dwSrcFmt) {\r
-    case V4L2_PIX_FMT_YUYV:\r
-        switch (fmt) {\r
-        case V4L2_PIX_FMT_YUV420:\r
-            yuyv_to_yuv420(pBuffer, grab_buf, width, height, 0);\r
-            break;\r
-        case V4L2_PIX_FMT_YVU420:\r
-            yuyv_to_yuv420(pBuffer, grab_buf, width, height, 1);\r
-            break;\r
-        case V4L2_PIX_FMT_YUYV:\r
-            memcpy(grab_buf, (void *)pBuffer, (size_t)dwSize);\r
-            break;\r
-        default:\r
-            ERR("Invalid pixel format\n");\r
-            return E_FAIL;\r
-        }\r
-        break;\r
-    case V4L2_PIX_FMT_RGB24:\r
-        switch (fmt) {\r
-        case V4L2_PIX_FMT_YUV420:\r
-            rgb24_to_yuv420(pBuffer, grab_buf, width, height, 0);\r
-            break;\r
-        case V4L2_PIX_FMT_YVU420:\r
-            rgb24_to_yuv420(pBuffer, grab_buf, width, height, 1);\r
-            break;\r
-        case V4L2_PIX_FMT_YUYV:\r
-            rgb24_to_yuyv(pBuffer, grab_buf, width, height);\r
-            break;\r
-        default:\r
-            ERR("Invalid pixel format\n");\r
-            return E_FAIL;\r
-        }\r
-        break;\r
-    case V4L2_PIX_FMT_YUV420:\r
-        switch (fmt) {\r
-        case V4L2_PIX_FMT_YUV420:\r
-            memcpy(grab_buf, (void *)pBuffer, (size_t)dwSize);\r
-            break;\r
-        case V4L2_PIX_FMT_YVU420:\r
-            yuv420_to_yvu420(pBuffer, grab_buf, width, height);\r
-            break;\r
-        case V4L2_PIX_FMT_YUYV:\r
-            yuv420_to_yuyv(pBuffer, grab_buf, width, height);\r
-            break;\r
-        default:\r
-            ERR("Invalid pixel format\n");\r
-            return E_FAIL;\r
-        }\r
-        break;\r
-    default:\r
-        ERR("Invalid pixel format\n");\r
-        return E_FAIL;\r
-    }\r
-\r
-    qemu_mutex_lock(&g_state->thread_mutex);\r
-    if (g_state->streamon) {\r
-        if (ready_count < MARUCAM_SKIPFRAMES) {\r
-            /* skip a frame cause first some frame are distorted */\r
-            ++ready_count;\r
-            TRACE("skip %d frame\n", ready_count);\r
-            qemu_mutex_unlock(&g_state->thread_mutex);\r
-            return S_OK;\r
-        }\r
-        if (g_state->req_frame == 0) {\r
-            TRACE("there is no request\n");\r
-            qemu_mutex_unlock(&g_state->thread_mutex);\r
-            return S_OK;\r
-        }\r
-        tmp_buf = g_state->vaddr + g_state->buf_size * (g_state->req_frame - 1);\r
-        memcpy(tmp_buf, grab_buf, g_state->buf_size);\r
-        g_state->req_frame = 0; /* clear request */\r
-        g_state->isr |= 0x01;   /* set a flag of rasing a interrupt */\r
-        qemu_bh_schedule(g_state->tx_bh);\r
-    }\r
-    qemu_mutex_unlock(&g_state->thread_mutex);\r
-    return S_OK;\r
-}\r
-\r
-/*\r
- * Internal functions for manipulate interfaces\r
- */\r
-\r
-static STDMETHODIMP_(void) CloseInterfaces(void)\r
-{\r
-    if (g_pMediaControl) {\r
-        g_pMediaControl->lpVtbl->Stop(g_pMediaControl);\r
-    }\r
-\r
-    if (g_pOutputPin) {\r
-        g_pOutputPin->lpVtbl->Disconnect(g_pOutputPin);\r
-    }\r
-\r
-    SAFE_RELEASE(g_pGB);\r
-    SAFE_RELEASE(g_pCGB);\r
-    SAFE_RELEASE(g_pMediaControl);\r
-    SAFE_RELEASE(g_pOutputPin);\r
-    SAFE_RELEASE(g_pInputPin);\r
-    SAFE_RELEASE(g_pDstFilter);\r
-    SAFE_RELEASE(g_pSrcFilter);\r
-    SAFE_RELEASE(g_pCallback);\r
-}\r
-\r
-static STDMETHODIMP_(void) DeleteMediaType(AM_MEDIA_TYPE *pmt)\r
-{\r
-    if (pmt == NULL) {\r
-        return;\r
-    }\r
-\r
-    if (pmt->cbFormat != 0) {\r
-        CoTaskMemFree((PVOID)pmt->pbFormat);\r
-        pmt->cbFormat = 0;\r
-        pmt->pbFormat = NULL;\r
-    }\r
-    if (pmt->pUnk != NULL) {\r
-        pmt->pUnk->lpVtbl->Release(pmt->pUnk);\r
-        pmt->pUnk = NULL;\r
-    }\r
-\r
-    CoTaskMemFree((PVOID)pmt);\r
-}\r
-\r
-static STDMETHODIMP GetPin(IBaseFilter *pFilter,\r
-                           PIN_DIRECTION PinDir, IPin **ppPin)\r
-{\r
-    HRESULT hr;\r
-    IEnumPins *pEnum = NULL;\r
-    IPin *pPin = NULL;\r
-\r
-    if (ppPin == NULL) {\r
-        return E_POINTER;\r
-    }\r
-\r
-    hr = pFilter->lpVtbl->EnumPins(pFilter, &pEnum);\r
-    if (FAILED(hr)) {\r
-        return hr;\r
-    }\r
-\r
-    while (pEnum->lpVtbl->Next(pEnum, 1, &pPin, 0) == S_OK) {\r
-        PIN_DIRECTION PinDirThis;\r
-        hr = pPin->lpVtbl->QueryDirection(pPin, &PinDirThis);\r
-        if (FAILED(hr)) {\r
-            SAFE_RELEASE(pPin);\r
-            SAFE_RELEASE(pEnum);\r
-            return hr;\r
-        }\r
-        if (PinDir == PinDirThis) {\r
-            *ppPin = pPin;\r
-            SAFE_RELEASE(pEnum);\r
-            return S_OK;\r
-        }\r
-        SAFE_RELEASE(pPin);\r
-    }\r
-\r
-    SAFE_RELEASE(pEnum);\r
-    return S_FALSE;\r
-}\r
-\r
-static STDMETHODIMP GraphBuilder_Init(void)\r
-{\r
-    HRESULT hr;\r
-\r
-    hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC,\r
-                          &IID_IGraphBuilder, (void **)&g_pGB);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to create instance of GraphBuilder, 0x%x\n", hr);\r
-        return hr;\r
-    }\r
-\r
-    hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,\r
-                          &IID_ICaptureGraphBuilder2, (void **)&g_pCGB);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to create instance of CaptureGraphBuilder2, 0x%x\n", hr);\r
-        return hr;\r
-    }\r
-\r
-    hr = g_pCGB->lpVtbl->SetFiltergraph(g_pCGB, g_pGB);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to SetFiltergraph, 0x%x\n", hr);\r
-        return hr;\r
-    }\r
-\r
-    hr = g_pGB->lpVtbl->QueryInterface(g_pGB, &IID_IMediaControl,\r
-                                       (void **)&g_pMediaControl);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to QueryInterface for IMediaControl, 0x%x\n", hr);\r
-        return hr;\r
-    }\r
-\r
-    hr = HWCGrabCallback_Construct(&g_pCallback);\r
-    if (g_pCallback == NULL) {\r
-        hr = E_OUTOFMEMORY;\r
-    }\r
-\r
-    hr = ((HWCGrabCallback *)g_pCallback)->SetCallback(g_pCallback,\r
-                            (CallbackFn)marucam_device_callbackfn);\r
-\r
-    return hr;\r
-}\r
-\r
-static STDMETHODIMP BindSourceFilter(void)\r
-{\r
-    HRESULT hr;\r
-    ICreateDevEnum *pCreateDevEnum = NULL;\r
-    IEnumMoniker *pEnumMK = NULL;\r
-    IMoniker *pMoniKer;\r
-\r
-    hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,\r
-                          &IID_ICreateDevEnum,\r
-                          (void **)&pCreateDevEnum);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to create instance of CreateDevEnum, 0x%x\n", hr);\r
-        return hr;\r
-    }\r
-\r
-    hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum,\r
-                                      &CLSID_VideoInputDeviceCategory,\r
-                                      &pEnumMK, 0);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to get VideoInputDeviceCategory, 0x%x\n", hr);\r
-        SAFE_RELEASE(pCreateDevEnum);\r
-        return hr;\r
-    }\r
-\r
-    if (!pEnumMK) {\r
-        ERR("ClassEnumerator moniker is NULL\n");\r
-        SAFE_RELEASE(pCreateDevEnum);\r
-        return E_FAIL;\r
-    }\r
-    pEnumMK->lpVtbl->Reset(pEnumMK);\r
-\r
-    hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL);\r
-    if (hr == S_FALSE) {\r
-        hr = E_FAIL;\r
-    }\r
-    if (SUCCEEDED(hr)) {\r
-        IPropertyBag *pBag = NULL;\r
-        hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0,\r
-                                             &IID_IPropertyBag,\r
-                                             (void **)&pBag);\r
-        if (SUCCEEDED(hr)) {\r
-            VARIANT var;\r
-            var.vt = VT_BSTR;\r
-            hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);\r
-            if (hr == NOERROR) {\r
-                hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL,\r
-                                                    &IID_IBaseFilter,\r
-                                                    (void **)&g_pSrcFilter);\r
-                if (FAILED(hr)) {\r
-                    ERR("Counldn't bind moniker to filter object!!\n");\r
-                } else {\r
-                    g_pSrcFilter->lpVtbl->AddRef(g_pSrcFilter);\r
-                }\r
-                SysFreeString(var.bstrVal);\r
-            }\r
-            SAFE_RELEASE(pBag);\r
-        }\r
-        SAFE_RELEASE(pMoniKer);\r
-    }\r
-\r
-    if (SUCCEEDED(hr)) {\r
-        hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pSrcFilter, L"Video Capture");\r
-        if (hr != S_OK && hr != S_FALSE) {\r
-            ERR("Counldn't add Video Capture filter to our graph!\n");\r
-            SAFE_RELEASE(g_pSrcFilter);\r
-        }\r
-    }\r
-    SAFE_RELEASE(pEnumMK);\r
-    SAFE_RELEASE(pCreateDevEnum);\r
-\r
-    return hr;\r
-}\r
-\r
-static STDMETHODIMP BindTargetFilter(void)\r
-{\r
-    HRESULT hr;\r
-    hr = HWCFilter_Construct(&g_pDstFilter);\r
-\r
-    if (SUCCEEDED(hr) && g_pDstFilter) {\r
-        hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pDstFilter, L"HWCFilter");\r
-        if (FAILED(hr)) {\r
-            ERR("Counldn't add HWCFilterr to our graph!\n");\r
-            SAFE_RELEASE(g_pDstFilter);\r
-        }\r
-    }\r
-    return hr;\r
-}\r
-\r
-static STDMETHODIMP ConnectFilters(void)\r
-{\r
-    HRESULT hr;\r
-\r
-    hr = GetPin(g_pSrcFilter, PINDIR_OUTPUT , &g_pOutputPin);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to get output pin. 0x%x\n", hr);\r
-        return hr;\r
-    }\r
-\r
-    hr = GetPin(g_pDstFilter, PINDIR_INPUT , &g_pInputPin);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to get input pin. 0x%x\n", hr);\r
-        return hr;\r
-    }\r
-\r
-    hr = g_pGB->lpVtbl->Connect(g_pGB, g_pOutputPin, g_pInputPin);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to connect pins. 0x%x\n", hr);\r
-    }\r
-    return hr;\r
-}\r
-\r
-static STDMETHODIMP DisconnectPins(void)\r
-{\r
-    HRESULT hr;\r
-\r
-    hr = g_pGB->lpVtbl->Disconnect(g_pGB, g_pOutputPin);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to disconnect output pin. 0x%x\n", hr);\r
-        return hr;\r
-    }\r
-\r
-    hr = g_pGB->lpVtbl->Disconnect(g_pGB, g_pInputPin);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to disconnect input pin. 0x%x\n", hr);\r
-    }\r
-\r
-    return hr;\r
-}\r
-\r
-static STDMETHODIMP RemoveFilters(void)\r
-{\r
-    HRESULT hr;\r
-\r
-    hr = g_pGB->lpVtbl->RemoveFilter(g_pGB, g_pSrcFilter);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to remove source filer. 0x%x\n", hr);\r
-        return hr;\r
-    }\r
-\r
-    hr = g_pGB->lpVtbl->RemoveFilter(g_pGB, g_pDstFilter);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to remove destination filer. 0x%x\n", hr);\r
-    }\r
-\r
-    return hr;\r
-}\r
-\r
-/* default fps is 15 */\r
-#define MARUCAM_DEFAULT_FRAMEINTERVAL    666666\r
-\r
-static STDMETHODIMP SetFormat(uint32_t dwWidth, uint32_t dwHeight,\r
-                              uint32_t dwDstFmt, uint32_t *dwSrcFmt)\r
-{\r
-    HRESULT hr;\r
-    IAMStreamConfig *pSConfig;\r
-    int iCount = 0, iSize = 0;\r
-    DWORD dwYUY2 = MAKEFOURCC('Y', 'U', 'Y', '2');\r
-    DWORD dwI420 = MAKEFOURCC('I', '4', '2', '0');\r
-\r
-    if (dwSrcFmt == NULL) {\r
-        ERR("invalid the source format pointer\n");\r
-        return E_FAIL;\r
-    }\r
-\r
-    hr = g_pCGB->lpVtbl->FindInterface(g_pCGB, &PIN_CATEGORY_CAPTURE, 0,\r
-                                       g_pSrcFilter, &IID_IAMStreamConfig,\r
-                                       (void **)&pSConfig);\r
-    if (FAILED(hr)) {\r
-        ERR("failed to FindInterface method\n");\r
-        return hr;\r
-    }\r
-\r
-    hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);\r
-    if (FAILED(hr)) {\r
-        ERR("failed to GetNumberOfCapabilities method\n");\r
-        SAFE_RELEASE(pSConfig);\r
-        return hr;\r
-    }\r
-\r
-    if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {\r
-        int iFormat = 0;\r
-        for (iFormat = 0; iFormat < iCount; iFormat++) {\r
-            VIDEO_STREAM_CONFIG_CAPS scc;\r
-            AM_MEDIA_TYPE *pmtConfig;\r
-\r
-            hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat,\r
-                                                 &pmtConfig, (BYTE *)&scc);\r
-            if (hr == S_OK) {\r
-                if (IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo)) {\r
-                    VIDEOINFOHEADER *pvi =\r
-                                         (VIDEOINFOHEADER *)pmtConfig->pbFormat;\r
-                    if ((pvi->bmiHeader.biWidth == (LONG)dwWidth) &&\r
-                        (pvi->bmiHeader.biHeight == (LONG)dwHeight)) {\r
-                        if (pvi->bmiHeader.biCompression == dwYUY2) {\r
-                            *dwSrcFmt = V4L2_PIX_FMT_YUYV;\r
-                        } else if ((pvi->bmiHeader.biCompression == BI_RGB) &&\r
-                                (pvi->bmiHeader.biBitCount == 24)) {\r
-                            *dwSrcFmt = V4L2_PIX_FMT_RGB24;\r
-                        } else if (pvi->bmiHeader.biCompression == dwI420) {\r
-                            *dwSrcFmt = V4L2_PIX_FMT_YUV420;\r
-                        } else { /* not support format */\r
-                            DeleteMediaType(pmtConfig);\r
-                            continue;\r
-                        }\r
-                        /* use minimum FPS(maximum frameinterval)\r
-                           with non-VT system  */\r
-#ifdef CONFIG_HAX\r
-                        if (!hax_enabled()) {\r
-                            pvi->AvgTimePerFrame =\r
-                                    (REFERENCE_TIME)scc.MaxFrameInterval;\r
-                        } else {\r
-                            pvi->AvgTimePerFrame =\r
-                                (REFERENCE_TIME)MARUCAM_DEFAULT_FRAMEINTERVAL;\r
-                        }\r
-#else\r
-                        pvi->AvgTimePerFrame =\r
-                                (REFERENCE_TIME)scc.MaxFrameInterval;\r
-#endif\r
-                        hr = pSConfig->lpVtbl->SetFormat(pSConfig, pmtConfig);\r
-                        DeleteMediaType(pmtConfig);\r
-                        break;\r
-                    }\r
-                }\r
-                DeleteMediaType(pmtConfig);\r
-            }\r
-        }\r
-        if (iFormat >= iCount) {\r
-            ERR("Failed to Set format. "\r
-                "Maybe connected webcam does not support the (%ldx%ld) "\r
-                "resolution or image formats(YUY2, RGB24, I420).\n",\r
-                dwWidth, dwHeight);\r
-            hr = E_FAIL;\r
-        }\r
-    }\r
-    SAFE_RELEASE(pSConfig);\r
-    return hr;\r
-}\r
-\r
-static STDMETHODIMP QueryVideoProcAmp(long nProperty, long *pMin, long *pMax,\r
-                                      long *pStep, long *pDefault)\r
-{\r
-    HRESULT hr;\r
-    long Flags;\r
-    IAMVideoProcAmp *pProcAmp = NULL;\r
-\r
-    hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,\r
-                                              &IID_IAMVideoProcAmp,\r
-                                              (void **)&pProcAmp);\r
-    if (FAILED(hr)) {\r
-        return hr;\r
-    }\r
-\r
-    hr = pProcAmp->lpVtbl->GetRange(pProcAmp, nProperty, pMin, pMax,\r
-                                    pStep, pDefault, &Flags);\r
-\r
-    SAFE_RELEASE(pProcAmp);\r
-    return hr;\r
-}\r
-\r
-static STDMETHODIMP GetVideoProcAmp(long nProperty, long *pValue)\r
-{\r
-    HRESULT hr;\r
-    long Flags;\r
-    IAMVideoProcAmp *pProcAmp = NULL;\r
-\r
-    hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,\r
-                                              &IID_IAMVideoProcAmp,\r
-                                              (void **)&pProcAmp);\r
-    if (FAILED(hr)) {\r
-        return hr;\r
-    }\r
-\r
-    hr = pProcAmp->lpVtbl->Get(pProcAmp, nProperty, pValue, &Flags);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to get property for video\n");\r
-    }\r
-\r
-    SAFE_RELEASE(pProcAmp);\r
-    return hr;\r
-}\r
-\r
-static STDMETHODIMP SetVideoProcAmp(long nProperty, long value)\r
-{\r
-    HRESULT hr;\r
-\r
-    IAMVideoProcAmp *pProcAmp = NULL;\r
-    hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,\r
-                                              &IID_IAMVideoProcAmp,\r
-                                              (void **)&pProcAmp);\r
-    if (FAILED(hr)) {\r
-        return hr;\r
-    }\r
-\r
-    hr = pProcAmp->lpVtbl->Set(pProcAmp, nProperty, value,\r
-                               VideoProcAmp_Flags_Manual);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to set property for video\n");\r
-    }\r
-    SAFE_RELEASE(pProcAmp);\r
-    return hr;\r
-}\r
-\r
-static char *__wchar_to_char(const WCHAR *pwstr)\r
-{\r
-    char *pstr = NULL;\r
-    int len = 0;\r
-\r
-    len = wcslen(pwstr) + 1;\r
-    pstr = (char *)g_malloc0(sizeof(char) * len);\r
-    wcstombs(pstr, pwstr, len + 1);\r
-\r
-    return pstr;\r
-}\r
-\r
-int marucam_device_check(int log_flag)\r
-{\r
-    struct timeval t1, t2;\r
-    int ret = 0;\r
-    char *device_name = NULL;\r
-    HRESULT hr = E_FAIL;\r
-    ICreateDevEnum *pCreateDevEnum = NULL;\r
-    IGraphBuilder *pGB = NULL;\r
-    ICaptureGraphBuilder2 *pCGB = NULL;\r
-    IBaseFilter *pSrcFilter = NULL;\r
-    IEnumMoniker *pEnumMK = NULL;\r
-    IMoniker *pMoniKer = NULL;\r
-    IAMStreamConfig *pSConfig = NULL;\r
-    int iCount = 0, iSize = 0;\r
-\r
-    gettimeofday(&t1, NULL);\r
-    hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);\r
-    if (FAILED(hr)) {\r
-        fprintf(stdout, "[Webcam] failed to CoInitailizeEx\n");\r
-        gettimeofday(&t2, NULL);\r
-        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-        return ret;\r
-    }\r
-\r
-    hr = CoCreateInstance(&CLSID_FilterGraph, NULL,\r
-                          CLSCTX_INPROC,\r
-                          &IID_IGraphBuilder,\r
-                          (void **)&pGB);\r
-    if (FAILED(hr)) {\r
-        fprintf(stdout, "[Webcam] Failed to create GraphBuilder, 0x%x\n", hr);\r
-        CoUninitialize();\r
-        gettimeofday(&t2, NULL);\r
-        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-        return ret;\r
-    }\r
-\r
-    hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL,\r
-                          CLSCTX_INPROC,\r
-                          &IID_ICaptureGraphBuilder2,\r
-                          (void **)&pCGB);\r
-    if (FAILED(hr)) {\r
-        fprintf(stdout,\r
-        "[Webcam] Failed to create CaptureGraphBuilder2, 0x%x\n", hr);\r
-        SAFE_RELEASE(pGB);\r
-        CoUninitialize();\r
-        gettimeofday(&t2, NULL);\r
-        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-        return ret;\r
-    }\r
-\r
-    hr = pCGB->lpVtbl->SetFiltergraph(pCGB, pGB);\r
-    if (FAILED(hr)) {\r
-        fprintf(stdout, "[Webcam] Failed to SetFiltergraph, 0x%x\n", hr);\r
-        SAFE_RELEASE(pCGB);\r
-        SAFE_RELEASE(pGB);\r
-        CoUninitialize();\r
-        gettimeofday(&t2, NULL);\r
-        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-        return ret;\r
-    }\r
-\r
-    hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL,\r
-                          CLSCTX_INPROC,\r
-                          &IID_ICreateDevEnum,\r
-                          (void **)&pCreateDevEnum);\r
-    if (FAILED(hr)) {\r
-        fprintf(stdout,\r
-            "[Webcam] failed to create instance of CLSID_SystemDeviceEnum\n");\r
-        SAFE_RELEASE(pCGB);\r
-        SAFE_RELEASE(pGB);\r
-        CoUninitialize();\r
-        gettimeofday(&t2, NULL);\r
-        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-        return ret;\r
-    }\r
-\r
-    hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum,\r
-                                  &CLSID_VideoInputDeviceCategory, &pEnumMK, 0);\r
-    if (FAILED(hr)) {\r
-        fprintf(stdout, "[Webcam] failed to create class enumerator\n");\r
-        SAFE_RELEASE(pCreateDevEnum);\r
-        SAFE_RELEASE(pCGB);\r
-        SAFE_RELEASE(pGB);\r
-        CoUninitialize();\r
-        gettimeofday(&t2, NULL);\r
-        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-        return ret;\r
-    }\r
-\r
-    if (!pEnumMK) {\r
-        fprintf(stdout, "[Webcam] class enumerator is NULL!!\n");\r
-        SAFE_RELEASE(pCreateDevEnum);\r
-        SAFE_RELEASE(pCGB);\r
-        SAFE_RELEASE(pGB);\r
-        CoUninitialize();\r
-        gettimeofday(&t2, NULL);\r
-        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-        return ret;\r
-    }\r
-    pEnumMK->lpVtbl->Reset(pEnumMK);\r
-\r
-    hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL);\r
-    if (FAILED(hr) || (hr == S_FALSE)) {\r
-        fprintf(stdout, "[Webcam] enum moniker returns a invalid value.\n");\r
-        SAFE_RELEASE(pEnumMK);\r
-        SAFE_RELEASE(pCreateDevEnum);\r
-        SAFE_RELEASE(pCGB);\r
-        SAFE_RELEASE(pGB);\r
-        CoUninitialize();\r
-        gettimeofday(&t2, NULL);\r
-        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-        return ret;\r
-    }\r
-\r
-    IPropertyBag *pBag = NULL;\r
-    hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0,\r
-                                         &IID_IPropertyBag,\r
-                                         (void **)&pBag);\r
-    if (FAILED(hr)) {\r
-        fprintf(stdout, "[Webcam] failed to bind to storage.\n");\r
-        SAFE_RELEASE(pEnumMK);\r
-        SAFE_RELEASE(pCreateDevEnum);\r
-        SAFE_RELEASE(pCGB);\r
-        SAFE_RELEASE(pGB);\r
-        CoUninitialize();\r
-        gettimeofday(&t2, NULL);\r
-        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-        return ret;\r
-    } else {\r
-        VARIANT var;\r
-        var.vt = VT_BSTR;\r
-        hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);\r
-        if (hr == S_OK) {\r
-            ret = 1;\r
-            if (!log_flag) {\r
-                SysFreeString(var.bstrVal);\r
-                SAFE_RELEASE(pBag);\r
-                SAFE_RELEASE(pMoniKer);\r
-                SAFE_RELEASE(pEnumMK);\r
-                SAFE_RELEASE(pCreateDevEnum);\r
-                SAFE_RELEASE(pCGB);\r
-                SAFE_RELEASE(pGB);\r
-                CoUninitialize();\r
-                gettimeofday(&t2, NULL);\r
-                fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                                t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-                return ret;\r
-            }\r
-            device_name = __wchar_to_char(var.bstrVal);\r
-            fprintf(stdout, "[Webcam] Device name : %s\n", device_name);\r
-            g_free(device_name);\r
-            hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL,\r
-                                                &IID_IBaseFilter,\r
-                                                (void **)&pSrcFilter);\r
-            if (FAILED(hr)) {\r
-                fprintf(stdout,\r
-                   "[Webcam] Counldn't bind moniker to filter object!!\n");\r
-                SysFreeString(var.bstrVal);\r
-                SAFE_RELEASE(pBag);\r
-                SAFE_RELEASE(pMoniKer);\r
-                SAFE_RELEASE(pEnumMK);\r
-                SAFE_RELEASE(pCreateDevEnum);\r
-                SAFE_RELEASE(pCGB);\r
-                SAFE_RELEASE(pGB);\r
-                CoUninitialize();\r
-                gettimeofday(&t2, NULL);\r
-                fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                                t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-                return ret;\r
-            } else {\r
-                pSrcFilter->lpVtbl->AddRef(pSrcFilter);\r
-            }\r
-            SysFreeString(var.bstrVal);\r
-        }\r
-        SAFE_RELEASE(pBag);\r
-    }\r
-    SAFE_RELEASE(pMoniKer);\r
-\r
-    hr = pGB->lpVtbl->AddFilter(pGB, pSrcFilter, L"Video Capture");\r
-    if (hr != S_OK && hr != S_FALSE) {\r
-        fprintf(stdout,\r
-                "[Webcam] Counldn't add Video Capture filter to our graph!\n");\r
-        SAFE_RELEASE(pSrcFilter);\r
-        SAFE_RELEASE(pEnumMK);\r
-        SAFE_RELEASE(pCreateDevEnum);\r
-        SAFE_RELEASE(pCGB);\r
-        SAFE_RELEASE(pGB);\r
-        CoUninitialize();\r
-        gettimeofday(&t2, NULL);\r
-        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-        return ret;\r
-    }\r
-\r
-    hr = pCGB->lpVtbl->FindInterface(pCGB, &PIN_CATEGORY_CAPTURE, 0,\r
-                                       pSrcFilter, &IID_IAMStreamConfig,\r
-                                       (void **)&pSConfig);\r
-    if (FAILED(hr)) {\r
-        fprintf(stdout, "[Webcam] failed to FindInterface method\n");\r
-        SAFE_RELEASE(pSrcFilter);\r
-        SAFE_RELEASE(pEnumMK);\r
-        SAFE_RELEASE(pCreateDevEnum);\r
-        SAFE_RELEASE(pCGB);\r
-        SAFE_RELEASE(pGB);\r
-        CoUninitialize();\r
-        gettimeofday(&t2, NULL);\r
-        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-        return ret;\r
-    }\r
-\r
-    hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);\r
-    if (FAILED(hr)) {\r
-        fprintf(stdout, "[Webcam] failed to GetNumberOfCapabilities method\n");\r
-        SAFE_RELEASE(pSConfig);\r
-        SAFE_RELEASE(pSrcFilter);\r
-        SAFE_RELEASE(pEnumMK);\r
-        SAFE_RELEASE(pCreateDevEnum);\r
-        SAFE_RELEASE(pCGB);\r
-        SAFE_RELEASE(pGB);\r
-        CoUninitialize();\r
-        gettimeofday(&t2, NULL);\r
-        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-        return ret;\r
-    }\r
-\r
-    if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {\r
-        int iFormat = 0;\r
-        for (iFormat = 0; iFormat < iCount; iFormat++) {\r
-            VIDEO_STREAM_CONFIG_CAPS scc;\r
-            AM_MEDIA_TYPE *pmtConfig;\r
-\r
-            hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat, &pmtConfig,\r
-                                                 (BYTE *)&scc);\r
-            if (hr == S_OK) {\r
-                if (IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo)) {\r
-                    VIDEOINFOHEADER *pvi =\r
-                                         (VIDEOINFOHEADER *)pmtConfig->pbFormat;\r
-                    if (pvi->bmiHeader.biCompression == BI_RGB) {\r
-                        fprintf(stdout, "[Webcam] RGB BitCount: %d, %ux%u\n",\r
-                                pvi->bmiHeader.biBitCount,\r
-                                pvi->bmiHeader.biWidth,\r
-                                pvi->bmiHeader.biHeight);\r
-                    } else {\r
-                        fprintf(stdout,\r
-                                "[Webcam] PixelFormat: %c%c%c%c, %ux%u\n",\r
-                                (char)(pvi->bmiHeader.biCompression),\r
-                                (char)(pvi->bmiHeader.biCompression >> 8),\r
-                                (char)(pvi->bmiHeader.biCompression >> 16),\r
-                                (char)(pvi->bmiHeader.biCompression >> 24),\r
-                                pvi->bmiHeader.biWidth,\r
-                                pvi->bmiHeader.biHeight);\r
-                    }\r
-                }\r
-                DeleteMediaType(pmtConfig);\r
-            }\r
-        }\r
-    }\r
-\r
-    hr = pGB->lpVtbl->RemoveFilter(pGB, pSrcFilter);\r
-    if (FAILED(hr)) {\r
-        fprintf(stdout, "[Webcam] Failed to remove source filer. 0x%x\n", hr);\r
-    }\r
-\r
-    SAFE_RELEASE(pSConfig);\r
-    SAFE_RELEASE(pSrcFilter);\r
-    SAFE_RELEASE(pCGB);\r
-    SAFE_RELEASE(pGB);\r
-    SAFE_RELEASE(pEnumMK);\r
-    SAFE_RELEASE(pCreateDevEnum);\r
-    CoUninitialize();\r
-    gettimeofday(&t2, NULL);\r
-    fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",\r
-                    t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);\r
-\r
-    return ret;\r
-}\r
-\r
-/* MARUCAM_CMD_INIT */\r
-void marucam_device_init(MaruCamState *state)\r
-{\r
-    g_state = state;\r
-}\r
-\r
-void marucam_device_exit(MaruCamState *state)\r
-{\r
-}\r
-\r
-/* MARUCAM_CMD_OPEN */\r
-void marucam_device_open(MaruCamState *state)\r
-{\r
-    HRESULT hr;\r
-    uint32_t dwHeight, dwWidth, dwDstFmt;\r
-    MaruCamParam *param = state->param;\r
-    param->top = 0;\r
-\r
-    hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);\r
-    if (FAILED(hr)) {\r
-        ERR("CoInitailizeEx\n");\r
-        ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-\r
-    hr = GraphBuilder_Init();\r
-    if (FAILED(hr)) {\r
-        ERR("GraphBuilder_Init\n");\r
-        DisconnectPins();\r
-        RemoveFilters();\r
-        CloseInterfaces();\r
-        CoUninitialize();\r
-        param->errCode = EINVAL;\r
-        ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);\r
-        return;\r
-    }\r
-\r
-    hr = BindSourceFilter();\r
-    if (FAILED(hr)) {\r
-        ERR("BindSourceFilter\n");\r
-        DisconnectPins();\r
-        RemoveFilters();\r
-        CloseInterfaces();\r
-        CoUninitialize();\r
-        param->errCode = EINVAL;\r
-        ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);\r
-        return;\r
-    }\r
-\r
-    hr = BindTargetFilter();\r
-    if (FAILED(hr)) {\r
-        ERR("BindTargetFilter\n");\r
-        DisconnectPins();\r
-        RemoveFilters();\r
-        CloseInterfaces();\r
-        CoUninitialize();\r
-        param->errCode = EINVAL;\r
-        ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);\r
-        return;\r
-    }\r
-\r
-    hr = ConnectFilters();\r
-    if (FAILED(hr)) {\r
-        ERR("ConnectFilters\n");\r
-        DisconnectPins();\r
-        RemoveFilters();\r
-        CloseInterfaces();\r
-        CoUninitialize();\r
-        param->errCode = EINVAL;\r
-        ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);\r
-        return;\r
-    }\r
-\r
-    cur_frame_idx = 0;\r
-    cur_fmt_idx = 0;\r
-\r
-    dwHeight = supported_dst_frames[cur_frame_idx].height;\r
-    dwWidth = supported_dst_frames[cur_frame_idx].width;\r
-    dwDstFmt = supported_dst_pixfmts[cur_fmt_idx].fmt;\r
-    hr = SetFormat(dwWidth, dwHeight, dwDstFmt, &g_dwSrcFmt);\r
-    if (hr != S_OK) {\r
-        ERR("failed to Set default values\n");\r
-        DisconnectPins();\r
-        RemoveFilters();\r
-        CloseInterfaces();\r
-        CoUninitialize();\r
-        param->errCode = EINVAL;\r
-        ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);\r
-        return;\r
-    }\r
-\r
-    INFO("Opened\n");\r
-    return;\r
-}\r
-\r
-/* MARUCAM_CMD_CLOSE */\r
-void marucam_device_close(MaruCamState *state)\r
-{\r
-    MaruCamParam *param = state->param;\r
-    param->top = 0;\r
-\r
-    DisconnectPins();\r
-    RemoveFilters();\r
-    CloseInterfaces();\r
-    CoUninitialize();\r
-    INFO("Closed\n");\r
-}\r
-\r
-/* MARUCAM_CMD_START_PREVIEW */\r
-void marucam_device_start_preview(MaruCamState *state)\r
-{\r
-    HRESULT hr;\r
-    uint32_t pixfmt, width, height;\r
-    MaruCamParam *param = state->param;\r
-    param->top = 0;\r
-\r
-    ready_count = 0;\r
-    width = supported_dst_frames[cur_frame_idx].width;\r
-    height = supported_dst_frames[cur_frame_idx].height;\r
-    pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;\r
-    state->buf_size = get_sizeimage(pixfmt, width, height);\r
-\r
-    INFO("Pixfmt(%c%c%c%c), W:H(%d:%d), buf size(%u)\n",\r
-         (char)(pixfmt), (char)(pixfmt >> 8),\r
-         (char)(pixfmt >> 16), (char)(pixfmt >> 24),\r
-         width, height, state->buf_size);\r
-    INFO("Starting preview\n");\r
-\r
-    assert(g_pCallback != NULL);\r
-    hr = ((HWCInPin *)g_pInputPin)->SetGrabCallbackIF(g_pInputPin,\r
-                                                       g_pCallback);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to set IGrabCallback interface.\n");\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-\r
-    if (grab_buf) {\r
-        g_free(grab_buf);\r
-        grab_buf = NULL;\r
-    }\r
-    grab_buf = (void *)g_malloc0(state->buf_size);\r
-    if (grab_buf == NULL) {\r
-        param->errCode = ENOMEM;\r
-        return;\r
-    }\r
-\r
-    hr = g_pMediaControl->lpVtbl->Run(g_pMediaControl);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to run media control. hr=0x%x\n", hr);\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-\r
-    qemu_mutex_lock(&state->thread_mutex);\r
-    state->streamon = 1;\r
-    qemu_mutex_unlock(&state->thread_mutex);\r
-\r
-    INFO("Streaming on ......\n");\r
-}\r
-\r
-/* MARUCAM_CMD_STOP_PREVIEW */\r
-void marucam_device_stop_preview(MaruCamState *state)\r
-{\r
-    HRESULT hr;\r
-    MaruCamParam *param = state->param;\r
-    param->top = 0;\r
-\r
-    INFO("...... Streaming off\n");\r
-    qemu_mutex_lock(&state->thread_mutex);\r
-    state->streamon = 0;\r
-    qemu_mutex_unlock(&state->thread_mutex);\r
-\r
-    hr = ((HWCInPin *)g_pInputPin)->SetGrabCallbackIF(g_pInputPin, NULL);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to set IGrabCallback interface.\n");\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-\r
-    hr = g_pMediaControl->lpVtbl->Stop(g_pMediaControl);\r
-    if (FAILED(hr)) {\r
-        ERR("Failed to stop media control.\n");\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-\r
-    if (grab_buf) {\r
-        g_free(grab_buf);\r
-        grab_buf = NULL;\r
-    }\r
-    state->buf_size = 0;\r
-\r
-    INFO("Stopping preview\n");\r
-}\r
-\r
-/* MARUCAM_CMD_S_PARAM */\r
-void marucam_device_s_param(MaruCamState *state)\r
-{\r
-    MaruCamParam *param = state->param;\r
-\r
-    /* We use default FPS of the webcam */\r
-    param->top = 0;\r
-}\r
-\r
-/* MARUCAM_CMD_G_PARAM */\r
-void marucam_device_g_param(MaruCamState *state)\r
-{\r
-    MaruCamParam *param = state->param;\r
-\r
-    /* We use default FPS of the webcam\r
-     * return a fixed value on guest ini file (1/30).\r
-     */\r
-    param->top = 0;\r
-    param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */\r
-    param->stack[1] = 1; /* numerator */\r
-    param->stack[2] = 30; /* denominator */\r
-}\r
-\r
-/* MARUCAM_CMD_S_FMT */\r
-void marucam_device_s_fmt(MaruCamState *state)\r
-{\r
-    uint32_t width, height, pixfmt, pidx, fidx;\r
-    MaruCamParam *param = state->param;\r
-\r
-    param->top = 0;\r
-    width = param->stack[0];\r
-    height = param->stack[1];\r
-    pixfmt = param->stack[2];\r
-\r
-    for (fidx = 0; fidx < ARRAY_SIZE(supported_dst_frames); fidx++) {\r
-        if ((supported_dst_frames[fidx].width == width) &&\r
-                (supported_dst_frames[fidx].height == height)) {\r
-            break;\r
-        }\r
-    }\r
-    if (fidx == ARRAY_SIZE(supported_dst_frames)) {\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-    for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) {\r
-        if (supported_dst_pixfmts[pidx].fmt == pixfmt) {\r
-            break;\r
-        }\r
-    }\r
-    if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-\r
-    if ((supported_dst_frames[cur_frame_idx].width != width) &&\r
-            (supported_dst_frames[cur_frame_idx].height != height)) {\r
-        HRESULT hr = SetFormat(width, height, pixfmt, &g_dwSrcFmt);\r
-        if (FAILED(hr)) {\r
-            param->errCode = EINVAL;\r
-            return;\r
-        }\r
-    }\r
-\r
-    cur_frame_idx = fidx;\r
-    cur_fmt_idx = pidx;\r
-\r
-    pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;\r
-    width = supported_dst_frames[cur_frame_idx].width;\r
-    height = supported_dst_frames[cur_frame_idx].height;\r
-\r
-    param->stack[0] = width;\r
-    param->stack[1] = height;\r
-    param->stack[2] = 1; /* V4L2_FIELD_NONE */\r
-    param->stack[3] = pixfmt;\r
-    param->stack[4] = get_bytesperline(pixfmt, width);\r
-    param->stack[5] = get_sizeimage(pixfmt, width, height);\r
-    param->stack[6] = 0;\r
-    param->stack[7] = 0;\r
-\r
-    TRACE("Set format...\n");\r
-}\r
-\r
-/* MARUCAM_CMD_G_FMT */\r
-void marucam_device_g_fmt(MaruCamState *state)\r
-{\r
-    uint32_t width, height, pixfmt;\r
-    MaruCamParam *param = state->param;\r
-\r
-    param->top = 0;\r
-    pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;\r
-    width = supported_dst_frames[cur_frame_idx].width;\r
-    height = supported_dst_frames[cur_frame_idx].height;\r
-\r
-    param->stack[0] = width;\r
-    param->stack[1] = height;\r
-    param->stack[2] = 1; /* V4L2_FIELD_NONE */\r
-    param->stack[3] = pixfmt;\r
-    param->stack[4] = get_bytesperline(pixfmt, width);\r
-    param->stack[5] = get_sizeimage(pixfmt, width, height);\r
-    param->stack[6] = 0;\r
-    param->stack[7] = 0;\r
-\r
-    TRACE("Get format...\n");\r
-}\r
-\r
-void marucam_device_try_fmt(MaruCamState *state)\r
-{\r
-    uint32_t width, height, pixfmt, i;\r
-    MaruCamParam *param = state->param;\r
-\r
-    param->top = 0;\r
-    width = param->stack[0];\r
-    height = param->stack[1];\r
-    pixfmt = param->stack[2];\r
-\r
-    for (i = 0; i < ARRAY_SIZE(supported_dst_frames); i++) {\r
-        if ((supported_dst_frames[i].width == width) &&\r
-                (supported_dst_frames[i].height == height)) {\r
-            break;\r
-        }\r
-    }\r
-    if (i == ARRAY_SIZE(supported_dst_frames)) {\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-    for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {\r
-        if (supported_dst_pixfmts[i].fmt == pixfmt) {\r
-            break;\r
-        }\r
-    }\r
-    if (i == ARRAY_SIZE(supported_dst_pixfmts)) {\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-\r
-    param->stack[0] = width;\r
-    param->stack[1] = height;\r
-    param->stack[2] = 1; /* V4L2_FIELD_NONE */\r
-    param->stack[3] = pixfmt;\r
-    param->stack[4] = get_bytesperline(pixfmt, width);\r
-    param->stack[5] = get_sizeimage(pixfmt, width, height);\r
-    param->stack[6] = 0;\r
-    param->stack[7] = 0;\r
-}\r
-\r
-void marucam_device_enum_fmt(MaruCamState *state)\r
-{\r
-    uint32_t index;\r
-    MaruCamParam *param = state->param;\r
-\r
-    param->top = 0;\r
-    index = param->stack[0];\r
-\r
-    if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-    param->stack[1] = 0; /* flags = NONE */\r
-    param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */\r
-    /* set description */\r
-    switch (supported_dst_pixfmts[index].fmt) {\r
-    case V4L2_PIX_FMT_YUYV:\r
-        memcpy(&param->stack[3], "YUYV", 32);\r
-        break;\r
-    case V4L2_PIX_FMT_YUV420:\r
-        memcpy(&param->stack[3], "YU12", 32);\r
-        break;\r
-    case V4L2_PIX_FMT_YVU420:\r
-        memcpy(&param->stack[3], "YV12", 32);\r
-        break;\r
-    default:\r
-        ERR("Invalid pixel format\n");\r
-        param->errCode = EINVAL;\r
-        break;\r
-    }\r
-}\r
-\r
-void marucam_device_qctrl(MaruCamState *state)\r
-{\r
-    HRESULT hr;\r
-    uint32_t id, i;\r
-    long property, min, max, step, def_val, set_val;\r
-    char name[32] = {0,};\r
-    MaruCamParam *param = state->param;\r
-\r
-    param->top = 0;\r
-    id = param->stack[0];\r
-\r
-    switch (id) {\r
-    case V4L2_CID_BRIGHTNESS:\r
-        TRACE("V4L2_CID_BRIGHTNESS\n");\r
-        property = VideoProcAmp_Brightness;\r
-        memcpy((void *)name, (void *)"brightness", 32);\r
-        i = 0;\r
-        break;\r
-    case V4L2_CID_CONTRAST:\r
-        TRACE("V4L2_CID_CONTRAST\n");\r
-        property = VideoProcAmp_Contrast;\r
-        memcpy((void *)name, (void *)"contrast", 32);\r
-        i = 1;\r
-        break;\r
-    case V4L2_CID_SATURATION:\r
-        TRACE("V4L2_CID_SATURATION\n");\r
-        property = VideoProcAmp_Saturation;\r
-        memcpy((void *)name, (void *)"saturation", 32);\r
-        i = 2;\r
-        break;\r
-    case V4L2_CID_SHARPNESS:\r
-        TRACE("V4L2_CID_SHARPNESS\n");\r
-        property = VideoProcAmp_Sharpness;\r
-        memcpy((void *)name, (void *)"sharpness", 32);\r
-        i = 3;\r
-        break;\r
-    default:\r
-        ERR("Invalid control ID\n");\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-    hr = QueryVideoProcAmp(property, &min, &max, &step, &def_val);\r
-    if (FAILED(hr)) {\r
-        param->errCode = EINVAL;\r
-        ERR("failed to query video controls [HRESULT : 0x%x]\n", hr);\r
-        return;\r
-    } else {\r
-        qctrl_tbl[i].hit = 1;\r
-        qctrl_tbl[i].min = min;\r
-        qctrl_tbl[i].max = max;\r
-        qctrl_tbl[i].step = step;\r
-        qctrl_tbl[i].init_val = def_val;\r
-\r
-        if ((qctrl_tbl[i].min + qctrl_tbl[i].max) == 0) {\r
-            set_val = 0;\r
-        } else {\r
-            set_val = (qctrl_tbl[i].min + qctrl_tbl[i].max) / 2;\r
-        }\r
-        hr = SetVideoProcAmp(property, set_val);\r
-        if (FAILED(hr)) {\r
-            param->errCode = EINVAL;\r
-            ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);\r
-            return;\r
-        }\r
-    }\r
-\r
-    param->stack[0] = id;\r
-    param->stack[1] = MARUCAM_CTRL_VALUE_MIN;  /* minimum */\r
-    param->stack[2] = MARUCAM_CTRL_VALUE_MAX;  /* maximum */\r
-    param->stack[3] = MARUCAM_CTRL_VALUE_STEP; /*  step   */\r
-    param->stack[4] = MARUCAM_CTRL_VALUE_MID;  /* default_value */\r
-    param->stack[5] = V4L2_CTRL_FLAG_SLIDER;\r
-    /* name field setting */\r
-    memcpy(&param->stack[6], (void *)name, sizeof(name)/sizeof(name[0]));\r
-}\r
-\r
-void marucam_device_s_ctrl(MaruCamState *state)\r
-{\r
-    HRESULT hr;\r
-    uint32_t i;\r
-    long property, set_val;\r
-    MaruCamParam *param = state->param;\r
-\r
-    param->top = 0;\r
-\r
-    switch (param->stack[0]) {\r
-    case V4L2_CID_BRIGHTNESS:\r
-        i = 0;\r
-        property = VideoProcAmp_Brightness;\r
-        break;\r
-    case V4L2_CID_CONTRAST:\r
-        i = 1;\r
-        property = VideoProcAmp_Contrast;\r
-        break;\r
-    case V4L2_CID_SATURATION:\r
-        i = 2;\r
-        property = VideoProcAmp_Saturation;\r
-        break;\r
-    case V4L2_CID_SHARPNESS:\r
-        i = 3;\r
-        property = VideoProcAmp_Sharpness;\r
-        break;\r
-    default:\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-    set_val = value_convert_from_guest(qctrl_tbl[i].min,\r
-            qctrl_tbl[i].max, (long)param->stack[1]);\r
-    hr = SetVideoProcAmp(property, set_val);\r
-    if (FAILED(hr)) {\r
-        param->errCode = EINVAL;\r
-        ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);\r
-        return;\r
-    }\r
-}\r
-\r
-void marucam_device_g_ctrl(MaruCamState *state)\r
-{\r
-    HRESULT hr;\r
-    uint32_t i;\r
-    long property, get_val;\r
-    MaruCamParam *param = state->param;\r
-\r
-    param->top = 0;\r
-    switch (param->stack[0]) {\r
-    case V4L2_CID_BRIGHTNESS:\r
-        i = 0;\r
-        property = VideoProcAmp_Brightness;\r
-        break;\r
-    case V4L2_CID_CONTRAST:\r
-        i = 1;\r
-        property = VideoProcAmp_Contrast;\r
-        break;\r
-    case V4L2_CID_SATURATION:\r
-        i = 2;\r
-        property = VideoProcAmp_Saturation;\r
-        break;\r
-    case V4L2_CID_SHARPNESS:\r
-        i = 3;\r
-        property = VideoProcAmp_Sharpness;\r
-        break;\r
-    default:\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-\r
-    hr = GetVideoProcAmp(property, &get_val);\r
-    if (FAILED(hr)) {\r
-        param->errCode = EINVAL;\r
-        ERR("failed to get video control value!!!, [HRESULT : 0x%x]\n", hr);\r
-        return;\r
-    }\r
-    param->stack[0] = (uint32_t)value_convert_to_guest(qctrl_tbl[i].min,\r
-                qctrl_tbl[i].max, get_val);\r
-}\r
-\r
-void marucam_device_enum_fsizes(MaruCamState *state)\r
-{\r
-    uint32_t index, pixfmt, i;\r
-    MaruCamParam *param = state->param;\r
-\r
-    param->top = 0;\r
-    index = param->stack[0];\r
-    pixfmt = param->stack[1];\r
-\r
-    if (index >= ARRAY_SIZE(supported_dst_frames)) {\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-    for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {\r
-        if (supported_dst_pixfmts[i].fmt == pixfmt) {\r
-            break;\r
-        }\r
-    }\r
-\r
-    if (i == ARRAY_SIZE(supported_dst_pixfmts)) {\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-\r
-    param->stack[0] = supported_dst_frames[index].width;\r
-    param->stack[1] = supported_dst_frames[index].height;\r
-}\r
-\r
-void marucam_device_enum_fintv(MaruCamState *state)\r
-{\r
-    MaruCamParam *param = state->param;\r
-\r
-    param->top = 0;\r
-\r
-    /* switch by index(param->stack[0]) */\r
-    switch (param->stack[0]) {\r
-    case 0:\r
-        param->stack[1] = 30; /* denominator */\r
-        break;\r
-    default:\r
-        param->errCode = EINVAL;\r
-        return;\r
-    }\r
-    param->stack[0] = 1; /* numerator */\r
-}\r
-\r
-void yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,\r
-        uint32_t width, uint32_t height, uint32_t yvu)\r
-{\r
-    uint32_t i, j;\r
-    const unsigned char *src1;\r
-    unsigned char *udest, *vdest;\r
-\r
-    /* copy the Y values */\r
-    src1 = src;\r
-    for (i = 0; i < height; i++) {\r
-        for (j = 0; j < width; j += 2) {\r
-            *dest++ = src1[0];\r
-            *dest++ = src1[2];\r
-            src1 += 4;\r
-        }\r
-    }\r
-\r
-    /* copy the U and V values */\r
-    src++;              /* point to V */\r
-    src1 = src + width * 2;     /* next line */\r
-    if (yvu) {\r
-        vdest = dest;\r
-        udest = dest + width * height / 4;\r
-    } else {\r
-        udest = dest;\r
-        vdest = dest + width * height / 4;\r
-    }\r
-    for (i = 0; i < height; i += 2) {\r
-        for (j = 0; j < width; j += 2) {\r
-            *udest++ = ((int) src[0] + src1[0]) / 2;    /* U */\r
-            *vdest++ = ((int) src[2] + src1[2]) / 2;    /* V */\r
-            src += 4;\r
-            src1 += 4;\r
-        }\r
-        src = src1;\r
-        src1 += width * 2;\r
-    }\r
-}\r
-\r
-#define RGB2Y(r, g, b, y)   \\r
-    (y) = ((8453 * (r) + 16594 * (g) + 3223 * (b) + 524288) >> 15)\r
-\r
-#define RGB2UV(r, g, b, u, v)   \\r
-    do {    \\r
-        (u) = ((-4878 * (r) - 9578 * (g) + 14456 * (b) + 4210688) >> 15);   \\r
-        (v) = ((14456 * (r) - 12105 * (g) - 2351 * (b) + 4210688) >> 15);   \\r
-    } while (0)\r
-\r
-#define CLIP(color) \\r
-    (unsigned char)(((color) > 0xFF) ? 0xff : (((color) < 0) ? 0 : (color)))\r
-\r
-void rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,\r
-                     uint32_t width, uint32_t height, uint32_t yvu)\r
-{\r
-    uint32_t x, y;\r
-    unsigned char *udest, *vdest;\r
-    uint32_t bytesperline = width * 3;\r
-\r
-    /* Y */\r
-    for (y = 0; y < height; y++) {\r
-        for (x = 0; x < width; x++) {\r
-            RGB2Y(src[2], src[1], src[0], *dest++);\r
-            src += 3;\r
-        }\r
-        src += bytesperline - 3 * width;\r
-    }\r
-    src -= height * bytesperline;\r
-\r
-    /* U + V */\r
-    if (yvu) {\r
-        vdest = dest;\r
-        udest = dest + width * height / 4;\r
-    } else {\r
-        udest = dest;\r
-        vdest = dest + width * height / 4;\r
-    }\r
-\r
-    for (y = 0; y < height / 2; y++) {\r
-        for (x = 0; x < width / 2; x++) {\r
-            uint32_t avg_src[3];\r
-\r
-            avg_src[0] = (src[0] + src[3] + src[bytesperline] +\r
-                    src[bytesperline + 3]) / 4;\r
-            avg_src[1] = (src[1] + src[4] + src[bytesperline + 1] +\r
-                    src[bytesperline + 4]) / 4;\r
-            avg_src[2] = (src[2] + src[5] + src[bytesperline + 2] +\r
-                    src[bytesperline + 5]) / 4;\r
-            RGB2UV(avg_src[2], avg_src[1], avg_src[0], *udest++, *vdest++);\r
-            src += 6;\r
-        }\r
-        src += 2 * bytesperline - 3 * width;\r
-    }\r
-}\r
-\r
-void rgb24_to_yuyv(unsigned char *src, unsigned char *dest,\r
-                   uint32_t width, uint32_t height)\r
-{\r
-    uint32_t i = 0;\r
-\r
-    for (i = 0; i < (width * height * 3); i = i + 6) {\r
-        /* y */\r
-        *dest++ = CLIP(0.299 * (src[i + 2] - 128) +\r
-                    0.587 * (src[i + 1] - 128) +\r
-                    0.114 * (src[i] - 128) + 128);\r
-        /* u */\r
-        *dest++ = CLIP(((-0.147 * (src[i + 2] - 128) -\r
-                    0.289 * (src[i + 1] - 128) +\r
-                    0.436 * (src[i] - 128) + 128) +\r
-                    (-0.147 * (src[i + 5] - 128) -\r
-                    0.289 * (src[i + 4] - 128) +\r
-                    0.436 * (src[i + 3] - 128) + 128)) / 2);\r
-        /* y1 */\r
-        *dest++ = CLIP(0.299 * (src[i + 5] - 128) +\r
-                    0.587 * (src[i + 4] - 128) +\r
-                    0.114 * (src[i + 3] - 128) + 128);\r
-        /* v */\r
-        *dest++ = CLIP(((0.615 * (src[i + 2] - 128) -\r
-                    0.515 * (src[i + 1] - 128) -\r
-                    0.100 * (src[i] - 128) + 128) +\r
-                    (0.615 * (src[i + 5] - 128) -\r
-                    0.515 * (src[i + 4] - 128) -\r
-                    0.100 * (src[i + 3] - 128) + 128)) / 2);\r
-    }\r
-}\r
-\r
-void yuv420_to_yvu420(unsigned char *src, unsigned char *dest,\r
-                      uint32_t width, uint32_t height)\r
-{\r
-    unsigned char *psrc_y, *pdst_y;\r
-    unsigned char *psrc_u, *pdst_u;\r
-    unsigned char *psrc_v, *pdst_v;\r
-\r
-    psrc_y = src;\r
-    psrc_u = psrc_y + (width * height);\r
-    psrc_v = psrc_u + (width * height / 4);\r
-\r
-    pdst_y = dest;\r
-    pdst_v = pdst_y + (width * height);\r
-    pdst_u = pdst_v + (width * height / 4);\r
-\r
-    memcpy(pdst_y, psrc_y, width * height);\r
-    memcpy(pdst_v, psrc_v, width * height / 4);\r
-    memcpy(pdst_u, psrc_u, width * height / 4);\r
-}\r
-\r
-void yuv420_to_yuyv(unsigned char *src, unsigned char *dest,\r
-                    uint32_t width, uint32_t height)\r
-{\r
-    unsigned char *py;\r
-    unsigned char *pu;\r
-    unsigned char *pv;\r
-\r
-    uint32_t linesize = width * 2;\r
-    uint32_t uvlinesize = width / 2;\r
-    uint32_t offset = 0;\r
-    uint32_t offset1 = 0;\r
-    uint32_t offsety = 0;\r
-    uint32_t offsety1 = 0;\r
-    uint32_t offsetuv = 0;\r
-    uint32_t h = 0;\r
-    uint32_t w = 0;\r
-    uint32_t wy = 0;\r
-    uint32_t huv = 0;\r
-    uint32_t wuv = 0;\r
-\r
-    py = src;\r
-    pu = py + (width * height);\r
-    pv = pu + (width * height / 4);\r
-\r
-    for (h = 0; h < height; h += 2) {\r
-        wy = 0;\r
-        wuv = 0;\r
-        offset = h * linesize;\r
-        offset1 = (h + 1) * linesize;\r
-        offsety = h * width;\r
-        offsety1 = (h + 1) * width;\r
-        offsetuv = huv * uvlinesize;\r
-\r
-        for (w = 0; w < linesize; w += 4) {\r
-            /* y00 */\r
-            dest[w + offset] = py[wy + offsety];\r
-            /* u0 */\r
-            dest[(w + 1) + offset] = pu[wuv + offsetuv];\r
-            /* y01 */\r
-            dest[(w + 2) + offset] = py[(wy + 1) + offsety];\r
-            /* v0 */\r
-            dest[(w + 3) + offset] = pv[wuv + offsetuv];\r
-\r
-            /* y10 */\r
-            dest[w + offset1] = py[wy + offsety1];\r
-            /* u0 */\r
-            dest[(w + 1) + offset1] = pu[wuv + offsetuv];\r
-            /* y11 */\r
-            dest[(w + 2) + offset1] = py[(wy + 1) + offsety1];\r
-            /* v0 */\r
-            dest[(w + 3) + offset1] = pv[wuv + offsetuv];\r
-\r
-            wuv++;\r
-            wy += 2;\r
-        }\r
-        huv++;\r
-    }\r
-}\r
+/*
+ * Implementation of MARU Virtual Camera device by PCI bus on Windows.
+ *
+ * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * JinHyung Jo <jinhyung.jo@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA  02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include "qemu-common.h"
+#include "maru_camera_common.h"
+#include "tizen/src/debug_ch.h"
+
+#define CINTERFACE
+#define COBJMACROS
+#include "ocidl.h"
+#include "errors.h"      /* for VFW_E_XXXX */
+#include "mmsystem.h"    /* for MAKEFOURCC macro */
+#include "maru_camera_win32_interface.h"
+
+MULTI_DEBUG_CHANNEL(tizen, camera_win32);
+
+/*
+ * COM Interface implementations
+ *
+ */
+
+#define SAFE_RELEASE(x) \
+    do { \
+        if (x) { \
+            (x)->lpVtbl->Release(x); \
+            x = NULL; \
+        } \
+    } while (0)
+
+typedef HRESULT (STDAPICALLTYPE *CallbackFn)(ULONG dwSize, BYTE *pBuffer);
+
+/*
+ * HWCGrabCallback
+ */
+
+typedef struct HWCGrabCallback {
+    IGrabCallback IGrabCallback_iface;
+    long m_cRef;
+    CallbackFn m_pCallback;
+    STDMETHODIMP (*SetCallback)(IGrabCallback *iface, CallbackFn pCallbackFn);
+} HWCGrabCallback;
+
+static inline HWCGrabCallback *impl_from_IGrabCallback(IGrabCallback *iface)
+{
+    return CONTAINING_RECORD(iface, HWCGrabCallback, IGrabCallback_iface);
+}
+
+static STDMETHODIMP HWCGrabCallback_QueryInterface(IGrabCallback *iface,
+                                                   REFIID riid, void **ppv)
+{
+    if (IsEqualIID(riid, &IID_IUnknown)) {
+        *ppv = (IUnknown *)iface;
+    } else if (IsEqualIID(riid, &IID_IGrabCallback)) {
+        *ppv = (IGrabCallback *)iface;
+    } else {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IGrabCallback_AddRef(iface);
+    return S_OK;
+}
+
+static STDMETHODIMP_(ULONG) HWCGrabCallback_AddRef(IGrabCallback *iface)
+{
+    HWCGrabCallback *This = impl_from_IGrabCallback(iface);
+
+    return InterlockedIncrement(&This->m_cRef);
+}
+
+static STDMETHODIMP_(ULONG) HWCGrabCallback_Release(IGrabCallback *iface)
+{
+    HWCGrabCallback *This = impl_from_IGrabCallback(iface);
+
+    if (InterlockedDecrement(&This->m_cRef) == 0) {
+        This->m_pCallback = NULL;
+        g_free((void *)This);
+        This = NULL;
+        return 0;
+    }
+
+    return This->m_cRef;
+}
+
+static STDMETHODIMP HWCGrabCallback_Grab(IGrabCallback *iface,
+                                         ULONG dwSize, BYTE *pBuffer)
+{
+    HWCGrabCallback *This = impl_from_IGrabCallback(iface);
+
+    if (This->m_pCallback) {
+        HRESULT hr = This->m_pCallback(dwSize, pBuffer);
+        if (FAILED(hr)) {
+            return E_FAIL;
+        } else {
+            return S_OK;
+        }
+    }
+
+    return E_FAIL;
+}
+
+static STDMETHODIMP HWCGrabCallback_SetCallback(IGrabCallback *iface,
+                                                CallbackFn pCallbackFn)
+{
+    HWCGrabCallback *This = impl_from_IGrabCallback(iface);
+
+    This->m_pCallback = pCallbackFn;
+    return S_OK;
+}
+
+static IGrabCallbackVtbl HWCGrabCallback_Vtbl = {
+        HWCGrabCallback_QueryInterface,
+        HWCGrabCallback_AddRef,
+        HWCGrabCallback_Release,
+        HWCGrabCallback_Grab
+};
+
+static STDMETHODIMP HWCGrabCallback_Construct(IGrabCallback **ppv)
+{
+    HWCGrabCallback *This =
+            (HWCGrabCallback *)g_malloc0(sizeof(HWCGrabCallback));
+
+    if (!This) {
+        ERR("failed to HWCGrabCallback_Construct, E_OUTOFMEMORY\n");
+        return E_OUTOFMEMORY;
+    }
+
+    This->IGrabCallback_iface.lpVtbl = &HWCGrabCallback_Vtbl;
+    This->m_cRef = 1;
+    This->m_pCallback = NULL;
+    This->SetCallback = HWCGrabCallback_SetCallback;
+    *ppv = &This->IGrabCallback_iface;
+    return S_OK;
+}
+
+/*
+ * HWCPin
+ */
+
+typedef struct HWCInPin {
+    IPin IPin_iface;
+    IMemInputPin IMemInputPin_iface;
+    IBaseFilter *m_pCFilter;
+    IPin *m_pConnectedPin;
+    IGrabCallback *m_pCallback;
+    IMemAllocator *m_pAllocator;
+    BOOL m_bReadOnly;
+    long m_cRef;
+    STDMETHODIMP (*SetGrabCallbackIF)(IPin *iface, IGrabCallback *pCaptureCB);
+} HWCInPin;
+
+static inline HWCInPin *impl_from_IPin(IPin *iface)
+{
+    return CONTAINING_RECORD(iface, HWCInPin, IPin_iface);
+}
+
+static inline HWCInPin *impl_from_IMemInputPin(IMemInputPin *iface)
+{
+    return CONTAINING_RECORD(iface, HWCInPin, IMemInputPin_iface);
+}
+
+static STDMETHODIMP HWCPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
+{
+    HWCInPin *This = impl_from_IPin(iface);
+
+    if (IsEqualIID(riid, &IID_IUnknown)) {
+        *ppv = (IUnknown *)(&This->IPin_iface);
+        IPin_AddRef((IPin *)*ppv);
+    } else if (IsEqualIID(riid, &IID_IPin)) {
+        *ppv = (IPin *)(&This->IPin_iface);
+        IPin_AddRef((IPin *)*ppv);
+    } else if (IsEqualIID(riid, &IID_IMemInputPin)) {
+        *ppv = (IMemInputPin *)(&This->IMemInputPin_iface);
+        IPin_AddRef((IMemInputPin *)*ppv);
+    } else {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    return S_OK;
+}
+
+static STDMETHODIMP_(ULONG) HWCPin_AddRef(IPin *iface)
+{
+    HWCInPin *This = impl_from_IPin(iface);
+
+    return InterlockedIncrement(&This->m_cRef);
+}
+
+static STDMETHODIMP_(ULONG) HWCPin_Release(IPin *iface)
+{
+    HWCInPin *This = impl_from_IPin(iface);
+
+    if (InterlockedDecrement(&This->m_cRef) == 0) {
+        if (This->m_pCallback) {
+            SAFE_RELEASE(This->m_pCallback);
+        }
+        if (This->m_pConnectedPin) {
+            SAFE_RELEASE(This->m_pConnectedPin);
+        }
+        if (This->m_pAllocator) {
+            IMemAllocator_Decommit(This->m_pAllocator);
+            SAFE_RELEASE(This->m_pAllocator);
+        }
+        g_free((void *)This);
+        This = NULL;
+        return 0;
+    }
+    return This->m_cRef;
+}
+
+static STDMETHODIMP HWCPin_Connect(IPin *iface,
+                                   IPin *pReceivePin,
+                                   const AM_MEDIA_TYPE *pmt)
+{
+    HWCInPin *This = impl_from_IPin(iface);
+
+    if (!pReceivePin) {
+        return E_POINTER;
+    }
+
+    if (This->m_pConnectedPin) {
+        return VFW_E_ALREADY_CONNECTED;
+    }
+
+    if (!pmt) {
+        return S_OK;
+    }
+    return S_FALSE;
+}
+
+static STDMETHODIMP HWCPin_ReceiveConnection(IPin *iface, IPin *pConnector,
+                                             const AM_MEDIA_TYPE *pmt)
+{
+    PIN_DIRECTION pd;
+    FILTER_STATE fs;
+    HWCInPin *This = impl_from_IPin(iface);
+
+    if (pConnector == NULL || pmt == NULL) {
+        return E_POINTER;
+    }
+
+    if (This->m_pConnectedPin) {
+        return VFW_E_ALREADY_CONNECTED;
+    }
+    IBaseFilter_GetState(This->m_pCFilter, 0, &fs);
+    if (fs != State_Stopped) {
+        return VFW_E_NOT_STOPPED;
+    }
+    IPin_QueryDirection(pConnector, &pd);
+    if (pd == PINDIR_INPUT) {
+        return VFW_E_INVALID_DIRECTION;
+    }
+
+    This->m_pConnectedPin = pConnector;
+    IPin_AddRef(This->m_pConnectedPin);
+    return S_OK;
+}
+
+static STDMETHODIMP HWCPin_Disconnect(IPin *iface)
+{
+    HWCInPin *This = impl_from_IPin(iface);
+
+    HRESULT hr;
+    FILTER_STATE fs;
+    IBaseFilter_GetState(This->m_pCFilter, 0, &fs);
+    if (fs != State_Stopped) {
+        return VFW_E_NOT_STOPPED;
+    }
+    if (This->m_pConnectedPin == NULL) {
+        hr = S_FALSE;
+    } else {
+        if (This->m_pAllocator) {
+            hr = IMemAllocator_Decommit(This->m_pAllocator);
+            if (FAILED(hr)) {
+                return hr;
+            }
+            SAFE_RELEASE(This->m_pAllocator);
+        }
+        SAFE_RELEASE(This->m_pConnectedPin);
+        hr = S_OK;
+    }
+    return hr;
+}
+
+static STDMETHODIMP HWCPin_ConnectedTo(IPin *iface, IPin **ppPin)
+{
+    HWCInPin *This = impl_from_IPin(iface);
+
+    if (ppPin == NULL) {
+        return E_POINTER;
+    }
+
+    if (This->m_pConnectedPin == NULL) {
+        *ppPin = NULL;
+        return VFW_E_NOT_CONNECTED;
+    } else {
+        *ppPin = This->m_pConnectedPin;
+        IPin_AddRef(This->m_pConnectedPin);
+    }
+    return S_OK;
+}
+
+static STDMETHODIMP HWCPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)
+{
+    if (pmt == NULL) {
+        return E_POINTER;
+    }
+    return VFW_E_NOT_CONNECTED;
+}
+
+static STDMETHODIMP HWCPin_QueryPinInfo(IPin *iface, PIN_INFO *pInfo)
+{
+    HWCInPin *This = impl_from_IPin(iface);
+
+    if (pInfo == NULL) {
+        return E_POINTER;
+    }
+
+    pInfo->pFilter = This->m_pCFilter;
+    if (This->m_pCFilter) {
+        IBaseFilter_AddRef(This->m_pCFilter);
+    }
+    memcpy((void *)pInfo->achName, (void *)HWCPinName, sizeof(HWCPinName));
+    pInfo->dir = PINDIR_INPUT;
+    return S_OK;
+}
+
+static STDMETHODIMP HWCPin_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir)
+{
+    if (pPinDir == NULL) {
+        return E_POINTER;
+    }
+    *pPinDir = PINDIR_INPUT;
+    return S_OK;
+}
+
+static STDMETHODIMP HWCPin_QueryId(IPin *iface, LPWSTR *Id)
+{
+    PVOID pId;
+    if (Id == NULL) {
+        return E_POINTER;
+    }
+    pId = CoTaskMemAlloc(sizeof(HWCPinName));
+    memcpy((void *)pId, (void *)HWCPinName, sizeof(HWCPinName));
+    *Id = (LPWSTR)pId;
+    return S_OK;
+}
+
+static STDMETHODIMP HWCPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)
+{
+    if (pmt == NULL) {
+        return E_POINTER;
+    }
+    return S_OK;
+}
+
+static STDMETHODIMP HWCPin_EnumMediaTypes(IPin *iface,
+                                          IEnumMediaTypes **ppEnum)
+{
+    if (ppEnum == NULL) {
+            return E_POINTER;
+    }
+    return E_NOTIMPL;
+}
+
+static STDMETHODIMP HWCPin_QueryInternalConnections(IPin *iface,
+                                                    IPin **ppPin,
+                                                    ULONG *nPin)
+{
+    return E_NOTIMPL;
+}
+
+static STDMETHODIMP HWCPin_EndOfStream(IPin *iface)
+{
+    return S_OK;
+}
+
+static STDMETHODIMP HWCPin_BeginFlush(IPin *iface)
+{
+    return S_OK;
+}
+
+static STDMETHODIMP HWCPin_EndFlush(IPin *iface)
+{
+    return S_OK;
+}
+
+static STDMETHODIMP HWCPin_NewSegment(IPin *iface, REFERENCE_TIME tStart,
+                                      REFERENCE_TIME tStop, double dRate)
+{
+    return S_OK;
+}
+
+static STDMETHODIMP HWCMemInputPin_QueryInterface(IMemInputPin *iface,
+                                                  REFIID riid, void **ppv)
+{
+    HWCInPin *This = impl_from_IMemInputPin(iface);
+
+    if (IsEqualIID(riid, &IID_IUnknown)) {
+        *ppv = (IUnknown *)(&This->IMemInputPin_iface);
+        IPin_AddRef((IPin *)*ppv);
+    } else if (IsEqualIID(riid, &IID_IPin)) {
+        *ppv = (IPin *)(&This->IPin_iface);
+        IPin_AddRef((IPin *)*ppv);
+    } else if (IsEqualIID(riid, &IID_IMemInputPin)) {
+        *ppv = (IMemInputPin *)(&This->IMemInputPin_iface);
+        IPin_AddRef((IMemInputPin *)*ppv);
+    } else {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    return S_OK;
+}
+
+static STDMETHODIMP_(ULONG) HWCMemInputPin_AddRef(IMemInputPin *iface)
+{
+    HWCInPin *This = impl_from_IMemInputPin(iface);
+
+    return InterlockedIncrement(&This->m_cRef);
+}
+
+static STDMETHODIMP_(ULONG) HWCMemInputPin_Release(IMemInputPin *iface)
+{
+    HWCInPin *This = impl_from_IMemInputPin(iface);
+
+    if (InterlockedDecrement(&This->m_cRef) == 0) {
+        if (This->m_pCallback) {
+            SAFE_RELEASE(This->m_pCallback);
+        }
+        if (This->m_pConnectedPin) {
+            SAFE_RELEASE(This->m_pConnectedPin);
+        }
+        if (This->m_pAllocator) {
+            IMemAllocator_Decommit(This->m_pAllocator);
+            SAFE_RELEASE(This->m_pAllocator);
+        }
+        g_free((void *)This);
+        This = NULL;
+        return 0;
+    }
+    return This->m_cRef;
+}
+
+static STDMETHODIMP HWCMemInputPin_GetAllocator(IMemInputPin *iface,
+                                                IMemAllocator **ppAllocator)
+{
+    HWCInPin *This = impl_from_IMemInputPin(iface);
+
+    if (ppAllocator == NULL) {
+        return E_POINTER;
+    }
+
+    if (This->m_pAllocator == NULL) {
+        HRESULT hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL,
+                                        CLSCTX_INPROC_SERVER,
+                                        &IID_IMemAllocator,
+                                        (void **)&(This->m_pAllocator));
+        if (FAILED(hr)) {
+            ERR("Failed to CoCreateInstance for retrieving MemoryAllocator\n");
+            return hr;
+        }
+    }
+    ASSERT(This->m_pAllocator != NULL);
+    *ppAllocator = This->m_pAllocator;
+    IMemAllocator_AddRef(This->m_pAllocator);
+
+    return S_OK;
+}
+
+static STDMETHODIMP HWCMemInputPin_NotifyAllocator(IMemInputPin *iface,
+                                                   IMemAllocator *pAllocator,
+                                                   BOOL bReadOnly)
+{
+    HWCInPin *This = impl_from_IMemInputPin(iface);
+
+    if (pAllocator == NULL) {
+        return E_POINTER;
+    }
+
+    IMemAllocator *pOldAllocator = This->m_pAllocator;
+    IMemAllocator_AddRef(pAllocator);
+    This->m_pAllocator = pAllocator;
+
+    if (pOldAllocator != NULL) {
+        SAFE_RELEASE(pOldAllocator);
+    }
+
+    This->m_bReadOnly = bReadOnly;
+
+    return S_OK;
+}
+
+static STDMETHODIMP HWCMemInputPin_GetAllocatorRequirements(
+                                   IMemInputPin *iface,
+                                   ALLOCATOR_PROPERTIES *pProps)
+{
+    return E_NOTIMPL;
+}
+
+static STDMETHODIMP HWCMemInputPin_Receive(IMemInputPin *iface,
+                                           IMediaSample *pSample)
+{
+    HWCInPin *This = impl_from_IMemInputPin(iface);
+
+    if (pSample == NULL) {
+        ERR("pSample is NULL\n");
+        return E_POINTER;
+    }
+    if (This->m_pCallback != NULL) {
+        HRESULT hr;
+        BYTE *pBuffer = NULL;
+        DWORD dwSize = 0;
+        dwSize = IMediaSample_GetSize(pSample);
+        hr = IMediaSample_GetPointer(pSample, &pBuffer);
+        if (FAILED(hr)) {
+            ERR("Receive function : "
+                "failed to IMediaSample_GetPointer, 0x%ld\n", hr);
+            return hr;
+        }
+        hr = IGrabCallback_Grab(This->m_pCallback, dwSize, pBuffer);
+        if (FAILED(hr)) {
+            ERR("Receive function : failed to IGrabCallback_Grab, 0x%ld\n",
+                hr);
+            return hr;
+        }
+    }
+    return S_OK;
+}
+
+static STDMETHODIMP HWCMemInputPin_ReceiveMultiple(IMemInputPin *iface,
+                                                   IMediaSample **pSamples,
+                                                   long nSamples,
+                                                   long *nSamplesProcessed)
+{
+    HRESULT hr = S_OK;
+
+    if (pSamples == NULL) {
+        return E_POINTER;
+    }
+
+    *nSamplesProcessed = 0;
+
+    while (nSamples-- > 0) {
+        hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
+        if (hr != S_OK) {
+            break;
+        }
+        (*nSamplesProcessed)++;
+    }
+    return hr;
+}
+
+static STDMETHODIMP HWCMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
+{
+    return S_FALSE;
+}
+
+static STDMETHODIMP HWCPin_SetCallback(IPin *iface, IGrabCallback *pCaptureCB)
+{
+    HWCInPin *This = impl_from_IPin(iface);
+
+    if (pCaptureCB == NULL) {
+        SAFE_RELEASE(This->m_pCallback);
+    } else {
+        This->m_pCallback = pCaptureCB;
+        IGrabCallback_AddRef(This->m_pCallback);
+    }
+
+    return S_OK;
+}
+
+
+static IPinVtbl HWCPin_Vtbl = {
+    HWCPin_QueryInterface,
+    HWCPin_AddRef,
+    HWCPin_Release,
+    HWCPin_Connect,
+    HWCPin_ReceiveConnection,
+    HWCPin_Disconnect,
+    HWCPin_ConnectedTo,
+    HWCPin_ConnectionMediaType,
+    HWCPin_QueryPinInfo,
+    HWCPin_QueryDirection,
+    HWCPin_QueryId,
+    HWCPin_QueryAccept,
+    HWCPin_EnumMediaTypes,
+    HWCPin_QueryInternalConnections,
+    HWCPin_EndOfStream,
+    HWCPin_BeginFlush,
+    HWCPin_EndFlush,
+    HWCPin_NewSegment
+};
+
+static IMemInputPinVtbl HWCMemInputPin_Vtbl = {
+    HWCMemInputPin_QueryInterface,
+    HWCMemInputPin_AddRef,
+    HWCMemInputPin_Release,
+    HWCMemInputPin_GetAllocator,
+    HWCMemInputPin_NotifyAllocator,
+    HWCMemInputPin_GetAllocatorRequirements,
+    HWCMemInputPin_Receive,
+    HWCMemInputPin_ReceiveMultiple,
+    HWCMemInputPin_ReceiveCanBlock
+};
+
+static STDMETHODIMP HWCInPin_Construct(IBaseFilter *pFilter, IPin **ppv)
+{
+    HWCInPin *This = (HWCInPin *)g_malloc0(sizeof(HWCInPin));
+
+    if (!This) {
+        ERR("failed to HWCInPin_Construct, E_OUTOFMEMORY\n");
+        return E_OUTOFMEMORY;
+    }
+
+    This->IPin_iface.lpVtbl = &HWCPin_Vtbl;
+    This->IMemInputPin_iface.lpVtbl = &HWCMemInputPin_Vtbl;
+    This->m_bReadOnly = FALSE;
+    This->m_pCFilter = pFilter;
+    This->m_pConnectedPin = NULL;
+    This->m_pCallback = NULL;
+    This->m_pAllocator = NULL;
+    This->m_cRef = 1;
+    This->SetGrabCallbackIF = HWCPin_SetCallback;
+    *ppv = &This->IPin_iface;
+
+    return S_OK;
+}
+
+/*
+ * HWCEnumPins
+ */
+
+typedef struct HWCEnumPins {
+    IEnumPins IEnumPins_iface;
+    IBaseFilter *m_pFilter;
+    int m_nPos;
+    long m_cRef;
+} HWCEnumPins;
+
+static inline HWCEnumPins *impl_from_IEnumPins(IEnumPins *iface)
+{
+    return CONTAINING_RECORD(iface, HWCEnumPins, IEnumPins_iface);
+}
+
+static STDMETHODIMP HWCEnumPins_QueryInterface(IEnumPins *iface,
+                                               REFIID riid, void **ppv)
+{
+    if (ppv == NULL) {
+        return E_POINTER;
+    }
+
+    if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumPins)) {
+        *ppv = iface;
+    } else {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IEnumPins_AddRef(iface);
+    return S_OK;
+}
+
+static STDMETHODIMP_(ULONG) HWCEnumPins_AddRef(IEnumPins *iface)
+{
+    HWCEnumPins *This = impl_from_IEnumPins(iface);
+
+    return InterlockedIncrement(&This->m_cRef);
+}
+
+static STDMETHODIMP_(ULONG) HWCEnumPins_Release(IEnumPins *iface)
+{
+    HWCEnumPins *This = impl_from_IEnumPins(iface);
+
+    if (InterlockedDecrement(&This->m_cRef) == 0) {
+        if (This->m_pFilter) {
+            SAFE_RELEASE(This->m_pFilter);
+        }
+        This->m_nPos = 0;
+        g_free((void *)This);
+        This = NULL;
+        return 0;
+    }
+    return This->m_cRef;
+}
+
+static STDMETHODIMP HWCEnumPins_Next(IEnumPins *iface, ULONG cPins,
+                                     IPin **ppPins, ULONG *pcFetched)
+{
+    ULONG fetched;
+    HWCEnumPins *This = impl_from_IEnumPins(iface);
+
+    if (ppPins == NULL) {
+        return E_POINTER;
+    }
+
+    if (This->m_nPos < 1 && cPins > 0) {
+        IPin *pPin;
+        IBaseFilter_FindPin(This->m_pFilter, HWCPinName, &pPin);
+        *ppPins = pPin;
+        fetched = 1;
+        This->m_nPos++;
+    } else {
+        fetched = 0;
+    }
+
+    if (pcFetched != NULL) {
+        *pcFetched = fetched;
+    }
+
+    return (fetched == cPins) ? S_OK : S_FALSE;
+}
+
+static STDMETHODIMP HWCEnumPins_Skip(IEnumPins *iface, ULONG cPins)
+{
+    HWCEnumPins *This = impl_from_IEnumPins(iface);
+    This->m_nPos += cPins;
+    return (This->m_nPos >= 1) ? S_FALSE : S_OK;
+}
+
+static STDMETHODIMP HWCEnumPins_Reset(IEnumPins *iface)
+{
+    HWCEnumPins *This = impl_from_IEnumPins(iface);
+    This->m_nPos = 0;
+    return S_OK;
+}
+
+static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter,
+                                          int nPos, IEnumPins **ppv);
+
+static STDMETHODIMP HWCEnumPins_Clone(IEnumPins *iface, IEnumPins **ppEnum)
+{
+    HWCEnumPins *This = impl_from_IEnumPins(iface);
+
+    if (ppEnum == NULL) {
+        return E_POINTER;
+    }
+
+    HWCEnumPins_Construct(This->m_pFilter, This->m_nPos, ppEnum);
+    if (*ppEnum == NULL) {
+        ERR("failed to HWCEnumPins_Construct in clone, E_OUTOFMEMORY\n");
+        return E_OUTOFMEMORY;
+    }
+
+    return S_OK;
+}
+
+static IEnumPinsVtbl HWCEnumPins_Vtbl = {
+    HWCEnumPins_QueryInterface,
+    HWCEnumPins_AddRef,
+    HWCEnumPins_Release,
+    HWCEnumPins_Next,
+    HWCEnumPins_Skip,
+    HWCEnumPins_Reset,
+    HWCEnumPins_Clone
+};
+
+
+static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter,
+                                          int nPos, IEnumPins **ppv)
+{
+    HWCEnumPins *This = (HWCEnumPins *)g_malloc0(sizeof(HWCEnumPins));
+
+    if (!This) {
+        ERR("failed to HWCEnumPins_Construct, E_OUTOFMEMORY\n");
+        return E_OUTOFMEMORY;
+    }
+
+    This->IEnumPins_iface.lpVtbl = &HWCEnumPins_Vtbl;
+    This->m_pFilter = pFilter;
+    if (This->m_pFilter) {
+        IBaseFilter_AddRef(This->m_pFilter);
+    }
+    This->m_cRef = 1;
+    This->m_nPos = nPos;
+    *ppv = &This->IEnumPins_iface;
+
+    return S_OK;
+}
+
+/*
+ * HWCFilter
+ */
+
+typedef struct HWCFilter {
+    IBaseFilter IBaseFilter_iface;
+    IPin *m_pPin;
+    IFilterGraph *m_pFilterGraph;
+    FILTER_STATE m_state;
+    long m_cRef;
+} HWCFilter;
+
+static inline HWCFilter *impl_from_IBaseFilter(IBaseFilter *iface)
+{
+    return CONTAINING_RECORD(iface, HWCFilter, IBaseFilter_iface);
+}
+
+static STDMETHODIMP HWCFilter_QueryInterface(IBaseFilter *iface,
+                                             REFIID riid, void **ppv)
+{
+    if (IsEqualIID(riid, &IID_IUnknown)) {
+        *ppv = (IUnknown *)iface;
+    } else if (IsEqualIID(riid, &IID_IPersist)) {
+        *ppv = (IPersist *)iface;
+    } else if (IsEqualIID(riid, &IID_IMediaFilter)) {
+        *ppv = (IMediaFilter *)iface;
+    } else if (IsEqualIID(riid, &IID_IBaseFilter)) {
+        *ppv = (IBaseFilter *)iface;
+    } else {
+        *ppv = NULL;
+        return E_NOINTERFACE;
+    }
+
+    IBaseFilter_AddRef(iface);
+    return S_OK;
+}
+
+static STDMETHODIMP_(ULONG) HWCFilter_AddRef(IBaseFilter *iface)
+{
+    HWCFilter *This = impl_from_IBaseFilter(iface);
+
+    return InterlockedIncrement(&This->m_cRef);
+}
+
+static STDMETHODIMP_(ULONG) HWCFilter_Release(IBaseFilter *iface)
+{
+    HWCFilter *This = impl_from_IBaseFilter(iface);
+
+    if (InterlockedDecrement(&This->m_cRef) == 0) {
+        if (This->m_pPin) {
+            SAFE_RELEASE(This->m_pPin);
+        }
+        g_free((void *)This);
+        This = NULL;
+        return 0;
+    }
+    return This->m_cRef;
+}
+
+static STDMETHODIMP HWCFilter_GetClassID(IBaseFilter *iface, CLSID *pClsID)
+{
+    if (pClsID == NULL) {
+        return E_POINTER;
+    }
+    return E_NOTIMPL;
+}
+
+static STDMETHODIMP HWCFilter_GetState(IBaseFilter *iface, DWORD dwMSecs,
+                                       FILTER_STATE *State)
+{
+    HWCFilter *This = impl_from_IBaseFilter(iface);
+    *State = This->m_state;
+    return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_SetSyncSource(IBaseFilter *iface,
+                                            IReferenceClock *pClock)
+{
+    return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_GetSyncSource(IBaseFilter *iface,
+                                            IReferenceClock **pClock)
+{
+    *pClock = NULL;
+    return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_Stop(IBaseFilter *iface)
+{
+    HWCFilter *This = impl_from_IBaseFilter(iface);
+
+    IPin_EndFlush(This->m_pPin);
+    This->m_state = State_Stopped;
+    return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_Pause(IBaseFilter *iface)
+{
+    HWCFilter *This = impl_from_IBaseFilter(iface);
+    This->m_state = State_Paused;
+    return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
+{
+    HWCFilter *This = impl_from_IBaseFilter(iface);
+
+    if (This->m_state == State_Stopped) {
+        HRESULT hr;
+        hr = IBaseFilter_Pause(iface);
+        if (FAILED(hr)) {
+            ERR("HWCFilter_Run : Failed to IBaseFilter_Pause, ret=0xld%\n", hr);
+            return hr;
+        }
+    }
+
+    This->m_state = State_Running;
+    return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum)
+{
+    if (ppEnum == NULL) {
+        return E_POINTER;
+    }
+
+    HWCEnumPins_Construct(iface, 0, ppEnum);
+    return *ppEnum == NULL ? E_OUTOFMEMORY : S_OK;
+}
+
+static STDMETHODIMP HWCFilter_FindPin(IBaseFilter *iface, LPCWSTR Id,
+                                      IPin **ppPin)
+{
+    HWCFilter *This = impl_from_IBaseFilter(iface);
+
+    if (ppPin == NULL) {
+        return E_POINTER;
+    }
+
+    if (memcmp((void *)Id, (void *)HWCPinName, sizeof(HWCPinName))) {
+        return VFW_E_NOT_FOUND;
+    }
+
+    if (!This->m_pPin) {
+        HWCInPin_Construct(iface, &This->m_pPin);
+    }
+    *ppPin = This->m_pPin;
+
+    IPin_AddRef(This->m_pPin);
+    return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_QueryFilterInfo(IBaseFilter *iface,
+                                              FILTER_INFO *pInfo)
+{
+    HWCFilter *This = impl_from_IBaseFilter(iface);
+
+    if (pInfo == NULL) {
+        return E_POINTER;
+    }
+
+    memcpy((void *)pInfo->achName,
+           (void *)HWCFilterName,
+           sizeof(HWCFilterName));
+    pInfo->pGraph = This->m_pFilterGraph;
+    if (This->m_pFilterGraph) {
+        IFilterGraph_AddRef(This->m_pFilterGraph);
+    }
+    return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_JoinFilterGraph(IBaseFilter *iface,
+                                              IFilterGraph *pGraph,
+                                              LPCWSTR pName)
+{
+    HWCFilter *This = impl_from_IBaseFilter(iface);
+
+    This->m_pFilterGraph = pGraph;
+    return S_OK;
+}
+
+static STDMETHODIMP HWCFilter_QueryVendorInfo(IBaseFilter *iface,
+                                              LPWSTR *pVendorInfo)
+{
+    return E_NOTIMPL;
+}
+
+static IBaseFilterVtbl HWCFilter_Vtbl = {
+    HWCFilter_QueryInterface,
+    HWCFilter_AddRef,
+    HWCFilter_Release,
+    HWCFilter_GetClassID,
+    HWCFilter_Stop,
+    HWCFilter_Pause,
+    HWCFilter_Run,
+    HWCFilter_GetState,
+    HWCFilter_SetSyncSource,
+    HWCFilter_GetSyncSource,
+    HWCFilter_EnumPins,
+    HWCFilter_FindPin,
+    HWCFilter_QueryFilterInfo,
+    HWCFilter_JoinFilterGraph,
+    HWCFilter_QueryVendorInfo
+};
+
+static STDMETHODIMP HWCFilter_Construct(IBaseFilter **ppv)
+{
+    HWCFilter *This = (HWCFilter *)g_malloc0(sizeof(HWCFilter));
+
+    if (!This) {
+        ERR("failed to HWCFilter_Construct, E_OUTOFMEMORY\n");
+        return E_OUTOFMEMORY;
+    }
+
+    This->IBaseFilter_iface.lpVtbl = &HWCFilter_Vtbl;
+    This->m_pFilterGraph = NULL;
+    This->m_state = State_Stopped;
+    This->m_cRef = 1;
+    HWCInPin_Construct(&This->IBaseFilter_iface, &This->m_pPin);
+    *ppv = &This->IBaseFilter_iface;
+
+    return S_OK;
+}
+
+/**********************************************************
+ *
+ * Virtual device implementations
+ *
+ **********************************************************/
+
+
+/*
+ * Declaration global variables for Win32 COM Interfaces
+ */
+IGraphBuilder *g_pGB ;
+ICaptureGraphBuilder2 *g_pCGB;
+IMediaControl *g_pMediaControl;
+
+IPin *g_pOutputPin;
+IPin *g_pInputPin;
+IBaseFilter *g_pDstFilter;
+IBaseFilter *g_pSrcFilter;
+
+IGrabCallback *g_pCallback;
+
+/* V4L2 defines copy from videodev2.h */
+#define V4L2_CTRL_FLAG_SLIDER       0x0020
+
+#define V4L2_CTRL_CLASS_USER        0x00980000
+#define V4L2_CID_BASE               (V4L2_CTRL_CLASS_USER | 0x900)
+#define V4L2_CID_BRIGHTNESS         (V4L2_CID_BASE+0)
+#define V4L2_CID_CONTRAST           (V4L2_CID_BASE+1)
+#define V4L2_CID_SATURATION         (V4L2_CID_BASE+2)
+#define V4L2_CID_SHARPNESS          (V4L2_CID_BASE+27)
+
+#define V4L2_PIX_FMT_YUYV    MAKEFOURCC('Y', 'U', 'Y', 'V') /* 16  YUV 4:2:2 */
+#define V4L2_PIX_FMT_YUV420  MAKEFOURCC('Y', 'U', '1', '2') /* 12  YUV 4:2:0 */
+#define V4L2_PIX_FMT_YVU420  MAKEFOURCC('Y', 'V', '1', '2') /* 12  YVU 4:2:0 */
+#define V4L2_PIX_FMT_RGB24   MAKEFOURCC('R', 'G', 'B', '3') /* 24  RGB-8-8-8 */
+
+typedef struct tagMaruCamConvertPixfmt {
+    uint32_t fmt;   /* fourcc */
+    uint32_t bpp;   /* bits per pixel, 0 for compressed formats */
+    uint32_t needs_conversion;
+} MaruCamConvertPixfmt;
+
+static MaruCamConvertPixfmt supported_dst_pixfmts[] = {
+        { V4L2_PIX_FMT_YUYV, 16, 0 },
+        { V4L2_PIX_FMT_YUV420, 12, 0 },
+        { V4L2_PIX_FMT_YVU420, 12, 0 },
+};
+
+typedef struct tagMaruCamConvertFrameInfo {
+    uint32_t width;
+    uint32_t height;
+} MaruCamConvertFrameInfo;
+
+static MaruCamConvertFrameInfo supported_dst_frames[] = {
+        { 640, 480 },
+        { 352, 288 },
+        { 320, 240 },
+        { 176, 144 },
+        { 160, 120 },
+};
+
+#define MARUCAM_CTRL_VALUE_MAX      20
+#define MARUCAM_CTRL_VALUE_MIN      1
+#define MARUCAM_CTRL_VALUE_MID      10
+#define MARUCAM_CTRL_VALUE_STEP     1
+
+struct marucam_qctrl {
+    uint32_t id;
+    uint32_t hit;
+    long min;
+    long max;
+    long step;
+    long init_val;
+};
+
+static struct marucam_qctrl qctrl_tbl[] = {
+    { V4L2_CID_BRIGHTNESS, 0, },
+    { V4L2_CID_CONTRAST, 0, },
+    { V4L2_CID_SATURATION, 0, },
+    { V4L2_CID_SHARPNESS, 0, },
+};
+
+static MaruCamState *g_state;
+
+static uint32_t ready_count;
+static uint32_t cur_fmt_idx;
+static uint32_t cur_frame_idx;
+static void *grab_buf;
+static uint32_t g_dwSrcFmt;
+
+
+/*
+ * Helper functions - converting image formats, converting values
+ */
+
+static uint32_t get_bytesperline(uint32_t pixfmt, uint32_t width)
+{
+    uint32_t bytesperline;
+
+    switch (pixfmt) {
+    case V4L2_PIX_FMT_YUV420:
+    case V4L2_PIX_FMT_YVU420:
+        bytesperline = (width * 12) >> 3;
+        break;
+    case V4L2_PIX_FMT_YUYV:
+    default:
+        bytesperline = width * 2;
+        break;
+    }
+
+    return bytesperline;
+}
+
+static uint32_t get_sizeimage(uint32_t pixfmt, uint32_t width, uint32_t height)
+{
+    return get_bytesperline(pixfmt, width) * height;
+}
+
+void yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
+        uint32_t width, uint32_t height, uint32_t yvu);
+void rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,
+        uint32_t width, uint32_t height, uint32_t yvu);
+void rgb24_to_yuyv(unsigned char *src, unsigned char *dest,
+        uint32_t width, uint32_t height);
+void yuv420_to_yvu420(unsigned char *src, unsigned char *dest,
+        uint32_t width, uint32_t height);
+void yuv420_to_yuyv(unsigned char *src, unsigned char *dest,
+        uint32_t width, uint32_t height);
+
+static long value_convert_from_guest(long min, long max, long value)
+{
+    double rate = 0.0;
+    long dist = 0, ret = 0;
+
+    dist = max - min;
+
+    if (dist < MARUCAM_CTRL_VALUE_MAX) {
+        rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
+        ret = min + (int32_t)(value / rate);
+    } else {
+        rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
+        ret = min + (int32_t)(rate * value);
+    }
+    return ret;
+}
+
+static long value_convert_to_guest(long min, long max, long value)
+{
+    double rate  = 0.0;
+    long dist = 0, ret = 0;
+
+    dist = max - min;
+
+    if (dist < MARUCAM_CTRL_VALUE_MAX) {
+        rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
+        ret = (int32_t)((double)(value - min) * rate);
+    } else {
+        rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
+        ret = (int32_t)((double)(value - min) / rate);
+    }
+
+    return ret;
+}
+
+/*
+ * Callback function for grab frames
+ */
+static STDMETHODIMP marucam_device_callbackfn(ULONG dwSize, BYTE *pBuffer)
+{
+    void *tmp_buf;
+    uint32_t width, height, fmt, imgsize;
+
+    width = supported_dst_frames[cur_frame_idx].width;
+    height = supported_dst_frames[cur_frame_idx].height;
+    fmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
+    imgsize = get_sizeimage(fmt, width, height);
+
+    if (imgsize > (uint32_t)dwSize) {
+        ERR("Image size is mismatched\n");
+        return E_FAIL;
+    }
+
+    switch (g_dwSrcFmt) {
+    case V4L2_PIX_FMT_YUYV:
+        switch (fmt) {
+        case V4L2_PIX_FMT_YUV420:
+            yuyv_to_yuv420(pBuffer, grab_buf, width, height, 0);
+            break;
+        case V4L2_PIX_FMT_YVU420:
+            yuyv_to_yuv420(pBuffer, grab_buf, width, height, 1);
+            break;
+        case V4L2_PIX_FMT_YUYV:
+            memcpy(grab_buf, (void *)pBuffer, (size_t)dwSize);
+            break;
+        default:
+            ERR("Invalid pixel format\n");
+            return E_FAIL;
+        }
+        break;
+    case V4L2_PIX_FMT_RGB24:
+        switch (fmt) {
+        case V4L2_PIX_FMT_YUV420:
+            rgb24_to_yuv420(pBuffer, grab_buf, width, height, 0);
+            break;
+        case V4L2_PIX_FMT_YVU420:
+            rgb24_to_yuv420(pBuffer, grab_buf, width, height, 1);
+            break;
+        case V4L2_PIX_FMT_YUYV:
+            rgb24_to_yuyv(pBuffer, grab_buf, width, height);
+            break;
+        default:
+            ERR("Invalid pixel format\n");
+            return E_FAIL;
+        }
+        break;
+    case V4L2_PIX_FMT_YUV420:
+        switch (fmt) {
+        case V4L2_PIX_FMT_YUV420:
+            memcpy(grab_buf, (void *)pBuffer, (size_t)dwSize);
+            break;
+        case V4L2_PIX_FMT_YVU420:
+            yuv420_to_yvu420(pBuffer, grab_buf, width, height);
+            break;
+        case V4L2_PIX_FMT_YUYV:
+            yuv420_to_yuyv(pBuffer, grab_buf, width, height);
+            break;
+        default:
+            ERR("Invalid pixel format\n");
+            return E_FAIL;
+        }
+        break;
+    default:
+        ERR("Invalid pixel format\n");
+        return E_FAIL;
+    }
+
+    qemu_mutex_lock(&g_state->thread_mutex);
+    if (g_state->streamon) {
+        if (ready_count < MARUCAM_SKIPFRAMES) {
+            /* skip a frame cause first some frame are distorted */
+            ++ready_count;
+            TRACE("skip %d frame\n", ready_count);
+            qemu_mutex_unlock(&g_state->thread_mutex);
+            return S_OK;
+        }
+        if (g_state->req_frame == 0) {
+            TRACE("there is no request\n");
+            qemu_mutex_unlock(&g_state->thread_mutex);
+            return S_OK;
+        }
+        tmp_buf = g_state->vaddr + g_state->buf_size * (g_state->req_frame - 1);
+        memcpy(tmp_buf, grab_buf, g_state->buf_size);
+        g_state->req_frame = 0; /* clear request */
+        g_state->isr |= 0x01;   /* set a flag of rasing a interrupt */
+        qemu_bh_schedule(g_state->tx_bh);
+    }
+    qemu_mutex_unlock(&g_state->thread_mutex);
+    return S_OK;
+}
+
+/*
+ * Internal functions for manipulate interfaces
+ */
+
+static STDMETHODIMP_(void) CloseInterfaces(void)
+{
+    if (g_pMediaControl) {
+        g_pMediaControl->lpVtbl->Stop(g_pMediaControl);
+    }
+
+    if (g_pOutputPin) {
+        g_pOutputPin->lpVtbl->Disconnect(g_pOutputPin);
+    }
+
+    SAFE_RELEASE(g_pGB);
+    SAFE_RELEASE(g_pCGB);
+    SAFE_RELEASE(g_pMediaControl);
+    SAFE_RELEASE(g_pOutputPin);
+    SAFE_RELEASE(g_pInputPin);
+    SAFE_RELEASE(g_pDstFilter);
+    SAFE_RELEASE(g_pSrcFilter);
+    SAFE_RELEASE(g_pCallback);
+}
+
+static STDMETHODIMP_(void) DeleteMediaType(AM_MEDIA_TYPE *pmt)
+{
+    if (pmt == NULL) {
+        return;
+    }
+
+    if (pmt->cbFormat != 0) {
+        CoTaskMemFree((PVOID)pmt->pbFormat);
+        pmt->cbFormat = 0;
+        pmt->pbFormat = NULL;
+    }
+    if (pmt->pUnk != NULL) {
+        pmt->pUnk->lpVtbl->Release(pmt->pUnk);
+        pmt->pUnk = NULL;
+    }
+
+    CoTaskMemFree((PVOID)pmt);
+}
+
+static STDMETHODIMP GetPin(IBaseFilter *pFilter,
+                           PIN_DIRECTION PinDir, IPin **ppPin)
+{
+    HRESULT hr;
+    IEnumPins *pEnum = NULL;
+    IPin *pPin = NULL;
+
+    if (ppPin == NULL) {
+        return E_POINTER;
+    }
+
+    hr = pFilter->lpVtbl->EnumPins(pFilter, &pEnum);
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    while (pEnum->lpVtbl->Next(pEnum, 1, &pPin, 0) == S_OK) {
+        PIN_DIRECTION PinDirThis;
+        hr = pPin->lpVtbl->QueryDirection(pPin, &PinDirThis);
+        if (FAILED(hr)) {
+            SAFE_RELEASE(pPin);
+            SAFE_RELEASE(pEnum);
+            return hr;
+        }
+        if (PinDir == PinDirThis) {
+            *ppPin = pPin;
+            SAFE_RELEASE(pEnum);
+            return S_OK;
+        }
+        SAFE_RELEASE(pPin);
+    }
+
+    SAFE_RELEASE(pEnum);
+    return S_FALSE;
+}
+
+static STDMETHODIMP GraphBuilder_Init(void)
+{
+    HRESULT hr;
+
+    hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC,
+                          &IID_IGraphBuilder, (void **)&g_pGB);
+    if (FAILED(hr)) {
+        ERR("Failed to create instance of GraphBuilder, 0x%x\n", hr);
+        return hr;
+    }
+
+    hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,
+                          &IID_ICaptureGraphBuilder2, (void **)&g_pCGB);
+    if (FAILED(hr)) {
+        ERR("Failed to create instance of CaptureGraphBuilder2, 0x%x\n", hr);
+        return hr;
+    }
+
+    hr = g_pCGB->lpVtbl->SetFiltergraph(g_pCGB, g_pGB);
+    if (FAILED(hr)) {
+        ERR("Failed to SetFiltergraph, 0x%x\n", hr);
+        return hr;
+    }
+
+    hr = g_pGB->lpVtbl->QueryInterface(g_pGB, &IID_IMediaControl,
+                                       (void **)&g_pMediaControl);
+    if (FAILED(hr)) {
+        ERR("Failed to QueryInterface for IMediaControl, 0x%x\n", hr);
+        return hr;
+    }
+
+    hr = HWCGrabCallback_Construct(&g_pCallback);
+    if (g_pCallback == NULL) {
+        hr = E_OUTOFMEMORY;
+    }
+
+    hr = ((HWCGrabCallback *)g_pCallback)->SetCallback(g_pCallback,
+                            (CallbackFn)marucam_device_callbackfn);
+
+    return hr;
+}
+
+static STDMETHODIMP BindSourceFilter(void)
+{
+    HRESULT hr;
+    ICreateDevEnum *pCreateDevEnum = NULL;
+    IEnumMoniker *pEnumMK = NULL;
+    IMoniker *pMoniKer;
+
+    hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
+                          &IID_ICreateDevEnum,
+                          (void **)&pCreateDevEnum);
+    if (FAILED(hr)) {
+        ERR("Failed to create instance of CreateDevEnum, 0x%x\n", hr);
+        return hr;
+    }
+
+    hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum,
+                                      &CLSID_VideoInputDeviceCategory,
+                                      &pEnumMK, 0);
+    if (FAILED(hr)) {
+        ERR("Failed to get VideoInputDeviceCategory, 0x%x\n", hr);
+        SAFE_RELEASE(pCreateDevEnum);
+        return hr;
+    }
+
+    if (!pEnumMK) {
+        ERR("ClassEnumerator moniker is NULL\n");
+        SAFE_RELEASE(pCreateDevEnum);
+        return E_FAIL;
+    }
+    pEnumMK->lpVtbl->Reset(pEnumMK);
+
+    hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL);
+    if (hr == S_FALSE) {
+        hr = E_FAIL;
+    }
+    if (SUCCEEDED(hr)) {
+        IPropertyBag *pBag = NULL;
+        hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0,
+                                             &IID_IPropertyBag,
+                                             (void **)&pBag);
+        if (SUCCEEDED(hr)) {
+            VARIANT var;
+            var.vt = VT_BSTR;
+            hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);
+            if (hr == NOERROR) {
+                hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL,
+                                                    &IID_IBaseFilter,
+                                                    (void **)&g_pSrcFilter);
+                if (FAILED(hr)) {
+                    ERR("Counldn't bind moniker to filter object!!\n");
+                } else {
+                    g_pSrcFilter->lpVtbl->AddRef(g_pSrcFilter);
+                }
+                SysFreeString(var.bstrVal);
+            }
+            SAFE_RELEASE(pBag);
+        }
+        SAFE_RELEASE(pMoniKer);
+    }
+
+    if (SUCCEEDED(hr)) {
+        hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pSrcFilter, L"Video Capture");
+        if (hr != S_OK && hr != S_FALSE) {
+            ERR("Counldn't add Video Capture filter to our graph!\n");
+            SAFE_RELEASE(g_pSrcFilter);
+        }
+    }
+    SAFE_RELEASE(pEnumMK);
+    SAFE_RELEASE(pCreateDevEnum);
+
+    return hr;
+}
+
+static STDMETHODIMP BindTargetFilter(void)
+{
+    HRESULT hr;
+    hr = HWCFilter_Construct(&g_pDstFilter);
+
+    if (SUCCEEDED(hr) && g_pDstFilter) {
+        hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pDstFilter, L"HWCFilter");
+        if (FAILED(hr)) {
+            ERR("Counldn't add HWCFilterr to our graph!\n");
+            SAFE_RELEASE(g_pDstFilter);
+        }
+    }
+    return hr;
+}
+
+static STDMETHODIMP ConnectFilters(void)
+{
+    HRESULT hr;
+
+    hr = GetPin(g_pSrcFilter, PINDIR_OUTPUT , &g_pOutputPin);
+    if (FAILED(hr)) {
+        ERR("Failed to get output pin. 0x%x\n", hr);
+        return hr;
+    }
+
+    hr = GetPin(g_pDstFilter, PINDIR_INPUT , &g_pInputPin);
+    if (FAILED(hr)) {
+        ERR("Failed to get input pin. 0x%x\n", hr);
+        return hr;
+    }
+
+    hr = g_pGB->lpVtbl->Connect(g_pGB, g_pOutputPin, g_pInputPin);
+    if (FAILED(hr)) {
+        ERR("Failed to connect pins. 0x%x\n", hr);
+    }
+    return hr;
+}
+
+static STDMETHODIMP DisconnectPins(void)
+{
+    HRESULT hr;
+
+    hr = g_pGB->lpVtbl->Disconnect(g_pGB, g_pOutputPin);
+    if (FAILED(hr)) {
+        ERR("Failed to disconnect output pin. 0x%x\n", hr);
+        return hr;
+    }
+
+    hr = g_pGB->lpVtbl->Disconnect(g_pGB, g_pInputPin);
+    if (FAILED(hr)) {
+        ERR("Failed to disconnect input pin. 0x%x\n", hr);
+    }
+
+    return hr;
+}
+
+static STDMETHODIMP RemoveFilters(void)
+{
+    HRESULT hr;
+
+    hr = g_pGB->lpVtbl->RemoveFilter(g_pGB, g_pSrcFilter);
+    if (FAILED(hr)) {
+        ERR("Failed to remove source filer. 0x%x\n", hr);
+        return hr;
+    }
+
+    hr = g_pGB->lpVtbl->RemoveFilter(g_pGB, g_pDstFilter);
+    if (FAILED(hr)) {
+        ERR("Failed to remove destination filer. 0x%x\n", hr);
+    }
+
+    return hr;
+}
+
+/* default fps is 15 */
+#define MARUCAM_DEFAULT_FRAMEINTERVAL    666666
+
+static STDMETHODIMP SetFormat(uint32_t dwWidth, uint32_t dwHeight,
+                              uint32_t dwDstFmt, uint32_t *dwSrcFmt)
+{
+    HRESULT hr;
+    IAMStreamConfig *pSConfig;
+    int iCount = 0, iSize = 0;
+    DWORD dwYUY2 = MAKEFOURCC('Y', 'U', 'Y', '2');
+    DWORD dwI420 = MAKEFOURCC('I', '4', '2', '0');
+
+    if (dwSrcFmt == NULL) {
+        ERR("invalid the source format pointer\n");
+        return E_FAIL;
+    }
+
+    hr = g_pCGB->lpVtbl->FindInterface(g_pCGB, &PIN_CATEGORY_CAPTURE, 0,
+                                       g_pSrcFilter, &IID_IAMStreamConfig,
+                                       (void **)&pSConfig);
+    if (FAILED(hr)) {
+        ERR("failed to FindInterface method\n");
+        return hr;
+    }
+
+    hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);
+    if (FAILED(hr)) {
+        ERR("failed to GetNumberOfCapabilities method\n");
+        SAFE_RELEASE(pSConfig);
+        return hr;
+    }
+
+    if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
+        int iFormat = 0;
+        for (iFormat = 0; iFormat < iCount; iFormat++) {
+            VIDEO_STREAM_CONFIG_CAPS scc;
+            AM_MEDIA_TYPE *pmtConfig;
+
+            hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat,
+                                                 &pmtConfig, (BYTE *)&scc);
+            if (hr == S_OK) {
+                if (IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo)) {
+                    VIDEOINFOHEADER *pvi =
+                                         (VIDEOINFOHEADER *)pmtConfig->pbFormat;
+                    if ((pvi->bmiHeader.biWidth == (LONG)dwWidth) &&
+                        (pvi->bmiHeader.biHeight == (LONG)dwHeight)) {
+                        if (pvi->bmiHeader.biCompression == dwYUY2) {
+                            *dwSrcFmt = V4L2_PIX_FMT_YUYV;
+                        } else if ((pvi->bmiHeader.biCompression == BI_RGB) &&
+                                (pvi->bmiHeader.biBitCount == 24)) {
+                            *dwSrcFmt = V4L2_PIX_FMT_RGB24;
+                        } else if (pvi->bmiHeader.biCompression == dwI420) {
+                            *dwSrcFmt = V4L2_PIX_FMT_YUV420;
+                        } else { /* not support format */
+                            DeleteMediaType(pmtConfig);
+                            continue;
+                        }
+                        /* use minimum FPS(maximum frameinterval)
+                           with non-VT system  */
+#ifdef CONFIG_HAX
+                        if (!hax_enabled()) {
+                            pvi->AvgTimePerFrame =
+                                    (REFERENCE_TIME)scc.MaxFrameInterval;
+                        } else {
+                            pvi->AvgTimePerFrame =
+                                (REFERENCE_TIME)MARUCAM_DEFAULT_FRAMEINTERVAL;
+                        }
+#else
+                        pvi->AvgTimePerFrame =
+                                (REFERENCE_TIME)scc.MaxFrameInterval;
+#endif
+                        hr = pSConfig->lpVtbl->SetFormat(pSConfig, pmtConfig);
+                        DeleteMediaType(pmtConfig);
+                        break;
+                    }
+                }
+                DeleteMediaType(pmtConfig);
+            }
+        }
+        if (iFormat >= iCount) {
+            ERR("Failed to Set format. "
+                "Maybe connected webcam does not support the (%ldx%ld) "
+                "resolution or image formats(YUY2, RGB24, I420).\n",
+                dwWidth, dwHeight);
+            hr = E_FAIL;
+        }
+    }
+    SAFE_RELEASE(pSConfig);
+    return hr;
+}
+
+static STDMETHODIMP QueryVideoProcAmp(long nProperty, long *pMin, long *pMax,
+                                      long *pStep, long *pDefault)
+{
+    HRESULT hr;
+    long Flags;
+    IAMVideoProcAmp *pProcAmp = NULL;
+
+    hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
+                                              &IID_IAMVideoProcAmp,
+                                              (void **)&pProcAmp);
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    hr = pProcAmp->lpVtbl->GetRange(pProcAmp, nProperty, pMin, pMax,
+                                    pStep, pDefault, &Flags);
+
+    SAFE_RELEASE(pProcAmp);
+    return hr;
+}
+
+static STDMETHODIMP GetVideoProcAmp(long nProperty, long *pValue)
+{
+    HRESULT hr;
+    long Flags;
+    IAMVideoProcAmp *pProcAmp = NULL;
+
+    hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
+                                              &IID_IAMVideoProcAmp,
+                                              (void **)&pProcAmp);
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    hr = pProcAmp->lpVtbl->Get(pProcAmp, nProperty, pValue, &Flags);
+    if (FAILED(hr)) {
+        ERR("Failed to get property for video\n");
+    }
+
+    SAFE_RELEASE(pProcAmp);
+    return hr;
+}
+
+static STDMETHODIMP SetVideoProcAmp(long nProperty, long value)
+{
+    HRESULT hr;
+
+    IAMVideoProcAmp *pProcAmp = NULL;
+    hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
+                                              &IID_IAMVideoProcAmp,
+                                              (void **)&pProcAmp);
+    if (FAILED(hr)) {
+        return hr;
+    }
+
+    hr = pProcAmp->lpVtbl->Set(pProcAmp, nProperty, value,
+                               VideoProcAmp_Flags_Manual);
+    if (FAILED(hr)) {
+        ERR("Failed to set property for video\n");
+    }
+    SAFE_RELEASE(pProcAmp);
+    return hr;
+}
+
+static char *__wchar_to_char(const WCHAR *pwstr)
+{
+    char *pstr = NULL;
+    int len = 0;
+
+    len = wcslen(pwstr) + 1;
+    pstr = (char *)g_malloc0(sizeof(char) * len);
+    wcstombs(pstr, pwstr, len + 1);
+
+    return pstr;
+}
+
+int marucam_device_check(int log_flag)
+{
+    struct timeval t1, t2;
+    int ret = 0;
+    char *device_name = NULL;
+    HRESULT hr = E_FAIL;
+    ICreateDevEnum *pCreateDevEnum = NULL;
+    IGraphBuilder *pGB = NULL;
+    ICaptureGraphBuilder2 *pCGB = NULL;
+    IBaseFilter *pSrcFilter = NULL;
+    IEnumMoniker *pEnumMK = NULL;
+    IMoniker *pMoniKer = NULL;
+    IAMStreamConfig *pSConfig = NULL;
+    int iCount = 0, iSize = 0;
+
+    gettimeofday(&t1, NULL);
+    hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+    if (FAILED(hr)) {
+        fprintf(stdout, "[Webcam] failed to CoInitailizeEx\n");
+        gettimeofday(&t2, NULL);
+        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+        return ret;
+    }
+
+    hr = CoCreateInstance(&CLSID_FilterGraph, NULL,
+                          CLSCTX_INPROC,
+                          &IID_IGraphBuilder,
+                          (void **)&pGB);
+    if (FAILED(hr)) {
+        fprintf(stdout, "[Webcam] Failed to create GraphBuilder, 0x%x\n", hr);
+        CoUninitialize();
+        gettimeofday(&t2, NULL);
+        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+        return ret;
+    }
+
+    hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL,
+                          CLSCTX_INPROC,
+                          &IID_ICaptureGraphBuilder2,
+                          (void **)&pCGB);
+    if (FAILED(hr)) {
+        fprintf(stdout,
+        "[Webcam] Failed to create CaptureGraphBuilder2, 0x%x\n", hr);
+        SAFE_RELEASE(pGB);
+        CoUninitialize();
+        gettimeofday(&t2, NULL);
+        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+        return ret;
+    }
+
+    hr = pCGB->lpVtbl->SetFiltergraph(pCGB, pGB);
+    if (FAILED(hr)) {
+        fprintf(stdout, "[Webcam] Failed to SetFiltergraph, 0x%x\n", hr);
+        SAFE_RELEASE(pCGB);
+        SAFE_RELEASE(pGB);
+        CoUninitialize();
+        gettimeofday(&t2, NULL);
+        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+        return ret;
+    }
+
+    hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL,
+                          CLSCTX_INPROC,
+                          &IID_ICreateDevEnum,
+                          (void **)&pCreateDevEnum);
+    if (FAILED(hr)) {
+        fprintf(stdout,
+            "[Webcam] failed to create instance of CLSID_SystemDeviceEnum\n");
+        SAFE_RELEASE(pCGB);
+        SAFE_RELEASE(pGB);
+        CoUninitialize();
+        gettimeofday(&t2, NULL);
+        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+        return ret;
+    }
+
+    hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum,
+                                  &CLSID_VideoInputDeviceCategory, &pEnumMK, 0);
+    if (FAILED(hr)) {
+        fprintf(stdout, "[Webcam] failed to create class enumerator\n");
+        SAFE_RELEASE(pCreateDevEnum);
+        SAFE_RELEASE(pCGB);
+        SAFE_RELEASE(pGB);
+        CoUninitialize();
+        gettimeofday(&t2, NULL);
+        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+        return ret;
+    }
+
+    if (!pEnumMK) {
+        fprintf(stdout, "[Webcam] class enumerator is NULL!!\n");
+        SAFE_RELEASE(pCreateDevEnum);
+        SAFE_RELEASE(pCGB);
+        SAFE_RELEASE(pGB);
+        CoUninitialize();
+        gettimeofday(&t2, NULL);
+        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+        return ret;
+    }
+    pEnumMK->lpVtbl->Reset(pEnumMK);
+
+    hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL);
+    if (FAILED(hr) || (hr == S_FALSE)) {
+        fprintf(stdout, "[Webcam] enum moniker returns a invalid value.\n");
+        SAFE_RELEASE(pEnumMK);
+        SAFE_RELEASE(pCreateDevEnum);
+        SAFE_RELEASE(pCGB);
+        SAFE_RELEASE(pGB);
+        CoUninitialize();
+        gettimeofday(&t2, NULL);
+        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+        return ret;
+    }
+
+    IPropertyBag *pBag = NULL;
+    hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0,
+                                         &IID_IPropertyBag,
+                                         (void **)&pBag);
+    if (FAILED(hr)) {
+        fprintf(stdout, "[Webcam] failed to bind to storage.\n");
+        SAFE_RELEASE(pEnumMK);
+        SAFE_RELEASE(pCreateDevEnum);
+        SAFE_RELEASE(pCGB);
+        SAFE_RELEASE(pGB);
+        CoUninitialize();
+        gettimeofday(&t2, NULL);
+        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+        return ret;
+    } else {
+        VARIANT var;
+        var.vt = VT_BSTR;
+        hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);
+        if (hr == S_OK) {
+            ret = 1;
+            if (!log_flag) {
+                SysFreeString(var.bstrVal);
+                SAFE_RELEASE(pBag);
+                SAFE_RELEASE(pMoniKer);
+                SAFE_RELEASE(pEnumMK);
+                SAFE_RELEASE(pCreateDevEnum);
+                SAFE_RELEASE(pCGB);
+                SAFE_RELEASE(pGB);
+                CoUninitialize();
+                gettimeofday(&t2, NULL);
+                fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                                t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+                return ret;
+            }
+            device_name = __wchar_to_char(var.bstrVal);
+            fprintf(stdout, "[Webcam] Device name : %s\n", device_name);
+            g_free(device_name);
+            hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL,
+                                                &IID_IBaseFilter,
+                                                (void **)&pSrcFilter);
+            if (FAILED(hr)) {
+                fprintf(stdout,
+                   "[Webcam] Counldn't bind moniker to filter object!!\n");
+                SysFreeString(var.bstrVal);
+                SAFE_RELEASE(pBag);
+                SAFE_RELEASE(pMoniKer);
+                SAFE_RELEASE(pEnumMK);
+                SAFE_RELEASE(pCreateDevEnum);
+                SAFE_RELEASE(pCGB);
+                SAFE_RELEASE(pGB);
+                CoUninitialize();
+                gettimeofday(&t2, NULL);
+                fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                                t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+                return ret;
+            } else {
+                pSrcFilter->lpVtbl->AddRef(pSrcFilter);
+            }
+            SysFreeString(var.bstrVal);
+        }
+        SAFE_RELEASE(pBag);
+    }
+    SAFE_RELEASE(pMoniKer);
+
+    hr = pGB->lpVtbl->AddFilter(pGB, pSrcFilter, L"Video Capture");
+    if (hr != S_OK && hr != S_FALSE) {
+        fprintf(stdout,
+                "[Webcam] Counldn't add Video Capture filter to our graph!\n");
+        SAFE_RELEASE(pSrcFilter);
+        SAFE_RELEASE(pEnumMK);
+        SAFE_RELEASE(pCreateDevEnum);
+        SAFE_RELEASE(pCGB);
+        SAFE_RELEASE(pGB);
+        CoUninitialize();
+        gettimeofday(&t2, NULL);
+        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+        return ret;
+    }
+
+    hr = pCGB->lpVtbl->FindInterface(pCGB, &PIN_CATEGORY_CAPTURE, 0,
+                                       pSrcFilter, &IID_IAMStreamConfig,
+                                       (void **)&pSConfig);
+    if (FAILED(hr)) {
+        fprintf(stdout, "[Webcam] failed to FindInterface method\n");
+        SAFE_RELEASE(pSrcFilter);
+        SAFE_RELEASE(pEnumMK);
+        SAFE_RELEASE(pCreateDevEnum);
+        SAFE_RELEASE(pCGB);
+        SAFE_RELEASE(pGB);
+        CoUninitialize();
+        gettimeofday(&t2, NULL);
+        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+        return ret;
+    }
+
+    hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);
+    if (FAILED(hr)) {
+        fprintf(stdout, "[Webcam] failed to GetNumberOfCapabilities method\n");
+        SAFE_RELEASE(pSConfig);
+        SAFE_RELEASE(pSrcFilter);
+        SAFE_RELEASE(pEnumMK);
+        SAFE_RELEASE(pCreateDevEnum);
+        SAFE_RELEASE(pCGB);
+        SAFE_RELEASE(pGB);
+        CoUninitialize();
+        gettimeofday(&t2, NULL);
+        fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                        t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+        return ret;
+    }
+
+    if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
+        int iFormat = 0;
+        for (iFormat = 0; iFormat < iCount; iFormat++) {
+            VIDEO_STREAM_CONFIG_CAPS scc;
+            AM_MEDIA_TYPE *pmtConfig;
+
+            hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat, &pmtConfig,
+                                                 (BYTE *)&scc);
+            if (hr == S_OK) {
+                if (IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo)) {
+                    VIDEOINFOHEADER *pvi =
+                                         (VIDEOINFOHEADER *)pmtConfig->pbFormat;
+                    if (pvi->bmiHeader.biCompression == BI_RGB) {
+                        fprintf(stdout, "[Webcam] RGB BitCount: %d, %ux%u\n",
+                                pvi->bmiHeader.biBitCount,
+                                pvi->bmiHeader.biWidth,
+                                pvi->bmiHeader.biHeight);
+                    } else {
+                        fprintf(stdout,
+                                "[Webcam] PixelFormat: %c%c%c%c, %ux%u\n",
+                                (char)(pvi->bmiHeader.biCompression),
+                                (char)(pvi->bmiHeader.biCompression >> 8),
+                                (char)(pvi->bmiHeader.biCompression >> 16),
+                                (char)(pvi->bmiHeader.biCompression >> 24),
+                                pvi->bmiHeader.biWidth,
+                                pvi->bmiHeader.biHeight);
+                    }
+                }
+                DeleteMediaType(pmtConfig);
+            }
+        }
+    }
+
+    hr = pGB->lpVtbl->RemoveFilter(pGB, pSrcFilter);
+    if (FAILED(hr)) {
+        fprintf(stdout, "[Webcam] Failed to remove source filer. 0x%x\n", hr);
+    }
+
+    SAFE_RELEASE(pSConfig);
+    SAFE_RELEASE(pSrcFilter);
+    SAFE_RELEASE(pCGB);
+    SAFE_RELEASE(pGB);
+    SAFE_RELEASE(pEnumMK);
+    SAFE_RELEASE(pCreateDevEnum);
+    CoUninitialize();
+    gettimeofday(&t2, NULL);
+    fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
+                    t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
+
+    return ret;
+}
+
+/* MARUCAM_CMD_INIT */
+void marucam_device_init(MaruCamState *state)
+{
+    g_state = state;
+}
+
+void marucam_device_exit(MaruCamState *state)
+{
+}
+
+/* MARUCAM_CMD_OPEN */
+void marucam_device_open(MaruCamState *state)
+{
+    HRESULT hr;
+    uint32_t dwHeight, dwWidth, dwDstFmt;
+    MaruCamParam *param = state->param;
+    param->top = 0;
+
+    hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
+    if (FAILED(hr)) {
+        ERR("CoInitailizeEx\n");
+        ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
+        param->errCode = EINVAL;
+        return;
+    }
+
+    hr = GraphBuilder_Init();
+    if (FAILED(hr)) {
+        ERR("GraphBuilder_Init\n");
+        DisconnectPins();
+        RemoveFilters();
+        CloseInterfaces();
+        CoUninitialize();
+        param->errCode = EINVAL;
+        ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
+        return;
+    }
+
+    hr = BindSourceFilter();
+    if (FAILED(hr)) {
+        ERR("BindSourceFilter\n");
+        DisconnectPins();
+        RemoveFilters();
+        CloseInterfaces();
+        CoUninitialize();
+        param->errCode = EINVAL;
+        ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
+        return;
+    }
+
+    hr = BindTargetFilter();
+    if (FAILED(hr)) {
+        ERR("BindTargetFilter\n");
+        DisconnectPins();
+        RemoveFilters();
+        CloseInterfaces();
+        CoUninitialize();
+        param->errCode = EINVAL;
+        ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
+        return;
+    }
+
+    hr = ConnectFilters();
+    if (FAILED(hr)) {
+        ERR("ConnectFilters\n");
+        DisconnectPins();
+        RemoveFilters();
+        CloseInterfaces();
+        CoUninitialize();
+        param->errCode = EINVAL;
+        ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
+        return;
+    }
+
+    cur_frame_idx = 0;
+    cur_fmt_idx = 0;
+
+    dwHeight = supported_dst_frames[cur_frame_idx].height;
+    dwWidth = supported_dst_frames[cur_frame_idx].width;
+    dwDstFmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
+    hr = SetFormat(dwWidth, dwHeight, dwDstFmt, &g_dwSrcFmt);
+    if (hr != S_OK) {
+        ERR("failed to Set default values\n");
+        DisconnectPins();
+        RemoveFilters();
+        CloseInterfaces();
+        CoUninitialize();
+        param->errCode = EINVAL;
+        ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
+        return;
+    }
+
+    INFO("Opened\n");
+    return;
+}
+
+/* MARUCAM_CMD_CLOSE */
+void marucam_device_close(MaruCamState *state)
+{
+    MaruCamParam *param = state->param;
+    param->top = 0;
+
+    DisconnectPins();
+    RemoveFilters();
+    CloseInterfaces();
+    CoUninitialize();
+    INFO("Closed\n");
+}
+
+/* MARUCAM_CMD_START_PREVIEW */
+void marucam_device_start_preview(MaruCamState *state)
+{
+    HRESULT hr;
+    uint32_t pixfmt, width, height;
+    MaruCamParam *param = state->param;
+    param->top = 0;
+
+    ready_count = 0;
+    width = supported_dst_frames[cur_frame_idx].width;
+    height = supported_dst_frames[cur_frame_idx].height;
+    pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
+    state->buf_size = get_sizeimage(pixfmt, width, height);
+
+    INFO("Pixfmt(%c%c%c%c), W:H(%d:%d), buf size(%u)\n",
+         (char)(pixfmt), (char)(pixfmt >> 8),
+         (char)(pixfmt >> 16), (char)(pixfmt >> 24),
+         width, height, state->buf_size);
+    INFO("Starting preview\n");
+
+    assert(g_pCallback != NULL);
+    hr = ((HWCInPin *)g_pInputPin)->SetGrabCallbackIF(g_pInputPin,
+                                                       g_pCallback);
+    if (FAILED(hr)) {
+        ERR("Failed to set IGrabCallback interface.\n");
+        param->errCode = EINVAL;
+        return;
+    }
+
+    if (grab_buf) {
+        g_free(grab_buf);
+        grab_buf = NULL;
+    }
+    grab_buf = (void *)g_malloc0(state->buf_size);
+    if (grab_buf == NULL) {
+        param->errCode = ENOMEM;
+        return;
+    }
+
+    hr = g_pMediaControl->lpVtbl->Run(g_pMediaControl);
+    if (FAILED(hr)) {
+        ERR("Failed to run media control. hr=0x%x\n", hr);
+        param->errCode = EINVAL;
+        return;
+    }
+
+    qemu_mutex_lock(&state->thread_mutex);
+    state->streamon = 1;
+    qemu_mutex_unlock(&state->thread_mutex);
+
+    INFO("Streaming on ......\n");
+}
+
+/* MARUCAM_CMD_STOP_PREVIEW */
+void marucam_device_stop_preview(MaruCamState *state)
+{
+    HRESULT hr;
+    MaruCamParam *param = state->param;
+    param->top = 0;
+
+    INFO("...... Streaming off\n");
+    qemu_mutex_lock(&state->thread_mutex);
+    state->streamon = 0;
+    qemu_mutex_unlock(&state->thread_mutex);
+
+    hr = ((HWCInPin *)g_pInputPin)->SetGrabCallbackIF(g_pInputPin, NULL);
+    if (FAILED(hr)) {
+        ERR("Failed to set IGrabCallback interface.\n");
+        param->errCode = EINVAL;
+        return;
+    }
+
+    hr = g_pMediaControl->lpVtbl->Stop(g_pMediaControl);
+    if (FAILED(hr)) {
+        ERR("Failed to stop media control.\n");
+        param->errCode = EINVAL;
+        return;
+    }
+
+    if (grab_buf) {
+        g_free(grab_buf);
+        grab_buf = NULL;
+    }
+    state->buf_size = 0;
+
+    INFO("Stopping preview\n");
+}
+
+/* MARUCAM_CMD_S_PARAM */
+void marucam_device_s_param(MaruCamState *state)
+{
+    MaruCamParam *param = state->param;
+
+    /* We use default FPS of the webcam */
+    param->top = 0;
+}
+
+/* MARUCAM_CMD_G_PARAM */
+void marucam_device_g_param(MaruCamState *state)
+{
+    MaruCamParam *param = state->param;
+
+    /* We use default FPS of the webcam
+     * return a fixed value on guest ini file (1/30).
+     */
+    param->top = 0;
+    param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */
+    param->stack[1] = 1; /* numerator */
+    param->stack[2] = 30; /* denominator */
+}
+
+/* MARUCAM_CMD_S_FMT */
+void marucam_device_s_fmt(MaruCamState *state)
+{
+    uint32_t width, height, pixfmt, pidx, fidx;
+    MaruCamParam *param = state->param;
+
+    param->top = 0;
+    width = param->stack[0];
+    height = param->stack[1];
+    pixfmt = param->stack[2];
+
+    for (fidx = 0; fidx < ARRAY_SIZE(supported_dst_frames); fidx++) {
+        if ((supported_dst_frames[fidx].width == width) &&
+                (supported_dst_frames[fidx].height == height)) {
+            break;
+        }
+    }
+    if (fidx == ARRAY_SIZE(supported_dst_frames)) {
+        param->errCode = EINVAL;
+        return;
+    }
+    for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) {
+        if (supported_dst_pixfmts[pidx].fmt == pixfmt) {
+            break;
+        }
+    }
+    if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {
+        param->errCode = EINVAL;
+        return;
+    }
+
+    if ((supported_dst_frames[cur_frame_idx].width != width) &&
+            (supported_dst_frames[cur_frame_idx].height != height)) {
+        HRESULT hr = SetFormat(width, height, pixfmt, &g_dwSrcFmt);
+        if (FAILED(hr)) {
+            param->errCode = EINVAL;
+            return;
+        }
+    }
+
+    cur_frame_idx = fidx;
+    cur_fmt_idx = pidx;
+
+    pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
+    width = supported_dst_frames[cur_frame_idx].width;
+    height = supported_dst_frames[cur_frame_idx].height;
+
+    param->stack[0] = width;
+    param->stack[1] = height;
+    param->stack[2] = 1; /* V4L2_FIELD_NONE */
+    param->stack[3] = pixfmt;
+    param->stack[4] = get_bytesperline(pixfmt, width);
+    param->stack[5] = get_sizeimage(pixfmt, width, height);
+    param->stack[6] = 0;
+    param->stack[7] = 0;
+
+    TRACE("Set format...\n");
+}
+
+/* MARUCAM_CMD_G_FMT */
+void marucam_device_g_fmt(MaruCamState *state)
+{
+    uint32_t width, height, pixfmt;
+    MaruCamParam *param = state->param;
+
+    param->top = 0;
+    pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
+    width = supported_dst_frames[cur_frame_idx].width;
+    height = supported_dst_frames[cur_frame_idx].height;
+
+    param->stack[0] = width;
+    param->stack[1] = height;
+    param->stack[2] = 1; /* V4L2_FIELD_NONE */
+    param->stack[3] = pixfmt;
+    param->stack[4] = get_bytesperline(pixfmt, width);
+    param->stack[5] = get_sizeimage(pixfmt, width, height);
+    param->stack[6] = 0;
+    param->stack[7] = 0;
+
+    TRACE("Get format...\n");
+}
+
+void marucam_device_try_fmt(MaruCamState *state)
+{
+    uint32_t width, height, pixfmt, i;
+    MaruCamParam *param = state->param;
+
+    param->top = 0;
+    width = param->stack[0];
+    height = param->stack[1];
+    pixfmt = param->stack[2];
+
+    for (i = 0; i < ARRAY_SIZE(supported_dst_frames); i++) {
+        if ((supported_dst_frames[i].width == width) &&
+                (supported_dst_frames[i].height == height)) {
+            break;
+        }
+    }
+    if (i == ARRAY_SIZE(supported_dst_frames)) {
+        param->errCode = EINVAL;
+        return;
+    }
+    for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
+        if (supported_dst_pixfmts[i].fmt == pixfmt) {
+            break;
+        }
+    }
+    if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
+        param->errCode = EINVAL;
+        return;
+    }
+
+    param->stack[0] = width;
+    param->stack[1] = height;
+    param->stack[2] = 1; /* V4L2_FIELD_NONE */
+    param->stack[3] = pixfmt;
+    param->stack[4] = get_bytesperline(pixfmt, width);
+    param->stack[5] = get_sizeimage(pixfmt, width, height);
+    param->stack[6] = 0;
+    param->stack[7] = 0;
+}
+
+void marucam_device_enum_fmt(MaruCamState *state)
+{
+    uint32_t index;
+    MaruCamParam *param = state->param;
+
+    param->top = 0;
+    index = param->stack[0];
+
+    if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
+        param->errCode = EINVAL;
+        return;
+    }
+    param->stack[1] = 0; /* flags = NONE */
+    param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */
+    /* set description */
+    switch (supported_dst_pixfmts[index].fmt) {
+    case V4L2_PIX_FMT_YUYV:
+        memcpy(&param->stack[3], "YUYV", 32);
+        break;
+    case V4L2_PIX_FMT_YUV420:
+        memcpy(&param->stack[3], "YU12", 32);
+        break;
+    case V4L2_PIX_FMT_YVU420:
+        memcpy(&param->stack[3], "YV12", 32);
+        break;
+    default:
+        ERR("Invalid pixel format\n");
+        param->errCode = EINVAL;
+        break;
+    }
+}
+
+void marucam_device_qctrl(MaruCamState *state)
+{
+    HRESULT hr;
+    uint32_t id, i;
+    long property, min, max, step, def_val, set_val;
+    char name[32] = {0,};
+    MaruCamParam *param = state->param;
+
+    param->top = 0;
+    id = param->stack[0];
+
+    switch (id) {
+    case V4L2_CID_BRIGHTNESS:
+        TRACE("V4L2_CID_BRIGHTNESS\n");
+        property = VideoProcAmp_Brightness;
+        memcpy((void *)name, (void *)"brightness", 32);
+        i = 0;
+        break;
+    case V4L2_CID_CONTRAST:
+        TRACE("V4L2_CID_CONTRAST\n");
+        property = VideoProcAmp_Contrast;
+        memcpy((void *)name, (void *)"contrast", 32);
+        i = 1;
+        break;
+    case V4L2_CID_SATURATION:
+        TRACE("V4L2_CID_SATURATION\n");
+        property = VideoProcAmp_Saturation;
+        memcpy((void *)name, (void *)"saturation", 32);
+        i = 2;
+        break;
+    case V4L2_CID_SHARPNESS:
+        TRACE("V4L2_CID_SHARPNESS\n");
+        property = VideoProcAmp_Sharpness;
+        memcpy((void *)name, (void *)"sharpness", 32);
+        i = 3;
+        break;
+    default:
+        ERR("Invalid control ID\n");
+        param->errCode = EINVAL;
+        return;
+    }
+    hr = QueryVideoProcAmp(property, &min, &max, &step, &def_val);
+    if (FAILED(hr)) {
+        param->errCode = EINVAL;
+        ERR("failed to query video controls [HRESULT : 0x%x]\n", hr);
+        return;
+    } else {
+        qctrl_tbl[i].hit = 1;
+        qctrl_tbl[i].min = min;
+        qctrl_tbl[i].max = max;
+        qctrl_tbl[i].step = step;
+        qctrl_tbl[i].init_val = def_val;
+
+        if ((qctrl_tbl[i].min + qctrl_tbl[i].max) == 0) {
+            set_val = 0;
+        } else {
+            set_val = (qctrl_tbl[i].min + qctrl_tbl[i].max) / 2;
+        }
+        hr = SetVideoProcAmp(property, set_val);
+        if (FAILED(hr)) {
+            param->errCode = EINVAL;
+            ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
+            return;
+        }
+    }
+
+    param->stack[0] = id;
+    param->stack[1] = MARUCAM_CTRL_VALUE_MIN;  /* minimum */
+    param->stack[2] = MARUCAM_CTRL_VALUE_MAX;  /* maximum */
+    param->stack[3] = MARUCAM_CTRL_VALUE_STEP; /*  step   */
+    param->stack[4] = MARUCAM_CTRL_VALUE_MID;  /* default_value */
+    param->stack[5] = V4L2_CTRL_FLAG_SLIDER;
+    /* name field setting */
+    memcpy(&param->stack[6], (void *)name, sizeof(name)/sizeof(name[0]));
+}
+
+void marucam_device_s_ctrl(MaruCamState *state)
+{
+    HRESULT hr;
+    uint32_t i;
+    long property, set_val;
+    MaruCamParam *param = state->param;
+
+    param->top = 0;
+
+    switch (param->stack[0]) {
+    case V4L2_CID_BRIGHTNESS:
+        i = 0;
+        property = VideoProcAmp_Brightness;
+        break;
+    case V4L2_CID_CONTRAST:
+        i = 1;
+        property = VideoProcAmp_Contrast;
+        break;
+    case V4L2_CID_SATURATION:
+        i = 2;
+        property = VideoProcAmp_Saturation;
+        break;
+    case V4L2_CID_SHARPNESS:
+        i = 3;
+        property = VideoProcAmp_Sharpness;
+        break;
+    default:
+        param->errCode = EINVAL;
+        return;
+    }
+    set_val = value_convert_from_guest(qctrl_tbl[i].min,
+            qctrl_tbl[i].max, (long)param->stack[1]);
+    hr = SetVideoProcAmp(property, set_val);
+    if (FAILED(hr)) {
+        param->errCode = EINVAL;
+        ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
+        return;
+    }
+}
+
+void marucam_device_g_ctrl(MaruCamState *state)
+{
+    HRESULT hr;
+    uint32_t i;
+    long property, get_val;
+    MaruCamParam *param = state->param;
+
+    param->top = 0;
+    switch (param->stack[0]) {
+    case V4L2_CID_BRIGHTNESS:
+        i = 0;
+        property = VideoProcAmp_Brightness;
+        break;
+    case V4L2_CID_CONTRAST:
+        i = 1;
+        property = VideoProcAmp_Contrast;
+        break;
+    case V4L2_CID_SATURATION:
+        i = 2;
+        property = VideoProcAmp_Saturation;
+        break;
+    case V4L2_CID_SHARPNESS:
+        i = 3;
+        property = VideoProcAmp_Sharpness;
+        break;
+    default:
+        param->errCode = EINVAL;
+        return;
+    }
+
+    hr = GetVideoProcAmp(property, &get_val);
+    if (FAILED(hr)) {
+        param->errCode = EINVAL;
+        ERR("failed to get video control value!!!, [HRESULT : 0x%x]\n", hr);
+        return;
+    }
+    param->stack[0] = (uint32_t)value_convert_to_guest(qctrl_tbl[i].min,
+                qctrl_tbl[i].max, get_val);
+}
+
+void marucam_device_enum_fsizes(MaruCamState *state)
+{
+    uint32_t index, pixfmt, i;
+    MaruCamParam *param = state->param;
+
+    param->top = 0;
+    index = param->stack[0];
+    pixfmt = param->stack[1];
+
+    if (index >= ARRAY_SIZE(supported_dst_frames)) {
+        param->errCode = EINVAL;
+        return;
+    }
+    for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
+        if (supported_dst_pixfmts[i].fmt == pixfmt) {
+            break;
+        }
+    }
+
+    if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
+        param->errCode = EINVAL;
+        return;
+    }
+
+    param->stack[0] = supported_dst_frames[index].width;
+    param->stack[1] = supported_dst_frames[index].height;
+}
+
+void marucam_device_enum_fintv(MaruCamState *state)
+{
+    MaruCamParam *param = state->param;
+
+    param->top = 0;
+
+    /* switch by index(param->stack[0]) */
+    switch (param->stack[0]) {
+    case 0:
+        param->stack[1] = 30; /* denominator */
+        break;
+    default:
+        param->errCode = EINVAL;
+        return;
+    }
+    param->stack[0] = 1; /* numerator */
+}
+
+void yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
+        uint32_t width, uint32_t height, uint32_t yvu)
+{
+    uint32_t i, j;
+    const unsigned char *src1;
+    unsigned char *udest, *vdest;
+
+    /* copy the Y values */
+    src1 = src;
+    for (i = 0; i < height; i++) {
+        for (j = 0; j < width; j += 2) {
+            *dest++ = src1[0];
+            *dest++ = src1[2];
+            src1 += 4;
+        }
+    }
+
+    /* copy the U and V values */
+    src++;              /* point to V */
+    src1 = src + width * 2;     /* next line */
+    if (yvu) {
+        vdest = dest;
+        udest = dest + width * height / 4;
+    } else {
+        udest = dest;
+        vdest = dest + width * height / 4;
+    }
+    for (i = 0; i < height; i += 2) {
+        for (j = 0; j < width; j += 2) {
+            *udest++ = ((int) src[0] + src1[0]) / 2;    /* U */
+            *vdest++ = ((int) src[2] + src1[2]) / 2;    /* V */
+            src += 4;
+            src1 += 4;
+        }
+        src = src1;
+        src1 += width * 2;
+    }
+}
+
+#define RGB2Y(r, g, b, y)   \
+    (y) = ((8453 * (r) + 16594 * (g) + 3223 * (b) + 524288) >> 15)
+
+#define RGB2UV(r, g, b, u, v)   \
+    do {    \
+        (u) = ((-4878 * (r) - 9578 * (g) + 14456 * (b) + 4210688) >> 15);   \
+        (v) = ((14456 * (r) - 12105 * (g) - 2351 * (b) + 4210688) >> 15);   \
+    } while (0)
+
+#define CLIP(color) \
+    (unsigned char)(((color) > 0xFF) ? 0xff : (((color) < 0) ? 0 : (color)))
+
+void rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,
+                     uint32_t width, uint32_t height, uint32_t yvu)
+{
+    uint32_t x, y;
+    unsigned char *udest, *vdest;
+    uint32_t bytesperline = width * 3;
+
+    /* Y */
+    for (y = 0; y < height; y++) {
+        for (x = 0; x < width; x++) {
+            RGB2Y(src[2], src[1], src[0], *dest++);
+            src += 3;
+        }
+        src += bytesperline - 3 * width;
+    }
+    src -= height * bytesperline;
+
+    /* U + V */
+    if (yvu) {
+        vdest = dest;
+        udest = dest + width * height / 4;
+    } else {
+        udest = dest;
+        vdest = dest + width * height / 4;
+    }
+
+    for (y = 0; y < height / 2; y++) {
+        for (x = 0; x < width / 2; x++) {
+            uint32_t avg_src[3];
+
+            avg_src[0] = (src[0] + src[3] + src[bytesperline] +
+                    src[bytesperline + 3]) / 4;
+            avg_src[1] = (src[1] + src[4] + src[bytesperline + 1] +
+                    src[bytesperline + 4]) / 4;
+            avg_src[2] = (src[2] + src[5] + src[bytesperline + 2] +
+                    src[bytesperline + 5]) / 4;
+            RGB2UV(avg_src[2], avg_src[1], avg_src[0], *udest++, *vdest++);
+            src += 6;
+        }
+        src += 2 * bytesperline - 3 * width;
+    }
+}
+
+void rgb24_to_yuyv(unsigned char *src, unsigned char *dest,
+                   uint32_t width, uint32_t height)
+{
+    uint32_t i = 0;
+
+    for (i = 0; i < (width * height * 3); i = i + 6) {
+        /* y */
+        *dest++ = CLIP(0.299 * (src[i + 2] - 128) +
+                    0.587 * (src[i + 1] - 128) +
+                    0.114 * (src[i] - 128) + 128);
+        /* u */
+        *dest++ = CLIP(((-0.147 * (src[i + 2] - 128) -
+                    0.289 * (src[i + 1] - 128) +
+                    0.436 * (src[i] - 128) + 128) +
+                    (-0.147 * (src[i + 5] - 128) -
+                    0.289 * (src[i + 4] - 128) +
+                    0.436 * (src[i + 3] - 128) + 128)) / 2);
+        /* y1 */
+        *dest++ = CLIP(0.299 * (src[i + 5] - 128) +
+                    0.587 * (src[i + 4] - 128) +
+                    0.114 * (src[i + 3] - 128) + 128);
+        /* v */
+        *dest++ = CLIP(((0.615 * (src[i + 2] - 128) -
+                    0.515 * (src[i + 1] - 128) -
+                    0.100 * (src[i] - 128) + 128) +
+                    (0.615 * (src[i + 5] - 128) -
+                    0.515 * (src[i + 4] - 128) -
+                    0.100 * (src[i + 3] - 128) + 128)) / 2);
+    }
+}
+
+void yuv420_to_yvu420(unsigned char *src, unsigned char *dest,
+                      uint32_t width, uint32_t height)
+{
+    unsigned char *psrc_y, *pdst_y;
+    unsigned char *psrc_u, *pdst_u;
+    unsigned char *psrc_v, *pdst_v;
+
+    psrc_y = src;
+    psrc_u = psrc_y + (width * height);
+    psrc_v = psrc_u + (width * height / 4);
+
+    pdst_y = dest;
+    pdst_v = pdst_y + (width * height);
+    pdst_u = pdst_v + (width * height / 4);
+
+    memcpy(pdst_y, psrc_y, width * height);
+    memcpy(pdst_v, psrc_v, width * height / 4);
+    memcpy(pdst_u, psrc_u, width * height / 4);
+}
+
+void yuv420_to_yuyv(unsigned char *src, unsigned char *dest,
+                    uint32_t width, uint32_t height)
+{
+    unsigned char *py;
+    unsigned char *pu;
+    unsigned char *pv;
+
+    uint32_t linesize = width * 2;
+    uint32_t uvlinesize = width / 2;
+    uint32_t offset = 0;
+    uint32_t offset1 = 0;
+    uint32_t offsety = 0;
+    uint32_t offsety1 = 0;
+    uint32_t offsetuv = 0;
+    uint32_t h = 0;
+    uint32_t w = 0;
+    uint32_t wy = 0;
+    uint32_t huv = 0;
+    uint32_t wuv = 0;
+
+    py = src;
+    pu = py + (width * height);
+    pv = pu + (width * height / 4);
+
+    for (h = 0; h < height; h += 2) {
+        wy = 0;
+        wuv = 0;
+        offset = h * linesize;
+        offset1 = (h + 1) * linesize;
+        offsety = h * width;
+        offsety1 = (h + 1) * width;
+        offsetuv = huv * uvlinesize;
+
+        for (w = 0; w < linesize; w += 4) {
+            /* y00 */
+            dest[w + offset] = py[wy + offsety];
+            /* u0 */
+            dest[(w + 1) + offset] = pu[wuv + offsetuv];
+            /* y01 */
+            dest[(w + 2) + offset] = py[(wy + 1) + offsety];
+            /* v0 */
+            dest[(w + 3) + offset] = pv[wuv + offsetuv];
+
+            /* y10 */
+            dest[w + offset1] = py[wy + offsety1];
+            /* u0 */
+            dest[(w + 1) + offset1] = pu[wuv + offsetuv];
+            /* y11 */
+            dest[(w + 2) + offset1] = py[(wy + 1) + offsety1];
+            /* v0 */
+            dest[(w + 3) + offset1] = pv[wuv + offsetuv];
+
+            wuv++;
+            wy += 2;
+        }
+        huv++;
+    }
+}