update source for tizen_2.1
[sdk/emulator/qemu.git] / tizen / src / hw / maru_camera_darwin_pci.m
1 /*
2  * Implementation of MARU Virtual Camera device by PCI bus on MacOS.
3  *
4  * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
5  *
6  * Contact:
7  * Jun Tian <jun.j.tian@intel.com>
8  * JinHyung Jo <jinhyung.jo@samsung.com>
9  * YeongKyoon Lee <yeongkyoon.lee@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,
24  * MA  02110-1301, USA.
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  *
29  */
30
31 #import <Cocoa/Cocoa.h>
32 #import <QTKit/QTKit.h>
33 #import <CoreAudio/CoreAudio.h>
34
35 #include <pthread.h>
36 #include "qemu-common.h"
37 #include "maru_camera_common.h"
38 #include "maru_camera_darwin.h"
39 #include "pci.h"
40 #include "tizen/src/debug_ch.h"
41
42 MULTI_DEBUG_CHANNEL(tizen, camera_darwin);
43
44 /* V4L2 defines copy from videodev2.h */
45 #define V4L2_CTRL_FLAG_SLIDER       0x0020
46
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)
53
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;
59
60
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 },
66 };
67
68 typedef struct tagMaruCamConvertFrameInfo {
69     uint32_t width;
70     uint32_t height;
71 } MaruCamConvertFrameInfo;
72
73 static MaruCamConvertFrameInfo supported_dst_frames[] = {
74     { 640, 480 },
75     { 352, 288 },
76     { 320, 240 },
77     { 176, 144 },
78     { 160, 120 },
79 };
80
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
85
86 enum {
87     _MC_THREAD_PAUSED,
88     _MC_THREAD_STREAMON,
89     _MC_THREAD_STREAMOFF,
90 };
91
92 #if 0
93 struct marucam_qctrl {
94     uint32_t id;
95     uint32_t hit;
96     long min;
97     long max;
98     long step;
99     long init_val;
100 };
101
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, },
107 };
108 #endif
109
110 static MaruCamState *g_state;
111
112 static uint32_t ready_count;
113 static uint32_t cur_fmt_idx;
114 static uint32_t cur_frame_idx;
115
116 /***********************************
117  * Mac camera helper functions
118  ***********************************/
119
120 /* Convert Core Video format to FOURCC */
121 static uint32_t corevideo_to_fourcc(uint32_t cv_pix_fmt)
122 {
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;
140     default:
141         ERR("Unknown pixel format '%.4s'", (const char *)&cv_pix_fmt);
142         return 0;
143     }
144 }
145
146 static uint32_t get_bytesperline(uint32_t pixfmt, uint32_t width)
147 {
148     uint32_t bytesperline;
149
150     switch (pixfmt) {
151     case V4L2_PIX_FMT_YUV420:
152     case V4L2_PIX_FMT_YVU420:
153         bytesperline = (width * 12) >> 3;
154         break;
155     case V4L2_PIX_FMT_YUYV:
156     case V4L2_PIX_FMT_UYVY:
157     default:
158         bytesperline = width * 2;
159         break;
160     }
161
162     return bytesperline;
163 }
164
165 static uint32_t get_sizeimage(uint32_t pixfmt, uint32_t width, uint32_t height)
166 {
167     return get_bytesperline(pixfmt, width) * height;
168 }
169
170 /******************************************************************
171  **   Maru Camera Implementation
172  *****************************************************************/
173
174 @interface MaruCameraDriver : NSObject {
175     QTCaptureSession               *mCaptureSession;
176     QTCaptureDeviceInput           *mCaptureVideoDeviceInput;
177     QTCaptureVideoPreviewOutput    *mCaptureVideoPreviewOutput;
178
179     CVImageBufferRef               mCurrentImageBuffer;
180     BOOL mDeviceIsOpened;
181     BOOL mCaptureIsStarted;
182 }
183
184 - (MaruCameraDriver *)init;
185 - (int)startCapture:(int)width:(int)height;
186 - (void)stopCapture;
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;
191
192 @end
193
194 @implementation MaruCameraDriver
195
196 - (MaruCameraDriver *)init
197 {
198     BOOL success = NO;
199     NSError *error;
200     mDeviceIsOpened = NO;
201     mCaptureIsStarted = NO;
202     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
203
204     /* Create the capture session */
205     mCaptureSession = [[QTCaptureSession alloc] init];
206
207     /* Find a video device */
208     QTCaptureDevice *videoDevice = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo];
209     success = [videoDevice open:&error];
210
211     /* If a video input device can't be found or opened, try to find and open a muxed input device */
212     if (!success) {
213         videoDevice = [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeMuxed];
214         success = [videoDevice open:&error];
215         [pool release];
216         return nil;
217     }
218
219     if (!success) {
220         videoDevice = nil;
221         [pool release];
222         return nil;
223     }
224
225     if (videoDevice) {
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];
229
230         if (!success) {
231             [pool release];
232             return nil;
233         }
234
235         mCaptureVideoPreviewOutput = [[QTCaptureVideoPreviewOutput alloc] init];
236         success = [mCaptureSession addOutput:mCaptureVideoPreviewOutput error:&error];
237         if (!success) {
238             [pool release];
239             return nil;
240         }
241
242         mDeviceIsOpened = YES;
243         [mCaptureVideoPreviewOutput setDelegate:self];
244         INFO("Camera session bundling successfully!\n");
245         [pool release];
246         return self;
247     } else {
248         [pool release];
249         return nil;
250     }
251 }
252
253 - (int)startCapture:(int)width:(int)height
254 {
255     int ret = -1;
256
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,
262                                                  nil];
263         [mCaptureVideoPreviewOutput setPixelBufferAttributes:attributes];
264         [mCaptureSession startRunning];
265     } else {
266         ERR("Capture session is already running, exit\n");
267         return ret;
268     }
269
270     if ([mCaptureSession isRunning]) {
271         while(!mCaptureIsStarted) {
272             /* Wait Until Capture is started */
273             [[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.5]];
274         }
275         ret = 0;
276     }
277     return ret;
278 }
279
280 - (void)stopCapture
281 {
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]];
287         }
288
289     }
290     mCaptureIsStarted = NO;
291 }
292
293 - (int)readFrame:(void *)video_buf
294 {
295     NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
296
297     @synchronized (self) {
298         if (mCaptureIsStarted == NO) {
299             [pool release];
300             return 0;
301         }
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);
309
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);
315
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);
320             [pool release];
321             return 1;
322         }
323     }
324
325     [pool release];
326     return -1;
327 }
328
329 - (int)setCaptureFormat:(int)width:(int)height:(int)pix_format
330 {
331     int ret = -1;
332     NSDictionary *attributes;
333
334     if (mCaptureSession == nil || mCaptureVideoPreviewOutput == nil) {
335         ERR("Capture session is not initiated.\n");
336         return ret;
337     }
338
339     /* Set the pixel buffer attributes before running the capture session */
340     if (![mCaptureSession isRunning]) {
341         if (pix_format) {
342             attributes = [NSDictionary dictionaryWithObjectsAndKeys:
343                                             [NSNumber numberWithInt: width], (id)kCVPixelBufferWidthKey,
344                                             [NSNumber numberWithInt: height], (id)kCVPixelBufferHeightKey,
345                                             [NSNumber numberWithInt: pix_format], (id)kCVPixelBufferPixelFormatTypeKey,
346                                        nil];
347         } else {
348             attributes = [NSDictionary dictionaryWithObjectsAndKeys:
349                                             [NSNumber numberWithInt: width], (id)kCVPixelBufferWidthKey,
350                                             [NSNumber numberWithInt: height], (id)kCVPixelBufferHeightKey,
351                                        nil];
352         }
353         [mCaptureVideoPreviewOutput setPixelBufferAttributes:attributes];
354         ret = 0;
355     } else {
356         ERR("Cannot set pixel buffer attributes when it's running.\n");
357         return ret;
358     }
359
360     return ret;
361 }
362
363 - (int)getCaptureFormat:(int)width:(int)height:(int)pix_format
364 {
365     return 0;
366 }
367
368 /* Get the device bundling status */
369 - (BOOL)deviceStatus
370 {
371     return mDeviceIsOpened;
372 }
373
374 /* Handle deallocation of memory for your capture objects */
375
376 - (void)dealloc
377 {
378     [mCaptureSession release];
379     [mCaptureVideoDeviceInput release];
380     [mCaptureVideoPreviewOutput release];
381     [super dealloc];
382 }
383
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
387 {
388     CVImageBufferRef imageBufferToRelease;
389     CVBufferRetain(videoFrame);
390
391     @synchronized (self)
392     {
393         imageBufferToRelease = mCurrentImageBuffer;
394         mCurrentImageBuffer = videoFrame;
395         mCaptureIsStarted = YES;
396     }
397     CVBufferRelease(imageBufferToRelease);
398 }
399
400 @end
401
402 /******************************************************************
403  **   Maru Camera APIs
404  *****************************************************************/
405
406 typedef struct MaruCameraDevice MaruCameraDevice;
407 struct MaruCameraDevice {
408     /* Maru camera device object. */
409     MaruCameraDriver *driver;
410 };
411
412 /* Golbal representation of the Maru camera */
413 MaruCameraDevice *mcd = NULL;
414
415 static int is_streamon()
416 {
417     int st;
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);
422 }
423
424 static void __raise_err_intr()
425 {
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);
431     }
432     qemu_mutex_unlock(&g_state->thread_mutex);
433 }
434
435 static int marucam_device_read_frame()
436 {
437     int ret;
438     void *tmp_buf;
439
440     qemu_mutex_lock(&g_state->thread_mutex);
441     if (g_state->streamon == _MC_THREAD_STREAMON) {
442 #if 0
443         if (ready_count < MARUCAM_SKIPFRAMES) {
444             /* skip a frame cause first some frame are distorted */
445             ++ready_count;
446             TRACE("Skip %d frame\n", ready_count);
447             qemu_mutex_unlock(&g_state->thread_mutex);
448             return 0;
449         }
450 #endif
451         if (g_state->req_frame == 0) {
452             TRACE("There is no request\n");
453             qemu_mutex_unlock(&g_state->thread_mutex);
454             return 0;
455         }
456
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];
460         if (ret < 0) {
461             ERR("%s, Capture error\n", __func__);
462             qemu_mutex_unlock(&g_state->thread_mutex);
463             __raise_err_intr();
464             return -1;
465         } else if (!ret) {
466             qemu_mutex_unlock(&g_state->thread_mutex);
467             return 0;
468         }
469
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);
473     } else {
474         qemu_mutex_unlock(&g_state->thread_mutex);
475         return -1;
476     }
477     qemu_mutex_unlock(&g_state->thread_mutex);
478     return 0;
479 }
480
481 /* Worker thread to grab frames to the preview window */
482 static void *marucam_worker_thread(void *thread_param)
483 {
484     while (1) {
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);
489
490         if (g_state->destroying) {
491             break;
492         }
493
494         ready_count = 0;
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");
499
500         /* Loop: capture frame -> convert format -> render to screen */
501         while (1) {
502             if (is_streamon()) {
503                 if (marucam_device_read_frame() < 0) {
504                     INFO("Streaming is off ...\n");
505                     break;
506                 } else {
507                     /* wait until next frame is avalilable */
508                     usleep(22000);
509                 }
510             } else {
511                 INFO("Streaming is off ...\n");
512                 break;
513             }
514         }
515     }
516
517     return NULL;
518 }
519
520 int marucam_device_check(int log_flag)
521 {
522     /* FIXME: check the device parameters */
523     INFO("Checking camera device\n");
524     return 1;
525 }
526
527 /**********************************************
528  * MARU camera routines
529  **********************************************/
530
531 void marucam_device_init(MaruCamState *state)
532 {
533     g_state = state;
534     g_state->destroying = false;
535     qemu_thread_create(&state->thread_id, marucam_worker_thread,
536                        NULL, QEMU_THREAD_JOINABLE);
537 }
538
539 void marucam_device_exit(MaruCamState *state)
540 {
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);
546 }
547
548 /* MARUCAM_CMD_OPEN */
549 void marucam_device_open(MaruCamState *state)
550 {
551     MaruCamParam *param = state->param;
552     param->top = 0;
553
554     mcd = (MaruCameraDevice *)malloc(sizeof(MaruCameraDevice));
555     if (mcd == NULL) {
556         ERR("%s: MaruCameraDevice allocate failed\n", __func__);
557         param->errCode = EINVAL;
558         return;
559     }
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];
565         free(mcd);
566         param->errCode = EINVAL;
567         return;
568     }
569     INFO("Camera opened!\n");
570 }
571
572 /* MARUCAM_CMD_CLOSE */
573 void marucam_device_close(MaruCamState *state)
574 {
575     MaruCamParam *param = state->param;
576     param->top = 0;
577
578     if (mcd != NULL) {
579         [mcd->driver dealloc];
580         free(mcd);
581     }
582
583     /* marucam_reset_controls(); */
584     INFO("Camera closed\n");
585 }
586
587 /* MARUCAM_CMD_START_PREVIEW */
588 void marucam_device_start_preview(MaruCamState *state)
589 {
590     uint32_t width, height, pixfmt;
591     MaruCamParam *param = state->param;
592     param->top = 0;
593
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);
598
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);
604
605     if (mcd->driver == nil) {
606         ERR("%s: Start capture failed: vaild device", __func__);
607         param->errCode = EINVAL;
608         return;
609     }
610     
611     INFO("Starting preview ...\n");
612     [mcd->driver startCapture: width: height];
613
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);
618
619     while (!is_streamon()) {
620         usleep(10000);
621     }
622 }
623
624 /* MARUCAM_CMD_STOP_PREVIEW */
625 void marucam_device_stop_preview(MaruCamState *state)
626 {
627     MaruCamParam *param = state->param;
628     param->top = 0;
629
630     if (is_streamon()) {
631         qemu_mutex_lock(&state->thread_mutex);
632         state->streamon = _MC_THREAD_STREAMOFF;
633         qemu_mutex_unlock(&state->thread_mutex);
634
635         while (is_streamon()) {
636             usleep(10000);
637         }
638     }
639
640     if (mcd->driver != nil) {
641         [mcd->driver stopCapture];
642     }
643
644     state->buf_size = 0;
645     INFO("Stopping preview ...\n");
646 }
647
648 /* MARUCAM_CMD_S_PARAM */
649 void marucam_device_s_param(MaruCamState *state)
650 {
651     MaruCamParam *param = state->param;
652
653     /* We use default FPS of the webcam */
654     param->top = 0;
655 }
656
657 /* MARUCAM_CMD_G_PARAM */
658 void marucam_device_g_param(MaruCamState *state)
659 {
660     MaruCamParam *param = state->param;
661     /* We use default FPS of the webcam
662      * return a fixed value on guest ini file (1/30).
663      */
664     param->top = 0;
665     param->stack[0] = 0x1000; /* V4L2_CAP_TIMEPERFRAME */
666     param->stack[1] = 1; /* numerator */
667     param->stack[2] = 30; /* denominator */
668 }
669
670 /* MARUCAM_CMD_S_FMT */
671 void marucam_device_s_fmt(MaruCamState *state)
672 {
673     MaruCamParam *param = state->param;
674     uint32_t width, height, pixfmt, pidx, fidx;
675
676     param->top = 0;
677     width = param->stack[0];
678     height = param->stack[1];
679     pixfmt = param->stack[2];
680
681     TRACE("Set format: width(%d), height(%d), pixfmt(%d, %.4s)\n",
682          width, height, pixfmt, (const char*)&pixfmt);
683
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)) {
687             break;
688         }
689     }
690     if (fidx == ARRAY_SIZE(supported_dst_frames)) {
691         param->errCode = EINVAL;
692         return;
693     }
694
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);
698             break;
699         }
700     }
701     if (pidx == ARRAY_SIZE(supported_dst_pixfmts)) {
702         param->errCode = EINVAL;
703         return;
704     }
705
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;
711             return;
712         }
713
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);
716     }
717
718     cur_frame_idx = fidx;
719     cur_fmt_idx = pidx;
720
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;
724
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);
731     param->stack[6] = 0;
732     param->stack[7] = 0;
733
734     TRACE("Set device pixel format ...\n");
735 }
736
737 /* MARUCAM_CMD_G_FMT */
738 void marucam_device_g_fmt(MaruCamState *state)
739 {
740     uint32_t width, height, pixfmt;
741     MaruCamParam *param = state->param;
742
743     param->top = 0;
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;
747
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);
754     param->stack[6] = 0;
755     param->stack[7] = 0;
756
757     TRACE("Get device frame format ...\n");
758 }
759
760 void marucam_device_try_fmt(MaruCamState *state)
761 {
762     TRACE("Try device frame format, use default setting ...\n");
763 }
764
765 /* Get specific pixelformat description */
766 void marucam_device_enum_fmt(MaruCamState *state)
767 {
768     uint32_t index;
769     MaruCamParam *param = state->param;
770
771     param->top = 0;
772     index = param->stack[0];
773
774     if (index >= ARRAY_SIZE(supported_dst_pixfmts)) {
775         param->errCode = EINVAL;
776         return;
777     }
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(&param->stack[3], "YUYV", 32);
783         break;
784     case V4L2_PIX_FMT_UYVY:
785         memcpy(&param->stack[3], "UYVY", 32);
786         break;
787     case V4L2_PIX_FMT_YUV420:
788         memcpy(&param->stack[3], "YU12", 32);
789         break;
790     case V4L2_PIX_FMT_YVU420:
791         memcpy(&param->stack[3], "YV12", 32);
792         break;
793     default:
794         param->errCode = EINVAL;
795         break;
796     }
797 }
798
799 /*
800  * QTKit don't support setting brightness, contrast, saturation & sharpness
801  */
802 void marucam_device_qctrl(MaruCamState *state)
803 {
804     uint32_t id, i;
805     /* long property, min, max, step, def_val, set_val; */
806     char name[32] = {0,};
807     MaruCamParam *param = state->param;
808
809     param->top = 0;
810     id = param->stack[0];
811
812     switch (id) {
813     case V4L2_CID_BRIGHTNESS:
814         TRACE("V4L2_CID_BRIGHTNESS\n");
815         memcpy((void *)name, (void *)"brightness", 32);
816         i = 0;
817         break;
818     case V4L2_CID_CONTRAST:
819         TRACE("V4L2_CID_CONTRAST\n");
820         memcpy((void *)name, (void *)"contrast", 32);
821         i = 1;
822         break;
823     case V4L2_CID_SATURATION:
824         TRACE("V4L2_CID_SATURATION\n");
825         memcpy((void *)name, (void *)"saturation", 32);
826         i = 2;
827         break;
828     case V4L2_CID_SHARPNESS:
829         TRACE("V4L2_CID_SHARPNESS\n");
830         memcpy((void *)name, (void *)"sharpness", 32);
831         i = 3;
832         break;
833     default:
834         param->errCode = EINVAL;
835         return;
836     }
837
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(&param->stack[6], (void *)name, sizeof(name)/sizeof(name[0]));
846 }
847
848 void marucam_device_s_ctrl(MaruCamState *state)
849 {
850     INFO("Set control\n");
851 }
852
853 void marucam_device_g_ctrl(MaruCamState *state)
854 {
855     INFO("Get control\n");
856 }
857
858 /* Get frame width & height */
859 void marucam_device_enum_fsizes(MaruCamState *state)
860 {
861     uint32_t index, pixfmt, i;
862     MaruCamParam *param = state->param;
863
864     param->top = 0;
865     index = param->stack[0];
866     pixfmt = param->stack[1];
867
868     if (index >= ARRAY_SIZE(supported_dst_frames)) {
869         param->errCode = EINVAL;
870         return;
871     }
872     for (i = 0; i < ARRAY_SIZE(supported_dst_pixfmts); i++) {
873         if (supported_dst_pixfmts[i].fmt == pixfmt) {
874             break;
875         }
876     }
877
878     if (i == ARRAY_SIZE(supported_dst_pixfmts)) {
879         param->errCode = EINVAL;
880         return;
881     }
882
883     param->stack[0] = supported_dst_frames[index].width;
884     param->stack[1] = supported_dst_frames[index].height;
885 }
886
887 void marucam_device_enum_fintv(MaruCamState *state)
888 {
889     MaruCamParam *param = state->param;
890     param->top = 0;
891
892     /* switch by index(param->stack[0]) */
893     switch (param->stack[0]) {
894     case 0:
895         param->stack[1] = 30; /* denominator */
896         break;
897     default:
898         param->errCode = EINVAL;
899         return;
900     }
901     param->stack[0] = 1; /* numerator */
902 }