2 * Implementation of MARU Virtual Camera device by PCI bus on Linux.
4 * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
7 * JinHyung Jo <jinhyung.jo@samsung.com>
8 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
30 #include "qemu-common.h"
31 #include "maru_camera_common.h"
34 #include "tizen/src/debug_ch.h"
36 #include <linux/videodev2.h>
39 #include <sys/ioctl.h>
43 #include <libv4lconvert.h>
45 MULTI_DEBUG_CHANNEL(tizen, camera_linux);
47 #define CLEAR(x) memset(&(x), 0, sizeof(x))
49 #define MARUCAM_DEFAULT_BUFFER_COUNT 4
50 #define MARUCAM_DUMMYFRAME_COUNT 2
52 #define MARUCAM_CTRL_VALUE_MAX 20
53 #define MARUCAM_CTRL_VALUE_MIN 1
54 #define MARUCAM_CTRL_VALUE_MID 10
55 #define MARUCAM_CTRL_VALUE_STEP 1
63 typedef struct marucam_framebuffer {
66 } marucam_framebuffer;
68 static int n_framebuffer;
69 static struct marucam_framebuffer *framebuffer;
71 static const char *dev_name = "/dev/video0";
73 static int convert_trial;
74 static int ready_count;
77 static struct v4l2_format dst_fmt;
79 static void make_yu12_black(unsigned char *dest, uint32_t width, uint32_t height)
82 unsigned char *udest, *vdest;
85 for (y = 0; y < height; y++) {
86 for (x = 0; x < width; x++) {
93 vdest = dest + width * height / 4;
95 for (y = 0; y < height / 2; y++) {
96 for (x = 0; x < width / 2; x++) {
97 *udest++ = *vdest++ = 128;
102 static int yioctl(int fd, int req, void *arg)
107 r = ioctl(fd, req, arg);
108 } while (r < 0 && errno == EINTR);
113 static int xioctl(int fd, int req, void *arg)
118 r = v4l2_ioctl(fd, req, arg);
119 } while (r < 0 && errno == EINTR);
124 typedef struct tagMaruCamConvertPixfmt {
125 uint32_t fmt; /* fourcc */
126 } MaruCamConvertPixfmt;
128 static MaruCamConvertPixfmt supported_dst_pixfmts[] = {
129 { V4L2_PIX_FMT_YUYV },
130 { V4L2_PIX_FMT_YUV420 },
131 { V4L2_PIX_FMT_YVU420 },
134 typedef struct tagMaruCamConvertFrameInfo {
137 } MaruCamConvertFrameInfo;
139 static MaruCamConvertFrameInfo supported_dst_frames[] = {
147 struct marucam_qctrl {
156 static struct marucam_qctrl qctrl_tbl[] = {
157 { V4L2_CID_BRIGHTNESS, 0, },
158 { V4L2_CID_CONTRAST, 0, },
159 { V4L2_CID_SATURATION, 0, },
160 { V4L2_CID_SHARPNESS, 0, },
163 static void marucam_reset_controls(void)
166 for (i = 0; i < ARRAY_SIZE(qctrl_tbl); i++) {
167 if (qctrl_tbl[i].hit) {
168 struct v4l2_control ctrl = {0,};
169 qctrl_tbl[i].hit = 0;
170 ctrl.id = qctrl_tbl[i].id;
171 ctrl.value = qctrl_tbl[i].init_val;
172 if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) {
173 ERR("Failed to reset control value: id(0x%x), errstr(%s)\n",
174 ctrl.id, strerror(errno));
180 static int32_t value_convert_from_guest(int32_t min, int32_t max, int32_t value)
183 int32_t dist = 0, ret = 0;
187 if (dist < MARUCAM_CTRL_VALUE_MAX) {
188 rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
189 ret = min + (int32_t)(value / rate);
191 rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
192 ret = min + (int32_t)(rate * value);
197 static int32_t value_convert_to_guest(int32_t min, int32_t max, int32_t value)
200 int32_t dist = 0, ret = 0;
204 if (dist < MARUCAM_CTRL_VALUE_MAX) {
205 rate = (double)MARUCAM_CTRL_VALUE_MAX / (double)dist;
206 ret = (int32_t)((double)(value - min) * rate);
208 rate = (double)dist / (double)MARUCAM_CTRL_VALUE_MAX;
209 ret = (int32_t)((double)(value - min) / rate);
215 static void set_maxframeinterval(MaruCamState *state, uint32_t pixel_format,
216 uint32_t width, uint32_t height)
218 struct v4l2_frmivalenum fival;
219 struct v4l2_streamparm sp;
220 uint32_t min_num = 0, min_denom = 0;
223 fival.pixel_format = pixel_format;
225 fival.height = height;
227 if (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) < 0) {
228 ERR("Unable to enumerate intervals for pixelformat(0x%x), (%d:%d)\n",
229 pixel_format, width, height);
233 if (fival.type == V4L2_FRMIVAL_TYPE_DISCRETE) {
234 float max_ival = -1.0;
236 float cur_ival = (float)fival.discrete.numerator
237 / (float)fival.discrete.denominator;
238 if (cur_ival > max_ival) {
240 min_num = fival.discrete.numerator;
241 min_denom = fival.discrete.denominator;
243 TRACE("Discrete frame interval %u/%u supported\n",
244 fival.discrete.numerator, fival.discrete.denominator);
246 } while (xioctl(v4l2_fd, VIDIOC_ENUM_FRAMEINTERVALS, &fival) >= 0);
247 } else if ((fival.type == V4L2_FRMIVAL_TYPE_STEPWISE) ||
248 (fival.type == V4L2_FRMIVAL_TYPE_CONTINUOUS)) {
249 TRACE("Frame intervals from %u/%u to %u/%u supported",
250 fival.stepwise.min.numerator, fival.stepwise.min.denominator,
251 fival.stepwise.max.numerator, fival.stepwise.max.denominator);
252 if (fival.type == V4L2_FRMIVAL_TYPE_STEPWISE) {
253 TRACE("with %u/%u step", fival.stepwise.step.numerator,
254 fival.stepwise.step.denominator);
256 if (((float)fival.stepwise.max.denominator /
257 (float)fival.stepwise.max.numerator) >
258 ((float)fival.stepwise.min.denominator /
259 (float)fival.stepwise.min.numerator)) {
260 min_num = fival.stepwise.max.numerator;
261 min_denom = fival.stepwise.max.denominator;
263 min_num = fival.stepwise.min.numerator;
264 min_denom = fival.stepwise.min.denominator;
267 TRACE("The actual min values: %u/%u\n", min_num, min_denom);
270 sp.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
271 sp.parm.capture.timeperframe.numerator = min_num;
272 sp.parm.capture.timeperframe.denominator = min_denom;
274 if (xioctl(v4l2_fd, VIDIOC_S_PARM, &sp) < 0) {
275 ERR("Failed to set to minimum FPS(%u/%u)\n", min_num, min_denom);
279 static uint32_t stop_capturing(void)
281 enum v4l2_buf_type type;
283 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
284 if (xioctl(v4l2_fd, VIDIOC_STREAMOFF, &type) < 0) {
285 ERR("Failed to ioctl() with VIDIOC_STREAMOFF: %s\n", strerror(errno));
291 static uint32_t start_capturing(void)
293 enum v4l2_buf_type type;
295 type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
296 if (xioctl(v4l2_fd, VIDIOC_STREAMON, &type) < 0) {
297 ERR("Failed to ioctl() with VIDIOC_STREAMON: %s\n", strerror(errno));
303 static void free_framebuffers(marucam_framebuffer *fb, int buf_num)
308 ERR("The framebuffer is NULL. Failed to release the framebuffer\n");
310 } else if (buf_num == 0) {
311 ERR("The buffer count is 0. Failed to release the framebuffer\n");
314 TRACE("[%s]:fb(0x%p), buf_num(%d)\n", __func__, fb, buf_num);
317 /* Unmap framebuffers. */
318 for (i = 0; i < buf_num; i++) {
319 if (fb[i].data != NULL) {
320 v4l2_munmap(fb[i].data, fb[i].size);
324 ERR("framebuffer[%d].data is NULL.\n", i);
330 mmap_framebuffers(marucam_framebuffer **fb, int *buf_num)
332 struct v4l2_requestbuffers req;
335 req.count = MARUCAM_DEFAULT_BUFFER_COUNT;
336 req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
337 req.memory = V4L2_MEMORY_MMAP;
338 if (xioctl(v4l2_fd, VIDIOC_REQBUFS, &req) < 0) {
339 if (errno == EINVAL) {
340 ERR("%s does not support memory mapping: %s\n",
341 dev_name, strerror(errno));
343 ERR("Failed to request bufs: %s\n", strerror(errno));
347 if (req.count == 0) {
348 ERR("Insufficient buffer memory on %s\n", dev_name);
352 *fb = g_new0(marucam_framebuffer, req.count);
354 ERR("Not enough memory to allocate framebuffers\n");
358 for (*buf_num = 0; *buf_num < req.count; ++*buf_num) {
359 struct v4l2_buffer buf;
361 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
362 buf.memory = V4L2_MEMORY_MMAP;
363 buf.index = *buf_num;
364 if (xioctl(v4l2_fd, VIDIOC_QUERYBUF, &buf) < 0) {
365 ERR("Failed to ioctl() with VIDIOC_QUERYBUF: %s\n",
370 (*fb)[*buf_num].size = buf.length;
371 (*fb)[*buf_num].data = v4l2_mmap(NULL,
373 PROT_READ | PROT_WRITE,
375 v4l2_fd, buf.m.offset);
376 if (MAP_FAILED == (*fb)[*buf_num].data) {
377 ERR("Failed to mmap: %s\n", strerror(errno));
381 /* Queue the mapped buffer. */
383 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
384 buf.memory = V4L2_MEMORY_MMAP;
385 buf.index = *buf_num;
386 if (xioctl(v4l2_fd, VIDIOC_QBUF, &buf) < 0) {
387 ERR("Failed to ioctl() with VIDIOC_QBUF: %s\n", strerror(errno));
394 static int is_streamon(MaruCamState *state)
397 qemu_mutex_lock(&state->thread_mutex);
398 st = state->streamon;
399 qemu_mutex_unlock(&state->thread_mutex);
400 return (st == _MC_THREAD_STREAMON);
403 static int is_stream_paused(MaruCamState *state)
406 qemu_mutex_lock(&state->thread_mutex);
407 st = state->streamon;
408 qemu_mutex_unlock(&state->thread_mutex);
409 return (st == _MC_THREAD_PAUSED);
412 /* sends a frame, YU12/black color */
413 static void __raise_empty_intr(MaruCamState *state)
416 qemu_mutex_lock(&state->thread_mutex);
417 if (state->streamon == _MC_THREAD_STREAMON && state->req_frame) {
418 buf = state->vaddr + state->buf_size * (state->req_frame - 1);
419 make_yu12_black(buf, dst_fmt.fmt.pix.width, dst_fmt.fmt.pix.height);
420 state->req_frame = 0; /* clear request */
421 state->isr = 0x01; /* set a flag of raising a interrupt */
422 qemu_bh_schedule(state->tx_bh);
424 qemu_mutex_unlock(&state->thread_mutex);
427 static void __raise_err_intr(MaruCamState *state)
429 qemu_mutex_lock(&state->thread_mutex);
430 if (state->streamon == _MC_THREAD_STREAMON) {
431 state->req_frame = 0; /* clear request */
432 state->isr = 0x08; /* set a error flag of raising a interrupt */
433 qemu_bh_schedule(state->tx_bh);
435 qemu_mutex_unlock(&state->thread_mutex);
439 notify_buffer_ready(MaruCamState *state, void *ptr, size_t size)
443 qemu_mutex_lock(&state->thread_mutex);
444 if (state->streamon == _MC_THREAD_STREAMON) {
445 if (ready_count < MARUCAM_SKIPFRAMES) {
446 /* skip a frame cause first some frame are distorted */
448 TRACE("Skip %d frame\n", ready_count);
449 qemu_mutex_unlock(&state->thread_mutex);
452 if (state->req_frame == 0) {
453 TRACE("There is no request\n");
454 qemu_mutex_unlock(&state->thread_mutex);
457 buf = state->vaddr + state->buf_size * (state->req_frame - 1);
458 memcpy(buf, ptr, state->buf_size);
459 state->req_frame = 0; /* clear request */
460 state->isr |= 0x01; /* set a flag of rasing a interrupt */
461 qemu_bh_schedule(state->tx_bh);
463 qemu_mutex_unlock(&state->thread_mutex);
466 static int read_frame(MaruCamState *state)
468 struct v4l2_buffer buf;
471 buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
472 buf.memory = V4L2_MEMORY_MMAP;
473 if (xioctl(v4l2_fd, VIDIOC_DQBUF, &buf) < 0) {
477 ERR("DQBUF error, try again: %s\n", strerror(errno));
480 ERR("The v4l2_read() met the EIO\n");
481 if (convert_trial-- == -1) {
482 ERR("Try count for v4l2_read is exceeded: %s\n",
488 ERR("DQBUF error: %s\n", strerror(errno));
493 notify_buffer_ready(state, framebuffer[buf.index].data, buf.bytesused);
495 if (xioctl(v4l2_fd, VIDIOC_QBUF, &buf) < 0) {
496 ERR("QBUF error: %s\n", strerror(errno));
502 static int __v4l2_streaming(MaruCamState *state)
509 FD_SET(v4l2_fd, &fds);
514 ret = select(v4l2_fd + 1, &fds, NULL, NULL, &tv);
516 if (errno == EAGAIN || errno == EINTR) {
517 ERR("Select again: %s\n", strerror(errno));
520 ERR("Failed to select: %s\n", strerror(errno));
521 __raise_err_intr(state);
525 ERR("Select timed out: count(%u)\n", timeout_n);
526 if (ready_count == 0) {
527 if (timeout_n <= MARUCAM_DUMMYFRAME_COUNT) {
528 ERR("Sends dummy data to initialize the camera\n");
529 __raise_empty_intr(state);
532 ERR("Webcam is busy, failed to a read frame."
533 " Raises an error\n");
534 __raise_err_intr(state);
538 if (timeout_n >= 5) {
539 ERR("Webcam is busy, failed to a read frame. Raises an error\n");
540 __raise_err_intr(state);
546 if (!v4l2_fd || (v4l2_fd == -1)) {
547 ERR("The file descriptor is closed or not opened\n");
548 __raise_err_intr(state);
552 ret = read_frame(state);
554 ERR("Failed to operate the read_frame()\n");
555 __raise_err_intr(state);
559 /* clear the skip count for select time-out */
568 static void *marucam_worker_thread(void *thread_param)
570 MaruCamState *state = (MaruCamState *)thread_param;
573 qemu_mutex_lock(&state->thread_mutex);
574 state->streamon = _MC_THREAD_PAUSED;
575 qemu_cond_wait(&state->thread_cond, &state->thread_mutex);
576 qemu_mutex_unlock(&state->thread_mutex);
578 if (state->destroying) {
585 qemu_mutex_lock(&state->thread_mutex);
586 state->streamon = _MC_THREAD_STREAMON;
587 qemu_mutex_unlock(&state->thread_mutex);
588 INFO("Streaming on ......\n");
591 if (is_streamon(state)) {
592 if (__v4l2_streaming(state) < 0) {
593 INFO("...... Streaming off\n");
597 INFO("...... Streaming off\n");
606 int marucam_device_check(int log_flag)
609 struct timeval t1, t2;
611 struct v4l2_fmtdesc format;
612 struct v4l2_frmsizeenum size;
613 struct v4l2_capability cap;
616 gettimeofday(&t1, NULL);
617 if (stat(dev_name, &st) < 0) {
618 fprintf(stdout, "[Webcam] <WARNING> Cannot identify '%s': %s\n",
619 dev_name, strerror(errno));
621 if (!S_ISCHR(st.st_mode)) {
622 fprintf(stdout, "[Webcam] <WARNING>%s is no character device\n",
627 tmp_fd = open(dev_name, O_RDWR | O_NONBLOCK, 0);
629 fprintf(stdout, "[Webcam] Camera device open failed: %s\n", dev_name);
630 gettimeofday(&t2, NULL);
631 fprintf(stdout, "[Webcam] Elapsed time: %lu:%06lu\n",
632 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
635 if (ioctl(tmp_fd, VIDIOC_QUERYCAP, &cap) < 0) {
636 fprintf(stdout, "[Webcam] Could not qeury video capabilities\n");
638 gettimeofday(&t2, NULL);
639 fprintf(stdout, "[Webcam] Elapsed time: %lu:%06lu\n",
640 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
643 if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE) ||
644 !(cap.capabilities & V4L2_CAP_STREAMING)) {
645 fprintf(stdout, "[Webcam] Not supported video driver\n");
647 gettimeofday(&t2, NULL);
648 fprintf(stdout, "[Webcam] Elapsed time: %lu:%06lu\n",
649 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
655 fprintf(stdout, "[Webcam] Driver: %s\n", cap.driver);
656 fprintf(stdout, "[Webcam] Card: %s\n", cap.card);
657 fprintf(stdout, "[Webcam] Bus info: %s\n", cap.bus_info);
661 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
663 if (yioctl(tmp_fd, VIDIOC_ENUM_FMT, &format) < 0) {
665 gettimeofday(&t2, NULL);
666 fprintf(stdout, "[Webcam] Elapsed time: %lu:%06lu\n",
667 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
674 size.pixel_format = format.pixelformat;
676 fprintf(stdout, "[Webcam] PixelFormat: %c%c%c%c\n",
677 (char)(format.pixelformat),
678 (char)(format.pixelformat >> 8),
679 (char)(format.pixelformat >> 16),
680 (char)(format.pixelformat >> 24));
682 if (yioctl(tmp_fd, VIDIOC_ENUM_FRAMESIZES, &size) < 0) {
684 gettimeofday(&t2, NULL);
685 fprintf(stdout, "[Webcam] Elapsed time: %lu:%06lu\n",
686 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
690 if (size.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
692 fprintf(stdout, "[Webcam] got discrete frame size %dx%d\n",
693 size.discrete.width, size.discrete.height);
695 } while (yioctl(tmp_fd, VIDIOC_ENUM_FRAMESIZES, &size) >= 0);
696 } else if (size.type == V4L2_FRMSIZE_TYPE_STEPWISE) {
697 fprintf(stdout, "[Webcam] we have stepwise frame sizes:\n");
698 fprintf(stdout, "[Webcam] min width: %d, min height: %d\n",
699 size.stepwise.min_width, size.stepwise.min_height);
700 fprintf(stdout, "[Webcam] max width: %d, max height: %d\n",
701 size.stepwise.max_width, size.stepwise.max_height);
702 fprintf(stdout, "[Webcam] step width: %d, step height: %d\n",
703 size.stepwise.step_width, size.stepwise.step_height);
704 } else if (size.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) {
705 fprintf(stdout, "[Webcam] we have continuous frame sizes:\n");
706 fprintf(stdout, "[Webcam] min width: %d, min height: %d\n",
707 size.stepwise.min_width, size.stepwise.min_height);
708 fprintf(stdout, "[Webcam] max width: %d, max height: %d\n",
709 size.stepwise.max_width, size.stepwise.max_height);
713 } while (yioctl(tmp_fd, VIDIOC_ENUM_FMT, &format) >= 0);
717 gettimeofday(&t2, NULL);
718 fprintf(stdout, "[Webcam] Elapsed time: %lu:%06lu\n",
719 t2.tv_sec-t1.tv_sec, t2.tv_usec-t1.tv_usec);
723 void marucam_device_init(MaruCamState *state)
725 state->destroying = false;
726 qemu_thread_create(&state->thread_id, marucam_worker_thread, (void *)state,
727 QEMU_THREAD_JOINABLE);
730 void marucam_device_exit(MaruCamState *state)
732 state->destroying = true;
733 qemu_mutex_lock(&state->thread_mutex);
734 qemu_cond_signal(&state->thread_cond);
735 qemu_mutex_unlock(&state->thread_mutex);
736 qemu_thread_join(&state->thread_id);
739 void marucam_device_open(MaruCamState *state)
741 MaruCamParam *param = state->param;
744 v4l2_fd = v4l2_open(dev_name, O_RDWR | O_NONBLOCK, 0);
746 ERR("The v4l2 device open failed: %s\n", dev_name);
747 param->errCode = EINVAL;
752 /* FIXME : Do not use fixed values */
754 dst_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
755 dst_fmt.fmt.pix.width = 640;
756 dst_fmt.fmt.pix.height = 480;
757 dst_fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
758 dst_fmt.fmt.pix.field = V4L2_FIELD_ANY;
760 if (xioctl(v4l2_fd, VIDIOC_S_FMT, &dst_fmt) < 0) {
761 ERR("Failed to set video format: format(0x%x), width:height(%d:%d), "
762 "errstr(%s)\n", dst_fmt.fmt.pix.pixelformat, dst_fmt.fmt.pix.width,
763 dst_fmt.fmt.pix.height, strerror(errno));
764 param->errCode = errno;
767 TRACE("Set the default format: w:h(%dx%d), fmt(0x%x), size(%d), "
768 "color(%d), field(%d)\n",
769 dst_fmt.fmt.pix.width, dst_fmt.fmt.pix.height,
770 dst_fmt.fmt.pix.pixelformat, dst_fmt.fmt.pix.sizeimage,
771 dst_fmt.fmt.pix.colorspace, dst_fmt.fmt.pix.field);
774 void marucam_device_start_preview(MaruCamState *state)
777 MaruCamParam *param = state->param;
780 req.tv_nsec = 10000000;
782 INFO("Pixfmt(%c%c%c%C), W:H(%d:%d), buf size(%u)\n",
783 (char)(dst_fmt.fmt.pix.pixelformat),
784 (char)(dst_fmt.fmt.pix.pixelformat >> 8),
785 (char)(dst_fmt.fmt.pix.pixelformat >> 16),
786 (char)(dst_fmt.fmt.pix.pixelformat >> 24),
787 dst_fmt.fmt.pix.width,
788 dst_fmt.fmt.pix.height,
789 dst_fmt.fmt.pix.sizeimage);
791 param->errCode = mmap_framebuffers(&framebuffer, &n_framebuffer);
792 if (param->errCode) {
793 ERR("Failed to mmap framebuffers\n");
794 if (framebuffer != NULL) {
795 free_framebuffers(framebuffer, n_framebuffer);
803 param->errCode = start_capturing();
804 if (param->errCode) {
805 if (framebuffer != NULL) {
806 free_framebuffers(framebuffer, n_framebuffer);
814 INFO("Starting preview\n");
815 state->buf_size = dst_fmt.fmt.pix.sizeimage;
816 qemu_mutex_lock(&state->thread_mutex);
817 qemu_cond_signal(&state->thread_cond);
818 qemu_mutex_unlock(&state->thread_mutex);
820 /* nanosleep until thread is streamon */
821 while (!is_streamon(state)) {
822 nanosleep(&req, NULL);
826 void marucam_device_stop_preview(MaruCamState *state)
829 struct v4l2_requestbuffers reqbuf;
830 MaruCamParam *param = state->param;
833 req.tv_nsec = 50000000;
835 if (is_streamon(state)) {
836 qemu_mutex_lock(&state->thread_mutex);
837 state->streamon = _MC_THREAD_STREAMOFF;
838 qemu_mutex_unlock(&state->thread_mutex);
840 /* nanosleep until thread is paused */
841 while (!is_stream_paused(state)) {
842 nanosleep(&req, NULL);
846 param->errCode = stop_capturing();
847 if (framebuffer != NULL) {
848 free_framebuffers(framebuffer, n_framebuffer);
856 reqbuf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
857 reqbuf.memory = V4L2_MEMORY_MMAP;
858 if (xioctl(v4l2_fd, VIDIOC_REQBUFS, &reqbuf) < 0) {
859 ERR("Failed to ioctl() with VIDIOC_REQBUF in stop_preview: %s\n",
862 INFO("Stopping preview\n");
865 void marucam_device_s_param(MaruCamState *state)
867 MaruCamParam *param = state->param;
871 /* If KVM enabled, We use default FPS of the webcam.
872 * If KVM disabled, we use mininum FPS of the webcam */
873 if (!kvm_enabled()) {
874 set_maxframeinterval(state, dst_fmt.fmt.pix.pixelformat,
875 dst_fmt.fmt.pix.width,
876 dst_fmt.fmt.pix.height);
880 void marucam_device_g_param(MaruCamState *state)
882 MaruCamParam *param = state->param;
884 /* We use default FPS of the webcam
885 * return a fixed value on guest ini file (1/30).
888 param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */
889 param->stack[1] = 1; /* numerator */
890 param->stack[2] = 30; /* denominator */
893 void marucam_device_s_fmt(MaruCamState *state)
895 struct v4l2_format format;
896 MaruCamParam *param = state->param;
900 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
901 format.fmt.pix.width = param->stack[0];
902 format.fmt.pix.height = param->stack[1];
903 format.fmt.pix.pixelformat = param->stack[2];
904 format.fmt.pix.field = V4L2_FIELD_ANY;
906 if (xioctl(v4l2_fd, VIDIOC_S_FMT, &format) < 0) {
907 ERR("Failed to set video format: format(0x%x), width:height(%d:%d), "
908 "errstr(%s)\n", format.fmt.pix.pixelformat, format.fmt.pix.width,
909 format.fmt.pix.height, strerror(errno));
910 param->errCode = errno;
914 memcpy(&dst_fmt, &format, sizeof(format));
915 param->stack[0] = dst_fmt.fmt.pix.width;
916 param->stack[1] = dst_fmt.fmt.pix.height;
917 param->stack[2] = dst_fmt.fmt.pix.field;
918 param->stack[3] = dst_fmt.fmt.pix.pixelformat;
919 param->stack[4] = dst_fmt.fmt.pix.bytesperline;
920 param->stack[5] = dst_fmt.fmt.pix.sizeimage;
921 param->stack[6] = dst_fmt.fmt.pix.colorspace;
922 param->stack[7] = dst_fmt.fmt.pix.priv;
923 TRACE("Set the format: w:h(%dx%d), fmt(0x%x), size(%d), "
924 "color(%d), field(%d)\n",
925 dst_fmt.fmt.pix.width, dst_fmt.fmt.pix.height,
926 dst_fmt.fmt.pix.pixelformat, dst_fmt.fmt.pix.sizeimage,
927 dst_fmt.fmt.pix.colorspace, dst_fmt.fmt.pix.field);
930 void marucam_device_g_fmt(MaruCamState *state)
932 struct v4l2_format format;
933 MaruCamParam *param = state->param;
937 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
939 if (xioctl(v4l2_fd, VIDIOC_G_FMT, &format) < 0) {
940 ERR("Failed to get video format: %s\n", strerror(errno));
941 param->errCode = errno;
943 param->stack[0] = format.fmt.pix.width;
944 param->stack[1] = format.fmt.pix.height;
945 param->stack[2] = format.fmt.pix.field;
946 param->stack[3] = format.fmt.pix.pixelformat;
947 param->stack[4] = format.fmt.pix.bytesperline;
948 param->stack[5] = format.fmt.pix.sizeimage;
949 param->stack[6] = format.fmt.pix.colorspace;
950 param->stack[7] = format.fmt.pix.priv;
951 TRACE("Get the format: w:h(%dx%d), fmt(0x%x), size(%d), "
952 "color(%d), field(%d)\n",
953 format.fmt.pix.width, format.fmt.pix.height,
954 format.fmt.pix.pixelformat, format.fmt.pix.sizeimage,
955 format.fmt.pix.colorspace, format.fmt.pix.field);
959 void marucam_device_try_fmt(MaruCamState *state)
961 struct v4l2_format format;
962 MaruCamParam *param = state->param;
966 format.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
967 format.fmt.pix.width = param->stack[0];
968 format.fmt.pix.height = param->stack[1];
969 format.fmt.pix.pixelformat = param->stack[2];
970 format.fmt.pix.field = V4L2_FIELD_ANY;
972 if (xioctl(v4l2_fd, VIDIOC_TRY_FMT, &format) < 0) {
973 ERR("Failed to check video format: format(0x%x), width:height(%d:%d),"
974 " errstr(%s)\n", format.fmt.pix.pixelformat, format.fmt.pix.width,
975 format.fmt.pix.height, strerror(errno));
976 param->errCode = errno;
979 param->stack[0] = format.fmt.pix.width;
980 param->stack[1] = format.fmt.pix.height;
981 param->stack[2] = format.fmt.pix.field;
982 param->stack[3] = format.fmt.pix.pixelformat;
983 param->stack[4] = format.fmt.pix.bytesperline;
984 param->stack[5] = format.fmt.pix.sizeimage;
985 param->stack[6] = format.fmt.pix.colorspace;
986 param->stack[7] = format.fmt.pix.priv;
987 TRACE("Check the format: w:h(%dx%d), fmt(0x%x), size(%d), "
988 "color(%d), field(%d)\n",
989 format.fmt.pix.width, format.fmt.pix.height,
990 format.fmt.pix.pixelformat, format.fmt.pix.sizeimage,
991 format.fmt.pix.colorspace, format.fmt.pix.field);
994 void marucam_device_enum_fmt(MaruCamState *state)
997 MaruCamParam *param = state->param;
1000 index = param->stack[0];
1002 if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
1003 param->errCode = EINVAL;
1006 param->stack[1] = 0; /* flags = NONE */
1007 param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */
1008 /* set description */
1009 switch (supported_dst_pixfmts[index].fmt) {
1010 case V4L2_PIX_FMT_YUYV:
1011 memcpy(¶m->stack[3], "YUYV", 32);
1013 case V4L2_PIX_FMT_YUV420:
1014 memcpy(¶m->stack[3], "YU12", 32);
1016 case V4L2_PIX_FMT_YVU420:
1017 memcpy(¶m->stack[3], "YV12", 32);
1020 ERR("Invalid fixel format\n");
1021 param->errCode = EINVAL;
1026 void marucam_device_qctrl(MaruCamState *state)
1029 char name[32] = {0,};
1030 struct v4l2_queryctrl ctrl;
1031 MaruCamParam *param = state->param;
1035 ctrl.id = param->stack[0];
1038 case V4L2_CID_BRIGHTNESS:
1039 TRACE("Query : BRIGHTNESS\n");
1040 memcpy((void *)name, (void *)"brightness", 32);
1043 case V4L2_CID_CONTRAST:
1044 TRACE("Query : CONTRAST\n");
1045 memcpy((void *)name, (void *)"contrast", 32);
1048 case V4L2_CID_SATURATION:
1049 TRACE("Query : SATURATION\n");
1050 memcpy((void *)name, (void *)"saturation", 32);
1053 case V4L2_CID_SHARPNESS:
1054 TRACE("Query : SHARPNESS\n");
1055 memcpy((void *)name, (void *)"sharpness", 32);
1059 ERR("Invalid control ID\n");
1060 param->errCode = EINVAL;
1064 if (xioctl(v4l2_fd, VIDIOC_QUERYCTRL, &ctrl) < 0) {
1065 if (errno != EINVAL) {
1066 ERR("Failed to query video controls: %s\n", strerror(errno));
1068 param->errCode = errno;
1071 struct v4l2_control sctrl;
1074 if ((ctrl.maximum + ctrl.minimum) == 0) {
1077 sctrl.value = (ctrl.maximum + ctrl.minimum) / 2;
1079 if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &sctrl) < 0) {
1080 ERR("Failed to set control value: id(0x%x), value(%d), "
1081 "errstr(%s)\n", sctrl.id, sctrl.value, strerror(errno));
1082 param->errCode = errno;
1085 qctrl_tbl[i].hit = 1;
1086 qctrl_tbl[i].min = ctrl.minimum;
1087 qctrl_tbl[i].max = ctrl.maximum;
1088 qctrl_tbl[i].step = ctrl.step;
1089 qctrl_tbl[i].init_val = ctrl.default_value;
1092 /* set fixed values by FW configuration file */
1093 param->stack[0] = ctrl.id;
1094 param->stack[1] = MARUCAM_CTRL_VALUE_MIN; /* minimum */
1095 param->stack[2] = MARUCAM_CTRL_VALUE_MAX; /* maximum */
1096 param->stack[3] = MARUCAM_CTRL_VALUE_STEP; /* step */
1097 param->stack[4] = MARUCAM_CTRL_VALUE_MID; /* default_value */
1098 param->stack[5] = ctrl.flags;
1099 /* name field setting */
1100 memcpy(¶m->stack[6], (void *)name, sizeof(ctrl.name));
1103 void marucam_device_s_ctrl(MaruCamState *state)
1106 struct v4l2_control ctrl;
1107 MaruCamParam *param = state->param;
1111 ctrl.id = param->stack[0];
1114 case V4L2_CID_BRIGHTNESS:
1116 TRACE("%d is set to the value of the BRIGHTNESS\n", param->stack[1]);
1118 case V4L2_CID_CONTRAST:
1120 TRACE("%d is set to the value of the CONTRAST\n", param->stack[1]);
1122 case V4L2_CID_SATURATION:
1124 TRACE("%d is set to the value of the SATURATION\n", param->stack[1]);
1126 case V4L2_CID_SHARPNESS:
1128 TRACE("%d is set to the value of the SHARPNESS\n", param->stack[1]);
1131 ERR("Our emulator does not support this control: 0x%x\n", ctrl.id);
1132 param->errCode = EINVAL;
1136 ctrl.value = value_convert_from_guest(qctrl_tbl[i].min,
1137 qctrl_tbl[i].max, param->stack[1]);
1138 if (xioctl(v4l2_fd, VIDIOC_S_CTRL, &ctrl) < 0) {
1139 ERR("Failed to set control value: id(0x%x), value(r:%d, c:%d), "
1140 "errstr(%s)\n", ctrl.id, param->stack[1], ctrl.value,
1142 param->errCode = errno;
1147 void marucam_device_g_ctrl(MaruCamState *state)
1150 struct v4l2_control ctrl;
1151 MaruCamParam *param = state->param;
1155 ctrl.id = param->stack[0];
1158 case V4L2_CID_BRIGHTNESS:
1159 TRACE("Gets the value of the BRIGHTNESS\n");
1162 case V4L2_CID_CONTRAST:
1163 TRACE("Gets the value of the CONTRAST\n");
1166 case V4L2_CID_SATURATION:
1167 TRACE("Gets the value of the SATURATION\n");
1170 case V4L2_CID_SHARPNESS:
1171 TRACE("Gets the value of the SHARPNESS\n");
1175 ERR("Our emulator does not support this control: 0x%x\n", ctrl.id);
1176 param->errCode = EINVAL;
1180 if (xioctl(v4l2_fd, VIDIOC_G_CTRL, &ctrl) < 0) {
1181 ERR("Failed to get video control value: %s\n", strerror(errno));
1182 param->errCode = errno;
1185 param->stack[0] = value_convert_to_guest(qctrl_tbl[i].min,
1186 qctrl_tbl[i].max, ctrl.value);
1187 TRACE("Value: %d\n", param->stack[0]);
1190 void marucam_device_enum_fsizes(MaruCamState *state)
1192 uint32_t index, pixfmt, i;
1193 MaruCamParam *param = state->param;
1196 index = param->stack[0];
1197 pixfmt = param->stack[1];
1199 if (index >= ARRAY_SIZE(supported_dst_frames)) {
1200 param->errCode = EINVAL;
1203 for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
1204 if (supported_dst_pixfmts[i].fmt == pixfmt) {
1209 if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
1210 param->errCode = EINVAL;
1214 param->stack[0] = supported_dst_frames[index].width;
1215 param->stack[1] = supported_dst_frames[index].height;
1218 void marucam_device_enum_fintv(MaruCamState *state)
1220 MaruCamParam *param = state->param;
1224 /* switch by index(param->stack[0]) */
1225 switch (param->stack[0]) {
1227 /* we only use 1/30 frame interval */
1228 param->stack[1] = 30; /* denominator */
1231 param->errCode = EINVAL;
1234 param->stack[0] = 1; /* numerator */
1237 void marucam_device_close(MaruCamState *state)
1239 if (!is_stream_paused(state)) {
1240 marucam_device_stop_preview(state);
1243 marucam_reset_controls();
1245 v4l2_close(v4l2_fd);