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