return r;\r
}\r
\r
+typedef struct tagMaruCamConvertPixfmt {\r
+ uint32_t fmt; /* fourcc */\r
+} MaruCamConvertPixfmt;\r
+\r
+static MaruCamConvertPixfmt supported_dst_pixfmts[] = {\r
+ { V4L2_PIX_FMT_YUYV },\r
+ { V4L2_PIX_FMT_YUV420 },\r
+ { V4L2_PIX_FMT_YVU420 },\r
+};\r
+\r
+typedef struct tagMaruCamConvertFrameInfo {\r
+ uint32_t width;\r
+ uint32_t height;\r
+} MaruCamConvertFrameInfo;\r
+\r
+static MaruCamConvertFrameInfo supported_dst_frames[] = {\r
+ { 640, 480 },\r
+ { 352, 288 },\r
+ { 320, 240 },\r
+ { 176, 144 },\r
+ { 160, 120 },\r
+};\r
+\r
#define MARUCAM_CTRL_VALUE_MAX 20\r
#define MARUCAM_CTRL_VALUE_MIN 1\r
#define MARUCAM_CTRL_VALUE_MID 10\r
return ret;\r
}\r
\r
+static void set_maxframeinterval(MaruCamState *state, uint32_t pixel_format,\r
+ uint32_t width, uint32_t height)\r
+{\r
+ struct v4l2_frmivalenum fival;\r
+ struct v4l2_streamparm sp;\r
+ uint32_t min_num = 0, min_denom = 0;\r
+\r
+ CLEAR(fival);\r
+ fival.pixel_format = pixel_format;\r
+ fival.width = width;\r
+ fival.height = height;\r
+\r
+ if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) < 0) {\r
+ ERR("Unable to enumerate intervals for pixelformat(0x%x), (%d:%d)\n",\r
+ pixel_format, width, height);\r
+ return;\r
+ }\r
+\r
+ if (fival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {\r
+ float max_ival = -1.0;\r
+ do {\r
+ float cur_ival = (float)fival.discrete.numerator\r
+ / (float)fival.discrete.denominator;\r
+ if (cur_ival > max_ival) {\r
+ max_ival = cur_ival;\r
+ min_num = fival.discrete.numerator;\r
+ min_denom = fival.discrete.denominator;\r
+ }\r
+ TRACE("Discrete frame interval %u/%u supported\n",\r
+ fival.discrete.numerator, fival.discrete.denominator);\r
+ fival.index++;\r
+ } while (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) >= 0);\r
+ } else if ((fival.type == V4L2_FRMIVAL_TYPE_STEPWISE) ||\r
+ (fival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)) {\r
+ TRACE("Frame intervals from %u/%u to %u/%u supported",\r
+ fival.stepwise.min.numerator, fival.stepwise.min.denominator,\r
+ fival.stepwise.max.numerator, fival.stepwise.max.denominator);\r
+ if(fival.type == V4L2_FRMIVAL_TYPE_STEPWISE)\r
+ TRACE("with %u/%u step",\r
+ fival.stepwise.step.numerator, fival.stepwise.step.denominator);\r
+ if (((float)fival.stepwise.max.denominator /\r
+ (float)fival.stepwise.max.numerator) >\r
+ ((float)fival.stepwise.min.denominator /\r
+ (float)fival.stepwise.min.numerator)) {\r
+ min_num = fival.stepwise.max.numerator;\r
+ min_denom = fival.stepwise.max.denominator;\r
+ } else {\r
+ min_num = fival.stepwise.min.numerator;\r
+ min_denom = fival.stepwise.min.denominator;\r
+ }\r
+ }\r
+ TRACE("actual min values : %u/%u\n", min_num, min_denom);\r
+\r
+ CLEAR(sp);\r
+ sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
+ sp.parm.capture.timeperframe.numerator = min_num;\r
+ sp.parm.capture.timeperframe.denominator = min_denom;\r
+\r
+ if (xioctl(v4l2_fd, VIDIOC_S_PARM, &sp) < 0) {\r
+ ERR("Failed to set to minimum FPS(%u/%u)\n", min_num, min_denom);\r
+ }\r
+}\r
+\r
static int is_streamon(MaruCamState *state)\r
{\r
int st;\r
\r
void marucam_device_start_preview(MaruCamState* state)\r
{\r
+ struct timespec req;\r
+ req.tv_sec = 0;\r
+ req.tv_nsec = 10000000;\r
+\r
+ INFO("Starting preview!\n");\r
qemu_mutex_lock(&state->thread_mutex);\r
qemu_cond_signal(&state->thread_cond);\r
qemu_mutex_unlock(&state->thread_mutex);\r
- INFO("Starting preview!\n");\r
+\r
+ /* nanosleep until thread is streamon */\r
+ while (!is_stream_on(state))\r
+ nanosleep(&req, NULL);\r
}\r
\r
void marucam_device_stop_preview(MaruCamState* state)\r
{\r
MaruCamParam *param = state->param;\r
\r
- /* We use default FPS of the webcam */\r
param->top = 0;\r
+\r
+ /* If KVM enabled, We use default FPS of the webcam.\r
+ * If KVM disabled, we use mininum FPS of the webcam */\r
+ if (!kvm_enabled()) {\r
+ set_maxframeinterval(state, dst_fmt.fmt.pix.pixelformat,\r
+ dst_fmt.fmt.pix.width,\r
+ dst_fmt.fmt.pix.height);\r
+ }\r
}\r
\r
void marucam_device_g_param(MaruCamState* state)\r
\r
void marucam_device_enum_fmt(MaruCamState* state)\r
{\r
- struct v4l2_fmtdesc format;\r
+ uint32_t index;\r
MaruCamParam *param = state->param;\r
\r
param->top = 0;\r
- CLEAR(format);\r
- format.index = param->stack[0];\r
- format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;\r
+ index = param->stack[0];\r
\r
- if (xioctl(v4l2_fd, VIDIOC_ENUM_FMT, &format) < 0) {\r
- if (errno != EINVAL)\r
- ERR("failed to enumerate video formats: %s\n", strerror(errno));\r
- param->errCode = errno;\r
+ if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {\r
+ param->errCode = EINVAL;\r
return;\r
}\r
- param->stack[0] = format.index;\r
- param->stack[1] = format.flags;\r
- param->stack[2] = format.pixelformat;\r
+ param->stack[1] = 0; /* flags = NONE */\r
+ param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */\r
/* set description */\r
- memcpy(¶m->stack[3], format.description, sizeof(format.description));\r
+ switch (supported_dst_pixfmts[index].fmt) {\r
+ case V4L2_PIX_FMT_YUYV:\r
+ memcpy(¶m->stack[3], "YUYV", 32);\r
+ break;\r
+ case V4L2_PIX_FMT_YUV420:\r
+ memcpy(¶m->stack[3], "YU12", 32);\r
+ break;\r
+ case V4L2_PIX_FMT_YVU420:\r
+ memcpy(¶m->stack[3], "YV12", 32);\r
+ break;\r
+ }\r
}\r
\r
void marucam_device_qctrl(MaruCamState* state)\r
\r
void marucam_device_enum_fsizes(MaruCamState* state)\r
{\r
- struct v4l2_frmsizeenum fsize;\r
+ uint32_t index, pixfmt, i;\r
MaruCamParam *param = state->param;\r
\r
param->top = 0;\r
- CLEAR(fsize);\r
- fsize.index = param->stack[0];\r
- fsize.pixel_format = param->stack[1];\r
+ index = param->stack[0];\r
+ pixfmt = param->stack[1];\r
\r
- if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMESIZES, &fsize) < 0) {\r
- if (errno != EINVAL)\r
- ERR("failed to get frame sizes : %s\n", strerror(errno));\r
- param->errCode = errno;\r
+ if (index >= ARRAY_SIZE(supported_dst_frames)) {\r
+ param->errCode = EINVAL;\r
return;\r
}\r
+ for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {\r
+ if (supported_dst_pixfmts[i].fmt == pixfmt)\r
+ break;\r
+ }\r
\r
- if (fsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {\r
- param->stack[0] = fsize.discrete.width;\r
- param->stack[1] = fsize.discrete.height;\r
- } else {\r
+ if (i == ARRAY_SIZE(supported_dst_pixfmts)) {\r
param->errCode = EINVAL;\r
- ERR("Not Supported mode, we only support DISCRETE\n");\r
+ return;\r
}\r
+\r
+ param->stack[0] = supported_dst_frames[index].width;\r
+ param->stack[1] = supported_dst_frames[index].height;\r
}\r
\r
void marucam_device_enum_fintv(MaruCamState* state)\r
{\r
- struct v4l2_frmivalenum ival;\r
MaruCamParam *param = state->param;\r
\r
param->top = 0;\r
- CLEAR(ival);\r
- ival.index = param->stack[0];\r
- ival.pixel_format = param->stack[1];\r
- ival.width = param->stack[2];\r
- ival.height = param->stack[3];\r
-\r
- if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &ival) < 0) {\r
- if (errno != EINVAL)\r
- ERR("failed to get frame intervals : %s\n", strerror(errno));\r
- param->errCode = errno;\r
- return;\r
- }\r
\r
- if (ival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {\r
- param->stack[0] = ival.discrete.numerator;\r
- param->stack[1] = ival.discrete.denominator;\r
- } else {\r
+ /* switch by index(param->stack[0]) */\r
+ switch (param->stack[0]) {\r
+ case 0:\r
+ /* we only use 1/30 frame interval */\r
+ param->stack[1] = 30; /* denominator */\r
+ break;\r
+ default:\r
param->errCode = EINVAL;\r
- ERR("Not Supported mode, we only support DISCRETE\n");\r
+ return;\r
}\r
+ param->stack[0] = 1; /* numerator */\r
}\r
\r
void marucam_device_close(MaruCamState* state)\r