f2a044501ae76d4ef92dcdab164c3089490c7043
[sdk/emulator/qemu.git] / tizen / src / hw / maru_camera_win32_pci.c
1 /*
2  * Implementation of MARU Virtual Camera device by PCI bus on Windows.
3  *
4  * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
5  *
6  * Contact:
7  * JinHyung Jo <jinhyung.jo@samsung.com>
8  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
9  *
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.
14  *
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.
19  *
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,
23  * MA  02110-1301, USA.
24  *
25  * Contributors:
26  * - S-Core Co., Ltd
27  *
28  */
29
30
31 #include "qemu-common.h"
32 #include "maru_camera_common.h"
33 #include "tizen/src/debug_ch.h"
34
35 #define CINTERFACE
36 #define COBJMACROS
37 #include "ocidl.h"
38 #include "errors.h"      /* for VFW_E_XXXX */
39 #include "mmsystem.h"    /* for MAKEFOURCC macro */
40 #include "maru_camera_win32_interface.h"
41
42 MULTI_DEBUG_CHANNEL(tizen, camera_win32);
43
44 /*
45  * COM Interface implementations
46  *
47  */
48
49 #define SAFE_RELEASE(x) \
50     do { \
51         if (x) { \
52             (x)->lpVtbl->Release(x); \
53             x = NULL; \
54         } \
55     } while (0)
56
57 typedef HRESULT (STDAPICALLTYPE *CallbackFn)(ULONG dwSize, BYTE *pBuffer);
58
59 /*
60  * HWCGrabCallback
61  */
62
63 typedef struct HWCGrabCallback {
64     IGrabCallback IGrabCallback_iface;
65     long m_cRef;
66     CallbackFn m_pCallback;
67     STDMETHODIMP (*SetCallback)(IGrabCallback *iface, CallbackFn pCallbackFn);
68 } HWCGrabCallback;
69
70 static inline HWCGrabCallback *impl_from_IGrabCallback(IGrabCallback *iface)
71 {
72     return CONTAINING_RECORD(iface, HWCGrabCallback, IGrabCallback_iface);
73 }
74
75 static STDMETHODIMP HWCGrabCallback_QueryInterface(IGrabCallback *iface,
76                                                    REFIID riid, void **ppv)
77 {
78     if (IsEqualIID(riid, &IID_IUnknown)) {
79         *ppv = (IUnknown *)iface;
80     } else if (IsEqualIID(riid, &IID_IGrabCallback)) {
81         *ppv = (IGrabCallback *)iface;
82     } else {
83         *ppv = NULL;
84         return E_NOINTERFACE;
85     }
86
87     IGrabCallback_AddRef(iface);
88     return S_OK;
89 }
90
91 static STDMETHODIMP_(ULONG) HWCGrabCallback_AddRef(IGrabCallback *iface)
92 {
93     HWCGrabCallback *This = impl_from_IGrabCallback(iface);
94
95     return InterlockedIncrement(&This->m_cRef);
96 }
97
98 static STDMETHODIMP_(ULONG) HWCGrabCallback_Release(IGrabCallback *iface)
99 {
100     HWCGrabCallback *This = impl_from_IGrabCallback(iface);
101
102     if (InterlockedDecrement(&This->m_cRef) == 0) {
103         This->m_pCallback = NULL;
104         g_free((void *)This);
105         This = NULL;
106         return 0;
107     }
108
109     return This->m_cRef;
110 }
111
112 static STDMETHODIMP HWCGrabCallback_Grab(IGrabCallback *iface,
113                                          ULONG dwSize, BYTE *pBuffer)
114 {
115     HWCGrabCallback *This = impl_from_IGrabCallback(iface);
116
117     if (This->m_pCallback) {
118         HRESULT hr = This->m_pCallback(dwSize, pBuffer);
119         if (FAILED(hr)) {
120             return E_FAIL;
121         } else {
122             return S_OK;
123         }
124     }
125
126     return E_FAIL;
127 }
128
129 static STDMETHODIMP HWCGrabCallback_SetCallback(IGrabCallback *iface,
130                                                 CallbackFn pCallbackFn)
131 {
132     HWCGrabCallback *This = impl_from_IGrabCallback(iface);
133
134     This->m_pCallback = pCallbackFn;
135     return S_OK;
136 }
137
138 static IGrabCallbackVtbl HWCGrabCallback_Vtbl = {
139         HWCGrabCallback_QueryInterface,
140         HWCGrabCallback_AddRef,
141         HWCGrabCallback_Release,
142         HWCGrabCallback_Grab
143 };
144
145 static STDMETHODIMP HWCGrabCallback_Construct(IGrabCallback **ppv)
146 {
147     HWCGrabCallback *This =
148             (HWCGrabCallback *)g_malloc0(sizeof(HWCGrabCallback));
149
150     if (!This) {
151         ERR("failed to HWCGrabCallback_Construct, E_OUTOFMEMORY\n");
152         return E_OUTOFMEMORY;
153     }
154
155     This->IGrabCallback_iface.lpVtbl = &HWCGrabCallback_Vtbl;
156     This->m_cRef = 1;
157     This->m_pCallback = NULL;
158     This->SetCallback = HWCGrabCallback_SetCallback;
159     *ppv = &This->IGrabCallback_iface;
160     return S_OK;
161 }
162
163 /*
164  * HWCPin
165  */
166
167 typedef struct HWCInPin {
168     IPin IPin_iface;
169     IMemInputPin IMemInputPin_iface;
170     IBaseFilter *m_pCFilter;
171     IPin *m_pConnectedPin;
172     IGrabCallback *m_pCallback;
173     IMemAllocator *m_pAllocator;
174     BOOL m_bReadOnly;
175     long m_cRef;
176     STDMETHODIMP (*SetGrabCallbackIF)(IPin *iface, IGrabCallback *pCaptureCB);
177 } HWCInPin;
178
179 static inline HWCInPin *impl_from_IPin(IPin *iface)
180 {
181     return CONTAINING_RECORD(iface, HWCInPin, IPin_iface);
182 }
183
184 static inline HWCInPin *impl_from_IMemInputPin(IMemInputPin *iface)
185 {
186     return CONTAINING_RECORD(iface, HWCInPin, IMemInputPin_iface);
187 }
188
189 static STDMETHODIMP HWCPin_QueryInterface(IPin *iface, REFIID riid, void **ppv)
190 {
191     HWCInPin *This = impl_from_IPin(iface);
192
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);
202     } else {
203         *ppv = NULL;
204         return E_NOINTERFACE;
205     }
206
207     return S_OK;
208 }
209
210 static STDMETHODIMP_(ULONG) HWCPin_AddRef(IPin *iface)
211 {
212     HWCInPin *This = impl_from_IPin(iface);
213
214     return InterlockedIncrement(&This->m_cRef);
215 }
216
217 static STDMETHODIMP_(ULONG) HWCPin_Release(IPin *iface)
218 {
219     HWCInPin *This = impl_from_IPin(iface);
220
221     if (InterlockedDecrement(&This->m_cRef) == 0) {
222         if (This->m_pCallback) {
223             SAFE_RELEASE(This->m_pCallback);
224         }
225         if (This->m_pConnectedPin) {
226             SAFE_RELEASE(This->m_pConnectedPin);
227         }
228         if (This->m_pAllocator) {
229             IMemAllocator_Decommit(This->m_pAllocator);
230             SAFE_RELEASE(This->m_pAllocator);
231         }
232         g_free((void *)This);
233         This = NULL;
234         return 0;
235     }
236     return This->m_cRef;
237 }
238
239 static STDMETHODIMP HWCPin_Connect(IPin *iface,
240                                    IPin *pReceivePin,
241                                    const AM_MEDIA_TYPE *pmt)
242 {
243     HWCInPin *This = impl_from_IPin(iface);
244
245     if (!pReceivePin) {
246         return E_POINTER;
247     }
248
249     if (This->m_pConnectedPin) {
250         return VFW_E_ALREADY_CONNECTED;
251     }
252
253     if (!pmt) {
254         return S_OK;
255     }
256     return S_FALSE;
257 }
258
259 static STDMETHODIMP HWCPin_ReceiveConnection(IPin *iface, IPin *pConnector,
260                                              const AM_MEDIA_TYPE *pmt)
261 {
262     PIN_DIRECTION pd;
263     FILTER_STATE fs;
264     HWCInPin *This = impl_from_IPin(iface);
265
266     if (pConnector == NULL || pmt == NULL) {
267         return E_POINTER;
268     }
269
270     if (This->m_pConnectedPin) {
271         return VFW_E_ALREADY_CONNECTED;
272     }
273     IBaseFilter_GetState(This->m_pCFilter, 0, &fs);
274     if (fs != State_Stopped) {
275         return VFW_E_NOT_STOPPED;
276     }
277     IPin_QueryDirection(pConnector, &pd);
278     if (pd == PINDIR_INPUT) {
279         return VFW_E_INVALID_DIRECTION;
280     }
281
282     This->m_pConnectedPin = pConnector;
283     IPin_AddRef(This->m_pConnectedPin);
284     return S_OK;
285 }
286
287 static STDMETHODIMP HWCPin_Disconnect(IPin *iface)
288 {
289     HWCInPin *This = impl_from_IPin(iface);
290
291     HRESULT hr;
292     FILTER_STATE fs;
293     IBaseFilter_GetState(This->m_pCFilter, 0, &fs);
294     if (fs != State_Stopped) {
295         return VFW_E_NOT_STOPPED;
296     }
297     if (This->m_pConnectedPin == NULL) {
298         hr = S_FALSE;
299     } else {
300         if (This->m_pAllocator) {
301             hr = IMemAllocator_Decommit(This->m_pAllocator);
302             if (FAILED(hr)) {
303                 return hr;
304             }
305             SAFE_RELEASE(This->m_pAllocator);
306         }
307         SAFE_RELEASE(This->m_pConnectedPin);
308         hr = S_OK;
309     }
310     return hr;
311 }
312
313 static STDMETHODIMP HWCPin_ConnectedTo(IPin *iface, IPin **ppPin)
314 {
315     HWCInPin *This = impl_from_IPin(iface);
316
317     if (ppPin == NULL) {
318         return E_POINTER;
319     }
320
321     if (This->m_pConnectedPin == NULL) {
322         *ppPin = NULL;
323         return VFW_E_NOT_CONNECTED;
324     } else {
325         *ppPin = This->m_pConnectedPin;
326         IPin_AddRef(This->m_pConnectedPin);
327     }
328     return S_OK;
329 }
330
331 static STDMETHODIMP HWCPin_ConnectionMediaType(IPin *iface, AM_MEDIA_TYPE *pmt)
332 {
333     if (pmt == NULL) {
334         return E_POINTER;
335     }
336     return VFW_E_NOT_CONNECTED;
337 }
338
339 static STDMETHODIMP HWCPin_QueryPinInfo(IPin *iface, PIN_INFO *pInfo)
340 {
341     HWCInPin *This = impl_from_IPin(iface);
342
343     if (pInfo == NULL) {
344         return E_POINTER;
345     }
346
347     pInfo->pFilter = This->m_pCFilter;
348     if (This->m_pCFilter) {
349         IBaseFilter_AddRef(This->m_pCFilter);
350     }
351     memcpy((void *)pInfo->achName, (void *)HWCPinName, sizeof(HWCPinName));
352     pInfo->dir = PINDIR_INPUT;
353     return S_OK;
354 }
355
356 static STDMETHODIMP HWCPin_QueryDirection(IPin *iface, PIN_DIRECTION *pPinDir)
357 {
358     if (pPinDir == NULL) {
359         return E_POINTER;
360     }
361     *pPinDir = PINDIR_INPUT;
362     return S_OK;
363 }
364
365 static STDMETHODIMP HWCPin_QueryId(IPin *iface, LPWSTR *Id)
366 {
367     PVOID pId;
368     if (Id == NULL) {
369         return E_POINTER;
370     }
371     pId = CoTaskMemAlloc(sizeof(HWCPinName));
372     memcpy((void *)pId, (void *)HWCPinName, sizeof(HWCPinName));
373     *Id = (LPWSTR)pId;
374     return S_OK;
375 }
376
377 static STDMETHODIMP HWCPin_QueryAccept(IPin *iface, const AM_MEDIA_TYPE *pmt)
378 {
379     if (pmt == NULL) {
380         return E_POINTER;
381     }
382     return S_OK;
383 }
384
385 static STDMETHODIMP HWCPin_EnumMediaTypes(IPin *iface,
386                                           IEnumMediaTypes **ppEnum)
387 {
388     if (ppEnum == NULL) {
389             return E_POINTER;
390     }
391     return E_NOTIMPL;
392 }
393
394 static STDMETHODIMP HWCPin_QueryInternalConnections(IPin *iface,
395                                                     IPin **ppPin,
396                                                     ULONG *nPin)
397 {
398     return E_NOTIMPL;
399 }
400
401 static STDMETHODIMP HWCPin_EndOfStream(IPin *iface)
402 {
403     return S_OK;
404 }
405
406 static STDMETHODIMP HWCPin_BeginFlush(IPin *iface)
407 {
408     return S_OK;
409 }
410
411 static STDMETHODIMP HWCPin_EndFlush(IPin *iface)
412 {
413     return S_OK;
414 }
415
416 static STDMETHODIMP HWCPin_NewSegment(IPin *iface, REFERENCE_TIME tStart,
417                                       REFERENCE_TIME tStop, double dRate)
418 {
419     return S_OK;
420 }
421
422 static STDMETHODIMP HWCMemInputPin_QueryInterface(IMemInputPin *iface,
423                                                   REFIID riid, void **ppv)
424 {
425     HWCInPin *This = impl_from_IMemInputPin(iface);
426
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);
436     } else {
437         *ppv = NULL;
438         return E_NOINTERFACE;
439     }
440
441     return S_OK;
442 }
443
444 static STDMETHODIMP_(ULONG) HWCMemInputPin_AddRef(IMemInputPin *iface)
445 {
446     HWCInPin *This = impl_from_IMemInputPin(iface);
447
448     return InterlockedIncrement(&This->m_cRef);
449 }
450
451 static STDMETHODIMP_(ULONG) HWCMemInputPin_Release(IMemInputPin *iface)
452 {
453     HWCInPin *This = impl_from_IMemInputPin(iface);
454
455     if (InterlockedDecrement(&This->m_cRef) == 0) {
456         if (This->m_pCallback) {
457             SAFE_RELEASE(This->m_pCallback);
458         }
459         if (This->m_pConnectedPin) {
460             SAFE_RELEASE(This->m_pConnectedPin);
461         }
462         if (This->m_pAllocator) {
463             IMemAllocator_Decommit(This->m_pAllocator);
464             SAFE_RELEASE(This->m_pAllocator);
465         }
466         g_free((void *)This);
467         This = NULL;
468         return 0;
469     }
470     return This->m_cRef;
471 }
472
473 static STDMETHODIMP HWCMemInputPin_GetAllocator(IMemInputPin *iface,
474                                                 IMemAllocator **ppAllocator)
475 {
476     HWCInPin *This = impl_from_IMemInputPin(iface);
477
478     if (ppAllocator == NULL) {
479         return E_POINTER;
480     }
481
482     if (This->m_pAllocator == NULL) {
483         HRESULT hr = CoCreateInstance(&CLSID_MemoryAllocator, NULL,
484                                         CLSCTX_INPROC_SERVER,
485                                         &IID_IMemAllocator,
486                                         (void **)&(This->m_pAllocator));
487         if (FAILED(hr)) {
488             ERR("Failed to CoCreateInstance for retrieving MemoryAllocator\n");
489             return hr;
490         }
491     }
492     ASSERT(This->m_pAllocator != NULL);
493     *ppAllocator = This->m_pAllocator;
494     IMemAllocator_AddRef(This->m_pAllocator);
495
496     return S_OK;
497 }
498
499 static STDMETHODIMP HWCMemInputPin_NotifyAllocator(IMemInputPin *iface,
500                                                    IMemAllocator *pAllocator,
501                                                    BOOL bReadOnly)
502 {
503     HWCInPin *This = impl_from_IMemInputPin(iface);
504
505     if (pAllocator == NULL) {
506         return E_POINTER;
507     }
508
509     IMemAllocator *pOldAllocator = This->m_pAllocator;
510     IMemAllocator_AddRef(pAllocator);
511     This->m_pAllocator = pAllocator;
512
513     if (pOldAllocator != NULL) {
514         SAFE_RELEASE(pOldAllocator);
515     }
516
517     This->m_bReadOnly = bReadOnly;
518
519     return S_OK;
520 }
521
522 static STDMETHODIMP HWCMemInputPin_GetAllocatorRequirements(
523                                    IMemInputPin *iface,
524                                    ALLOCATOR_PROPERTIES *pProps)
525 {
526     return E_NOTIMPL;
527 }
528
529 static STDMETHODIMP HWCMemInputPin_Receive(IMemInputPin *iface,
530                                            IMediaSample *pSample)
531 {
532     HWCInPin *This = impl_from_IMemInputPin(iface);
533
534     if (pSample == NULL) {
535         ERR("pSample is NULL\n");
536         return E_POINTER;
537     }
538     if (This->m_pCallback != NULL) {
539         HRESULT hr;
540         BYTE *pBuffer = NULL;
541         DWORD dwSize = 0;
542         dwSize = IMediaSample_GetSize(pSample);
543         hr = IMediaSample_GetPointer(pSample, &pBuffer);
544         if (FAILED(hr)) {
545             ERR("Receive function : "
546                 "failed to IMediaSample_GetPointer, 0x%ld\n", hr);
547             return hr;
548         }
549         hr = IGrabCallback_Grab(This->m_pCallback, dwSize, pBuffer);
550         if (FAILED(hr)) {
551             ERR("Receive function : failed to IGrabCallback_Grab, 0x%ld\n",
552                 hr);
553             return hr;
554         }
555     }
556     return S_OK;
557 }
558
559 static STDMETHODIMP HWCMemInputPin_ReceiveMultiple(IMemInputPin *iface,
560                                                    IMediaSample **pSamples,
561                                                    long nSamples,
562                                                    long *nSamplesProcessed)
563 {
564     HRESULT hr = S_OK;
565
566     if (pSamples == NULL) {
567         return E_POINTER;
568     }
569
570     *nSamplesProcessed = 0;
571
572     while (nSamples-- > 0) {
573         hr = IMemInputPin_Receive(iface, pSamples[*nSamplesProcessed]);
574         if (hr != S_OK) {
575             break;
576         }
577         (*nSamplesProcessed)++;
578     }
579     return hr;
580 }
581
582 static STDMETHODIMP HWCMemInputPin_ReceiveCanBlock(IMemInputPin *iface)
583 {
584     return S_FALSE;
585 }
586
587 static STDMETHODIMP HWCPin_SetCallback(IPin *iface, IGrabCallback *pCaptureCB)
588 {
589     HWCInPin *This = impl_from_IPin(iface);
590
591     if (pCaptureCB == NULL) {
592         SAFE_RELEASE(This->m_pCallback);
593     } else {
594         This->m_pCallback = pCaptureCB;
595         IGrabCallback_AddRef(This->m_pCallback);
596     }
597
598     return S_OK;
599 }
600
601
602 static IPinVtbl HWCPin_Vtbl = {
603     HWCPin_QueryInterface,
604     HWCPin_AddRef,
605     HWCPin_Release,
606     HWCPin_Connect,
607     HWCPin_ReceiveConnection,
608     HWCPin_Disconnect,
609     HWCPin_ConnectedTo,
610     HWCPin_ConnectionMediaType,
611     HWCPin_QueryPinInfo,
612     HWCPin_QueryDirection,
613     HWCPin_QueryId,
614     HWCPin_QueryAccept,
615     HWCPin_EnumMediaTypes,
616     HWCPin_QueryInternalConnections,
617     HWCPin_EndOfStream,
618     HWCPin_BeginFlush,
619     HWCPin_EndFlush,
620     HWCPin_NewSegment
621 };
622
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
633 };
634
635 static STDMETHODIMP HWCInPin_Construct(IBaseFilter *pFilter, IPin **ppv)
636 {
637     HWCInPin *This = (HWCInPin *)g_malloc0(sizeof(HWCInPin));
638
639     if (!This) {
640         ERR("failed to HWCInPin_Construct, E_OUTOFMEMORY\n");
641         return E_OUTOFMEMORY;
642     }
643
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;
651     This->m_cRef = 1;
652     This->SetGrabCallbackIF = HWCPin_SetCallback;
653     *ppv = &This->IPin_iface;
654
655     return S_OK;
656 }
657
658 /*
659  * HWCEnumPins
660  */
661
662 typedef struct HWCEnumPins {
663     IEnumPins IEnumPins_iface;
664     IBaseFilter *m_pFilter;
665     int m_nPos;
666     long m_cRef;
667 } HWCEnumPins;
668
669 static inline HWCEnumPins *impl_from_IEnumPins(IEnumPins *iface)
670 {
671     return CONTAINING_RECORD(iface, HWCEnumPins, IEnumPins_iface);
672 }
673
674 static STDMETHODIMP HWCEnumPins_QueryInterface(IEnumPins *iface,
675                                                REFIID riid, void **ppv)
676 {
677     if (ppv == NULL) {
678         return E_POINTER;
679     }
680
681     if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumPins)) {
682         *ppv = iface;
683     } else {
684         *ppv = NULL;
685         return E_NOINTERFACE;
686     }
687
688     IEnumPins_AddRef(iface);
689     return S_OK;
690 }
691
692 static STDMETHODIMP_(ULONG) HWCEnumPins_AddRef(IEnumPins *iface)
693 {
694     HWCEnumPins *This = impl_from_IEnumPins(iface);
695
696     return InterlockedIncrement(&This->m_cRef);
697 }
698
699 static STDMETHODIMP_(ULONG) HWCEnumPins_Release(IEnumPins *iface)
700 {
701     HWCEnumPins *This = impl_from_IEnumPins(iface);
702
703     if (InterlockedDecrement(&This->m_cRef) == 0) {
704         if (This->m_pFilter) {
705             SAFE_RELEASE(This->m_pFilter);
706         }
707         This->m_nPos = 0;
708         g_free((void *)This);
709         This = NULL;
710         return 0;
711     }
712     return This->m_cRef;
713 }
714
715 static STDMETHODIMP HWCEnumPins_Next(IEnumPins *iface, ULONG cPins,
716                                      IPin **ppPins, ULONG *pcFetched)
717 {
718     ULONG fetched;
719     HWCEnumPins *This = impl_from_IEnumPins(iface);
720
721     if (ppPins == NULL) {
722         return E_POINTER;
723     }
724
725     if (This->m_nPos < 1 && cPins > 0) {
726         IPin *pPin;
727         IBaseFilter_FindPin(This->m_pFilter, HWCPinName, &pPin);
728         *ppPins = pPin;
729         fetched = 1;
730         This->m_nPos++;
731     } else {
732         fetched = 0;
733     }
734
735     if (pcFetched != NULL) {
736         *pcFetched = fetched;
737     }
738
739     return (fetched == cPins) ? S_OK : S_FALSE;
740 }
741
742 static STDMETHODIMP HWCEnumPins_Skip(IEnumPins *iface, ULONG cPins)
743 {
744     HWCEnumPins *This = impl_from_IEnumPins(iface);
745     This->m_nPos += cPins;
746     return (This->m_nPos >= 1) ? S_FALSE : S_OK;
747 }
748
749 static STDMETHODIMP HWCEnumPins_Reset(IEnumPins *iface)
750 {
751     HWCEnumPins *This = impl_from_IEnumPins(iface);
752     This->m_nPos = 0;
753     return S_OK;
754 }
755
756 static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter,
757                                           int nPos, IEnumPins **ppv);
758
759 static STDMETHODIMP HWCEnumPins_Clone(IEnumPins *iface, IEnumPins **ppEnum)
760 {
761     HWCEnumPins *This = impl_from_IEnumPins(iface);
762
763     if (ppEnum == NULL) {
764         return E_POINTER;
765     }
766
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;
771     }
772
773     return S_OK;
774 }
775
776 static IEnumPinsVtbl HWCEnumPins_Vtbl = {
777     HWCEnumPins_QueryInterface,
778     HWCEnumPins_AddRef,
779     HWCEnumPins_Release,
780     HWCEnumPins_Next,
781     HWCEnumPins_Skip,
782     HWCEnumPins_Reset,
783     HWCEnumPins_Clone
784 };
785
786
787 static STDMETHODIMP HWCEnumPins_Construct(IBaseFilter *pFilter,
788                                           int nPos, IEnumPins **ppv)
789 {
790     HWCEnumPins *This = (HWCEnumPins *)g_malloc0(sizeof(HWCEnumPins));
791
792     if (!This) {
793         ERR("failed to HWCEnumPins_Construct, E_OUTOFMEMORY\n");
794         return E_OUTOFMEMORY;
795     }
796
797     This->IEnumPins_iface.lpVtbl = &HWCEnumPins_Vtbl;
798     This->m_pFilter = pFilter;
799     if (This->m_pFilter) {
800         IBaseFilter_AddRef(This->m_pFilter);
801     }
802     This->m_cRef = 1;
803     This->m_nPos = nPos;
804     *ppv = &This->IEnumPins_iface;
805
806     return S_OK;
807 }
808
809 /*
810  * HWCFilter
811  */
812
813 typedef struct HWCFilter {
814     IBaseFilter IBaseFilter_iface;
815     IPin *m_pPin;
816     IFilterGraph *m_pFilterGraph;
817     FILTER_STATE m_state;
818     long m_cRef;
819 } HWCFilter;
820
821 static inline HWCFilter *impl_from_IBaseFilter(IBaseFilter *iface)
822 {
823     return CONTAINING_RECORD(iface, HWCFilter, IBaseFilter_iface);
824 }
825
826 static STDMETHODIMP HWCFilter_QueryInterface(IBaseFilter *iface,
827                                              REFIID riid, void **ppv)
828 {
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;
837     } else {
838         *ppv = NULL;
839         return E_NOINTERFACE;
840     }
841
842     IBaseFilter_AddRef(iface);
843     return S_OK;
844 }
845
846 static STDMETHODIMP_(ULONG) HWCFilter_AddRef(IBaseFilter *iface)
847 {
848     HWCFilter *This = impl_from_IBaseFilter(iface);
849
850     return InterlockedIncrement(&This->m_cRef);
851 }
852
853 static STDMETHODIMP_(ULONG) HWCFilter_Release(IBaseFilter *iface)
854 {
855     HWCFilter *This = impl_from_IBaseFilter(iface);
856
857     if (InterlockedDecrement(&This->m_cRef) == 0) {
858         if (This->m_pPin) {
859             SAFE_RELEASE(This->m_pPin);
860         }
861         g_free((void *)This);
862         This = NULL;
863         return 0;
864     }
865     return This->m_cRef;
866 }
867
868 static STDMETHODIMP HWCFilter_GetClassID(IBaseFilter *iface, CLSID *pClsID)
869 {
870     if (pClsID == NULL) {
871         return E_POINTER;
872     }
873     return E_NOTIMPL;
874 }
875
876 static STDMETHODIMP HWCFilter_GetState(IBaseFilter *iface, DWORD dwMSecs,
877                                        FILTER_STATE *State)
878 {
879     HWCFilter *This = impl_from_IBaseFilter(iface);
880     *State = This->m_state;
881     return S_OK;
882 }
883
884 static STDMETHODIMP HWCFilter_SetSyncSource(IBaseFilter *iface,
885                                             IReferenceClock *pClock)
886 {
887     return S_OK;
888 }
889
890 static STDMETHODIMP HWCFilter_GetSyncSource(IBaseFilter *iface,
891                                             IReferenceClock **pClock)
892 {
893     *pClock = NULL;
894     return S_OK;
895 }
896
897 static STDMETHODIMP HWCFilter_Stop(IBaseFilter *iface)
898 {
899     HWCFilter *This = impl_from_IBaseFilter(iface);
900
901     IPin_EndFlush(This->m_pPin);
902     This->m_state = State_Stopped;
903     return S_OK;
904 }
905
906 static STDMETHODIMP HWCFilter_Pause(IBaseFilter *iface)
907 {
908     HWCFilter *This = impl_from_IBaseFilter(iface);
909     This->m_state = State_Paused;
910     return S_OK;
911 }
912
913 static STDMETHODIMP HWCFilter_Run(IBaseFilter *iface, REFERENCE_TIME tStart)
914 {
915     HWCFilter *This = impl_from_IBaseFilter(iface);
916
917     if (This->m_state == State_Stopped) {
918         HRESULT hr;
919         hr = IBaseFilter_Pause(iface);
920         if (FAILED(hr)) {
921             ERR("HWCFilter_Run : Failed to IBaseFilter_Pause, ret=0xld%\n", hr);
922             return hr;
923         }
924     }
925
926     This->m_state = State_Running;
927     return S_OK;
928 }
929
930 static STDMETHODIMP HWCFilter_EnumPins(IBaseFilter *iface, IEnumPins **ppEnum)
931 {
932     if (ppEnum == NULL) {
933         return E_POINTER;
934     }
935
936     HWCEnumPins_Construct(iface, 0, ppEnum);
937     return *ppEnum == NULL ? E_OUTOFMEMORY : S_OK;
938 }
939
940 static STDMETHODIMP HWCFilter_FindPin(IBaseFilter *iface, LPCWSTR Id,
941                                       IPin **ppPin)
942 {
943     HWCFilter *This = impl_from_IBaseFilter(iface);
944
945     if (ppPin == NULL) {
946         return E_POINTER;
947     }
948
949     if (memcmp((void *)Id, (void *)HWCPinName, sizeof(HWCPinName))) {
950         return VFW_E_NOT_FOUND;
951     }
952
953     if (!This->m_pPin) {
954         HWCInPin_Construct(iface, &This->m_pPin);
955     }
956     *ppPin = This->m_pPin;
957
958     IPin_AddRef(This->m_pPin);
959     return S_OK;
960 }
961
962 static STDMETHODIMP HWCFilter_QueryFilterInfo(IBaseFilter *iface,
963                                               FILTER_INFO *pInfo)
964 {
965     HWCFilter *This = impl_from_IBaseFilter(iface);
966
967     if (pInfo == NULL) {
968         return E_POINTER;
969     }
970
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);
977     }
978     return S_OK;
979 }
980
981 static STDMETHODIMP HWCFilter_JoinFilterGraph(IBaseFilter *iface,
982                                               IFilterGraph *pGraph,
983                                               LPCWSTR pName)
984 {
985     HWCFilter *This = impl_from_IBaseFilter(iface);
986
987     This->m_pFilterGraph = pGraph;
988     return S_OK;
989 }
990
991 static STDMETHODIMP HWCFilter_QueryVendorInfo(IBaseFilter *iface,
992                                               LPWSTR *pVendorInfo)
993 {
994     return E_NOTIMPL;
995 }
996
997 static IBaseFilterVtbl HWCFilter_Vtbl = {
998     HWCFilter_QueryInterface,
999     HWCFilter_AddRef,
1000     HWCFilter_Release,
1001     HWCFilter_GetClassID,
1002     HWCFilter_Stop,
1003     HWCFilter_Pause,
1004     HWCFilter_Run,
1005     HWCFilter_GetState,
1006     HWCFilter_SetSyncSource,
1007     HWCFilter_GetSyncSource,
1008     HWCFilter_EnumPins,
1009     HWCFilter_FindPin,
1010     HWCFilter_QueryFilterInfo,
1011     HWCFilter_JoinFilterGraph,
1012     HWCFilter_QueryVendorInfo
1013 };
1014
1015 static STDMETHODIMP HWCFilter_Construct(IBaseFilter **ppv)
1016 {
1017     HWCFilter *This = (HWCFilter *)g_malloc0(sizeof(HWCFilter));
1018
1019     if (!This) {
1020         ERR("failed to HWCFilter_Construct, E_OUTOFMEMORY\n");
1021         return E_OUTOFMEMORY;
1022     }
1023
1024     This->IBaseFilter_iface.lpVtbl = &HWCFilter_Vtbl;
1025     This->m_pFilterGraph = NULL;
1026     This->m_state = State_Stopped;
1027     This->m_cRef = 1;
1028     HWCInPin_Construct(&This->IBaseFilter_iface, &This->m_pPin);
1029     *ppv = &This->IBaseFilter_iface;
1030
1031     return S_OK;
1032 }
1033
1034 /**********************************************************
1035  *
1036  * Virtual device implementations
1037  *
1038  **********************************************************/
1039
1040
1041 /*
1042  * Declaration global variables for Win32 COM Interfaces
1043  */
1044 IGraphBuilder *g_pGB ;
1045 ICaptureGraphBuilder2 *g_pCGB;
1046 IMediaControl *g_pMediaControl;
1047
1048 IPin *g_pOutputPin;
1049 IPin *g_pInputPin;
1050 IBaseFilter *g_pDstFilter;
1051 IBaseFilter *g_pSrcFilter;
1052
1053 IGrabCallback *g_pCallback;
1054
1055 /* V4L2 defines copy from videodev2.h */
1056 #define V4L2_CTRL_FLAG_SLIDER       0x0020
1057
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)
1064
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 */
1069
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;
1075
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 },
1080 };
1081
1082 typedef struct tagMaruCamConvertFrameInfo {
1083     uint32_t width;
1084     uint32_t height;
1085 } MaruCamConvertFrameInfo;
1086
1087 static MaruCamConvertFrameInfo supported_dst_frames[] = {
1088         { 640, 480 },
1089         { 352, 288 },
1090         { 320, 240 },
1091         { 176, 144 },
1092         { 160, 120 },
1093 };
1094
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
1099
1100 struct marucam_qctrl {
1101     uint32_t id;
1102     uint32_t hit;
1103     long min;
1104     long max;
1105     long step;
1106     long init_val;
1107 };
1108
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, },
1114 };
1115
1116 static MaruCamState *g_state;
1117
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;
1123
1124
1125 /*
1126  * Helper functions - converting image formats, converting values
1127  */
1128
1129 static uint32_t get_bytesperline(uint32_t pixfmt, uint32_t width)
1130 {
1131     uint32_t bytesperline;
1132
1133     switch (pixfmt) {
1134     case V4L2_PIX_FMT_YUV420:
1135     case V4L2_PIX_FMT_YVU420:
1136         bytesperline = (width * 12) >> 3;
1137         break;
1138     case V4L2_PIX_FMT_YUYV:
1139     default:
1140         bytesperline = width * 2;
1141         break;
1142     }
1143
1144     return bytesperline;
1145 }
1146
1147 static uint32_t get_sizeimage(uint32_t pixfmt, uint32_t width, uint32_t height)
1148 {
1149     return get_bytesperline(pixfmt, width) * height;
1150 }
1151
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);
1162
1163 static long value_convert_from_guest(long min, long max, long value)
1164 {
1165     double rate = 0.0;
1166     long dist = 0, ret = 0;
1167
1168     dist = max - min;
1169
1170     if (dist < MARUCAM_CTRL_VALUE_MAX) {
1171         rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
1172         ret = min + (int32_t)(value / rate);
1173     } else {
1174         rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
1175         ret = min + (int32_t)(rate * value);
1176     }
1177     return ret;
1178 }
1179
1180 static long value_convert_to_guest(long min, long max, long value)
1181 {
1182     double rate  = 0.0;
1183     long dist = 0, ret = 0;
1184
1185     dist = max - min;
1186
1187     if (dist < MARUCAM_CTRL_VALUE_MAX) {
1188         rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
1189         ret = (int32_t)((double)(value - min) * rate);
1190     } else {
1191         rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
1192         ret = (int32_t)((double)(value - min) / rate);
1193     }
1194
1195     return ret;
1196 }
1197
1198 /*
1199  * Callback function for grab frames
1200  */
1201 static STDMETHODIMP marucam_device_callbackfn(ULONG dwSize, BYTE *pBuffer)
1202 {
1203     void *tmp_buf;
1204     uint32_t width, height, fmt, imgsize;
1205
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);
1210
1211     if (imgsize > (uint32_t)dwSize) {
1212         ERR("Image size is mismatched\n");
1213         return E_FAIL;
1214     }
1215
1216     switch (g_dwSrcFmt) {
1217     case V4L2_PIX_FMT_YUYV:
1218         switch (fmt) {
1219         case V4L2_PIX_FMT_YUV420:
1220             yuyv_to_yuv420(pBuffer, grab_buf, width, height, 0);
1221             break;
1222         case V4L2_PIX_FMT_YVU420:
1223             yuyv_to_yuv420(pBuffer, grab_buf, width, height, 1);
1224             break;
1225         case V4L2_PIX_FMT_YUYV:
1226             memcpy(grab_buf, (void *)pBuffer, (size_t)dwSize);
1227             break;
1228         default:
1229             ERR("Invalid pixel format\n");
1230             return E_FAIL;
1231         }
1232         break;
1233     case V4L2_PIX_FMT_RGB24:
1234         switch (fmt) {
1235         case V4L2_PIX_FMT_YUV420:
1236             rgb24_to_yuv420(pBuffer, grab_buf, width, height, 0);
1237             break;
1238         case V4L2_PIX_FMT_YVU420:
1239             rgb24_to_yuv420(pBuffer, grab_buf, width, height, 1);
1240             break;
1241         case V4L2_PIX_FMT_YUYV:
1242             rgb24_to_yuyv(pBuffer, grab_buf, width, height);
1243             break;
1244         default:
1245             ERR("Invalid pixel format\n");
1246             return E_FAIL;
1247         }
1248         break;
1249     case V4L2_PIX_FMT_YUV420:
1250         switch (fmt) {
1251         case V4L2_PIX_FMT_YUV420:
1252             memcpy(grab_buf, (void *)pBuffer, (size_t)dwSize);
1253             break;
1254         case V4L2_PIX_FMT_YVU420:
1255             yuv420_to_yvu420(pBuffer, grab_buf, width, height);
1256             break;
1257         case V4L2_PIX_FMT_YUYV:
1258             yuv420_to_yuyv(pBuffer, grab_buf, width, height);
1259             break;
1260         default:
1261             ERR("Invalid pixel format\n");
1262             return E_FAIL;
1263         }
1264         break;
1265     default:
1266         ERR("Invalid pixel format\n");
1267         return E_FAIL;
1268     }
1269
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 */
1274             ++ready_count;
1275             TRACE("skip %d frame\n", ready_count);
1276             qemu_mutex_unlock(&g_state->thread_mutex);
1277             return S_OK;
1278         }
1279         if (g_state->req_frame == 0) {
1280             TRACE("there is no request\n");
1281             qemu_mutex_unlock(&g_state->thread_mutex);
1282             return S_OK;
1283         }
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);
1289     }
1290     qemu_mutex_unlock(&g_state->thread_mutex);
1291     return S_OK;
1292 }
1293
1294 /*
1295  * Internal functions for manipulate interfaces
1296  */
1297
1298 static STDMETHODIMP_(void) CloseInterfaces(void)
1299 {
1300     if (g_pMediaControl) {
1301         g_pMediaControl->lpVtbl->Stop(g_pMediaControl);
1302     }
1303
1304     if (g_pOutputPin) {
1305         g_pOutputPin->lpVtbl->Disconnect(g_pOutputPin);
1306     }
1307
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);
1316 }
1317
1318 static STDMETHODIMP_(void) DeleteMediaType(AM_MEDIA_TYPE *pmt)
1319 {
1320     if (pmt == NULL) {
1321         return;
1322     }
1323
1324     if (pmt->cbFormat != 0) {
1325         CoTaskMemFree((PVOID)pmt->pbFormat);
1326         pmt->cbFormat = 0;
1327         pmt->pbFormat = NULL;
1328     }
1329     if (pmt->pUnk != NULL) {
1330         pmt->pUnk->lpVtbl->Release(pmt->pUnk);
1331         pmt->pUnk = NULL;
1332     }
1333
1334     CoTaskMemFree((PVOID)pmt);
1335 }
1336
1337 static STDMETHODIMP GetPin(IBaseFilter *pFilter,
1338                            PIN_DIRECTION PinDir, IPin **ppPin)
1339 {
1340     HRESULT hr;
1341     IEnumPins *pEnum = NULL;
1342     IPin *pPin = NULL;
1343
1344     if (ppPin == NULL) {
1345         return E_POINTER;
1346     }
1347
1348     hr = pFilter->lpVtbl->EnumPins(pFilter, &pEnum);
1349     if (FAILED(hr)) {
1350         return hr;
1351     }
1352
1353     while (pEnum->lpVtbl->Next(pEnum, 1, &pPin, 0) == S_OK) {
1354         PIN_DIRECTION PinDirThis;
1355         hr = pPin->lpVtbl->QueryDirection(pPin, &PinDirThis);
1356         if (FAILED(hr)) {
1357             SAFE_RELEASE(pPin);
1358             SAFE_RELEASE(pEnum);
1359             return hr;
1360         }
1361         if (PinDir == PinDirThis) {
1362             *ppPin = pPin;
1363             SAFE_RELEASE(pEnum);
1364             return S_OK;
1365         }
1366         SAFE_RELEASE(pPin);
1367     }
1368
1369     SAFE_RELEASE(pEnum);
1370     return S_FALSE;
1371 }
1372
1373 static STDMETHODIMP GraphBuilder_Init(void)
1374 {
1375     HRESULT hr;
1376
1377     hr = CoCreateInstance(&CLSID_FilterGraph, NULL, CLSCTX_INPROC,
1378                           &IID_IGraphBuilder, (void **)&g_pGB);
1379     if (FAILED(hr)) {
1380         ERR("Failed to create instance of GraphBuilder, 0x%x\n", hr);
1381         return hr;
1382     }
1383
1384     hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL, CLSCTX_INPROC,
1385                           &IID_ICaptureGraphBuilder2, (void **)&g_pCGB);
1386     if (FAILED(hr)) {
1387         ERR("Failed to create instance of CaptureGraphBuilder2, 0x%x\n", hr);
1388         return hr;
1389     }
1390
1391     hr = g_pCGB->lpVtbl->SetFiltergraph(g_pCGB, g_pGB);
1392     if (FAILED(hr)) {
1393         ERR("Failed to SetFiltergraph, 0x%x\n", hr);
1394         return hr;
1395     }
1396
1397     hr = g_pGB->lpVtbl->QueryInterface(g_pGB, &IID_IMediaControl,
1398                                        (void **)&g_pMediaControl);
1399     if (FAILED(hr)) {
1400         ERR("Failed to QueryInterface for IMediaControl, 0x%x\n", hr);
1401         return hr;
1402     }
1403
1404     hr = HWCGrabCallback_Construct(&g_pCallback);
1405     if (g_pCallback == NULL) {
1406         hr = E_OUTOFMEMORY;
1407     }
1408
1409     hr = ((HWCGrabCallback *)g_pCallback)->SetCallback(g_pCallback,
1410                             (CallbackFn)marucam_device_callbackfn);
1411
1412     return hr;
1413 }
1414
1415 static STDMETHODIMP BindSourceFilter(void)
1416 {
1417     HRESULT hr;
1418     ICreateDevEnum *pCreateDevEnum = NULL;
1419     IEnumMoniker *pEnumMK = NULL;
1420     IMoniker *pMoniKer;
1421
1422     hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC,
1423                           &IID_ICreateDevEnum,
1424                           (void **)&pCreateDevEnum);
1425     if (FAILED(hr)) {
1426         ERR("Failed to create instance of CreateDevEnum, 0x%x\n", hr);
1427         return hr;
1428     }
1429
1430     hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum,
1431                                       &CLSID_VideoInputDeviceCategory,
1432                                       &pEnumMK, 0);
1433     if (FAILED(hr)) {
1434         ERR("Failed to get VideoInputDeviceCategory, 0x%x\n", hr);
1435         SAFE_RELEASE(pCreateDevEnum);
1436         return hr;
1437     }
1438
1439     if (!pEnumMK) {
1440         ERR("ClassEnumerator moniker is NULL\n");
1441         SAFE_RELEASE(pCreateDevEnum);
1442         return E_FAIL;
1443     }
1444     pEnumMK->lpVtbl->Reset(pEnumMK);
1445
1446     hr = pEnumMK->lpVtbl->Next(pEnumMK, 1, &pMoniKer, NULL);
1447     if (hr == S_FALSE) {
1448         hr = E_FAIL;
1449     }
1450     if (SUCCEEDED(hr)) {
1451         IPropertyBag *pBag = NULL;
1452         hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0,
1453                                              &IID_IPropertyBag,
1454                                              (void **)&pBag);
1455         if (SUCCEEDED(hr)) {
1456             VARIANT var;
1457             var.vt = VT_BSTR;
1458             hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);
1459             if (hr == NOERROR) {
1460                 hr = pMoniKer->lpVtbl->BindToObject(pMoniKer, NULL, NULL,
1461                                                     &IID_IBaseFilter,
1462                                                     (void **)&g_pSrcFilter);
1463                 if (FAILED(hr)) {
1464                     ERR("Counldn't bind moniker to filter object!!\n");
1465                 } else {
1466                     g_pSrcFilter->lpVtbl->AddRef(g_pSrcFilter);
1467                 }
1468                 SysFreeString(var.bstrVal);
1469             }
1470             SAFE_RELEASE(pBag);
1471         }
1472         SAFE_RELEASE(pMoniKer);
1473     }
1474
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);
1480         }
1481     }
1482     SAFE_RELEASE(pEnumMK);
1483     SAFE_RELEASE(pCreateDevEnum);
1484
1485     return hr;
1486 }
1487
1488 static STDMETHODIMP BindTargetFilter(void)
1489 {
1490     HRESULT hr;
1491     hr = HWCFilter_Construct(&g_pDstFilter);
1492
1493     if (SUCCEEDED(hr) && g_pDstFilter) {
1494         hr = g_pGB->lpVtbl->AddFilter(g_pGB, g_pDstFilter, L"HWCFilter");
1495         if (FAILED(hr)) {
1496             ERR("Counldn't add HWCFilterr to our graph!\n");
1497             SAFE_RELEASE(g_pDstFilter);
1498         }
1499     }
1500     return hr;
1501 }
1502
1503 static STDMETHODIMP ConnectFilters(void)
1504 {
1505     HRESULT hr;
1506
1507     hr = GetPin(g_pSrcFilter, PINDIR_OUTPUT , &g_pOutputPin);
1508     if (FAILED(hr)) {
1509         ERR("Failed to get output pin. 0x%x\n", hr);
1510         return hr;
1511     }
1512
1513     hr = GetPin(g_pDstFilter, PINDIR_INPUT , &g_pInputPin);
1514     if (FAILED(hr)) {
1515         ERR("Failed to get input pin. 0x%x\n", hr);
1516         return hr;
1517     }
1518
1519     hr = g_pGB->lpVtbl->Connect(g_pGB, g_pOutputPin, g_pInputPin);
1520     if (FAILED(hr)) {
1521         ERR("Failed to connect pins. 0x%x\n", hr);
1522     }
1523     return hr;
1524 }
1525
1526 static STDMETHODIMP DisconnectPins(void)
1527 {
1528     HRESULT hr;
1529
1530     hr = g_pGB->lpVtbl->Disconnect(g_pGB, g_pOutputPin);
1531     if (FAILED(hr)) {
1532         ERR("Failed to disconnect output pin. 0x%x\n", hr);
1533         return hr;
1534     }
1535
1536     hr = g_pGB->lpVtbl->Disconnect(g_pGB, g_pInputPin);
1537     if (FAILED(hr)) {
1538         ERR("Failed to disconnect input pin. 0x%x\n", hr);
1539     }
1540
1541     return hr;
1542 }
1543
1544 static STDMETHODIMP RemoveFilters(void)
1545 {
1546     HRESULT hr;
1547
1548     hr = g_pGB->lpVtbl->RemoveFilter(g_pGB, g_pSrcFilter);
1549     if (FAILED(hr)) {
1550         ERR("Failed to remove source filer. 0x%x\n", hr);
1551         return hr;
1552     }
1553
1554     hr = g_pGB->lpVtbl->RemoveFilter(g_pGB, g_pDstFilter);
1555     if (FAILED(hr)) {
1556         ERR("Failed to remove destination filer. 0x%x\n", hr);
1557     }
1558
1559     return hr;
1560 }
1561
1562 /* default fps is 15 */
1563 #define MARUCAM_DEFAULT_FRAMEINTERVAL    666666
1564
1565 static STDMETHODIMP SetFormat(uint32_t dwWidth, uint32_t dwHeight,
1566                               uint32_t dwDstFmt, uint32_t *dwSrcFmt)
1567 {
1568     HRESULT hr;
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');
1573
1574     if (dwSrcFmt == NULL) {
1575         ERR("invalid the source format pointer\n");
1576         return E_FAIL;
1577     }
1578
1579     hr = g_pCGB->lpVtbl->FindInterface(g_pCGB, &PIN_CATEGORY_CAPTURE, 0,
1580                                        g_pSrcFilter, &IID_IAMStreamConfig,
1581                                        (void **)&pSConfig);
1582     if (FAILED(hr)) {
1583         ERR("failed to FindInterface method\n");
1584         return hr;
1585     }
1586
1587     hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);
1588     if (FAILED(hr)) {
1589         ERR("failed to GetNumberOfCapabilities method\n");
1590         SAFE_RELEASE(pSConfig);
1591         return hr;
1592     }
1593
1594     if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
1595         int iFormat = 0;
1596         for (iFormat = 0; iFormat < iCount; iFormat++) {
1597             VIDEO_STREAM_CONFIG_CAPS scc;
1598             AM_MEDIA_TYPE *pmtConfig;
1599
1600             hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat,
1601                                                  &pmtConfig, (BYTE *)&scc);
1602             if (hr == S_OK) {
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);
1617                             continue;
1618                         }
1619                         /* use minimum FPS(maximum frameinterval)
1620                            with non-VT system  */
1621 #ifdef CONFIG_HAX
1622                         if (!hax_enabled()) {
1623                             pvi->AvgTimePerFrame =
1624                                     (REFERENCE_TIME)scc.MaxFrameInterval;
1625                         } else {
1626                             pvi->AvgTimePerFrame =
1627                                 (REFERENCE_TIME)MARUCAM_DEFAULT_FRAMEINTERVAL;
1628                         }
1629 #else
1630                         pvi->AvgTimePerFrame =
1631                                 (REFERENCE_TIME)scc.MaxFrameInterval;
1632 #endif
1633                         hr = pSConfig->lpVtbl->SetFormat(pSConfig, pmtConfig);
1634                         DeleteMediaType(pmtConfig);
1635                         break;
1636                     }
1637                 }
1638                 DeleteMediaType(pmtConfig);
1639             }
1640         }
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",
1645                 dwWidth, dwHeight);
1646             hr = E_FAIL;
1647         }
1648     }
1649     SAFE_RELEASE(pSConfig);
1650     return hr;
1651 }
1652
1653 static STDMETHODIMP QueryVideoProcAmp(long nProperty, long *pMin, long *pMax,
1654                                       long *pStep, long *pDefault)
1655 {
1656     HRESULT hr;
1657     long Flags;
1658     IAMVideoProcAmp *pProcAmp = NULL;
1659
1660     hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
1661                                               &IID_IAMVideoProcAmp,
1662                                               (void **)&pProcAmp);
1663     if (FAILED(hr)) {
1664         return hr;
1665     }
1666
1667     hr = pProcAmp->lpVtbl->GetRange(pProcAmp, nProperty, pMin, pMax,
1668                                     pStep, pDefault, &Flags);
1669
1670     SAFE_RELEASE(pProcAmp);
1671     return hr;
1672 }
1673
1674 static STDMETHODIMP GetVideoProcAmp(long nProperty, long *pValue)
1675 {
1676     HRESULT hr;
1677     long Flags;
1678     IAMVideoProcAmp *pProcAmp = NULL;
1679
1680     hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
1681                                               &IID_IAMVideoProcAmp,
1682                                               (void **)&pProcAmp);
1683     if (FAILED(hr)) {
1684         return hr;
1685     }
1686
1687     hr = pProcAmp->lpVtbl->Get(pProcAmp, nProperty, pValue, &Flags);
1688     if (FAILED(hr)) {
1689         ERR("Failed to get property for video\n");
1690     }
1691
1692     SAFE_RELEASE(pProcAmp);
1693     return hr;
1694 }
1695
1696 static STDMETHODIMP SetVideoProcAmp(long nProperty, long value)
1697 {
1698     HRESULT hr;
1699
1700     IAMVideoProcAmp *pProcAmp = NULL;
1701     hr = g_pSrcFilter->lpVtbl->QueryInterface(g_pSrcFilter,
1702                                               &IID_IAMVideoProcAmp,
1703                                               (void **)&pProcAmp);
1704     if (FAILED(hr)) {
1705         return hr;
1706     }
1707
1708     hr = pProcAmp->lpVtbl->Set(pProcAmp, nProperty, value,
1709                                VideoProcAmp_Flags_Manual);
1710     if (FAILED(hr)) {
1711         ERR("Failed to set property for video\n");
1712     }
1713     SAFE_RELEASE(pProcAmp);
1714     return hr;
1715 }
1716
1717 static char *__wchar_to_char(const WCHAR *pwstr)
1718 {
1719     char *pstr = NULL;
1720     int len = 0;
1721
1722     len = wcslen(pwstr) + 1;
1723     pstr = (char *)g_malloc0(sizeof(char) * len);
1724     wcstombs(pstr, pwstr, len + 1);
1725
1726     return pstr;
1727 }
1728
1729 int marucam_device_check(int log_flag)
1730 {
1731     struct timeval t1, t2;
1732     int ret = 0;
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;
1743
1744     gettimeofday(&t1, NULL);
1745     hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
1746     if (FAILED(hr)) {
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);
1751         return ret;
1752     }
1753
1754     hr = CoCreateInstance(&CLSID_FilterGraph, NULL,
1755                           CLSCTX_INPROC,
1756                           &IID_IGraphBuilder,
1757                           (void **)&pGB);
1758     if (FAILED(hr)) {
1759         fprintf(stdout, "[Webcam] Failed to create GraphBuilder, 0x%x\n", hr);
1760         CoUninitialize();
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);
1764         return ret;
1765     }
1766
1767     hr = CoCreateInstance(&CLSID_CaptureGraphBuilder2, NULL,
1768                           CLSCTX_INPROC,
1769                           &IID_ICaptureGraphBuilder2,
1770                           (void **)&pCGB);
1771     if (FAILED(hr)) {
1772         fprintf(stdout,
1773         "[Webcam] Failed to create CaptureGraphBuilder2, 0x%x\n", hr);
1774         SAFE_RELEASE(pGB);
1775         CoUninitialize();
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);
1779         return ret;
1780     }
1781
1782     hr = pCGB->lpVtbl->SetFiltergraph(pCGB, pGB);
1783     if (FAILED(hr)) {
1784         fprintf(stdout, "[Webcam] Failed to SetFiltergraph, 0x%x\n", hr);
1785         SAFE_RELEASE(pCGB);
1786         SAFE_RELEASE(pGB);
1787         CoUninitialize();
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);
1791         return ret;
1792     }
1793
1794     hr = CoCreateInstance(&CLSID_SystemDeviceEnum, NULL,
1795                           CLSCTX_INPROC,
1796                           &IID_ICreateDevEnum,
1797                           (void **)&pCreateDevEnum);
1798     if (FAILED(hr)) {
1799         fprintf(stdout,
1800             "[Webcam] failed to create instance of CLSID_SystemDeviceEnum\n");
1801         SAFE_RELEASE(pCGB);
1802         SAFE_RELEASE(pGB);
1803         CoUninitialize();
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);
1807         return ret;
1808     }
1809
1810     hr = pCreateDevEnum->lpVtbl->CreateClassEnumerator(pCreateDevEnum,
1811                                   &CLSID_VideoInputDeviceCategory, &pEnumMK, 0);
1812     if (FAILED(hr)) {
1813         fprintf(stdout, "[Webcam] failed to create class enumerator\n");
1814         SAFE_RELEASE(pCreateDevEnum);
1815         SAFE_RELEASE(pCGB);
1816         SAFE_RELEASE(pGB);
1817         CoUninitialize();
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);
1821         return ret;
1822     }
1823
1824     if (!pEnumMK) {
1825         fprintf(stdout, "[Webcam] class enumerator is NULL!!\n");
1826         SAFE_RELEASE(pCreateDevEnum);
1827         SAFE_RELEASE(pCGB);
1828         SAFE_RELEASE(pGB);
1829         CoUninitialize();
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);
1833         return ret;
1834     }
1835     pEnumMK->lpVtbl->Reset(pEnumMK);
1836
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);
1842         SAFE_RELEASE(pCGB);
1843         SAFE_RELEASE(pGB);
1844         CoUninitialize();
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);
1848         return ret;
1849     }
1850
1851     IPropertyBag *pBag = NULL;
1852     hr = pMoniKer->lpVtbl->BindToStorage(pMoniKer, 0, 0,
1853                                          &IID_IPropertyBag,
1854                                          (void **)&pBag);
1855     if (FAILED(hr)) {
1856         fprintf(stdout, "[Webcam] failed to bind to storage.\n");
1857         SAFE_RELEASE(pEnumMK);
1858         SAFE_RELEASE(pCreateDevEnum);
1859         SAFE_RELEASE(pCGB);
1860         SAFE_RELEASE(pGB);
1861         CoUninitialize();
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);
1865         return ret;
1866     } else {
1867         VARIANT var;
1868         var.vt = VT_BSTR;
1869         hr = pBag->lpVtbl->Read(pBag, L"FriendlyName", &var, NULL);
1870         if (hr == S_OK) {
1871             ret = 1;
1872             if (!log_flag) {
1873                 SysFreeString(var.bstrVal);
1874                 SAFE_RELEASE(pBag);
1875                 SAFE_RELEASE(pMoniKer);
1876                 SAFE_RELEASE(pEnumMK);
1877                 SAFE_RELEASE(pCreateDevEnum);
1878                 SAFE_RELEASE(pCGB);
1879                 SAFE_RELEASE(pGB);
1880                 CoUninitialize();
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);
1884                 return ret;
1885             }
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,
1890                                                 &IID_IBaseFilter,
1891                                                 (void **)&pSrcFilter);
1892             if (FAILED(hr)) {
1893                 fprintf(stdout,
1894                    "[Webcam] Counldn't bind moniker to filter object!!\n");
1895                 SysFreeString(var.bstrVal);
1896                 SAFE_RELEASE(pBag);
1897                 SAFE_RELEASE(pMoniKer);
1898                 SAFE_RELEASE(pEnumMK);
1899                 SAFE_RELEASE(pCreateDevEnum);
1900                 SAFE_RELEASE(pCGB);
1901                 SAFE_RELEASE(pGB);
1902                 CoUninitialize();
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);
1906                 return ret;
1907             } else {
1908                 pSrcFilter->lpVtbl->AddRef(pSrcFilter);
1909             }
1910             SysFreeString(var.bstrVal);
1911         }
1912         SAFE_RELEASE(pBag);
1913     }
1914     SAFE_RELEASE(pMoniKer);
1915
1916     hr = pGB->lpVtbl->AddFilter(pGB, pSrcFilter, L"Video Capture");
1917     if (hr != S_OK && hr != S_FALSE) {
1918         fprintf(stdout,
1919                 "[Webcam] Counldn't add Video Capture filter to our graph!\n");
1920         SAFE_RELEASE(pSrcFilter);
1921         SAFE_RELEASE(pEnumMK);
1922         SAFE_RELEASE(pCreateDevEnum);
1923         SAFE_RELEASE(pCGB);
1924         SAFE_RELEASE(pGB);
1925         CoUninitialize();
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);
1929         return ret;
1930     }
1931
1932     hr = pCGB->lpVtbl->FindInterface(pCGB, &PIN_CATEGORY_CAPTURE, 0,
1933                                        pSrcFilter, &IID_IAMStreamConfig,
1934                                        (void **)&pSConfig);
1935     if (FAILED(hr)) {
1936         fprintf(stdout, "[Webcam] failed to FindInterface method\n");
1937         SAFE_RELEASE(pSrcFilter);
1938         SAFE_RELEASE(pEnumMK);
1939         SAFE_RELEASE(pCreateDevEnum);
1940         SAFE_RELEASE(pCGB);
1941         SAFE_RELEASE(pGB);
1942         CoUninitialize();
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);
1946         return ret;
1947     }
1948
1949     hr = pSConfig->lpVtbl->GetNumberOfCapabilities(pSConfig, &iCount, &iSize);
1950     if (FAILED(hr)) {
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);
1956         SAFE_RELEASE(pCGB);
1957         SAFE_RELEASE(pGB);
1958         CoUninitialize();
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);
1962         return ret;
1963     }
1964
1965     if (iSize == sizeof(VIDEO_STREAM_CONFIG_CAPS)) {
1966         int iFormat = 0;
1967         for (iFormat = 0; iFormat < iCount; iFormat++) {
1968             VIDEO_STREAM_CONFIG_CAPS scc;
1969             AM_MEDIA_TYPE *pmtConfig;
1970
1971             hr = pSConfig->lpVtbl->GetStreamCaps(pSConfig, iFormat, &pmtConfig,
1972                                                  (BYTE *)&scc);
1973             if (hr == S_OK) {
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);
1982                     } else {
1983                         fprintf(stdout,
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);
1991                     }
1992                 }
1993                 DeleteMediaType(pmtConfig);
1994             }
1995         }
1996     }
1997
1998     hr = pGB->lpVtbl->RemoveFilter(pGB, pSrcFilter);
1999     if (FAILED(hr)) {
2000         fprintf(stdout, "[Webcam] Failed to remove source filer. 0x%x\n", hr);
2001     }
2002
2003     SAFE_RELEASE(pSConfig);
2004     SAFE_RELEASE(pSrcFilter);
2005     SAFE_RELEASE(pCGB);
2006     SAFE_RELEASE(pGB);
2007     SAFE_RELEASE(pEnumMK);
2008     SAFE_RELEASE(pCreateDevEnum);
2009     CoUninitialize();
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);
2013
2014     return ret;
2015 }
2016
2017 /* MARUCAM_CMD_INIT */
2018 void marucam_device_init(MaruCamState *state)
2019 {
2020     g_state = state;
2021 }
2022
2023 void marucam_device_exit(MaruCamState *state)
2024 {
2025 }
2026
2027 /* MARUCAM_CMD_OPEN */
2028 void marucam_device_open(MaruCamState *state)
2029 {
2030     HRESULT hr;
2031     uint32_t dwHeight, dwWidth, dwDstFmt;
2032     MaruCamParam *param = state->param;
2033     param->top = 0;
2034
2035     hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
2036     if (FAILED(hr)) {
2037         ERR("CoInitailizeEx\n");
2038         ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
2039         param->errCode = EINVAL;
2040         return;
2041     }
2042
2043     hr = GraphBuilder_Init();
2044     if (FAILED(hr)) {
2045         ERR("GraphBuilder_Init\n");
2046         DisconnectPins();
2047         RemoveFilters();
2048         CloseInterfaces();
2049         CoUninitialize();
2050         param->errCode = EINVAL;
2051         ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
2052         return;
2053     }
2054
2055     hr = BindSourceFilter();
2056     if (FAILED(hr)) {
2057         ERR("BindSourceFilter\n");
2058         DisconnectPins();
2059         RemoveFilters();
2060         CloseInterfaces();
2061         CoUninitialize();
2062         param->errCode = EINVAL;
2063         ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
2064         return;
2065     }
2066
2067     hr = BindTargetFilter();
2068     if (FAILED(hr)) {
2069         ERR("BindTargetFilter\n");
2070         DisconnectPins();
2071         RemoveFilters();
2072         CloseInterfaces();
2073         CoUninitialize();
2074         param->errCode = EINVAL;
2075         ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
2076         return;
2077     }
2078
2079     hr = ConnectFilters();
2080     if (FAILED(hr)) {
2081         ERR("ConnectFilters\n");
2082         DisconnectPins();
2083         RemoveFilters();
2084         CloseInterfaces();
2085         CoUninitialize();
2086         param->errCode = EINVAL;
2087         ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
2088         return;
2089     }
2090
2091     cur_frame_idx = 0;
2092     cur_fmt_idx = 0;
2093
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);
2098     if (hr != S_OK) {
2099         ERR("failed to Set default values\n");
2100         DisconnectPins();
2101         RemoveFilters();
2102         CloseInterfaces();
2103         CoUninitialize();
2104         param->errCode = EINVAL;
2105         ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
2106         return;
2107     }
2108
2109     INFO("Opened\n");
2110     return;
2111 }
2112
2113 /* MARUCAM_CMD_CLOSE */
2114 void marucam_device_close(MaruCamState *state)
2115 {
2116     MaruCamParam *param = state->param;
2117     param->top = 0;
2118
2119     DisconnectPins();
2120     RemoveFilters();
2121     CloseInterfaces();
2122     CoUninitialize();
2123     INFO("Closed\n");
2124 }
2125
2126 /* MARUCAM_CMD_START_PREVIEW */
2127 void marucam_device_start_preview(MaruCamState *state)
2128 {
2129     HRESULT hr;
2130     uint32_t pixfmt, width, height;
2131     MaruCamParam *param = state->param;
2132     param->top = 0;
2133
2134     ready_count = 0;
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);
2139
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");
2145
2146     assert(g_pCallback != NULL);
2147     hr = ((HWCInPin *)g_pInputPin)->SetGrabCallbackIF(g_pInputPin,
2148                                                        g_pCallback);
2149     if (FAILED(hr)) {
2150         ERR("Failed to set IGrabCallback interface.\n");
2151         param->errCode = EINVAL;
2152         return;
2153     }
2154
2155     if (grab_buf) {
2156         g_free(grab_buf);
2157         grab_buf = NULL;
2158     }
2159     grab_buf = (void *)g_malloc0(state->buf_size);
2160     if (grab_buf == NULL) {
2161         param->errCode = ENOMEM;
2162         return;
2163     }
2164
2165     hr = g_pMediaControl->lpVtbl->Run(g_pMediaControl);
2166     if (FAILED(hr)) {
2167         ERR("Failed to run media control. hr=0x%x\n", hr);
2168         param->errCode = EINVAL;
2169         return;
2170     }
2171
2172     qemu_mutex_lock(&state->thread_mutex);
2173     state->streamon = 1;
2174     qemu_mutex_unlock(&state->thread_mutex);
2175
2176     INFO("Streaming on ......\n");
2177 }
2178
2179 /* MARUCAM_CMD_STOP_PREVIEW */
2180 void marucam_device_stop_preview(MaruCamState *state)
2181 {
2182     HRESULT hr;
2183     MaruCamParam *param = state->param;
2184     param->top = 0;
2185
2186     INFO("...... Streaming off\n");
2187     qemu_mutex_lock(&state->thread_mutex);
2188     state->streamon = 0;
2189     qemu_mutex_unlock(&state->thread_mutex);
2190
2191     hr = ((HWCInPin *)g_pInputPin)->SetGrabCallbackIF(g_pInputPin, NULL);
2192     if (FAILED(hr)) {
2193         ERR("Failed to set IGrabCallback interface.\n");
2194         param->errCode = EINVAL;
2195         return;
2196     }
2197
2198     hr = g_pMediaControl->lpVtbl->Stop(g_pMediaControl);
2199     if (FAILED(hr)) {
2200         ERR("Failed to stop media control.\n");
2201         param->errCode = EINVAL;
2202         return;
2203     }
2204
2205     if (grab_buf) {
2206         g_free(grab_buf);
2207         grab_buf = NULL;
2208     }
2209     state->buf_size = 0;
2210
2211     INFO("Stopping preview\n");
2212 }
2213
2214 /* MARUCAM_CMD_S_PARAM */
2215 void marucam_device_s_param(MaruCamState *state)
2216 {
2217     MaruCamParam *param = state->param;
2218
2219     /* We use default FPS of the webcam */
2220     param->top = 0;
2221 }
2222
2223 /* MARUCAM_CMD_G_PARAM */
2224 void marucam_device_g_param(MaruCamState *state)
2225 {
2226     MaruCamParam *param = state->param;
2227
2228     /* We use default FPS of the webcam
2229      * return a fixed value on guest ini file (1/30).
2230      */
2231     param->top = 0;
2232     param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */
2233     param->stack[1] = 1; /* numerator */
2234     param->stack[2] = 30; /* denominator */
2235 }
2236
2237 /* MARUCAM_CMD_S_FMT */
2238 void marucam_device_s_fmt(MaruCamState *state)
2239 {
2240     uint32_t width, height, pixfmt, pidx, fidx;
2241     MaruCamParam *param = state->param;
2242
2243     param->top = 0;
2244     width = param->stack[0];
2245     height = param->stack[1];
2246     pixfmt = param->stack[2];
2247
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)) {
2251             break;
2252         }
2253     }
2254     if (fidx == ARRAY_SIZE(supported_dst_frames)) {
2255         param->errCode = EINVAL;
2256         return;
2257     }
2258     for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) {
2259         if (supported_dst_pixfmts[pidx].fmt == pixfmt) {
2260             break;
2261         }
2262     }
2263     if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {
2264         param->errCode = EINVAL;
2265         return;
2266     }
2267
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);
2271         if (FAILED(hr)) {
2272             param->errCode = EINVAL;
2273             return;
2274         }
2275     }
2276
2277     cur_frame_idx = fidx;
2278     cur_fmt_idx = pidx;
2279
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;
2283
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;
2292
2293     TRACE("Set format...\n");
2294 }
2295
2296 /* MARUCAM_CMD_G_FMT */
2297 void marucam_device_g_fmt(MaruCamState *state)
2298 {
2299     uint32_t width, height, pixfmt;
2300     MaruCamParam *param = state->param;
2301
2302     param->top = 0;
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;
2306
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;
2315
2316     TRACE("Get format...\n");
2317 }
2318
2319 void marucam_device_try_fmt(MaruCamState *state)
2320 {
2321     uint32_t width, height, pixfmt, i;
2322     MaruCamParam *param = state->param;
2323
2324     param->top = 0;
2325     width = param->stack[0];
2326     height = param->stack[1];
2327     pixfmt = param->stack[2];
2328
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)) {
2332             break;
2333         }
2334     }
2335     if (i == ARRAY_SIZE(supported_dst_frames)) {
2336         param->errCode = EINVAL;
2337         return;
2338     }
2339     for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
2340         if (supported_dst_pixfmts[i].fmt == pixfmt) {
2341             break;
2342         }
2343     }
2344     if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
2345         param->errCode = EINVAL;
2346         return;
2347     }
2348
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;
2357 }
2358
2359 void marucam_device_enum_fmt(MaruCamState *state)
2360 {
2361     uint32_t index;
2362     MaruCamParam *param = state->param;
2363
2364     param->top = 0;
2365     index = param->stack[0];
2366
2367     if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
2368         param->errCode = EINVAL;
2369         return;
2370     }
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(&param->stack[3], "YUYV", 32);
2377         break;
2378     case V4L2_PIX_FMT_YUV420:
2379         memcpy(&param->stack[3], "YU12", 32);
2380         break;
2381     case V4L2_PIX_FMT_YVU420:
2382         memcpy(&param->stack[3], "YV12", 32);
2383         break;
2384     default:
2385         ERR("Invalid pixel format\n");
2386         param->errCode = EINVAL;
2387         break;
2388     }
2389 }
2390
2391 void marucam_device_qctrl(MaruCamState *state)
2392 {
2393     HRESULT hr;
2394     uint32_t id, i;
2395     long property, min, max, step, def_val, set_val;
2396     char name[32] = {0,};
2397     MaruCamParam *param = state->param;
2398
2399     param->top = 0;
2400     id = param->stack[0];
2401
2402     switch (id) {
2403     case V4L2_CID_BRIGHTNESS:
2404         TRACE("V4L2_CID_BRIGHTNESS\n");
2405         property = VideoProcAmp_Brightness;
2406         memcpy((void *)name, (void *)"brightness", 32);
2407         i = 0;
2408         break;
2409     case V4L2_CID_CONTRAST:
2410         TRACE("V4L2_CID_CONTRAST\n");
2411         property = VideoProcAmp_Contrast;
2412         memcpy((void *)name, (void *)"contrast", 32);
2413         i = 1;
2414         break;
2415     case V4L2_CID_SATURATION:
2416         TRACE("V4L2_CID_SATURATION\n");
2417         property = VideoProcAmp_Saturation;
2418         memcpy((void *)name, (void *)"saturation", 32);
2419         i = 2;
2420         break;
2421     case V4L2_CID_SHARPNESS:
2422         TRACE("V4L2_CID_SHARPNESS\n");
2423         property = VideoProcAmp_Sharpness;
2424         memcpy((void *)name, (void *)"sharpness", 32);
2425         i = 3;
2426         break;
2427     default:
2428         ERR("Invalid control ID\n");
2429         param->errCode = EINVAL;
2430         return;
2431     }
2432     hr = QueryVideoProcAmp(property, &min, &max, &step, &def_val);
2433     if (FAILED(hr)) {
2434         param->errCode = EINVAL;
2435         ERR("failed to query video controls [HRESULT : 0x%x]\n", hr);
2436         return;
2437     } else {
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;
2443
2444         if ((qctrl_tbl[i].min + qctrl_tbl[i].max) == 0) {
2445             set_val = 0;
2446         } else {
2447             set_val = (qctrl_tbl[i].min + qctrl_tbl[i].max) / 2;
2448         }
2449         hr = SetVideoProcAmp(property, set_val);
2450         if (FAILED(hr)) {
2451             param->errCode = EINVAL;
2452             ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
2453             return;
2454         }
2455     }
2456
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(&param->stack[6], (void *)name, sizeof(name)/sizeof(name[0]));
2465 }
2466
2467 void marucam_device_s_ctrl(MaruCamState *state)
2468 {
2469     HRESULT hr;
2470     uint32_t i;
2471     long property, set_val;
2472     MaruCamParam *param = state->param;
2473
2474     param->top = 0;
2475
2476     switch (param->stack[0]) {
2477     case V4L2_CID_BRIGHTNESS:
2478         i = 0;
2479         property = VideoProcAmp_Brightness;
2480         break;
2481     case V4L2_CID_CONTRAST:
2482         i = 1;
2483         property = VideoProcAmp_Contrast;
2484         break;
2485     case V4L2_CID_SATURATION:
2486         i = 2;
2487         property = VideoProcAmp_Saturation;
2488         break;
2489     case V4L2_CID_SHARPNESS:
2490         i = 3;
2491         property = VideoProcAmp_Sharpness;
2492         break;
2493     default:
2494         param->errCode = EINVAL;
2495         return;
2496     }
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);
2500     if (FAILED(hr)) {
2501         param->errCode = EINVAL;
2502         ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
2503         return;
2504     }
2505 }
2506
2507 void marucam_device_g_ctrl(MaruCamState *state)
2508 {
2509     HRESULT hr;
2510     uint32_t i;
2511     long property, get_val;
2512     MaruCamParam *param = state->param;
2513
2514     param->top = 0;
2515     switch (param->stack[0]) {
2516     case V4L2_CID_BRIGHTNESS:
2517         i = 0;
2518         property = VideoProcAmp_Brightness;
2519         break;
2520     case V4L2_CID_CONTRAST:
2521         i = 1;
2522         property = VideoProcAmp_Contrast;
2523         break;
2524     case V4L2_CID_SATURATION:
2525         i = 2;
2526         property = VideoProcAmp_Saturation;
2527         break;
2528     case V4L2_CID_SHARPNESS:
2529         i = 3;
2530         property = VideoProcAmp_Sharpness;
2531         break;
2532     default:
2533         param->errCode = EINVAL;
2534         return;
2535     }
2536
2537     hr = GetVideoProcAmp(property, &get_val);
2538     if (FAILED(hr)) {
2539         param->errCode = EINVAL;
2540         ERR("failed to get video control value!!!, [HRESULT : 0x%x]\n", hr);
2541         return;
2542     }
2543     param->stack[0] = (uint32_t)value_convert_to_guest(qctrl_tbl[i].min,
2544                 qctrl_tbl[i].max, get_val);
2545 }
2546
2547 void marucam_device_enum_fsizes(MaruCamState *state)
2548 {
2549     uint32_t index, pixfmt, i;
2550     MaruCamParam *param = state->param;
2551
2552     param->top = 0;
2553     index = param->stack[0];
2554     pixfmt = param->stack[1];
2555
2556     if (index >= ARRAY_SIZE(supported_dst_frames)) {
2557         param->errCode = EINVAL;
2558         return;
2559     }
2560     for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
2561         if (supported_dst_pixfmts[i].fmt == pixfmt) {
2562             break;
2563         }
2564     }
2565
2566     if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
2567         param->errCode = EINVAL;
2568         return;
2569     }
2570
2571     param->stack[0] = supported_dst_frames[index].width;
2572     param->stack[1] = supported_dst_frames[index].height;
2573 }
2574
2575 void marucam_device_enum_fintv(MaruCamState *state)
2576 {
2577     MaruCamParam *param = state->param;
2578
2579     param->top = 0;
2580
2581     /* switch by index(param->stack[0]) */
2582     switch (param->stack[0]) {
2583     case 0:
2584         param->stack[1] = 30; /* denominator */
2585         break;
2586     default:
2587         param->errCode = EINVAL;
2588         return;
2589     }
2590     param->stack[0] = 1; /* numerator */
2591 }
2592
2593 void yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
2594         uint32_t width, uint32_t height, uint32_t yvu)
2595 {
2596     uint32_t i, j;
2597     const unsigned char *src1;
2598     unsigned char *udest, *vdest;
2599
2600     /* copy the Y values */
2601     src1 = src;
2602     for (i = 0; i < height; i++) {
2603         for (j = 0; j < width; j += 2) {
2604             *dest++ = src1[0];
2605             *dest++ = src1[2];
2606             src1 += 4;
2607         }
2608     }
2609
2610     /* copy the U and V values */
2611     src++;              /* point to V */
2612     src1 = src + width * 2;     /* next line */
2613     if (yvu) {
2614         vdest = dest;
2615         udest = dest + width * height / 4;
2616     } else {
2617         udest = dest;
2618         vdest = dest + width * height / 4;
2619     }
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 */
2624             src += 4;
2625             src1 += 4;
2626         }
2627         src = src1;
2628         src1 += width * 2;
2629     }
2630 }
2631
2632 #define RGB2Y(r, g, b, y)   \
2633     (y) = ((8453 * (r) + 16594 * (g) + 3223 * (b) + 524288) >> 15)
2634
2635 #define RGB2UV(r, g, b, u, v)   \
2636     do {    \
2637         (u) = ((-4878 * (r) - 9578 * (g) + 14456 * (b) + 4210688) >> 15);   \
2638         (v) = ((14456 * (r) - 12105 * (g) - 2351 * (b) + 4210688) >> 15);   \
2639     } while (0)
2640
2641 #define CLIP(color) \
2642     (unsigned char)(((color) > 0xFF) ? 0xff : (((color) < 0) ? 0 : (color)))
2643
2644 void rgb24_to_yuv420(const unsigned char *src, unsigned char *dest,
2645                      uint32_t width, uint32_t height, uint32_t yvu)
2646 {
2647     uint32_t x, y;
2648     unsigned char *udest, *vdest;
2649     uint32_t bytesperline = width * 3;
2650
2651     /* Y */
2652     for (y = 0; y < height; y++) {
2653         for (x = 0; x < width; x++) {
2654             RGB2Y(src[2], src[1], src[0], *dest++);
2655             src += 3;
2656         }
2657         src += bytesperline - 3 * width;
2658     }
2659     src -= height * bytesperline;
2660
2661     /* U + V */
2662     if (yvu) {
2663         vdest = dest;
2664         udest = dest + width * height / 4;
2665     } else {
2666         udest = dest;
2667         vdest = dest + width * height / 4;
2668     }
2669
2670     for (y = 0; y < height / 2; y++) {
2671         for (x = 0; x < width / 2; x++) {
2672             uint32_t avg_src[3];
2673
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++);
2681             src += 6;
2682         }
2683         src += 2 * bytesperline - 3 * width;
2684     }
2685 }
2686
2687 void rgb24_to_yuyv(unsigned char *src, unsigned char *dest,
2688                    uint32_t width, uint32_t height)
2689 {
2690     uint32_t i = 0;
2691
2692     for (i = 0; i < (width * height * 3); i = i + 6) {
2693         /* y */
2694         *dest++ = CLIP(0.299 * (src[i + 2] - 128) +
2695                     0.587 * (src[i + 1] - 128) +
2696                     0.114 * (src[i] - 128) + 128);
2697         /* u */
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);
2704         /* y1 */
2705         *dest++ = CLIP(0.299 * (src[i + 5] - 128) +
2706                     0.587 * (src[i + 4] - 128) +
2707                     0.114 * (src[i + 3] - 128) + 128);
2708         /* v */
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);
2715     }
2716 }
2717
2718 void yuv420_to_yvu420(unsigned char *src, unsigned char *dest,
2719                       uint32_t width, uint32_t height)
2720 {
2721     unsigned char *psrc_y, *pdst_y;
2722     unsigned char *psrc_u, *pdst_u;
2723     unsigned char *psrc_v, *pdst_v;
2724
2725     psrc_y = src;
2726     psrc_u = psrc_y + (width * height);
2727     psrc_v = psrc_u + (width * height / 4);
2728
2729     pdst_y = dest;
2730     pdst_v = pdst_y + (width * height);
2731     pdst_u = pdst_v + (width * height / 4);
2732
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);
2736 }
2737
2738 void yuv420_to_yuyv(unsigned char *src, unsigned char *dest,
2739                     uint32_t width, uint32_t height)
2740 {
2741     unsigned char *py;
2742     unsigned char *pu;
2743     unsigned char *pv;
2744
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;
2752     uint32_t h = 0;
2753     uint32_t w = 0;
2754     uint32_t wy = 0;
2755     uint32_t huv = 0;
2756     uint32_t wuv = 0;
2757
2758     py = src;
2759     pu = py + (width * height);
2760     pv = pu + (width * height / 4);
2761
2762     for (h = 0; h < height; h += 2) {
2763         wy = 0;
2764         wuv = 0;
2765         offset = h * linesize;
2766         offset1 = (h + 1) * linesize;
2767         offsety = h * width;
2768         offsety1 = (h + 1) * width;
2769         offsetuv = huv * uvlinesize;
2770
2771         for (w = 0; w < linesize; w += 4) {
2772             /* y00 */
2773             dest[w + offset] = py[wy + offsety];
2774             /* u0 */
2775             dest[(w + 1) + offset] = pu[wuv + offsetuv];
2776             /* y01 */
2777             dest[(w + 2) + offset] = py[(wy + 1) + offsety];
2778             /* v0 */
2779             dest[(w + 3) + offset] = pv[wuv + offsetuv];
2780
2781             /* y10 */
2782             dest[w + offset1] = py[wy + offsety1];
2783             /* u0 */
2784             dest[(w + 1) + offset1] = pu[wuv + offsetuv];
2785             /* y11 */
2786             dest[(w + 2) + offset1] = py[(wy + 1) + offsety1];
2787             /* v0 */
2788             dest[(w + 3) + offset1] = pv[wuv + offsetuv];
2789
2790             wuv++;
2791             wy += 2;
2792         }
2793         huv++;
2794     }
2795 }