1955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/*
2955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * Copyright (C) 2011 The Android Open Source Project
3955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *
4955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * Licensed under the Apache License, Version 2.0 (the "License");
5955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * you may not use this file except in compliance with the License.
6955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * You may obtain a copy of the License at
7955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *
8955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *      http://www.apache.org/licenses/LICENSE-2.0
9955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *
10955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * Unless required by applicable law or agreed to in writing, software
11955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * distributed under the License is distributed on an "AS IS" BASIS,
12955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * See the License for the specific language governing permissions and
14955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * limitations under the License.
15955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine */
16955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
17955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/*
18955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * Contains code that is used to capture video frames from a camera device
19955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * on Mac. This code uses QTKit API to work with camera devices, and requires
20955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * Mac OS at least 10.5
21955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine */
22955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
23955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine#import <Cocoa/Cocoa.h>
24261c18d69b75388958b8fd9364b9df21003909c3Ji-Hwan Lee#if 0
25261c18d69b75388958b8fd9364b9df21003909c3Ji-Hwan Lee#import <QTKit/QTKit>
26261c18d69b75388958b8fd9364b9df21003909c3Ji-Hwan Lee#else
27261c18d69b75388958b8fd9364b9df21003909c3Ji-Hwan Lee// QTMovieModernizer.h does not compile with current toolchain.
28261c18d69b75388958b8fd9364b9df21003909c3Ji-Hwan Lee// TODO: revert this when toolchain is updated.
29261c18d69b75388958b8fd9364b9df21003909c3Ji-Hwan Lee#import <QTKit/QTCaptureConnection.h>
30261c18d69b75388958b8fd9364b9df21003909c3Ji-Hwan Lee#import <QTKit/QTCaptureDevice.h>
31261c18d69b75388958b8fd9364b9df21003909c3Ji-Hwan Lee#import <QTKit/QTCaptureDeviceInput.h>
32261c18d69b75388958b8fd9364b9df21003909c3Ji-Hwan Lee#import <QTKit/QTCaptureSession.h>
33261c18d69b75388958b8fd9364b9df21003909c3Ji-Hwan Lee#import <QTKit/QTCaptureVideoPreviewOutput.h>
34261c18d69b75388958b8fd9364b9df21003909c3Ji-Hwan Lee#import <QTKit/QTMedia.h>
35261c18d69b75388958b8fd9364b9df21003909c3Ji-Hwan Lee#import <QTKit/QTSampleBuffer.h>
36261c18d69b75388958b8fd9364b9df21003909c3Ji-Hwan Lee#endif
37955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine#import <CoreAudio/CoreAudio.h>
38955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine#include "android/camera/camera-capture.h"
39955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine#include "android/camera/camera-format-converters.h"
40955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
41955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine#define  E(...)    derror(__VA_ARGS__)
42955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine#define  W(...)    dwarning(__VA_ARGS__)
43955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine#define  D(...)    VERBOSE_PRINT(camera,__VA_ARGS__)
44955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
45955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/*******************************************************************************
46955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *                     Helper routines
47955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine ******************************************************************************/
48955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
49955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/* Converts internal QT pixel format to a FOURCC value. */
50955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkinestatic uint32_t
51955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine_QTtoFOURCC(uint32_t qt_pix_format)
52955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
53955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine  switch (qt_pix_format) {
54955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    case kCVPixelFormatType_24RGB:
55955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine      return V4L2_PIX_FMT_RGB24;
56955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
57955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    case kCVPixelFormatType_24BGR:
58955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine      return V4L2_PIX_FMT_BGR32;
59955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
60955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    case kCVPixelFormatType_32ARGB:
61955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    case kCVPixelFormatType_32RGBA:
62955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine      return V4L2_PIX_FMT_RGB32;
63955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
64955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    case kCVPixelFormatType_32BGRA:
65955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    case kCVPixelFormatType_32ABGR:
66955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine      return V4L2_PIX_FMT_BGR32;
67955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
68955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    case kCVPixelFormatType_422YpCbCr8:
69955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine      return V4L2_PIX_FMT_UYVY;
70955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
71955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    case kCVPixelFormatType_420YpCbCr8Planar:
72955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine      return V4L2_PIX_FMT_YVU420;
73955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
74955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    case 'yuvs':  // kCVPixelFormatType_422YpCbCr8_yuvs - undeclared?
75955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine      return V4L2_PIX_FMT_YUYV;
76955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
77955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    default:
78955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine      E("Unrecognized pixel format '%.4s'", (const char*)&qt_pix_format);
79955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine      return 0;
80955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine  }
81955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
82955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
83955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/*******************************************************************************
84955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *                     MacCamera implementation
85955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine ******************************************************************************/
86955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
87955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/* Encapsulates a camera device on MacOS */
88955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine@interface MacCamera : NSObject {
89955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Capture session. */
90955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    QTCaptureSession*             capture_session;
91955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Camera capture device. */
92955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    QTCaptureDevice*              capture_device;
93955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Input device registered with the capture session. */
94955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    QTCaptureDeviceInput*         input_device;
95955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Output device registered with the capture session. */
96955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    QTCaptureVideoPreviewOutput*  output_device;
97955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Current framebuffer. */
98955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    CVImageBufferRef              current_frame;
99955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Desired frame width */
100955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    int                           desired_width;
101955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Desired frame height */
102955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    int                           desired_height;
103955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
104955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
105955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/* Initializes MacCamera instance.
106955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * Return:
107955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *  Pointer to initialized instance on success, or nil on failure.
108955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine */
109955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine- (MacCamera*)init;
110955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
111955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/* Undoes 'init' */
112955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine- (void)free;
113955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
114955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/* Starts capturing video frames.
115955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * Param:
116955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *  width, height - Requested dimensions for the captured video frames.
117955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * Return:
118955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *  0 on success, or !=0 on failure.
119955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine */
120955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine- (int)start_capturing:(int)width:(int)height;
121955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
122955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/* Captures a frame from the camera device.
123955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * Param:
124955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *  framebuffers - Array of framebuffers where to read the frame. Size of this
125955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *      array is defined by the 'fbs_num' parameter. Note that the caller must
126955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *      make sure that buffers are large enough to contain entire frame captured
127955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *      from the device.
128955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *  fbs_num - Number of entries in the 'framebuffers' array.
129955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * Return:
130955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *  0 on success, or non-zero value on failure. There is a special vaule 1
131955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *  returned from this routine which indicates that frames are not yet available
132955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *  in the device. The client should respond to this value by repeating the
133955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *  read, rather than reporting an error.
134955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine */
13537fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine- (int)read_frame:(ClientFrameBuffer*)framebuffers:(int)fbs_num:(float)r_scale:(float)g_scale:(float)b_scale:(float)exp_comp;
136955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
137955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine@end
138955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
139955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine@implementation MacCamera
140955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
141955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine- (MacCamera*)init
142955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
143955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    NSError *error;
144955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    BOOL success;
145955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
146955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Obtain the capture device, make sure it's not used by another
147955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine     * application, and open it. */
148955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    capture_device =
149955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo];
150955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (capture_device == nil) {
151955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("There are no available video devices found.");
152955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [self release];
153955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return nil;
154955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
155955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if ([capture_device isInUseByAnotherApplication]) {
156955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("Default camera device is in use by another application.");
157955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [capture_device release];
158955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        capture_device = nil;
159955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [self release];
160955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return nil;
161955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
162955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    success = [capture_device open:&error];
163955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (!success) {
164955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("Unable to open camera device: '%s'",
165955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine          [[error localizedDescription] UTF8String]);
166955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [self free];
167955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [self release];
168955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return nil;
169955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
170955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
171955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Create capture session. */
172955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    capture_session = [[QTCaptureSession alloc] init];
173955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (capture_session == nil) {
174955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("Unable to create capure session.");
175955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [self free];
176955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [self release];
177955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return nil;
178955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
179955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
180955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Create an input device and register it with the capture session. */
181955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    input_device = [[QTCaptureDeviceInput alloc] initWithDevice:capture_device];
182955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    success = [capture_session addInput:input_device error:&error];
183955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (!success) {
184955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("Unable to initialize input device: '%s'",
185955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine          [[error localizedDescription] UTF8String]);
186955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [input_device release];
187955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        input_device = nil;
188955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [self free];
189955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [self release];
190955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return nil;
191955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
192955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
193955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Create an output device and register it with the capture session. */
194955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    output_device = [[QTCaptureVideoPreviewOutput alloc] init];
195955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    success = [capture_session addOutput:output_device error:&error];
196955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (!success) {
197955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("Unable to initialize output device: '%s'",
198955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine          [[error localizedDescription] UTF8String]);
199955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [output_device release];
200955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        output_device = nil;
201955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [self free];
202955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [self release];
203955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return nil;
204955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
205955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    [output_device setDelegate:self];
206955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
207955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    return self;
208955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
209955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
210955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine- (void)free
211955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
212955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Uninitialize capture session. */
213955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (capture_session != nil) {
214955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        /* Make sure that capturing is stopped. */
215955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        if ([capture_session isRunning]) {
216955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            [capture_session stopRunning];
217955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        }
218955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        /* Detach input and output devices from the session. */
219955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        if (input_device != nil) {
220955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            [capture_session removeInput:input_device];
221955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            [input_device release];
222955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            input_device = nil;
223955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        }
224955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        if (output_device != nil) {
225955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            [capture_session removeOutput:output_device];
226955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            [output_device release];
227955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            output_device = nil;
228955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        }
229955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        /* Destroy capture session. */
230955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [capture_session release];
231955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        capture_session = nil;
232955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
233955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
234955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Uninitialize capture device. */
235955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (capture_device != nil) {
236955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        /* Make sure device is not opened. */
237955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        if ([capture_device isOpen]) {
238955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            [capture_device close];
239955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        }
240955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [capture_device release];
241955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        capture_device = nil;
242955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
243955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
244955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Release current framebuffer. */
245955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (current_frame != nil) {
246955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine       CVBufferRelease(current_frame);
247955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine       current_frame = nil;
248955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
249955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
250955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
251955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine- (int)start_capturing:(int)width:(int)height
252955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
253955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine  if (![capture_session isRunning]) {
254955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        /* Set desired frame dimensions. */
255955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        desired_width = width;
256955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        desired_height = height;
257955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [output_device setPixelBufferAttributes:
258955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine          [NSDictionary dictionaryWithObjectsAndKeys:
259955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine              [NSNumber numberWithInt: width], kCVPixelBufferWidthKey,
260955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine              [NSNumber numberWithInt: height], kCVPixelBufferHeightKey,
261955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine              nil]];
262955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [capture_session startRunning];
263955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return 0;
264955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine  } else if (width == desired_width && height == desired_height) {
265955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine      W("%s: Already capturing %dx%d frames",
266955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        __FUNCTION__, desired_width, desired_height);
267955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine      return -1;
268955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine  } else {
269955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine      E("%s: Already capturing %dx%d frames. Requested frame dimensions are %dx%d",
270955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        __FUNCTION__, desired_width, desired_height, width, height);
271955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine      return -1;
272955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine  }
273955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
274955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
27537fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine- (int)read_frame:(ClientFrameBuffer*)framebuffers:(int)fbs_num:(float)r_scale:(float)g_scale:(float)b_scale:(float)exp_comp
276955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
277955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    int res = -1;
278955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
279955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Frames are pushed by QT in another thread.
280955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine     * So we need a protection here. */
281955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    @synchronized (self)
282955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    {
283955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        if (current_frame != nil) {
284955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            /* Collect frame info. */
285955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            const uint32_t pixel_format =
286955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine                _QTtoFOURCC(CVPixelBufferGetPixelFormatType(current_frame));
287955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            const int frame_width = CVPixelBufferGetWidth(current_frame);
288955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            const int frame_height = CVPixelBufferGetHeight(current_frame);
289955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            const size_t frame_size =
290955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine                CVPixelBufferGetBytesPerRow(current_frame) * frame_height;
291955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
292955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            /* Get framebuffer pointer. */
293955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            CVPixelBufferLockBaseAddress(current_frame, 0);
294955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            const void* pixels = CVPixelBufferGetBaseAddress(current_frame);
295955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            if (pixels != nil) {
296955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine                /* Convert framebuffer. */
297955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine                res = convert_frame(pixels, pixel_format, frame_size,
298955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine                                    frame_width, frame_height,
29937fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                                    framebuffers, fbs_num,
30037fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                                    r_scale, g_scale, b_scale, exp_comp);
301955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            } else {
302955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine                E("%s: Unable to obtain framebuffer", __FUNCTION__);
303955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine                res = -1;
304955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            }
305955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            CVPixelBufferUnlockBaseAddress(current_frame, 0);
306955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        } else {
307955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            /* First frame didn't come in just yet. Let the caller repeat. */
308955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            res = 1;
309955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        }
310955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
311955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
312955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    return res;
313955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
314955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
315955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine- (void)captureOutput:(QTCaptureOutput*) captureOutput
316955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine                      didOutputVideoFrame:(CVImageBufferRef)videoFrame
317955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine                      withSampleBuffer:(QTSampleBuffer*) sampleBuffer
318955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine                      fromConnection:(QTCaptureConnection*) connection
319955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
320955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    CVImageBufferRef to_release;
321955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    CVBufferRetain(videoFrame);
322955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
323955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Frames are pulled by the client in another thread.
324955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine     * So we need a protection here. */
325955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    @synchronized (self)
326955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    {
327955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        to_release = current_frame;
328955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        current_frame = videoFrame;
329955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
330955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    CVBufferRelease(to_release);
331955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
332955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
333955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine@end
334955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
335955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/*******************************************************************************
336955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *                     CameraDevice routines
337955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine ******************************************************************************/
338955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
339955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkinetypedef struct MacCameraDevice MacCameraDevice;
340955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/* MacOS-specific camera device descriptor. */
341955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkinestruct MacCameraDevice {
342955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Common camera device descriptor. */
343955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    CameraDevice  header;
344955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Actual camera device object. */
345955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    MacCamera*    device;
346955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine};
347955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
348955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/* Allocates an instance of MacCameraDevice structure.
349955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * Return:
350955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *  Allocated instance of MacCameraDevice structure. Note that this routine
351955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *  also sets 'opaque' field in the 'header' structure to point back to the
352955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *  containing MacCameraDevice instance.
353955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine */
354955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkinestatic MacCameraDevice*
355955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine_camera_device_alloc(void)
356955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
357955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    MacCameraDevice* cd = (MacCameraDevice*)malloc(sizeof(MacCameraDevice));
358955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (cd != NULL) {
359955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        memset(cd, 0, sizeof(MacCameraDevice));
360955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        cd->header.opaque = cd;
361955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    } else {
362955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("%s: Unable to allocate MacCameraDevice instance", __FUNCTION__);
363955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
364955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    return cd;
365955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
366955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
367955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/* Uninitializes and frees MacCameraDevice descriptor.
368955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * Note that upon return from this routine memory allocated for the descriptor
369955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * will be freed.
370955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine */
371955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkinestatic void
372955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine_camera_device_free(MacCameraDevice* cd)
373955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
374955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (cd != NULL) {
375955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        if (cd->device != NULL) {
376955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            [cd->device free];
377955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            [cd->device release];
378955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine            cd->device = nil;
379955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        }
380955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        AFREE(cd);
381955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    } else {
382955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        W("%s: No descriptor", __FUNCTION__);
383955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
384955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
385955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
386955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/* Resets camera device after capturing.
387955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * Since new capture request may require different frame dimensions we must
388955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * reset frame info cached in the capture window. The only way to do that would
389955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * be closing, and reopening it again. */
390955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkinestatic void
391955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine_camera_device_reset(MacCameraDevice* cd)
392955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
393955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (cd != NULL && cd->device) {
394955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [cd->device free];
395955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        cd->device = [cd->device init];
396955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
397955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
398955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
399955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/*******************************************************************************
400955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine *                     CameraDevice API
401955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine ******************************************************************************/
402955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
403955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir ChtchetkineCameraDevice*
404955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkinecamera_device_open(const char* name, int inp_channel)
405955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
406955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    MacCameraDevice* mcd;
407955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
408955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    mcd = _camera_device_alloc();
409955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (mcd == NULL) {
410955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("%s: Unable to allocate MacCameraDevice instance", __FUNCTION__);
411955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return NULL;
412955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
413955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    mcd->device = [[MacCamera alloc] init];
414955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (mcd->device == nil) {
415955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("%s: Unable to initialize camera device.", __FUNCTION__);
416955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return NULL;
417955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
418955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    return &mcd->header;
419955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
420955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
421955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkineint
422955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkinecamera_device_start_capturing(CameraDevice* cd,
423955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine                              uint32_t pixel_format,
424955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine                              int frame_width,
425955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine                              int frame_height)
426955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
427955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    MacCameraDevice* mcd;
428955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
429955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Sanity checks. */
430955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (cd == NULL || cd->opaque == NULL) {
431955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("%s: Invalid camera device descriptor", __FUNCTION__);
432955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return -1;
433955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
434955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    mcd = (MacCameraDevice*)cd->opaque;
435955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (mcd->device == nil) {
436955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("%s: Camera device is not opened", __FUNCTION__);
437955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return -1;
438955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
439955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
440955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    return [mcd->device start_capturing:frame_width:frame_height];
441955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
442955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
443955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkineint
444955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkinecamera_device_stop_capturing(CameraDevice* cd)
445955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
446955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    MacCameraDevice* mcd;
447955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
448955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Sanity checks. */
449955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (cd == NULL || cd->opaque == NULL) {
450955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("%s: Invalid camera device descriptor", __FUNCTION__);
451955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return -1;
452955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
453955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    mcd = (MacCameraDevice*)cd->opaque;
454955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (mcd->device == nil) {
455955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("%s: Camera device is not opened", __FUNCTION__);
456955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return -1;
457955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
458955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
459955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Reset capture settings, so next call to capture can set its own. */
460955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    _camera_device_reset(mcd);
461955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
462955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    return 0;
463955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
464955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
465955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkineint
466955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkinecamera_device_read_frame(CameraDevice* cd,
467955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine                         ClientFrameBuffer* framebuffers,
46837fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                         int fbs_num,
46937fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                         float r_scale,
47037fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                         float g_scale,
47137fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                         float b_scale,
47237fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine                         float exp_comp)
473955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
474955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    MacCameraDevice* mcd;
475955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
476955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Sanity checks. */
477955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (cd == NULL || cd->opaque == NULL) {
478955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("%s: Invalid camera device descriptor", __FUNCTION__);
479955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return -1;
480955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
481955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    mcd = (MacCameraDevice*)cd->opaque;
482955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (mcd->device == nil) {
483955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("%s: Camera device is not opened", __FUNCTION__);
484955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return -1;
485955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
486955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
48737fb84f8b26e3061c1ccb404bf4c962eed5e6057Vladimir Chtchetkine    return [mcd->device read_frame:framebuffers:fbs_num:r_scale:g_scale:b_scale:exp_comp];
488955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
489955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
490955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkinevoid
491955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkinecamera_device_close(CameraDevice* cd)
492955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
493955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Sanity checks. */
494955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (cd == NULL || cd->opaque == NULL) {
495955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("%s: Invalid camera device descriptor", __FUNCTION__);
496955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    } else {
497955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        _camera_device_free((MacCameraDevice*)cd->opaque);
498955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
499955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
500955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
501955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkineint
502955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkineenumerate_camera_devices(CameraInfo* cis, int max)
503955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
504955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine/* Array containing emulated webcam frame dimensions.
505955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * QT API provides device independent frame dimensions, by scaling frames
506955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * received from the device to whatever dimensions were requested for the
507955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * output device. So, we can just use a small set of frame dimensions to
508955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine * emulate.
509955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine */
510955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkinestatic const CameraFrameDim _emulate_dims[] =
511955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine{
512955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine  /* Emulates 640x480 frame. */
513955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine  {640, 480},
5148d9a7a5fa4bd32f9b8aeb7b9e3bd047a475539abVladimir Chtchetkine  /* Emulates 352x288 frame (required by camera framework). */
5158d9a7a5fa4bd32f9b8aeb7b9e3bd047a475539abVladimir Chtchetkine  {352, 288},
516e080a45d3e29e41bce06669b79d5eb04f0fd05efVladimir Chtchetkine  /* Emulates 320x240 frame (required by camera framework). */
517e080a45d3e29e41bce06669b79d5eb04f0fd05efVladimir Chtchetkine  {320, 240},
5188d9a7a5fa4bd32f9b8aeb7b9e3bd047a475539abVladimir Chtchetkine  /* Emulates 176x144 frame (required by camera framework). */
5198d9a7a5fa4bd32f9b8aeb7b9e3bd047a475539abVladimir Chtchetkine  {176, 144}
520955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine};
521955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
522955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Obtain default video device. QT API doesn't really provide a reliable
523955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine     * way to identify camera devices. There is a QTCaptureDevice::uniqueId
524955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine     * method that supposedly does that, but in some cases it just doesn't
525955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine     * work. Until we figure out a reliable device identification, we will
526955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine     * stick to using only one (default) camera for emulation. */
527955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    QTCaptureDevice* video_dev =
528955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [QTCaptureDevice defaultInputDeviceWithMediaType:QTMediaTypeVideo];
529955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (video_dev == nil) {
530955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        D("No web cameras are connected to the host.");
531955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return 0;
532955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
533955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
534955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Obtain pixel format for the device. */
535955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    NSArray* pix_formats = [video_dev formatDescriptions];
536955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (pix_formats == nil || [pix_formats count] == 0) {
537955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("Unable to obtain pixel format for the default camera device.");
538955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [video_dev release];
539955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return 0;
540955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
541955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    const uint32_t qt_pix_format = [[pix_formats objectAtIndex:0] formatType];
542955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    [pix_formats release];
543955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
544955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Obtain FOURCC pixel format for the device. */
545955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    cis[0].pixel_format = _QTtoFOURCC(qt_pix_format);
546955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (cis[0].pixel_format == 0) {
547955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        /* Unsupported pixel format. */
548955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("Pixel format '%.4s' reported by the camera device is unsupported",
549955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine          (const char*)&qt_pix_format);
550955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [video_dev release];
551955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return 0;
552955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
553955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine
554955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    /* Initialize camera info structure. */
555955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    cis[0].frame_sizes = (CameraFrameDim*)malloc(sizeof(_emulate_dims));
556955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    if (cis[0].frame_sizes != NULL) {
557955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        cis[0].frame_sizes_num = sizeof(_emulate_dims) / sizeof(*_emulate_dims);
558955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        memcpy(cis[0].frame_sizes, _emulate_dims, sizeof(_emulate_dims));
559955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        cis[0].device_name = ASTRDUP("webcam0");
560955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        cis[0].inp_channel = 0;
561955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        cis[0].display_name = ASTRDUP("webcam0");
562955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        cis[0].in_use = 0;
563955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [video_dev release];
564955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return 1;
565955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    } else {
566955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        E("Unable to allocate memory for camera information.");
567955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        [video_dev release];
568955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine        return 0;
569955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine    }
570955a99781dd7af82e7a55525a4e51ce5d0814021Vladimir Chtchetkine}
571