VirtualBox

source: vbox/trunk/src/VBox/Main/src-client/UsbWebcamInterface.cpp@ 47469

Last change on this file since 47469 was 47416, checked in by vboxsync, 11 years ago

include,Main,Extpack: emulated webcam updates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.5 KB
Line 
1/* $Id: UsbWebcamInterface.cpp 47416 2013-07-26 06:55:18Z vboxsync $ */
2/** @file
3 * UsbWebcamInterface - Driver Interface for USB Webcam emulation.
4 */
5
6/*
7 * Copyright (C) 2011-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19#define LOG_GROUP LOG_GROUP_USB_WEBCAM
20#include "UsbWebcamInterface.h"
21#include "ConsoleImpl.h"
22#include "ConsoleVRDPServer.h"
23
24#include <VBox/vmm/pdmwebcaminfs.h>
25
26
27typedef struct EMWEBCAMDRV
28{
29 EmWebcam *pEmWebcam;
30 PPDMIWEBCAMUP pIWebcamUp;
31 PDMIWEBCAMDOWN IWebcamDown;
32} EMWEBCAMDRV, *PEMWEBCAMDRV;
33
34typedef struct EMWEBCAMREMOTE
35{
36 EmWebcam *pEmWebcam;
37
38 VRDEVIDEOINDEVICEHANDLE deviceHandle; /* The remote identifier. */
39 uint32_t u32Version; /* VRDE_VIDEOIN_NEGOTIATE_VERSION */
40 uint32_t fu32Capabilities; /* VRDE_VIDEOIN_NEGOTIATE_CAP_* */
41
42 /* The device identifier for the PDM device.*/
43 uint64_t u64DeviceId;
44} EMWEBCAMREMOTE;
45
46typedef struct EMWEBCAMREQCTX
47{
48 EMWEBCAMREMOTE *pRemote;
49 void *pvUser;
50} EMWEBCAMREQCTX;
51
52
53static DECLCALLBACK(void) drvEmWebcamReady(PPDMIWEBCAMDOWN pInterface,
54 bool fReady)
55{
56 PEMWEBCAMDRV pThis = RT_FROM_MEMBER(pInterface, EMWEBCAMDRV, IWebcamDown);
57 NOREF(pThis);
58 NOREF(fReady);
59}
60
61static DECLCALLBACK(int) drvEmWebcamControl(PPDMIWEBCAMDOWN pInterface,
62 void *pvUser,
63 uint64_t u64DeviceId,
64 const PDMIWEBCAM_CTRLHDR *pCtrl,
65 uint32_t cbCtrl)
66{
67 PEMWEBCAMDRV pThis = RT_FROM_MEMBER(pInterface, EMWEBCAMDRV, IWebcamDown);
68
69 LogFlowFunc(("pEmWebcam:%p, u64DeviceId %lld\n", pThis->pEmWebcam, u64DeviceId));
70
71 return pThis->pEmWebcam->SendControl(pThis, pvUser, u64DeviceId, (const VRDEVIDEOINCTRLHDR *)pCtrl, cbCtrl);
72}
73
74
75EmWebcam::EmWebcam(Console *console)
76 :
77 mParent(console),
78 mpDrv(NULL),
79 mpRemote(NULL),
80 mu64DeviceIdSrc(0)
81{
82}
83
84EmWebcam::~EmWebcam()
85{
86 if (mpDrv)
87 {
88 mpDrv->pEmWebcam = NULL;
89 mpDrv = NULL;
90 }
91}
92
93void EmWebcam::EmWebcamConstruct(EMWEBCAMDRV *pDrv)
94{
95 AssertReturnVoid(mpDrv == NULL);
96
97 mpDrv = pDrv;
98}
99
100void EmWebcam::EmWebcamDestruct(EMWEBCAMDRV *pDrv)
101{
102 AssertReturnVoid(pDrv == mpDrv);
103
104 if (mpRemote)
105 {
106 mParent->consoleVRDPServer()->VideoInDeviceDetach(&mpRemote->deviceHandle);
107 RTMemFree(mpRemote);
108 mpRemote = NULL;
109 }
110
111 mpDrv = NULL;
112}
113
114void EmWebcam::EmWebcamCbNotify(uint32_t u32Id, const void *pvData, uint32_t cbData)
115{
116 int rc = VINF_SUCCESS;
117
118 switch (u32Id)
119 {
120 case VRDE_VIDEOIN_NOTIFY_ID_ATTACH:
121 {
122 VRDEVIDEOINNOTIFYATTACH *p = (VRDEVIDEOINNOTIFYATTACH *)pvData;
123
124 /* Older versions did not report u32Version and fu32Capabilities. */
125 uint32_t u32Version = 1;
126 uint32_t fu32Capabilities = VRDE_VIDEOIN_NEGOTIATE_CAP_VOID;
127
128 if (cbData >= RT_OFFSETOF(VRDEVIDEOINNOTIFYATTACH, u32Version) + sizeof(p->u32Version))
129 {
130 u32Version = p->u32Version;
131 }
132
133 if (cbData >= RT_OFFSETOF(VRDEVIDEOINNOTIFYATTACH, fu32Capabilities) + sizeof(p->fu32Capabilities))
134 {
135 fu32Capabilities = p->fu32Capabilities;
136 }
137
138 LogFlowFunc(("ATTACH[%d,%d] version %d, caps 0x%08X\n",
139 p->deviceHandle.u32ClientId, p->deviceHandle.u32DeviceId,
140 u32Version, fu32Capabilities));
141
142 /* Currently only one device is allowed. */
143 if (mpRemote)
144 {
145 AssertFailed();
146 rc = VERR_NOT_SUPPORTED;
147 break;
148 }
149
150 EMWEBCAMREMOTE *pRemote = (EMWEBCAMREMOTE *)RTMemAllocZ(sizeof(EMWEBCAMREMOTE));
151 if (pRemote == NULL)
152 {
153 rc = VERR_NO_MEMORY;
154 break;
155 }
156
157 pRemote->pEmWebcam = this;
158 pRemote->deviceHandle = p->deviceHandle;
159 pRemote->u32Version = u32Version;
160 pRemote->fu32Capabilities = fu32Capabilities;
161 pRemote->u64DeviceId = ASMAtomicIncU64(&mu64DeviceIdSrc);
162
163 mpRemote = pRemote;
164
165 /* Tell the server that this webcam will be used. */
166 rc = mParent->consoleVRDPServer()->VideoInDeviceAttach(&mpRemote->deviceHandle, mpRemote);
167 if (RT_FAILURE(rc))
168 {
169 RTMemFree(mpRemote);
170 mpRemote = NULL;
171 break;
172 }
173
174 /* Get the device description. */
175 rc = mParent->consoleVRDPServer()->VideoInGetDeviceDesc(NULL, &mpRemote->deviceHandle);
176
177 if (RT_FAILURE(rc))
178 {
179 mParent->consoleVRDPServer()->VideoInDeviceDetach(&mpRemote->deviceHandle);
180 RTMemFree(mpRemote);
181 mpRemote = NULL;
182 break;
183 }
184
185 LogFlowFunc(("sent DeviceDesc\n"));
186 } break;
187
188 case VRDE_VIDEOIN_NOTIFY_ID_DETACH:
189 {
190 VRDEVIDEOINNOTIFYDETACH *p = (VRDEVIDEOINNOTIFYDETACH *)pvData;
191 Assert(cbData == sizeof(VRDEVIDEOINNOTIFYDETACH));
192
193 LogFlowFunc(("DETACH[%d,%d]\n", p->deviceHandle.u32ClientId, p->deviceHandle.u32DeviceId));
194
195 /* @todo */
196 if (mpRemote)
197 {
198 if (mpDrv && mpDrv->pIWebcamUp)
199 {
200 mpDrv->pIWebcamUp->pfnWebcamUpDetached(mpDrv->pIWebcamUp,
201 mpRemote->u64DeviceId);
202 }
203
204 /* No need to tell the server by calling VideoInDeviceDetach because the server is telling. */
205 RTMemFree(mpRemote);
206 mpRemote = NULL;
207 }
208 } break;
209
210 default:
211 rc = VERR_INVALID_PARAMETER;
212 AssertFailed();
213 break;
214 }
215
216 return;
217}
218
219void EmWebcam::EmWebcamCbDeviceDesc(int rcRequest, void *pDeviceCtx, void *pvUser,
220 const VRDEVIDEOINDEVICEDESC *pDeviceDesc, uint32_t cbDeviceDesc)
221{
222 EMWEBCAMREMOTE *pRemote = (EMWEBCAMREMOTE *)pDeviceCtx;
223 Assert(pRemote == mpRemote);
224
225 LogFlowFunc(("mpDrv %p, rcRequest %Rrc %p %p %p %d\n",
226 mpDrv, rcRequest, pDeviceCtx, pvUser, pDeviceDesc, cbDeviceDesc));
227
228 if (RT_SUCCESS(rcRequest))
229 {
230 if (mpDrv && mpDrv->pIWebcamUp)
231 {
232 mpDrv->pIWebcamUp->pfnWebcamUpAttached(mpDrv->pIWebcamUp,
233 pRemote->u64DeviceId,
234 (const PDMIWEBCAM_DEVICEDESC *)pDeviceDesc,
235 cbDeviceDesc,
236 pRemote->u32Version,
237 pRemote->fu32Capabilities);
238 }
239 }
240 else
241 {
242 mParent->consoleVRDPServer()->VideoInDeviceDetach(&mpRemote->deviceHandle);
243 RTMemFree(mpRemote);
244 mpRemote = NULL;
245 }
246}
247
248void EmWebcam::EmWebcamCbControl(int rcRequest, void *pDeviceCtx, void *pvUser,
249 const VRDEVIDEOINCTRLHDR *pControl, uint32_t cbControl)
250{
251 EMWEBCAMREMOTE *pRemote = (EMWEBCAMREMOTE *)pDeviceCtx;
252 Assert(pRemote == mpRemote);
253
254 LogFlowFunc(("rcRequest %Rrc %p %p %p %d\n",
255 rcRequest, pDeviceCtx, pvUser, pControl, cbControl));
256
257 bool fResponse = (pvUser != NULL);
258
259 if (mpDrv && mpDrv->pIWebcamUp)
260 {
261 mpDrv->pIWebcamUp->pfnWebcamUpControl(mpDrv->pIWebcamUp,
262 fResponse,
263 pvUser,
264 mpRemote->u64DeviceId,
265 (const PDMIWEBCAM_CTRLHDR *)pControl,
266 cbControl);
267 }
268
269 RTMemFree(pvUser);
270}
271
272void EmWebcam::EmWebcamCbFrame(int rcRequest, void *pDeviceCtx,
273 const VRDEVIDEOINPAYLOADHDR *pFrame, uint32_t cbFrame)
274{
275 LogFlowFunc(("rcRequest %Rrc %p %p %d\n",
276 rcRequest, pDeviceCtx, pFrame, cbFrame));
277
278 if (mpDrv && mpDrv->pIWebcamUp)
279 {
280 if ( cbFrame >= sizeof(VRDEVIDEOINPAYLOADHDR)
281 && cbFrame >= pFrame->u8HeaderLength)
282 {
283 uint32_t cbImage = cbFrame - pFrame->u8HeaderLength;
284 const uint8_t *pu8Image = cbImage > 0? (const uint8_t *)pFrame + pFrame->u8HeaderLength: NULL;
285
286 mpDrv->pIWebcamUp->pfnWebcamUpFrame(mpDrv->pIWebcamUp,
287 mpRemote->u64DeviceId,
288 (PDMIWEBCAM_FRAMEHDR *)pFrame,
289 pFrame->u8HeaderLength,
290 pu8Image,
291 cbImage);
292 }
293 }
294}
295
296int EmWebcam::SendControl(EMWEBCAMDRV *pDrv, void *pvUser, uint64_t u64DeviceId,
297 const VRDEVIDEOINCTRLHDR *pControl, uint32_t cbControl)
298{
299 AssertReturn(pDrv == mpDrv, VERR_NOT_SUPPORTED);
300
301 int rc = VINF_SUCCESS;
302
303 EMWEBCAMREQCTX *pCtx = NULL;
304
305 /* Verify that there is a remote device. */
306 if ( !mpRemote
307 || mpRemote->u64DeviceId != u64DeviceId)
308 {
309 rc = VERR_NOT_SUPPORTED;
310 }
311
312 if (RT_SUCCESS(rc))
313 {
314 pCtx = (EMWEBCAMREQCTX *)RTMemAlloc(sizeof(EMWEBCAMREQCTX));
315 if (!pCtx)
316 {
317 rc = VERR_NO_MEMORY;
318 }
319 }
320
321 if (RT_SUCCESS(rc))
322 {
323 pCtx->pRemote = mpRemote;
324 pCtx->pvUser = pvUser;
325
326 rc = mParent->consoleVRDPServer()->VideoInControl(pCtx, &mpRemote->deviceHandle, pControl, cbControl);
327
328 if (RT_FAILURE(rc))
329 {
330 RTMemFree(pCtx);
331 }
332 }
333
334 return rc;
335}
336
337/* static */ DECLCALLBACK(void *) EmWebcam::drvQueryInterface(PPDMIBASE pInterface, const char *pszIID)
338{
339 PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
340 PEMWEBCAMDRV pThis = PDMINS_2_DATA(pDrvIns, PEMWEBCAMDRV);
341
342 LogFlowFunc(("pszIID:%s\n", pszIID));
343
344 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
345 PDMIBASE_RETURN_INTERFACE(pszIID, PDMIWEBCAMDOWN, &pThis->IWebcamDown);
346 return NULL;
347}
348
349/* static */ DECLCALLBACK(void) EmWebcam::drvDestruct(PPDMDRVINS pDrvIns)
350{
351 PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns);
352 PEMWEBCAMDRV pThis = PDMINS_2_DATA(pDrvIns, PEMWEBCAMDRV);
353
354 LogFlowFunc(("iInstance %d, pEmWebcam %p, pIWebcamUp %p\n",
355 pDrvIns->iInstance, pThis->pEmWebcam, pThis->pIWebcamUp));
356
357 if (pThis->pEmWebcam)
358 {
359 pThis->pEmWebcam->EmWebcamDestruct(pThis);
360 pThis->pEmWebcam = NULL;
361 }
362}
363
364/* static */ DECLCALLBACK(int) EmWebcam::drvConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
365{
366 PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
367 LogFlowFunc(("iInstance:%d, pCfg:%p, fFlags:%x\n", pDrvIns->iInstance, pCfg, fFlags));
368
369 PEMWEBCAMDRV pThis = PDMINS_2_DATA(pDrvIns, PEMWEBCAMDRV);
370
371 if (!CFGMR3AreValuesValid(pCfg, "Object\0"))
372 return VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES;
373
374 AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
375 ("Configuration error: Not possible to attach anything to this driver!\n"),
376 VERR_PDM_DRVINS_NO_ATTACH);
377
378 /* Check early that there is a device. No need to init anything if there is no device. */
379 pThis->pIWebcamUp = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMIWEBCAMUP);
380 if (pThis->pIWebcamUp == NULL)
381 {
382 LogRel(("USBWEBCAM: Emulated webcam device does not exist.\n"));
383 return VERR_PDM_MISSING_INTERFACE;
384 }
385
386 void *pv = NULL;
387 int rc = CFGMR3QueryPtr(pCfg, "Object", &pv);
388 if (!RT_VALID_PTR(pv))
389 rc = VERR_INVALID_PARAMETER;
390 AssertMsgReturn(RT_SUCCESS(rc),
391 ("Configuration error: No/bad \"Object\" %p value! rc=%Rrc\n", pv, rc), rc);
392
393 /* Everything ok. Initialize. */
394 pThis->pEmWebcam = (EmWebcam *)pv;
395 pThis->pEmWebcam->EmWebcamConstruct(pThis);
396
397 pDrvIns->IBase.pfnQueryInterface = drvQueryInterface;
398
399 pThis->IWebcamDown.pfnWebcamDownReady = drvEmWebcamReady;
400 pThis->IWebcamDown.pfnWebcamDownControl = drvEmWebcamControl;
401
402 return VINF_SUCCESS;
403}
404
405/* static */ const PDMDRVREG EmWebcam::DrvReg =
406{
407 /* u32Version */
408 PDM_DRVREG_VERSION,
409 /* szName[32] */
410 "EmWebcam",
411 /* szRCMod[32] */
412 "",
413 /* szR0Mod[32] */
414 "",
415 /* pszDescription */
416 "Main Driver communicating with VRDE",
417 /* fFlags */
418 PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
419 /* fClass */
420 PDM_DRVREG_CLASS_USB,
421 /* cMaxInstances */
422 1,
423 /* cbInstance */
424 sizeof(EMWEBCAMDRV),
425 /* pfnConstruct */
426 EmWebcam::drvConstruct,
427 /* pfnDestruct */
428 EmWebcam::drvDestruct,
429 /* pfnRelocate */
430 NULL,
431 /* pfnIOCtl */
432 NULL,
433 /* pfnPowerOn */
434 NULL,
435 /* pfnReset */
436 NULL,
437 /* pfnSuspend */
438 NULL,
439 /* pfnResume */
440 NULL,
441 /* pfnAttach */
442 NULL,
443 /* pfnDetach */
444 NULL,
445 /* pfnPowerOff */
446 NULL,
447 /* pfnSoftReset */
448 NULL,
449 /* u32VersionEnd */
450 PDM_DRVREG_VERSION
451};
452/* vi: set tabstop=4 shiftwidth=4 expandtab: */
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use