2 * Implementation of MARU Virtual Camera device by PCI bus on Windows.
4 * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
7 * JinHyung Jo <jinhyung.jo@samsung.com>
8 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
31 #include "qemu-common.h"
32 #include "maru_camera_common.h"
33 #include "tizen/src/debug_ch.h"
38 #include "errors.h" /* for VFW_E_XXXX */
39 #include "mmsystem.h" /* for MAKEFOURCC macro */
40 #include "maru_camera_win32_interface.h"
42 MULTI_DEBUG_CHANNEL(tizen, camera_win32);
45 * COM Interface implementations
49 #define SAFE_RELEASE(x) \
52 (x)->lpVtbl->Release(x); \
57 typedef HRESULT (STDAPICALLTYPE *CallbackFn)(ULONG dwSize, BYTE *pBuffer);
63 typedef struct HWCGrabCallback {
64 IGrabCallback IGrabCallback_iface;
66 CallbackFn m_pCallback;
67 STDMETHODIMP (*SetCallback)(IGrabCallback *iface, CallbackFn pCallbackFn);
70 static inline HWCGrabCallback *impl_from_IGrabCallback(IGrabCallback *iface)
72 return CONTAINING_RECORD(iface, HWCGrabCallback, IGrabCallback_iface);
75 static STDMETHODIMP HWCGrabCallback_QueryInterface(IGrabCallback *iface,
76 REFIID riid, void **ppv)
78 if (IsEqualIID(riid, &IID_IUnknown)) {
79 *ppv = (IUnknown *)iface;
80 } else if (IsEqualIID(riid, &IID_IGrabCallback)) {
81 *ppv = (IGrabCallback *)iface;
87 IGrabCallback_AddRef(iface);
91 static STDMETHODIMP_(ULONG) HWCGrabCallback_AddRef(IGrabCallback *iface)
93 HWCGrabCallback *This = impl_from_IGrabCallback(iface);
95 return InterlockedIncrement(&This->m_cRef);
98 static STDMETHODIMP_(ULONG) HWCGrabCallback_Release(IGrabCallback *iface)
100 HWCGrabCallback *This = impl_from_IGrabCallback(iface);
102 if (InterlockedDecrement(&This->m_cRef) == 0) {
103 This->m_pCallback = NULL;
104 g_free((void *)This);
112 static STDMETHODIMP HWCGrabCallback_Grab(IGrabCallback *iface,
113 ULONG dwSize, BYTE *pBuffer)
115 HWCGrabCallback *This = impl_from_IGrabCallback(iface);
117 if (This->m_pCallback) {
118 HRESULT hr = This->m_pCallback(dwSize, pBuffer);
129 static STDMETHODIMP HWCGrabCallback_SetCallback(IGrabCallback *iface,
130 CallbackFn pCallbackFn)
132 HWCGrabCallback *This = impl_from_IGrabCallback(iface);
134 This->m_pCallback = pCallbackFn;
138 static IGrabCallbackVtbl HWCGrabCallback_Vtbl = {
139 HWCGrabCallback_QueryInterface,
140 HWCGrabCallback_AddRef,
141 HWCGrabCallback_Release,
145 static STDMETHODIMP HWCGrabCallback_Construct(IGrabCallback **ppv)
147 HWCGrabCallback *This =
148 (HWCGrabCallback *)g_malloc0(sizeof(HWCGrabCallback));
151 ERR("failed to HWCGrabCallback_Construct, E_OUTOFMEMORY\n");
152 return E_OUTOFMEMORY;
155 This->IGrabCallback_iface.lpVtbl = &HWCGrabCallback_Vtbl;
157 This->m_pCallback = NULL;
158 This->SetCallback = HWCGrabCallback_SetCallback;
159 *ppv = &This->IGrabCallback_iface;
167 typedef struct HWCInPin {
169 IMemInputPin IMemInputPin_iface;
170 IBaseFilter *m_pCFilter;
171 IPin *m_pConnectedPin;
172 IGrabCallback *m_pCallback;
173 IMemAllocator *m_pAllocator;
176 STDMETHODIMP (*SetGrabCallbackIF)(IPin *iface, IGrabCallback *pCaptureCB);
179 static inline HWCInPin *impl_from_IPin(IPin *iface)
181 return CONTAINING_RECORD(iface, HWCInPin, IPin_iface);
184 static inline HWCInPin *impl_from_IMemInputPin(IMemInputPin *iface)
186 return CONTAINING_RECORD(iface, HWCInPin, IMemInputPin_iface);
189 static STDMETHODIMP HWCPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
191 HWCInPin *This = impl_from_IPin(iface);
193 if (IsEqualIID(riid, &IID_IUnknown)) {
194 *ppv = (IUnknown *)(&This->IPin_iface);
195 IPin_AddRef((IPin *)*ppv);
196 } else if (IsEqualIID(riid, &IID_IPin)) {
197 *ppv = (IPin *)(&This->IPin_iface);
198 IPin_AddRef((IPin *)*ppv);
199 } else if (IsEqualIID(riid, &IID_IMemInputPin)) {
200 *ppv = (IMemInputPin *)(&This->IMemInputPin_iface);
201 IPin_AddRef((IMemInputPin *)*ppv);
204 return E_NOINTERFACE;
210 static STDMETHODIMP_(ULONG) HWCPin_AddRef(IPin *iface)
212 HWCInPin *This = impl_from_IPin(iface);
214 return InterlockedIncrement(&This->m_cRef);
217 static STDMETHODIMP_(ULONG) HWCPin_Release(IPin *iface)
219 HWCInPin *This = impl_from_IPin(iface);
221 if (InterlockedDecrement(&This->m_cRef) == 0) {
222 if (This->m_pCallback) {
223 SAFE_RELEASE(This->m_pCallback);
225 if (This->m_pConnectedPin) {
226 SAFE_RELEASE(This->m_pConnectedPin);
228 if (This->m_pAllocator) {
229 IMemAllocator_Decommit(This->m_pAllocator);
230 SAFE_RELEASE(This->m_pAllocator);
232 g_free((void *)This);
239 static STDMETHODIMP HWCPin_Connect(IPin *iface,
241 const AM_MEDIA_TYPE *pmt)
243 HWCInPin *This = impl_from_IPin(iface);
249 if (This->m_pConnectedPin) {
250 return VFW_E_ALREADY_CONNECTED;
259 static STDMETHODIMP HWCPin_ReceiveConnection(IPin *iface, IPin *pConnector,
260 const AM_MEDIA_TYPE *pmt)
264 HWCInPin *This = impl_from_IPin(iface);
266 if (pConnector == NULL || pmt == NULL) {
270 if (This->m_pConnectedPin) {
271 return VFW_E_ALREADY_CONNECTED;
273 IBaseFilter_GetState(This->m_pCFilter, 0, &fs);
274 if (fs != State_Stopped) {
275 return VFW_E_NOT_STOPPED;
277 IPin_QueryDirection(pConnector, &pd);
278 if (pd == PINDIR_INPUT) {
279 return VFW_E_INVALID_DIRECTION;
282 This->m_pConnectedPin = pConnector;
283 IPin_AddRef(This->m_pConnectedPin);
287 static STDMETHODIMP HWCPin_Disconnect(IPin *iface)
289 HWCInPin *This = impl_from_IPin(iface);
293 IBaseFilter_GetState(This->m_pCFilter, 0, &fs);
294 if (fs != State_Stopped) {
295 return VFW_E_NOT_STOPPED;
297 if (This->m_pConnectedPin == NULL) {
300 if (This->m_pAllocator) {
301 hr = IMemAllocator_Decommit(This->m_pAllocator);
305 SAFE_RELEASE(This->m_pAllocator);
307 SAFE_RELEASE(This->m_pConnectedPin);
313 static STDMETHODIMP HWCPin_ConnectedTo(IPin *iface, IPin **ppPin)
315 HWCInPin *This = impl_from_IPin(iface);
321 if (This->m_pConnectedPin == NULL) {
323 return VFW_E_NOT_CONNECTED;
325 *ppPin = This->m_pConnectedPin;
326 IPin_AddRef(This->m_pConnectedPin);
331 static STDMETHODIMP HWCPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)
336 return VFW_E_NOT_CONNECTED;
339 static STDMETHODIMP HWCPin_QueryPinInfo(IPin *iface, PIN_INFO *pInfo)
341 HWCInPin *This = impl_from_IPin(iface);
347 pInfo->pFilter = This->m_pCFilter;
348 if (This->m_pCFilter) {
349 IBaseFilter_AddRef(This->m_pCFilter);
351 memcpy((void *)pInfo->achName, (void *)HWCPinName, sizeof(HWCPinName));
352 pInfo->dir = PINDIR_INPUT;
356 static STDMETHODIMP HWCPin_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir)
358 if (pPinDir == NULL) {
361 *pPinDir = PINDIR_INPUT;
365 static STDMETHODIMP HWCPin_QueryId(IPin *iface, LPWSTR *Id)
371 pId = CoTaskMemAlloc(sizeof(HWCPinName));
372 memcpy((void *)pId, (void *)HWCPinName, sizeof(HWCPinName));
377 static STDMETHODIMP HWCPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)
385 static STDMETHODIMP HWCPin_EnumMediaTypes(IPin *iface,
386 IEnumMediaTypes **ppEnum)
388 if (ppEnum == NULL) {
394 static STDMETHODIMP HWCPin_QueryInternalConnections(IPin *iface,
401 static STDMETHODIMP HWCPin_EndOfStream(IPin *iface)
406 static STDMETHODIMP HWCPin_BeginFlush(IPin *iface)
411 static STDMETHODIMP HWCPin_EndFlush(IPin *iface)
416 static STDMETHODIMP HWCPin_NewSegment(IPin *iface, REFERENCE_TIME tStart,
417 REFERENCE_TIME tStop, double dRate)
422 static STDMETHODIMP HWCMemInputPin_QueryInterface(IMemInputPin *iface,
423 REFIID riid, void **ppv)
425 HWCInPin *This = impl_from_IMemInputPin(iface);
427 if (IsEqualIID(riid, &IID_IUnknown)) {
428 *ppv = (IUnknown *)(&This->IMemInputPin_iface);
429 IPin_AddRef((IPin *)*ppv);
430 } else if (IsEqualIID(riid, &IID_IPin)) {
431 *ppv = (IPin *)(&This->IPin_iface);
432 IPin_AddRef((IPin *)*ppv);
433 } else if (IsEqualIID(riid, &IID_IMemInputPin)) {
434 *ppv = (IMemInputPin *)(&This->IMemInputPin_iface);
435 IPin_AddRef((IMemInputPin *)*ppv);
438 return E_NOINTERFACE;
444 static STDMETHODIMP_(ULONG) HWCMemInputPin_AddRef(IMemInputPin *iface)
446 HWCInPin *This = impl_from_IMemInputPin(iface);
448 return InterlockedIncrement(&This->m_cRef);
451 static STDMETHODIMP_(ULONG) HWCMemInputPin_Release(IMemInputPin *iface)
453 HWCInPin *This = impl_from_IMemInputPin(iface);
455 if (InterlockedDecrement(&This->m_cRef) == 0) {
456 if (This->m_pCallback) {
457 SAFE_RELEASE(This->m_pCallback);
459 if (This->m_pConnectedPin) {
460 SAFE_RELEASE(This->m_pConnectedPin);
462 if (This->m_pAllocator) {
463 IMemAllocator_Decommit(This->m_pAllocator);
464 SAFE_RELEASE(This->m_pAllocator);
466 g_free((void *)This);
473 static STDMETHODIMP HWCMemInputPin_GetAllocator(IMemInputPin *iface,
474 IMemAllocator **ppAllocator)
476 HWCInPin *This = impl_from_IMemInputPin(iface);
478 if (ppAllocator == NULL) {
482 if (This->m_pAllocator == NULL) {
483 HRESULT hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL,
484 CLSCTX_INPROC_SERVER,
486 (void **)&(This->m_pAllocator));
488 ERR("Failed to CoCreateInstance for retrieving MemoryAllocator\n");
492 ASSERT(This->m_pAllocator != NULL);
493 *ppAllocator = This->m_pAllocator;
494 IMemAllocator_AddRef(This->m_pAllocator);
499 static STDMETHODIMP HWCMemInputPin_NotifyAllocator(IMemInputPin *iface,
500 IMemAllocator *pAllocator,
503 HWCInPin *This = impl_from_IMemInputPin(iface);
505 if (pAllocator == NULL) {
509 IMemAllocator *pOldAllocator = This->m_pAllocator;
510 IMemAllocator_AddRef(pAllocator);
511 This->m_pAllocator = pAllocator;
513 if (pOldAllocator != NULL) {
514 SAFE_RELEASE(pOldAllocator);
517 This->m_bReadOnly = bReadOnly;
522 static STDMETHODIMP HWCMemInputPin_GetAllocatorRequirements(
524 ALLOCATOR_PROPERTIES *pProps)
529 static STDMETHODIMP HWCMemInputPin_Receive(IMemInputPin *iface,
530 IMediaSample *pSample)
532 HWCInPin *This = impl_from_IMemInputPin(iface);
534 if (pSample == NULL) {
535 ERR("pSample is NULL\n");
538 if (This->m_pCallback != NULL) {
540 BYTE *pBuffer = NULL;
542 dwSize = IMediaSample_GetSize(pSample);
543 hr = IMediaSample_GetPointer(pSample, &pBuffer);
545 ERR("Receive function : "
546 "failed to IMediaSample_GetPointer, 0x%ld\n", hr);
549 hr = IGrabCallback_Grab(This->m_pCallback, dwSize, pBuffer);
551 ERR("Receive function : failed to IGrabCallback_Grab, 0x%ld\n",
559 static STDMETHODIMP HWCMemInputPin_ReceiveMultiple(IMemInputPin *iface,
560 IMediaSample **pSamples,
562 long *nSamplesProcessed)
566 if (pSamples == NULL) {
570 *nSamplesProcessed = 0;
572 while (nSamples-- > 0) {
573 hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
577 (*nSamplesProcessed)++;
582 static STDMETHODIMP HWCMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
587 static STDMETHODIMP HWCPin_SetCallback(IPin *iface, IGrabCallback *pCaptureCB)
589 HWCInPin *This = impl_from_IPin(iface);
591 if (pCaptureCB == NULL) {
592 SAFE_RELEASE(This->m_pCallback);
594 This->m_pCallback = pCaptureCB;
595 IGrabCallback_AddRef(This->m_pCallback);
602 static IPinVtbl HWCPin_Vtbl = {
603 HWCPin_QueryInterface,
607 HWCPin_ReceiveConnection,
610 HWCPin_ConnectionMediaType,
612 HWCPin_QueryDirection,
615 HWCPin_EnumMediaTypes,
616 HWCPin_QueryInternalConnections,
623 static IMemInputPinVtbl HWCMemInputPin_Vtbl = {
624 HWCMemInputPin_QueryInterface,
625 HWCMemInputPin_AddRef,
626 HWCMemInputPin_Release,
627 HWCMemInputPin_GetAllocator,
628 HWCMemInputPin_NotifyAllocator,
629 HWCMemInputPin_GetAllocatorRequirements,
630 HWCMemInputPin_Receive,
631 HWCMemInputPin_ReceiveMultiple,
632 HWCMemInputPin_ReceiveCanBlock
635 static STDMETHODIMP HWCInPin_Construct(IBaseFilter *pFilter, IPin **ppv)
637 HWCInPin *This = (HWCInPin *)g_malloc0(sizeof(HWCInPin));
640 ERR("failed to HWCInPin_Construct, E_OUTOFMEMORY\n");
641 return E_OUTOFMEMORY;
644 This->IPin_iface.lpVtbl = &HWCPin_Vtbl;
645 This->IMemInputPin_iface.lpVtbl = &HWCMemInputPin_Vtbl;
646 This->m_bReadOnly = FALSE;
647 This->m_pCFilter = pFilter;
648 This->m_pConnectedPin = NULL;
649 This->m_pCallback = NULL;
650 This->m_pAllocator = NULL;
652 This->SetGrabCallbackIF = HWCPin_SetCallback;
653 *ppv = &This->IPin_iface;
662 typedef struct HWCEnumPins {
663 IEnumPins IEnumPins_iface;
664 IBaseFilter *m_pFilter;
669 static inline HWCEnumPins *impl_from_IEnumPins(IEnumPins *iface)
671 return CONTAINING_RECORD(iface, HWCEnumPins, IEnumPins_iface);
674 static STDMETHODIMP HWCEnumPins_QueryInterface(IEnumPins *iface,
675 REFIID riid, void **ppv)
681 if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumPins)) {
685 return E_NOINTERFACE;
688 IEnumPins_AddRef(iface);
692 static STDMETHODIMP_(ULONG) HWCEnumPins_AddRef(IEnumPins *iface)
694 HWCEnumPins *This = impl_from_IEnumPins(iface);
696 return InterlockedIncrement(&This->m_cRef);
699 static STDMETHODIMP_(ULONG) HWCEnumPins_Release(IEnumPins *iface)
701 HWCEnumPins *This = impl_from_IEnumPins(iface);
703 if (InterlockedDecrement(&This->m_cRef) == 0) {
704 if (This->m_pFilter) {
705 SAFE_RELEASE(This->m_pFilter);
708 g_free((void *)This);
715 static STDMETHODIMP HWCEnumPins_Next(IEnumPins *iface, ULONG cPins,
716 IPin **ppPins, ULONG *pcFetched)
719 HWCEnumPins *This = impl_from_IEnumPins(iface);
721 if (ppPins == NULL) {
725 if (This->m_nPos < 1 && cPins > 0) {
727 IBaseFilter_FindPin(This->m_pFilter, HWCPinName, &pPin);
735 if (pcFetched != NULL) {
736 *pcFetched = fetched;
739 return (fetched == cPins) ? S_OK : S_FALSE;
742 static STDMETHODIMP HWCEnumPins_Skip(IEnumPins *iface, ULONG cPins)
744 HWCEnumPins *This = impl_from_IEnumPins(iface);
745 This->m_nPos += cPins;
746 return (This->m_nPos >= 1) ? S_FALSE : S_OK;
749 static STDMETHODIMP HWCEnumPins_Reset(IEnumPins *iface)
751 HWCEnumPins *This = impl_from_IEnumPins(iface);
756 static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter,
757 int nPos, IEnumPins **ppv);
759 static STDMETHODIMP HWCEnumPins_Clone(IEnumPins *iface, IEnumPins **ppEnum)
761 HWCEnumPins *This = impl_from_IEnumPins(iface);
763 if (ppEnum == NULL) {
767 HWCEnumPins_Construct(This->m_pFilter, This->m_nPos, ppEnum);
768 if (*ppEnum == NULL) {
769 ERR("failed to HWCEnumPins_Construct in clone, E_OUTOFMEMORY\n");
770 return E_OUTOFMEMORY;
776 static IEnumPinsVtbl HWCEnumPins_Vtbl = {
777 HWCEnumPins_QueryInterface,
787 static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter,
788 int nPos, IEnumPins **ppv)
790 HWCEnumPins *This = (HWCEnumPins *)g_malloc0(sizeof(HWCEnumPins));
793 ERR("failed to HWCEnumPins_Construct, E_OUTOFMEMORY\n");
794 return E_OUTOFMEMORY;
797 This->IEnumPins_iface.lpVtbl = &HWCEnumPins_Vtbl;
798 This->m_pFilter = pFilter;
799 if (This->m_pFilter) {
800 IBaseFilter_AddRef(This->m_pFilter);
804 *ppv = &This->IEnumPins_iface;
813 typedef struct HWCFilter {
814 IBaseFilter IBaseFilter_iface;
816 IFilterGraph *m_pFilterGraph;
817 FILTER_STATE m_state;
821 static inline HWCFilter *impl_from_IBaseFilter(IBaseFilter *iface)
823 return CONTAINING_RECORD(iface, HWCFilter, IBaseFilter_iface);
826 static STDMETHODIMP HWCFilter_QueryInterface(IBaseFilter *iface,
827 REFIID riid, void **ppv)
829 if (IsEqualIID(riid, &IID_IUnknown)) {
830 *ppv = (IUnknown *)iface;
831 } else if (IsEqualIID(riid, &IID_IPersist)) {
832 *ppv = (IPersist *)iface;
833 } else if (IsEqualIID(riid, &IID_IMediaFilter)) {
834 *ppv = (IMediaFilter *)iface;
835 } else if (IsEqualIID(riid, &IID_IBaseFilter)) {
836 *ppv = (IBaseFilter *)iface;
839 return E_NOINTERFACE;
842 IBaseFilter_AddRef(iface);
846 static STDMETHODIMP_(ULONG) HWCFilter_AddRef(IBaseFilter *iface)
848 HWCFilter *This = impl_from_IBaseFilter(iface);
850 return InterlockedIncrement(&This->m_cRef);
853 static STDMETHODIMP_(ULONG) HWCFilter_Release(IBaseFilter *iface)
855 HWCFilter *This = impl_from_IBaseFilter(iface);
857 if (InterlockedDecrement(&This->m_cRef) == 0) {
859 SAFE_RELEASE(This->m_pPin);
861 g_free((void *)This);
868 static STDMETHODIMP HWCFilter_GetClassID(IBaseFilter *iface, CLSID *pClsID)
870 if (pClsID == NULL) {
876 static STDMETHODIMP HWCFilter_GetState(IBaseFilter *iface, DWORD dwMSecs,
879 HWCFilter *This = impl_from_IBaseFilter(iface);
880 *State = This->m_state;
884 static STDMETHODIMP HWCFilter_SetSyncSource(IBaseFilter *iface,
885 IReferenceClock *pClock)
890 static STDMETHODIMP HWCFilter_GetSyncSource(IBaseFilter *iface,
891 IReferenceClock **pClock)
897 static STDMETHODIMP HWCFilter_Stop(IBaseFilter *iface)
899 HWCFilter *This = impl_from_IBaseFilter(iface);
901 IPin_EndFlush(This->m_pPin);
902 This->m_state = State_Stopped;
906 static STDMETHODIMP HWCFilter_Pause(IBaseFilter *iface)
908 HWCFilter *This = impl_from_IBaseFilter(iface);
909 This->m_state = State_Paused;
913 static STDMETHODIMP HWCFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
915 HWCFilter *This = impl_from_IBaseFilter(iface);
917 if (This->m_state == State_Stopped) {
919 hr = IBaseFilter_Pause(iface);
921 ERR("HWCFilter_Run : Failed to IBaseFilter_Pause, ret=0xld%\n", hr);
926 This->m_state = State_Running;
930 static STDMETHODIMP HWCFilter_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum)
932 if (ppEnum == NULL) {
936 HWCEnumPins_Construct(iface, 0, ppEnum);
937 return *ppEnum == NULL ? E_OUTOFMEMORY : S_OK;
940 static STDMETHODIMP HWCFilter_FindPin(IBaseFilter *iface, LPCWSTR Id,
943 HWCFilter *This = impl_from_IBaseFilter(iface);
949 if (memcmp((void *)Id, (void *)HWCPinName, sizeof(HWCPinName))) {
950 return VFW_E_NOT_FOUND;
954 HWCInPin_Construct(iface, &This->m_pPin);
956 *ppPin = This->m_pPin;
958 IPin_AddRef(This->m_pPin);
962 static STDMETHODIMP HWCFilter_QueryFilterInfo(IBaseFilter *iface,
965 HWCFilter *This = impl_from_IBaseFilter(iface);
971 memcpy((void *)pInfo->achName,
972 (void *)HWCFilterName,
973 sizeof(HWCFilterName));
974 pInfo->pGraph = This->m_pFilterGraph;
975 if (This->m_pFilterGraph) {
976 IFilterGraph_AddRef(This->m_pFilterGraph);
981 static STDMETHODIMP HWCFilter_JoinFilterGraph(IBaseFilter *iface,
982 IFilterGraph *pGraph,
985 HWCFilter *This = impl_from_IBaseFilter(iface);
987 This->m_pFilterGraph = pGraph;
991 static STDMETHODIMP HWCFilter_QueryVendorInfo(IBaseFilter *iface,
997 static IBaseFilterVtbl HWCFilter_Vtbl = {
998 HWCFilter_QueryInterface,
1001 HWCFilter_GetClassID,
1006 HWCFilter_SetSyncSource,
1007 HWCFilter_GetSyncSource,
1010 HWCFilter_QueryFilterInfo,
1011 HWCFilter_JoinFilterGraph,
1012 HWCFilter_QueryVendorInfo
1015 static STDMETHODIMP HWCFilter_Construct(IBaseFilter **ppv)
1017 HWCFilter *This = (HWCFilter *)g_malloc0(sizeof(HWCFilter));
1020 ERR("failed to HWCFilter_Construct, E_OUTOFMEMORY\n");
1021 return E_OUTOFMEMORY;
1024 This->IBaseFilter_iface.lpVtbl = &HWCFilter_Vtbl;
1025 This->m_pFilterGraph = NULL;
1026 This->m_state = State_Stopped;
1028 HWCInPin_Construct(&This->IBaseFilter_iface, &This->m_pPin);
1029 *ppv = &This->IBaseFilter_iface;
1034 /**********************************************************
1036 * Virtual device implementations
1038 **********************************************************/
1042 * Declaration global variables for Win32 COM Interfaces
1044 IGraphBuilder *g_pGB ;
1045 ICaptureGraphBuilder2 *g_pCGB;
1046 IMediaControl *g_pMediaControl;
1050 IBaseFilter *g_pDstFilter;
1051 IBaseFilter *g_pSrcFilter;
1053 IGrabCallback *g_pCallback;
1055 /* V4L2 defines copy from videodev2.h */
1056 #define V4L2_CTRL_FLAG_SLIDER 0x0020
1058 #define V4L2_CTRL_CLASS_USER 0x00980000
1059 #define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900)
1060 #define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0)
1061 #define V4L2_CID_CONTRAST (V4L2_CID_BASE+1)
1062 #define V4L2_CID_SATURATION (V4L2_CID_BASE+2)
1063 #define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27)
1065 #define V4L2_PIX_FMT_YUYV MAKEFOURCC('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */
1066 #define V4L2_PIX_FMT_YUV420 MAKEFOURCC('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */
1067 #define V4L2_PIX_FMT_YVU420 MAKEFOURCC('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */
1068 #define V4L2_PIX_FMT_RGB24 MAKEFOURCC('R', 'G', 'B', '3') /* 24 RGB-8-8-8 */
1070 typedef struct tagMaruCamConvertPixfmt {
1071 uint32_t fmt; /* fourcc */
1072 uint32_t bpp; /* bits per pixel, 0 for compressed formats */
1073 uint32_t needs_conversion;
1074 } MaruCamConvertPixfmt;
1076 static MaruCamConvertPixfmt supported_dst_pixfmts[] = {
1077 { V4L2_PIX_FMT_YUYV, 16, 0 },
1078 { V4L2_PIX_FMT_YUV420, 12, 0 },
1079 { V4L2_PIX_FMT_YVU420, 12, 0 },
1082 typedef struct tagMaruCamConvertFrameInfo {
1085 } MaruCamConvertFrameInfo;
1087 static MaruCamConvertFrameInfo supported_dst_frames[] = {
1095 #define MARUCAM_CTRL_VALUE_MAX 20
1096 #define MARUCAM_CTRL_VALUE_MIN 1
1097 #define MARUCAM_CTRL_VALUE_MID 10
1098 #define MARUCAM_CTRL_VALUE_STEP 1
1100 struct marucam_qctrl {
1109 static struct marucam_qctrl qctrl_tbl[] = {
1110 { V4L2_CID_BRIGHTNESS, 0, },
1111 { V4L2_CID_CONTRAST, 0, },
1112 { V4L2_CID_SATURATION, 0, },
1113 { V4L2_CID_SHARPNESS, 0, },
1116 static MaruCamState *g_state;
1118 static uint32_t ready_count;
1119 static uint32_t cur_fmt_idx;
1120 static uint32_t cur_frame_idx;
1121 static void *grab_buf;
1122 static uint32_t g_dwSrcFmt;
1126 * Helper functions - converting image formats, converting values
1129 static uint32_t get_bytesperline(uint32_t pixfmt, uint32_t width)
1131 uint32_t bytesperline;
1134 case V4L2_PIX_FMT_YUV420:
1135 case V4L2_PIX_FMT_YVU420:
1136 bytesperline = (width * 12) >> 3;
1138 case V4L2_PIX_FMT_YUYV:
1140 bytesperline = width * 2;
1144 return bytesperline;
1147 static uint32_t get_sizeimage(uint32_t pixfmt, uint32_t width, uint32_t height)
1149 return get_bytesperline(pixfmt, width) * height;
1152 void yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
1153 uint32_t width, uint32_t height, uint32_t yvu);
1154 void rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,
1155 uint32_t width, uint32_t height, uint32_t yvu);
1156 void rgb24_to_yuyv(unsigned char *src, unsigned char *dest,
1157 uint32_t width, uint32_t height);
1158 void yuv420_to_yvu420(unsigned char *src, unsigned char *dest,
1159 uint32_t width, uint32_t height);
1160 void yuv420_to_yuyv(unsigned char *src, unsigned char *dest,
1161 uint32_t width, uint32_t height);
1163 static long value_convert_from_guest(long min, long max, long value)
1166 long dist = 0, ret = 0;
1170 if (dist < MARUCAM_CTRL_VALUE_MAX) {
1171 rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
1172 ret = min + (int32_t)(value / rate);
1174 rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
1175 ret = min + (int32_t)(rate * value);
1180 static long value_convert_to_guest(long min, long max, long value)
1183 long dist = 0, ret = 0;
1187 if (dist < MARUCAM_CTRL_VALUE_MAX) {
1188 rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
1189 ret = (int32_t)((double)(value - min) * rate);
1191 rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
1192 ret = (int32_t)((double)(value - min) / rate);
1199 * Callback function for grab frames
1201 static STDMETHODIMP marucam_device_callbackfn(ULONG dwSize, BYTE *pBuffer)
1204 uint32_t width, height, fmt, imgsize;
1206 width = supported_dst_frames[cur_frame_idx].width;
1207 height = supported_dst_frames[cur_frame_idx].height;
1208 fmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
1209 imgsize = get_sizeimage(fmt, width, height);
1211 if (imgsize > (uint32_t)dwSize) {
1212 ERR("Image size is mismatched\n");
1216 switch (g_dwSrcFmt) {
1217 case V4L2_PIX_FMT_YUYV:
1219 case V4L2_PIX_FMT_YUV420:
1220 yuyv_to_yuv420(pBuffer, grab_buf, width, height, 0);
1222 case V4L2_PIX_FMT_YVU420:
1223 yuyv_to_yuv420(pBuffer, grab_buf, width, height, 1);
1225 case V4L2_PIX_FMT_YUYV:
1226 memcpy(grab_buf, (void *)pBuffer, (size_t)dwSize);
1229 ERR("Invalid pixel format\n");
1233 case V4L2_PIX_FMT_RGB24:
1235 case V4L2_PIX_FMT_YUV420:
1236 rgb24_to_yuv420(pBuffer, grab_buf, width, height, 0);
1238 case V4L2_PIX_FMT_YVU420:
1239 rgb24_to_yuv420(pBuffer, grab_buf, width, height, 1);
1241 case V4L2_PIX_FMT_YUYV:
1242 rgb24_to_yuyv(pBuffer, grab_buf, width, height);
1245 ERR("Invalid pixel format\n");
1249 case V4L2_PIX_FMT_YUV420:
1251 case V4L2_PIX_FMT_YUV420:
1252 memcpy(grab_buf, (void *)pBuffer, (size_t)dwSize);
1254 case V4L2_PIX_FMT_YVU420:
1255 yuv420_to_yvu420(pBuffer, grab_buf, width, height);
1257 case V4L2_PIX_FMT_YUYV:
1258 yuv420_to_yuyv(pBuffer, grab_buf, width, height);
1261 ERR("Invalid pixel format\n");
1266 ERR("Invalid pixel format\n");
1270 qemu_mutex_lock(&g_state->thread_mutex);
1271 if (g_state->streamon) {
1272 if (ready_count < MARUCAM_SKIPFRAMES) {
1273 /* skip a frame cause first some frame are distorted */
1275 TRACE("skip %d frame\n", ready_count);
1276 qemu_mutex_unlock(&g_state->thread_mutex);
1279 if (g_state->req_frame == 0) {
1280 TRACE("there is no request\n");
1281 qemu_mutex_unlock(&g_state->thread_mutex);
1284 tmp_buf = g_state->vaddr + g_state->buf_size * (g_state->req_frame - 1);
1285 memcpy(tmp_buf, grab_buf, g_state->buf_size);
1286 g_state->req_frame = 0; /* clear request */
1287 g_state->isr |= 0x01; /* set a flag of rasing a interrupt */
1288 qemu_bh_schedule(g_state->tx_bh);
1290 qemu_mutex_unlock(&g_state->thread_mutex);
1295 * Internal functions for manipulate interfaces
1298 static STDMETHODIMP_(void) CloseInterfaces(void)
1300 if (g_pMediaControl) {
1301 g_pMediaControl->lpVtbl->Stop(g_pMediaControl);
1305 g_pOutputPin->lpVtbl->Disconnect(g_pOutputPin);
1308 SAFE_RELEASE(g_pGB);
1309 SAFE_RELEASE(g_pCGB);
1310 SAFE_RELEASE(g_pMediaControl);
1311 SAFE_RELEASE(g_pOutputPin);
1312 SAFE_RELEASE(g_pInputPin);
1313 SAFE_RELEASE(g_pDstFilter);
1314 SAFE_RELEASE(g_pSrcFilter);
1315 SAFE_RELEASE(g_pCallback);
1318 static STDMETHODIMP_(void) DeleteMediaType(AM_MEDIA_TYPE *pmt)
1324 if (pmt->cbFormat != 0) {
1325 CoTaskMemFree((PVOID)pmt->pbFormat);
1327 pmt->pbFormat = NULL;
1329 if (pmt->pUnk != NULL) {
1330 pmt->pUnk->lpVtbl->Release(pmt->pUnk);
1334 CoTaskMemFree((PVOID)pmt);
1337 static STDMETHODIMP GetPin(IBaseFilter *pFilter,
1338 PIN_DIRECTION PinDir, IPin **ppPin)
1341 IEnumPins *pEnum = NULL;
1344 if (ppPin == NULL) {
1348 hr = pFilter->lpVtbl->EnumPins(pFilter, &pEnum);
1353 while (pEnum->lpVtbl->Next(pEnum, 1, &pPin, 0) == S_OK) {
1354 PIN_DIRECTION PinDirThis;
1355 hr = pPin->lpVtbl->QueryDirection(pPin, &PinDirThis);
1358 SAFE_RELEASE(pEnum);
1361 if (PinDir == PinDirThis) {
1363 SAFE_RELEASE(pEnum);
1369 SAFE_RELEASE(pEnum);
1373 static STDMETHODIMP GraphBuilder_Init(void)
1377 hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC,
1378 &IID_IGraphBuilder, (void **)&g_pGB);
1380 ERR("Failed to create instance of GraphBuilder, 0x%x\n", hr);
1384 hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,
1385 &IID_ICaptureGraphBuilder2, (void **)&g_pCGB);
1387 ERR("Failed to create instance of CaptureGraphBuilder2, 0x%x\n", hr);
1391 hr = g_pCGB->lpVtbl->SetFiltergraph(g_pCGB, g_pGB);
1393 ERR("Failed to SetFiltergraph, 0x%x\n", hr);
1397 hr = g_pGB->lpVtbl->QueryInterface(g_pGB, &IID_IMediaControl,
1398 (void **)&g_pMediaControl);
1400 ERR("Failed to QueryInterface for IMediaControl, 0x%x\n", hr);
1404 hr = HWCGrabCallback_Construct(&g_pCallback);
1405 if (g_pCallback == NULL) {
1409 hr = ((HWCGrabCallback *)g_pCallback)->SetCallback(g_pCallback,
1410 (CallbackFn)marucam_device_callbackfn);
1415 static STDMETHODIMP BindSourceFilter(void)
1418 ICreateDevEnum *pCreateDevEnum = NULL;
1419 IEnumMoniker *pEnumMK = NULL;
1422 hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
1423 &IID_ICreateDevEnum,
1424 (void **)&pCreateDevEnum);
1426 ERR("Failed to create instance of CreateDevEnum, 0x%x\n", hr);
1430 hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum,
1431 &CLSID_VideoInputDeviceCategory,
1434 ERR("Failed to get VideoInputDeviceCategory, 0x%x\n", hr);
1435 SAFE_RELEASE(pCreateDevEnum);
1440 ERR("ClassEnumerator moniker is NULL\n");
1441 SAFE_RELEASE(pCreateDevEnum);
1444 pEnumMK->lpVtbl->Reset(pEnumMK);
1446 hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL);
1447 if (hr == S_FALSE) {
1450 if (SUCCEEDED(hr)) {
1451 IPropertyBag *pBag = NULL;
1452 hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0,
1455 if (SUCCEEDED(hr)) {
1458 hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);
1459 if (hr == NOERROR) {
1460 hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL,
1462 (void **)&g_pSrcFilter);
1464 ERR("Counldn't bind moniker to filter object!!\n");
1466 g_pSrcFilter->lpVtbl->AddRef(g_pSrcFilter);
1468 SysFreeString(var.bstrVal);
1472 SAFE_RELEASE(pMoniKer);
1475 if (SUCCEEDED(hr)) {
1476 hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pSrcFilter, L"Video Capture");
1477 if (hr != S_OK && hr != S_FALSE) {
1478 ERR("Counldn't add Video Capture filter to our graph!\n");
1479 SAFE_RELEASE(g_pSrcFilter);
1482 SAFE_RELEASE(pEnumMK);
1483 SAFE_RELEASE(pCreateDevEnum);
1488 static STDMETHODIMP BindTargetFilter(void)
1491 hr = HWCFilter_Construct(&g_pDstFilter);
1493 if (SUCCEEDED(hr) && g_pDstFilter) {
1494 hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pDstFilter, L"HWCFilter");
1496 ERR("Counldn't add HWCFilterr to our graph!\n");
1497 SAFE_RELEASE(g_pDstFilter);
1503 static STDMETHODIMP ConnectFilters(void)
1507 hr = GetPin(g_pSrcFilter, PINDIR_OUTPUT , &g_pOutputPin);
1509 ERR("Failed to get output pin. 0x%x\n", hr);
1513 hr = GetPin(g_pDstFilter, PINDIR_INPUT , &g_pInputPin);
1515 ERR("Failed to get input pin. 0x%x\n", hr);
1519 hr = g_pGB->lpVtbl->Connect(g_pGB, g_pOutputPin, g_pInputPin);
1521 ERR("Failed to connect pins. 0x%x\n", hr);
1526 static STDMETHODIMP DisconnectPins(void)
1530 hr = g_pGB->lpVtbl->Disconnect(g_pGB, g_pOutputPin);
1532 ERR("Failed to disconnect output pin. 0x%x\n", hr);
1536 hr = g_pGB->lpVtbl->Disconnect(g_pGB, g_pInputPin);
1538 ERR("Failed to disconnect input pin. 0x%x\n", hr);
1544 static STDMETHODIMP RemoveFilters(void)
1548 hr = g_pGB->lpVtbl->RemoveFilter(g_pGB, g_pSrcFilter);
1550 ERR("Failed to remove source filer. 0x%x\n", hr);
1554 hr = g_pGB->lpVtbl->RemoveFilter(g_pGB, g_pDstFilter);
1556 ERR("Failed to remove destination filer. 0x%x\n", hr);
1562 /* default fps is 15 */
1563 #define MARUCAM_DEFAULT_FRAMEINTERVAL 666666
1565 static STDMETHODIMP SetFormat(uint32_t dwWidth, uint32_t dwHeight,
1566 uint32_t dwDstFmt, uint32_t *dwSrcFmt)
1569 IAMStreamConfig *pSConfig;
1570 int iCount = 0, iSize = 0;
1571 DWORD dwYUY2 = MAKEFOURCC('Y', 'U', 'Y', '2');
1572 DWORD dwI420 = MAKEFOURCC('I', '4', '2', '0');
1574 if (dwSrcFmt == NULL) {
1575 ERR("invalid the source format pointer\n");
1579 hr = g_pCGB->lpVtbl->FindInterface(g_pCGB, &PIN_CATEGORY_CAPTURE, 0,
1580 g_pSrcFilter, &IID_IAMStreamConfig,
1581 (void **)&pSConfig);
1583 ERR("failed to FindInterface method\n");
1587 hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);
1589 ERR("failed to GetNumberOfCapabilities method\n");
1590 SAFE_RELEASE(pSConfig);
1594 if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
1596 for (iFormat = 0; iFormat < iCount; iFormat++) {
1597 VIDEO_STREAM_CONFIG_CAPS scc;
1598 AM_MEDIA_TYPE *pmtConfig;
1600 hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat,
1601 &pmtConfig, (BYTE *)&scc);
1603 if (IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo)) {
1604 VIDEOINFOHEADER *pvi =
1605 (VIDEOINFOHEADER *)pmtConfig->pbFormat;
1606 if ((pvi->bmiHeader.biWidth == (LONG)dwWidth) &&
1607 (pvi->bmiHeader.biHeight == (LONG)dwHeight)) {
1608 if (pvi->bmiHeader.biCompression == dwYUY2) {
1609 *dwSrcFmt = V4L2_PIX_FMT_YUYV;
1610 } else if ((pvi->bmiHeader.biCompression == BI_RGB) &&
1611 (pvi->bmiHeader.biBitCount == 24)) {
1612 *dwSrcFmt = V4L2_PIX_FMT_RGB24;
1613 } else if (pvi->bmiHeader.biCompression == dwI420) {
1614 *dwSrcFmt = V4L2_PIX_FMT_YUV420;
1615 } else { /* not support format */
1616 DeleteMediaType(pmtConfig);
1619 /* use minimum FPS(maximum frameinterval)
1620 with non-VT system */
1622 if (!hax_enabled()) {
1623 pvi->AvgTimePerFrame =
1624 (REFERENCE_TIME)scc.MaxFrameInterval;
1626 pvi->AvgTimePerFrame =
1627 (REFERENCE_TIME)MARUCAM_DEFAULT_FRAMEINTERVAL;
1630 pvi->AvgTimePerFrame =
1631 (REFERENCE_TIME)scc.MaxFrameInterval;
1633 hr = pSConfig->lpVtbl->SetFormat(pSConfig, pmtConfig);
1634 DeleteMediaType(pmtConfig);
1638 DeleteMediaType(pmtConfig);
1641 if (iFormat >= iCount) {
1642 ERR("Failed to Set format. "
1643 "Maybe connected webcam does not support the (%ldx%ld) "
1644 "resolution or image formats(YUY2, RGB24, I420).\n",
1649 SAFE_RELEASE(pSConfig);
1653 static STDMETHODIMP QueryVideoProcAmp(long nProperty, long *pMin, long *pMax,
1654 long *pStep, long *pDefault)
1658 IAMVideoProcAmp *pProcAmp = NULL;
1660 hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
1661 &IID_IAMVideoProcAmp,
1662 (void **)&pProcAmp);
1667 hr = pProcAmp->lpVtbl->GetRange(pProcAmp, nProperty, pMin, pMax,
1668 pStep, pDefault, &Flags);
1670 SAFE_RELEASE(pProcAmp);
1674 static STDMETHODIMP GetVideoProcAmp(long nProperty, long *pValue)
1678 IAMVideoProcAmp *pProcAmp = NULL;
1680 hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
1681 &IID_IAMVideoProcAmp,
1682 (void **)&pProcAmp);
1687 hr = pProcAmp->lpVtbl->Get(pProcAmp, nProperty, pValue, &Flags);
1689 ERR("Failed to get property for video\n");
1692 SAFE_RELEASE(pProcAmp);
1696 static STDMETHODIMP SetVideoProcAmp(long nProperty, long value)
1700 IAMVideoProcAmp *pProcAmp = NULL;
1701 hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
1702 &IID_IAMVideoProcAmp,
1703 (void **)&pProcAmp);
1708 hr = pProcAmp->lpVtbl->Set(pProcAmp, nProperty, value,
1709 VideoProcAmp_Flags_Manual);
1711 ERR("Failed to set property for video\n");
1713 SAFE_RELEASE(pProcAmp);
1717 static char *__wchar_to_char(const WCHAR *pwstr)
1722 len = wcslen(pwstr) + 1;
1723 pstr = (char *)g_malloc0(sizeof(char) * len);
1724 wcstombs(pstr, pwstr, len + 1);
1729 int marucam_device_check(int log_flag)
1731 struct timeval t1, t2;
1733 char *device_name = NULL;
1734 HRESULT hr = E_FAIL;
1735 ICreateDevEnum *pCreateDevEnum = NULL;
1736 IGraphBuilder *pGB = NULL;
1737 ICaptureGraphBuilder2 *pCGB = NULL;
1738 IBaseFilter *pSrcFilter = NULL;
1739 IEnumMoniker *pEnumMK = NULL;
1740 IMoniker *pMoniKer = NULL;
1741 IAMStreamConfig *pSConfig = NULL;
1742 int iCount = 0, iSize = 0;
1744 gettimeofday(&t1, NULL);
1745 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1747 fprintf(stdout, "[Webcam] failed to CoInitailizeEx\n");
1748 gettimeofday(&t2, NULL);
1749 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
1750 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
1754 hr = CoCreateInstance(&CLSID_FilterGraph, NULL,
1759 fprintf(stdout, "[Webcam] Failed to create GraphBuilder, 0x%x\n", hr);
1761 gettimeofday(&t2, NULL);
1762 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
1763 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
1767 hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL,
1769 &IID_ICaptureGraphBuilder2,
1773 "[Webcam] Failed to create CaptureGraphBuilder2, 0x%x\n", hr);
1776 gettimeofday(&t2, NULL);
1777 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
1778 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
1782 hr = pCGB->lpVtbl->SetFiltergraph(pCGB, pGB);
1784 fprintf(stdout, "[Webcam] Failed to SetFiltergraph, 0x%x\n", hr);
1788 gettimeofday(&t2, NULL);
1789 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
1790 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
1794 hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL,
1796 &IID_ICreateDevEnum,
1797 (void **)&pCreateDevEnum);
1800 "[Webcam] failed to create instance of CLSID_SystemDeviceEnum\n");
1804 gettimeofday(&t2, NULL);
1805 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
1806 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
1810 hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum,
1811 &CLSID_VideoInputDeviceCategory, &pEnumMK, 0);
1813 fprintf(stdout, "[Webcam] failed to create class enumerator\n");
1814 SAFE_RELEASE(pCreateDevEnum);
1818 gettimeofday(&t2, NULL);
1819 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
1820 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
1825 fprintf(stdout, "[Webcam] class enumerator is NULL!!\n");
1826 SAFE_RELEASE(pCreateDevEnum);
1830 gettimeofday(&t2, NULL);
1831 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
1832 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
1835 pEnumMK->lpVtbl->Reset(pEnumMK);
1837 hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL);
1838 if (FAILED(hr) || (hr == S_FALSE)) {
1839 fprintf(stdout, "[Webcam] enum moniker returns a invalid value.\n");
1840 SAFE_RELEASE(pEnumMK);
1841 SAFE_RELEASE(pCreateDevEnum);
1845 gettimeofday(&t2, NULL);
1846 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
1847 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
1851 IPropertyBag *pBag = NULL;
1852 hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0,
1856 fprintf(stdout, "[Webcam] failed to bind to storage.\n");
1857 SAFE_RELEASE(pEnumMK);
1858 SAFE_RELEASE(pCreateDevEnum);
1862 gettimeofday(&t2, NULL);
1863 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
1864 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
1869 hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);
1873 SysFreeString(var.bstrVal);
1875 SAFE_RELEASE(pMoniKer);
1876 SAFE_RELEASE(pEnumMK);
1877 SAFE_RELEASE(pCreateDevEnum);
1881 gettimeofday(&t2, NULL);
1882 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
1883 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
1886 device_name = __wchar_to_char(var.bstrVal);
1887 fprintf(stdout, "[Webcam] Device name : %s\n", device_name);
1888 g_free(device_name);
1889 hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL,
1891 (void **)&pSrcFilter);
1894 "[Webcam] Counldn't bind moniker to filter object!!\n");
1895 SysFreeString(var.bstrVal);
1897 SAFE_RELEASE(pMoniKer);
1898 SAFE_RELEASE(pEnumMK);
1899 SAFE_RELEASE(pCreateDevEnum);
1903 gettimeofday(&t2, NULL);
1904 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
1905 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
1908 pSrcFilter->lpVtbl->AddRef(pSrcFilter);
1910 SysFreeString(var.bstrVal);
1914 SAFE_RELEASE(pMoniKer);
1916 hr = pGB->lpVtbl->AddFilter(pGB, pSrcFilter, L"Video Capture");
1917 if (hr != S_OK && hr != S_FALSE) {
1919 "[Webcam] Counldn't add Video Capture filter to our graph!\n");
1920 SAFE_RELEASE(pSrcFilter);
1921 SAFE_RELEASE(pEnumMK);
1922 SAFE_RELEASE(pCreateDevEnum);
1926 gettimeofday(&t2, NULL);
1927 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
1928 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
1932 hr = pCGB->lpVtbl->FindInterface(pCGB, &PIN_CATEGORY_CAPTURE, 0,
1933 pSrcFilter, &IID_IAMStreamConfig,
1934 (void **)&pSConfig);
1936 fprintf(stdout, "[Webcam] failed to FindInterface method\n");
1937 SAFE_RELEASE(pSrcFilter);
1938 SAFE_RELEASE(pEnumMK);
1939 SAFE_RELEASE(pCreateDevEnum);
1943 gettimeofday(&t2, NULL);
1944 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
1945 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
1949 hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);
1951 fprintf(stdout, "[Webcam] failed to GetNumberOfCapabilities method\n");
1952 SAFE_RELEASE(pSConfig);
1953 SAFE_RELEASE(pSrcFilter);
1954 SAFE_RELEASE(pEnumMK);
1955 SAFE_RELEASE(pCreateDevEnum);
1959 gettimeofday(&t2, NULL);
1960 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
1961 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
1965 if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
1967 for (iFormat = 0; iFormat < iCount; iFormat++) {
1968 VIDEO_STREAM_CONFIG_CAPS scc;
1969 AM_MEDIA_TYPE *pmtConfig;
1971 hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat, &pmtConfig,
1974 if (IsEqualIID(&pmtConfig->formattype, &FORMAT_VideoInfo)) {
1975 VIDEOINFOHEADER *pvi =
1976 (VIDEOINFOHEADER *)pmtConfig->pbFormat;
1977 if (pvi->bmiHeader.biCompression == BI_RGB) {
1978 fprintf(stdout, "[Webcam] RGB BitCount: %d, %ux%u\n",
1979 pvi->bmiHeader.biBitCount,
1980 pvi->bmiHeader.biWidth,
1981 pvi->bmiHeader.biHeight);
1984 "[Webcam] PixelFormat: %c%c%c%c, %ux%u\n",
1985 (char)(pvi->bmiHeader.biCompression),
1986 (char)(pvi->bmiHeader.biCompression >> 8),
1987 (char)(pvi->bmiHeader.biCompression >> 16),
1988 (char)(pvi->bmiHeader.biCompression >> 24),
1989 pvi->bmiHeader.biWidth,
1990 pvi->bmiHeader.biHeight);
1993 DeleteMediaType(pmtConfig);
1998 hr = pGB->lpVtbl->RemoveFilter(pGB, pSrcFilter);
2000 fprintf(stdout, "[Webcam] Failed to remove source filer. 0x%x\n", hr);
2003 SAFE_RELEASE(pSConfig);
2004 SAFE_RELEASE(pSrcFilter);
2007 SAFE_RELEASE(pEnumMK);
2008 SAFE_RELEASE(pCreateDevEnum);
2010 gettimeofday(&t2, NULL);
2011 fprintf(stdout, "[Webcam] Elapsed time : %lu.%06lu\n",
2012 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
2017 /* MARUCAM_CMD_INIT */
2018 void marucam_device_init(MaruCamState *state)
2023 void marucam_device_exit(MaruCamState *state)
2027 /* MARUCAM_CMD_OPEN */
2028 void marucam_device_open(MaruCamState *state)
2031 uint32_t dwHeight, dwWidth, dwDstFmt;
2032 MaruCamParam *param = state->param;
2035 hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2037 ERR("CoInitailizeEx\n");
2038 ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
2039 param->errCode = EINVAL;
2043 hr = GraphBuilder_Init();
2045 ERR("GraphBuilder_Init\n");
2050 param->errCode = EINVAL;
2051 ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
2055 hr = BindSourceFilter();
2057 ERR("BindSourceFilter\n");
2062 param->errCode = EINVAL;
2063 ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
2067 hr = BindTargetFilter();
2069 ERR("BindTargetFilter\n");
2074 param->errCode = EINVAL;
2075 ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
2079 hr = ConnectFilters();
2081 ERR("ConnectFilters\n");
2086 param->errCode = EINVAL;
2087 ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
2094 dwHeight = supported_dst_frames[cur_frame_idx].height;
2095 dwWidth = supported_dst_frames[cur_frame_idx].width;
2096 dwDstFmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
2097 hr = SetFormat(dwWidth, dwHeight, dwDstFmt, &g_dwSrcFmt);
2099 ERR("failed to Set default values\n");
2104 param->errCode = EINVAL;
2105 ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
2113 /* MARUCAM_CMD_CLOSE */
2114 void marucam_device_close(MaruCamState *state)
2116 MaruCamParam *param = state->param;
2126 /* MARUCAM_CMD_START_PREVIEW */
2127 void marucam_device_start_preview(MaruCamState *state)
2130 uint32_t pixfmt, width, height;
2131 MaruCamParam *param = state->param;
2135 width = supported_dst_frames[cur_frame_idx].width;
2136 height = supported_dst_frames[cur_frame_idx].height;
2137 pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
2138 state->buf_size = get_sizeimage(pixfmt, width, height);
2140 INFO("Pixfmt(%c%c%c%c), W:H(%d:%d), buf size(%u)\n",
2141 (char)(pixfmt), (char)(pixfmt >> 8),
2142 (char)(pixfmt >> 16), (char)(pixfmt >> 24),
2143 width, height, state->buf_size);
2144 INFO("Starting preview\n");
2146 assert(g_pCallback != NULL);
2147 hr = ((HWCInPin *)g_pInputPin)->SetGrabCallbackIF(g_pInputPin,
2150 ERR("Failed to set IGrabCallback interface.\n");
2151 param->errCode = EINVAL;
2159 grab_buf = (void *)g_malloc0(state->buf_size);
2160 if (grab_buf == NULL) {
2161 param->errCode = ENOMEM;
2165 hr = g_pMediaControl->lpVtbl->Run(g_pMediaControl);
2167 ERR("Failed to run media control. hr=0x%x\n", hr);
2168 param->errCode = EINVAL;
2172 qemu_mutex_lock(&state->thread_mutex);
2173 state->streamon = 1;
2174 qemu_mutex_unlock(&state->thread_mutex);
2176 INFO("Streaming on ......\n");
2179 /* MARUCAM_CMD_STOP_PREVIEW */
2180 void marucam_device_stop_preview(MaruCamState *state)
2183 MaruCamParam *param = state->param;
2186 INFO("...... Streaming off\n");
2187 qemu_mutex_lock(&state->thread_mutex);
2188 state->streamon = 0;
2189 qemu_mutex_unlock(&state->thread_mutex);
2191 hr = ((HWCInPin *)g_pInputPin)->SetGrabCallbackIF(g_pInputPin, NULL);
2193 ERR("Failed to set IGrabCallback interface.\n");
2194 param->errCode = EINVAL;
2198 hr = g_pMediaControl->lpVtbl->Stop(g_pMediaControl);
2200 ERR("Failed to stop media control.\n");
2201 param->errCode = EINVAL;
2209 state->buf_size = 0;
2211 INFO("Stopping preview\n");
2214 /* MARUCAM_CMD_S_PARAM */
2215 void marucam_device_s_param(MaruCamState *state)
2217 MaruCamParam *param = state->param;
2219 /* We use default FPS of the webcam */
2223 /* MARUCAM_CMD_G_PARAM */
2224 void marucam_device_g_param(MaruCamState *state)
2226 MaruCamParam *param = state->param;
2228 /* We use default FPS of the webcam
2229 * return a fixed value on guest ini file (1/30).
2232 param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */
2233 param->stack[1] = 1; /* numerator */
2234 param->stack[2] = 30; /* denominator */
2237 /* MARUCAM_CMD_S_FMT */
2238 void marucam_device_s_fmt(MaruCamState *state)
2240 uint32_t width, height, pixfmt, pidx, fidx;
2241 MaruCamParam *param = state->param;
2244 width = param->stack[0];
2245 height = param->stack[1];
2246 pixfmt = param->stack[2];
2248 for (fidx = 0; fidx < ARRAY_SIZE(supported_dst_frames); fidx++) {
2249 if ((supported_dst_frames[fidx].width == width) &&
2250 (supported_dst_frames[fidx].height == height)) {
2254 if (fidx == ARRAY_SIZE(supported_dst_frames)) {
2255 param->errCode = EINVAL;
2258 for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) {
2259 if (supported_dst_pixfmts[pidx].fmt == pixfmt) {
2263 if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {
2264 param->errCode = EINVAL;
2268 if ((supported_dst_frames[cur_frame_idx].width != width) &&
2269 (supported_dst_frames[cur_frame_idx].height != height)) {
2270 HRESULT hr = SetFormat(width, height, pixfmt, &g_dwSrcFmt);
2272 param->errCode = EINVAL;
2277 cur_frame_idx = fidx;
2280 pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
2281 width = supported_dst_frames[cur_frame_idx].width;
2282 height = supported_dst_frames[cur_frame_idx].height;
2284 param->stack[0] = width;
2285 param->stack[1] = height;
2286 param->stack[2] = 1; /* V4L2_FIELD_NONE */
2287 param->stack[3] = pixfmt;
2288 param->stack[4] = get_bytesperline(pixfmt, width);
2289 param->stack[5] = get_sizeimage(pixfmt, width, height);
2290 param->stack[6] = 0;
2291 param->stack[7] = 0;
2293 TRACE("Set format...\n");
2296 /* MARUCAM_CMD_G_FMT */
2297 void marucam_device_g_fmt(MaruCamState *state)
2299 uint32_t width, height, pixfmt;
2300 MaruCamParam *param = state->param;
2303 pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
2304 width = supported_dst_frames[cur_frame_idx].width;
2305 height = supported_dst_frames[cur_frame_idx].height;
2307 param->stack[0] = width;
2308 param->stack[1] = height;
2309 param->stack[2] = 1; /* V4L2_FIELD_NONE */
2310 param->stack[3] = pixfmt;
2311 param->stack[4] = get_bytesperline(pixfmt, width);
2312 param->stack[5] = get_sizeimage(pixfmt, width, height);
2313 param->stack[6] = 0;
2314 param->stack[7] = 0;
2316 TRACE("Get format...\n");
2319 void marucam_device_try_fmt(MaruCamState *state)
2321 uint32_t width, height, pixfmt, i;
2322 MaruCamParam *param = state->param;
2325 width = param->stack[0];
2326 height = param->stack[1];
2327 pixfmt = param->stack[2];
2329 for (i = 0; i < ARRAY_SIZE(supported_dst_frames); i++) {
2330 if ((supported_dst_frames[i].width == width) &&
2331 (supported_dst_frames[i].height == height)) {
2335 if (i == ARRAY_SIZE(supported_dst_frames)) {
2336 param->errCode = EINVAL;
2339 for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
2340 if (supported_dst_pixfmts[i].fmt == pixfmt) {
2344 if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
2345 param->errCode = EINVAL;
2349 param->stack[0] = width;
2350 param->stack[1] = height;
2351 param->stack[2] = 1; /* V4L2_FIELD_NONE */
2352 param->stack[3] = pixfmt;
2353 param->stack[4] = get_bytesperline(pixfmt, width);
2354 param->stack[5] = get_sizeimage(pixfmt, width, height);
2355 param->stack[6] = 0;
2356 param->stack[7] = 0;
2359 void marucam_device_enum_fmt(MaruCamState *state)
2362 MaruCamParam *param = state->param;
2365 index = param->stack[0];
2367 if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
2368 param->errCode = EINVAL;
2371 param->stack[1] = 0; /* flags = NONE */
2372 param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */
2373 /* set description */
2374 switch (supported_dst_pixfmts[index].fmt) {
2375 case V4L2_PIX_FMT_YUYV:
2376 memcpy(¶m->stack[3], "YUYV", 32);
2378 case V4L2_PIX_FMT_YUV420:
2379 memcpy(¶m->stack[3], "YU12", 32);
2381 case V4L2_PIX_FMT_YVU420:
2382 memcpy(¶m->stack[3], "YV12", 32);
2385 ERR("Invalid pixel format\n");
2386 param->errCode = EINVAL;
2391 void marucam_device_qctrl(MaruCamState *state)
2395 long property, min, max, step, def_val, set_val;
2396 char name[32] = {0,};
2397 MaruCamParam *param = state->param;
2400 id = param->stack[0];
2403 case V4L2_CID_BRIGHTNESS:
2404 TRACE("V4L2_CID_BRIGHTNESS\n");
2405 property = VideoProcAmp_Brightness;
2406 memcpy((void *)name, (void *)"brightness", 32);
2409 case V4L2_CID_CONTRAST:
2410 TRACE("V4L2_CID_CONTRAST\n");
2411 property = VideoProcAmp_Contrast;
2412 memcpy((void *)name, (void *)"contrast", 32);
2415 case V4L2_CID_SATURATION:
2416 TRACE("V4L2_CID_SATURATION\n");
2417 property = VideoProcAmp_Saturation;
2418 memcpy((void *)name, (void *)"saturation", 32);
2421 case V4L2_CID_SHARPNESS:
2422 TRACE("V4L2_CID_SHARPNESS\n");
2423 property = VideoProcAmp_Sharpness;
2424 memcpy((void *)name, (void *)"sharpness", 32);
2428 ERR("Invalid control ID\n");
2429 param->errCode = EINVAL;
2432 hr = QueryVideoProcAmp(property, &min, &max, &step, &def_val);
2434 param->errCode = EINVAL;
2435 ERR("failed to query video controls [HRESULT : 0x%x]\n", hr);
2438 qctrl_tbl[i].hit = 1;
2439 qctrl_tbl[i].min = min;
2440 qctrl_tbl[i].max = max;
2441 qctrl_tbl[i].step = step;
2442 qctrl_tbl[i].init_val = def_val;
2444 if ((qctrl_tbl[i].min + qctrl_tbl[i].max) == 0) {
2447 set_val = (qctrl_tbl[i].min + qctrl_tbl[i].max) / 2;
2449 hr = SetVideoProcAmp(property, set_val);
2451 param->errCode = EINVAL;
2452 ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
2457 param->stack[0] = id;
2458 param->stack[1] = MARUCAM_CTRL_VALUE_MIN; /* minimum */
2459 param->stack[2] = MARUCAM_CTRL_VALUE_MAX; /* maximum */
2460 param->stack[3] = MARUCAM_CTRL_VALUE_STEP; /* step */
2461 param->stack[4] = MARUCAM_CTRL_VALUE_MID; /* default_value */
2462 param->stack[5] = V4L2_CTRL_FLAG_SLIDER;
2463 /* name field setting */
2464 memcpy(¶m->stack[6], (void *)name, sizeof(name)/sizeof(name[0]));
2467 void marucam_device_s_ctrl(MaruCamState *state)
2471 long property, set_val;
2472 MaruCamParam *param = state->param;
2476 switch (param->stack[0]) {
2477 case V4L2_CID_BRIGHTNESS:
2479 property = VideoProcAmp_Brightness;
2481 case V4L2_CID_CONTRAST:
2483 property = VideoProcAmp_Contrast;
2485 case V4L2_CID_SATURATION:
2487 property = VideoProcAmp_Saturation;
2489 case V4L2_CID_SHARPNESS:
2491 property = VideoProcAmp_Sharpness;
2494 param->errCode = EINVAL;
2497 set_val = value_convert_from_guest(qctrl_tbl[i].min,
2498 qctrl_tbl[i].max, (long)param->stack[1]);
2499 hr = SetVideoProcAmp(property, set_val);
2501 param->errCode = EINVAL;
2502 ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
2507 void marucam_device_g_ctrl(MaruCamState *state)
2511 long property, get_val;
2512 MaruCamParam *param = state->param;
2515 switch (param->stack[0]) {
2516 case V4L2_CID_BRIGHTNESS:
2518 property = VideoProcAmp_Brightness;
2520 case V4L2_CID_CONTRAST:
2522 property = VideoProcAmp_Contrast;
2524 case V4L2_CID_SATURATION:
2526 property = VideoProcAmp_Saturation;
2528 case V4L2_CID_SHARPNESS:
2530 property = VideoProcAmp_Sharpness;
2533 param->errCode = EINVAL;
2537 hr = GetVideoProcAmp(property, &get_val);
2539 param->errCode = EINVAL;
2540 ERR("failed to get video control value!!!, [HRESULT : 0x%x]\n", hr);
2543 param->stack[0] = (uint32_t)value_convert_to_guest(qctrl_tbl[i].min,
2544 qctrl_tbl[i].max, get_val);
2547 void marucam_device_enum_fsizes(MaruCamState *state)
2549 uint32_t index, pixfmt, i;
2550 MaruCamParam *param = state->param;
2553 index = param->stack[0];
2554 pixfmt = param->stack[1];
2556 if (index >= ARRAY_SIZE(supported_dst_frames)) {
2557 param->errCode = EINVAL;
2560 for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
2561 if (supported_dst_pixfmts[i].fmt == pixfmt) {
2566 if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
2567 param->errCode = EINVAL;
2571 param->stack[0] = supported_dst_frames[index].width;
2572 param->stack[1] = supported_dst_frames[index].height;
2575 void marucam_device_enum_fintv(MaruCamState *state)
2577 MaruCamParam *param = state->param;
2581 /* switch by index(param->stack[0]) */
2582 switch (param->stack[0]) {
2584 param->stack[1] = 30; /* denominator */
2587 param->errCode = EINVAL;
2590 param->stack[0] = 1; /* numerator */
2593 void yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
2594 uint32_t width, uint32_t height, uint32_t yvu)
2597 const unsigned char *src1;
2598 unsigned char *udest, *vdest;
2600 /* copy the Y values */
2602 for (i = 0; i < height; i++) {
2603 for (j = 0; j < width; j += 2) {
2610 /* copy the U and V values */
2611 src++; /* point to V */
2612 src1 = src + width * 2; /* next line */
2615 udest = dest + width * height / 4;
2618 vdest = dest + width * height / 4;
2620 for (i = 0; i < height; i += 2) {
2621 for (j = 0; j < width; j += 2) {
2622 *udest++ = ((int) src[0] + src1[0]) / 2; /* U */
2623 *vdest++ = ((int) src[2] + src1[2]) / 2; /* V */
2632 #define RGB2Y(r, g, b, y) \
2633 (y) = ((8453 * (r) + 16594 * (g) + 3223 * (b) + 524288) >> 15)
2635 #define RGB2UV(r, g, b, u, v) \
2637 (u) = ((-4878 * (r) - 9578 * (g) + 14456 * (b) + 4210688) >> 15); \
2638 (v) = ((14456 * (r) - 12105 * (g) - 2351 * (b) + 4210688) >> 15); \
2641 #define CLIP(color) \
2642 (unsigned char)(((color) > 0xFF) ? 0xff : (((color) < 0) ? 0 : (color)))
2644 void rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,
2645 uint32_t width, uint32_t height, uint32_t yvu)
2648 unsigned char *udest, *vdest;
2649 uint32_t bytesperline = width * 3;
2652 for (y = 0; y < height; y++) {
2653 for (x = 0; x < width; x++) {
2654 RGB2Y(src[2], src[1], src[0], *dest++);
2657 src += bytesperline - 3 * width;
2659 src -= height * bytesperline;
2664 udest = dest + width * height / 4;
2667 vdest = dest + width * height / 4;
2670 for (y = 0; y < height / 2; y++) {
2671 for (x = 0; x < width / 2; x++) {
2672 uint32_t avg_src[3];
2674 avg_src[0] = (src[0] + src[3] + src[bytesperline] +
2675 src[bytesperline + 3]) / 4;
2676 avg_src[1] = (src[1] + src[4] + src[bytesperline + 1] +
2677 src[bytesperline + 4]) / 4;
2678 avg_src[2] = (src[2] + src[5] + src[bytesperline + 2] +
2679 src[bytesperline + 5]) / 4;
2680 RGB2UV(avg_src[2], avg_src[1], avg_src[0], *udest++, *vdest++);
2683 src += 2 * bytesperline - 3 * width;
2687 void rgb24_to_yuyv(unsigned char *src, unsigned char *dest,
2688 uint32_t width, uint32_t height)
2692 for (i = 0; i < (width * height * 3); i = i + 6) {
2694 *dest++ = CLIP(0.299 * (src[i + 2] - 128) +
2695 0.587 * (src[i + 1] - 128) +
2696 0.114 * (src[i] - 128) + 128);
2698 *dest++ = CLIP(((-0.147 * (src[i + 2] - 128) -
2699 0.289 * (src[i + 1] - 128) +
2700 0.436 * (src[i] - 128) + 128) +
2701 (-0.147 * (src[i + 5] - 128) -
2702 0.289 * (src[i + 4] - 128) +
2703 0.436 * (src[i + 3] - 128) + 128)) / 2);
2705 *dest++ = CLIP(0.299 * (src[i + 5] - 128) +
2706 0.587 * (src[i + 4] - 128) +
2707 0.114 * (src[i + 3] - 128) + 128);
2709 *dest++ = CLIP(((0.615 * (src[i + 2] - 128) -
2710 0.515 * (src[i + 1] - 128) -
2711 0.100 * (src[i] - 128) + 128) +
2712 (0.615 * (src[i + 5] - 128) -
2713 0.515 * (src[i + 4] - 128) -
2714 0.100 * (src[i + 3] - 128) + 128)) / 2);
2718 void yuv420_to_yvu420(unsigned char *src, unsigned char *dest,
2719 uint32_t width, uint32_t height)
2721 unsigned char *psrc_y, *pdst_y;
2722 unsigned char *psrc_u, *pdst_u;
2723 unsigned char *psrc_v, *pdst_v;
2726 psrc_u = psrc_y + (width * height);
2727 psrc_v = psrc_u + (width * height / 4);
2730 pdst_v = pdst_y + (width * height);
2731 pdst_u = pdst_v + (width * height / 4);
2733 memcpy(pdst_y, psrc_y, width * height);
2734 memcpy(pdst_v, psrc_v, width * height / 4);
2735 memcpy(pdst_u, psrc_u, width * height / 4);
2738 void yuv420_to_yuyv(unsigned char *src, unsigned char *dest,
2739 uint32_t width, uint32_t height)
2745 uint32_t linesize = width * 2;
2746 uint32_t uvlinesize = width / 2;
2747 uint32_t offset = 0;
2748 uint32_t offset1 = 0;
2749 uint32_t offsety = 0;
2750 uint32_t offsety1 = 0;
2751 uint32_t offsetuv = 0;
2759 pu = py + (width * height);
2760 pv = pu + (width * height / 4);
2762 for (h = 0; h < height; h += 2) {
2765 offset = h * linesize;
2766 offset1 = (h + 1) * linesize;
2767 offsety = h * width;
2768 offsety1 = (h + 1) * width;
2769 offsetuv = huv * uvlinesize;
2771 for (w = 0; w < linesize; w += 4) {
2773 dest[w + offset] = py[wy + offsety];
2775 dest[(w + 1) + offset] = pu[wuv + offsetuv];
2777 dest[(w + 2) + offset] = py[(wy + 1) + offsety];
2779 dest[(w + 3) + offset] = pv[wuv + offsetuv];
2782 dest[w + offset1] = py[wy + offsety1];
2784 dest[(w + 1) + offset1] = pu[wuv + offsetuv];
2786 dest[(w + 2) + offset1] = py[(wy + 1) + offsety1];
2788 dest[(w + 3) + offset1] = pv[wuv + offsetuv];