2 * Implementation of MARU Virtual Camera device by PCI bus on MacOS.
4 * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
7 * Jun Tian <jun.j.tian@intel.com>
8 * JinHyung Jo <jinhyung.jo@samsung.com>
9 * YeongKyoon Lee <yeongkyoon.lee@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,
31 #import <Cocoa/Cocoa.h>
32 #import <QTKit/QTKit.h>
33 #import <CoreAudio/CoreAudio.h>
36 #include "qemu-common.h"
37 #include "maru_camera_common.h"
38 #include "maru_camera_darwin.h"
40 #include "tizen/src/debug_ch.h"
42 MULTI_DEBUG_CHANNEL(tizen, camera_darwin);
44 /* V4L2 defines copy from videodev2.h */
45 #define V4L2_CTRL_FLAG_SLIDER 0x0020
47 #define V4L2_CTRL_CLASS_USER 0x00980000
48 #define V4L2_CID_BASE (V4L2_CTRL_CLASS_USER | 0x900)
49 #define V4L2_CID_BRIGHTNESS (V4L2_CID_BASE + 0)
50 #define V4L2_CID_CONTRAST (V4L2_CID_BASE + 1)
51 #define V4L2_CID_SATURATION (V4L2_CID_BASE + 2)
52 #define V4L2_CID_SHARPNESS (V4L2_CID_BASE + 27)
54 typedef struct tagMaruCamConvertPixfmt {
55 uint32_t fmt; /* fourcc */
56 uint32_t bpp; /* bits per pixel, 0 for compressed formats */
57 uint32_t needs_conversion;
58 } MaruCamConvertPixfmt;
61 static MaruCamConvertPixfmt supported_dst_pixfmts[] = {
62 { V4L2_PIX_FMT_YUYV, 16, 0 },
63 { V4L2_PIX_FMT_UYVY, 16, 0 },
64 { V4L2_PIX_FMT_YUV420, 12, 0 },
65 { V4L2_PIX_FMT_YVU420, 12, 0 },
68 typedef struct tagMaruCamConvertFrameInfo {
71 } MaruCamConvertFrameInfo;
73 static MaruCamConvertFrameInfo supported_dst_frames[] = {
81 #define MARUCAM_CTRL_VALUE_MAX 20
82 #define MARUCAM_CTRL_VALUE_MIN 1
83 #define MARUCAM_CTRL_VALUE_MID 10
84 #define MARUCAM_CTRL_VALUE_STEP 1
93 struct marucam_qctrl {
102 static struct marucam_qctrl qctrl_tbl[] = {
103 { V4L2_CID_BRIGHTNESS, 0, },
104 { V4L2_CID_CONTRAST, 0, },
105 { V4L2_CID_SATURATION, 0, },
106 { V4L2_CID_SHARPNESS, 0, },
110 static MaruCamState *g_state;
112 static uint32_t ready_count;
113 static uint32_t cur_fmt_idx;
114 static uint32_t cur_frame_idx;
116 /***********************************
117 * Mac camera helper functions
118 ***********************************/
120 /* Convert Core Video format to FOURCC */
121 static uint32_t corevideo_to_fourcc(uint32_t cv_pix_fmt)
123 switch (cv_pix_fmt) {
124 case kCVPixelFormatType_420YpCbCr8Planar:
125 return V4L2_PIX_FMT_YVU420;
126 case kCVPixelFormatType_422YpCbCr8:
127 return V4L2_PIX_FMT_UYVY;
128 case kCVPixelFormatType_422YpCbCr8_yuvs:
129 return V4L2_PIX_FMT_YUYV;
130 case kCVPixelFormatType_32ARGB:
131 case kCVPixelFormatType_32RGBA:
132 return V4L2_PIX_FMT_RGB32;
133 case kCVPixelFormatType_32BGRA:
134 case kCVPixelFormatType_32ABGR:
135 return V4L2_PIX_FMT_BGR32;
136 case kCVPixelFormatType_24RGB:
137 return V4L2_PIX_FMT_RGB24;
138 case kCVPixelFormatType_24BGR:
139 return V4L2_PIX_FMT_BGR32;
141 ERR("Unknown pixel format '%.4s'", (const char *)&cv_pix_fmt);
146 static uint32_t get_bytesperline(uint32_t pixfmt, uint32_t width)
148 uint32_t bytesperline;
151 case V4L2_PIX_FMT_YUV420:
152 case V4L2_PIX_FMT_YVU420:
153 bytesperline = (width * 12) >> 3;
155 case V4L2_PIX_FMT_YUYV:
156 case V4L2_PIX_FMT_UYVY:
158 bytesperline = width * 2;
165 static uint32_t get_sizeimage(uint32_t pixfmt, uint32_t width, uint32_t height)
167 return get_bytesperline(pixfmt, width) * height;
170 /******************************************************************
171 ** Maru Camera Implementation
172 *****************************************************************/
174 @interface MaruCameraDriver : NSObject {
175 QTCaptureSession *mCaptureSession;
176 QTCaptureDeviceInput *mCaptureVideoDeviceInput;
177 QTCaptureVideoPreviewOutput *mCaptureVideoPreviewOutput;
179 CVImageBufferRef mCurrentImageBuffer;
180 BOOL mDeviceIsOpened;
181 BOOL mCaptureIsStarted;
184 - (MaruCameraDriver *)init;
185 - (int)startCapture:(int)width:(int)height;
187 - (int)readFrame:(void *)video_buf;
188 - (int)setCaptureFormat:(int)width:(int)height:(int)pix_format;
189 - (int)getCaptureFormat:(int)width:(int)height:(int)pix_format;
190 - (BOOL)deviceStatus;
194 @implementation MaruCameraDriver
196 - (MaruCameraDriver *)init
200 mDeviceIsOpened = NO;
201 mCaptureIsStarted = NO;
202 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
204 /* Create the capture session */
205 mCaptureSession = [[QTCaptureSession alloc] init];
207 /* Find a video device */
208 QTCaptureDevice *videoDevice = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo];
209 success = [videoDevice open:&error];
211 /* If a video input device can't be found or opened, try to find and open a muxed input device */
213 videoDevice = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeMuxed];
214 success = [videoDevice open:&error];
226 /* Add the video device to the session as a device input */
227 mCaptureVideoDeviceInput = [[QTCaptureDeviceInput alloc] initWithDevice:videoDevice];
228 success = [mCaptureSession addInput:mCaptureVideoDeviceInput error:&error];
235 mCaptureVideoPreviewOutput = [[QTCaptureVideoPreviewOutput alloc] init];
236 success = [mCaptureSession addOutput:mCaptureVideoPreviewOutput error:&error];
242 mDeviceIsOpened = YES;
243 [mCaptureVideoPreviewOutput setDelegate:self];
244 INFO("Camera session bundling successfully!\n");
253 - (int)startCapture:(int)width:(int)height
257 if (![mCaptureSession isRunning]) {
258 /* Set width & height, using default pixel format to capture */
259 NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys:
260 [NSNumber numberWithInt: width], (id)kCVPixelBufferWidthKey,
261 [NSNumber numberWithInt: height], (id)kCVPixelBufferHeightKey,
263 [mCaptureVideoPreviewOutput setPixelBufferAttributes:attributes];
264 [mCaptureSession startRunning];
266 ERR("Capture session is already running, exit\n");
270 if ([mCaptureSession isRunning]) {
271 while(!mCaptureIsStarted) {
272 /* Wait Until Capture is started */
273 [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.5]];
282 if ([mCaptureSession isRunning]) {
283 [mCaptureSession stopRunning];
284 while([mCaptureSession isRunning]) {
285 /* Wait Until Capture is stopped */
286 [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.1]];
290 mCaptureIsStarted = NO;
293 - (int)readFrame:(void *)video_buf
295 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
297 @synchronized (self) {
298 if (mCaptureIsStarted == NO) {
302 if (mCurrentImageBuffer != nil) {
303 CVPixelBufferLockBaseAddress(mCurrentImageBuffer, 0);
304 const uint32_t pixel_format = corevideo_to_fourcc(CVPixelBufferGetPixelFormatType(mCurrentImageBuffer));
305 const int frame_width = CVPixelBufferGetWidth(mCurrentImageBuffer);
306 const int frame_height = CVPixelBufferGetHeight(mCurrentImageBuffer);
307 const size_t frame_size = CVPixelBufferGetBytesPerRow(mCurrentImageBuffer) * frame_height;
308 const void *frame_pixels = CVPixelBufferGetBaseAddress(mCurrentImageBuffer);
310 TRACE("buffer(%p), pixel_format(%d,%.4s), frame_width(%d), "
311 "frame_height(%d), frame_size(%d)\n",
312 mCurrentImageBuffer, (int)pixel_format,
313 (const char *)&pixel_format, frame_width,
314 frame_height, (int)frame_size);
316 /* convert frame to v4l2 format */
317 convert_frame(pixel_format, frame_width, frame_height,
318 frame_size, (void *)frame_pixels, video_buf);
319 CVPixelBufferUnlockBaseAddress(mCurrentImageBuffer, 0);
329 - (int)setCaptureFormat:(int)width:(int)height:(int)pix_format
332 NSDictionary *attributes;
334 if (mCaptureSession == nil || mCaptureVideoPreviewOutput == nil) {
335 ERR("Capture session is not initiated.\n");
339 /* Set the pixel buffer attributes before running the capture session */
340 if (![mCaptureSession isRunning]) {
342 attributes = [NSDictionary dictionaryWithObjectsAndKeys:
343 [NSNumber numberWithInt: width], (id)kCVPixelBufferWidthKey,
344 [NSNumber numberWithInt: height], (id)kCVPixelBufferHeightKey,
345 [NSNumber numberWithInt: pix_format], (id)kCVPixelBufferPixelFormatTypeKey,
348 attributes = [NSDictionary dictionaryWithObjectsAndKeys:
349 [NSNumber numberWithInt: width], (id)kCVPixelBufferWidthKey,
350 [NSNumber numberWithInt: height], (id)kCVPixelBufferHeightKey,
353 [mCaptureVideoPreviewOutput setPixelBufferAttributes:attributes];
356 ERR("Cannot set pixel buffer attributes when it's running.\n");
363 - (int)getCaptureFormat:(int)width:(int)height:(int)pix_format
368 /* Get the device bundling status */
371 return mDeviceIsOpened;
374 /* Handle deallocation of memory for your capture objects */
378 [mCaptureSession release];
379 [mCaptureVideoDeviceInput release];
380 [mCaptureVideoPreviewOutput release];
384 /* Receive this method whenever the output decompresses and outputs a new video frame */
385 - (void)captureOutput:(QTCaptureOutput *)captureOutput didOutputVideoFrame:(CVImageBufferRef)videoFrame
386 withSampleBuffer:(QTSampleBuffer *)sampleBuffer fromConnection:(QTCaptureConnection *)connection
388 CVImageBufferRef imageBufferToRelease;
389 CVBufferRetain(videoFrame);
393 imageBufferToRelease = mCurrentImageBuffer;
394 mCurrentImageBuffer = videoFrame;
395 mCaptureIsStarted = YES;
397 CVBufferRelease(imageBufferToRelease);
402 /******************************************************************
404 *****************************************************************/
406 typedef struct MaruCameraDevice MaruCameraDevice;
407 struct MaruCameraDevice {
408 /* Maru camera device object. */
409 MaruCameraDriver *driver;
412 /* Golbal representation of the Maru camera */
413 MaruCameraDevice *mcd = NULL;
415 static int is_streamon()
418 qemu_mutex_lock(&g_state->thread_mutex);
419 st = g_state->streamon;
420 qemu_mutex_unlock(&g_state->thread_mutex);
421 return (st == _MC_THREAD_STREAMON);
424 static void __raise_err_intr()
426 qemu_mutex_lock(&g_state->thread_mutex);
427 if (g_state->streamon == _MC_THREAD_STREAMON) {
428 g_state->req_frame = 0; /* clear request */
429 g_state->isr = 0x08; /* set a error flag of rasing a interrupt */
430 qemu_bh_schedule(g_state->tx_bh);
432 qemu_mutex_unlock(&g_state->thread_mutex);
435 static int marucam_device_read_frame()
440 qemu_mutex_lock(&g_state->thread_mutex);
441 if (g_state->streamon == _MC_THREAD_STREAMON) {
443 if (ready_count < MARUCAM_SKIPFRAMES) {
444 /* skip a frame cause first some frame are distorted */
446 TRACE("Skip %d frame\n", ready_count);
447 qemu_mutex_unlock(&g_state->thread_mutex);
451 if (g_state->req_frame == 0) {
452 TRACE("There is no request\n");
453 qemu_mutex_unlock(&g_state->thread_mutex);
457 /* Grab the camera frame into temp buffer */
458 tmp_buf = g_state->vaddr + g_state->buf_size * (g_state->req_frame - 1);
459 ret = [mcd->driver readFrame: tmp_buf];
461 ERR("%s, Capture error\n", __func__);
462 qemu_mutex_unlock(&g_state->thread_mutex);
466 qemu_mutex_unlock(&g_state->thread_mutex);
470 g_state->req_frame = 0; /* clear request */
471 g_state->isr |= 0x01; /* set a flag of rasing a interrupt */
472 qemu_bh_schedule(g_state->tx_bh);
474 qemu_mutex_unlock(&g_state->thread_mutex);
477 qemu_mutex_unlock(&g_state->thread_mutex);
481 /* Worker thread to grab frames to the preview window */
482 static void *marucam_worker_thread(void *thread_param)
485 qemu_mutex_lock(&g_state->thread_mutex);
486 g_state->streamon = _MC_THREAD_PAUSED;
487 qemu_cond_wait(&g_state->thread_cond, &g_state->thread_mutex);
488 qemu_mutex_unlock(&g_state->thread_mutex);
490 if (g_state->destroying) {
495 qemu_mutex_lock(&g_state->thread_mutex);
496 g_state->streamon = _MC_THREAD_STREAMON;
497 qemu_mutex_unlock(&g_state->thread_mutex);
498 INFO("Streaming on ......\n");
500 /* Loop: capture frame -> convert format -> render to screen */
503 if (marucam_device_read_frame() < 0) {
504 INFO("Streaming is off ...\n");
507 /* wait until next frame is avalilable */
511 INFO("Streaming is off ...\n");
520 int marucam_device_check(int log_flag)
522 /* FIXME: check the device parameters */
523 INFO("Checking camera device\n");
527 /**********************************************
528 * MARU camera routines
529 **********************************************/
531 void marucam_device_init(MaruCamState *state)
534 g_state->destroying = false;
535 qemu_thread_create(&state->thread_id, marucam_worker_thread,
536 NULL, QEMU_THREAD_JOINABLE);
539 void marucam_device_exit(MaruCamState *state)
541 state->destroying = true;
542 qemu_mutex_lock(&state->thread_mutex);
543 qemu_cond_signal(&state->thread_cond);
544 qemu_mutex_unlock(&state->thread_mutex);
545 qemu_thread_join(&state->thread_id);
548 /* MARUCAM_CMD_OPEN */
549 void marucam_device_open(MaruCamState *state)
551 MaruCamParam *param = state->param;
554 mcd = (MaruCameraDevice *)malloc(sizeof(MaruCameraDevice));
556 ERR("%s: MaruCameraDevice allocate failed\n", __func__);
557 param->errCode = EINVAL;
560 memset(mcd, 0, sizeof(MaruCameraDevice));
561 mcd->driver = [[MaruCameraDriver alloc] init];
562 if (mcd->driver == nil) {
563 ERR("Camera device open failed\n");
564 [mcd->driver dealloc];
566 param->errCode = EINVAL;
569 INFO("Camera opened!\n");
572 /* MARUCAM_CMD_CLOSE */
573 void marucam_device_close(MaruCamState *state)
575 MaruCamParam *param = state->param;
579 [mcd->driver dealloc];
583 /* marucam_reset_controls(); */
584 INFO("Camera closed\n");
587 /* MARUCAM_CMD_START_PREVIEW */
588 void marucam_device_start_preview(MaruCamState *state)
590 uint32_t width, height, pixfmt;
591 MaruCamParam *param = state->param;
594 width = supported_dst_frames[cur_frame_idx].width;
595 height = supported_dst_frames[cur_frame_idx].height;
596 pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
597 state->buf_size = get_sizeimage(pixfmt, width, height);
599 INFO("Pixfmt(%c%c%c%c), W:H(%d:%d), buf size(%u), frame idx(%d), fmt idx(%d)\n",
600 (char)(pixfmt), (char)(pixfmt >> 8),
601 (char)(pixfmt >> 16), (char)(pixfmt >> 24),
602 width, height, state->buf_size,
603 cur_frame_idx, cur_fmt_idx);
605 if (mcd->driver == nil) {
606 ERR("%s: Start capture failed: vaild device", __func__);
607 param->errCode = EINVAL;
611 INFO("Starting preview ...\n");
612 [mcd->driver startCapture: width: height];
614 /* Enable the condition to capture frames now */
615 qemu_mutex_lock(&state->thread_mutex);
616 qemu_cond_signal(&state->thread_cond);
617 qemu_mutex_unlock(&state->thread_mutex);
619 while (!is_streamon()) {
624 /* MARUCAM_CMD_STOP_PREVIEW */
625 void marucam_device_stop_preview(MaruCamState *state)
627 MaruCamParam *param = state->param;
631 qemu_mutex_lock(&state->thread_mutex);
632 state->streamon = _MC_THREAD_STREAMOFF;
633 qemu_mutex_unlock(&state->thread_mutex);
635 while (is_streamon()) {
640 if (mcd->driver != nil) {
641 [mcd->driver stopCapture];
645 INFO("Stopping preview ...\n");
648 /* MARUCAM_CMD_S_PARAM */
649 void marucam_device_s_param(MaruCamState *state)
651 MaruCamParam *param = state->param;
653 /* We use default FPS of the webcam */
657 /* MARUCAM_CMD_G_PARAM */
658 void marucam_device_g_param(MaruCamState *state)
660 MaruCamParam *param = state->param;
661 /* We use default FPS of the webcam
662 * return a fixed value on guest ini file (1/30).
665 param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */
666 param->stack[1] = 1; /* numerator */
667 param->stack[2] = 30; /* denominator */
670 /* MARUCAM_CMD_S_FMT */
671 void marucam_device_s_fmt(MaruCamState *state)
673 MaruCamParam *param = state->param;
674 uint32_t width, height, pixfmt, pidx, fidx;
677 width = param->stack[0];
678 height = param->stack[1];
679 pixfmt = param->stack[2];
681 TRACE("Set format: width(%d), height(%d), pixfmt(%d, %.4s)\n",
682 width, height, pixfmt, (const char*)&pixfmt);
684 for (fidx = 0; fidx < ARRAY_SIZE(supported_dst_frames); fidx++) {
685 if ((supported_dst_frames[fidx].width == width) &&
686 (supported_dst_frames[fidx].height == height)) {
690 if (fidx == ARRAY_SIZE(supported_dst_frames)) {
691 param->errCode = EINVAL;
695 for (pidx = 0; pidx < ARRAY_SIZE(supported_dst_pixfmts); pidx++) {
696 if (supported_dst_pixfmts[pidx].fmt == pixfmt) {
697 TRACE("pixfmt index is match: %d\n", pidx);
701 if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {
702 param->errCode = EINVAL;
706 if ((supported_dst_frames[cur_frame_idx].width != width) &&
707 (supported_dst_frames[cur_frame_idx].height != height)) {
708 if (mcd->driver == nil || [mcd->driver setCaptureFormat: width: height: 0] < 0) {
709 ERR("Set pixel format failed\n");
710 param->errCode = EINVAL;
714 TRACE("cur_frame_idx:%d, supported_dst_frames[cur_frame_idx].width:%d\n",
715 cur_frame_idx, supported_dst_frames[cur_frame_idx].width);
718 cur_frame_idx = fidx;
721 pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
722 width = supported_dst_frames[cur_frame_idx].width;
723 height = supported_dst_frames[cur_frame_idx].height;
725 param->stack[0] = width;
726 param->stack[1] = height;
727 param->stack[2] = 1; /* V4L2_FIELD_NONE */
728 param->stack[3] = pixfmt;
729 param->stack[4] = get_bytesperline(pixfmt, width);
730 param->stack[5] = get_sizeimage(pixfmt, width, height);
734 TRACE("Set device pixel format ...\n");
737 /* MARUCAM_CMD_G_FMT */
738 void marucam_device_g_fmt(MaruCamState *state)
740 uint32_t width, height, pixfmt;
741 MaruCamParam *param = state->param;
744 pixfmt = supported_dst_pixfmts[cur_fmt_idx].fmt;
745 width = supported_dst_frames[cur_frame_idx].width;
746 height = supported_dst_frames[cur_frame_idx].height;
748 param->stack[0] = width;
749 param->stack[1] = height;
750 param->stack[2] = 1; /* V4L2_FIELD_NONE */
751 param->stack[3] = pixfmt;
752 param->stack[4] = get_bytesperline(pixfmt, width);
753 param->stack[5] = get_sizeimage(pixfmt, width, height);
757 TRACE("Get device frame format ...\n");
760 void marucam_device_try_fmt(MaruCamState *state)
762 TRACE("Try device frame format, use default setting ...\n");
765 /* Get specific pixelformat description */
766 void marucam_device_enum_fmt(MaruCamState *state)
769 MaruCamParam *param = state->param;
772 index = param->stack[0];
774 if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
775 param->errCode = EINVAL;
778 param->stack[1] = 0; /* flags = NONE */
779 param->stack[2] = supported_dst_pixfmts[index].fmt; /* pixelformat */
780 switch (supported_dst_pixfmts[index].fmt) {
781 case V4L2_PIX_FMT_YUYV:
782 memcpy(¶m->stack[3], "YUYV", 32);
784 case V4L2_PIX_FMT_UYVY:
785 memcpy(¶m->stack[3], "UYVY", 32);
787 case V4L2_PIX_FMT_YUV420:
788 memcpy(¶m->stack[3], "YU12", 32);
790 case V4L2_PIX_FMT_YVU420:
791 memcpy(¶m->stack[3], "YV12", 32);
794 param->errCode = EINVAL;
800 * QTKit don't support setting brightness, contrast, saturation & sharpness
802 void marucam_device_qctrl(MaruCamState *state)
805 /* long property, min, max, step, def_val, set_val; */
806 char name[32] = {0,};
807 MaruCamParam *param = state->param;
810 id = param->stack[0];
813 case V4L2_CID_BRIGHTNESS:
814 TRACE("V4L2_CID_BRIGHTNESS\n");
815 memcpy((void *)name, (void *)"brightness", 32);
818 case V4L2_CID_CONTRAST:
819 TRACE("V4L2_CID_CONTRAST\n");
820 memcpy((void *)name, (void *)"contrast", 32);
823 case V4L2_CID_SATURATION:
824 TRACE("V4L2_CID_SATURATION\n");
825 memcpy((void *)name, (void *)"saturation", 32);
828 case V4L2_CID_SHARPNESS:
829 TRACE("V4L2_CID_SHARPNESS\n");
830 memcpy((void *)name, (void *)"sharpness", 32);
834 param->errCode = EINVAL;
838 param->stack[0] = id;
839 param->stack[1] = MARUCAM_CTRL_VALUE_MIN; /* minimum */
840 param->stack[2] = MARUCAM_CTRL_VALUE_MAX; /* maximum */
841 param->stack[3] = MARUCAM_CTRL_VALUE_STEP; /* step */
842 param->stack[4] = MARUCAM_CTRL_VALUE_MID; /* default_value */
843 param->stack[5] = V4L2_CTRL_FLAG_SLIDER;
844 /* name field setting */
845 memcpy(¶m->stack[6], (void *)name, sizeof(name)/sizeof(name[0]));
848 void marucam_device_s_ctrl(MaruCamState *state)
850 INFO("Set control\n");
853 void marucam_device_g_ctrl(MaruCamState *state)
855 INFO("Get control\n");
858 /* Get frame width & height */
859 void marucam_device_enum_fsizes(MaruCamState *state)
861 uint32_t index, pixfmt, i;
862 MaruCamParam *param = state->param;
865 index = param->stack[0];
866 pixfmt = param->stack[1];
868 if (index >= ARRAY_SIZE(supported_dst_frames)) {
869 param->errCode = EINVAL;
872 for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
873 if (supported_dst_pixfmts[i].fmt == pixfmt) {
878 if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
879 param->errCode = EINVAL;
883 param->stack[0] = supported_dst_frames[index].width;
884 param->stack[1] = supported_dst_frames[index].height;
887 void marucam_device_enum_fintv(MaruCamState *state)
889 MaruCamParam *param = state->param;
892 /* switch by index(param->stack[0]) */
893 switch (param->stack[0]) {
895 param->stack[1] = 30; /* denominator */
898 param->errCode = EINVAL;
901 param->stack[0] = 1; /* numerator */