2 * Virtual Camera device(PCI) for Windows host.
4 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
7 * JinHyung Jo <jinhyung.jo@samsung.com>
8 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
9 * DongKyun Yun <dk77.yun@samsung.com>
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 #include "qemu-common.h"
35 #include "tizen/src/debug_ch.h"
41 MULTI_DEBUG_CHANNEL(tizen, camera_win32);
43 // V4L2 defines copy from videodev2.h
44 #define V4L2_CTRL_FLAG_SLIDER 0x0020
46 #define V4L2_CTRL_CLASS_USER 0x00980000
47 #define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900)
48 #define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE+0)
49 #define V4L2_CID_CONTRAST (V4L2_CID_BASE+1)
50 #define V4L2_CID_SATURATION (V4L2_CID_BASE+2)
51 #define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27)
53 #define V4L2_PIX_FMT_YUYV MAKEFOURCC('Y', 'U', 'Y', 'V') /* 16 YUV 4:2:2 */
54 #define V4L2_PIX_FMT_YUV420 MAKEFOURCC('Y', 'U', '1', '2') /* 12 YUV 4:2:0 */
55 #define V4L2_PIX_FMT_YVU420 MAKEFOURCC('Y', 'V', '1', '2') /* 12 YVU 4:2:0 */
75 typedef enum tagVideoProcAmpProperty {
76 VideoProcAmp_Brightness,
77 VideoProcAmp_Contrast,
79 VideoProcAmp_Saturation,
80 VideoProcAmp_Sharpness,
82 VideoProcAmp_ColorEnable,
83 VideoProcAmp_WhiteBalance,
84 VideoProcAmp_BacklightCompensation,
86 } VideoProcAmpProperty;
88 typedef struct tagHWCParam {
96 typedef struct tagSVCamConvertPixfmt {
97 uint32_t fmt; /* fourcc */
98 uint32_t bpp; /* bits per pixel, 0 for compressed formats */
99 uint32_t needs_conversion;
100 } SVCamConvertPixfmt;
102 static SVCamConvertPixfmt supported_dst_pixfmts[] = {
103 { V4L2_PIX_FMT_YUYV, 16, 0 },
104 { V4L2_PIX_FMT_YUV420, 12, 0 },
105 { V4L2_PIX_FMT_YVU420, 12, 0 },
108 typedef struct tagSVCamConvertFrameInfo {
111 } SVCamConvertFrameInfo;
113 static SVCamConvertFrameInfo supported_dst_frames[] = {
121 #define SVCAM_CTRL_VALUE_MAX 20
122 #define SVCAM_CTRL_VALUE_MIN 1
123 #define SVCAM_CTRL_VALUE_MID 10
124 #define SVCAM_CTRL_VALUE_STEP 1
135 static struct svcam_qctrl qctrl_tbl[] = {
136 { V4L2_CID_BRIGHTNESS, 0, },
137 { V4L2_CID_CONTRAST, 0, },
138 { V4L2_CID_SATURATION,0, },
139 { V4L2_CID_SHARPNESS, 0, },
142 typedef int (STDAPICALLTYPE *CallbackFn)(ULONG dwSize, BYTE *pBuffer);
143 typedef HRESULT (STDAPICALLTYPE *CTRLFN)(UINT, UINT, LPVOID);
144 typedef HRESULT (STDAPICALLTYPE *SETCALLBACKFN)(CallbackFn);
147 static HINSTANCE g_hInst = NULL;
148 static SVCamState *g_state = NULL;
150 static CTRLFN SVCamCtrl;
151 static SETCALLBACKFN SVCamSetCallbackFn;
153 static uint32_t cur_fmt_idx = 0;
154 static uint32_t cur_frame_idx = 0;
156 void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
157 uint32_t width, uint32_t height, uint32_t yvu);
160 static long value_convert_from_guest(long min, long max, long value)
163 long dist = 0, ret = 0;
167 if (dist < SVCAM_CTRL_VALUE_MAX) {
168 rate = (double)SVCAM_CTRL_VALUE_MAX / (double)dist;
169 ret = min + (int32_t)(value / rate);
171 rate = (double)dist / (double)SVCAM_CTRL_VALUE_MAX;
172 ret = min + (int32_t)(rate * value);
177 static long value_convert_to_guest(long min, long max, long value)
180 long dist = 0, ret = 0;
184 if (dist < SVCAM_CTRL_VALUE_MAX) {
185 rate = (double)SVCAM_CTRL_VALUE_MAX / (double)dist;
186 ret = (int32_t)((double)(value - min) * rate);
188 rate = (double)dist / (double)SVCAM_CTRL_VALUE_MAX;
189 ret = (int32_t)((double)(value - min) / rate);
195 static int STDAPICALLTYPE svcam_device_callbackfn(ULONG dwSize, BYTE *pBuffer)
197 static uint32_t index = 0;
198 uint32_t width, height;
199 width = supported_dst_frames[cur_frame_idx].width;
200 height = supported_dst_frames[cur_frame_idx].height;
201 void *buf = g_state->vaddr + (g_state->buf_size * index);
203 switch (supported_dst_pixfmts[cur_fmt_idx].fmt) {
204 case V4L2_PIX_FMT_YUV420:
205 v4lconvert_yuyv_to_yuv420(pBuffer, buf, width, height, 0);
207 case V4L2_PIX_FMT_YVU420:
208 v4lconvert_yuyv_to_yuv420(pBuffer, buf, width, height, 1);
210 case V4L2_PIX_FMT_YUYV:
211 memcpy(buf, (void*)pBuffer, dwSize);
216 if (g_state->req_frame) {
217 qemu_irq_raise(g_state->dev.irq[2]);
218 g_state->req_frame = 0;
224 void svcam_device_init(SVCamState* state)
226 SVCamThreadInfo *thread = state->thread;
228 pthread_cond_init(&thread->thread_cond, NULL);
229 pthread_mutex_init(&thread->mutex_lock, NULL);
235 void svcam_device_open(SVCamState* state)
238 SVCamParam *param = state->thread->param;
241 g_hInst = LoadLibrary("hwcfilter.dll");
244 g_hInst = LoadLibrary("bin\\hwcfilter.dll");
246 ERR("load library failed!!!!\n");
247 param->errCode = EINVAL;
252 SVCamCtrl = (CTRLFN)GetProcAddress(g_hInst, "HWCCtrl");
254 ERR("HWCCtrl get failed!!!\n");
255 FreeLibrary(g_hInst);
256 param->errCode = EINVAL;
260 SVCamSetCallbackFn = (SETCALLBACKFN)GetProcAddress(g_hInst, "HWCSetCallback");
261 if (!SVCamSetCallbackFn) {
262 ERR("HWCSetCallback get failed!!!\n");
263 FreeLibrary(g_hInst);
264 param->errCode = EINVAL;
268 hr = SVCamCtrl(HWC_OPEN, 0, NULL);
270 param->errCode = EINVAL;
271 FreeLibrary(g_hInst);
272 ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
275 hr = SVCamSetCallbackFn((CallbackFn)svcam_device_callbackfn);
277 param->errCode = EINVAL;
278 SVCamCtrl(HWC_CLOSE, 0, NULL);
279 FreeLibrary(g_hInst);
280 ERR("call back function set failed!!!, [HRESULT : 0x%x]\n", hr);
283 TRACE("camera device open success!!!, [HRESULT : 0x%x]\n", hr);
287 void svcam_device_close(SVCamState* state)
290 SVCamParam *param = state->thread->param;
292 hr = SVCamCtrl(HWC_CLOSE, 0, NULL);
294 param->errCode = EINVAL;
295 ERR("camera device close failed!!!, [HRESULT : 0x%x]\n", hr);
297 FreeLibrary(g_hInst);
298 TRACE("camera device close success!!!, [HRESULT : 0x%x]\n", hr);
301 // SVCAM_CMD_START_PREVIEW
302 void svcam_device_start_preview(SVCamState* state)
305 uint32_t width, height;
306 SVCamParam *param = state->thread->param;
307 TRACE("svcam_device_start_preview\n");
309 hr = SVCamCtrl(HWC_START, 0, NULL);
311 param->errCode = EINVAL;
312 ERR("start preview failed!!!, [HRESULT : 0x%x]\n", hr);
315 pthread_mutex_lock(&state->thread->mutex_lock);
317 pthread_mutex_unlock(&state->thread->mutex_lock);
319 width = supported_dst_frames[cur_frame_idx].width;
320 height = supported_dst_frames[cur_frame_idx].height;
321 state->buf_size = height * ((width * supported_dst_pixfmts[cur_fmt_idx].bpp) >> 3);
324 // SVCAM_CMD_STOP_PREVIEW
325 void svcam_device_stop_preview(SVCamState* state)
328 SVCamParam *param = state->thread->param;
329 TRACE("svcam_device_stop_preview\n");
331 hr = SVCamCtrl(HWC_STOP, 0, NULL);
333 param->errCode = EINVAL;
334 ERR("stop preview failed!!!, [HRESULT : 0x%x]\n", hr);
336 pthread_mutex_lock(&state->thread->mutex_lock);
338 pthread_mutex_unlock(&state->thread->mutex_lock);
343 void svcam_device_s_param(SVCamState* state)
345 SVCamParam *param = state->thread->param;
348 TRACE("setting fps : %d/%d\n", param->stack[0], param->stack[1]);
352 void svcam_device_g_param(SVCamState* state)
354 SVCamParam *param = state->thread->param;
357 TRACE("getting fps : 30/1\n");
359 param->stack[0] = 0x1000; // V4L2_CAP_TIMEPERFRAME
360 param->stack[1] = 1; // numerator;
361 param->stack[2] = 30; // denominator;
365 void svcam_device_s_fmt(SVCamState* state)
367 uint32_t width, height, pixfmt, pidx, fidx;
368 SVCamParam *param = state->thread->param;
371 width = param->stack[0]; // width
372 height = param->stack[1]; // height
373 pixfmt = param->stack[2]; // pixelformat
375 for (fidx = 0; fidx < ARRAY_SIZE(supported_dst_frames); fidx++) {
376 if ((supported_dst_frames[fidx].width == width) &&
377 (supported_dst_frames[fidx].height == height)) {
381 if (fidx == ARRAY_SIZE(supported_dst_frames)) {
382 param->errCode = EINVAL;
385 for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) {
386 if (supported_dst_pixfmts[pidx].fmt == pixfmt) {
390 if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {
391 param->errCode = EINVAL;
395 if ((supported_dst_frames[cur_frame_idx].width != width) &&
396 (supported_dst_frames[cur_frame_idx].height != height)) {
397 HWCParam inParam = {0,};
398 inParam.val1 = width;
399 inParam.val2 = height;
400 HRESULT hr = SVCamCtrl(HWC_S_FMT, sizeof(HWCParam), &inParam);
402 param->errCode = EINVAL;
407 param->stack[0] = width;
408 param->stack[1] = height;
409 param->stack[2] = 1; // V4L2_FIELD_NONE
410 param->stack[3] = pixfmt;
411 // bytes per line = (width * bpp) / 8
412 param->stack[4] = (width * supported_dst_pixfmts[pidx].bpp) >> 3;
413 param->stack[5] = param->stack[4] * height; // height * bytesperline
417 cur_frame_idx = fidx;
422 void svcam_device_g_fmt(SVCamState* state)
424 SVCamParam *param = state->thread->param;
428 param->stack[0] = supported_dst_frames[cur_frame_idx].width; // width
429 param->stack[1] = supported_dst_frames[cur_frame_idx].height; // height
430 param->stack[2] = 1; // V4L2_FIELD_NONE
431 param->stack[3] = supported_dst_pixfmts[cur_fmt_idx].fmt; // pixelformat
432 // bytes per line = (width * bpp) / 8
433 param->stack[4] = (param->stack[0] * supported_dst_pixfmts[cur_fmt_idx].bpp) >> 3;
434 param->stack[5] = param->stack[1] * param->stack[4]; // height * bytesperline
439 void svcam_device_try_fmt(SVCamState* state)
441 uint32_t width, height, pixfmt, i;
442 SVCamParam *param = state->thread->param;
445 width = param->stack[0]; // width
446 height = param->stack[1]; // height
447 pixfmt = param->stack[2]; // pixelformat
449 for (i = 0; i < ARRAY_SIZE(supported_dst_frames); i++) {
450 if ((supported_dst_frames[i].width == width) &&
451 (supported_dst_frames[i].height == height)) {
455 if (i == ARRAY_SIZE(supported_dst_frames)) {
456 param->errCode = EINVAL;
459 for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
460 if (supported_dst_pixfmts[i].fmt == pixfmt) {
464 if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
465 param->errCode = EINVAL;
469 param->stack[0] = width;
470 param->stack[1] = height;
471 param->stack[2] = 1; // V4L2_FIELD_NONE
472 param->stack[3] = pixfmt;
473 // bytes per line = (width * bpp) / 8
474 param->stack[4] = (width * supported_dst_pixfmts[i].bpp) >> 3;
475 param->stack[5] = param->stack[4] * height; // height * bytesperline
480 void svcam_device_enum_fmt(SVCamState* state)
483 SVCamParam *param = state->thread->param;
486 index = param->stack[0];
488 if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
489 param->errCode = EINVAL;
492 param->stack[1] = 0; // flags = NONE;
493 param->stack[2] = supported_dst_pixfmts[index].fmt; // pixelformat;
494 /* set description */
495 switch (supported_dst_pixfmts[index].fmt) {
496 case V4L2_PIX_FMT_YUYV:
497 memcpy(¶m->stack[3], "YUY2", 32);
499 case V4L2_PIX_FMT_YUV420:
500 memcpy(¶m->stack[3], "YU12", 32);
502 case V4L2_PIX_FMT_YVU420:
503 memcpy(¶m->stack[3], "YV12", 32);
508 void svcam_device_qctrl(SVCamState* state)
512 HWCParam inParam = {0,};
513 char name[32] = {0,};
514 SVCamParam *param = state->thread->param;
517 id = param->stack[0];
520 case V4L2_CID_BRIGHTNESS:
521 TRACE("V4L2_CID_BRIGHTNESS\n");
522 inParam.val1 = VideoProcAmp_Brightness;
523 memcpy((void*)name, (void*)"brightness", 32);
526 case V4L2_CID_CONTRAST:
527 TRACE("V4L2_CID_CONTRAST\n");
528 inParam.val1 = VideoProcAmp_Contrast;
529 memcpy((void*)name, (void*)"contrast", 32);
532 case V4L2_CID_SATURATION:
533 TRACE("V4L2_CID_SATURATION\n");
534 inParam.val1 = VideoProcAmp_Saturation;
535 memcpy((void*)name, (void*)"saturation", 32);
538 case V4L2_CID_SHARPNESS:
539 TRACE("V4L2_CID_SHARPNESS\n");
540 inParam.val1 = VideoProcAmp_Sharpness;
541 memcpy((void*)name, (void*)"sharpness", 32);
545 param->errCode = EINVAL;
548 hr = SVCamCtrl(HWC_QCTRL, sizeof(inParam), &inParam);
550 param->errCode = EINVAL;
551 ERR("failed to query video controls [HRESULT : 0x%x]\n", hr);
554 qctrl_tbl[i].hit = 1;
555 qctrl_tbl[i].min = inParam.val2;
556 qctrl_tbl[i].max = inParam.val3;
557 qctrl_tbl[i].step = inParam.val4;
558 qctrl_tbl[i].init_val = inParam.val5;
560 if ((qctrl_tbl[i].min + qctrl_tbl[i].max) == 0) {
563 inParam.val2 = (qctrl_tbl[i].min + qctrl_tbl[i].max) / 2;
565 hr = SVCamCtrl(HWC_S_CTRL, sizeof(inParam), &inParam);
567 param->errCode = EINVAL;
568 ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
573 param->stack[0] = id;
574 param->stack[1] = SVCAM_CTRL_VALUE_MIN; // minimum
575 param->stack[2] = SVCAM_CTRL_VALUE_MAX; // maximum
576 param->stack[3] = SVCAM_CTRL_VALUE_STEP;// step
577 param->stack[4] = SVCAM_CTRL_VALUE_MID; // default_value
578 param->stack[5] = V4L2_CTRL_FLAG_SLIDER;
579 /* name field setting */
580 memcpy(¶m->stack[6], (void*)name, sizeof(name)/sizeof(name[0]));
583 void svcam_device_s_ctrl(SVCamState* state)
587 HWCParam inParam = {0,};
588 SVCamParam *param = state->thread->param;
592 switch (param->stack[0]) {
593 case V4L2_CID_BRIGHTNESS:
595 inParam.val1 = VideoProcAmp_Brightness;
597 case V4L2_CID_CONTRAST:
599 inParam.val1 = VideoProcAmp_Contrast;
601 case V4L2_CID_SATURATION:
603 inParam.val1 = VideoProcAmp_Saturation;
605 case V4L2_CID_SHARPNESS:
607 inParam.val1 = VideoProcAmp_Sharpness;
610 param->errCode = EINVAL;
613 inParam.val2 = value_convert_from_guest(qctrl_tbl[i].min,
614 qctrl_tbl[i].max, (long)param->stack[1]);
615 hr = SVCamCtrl(HWC_S_CTRL, sizeof(inParam), &inParam);
617 param->errCode = EINVAL;
618 ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
623 void svcam_device_g_ctrl(SVCamState* state)
627 HWCParam inParam = {0,};
628 SVCamParam *param = state->thread->param;
631 switch (param->stack[0]) {
632 case V4L2_CID_BRIGHTNESS:
634 inParam.val1 = VideoProcAmp_Brightness;
636 case V4L2_CID_CONTRAST:
638 inParam.val1 = VideoProcAmp_Contrast;
640 case V4L2_CID_SATURATION:
642 inParam.val1 = VideoProcAmp_Saturation;
644 case V4L2_CID_SHARPNESS:
646 inParam.val1 = VideoProcAmp_Sharpness;
649 param->errCode = EINVAL;
653 hr = SVCamCtrl(HWC_G_CTRL, sizeof(inParam), &inParam);
655 param->errCode = EINVAL;
656 ERR("failed to get video control value!!!, [HRESULT : 0x%x]\n", hr);
659 param->stack[0] = (uint32_t)value_convert_to_guest(qctrl_tbl[i].min,
660 qctrl_tbl[i].max, inParam.val2);
663 void svcam_device_enum_fsizes(SVCamState* state)
665 uint32_t index, pixfmt, i;
666 SVCamParam *param = state->thread->param;
669 index = param->stack[0];
670 pixfmt = param->stack[1];
672 if (index >= ARRAY_SIZE(supported_dst_frames)) {
673 param->errCode = EINVAL;
676 for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
677 if (supported_dst_pixfmts[i].fmt == pixfmt)
681 if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
682 param->errCode = EINVAL;
686 param->stack[0] = supported_dst_frames[index].width;
687 param->stack[1] = supported_dst_frames[index].height;
690 void svcam_device_enum_fintv(SVCamState* state)
692 SVCamParam *param = state->thread->param;
696 // switch by index(param->stack[0])
697 switch (param->stack[0]) {
699 param->stack[1] = 30; // denominator
702 param->errCode = EINVAL;
705 param->stack[0] = 1; // numerator
708 void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
709 uint32_t width, uint32_t height, uint32_t yvu)
712 const unsigned char *src1;
713 unsigned char *udest, *vdest;
715 /* copy the Y values */
717 for (i = 0; i < height; i++) {
718 for (j = 0; j < width; j += 2) {
725 /* copy the U and V values */
726 src++; /* point to V */
727 src1 = src + width * 2; /* next line */
730 udest = dest + width * height / 4;
733 vdest = dest + width * height / 4;
735 for (i = 0; i < height; i += 2) {
736 for (j = 0; j < width; j += 2) {
737 *udest++ = ((int) src[0] + src1[0]) / 2; /* U */
738 *vdest++ = ((int) src[2] + src1[2]) / 2; /* V */