libcvd-members
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[libcvd-members] libcvd/progs video_capture.m


From: Joseph Newman
Subject: [libcvd-members] libcvd/progs video_capture.m
Date: Fri, 30 Apr 2010 10:48:08 +0000

CVSROOT:        /sources/libcvd
Module name:    libcvd
Changes by:     Joseph Newman <jfn20>   10/04/30 10:48:08

Added files:
        progs          : video_capture.m 

Log message:
        objective-C code using the QTKit framework to obtain video frames and 
pass them via C data structures

CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/libcvd/progs/video_capture.m?cvsroot=libcvd&rev=1.1

Patches:
Index: video_capture.m
===================================================================
RCS file: video_capture.m
diff -N video_capture.m
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ video_capture.m     30 Apr 2010 10:48:08 -0000      1.1
@@ -0,0 +1,466 @@
+#import <QTKit/QTKit.h>
+#include "video_capture.h"
+
+#define DebugLog if (0) NSLog
+
+// -*- mode: objc -*-
+
address@hidden VideoCapture: NSObject 
+{
+  QTCaptureSession*                 captureSession;
+  NSMutableArray*                   videoDevices;
+  QTCaptureDeviceInput*             deviceInput;
+  QTCaptureDecompressedVideoOutput* videoOutput;
+
+  vcapture_frame_callback callback;
+  void* userdata;
+  
+  struct vcapture_frame_format requested;
+  struct vcapture_frame_format actual;
+  BOOL needActual;
+
+}
+
+- (NSArray*) devices;
+- (int) device;
+- (int) setDevice: (int)idx;
+
+- (BOOL) active;
+- (int) start;
+- (int) stop;
+
+- (vcapture_frame_callback) callback;
+- (void) setCallback: (vcapture_frame_callback)callback 
withUserData:(void*)userdata;
+
+- (void) getRequestedFormat:(struct vcapture_frame_format*)format;
+- (int)  setRequestedFormat:(const struct vcapture_frame_format*)format;
+
+- (void) captureOutput:(QTCaptureOutput *)captureOutput 
+         didOutputVideoFrame:(CVImageBufferRef)videoFrame 
+         withSampleBuffer:(QTSampleBuffer *)sampleBuffer 
+         fromConnection:(QTCaptureConnection *)connection;
+
address@hidden
+
address@hidden VideoCapture 
+
+- (id) init {
+  if ( (self = [super init]) ) {
+
+    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+
+    captureSession = [[QTCaptureSession alloc] init];
+    videoDevices = [[NSMutableArray alloc] init];
+    deviceInput = nil;
+    videoOutput = nil;
+    callback = 0;
+    userdata = 0;
+
+    memset(&requested, 0, sizeof(struct vcapture_frame_format));
+    memset(&actual, 0, sizeof(struct vcapture_frame_format));
+
+    requested.type = VC_TYPE_RGB;
+    needActual = YES;
+
+    NSArray* allInputDevices = [QTCaptureDevice inputDevices];
+
+    for (QTCaptureDevice* device in allInputDevices) {
+      DebugLog(@"device: %@", device);
+      if ([device hasMediaType:QTMediaTypeVideo] ||
+          [device hasMediaType:QTMediaTypeMuxed]) {
+        DebugLog(@"  it is video!");
+        [videoDevices addObject:device];
+      }
+    }
+
+    [pool release];
+
+  }
+  return self;
+}
+
+- (void) resetDevice {
+
+  if ([self active]) {
+    [self stop];
+  }
+
+  if (videoOutput) {
+    [captureSession removeOutput:videoOutput];
+    [videoOutput release];
+    videoOutput = nil;
+  }
+
+  if (deviceInput) {
+    [captureSession removeInput:deviceInput];
+    QTCaptureDevice* device = [deviceInput device];
+    if ([device isOpen]) {
+      [device close];
+    }
+    [deviceInput release];
+    deviceInput = nil;
+  }
+
+}
+
+- (void) dealloc {
+  DebugLog(@"deallocating a %@", [self className]);
+  if (deviceInput) {
+    if ([self active]) {
+      DebugLog(@"stopping device in dealloc");
+    }
+    DebugLog(@"resetting device in dealloc");
+  }
+  [self resetDevice];
+  [videoDevices release];
+  [captureSession release];
+  [super dealloc];
+}
+
+- (int) device {
+  if (deviceInput == nil) {
+    return -1;
+  } else {
+    return [videoDevices indexOfObject:[deviceInput device]];
+  }
+}
+
+- (int) setDevice: (int)idx {
+
+  if ([self device] == idx) {
+    return VC_SUCCESS;
+  }
+
+  [self resetDevice];
+
+  if (idx < 0) { return VC_SUCCESS; }
+  if (idx >= [videoDevices count]) { return VC_INVALID_DEVICE; }
+
+
+  QTCaptureDevice* device = [videoDevices objectAtIndex:idx];
+  NSError* error = nil;
+
+  BOOL success = [device open:&error];
+
+  if (!success) {
+    NSLog(@"Error opening device: %@", error);
+    return VC_DEVICE_OPEN_ERROR;
+  }
+
+  deviceInput = [[QTCaptureDeviceInput alloc] initWithDevice: device];
+
+  success = [captureSession addInput:deviceInput error:&error];
+  if (!success) {
+    NSLog(@"Error adding input: %@", error);
+    [self resetDevice];
+    return VC_DEVICE_OPEN_ERROR;
+  }
+
+  videoOutput = [[QTCaptureDecompressedVideoOutput alloc] init];
+  success = [captureSession addOutput:videoOutput error:&error];
+  if (!success) {
+    NSLog(@"Error adding output: %@", error);
+    [self resetDevice];
+    return VC_DEVICE_OPEN_ERROR;
+  }
+
+  [videoOutput setDelegate:self];
+  [videoOutput setAutomaticallyDropsLateVideoFrames:YES];
+
+  needActual = YES;
+
+
+  NSMutableDictionary* pixelBufferAttributes = [[NSMutableDictionary alloc] 
init];
+  NSString* key;
+  NSNumber* val;
+
+  
+  if (requested.fourcc || requested.type) {
+
+    unsigned int type;
+    if (requested.fourcc) {
+      type = requested.fourcc;
+    } else {
+      type = vcapture_type_to_fourcc(requested.type);
+    }
+
+    key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
+    val = [NSNumber numberWithUnsignedInt:type];
+
+    DebugLog(@"set pixelBufferAttributes address@hidden>%@", key, val);
+
+    [pixelBufferAttributes setObject:val forKey:key];
+
+  }
+
+  if (requested.width && requested.height) {
+
+    key = (NSString*)kCVPixelBufferWidthKey;
+    val = [NSNumber numberWithInt:requested.width];
+    [pixelBufferAttributes setObject:val forKey:key];
+    DebugLog(@"set pixelBufferAttributes address@hidden>%@", key, val);
+
+    key = (NSString*)kCVPixelBufferHeightKey;
+    val = [NSNumber numberWithInt:requested.height];
+    [pixelBufferAttributes setObject:val forKey:key];
+    DebugLog(@"set pixelBufferAttributes address@hidden>%@", key, val);
+
+  }
+
+  if ([pixelBufferAttributes count]) {
+    [videoOutput setPixelBufferAttributes:pixelBufferAttributes];
+  } else {
+    [pixelBufferAttributes release];
+  }
+  
+  return VC_SUCCESS;
+
+}
+
+- (NSArray*) devices {
+  return videoDevices;
+}
+
+- (vcapture_frame_callback) callback {
+  return callback;
+}
+
+- (void)captureOutput:(QTCaptureOutput *)captureOutput 
+  didOutputVideoFrame:(CVImageBufferRef)videoFrame 
+  withSampleBuffer:(QTSampleBuffer *)sampleBuffer 
+  fromConnection:(QTCaptureConnection *)connection 
+
+{
+
+  [sampleBuffer incrementSampleUseCount];
+
+  CVReturn status = CVPixelBufferLockBaseAddress(videoFrame, 0);
+
+  if (status == 0) { 
+
+    if (needActual) {
+
+      needActual = NO;
+
+      actual.fourcc = CVPixelBufferGetPixelFormatType(videoFrame);
+      actual.type = vcapture_fourcc_to_type(actual.fourcc);
+      actual.width = CVPixelBufferGetWidth(videoFrame);
+      actual.height = CVPixelBufferGetHeight(videoFrame);
+
+      size_t l, r, t, b;
+
+      CVPixelBufferGetExtendedPixels(videoFrame, &l, &r, &t, &b);
+
+      actual.pad_left = l;
+      actual.pad_right = r;
+      actual.pad_top = t;
+      actual.pad_bottom = b;
+
+      actual.bytes_per_row = CVPixelBufferGetBytesPerRow(videoFrame);
+    
+    }
+
+    struct vcapture_frame frame;
+
+    memset(frame.planes, 0, sizeof(frame.planes));
+
+    unsigned long long timestamp = 0;
+
+
+    if (CVPixelBufferIsPlanar(videoFrame)) {
+      frame.count = CVPixelBufferGetPlaneCount(videoFrame);
+      if (frame.count > 4) { frame.count = 4; }
+      int i;
+      for (i=0; i<frame.count; ++i) {
+        frame.planes[i] = CVPixelBufferGetBaseAddressOfPlane(videoFrame, i);
+      }
+    } else {
+      frame.count = 0;
+      frame.planes[0] = CVPixelBufferGetBaseAddress(videoFrame);    
+    }
+  
+    callback(&actual, &frame, timestamp, userdata);
+  
+    CVPixelBufferUnlockBaseAddress(videoFrame, 0);
+
+  }
+
+  [sampleBuffer decrementSampleUseCount];
+
+}
+
+- (BOOL) active {
+  return [captureSession isRunning];
+}
+
+- (int) start {
+  if ([self device] < 0) { return VC_NO_ACTIVE_DEVICE; }
+  [captureSession startRunning];
+  return VC_SUCCESS;
+}
+
+- (int) stop {
+  if ([captureSession isRunning]) {
+    [captureSession stopRunning];
+  }
+  return VC_SUCCESS;
+}
+
+- (void) setCallback: (vcapture_frame_callback)c withUserData:(void*)u {
+  callback = c;
+  userdata = u;
+}
+
+- (void) getRequestedFormat:(struct vcapture_frame_format*)format {
+  memcpy(format, &requested, sizeof(struct vcapture_frame_format));
+}
+
+- (int) setRequestedFormat:(const struct vcapture_frame_format*)format {
+  if ([self active]) {
+    return VC_DEVICE_RUNNING;
+  } 
+  int oldDevice = [self device];
+  [self resetDevice];
+  memcpy(&requested, format, sizeof(struct vcapture_frame_format));
+  return [self setDevice:oldDevice];
+}
+
address@hidden
+
+//////////////////////////////////////////////////////////////////////
+
+unsigned int vcapture_type_to_fourcc(enum vcapture_format_type t) {
+  switch (t) {
+  case VC_TYPE_RGB: return k24RGBPixelFormat;
+  case VC_TYPE_RGBA: return kCVPixelFormatType_32RGBA;
+  case VC_TYPE_ARGB: return kCVPixelFormatType_32ARGB;
+  case VC_TYPE_FOURCC_2uvy: return '2uvy';
+  case VC_TYPE_FOURCC_yuvs: return 'yuvs';
+  case VC_TYPE_FOURCC_YVYU: return 'YVYU';
+  case VC_TYPE_FOURCC_yuvu: return 'yuvu';
+  default:
+    break;
+  }
+  return 0;
+}
+
+enum vcapture_format_type vcapture_fourcc_to_type(unsigned int fourcc) {
+  switch (fourcc) {
+  case k24RGBPixelFormat: return VC_TYPE_RGB;
+  case kCVPixelFormatType_32ARGB: return VC_TYPE_ARGB;
+  case kCVPixelFormatType_32RGBA: return VC_TYPE_RGBA;
+  case '2uvy': return VC_TYPE_FOURCC_2uvy;
+  case 'yuvs': return VC_TYPE_FOURCC_yuvs;
+  case 'YVYU': return VC_TYPE_FOURCC_YVYU;
+  case 'yuvu': return VC_TYPE_FOURCC_yuvu;
+  default:
+    break;
+  }
+  return VC_TYPE_UNKNOWN;
+}
+
+//////////////////////////////////////////////////////////////////////
+
+void vcapture_poll(int msec) {
+  NSTimeInterval interval = msec / 1000.0;
+  NSDate* date = [[NSDate alloc] initWithTimeIntervalSinceNow:interval];
+  [[NSRunLoop currentRunLoop]  runMode:NSDefaultRunLoopMode beforeDate:date];
+  [date release];
+}
+
+//////////////////////////////////////////////////////////////////////
+
+struct video_capture {
+  NSAutoreleasePool* pool;
+  VideoCapture* instance;
+};
+
+//////////////////////////////////////////////////////////////////////
+
+vcapture vcapture_alloc() {
+  vcapture rval = (vcapture)malloc(sizeof(struct video_capture));
+  if (!rval) { return 0; }
+  rval->pool = [[NSAutoreleasePool alloc] init];
+  rval->instance = [[VideoCapture alloc] init];
+  if (!rval->instance) {
+    vcapture_free(rval);
+    rval = 0;
+  }
+  return rval;
+}
+
+void vcapture_free(vcapture v) {
+  [v->instance release];
+  [v->pool release];
+  free(v);
+}
+
+//////////////////////////////////////////////////////////////////////
+
+int vcapture_device_count(vcapture v) {
+  return [[v->instance devices] count];
+}
+
+const char* vcapture_device_name(vcapture v, int idx) {
+
+  NSArray* devices = [v->instance devices];
+  if (idx >= [devices count]) {
+    return 0;
+  }
+
+  QTCaptureDevice* device = [devices objectAtIndex:idx];
+  NSString* str = [device description];
+
+  if (!str) { return 0; }
+
+  return [str cStringUsingEncoding:NSUTF8StringEncoding];
+
+}
+
+//////////////////////////////////////////////////////////////////////
+
+int vcapture_get_device(vcapture v) {
+  return [v->instance device];
+}
+
+int vcapture_set_device(vcapture v, int device) {
+  return [v->instance setDevice:device];
+}
+
+//////////////////////////////////////////////////////////////////////
+
+int vcapture_get_requested_format(vcapture v, struct vcapture_frame_format* f) 
{
+  [v->instance getRequestedFormat:f];
+  return VC_SUCCESS;
+}
+
+int vcapture_set_requested_format(vcapture v, const struct 
vcapture_frame_format* f) {
+  return [v->instance setRequestedFormat:f];
+}
+
+//////////////////////////////////////////////////////////////////////
+
+int vcapture_set_callback(vcapture v,
+                          vcapture_frame_callback callback,
+                          void* userdata) {
+  [v->instance setCallback:callback withUserData:userdata];
+  return VC_SUCCESS;
+}
+ 
+vcapture_frame_callback vcapture_get_callback(vcapture v) {
+  return [v->instance callback];
+}
+
+//////////////////////////////////////////////////////////////////////
+
+int vcapture_active(vcapture v) {
+  return [v->instance active];
+}
+
+int vcapture_start(vcapture v) {
+  return [v->instance start];
+}
+
+int vcapture_stop(vcapture v) {
+  return [v->instance stop];
+}




reply via email to

[Prev in Thread] Current Thread [Next in Thread]