Initialize
[sdk/emulator/qemu.git] / tizen / src / hw / svcamera_win32.c
1 /*
2  * Virtual Camera device(PCI) for Windows host.
3  *
4  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
5  *
6  * Contact:
7  * JinHyung Jo <jinhyung.jo@samsung.com>
8  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
9  * DongKyun Yun <dk77.yun@samsung.com>
10  *
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.
15  *
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.
20  *
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.
24  *
25  * Contributors:
26  * - S-Core Co., Ltd
27  *
28  */
29
30
31 #include "qemu-common.h"
32 #include "svcamera.h"
33 #include "pci.h"
34 #include "kvm.h"
35 #include "tizen/src/debug_ch.h"
36
37 #include "windows.h"
38 #include "basetyps.h"
39 #include "mmsystem.h"
40
41 MULTI_DEBUG_CHANNEL(tizen, camera_win32);
42
43 // V4L2 defines copy from videodev2.h
44 #define V4L2_CTRL_FLAG_SLIDER       0x0020
45
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)
52
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     */
56
57 enum {
58     HWC_OPEN,
59     HWC_CLOSE,
60     HWC_START,
61     HWC_STOP,
62     HWC_S_FPS,
63     HWC_G_FPS,
64     HWC_S_FMT,
65     HWC_G_FMT,
66     HWC_TRY_FMT,
67     HWC_ENUM_FMT,
68     HWC_QCTRL,
69     HWC_S_CTRL,
70     HWC_G_CTRL,
71     HWC_ENUM_FSIZES,
72     HWC_ENUM_INTERVALS
73 };
74
75 typedef enum tagVideoProcAmpProperty {
76   VideoProcAmp_Brightness,
77   VideoProcAmp_Contrast,
78   VideoProcAmp_Hue,
79   VideoProcAmp_Saturation,
80   VideoProcAmp_Sharpness,
81   VideoProcAmp_Gamma,
82   VideoProcAmp_ColorEnable,
83   VideoProcAmp_WhiteBalance,
84   VideoProcAmp_BacklightCompensation,
85   VideoProcAmp_Gain
86 } VideoProcAmpProperty;
87
88 typedef struct tagHWCParam {
89     long val1;
90     long val2;
91     long val3;
92     long val4;
93     long val5;
94 } HWCParam;
95
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;
101
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 },
106 };
107
108 typedef struct tagSVCamConvertFrameInfo {
109     uint32_t width;
110     uint32_t height;
111 } SVCamConvertFrameInfo;
112
113 static SVCamConvertFrameInfo supported_dst_frames[] = {
114         { 640, 480 },
115         { 352, 288 },
116         { 320, 240 },
117         { 176, 144 },
118         { 160, 120 },
119 };
120
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
125
126 struct svcam_qctrl {
127     uint32_t id;
128     uint32_t hit;
129     long min;
130     long max;
131     long step;
132     long init_val;
133 };
134
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, },
140 };
141
142 typedef int (STDAPICALLTYPE *CallbackFn)(ULONG dwSize, BYTE *pBuffer);
143 typedef HRESULT (STDAPICALLTYPE *CTRLFN)(UINT, UINT, LPVOID);
144 typedef HRESULT (STDAPICALLTYPE *SETCALLBACKFN)(CallbackFn);
145
146
147 static HINSTANCE g_hInst = NULL;
148 static SVCamState *g_state = NULL;
149
150 static CTRLFN SVCamCtrl;
151 static SETCALLBACKFN SVCamSetCallbackFn;
152
153 static uint32_t cur_fmt_idx = 0;
154 static uint32_t cur_frame_idx = 0;
155
156 void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
157         uint32_t width, uint32_t height, uint32_t yvu);
158
159
160 static long value_convert_from_guest(long min, long max, long value)
161 {
162     double rate = 0.0;
163     long dist = 0, ret = 0;
164
165     dist = max - min;
166
167     if (dist < SVCAM_CTRL_VALUE_MAX) {
168         rate = (double)SVCAM_CTRL_VALUE_MAX / (double)dist;
169         ret = min + (int32_t)(value / rate);
170     } else {
171         rate = (double)dist / (double)SVCAM_CTRL_VALUE_MAX;
172         ret = min + (int32_t)(rate * value);
173     }
174     return ret;
175 }
176
177 static long value_convert_to_guest(long min, long max, long value)
178 {
179     double rate  = 0.0;
180     long dist = 0, ret = 0;
181
182     dist = max - min;
183
184     if (dist < SVCAM_CTRL_VALUE_MAX) {
185         rate = (double)SVCAM_CTRL_VALUE_MAX / (double)dist;
186         ret = (int32_t)((double)(value - min) * rate);
187     } else {
188         rate = (double)dist / (double)SVCAM_CTRL_VALUE_MAX;
189         ret = (int32_t)((double)(value - min) / rate);
190     }
191
192     return ret;
193 }
194
195 static int STDAPICALLTYPE svcam_device_callbackfn(ULONG dwSize, BYTE *pBuffer)
196 {
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);
202
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);
206         break;
207     case V4L2_PIX_FMT_YVU420:
208         v4lconvert_yuyv_to_yuv420(pBuffer, buf, width, height, 1);
209         break;
210     case V4L2_PIX_FMT_YUYV:
211         memcpy(buf, (void*)pBuffer, dwSize);
212         break;
213     }
214     index = !index;
215
216     if (g_state->req_frame) {
217         qemu_irq_raise(g_state->dev.irq[2]);
218         g_state->req_frame = 0;
219     }
220     return 1;
221 }
222
223 // SVCAM_CMD_INIT
224 void svcam_device_init(SVCamState* state)
225 {
226     SVCamThreadInfo *thread = state->thread;
227
228     pthread_cond_init(&thread->thread_cond, NULL);
229     pthread_mutex_init(&thread->mutex_lock, NULL);
230
231     g_state = state;
232 }
233
234 // SVCAM_CMD_OPEN
235 void svcam_device_open(SVCamState* state)
236 {
237     HRESULT hr;
238     SVCamParam *param = state->thread->param;
239     param->top = 0;
240
241     g_hInst = LoadLibrary("hwcfilter.dll");
242
243     if (!g_hInst) {
244         g_hInst = LoadLibrary("bin\\hwcfilter.dll");
245         if (!g_hInst) {
246             ERR("load library failed!!!!\n");
247             param->errCode = EINVAL;
248             return;
249         }
250     }
251
252     SVCamCtrl = (CTRLFN)GetProcAddress(g_hInst, "HWCCtrl");
253     if (!SVCamCtrl) {
254         ERR("HWCCtrl get failed!!!\n");
255         FreeLibrary(g_hInst);
256         param->errCode = EINVAL;
257         return;
258     }
259
260     SVCamSetCallbackFn = (SETCALLBACKFN)GetProcAddress(g_hInst, "HWCSetCallback");
261     if (!SVCamSetCallbackFn) {
262         ERR("HWCSetCallback get failed!!!\n");
263         FreeLibrary(g_hInst);
264         param->errCode = EINVAL;
265         return;
266     }
267
268     hr = SVCamCtrl(HWC_OPEN, 0, NULL);
269     if (FAILED(hr)) {
270         param->errCode = EINVAL;
271         FreeLibrary(g_hInst);
272         ERR("camera device open failed!!!, [HRESULT : 0x%x]\n", hr);
273         return;
274     }
275     hr = SVCamSetCallbackFn((CallbackFn)svcam_device_callbackfn);
276     if (FAILED(hr)) {
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);
281     }
282
283     TRACE("camera device open success!!!, [HRESULT : 0x%x]\n", hr);
284 }
285
286 // SVCAM_CMD_CLOSE
287 void svcam_device_close(SVCamState* state)
288 {
289     HRESULT hr;
290     SVCamParam *param = state->thread->param;
291     param->top = 0;
292     hr = SVCamCtrl(HWC_CLOSE, 0, NULL);
293     if (FAILED(hr)) {
294         param->errCode = EINVAL;
295         ERR("camera device close failed!!!, [HRESULT : 0x%x]\n", hr);
296     }
297     FreeLibrary(g_hInst);
298     TRACE("camera device close success!!!, [HRESULT : 0x%x]\n", hr);
299 }
300
301 // SVCAM_CMD_START_PREVIEW
302 void svcam_device_start_preview(SVCamState* state)
303 {
304     HRESULT hr;
305     uint32_t width, height;
306     SVCamParam *param = state->thread->param;
307     TRACE("svcam_device_start_preview\n");
308     param->top = 0;
309     hr = SVCamCtrl(HWC_START, 0, NULL);
310     if (FAILED(hr)) {
311         param->errCode = EINVAL;
312         ERR("start preview failed!!!, [HRESULT : 0x%x]\n", hr);
313         return;
314     }
315     pthread_mutex_lock(&state->thread->mutex_lock);
316     state->streamon = 1;
317     pthread_mutex_unlock(&state->thread->mutex_lock);
318
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);
322 }
323
324 // SVCAM_CMD_STOP_PREVIEW
325 void svcam_device_stop_preview(SVCamState* state)
326 {
327     HRESULT hr;
328     SVCamParam *param = state->thread->param;
329     TRACE("svcam_device_stop_preview\n");
330     param->top = 0;
331     hr = SVCamCtrl(HWC_STOP, 0, NULL);
332     if (FAILED(hr)) {
333         param->errCode = EINVAL;
334         ERR("stop preview failed!!!, [HRESULT : 0x%x]\n", hr);
335     }
336     pthread_mutex_lock(&state->thread->mutex_lock);
337     state->streamon = 0;
338     pthread_mutex_unlock(&state->thread->mutex_lock);
339     state->buf_size = 0;
340 }
341
342 // SVCAM_CMD_S_PARAM
343 void svcam_device_s_param(SVCamState* state)
344 {
345     SVCamParam *param = state->thread->param;
346
347     param->top = 0;
348     TRACE("setting fps : %d/%d\n", param->stack[0], param->stack[1]);
349 }
350
351 // SVCAM_CMD_G_PARAM
352 void svcam_device_g_param(SVCamState* state)
353 {
354     SVCamParam *param = state->thread->param;
355
356     param->top = 0;
357     TRACE("getting fps : 30/1\n");
358
359     param->stack[0] = 0x1000; // V4L2_CAP_TIMEPERFRAME
360     param->stack[1] = 1; // numerator;
361     param->stack[2] = 30; // denominator;
362 }
363
364 // SVCAM_CMD_S_FMT
365 void svcam_device_s_fmt(SVCamState* state)
366 {
367     uint32_t width, height, pixfmt, pidx, fidx;
368     SVCamParam *param = state->thread->param;
369
370     param->top = 0;
371     width = param->stack[0];        // width
372     height = param->stack[1];       // height
373     pixfmt = param->stack[2];       // pixelformat
374
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)) {
378             break;
379         }
380     }
381     if (fidx == ARRAY_SIZE(supported_dst_frames)) {
382         param->errCode = EINVAL;
383         return;
384     }
385     for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) {
386         if (supported_dst_pixfmts[pidx].fmt == pixfmt) {
387             break;
388         }
389     }
390     if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {
391         param->errCode = EINVAL;
392         return;
393     }
394
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);
401         if (FAILED(hr)) {
402             param->errCode = EINVAL;
403             return;
404         }
405     }
406
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
414     param->stack[6] = 0;
415     param->stack[7] = 0;
416
417     cur_frame_idx = fidx;
418     cur_fmt_idx = pidx;
419 }
420
421 // SVCAM_CMD_G_FMT
422 void svcam_device_g_fmt(SVCamState* state)
423 {
424     SVCamParam *param = state->thread->param;
425
426     param->top = 0;
427
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
435     param->stack[6] = 0;
436     param->stack[7] = 0;
437 }
438
439 void svcam_device_try_fmt(SVCamState* state)
440 {
441     uint32_t width, height, pixfmt, i;
442     SVCamParam *param = state->thread->param;
443
444     param->top = 0;
445     width = param->stack[0];        // width
446     height = param->stack[1];       // height
447     pixfmt = param->stack[2];       // pixelformat
448
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)) {
452             break;
453         }
454     }
455     if (i == ARRAY_SIZE(supported_dst_frames)) {
456         param->errCode = EINVAL;
457         return;
458     }
459     for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
460         if (supported_dst_pixfmts[i].fmt == pixfmt) {
461             break;
462         }
463     }
464     if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
465         param->errCode = EINVAL;
466         return;
467     }
468
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
476     param->stack[6] = 0;
477     param->stack[7] = 0;
478 }
479
480 void svcam_device_enum_fmt(SVCamState* state)
481 {
482     uint32_t index;
483     SVCamParam *param = state->thread->param;
484
485     param->top = 0;
486     index = param->stack[0];
487
488     if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
489         param->errCode = EINVAL;
490         return;
491     }
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(&param->stack[3], "YUY2", 32);
498         break;
499     case V4L2_PIX_FMT_YUV420:
500         memcpy(&param->stack[3], "YU12", 32);
501         break;
502     case V4L2_PIX_FMT_YVU420:
503         memcpy(&param->stack[3], "YV12", 32);
504         break;
505     }
506 }
507
508 void svcam_device_qctrl(SVCamState* state)
509 {
510     HRESULT hr;
511     uint32_t id, i;
512     HWCParam inParam = {0,};
513     char name[32] = {0,};
514     SVCamParam *param = state->thread->param;
515
516     param->top = 0;
517     id = param->stack[0];
518
519     switch (id) {
520     case V4L2_CID_BRIGHTNESS:
521         TRACE("V4L2_CID_BRIGHTNESS\n");
522         inParam.val1 = VideoProcAmp_Brightness;
523         memcpy((void*)name, (void*)"brightness", 32);
524         i = 0;
525         break;
526     case V4L2_CID_CONTRAST:
527         TRACE("V4L2_CID_CONTRAST\n");
528         inParam.val1 = VideoProcAmp_Contrast;
529         memcpy((void*)name, (void*)"contrast", 32);
530         i = 1;
531         break;
532     case V4L2_CID_SATURATION:
533         TRACE("V4L2_CID_SATURATION\n");
534         inParam.val1 = VideoProcAmp_Saturation;
535         memcpy((void*)name, (void*)"saturation", 32);
536         i = 2;
537         break;
538     case V4L2_CID_SHARPNESS:
539         TRACE("V4L2_CID_SHARPNESS\n");
540         inParam.val1 = VideoProcAmp_Sharpness;
541         memcpy((void*)name, (void*)"sharpness", 32);
542         i = 3;
543         break;
544     default:
545         param->errCode = EINVAL;
546         return;
547     }
548     hr = SVCamCtrl(HWC_QCTRL, sizeof(inParam), &inParam);
549     if (FAILED(hr)) {
550         param->errCode = EINVAL;
551         ERR("failed to query video controls [HRESULT : 0x%x]\n", hr);
552         return;
553     } else {
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;
559
560         if ((qctrl_tbl[i].min + qctrl_tbl[i].max) == 0) {
561             inParam.val2 = 0;
562         } else {
563             inParam.val2 = (qctrl_tbl[i].min + qctrl_tbl[i].max) / 2;
564         }
565         hr = SVCamCtrl(HWC_S_CTRL, sizeof(inParam), &inParam);
566         if (FAILED(hr)) {
567             param->errCode = EINVAL;
568             ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
569             return;
570         }
571     }
572
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(&param->stack[6], (void*)name, sizeof(name)/sizeof(name[0]));
581 }
582
583 void svcam_device_s_ctrl(SVCamState* state)
584 {
585     HRESULT hr;
586     uint32_t i;
587     HWCParam inParam = {0,};
588     SVCamParam *param = state->thread->param;
589
590     param->top = 0;
591
592     switch (param->stack[0]) {
593     case V4L2_CID_BRIGHTNESS:
594         i = 0;
595         inParam.val1 = VideoProcAmp_Brightness;
596         break;
597     case V4L2_CID_CONTRAST:
598         i = 1;
599         inParam.val1 = VideoProcAmp_Contrast;
600         break;
601     case V4L2_CID_SATURATION:
602         i = 2;
603         inParam.val1 = VideoProcAmp_Saturation;
604         break;
605     case V4L2_CID_SHARPNESS:
606         i = 3;
607         inParam.val1 = VideoProcAmp_Sharpness;
608         break;
609     default:
610         param->errCode = EINVAL;
611         return;
612     }
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);
616     if (FAILED(hr)) {
617         param->errCode = EINVAL;
618         ERR("failed to set video control value, [HRESULT : 0x%x]\n", hr);
619         return;
620     }
621 }
622
623 void svcam_device_g_ctrl(SVCamState* state)
624 {
625     HRESULT hr;
626     uint32_t i;
627     HWCParam inParam = {0,};
628     SVCamParam *param = state->thread->param;
629
630     param->top = 0;
631     switch (param->stack[0]) {
632     case V4L2_CID_BRIGHTNESS:
633         i = 0;
634         inParam.val1 = VideoProcAmp_Brightness;
635         break;
636     case V4L2_CID_CONTRAST:
637         i = 1;
638         inParam.val1 = VideoProcAmp_Contrast;
639         break;
640     case V4L2_CID_SATURATION:
641         i = 2;
642         inParam.val1 = VideoProcAmp_Saturation;
643         break;
644     case V4L2_CID_SHARPNESS:
645         i = 3;
646         inParam.val1 = VideoProcAmp_Sharpness;
647         break;
648     default:
649         param->errCode = EINVAL;
650         return;
651     }
652
653     hr = SVCamCtrl(HWC_G_CTRL, sizeof(inParam), &inParam);
654     if (FAILED(hr)) {
655         param->errCode = EINVAL;
656         ERR("failed to get video control value!!!, [HRESULT : 0x%x]\n", hr);
657         return;
658     }
659     param->stack[0] = (uint32_t)value_convert_to_guest(qctrl_tbl[i].min,
660                 qctrl_tbl[i].max, inParam.val2);
661 }
662
663 void svcam_device_enum_fsizes(SVCamState* state)
664 {
665     uint32_t index, pixfmt, i;
666     SVCamParam *param = state->thread->param;
667
668     param->top = 0;
669     index = param->stack[0];
670     pixfmt = param->stack[1];
671
672     if (index >= ARRAY_SIZE(supported_dst_frames)) {
673         param->errCode = EINVAL;
674         return;
675     }
676     for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
677         if (supported_dst_pixfmts[i].fmt == pixfmt)
678             break;
679     }
680
681     if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
682         param->errCode = EINVAL;
683         return;
684     }
685
686     param->stack[0] = supported_dst_frames[index].width;
687     param->stack[1] = supported_dst_frames[index].height;
688 }
689
690 void svcam_device_enum_fintv(SVCamState* state)
691 {
692     SVCamParam *param = state->thread->param;
693
694     param->top = 0;
695
696     // switch by index(param->stack[0])
697     switch (param->stack[0]) {
698     case 0:
699         param->stack[1] = 30;   // denominator
700         break;
701     default:
702         param->errCode = EINVAL;
703         return;
704     }
705     param->stack[0] = 1;    // numerator
706 }
707
708 void v4lconvert_yuyv_to_yuv420(const unsigned char *src, unsigned char *dest,
709         uint32_t width, uint32_t height, uint32_t yvu)
710 {
711     uint32_t i, j;
712     const unsigned char *src1;
713     unsigned char *udest, *vdest;
714
715     /* copy the Y values */
716     src1 = src;
717     for (i = 0; i < height; i++) {
718         for (j = 0; j < width; j += 2) {
719             *dest++ = src1[0];
720             *dest++ = src1[2];
721             src1 += 4;
722         }
723     }
724
725     /* copy the U and V values */
726     src++;              /* point to V */
727     src1 = src + width * 2;     /* next line */
728     if (yvu) {
729         vdest = dest;
730         udest = dest + width * height / 4;
731     } else {
732         udest = dest;
733         vdest = dest + width * height / 4;
734     }
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 */
739             src += 4;
740             src1 += 4;
741         }
742         src = src1;
743         src1 += width * 2;
744     }
745 }