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