v002 / v002-Camera-Live

Live Syphon Camera
Other
1.17k stars 105 forks source link

Camera controls in app #162

Open scj643 opened 4 years ago

scj643 commented 4 years ago

Bindings for driving the focus as well as the exposure and other settings would be nice. The XPC service would need to expose controls for the current camera.

https://github.com/gphoto/libgphoto2/blob/master/examples/focus.c is an example of driving the focus with libgphoto2.

scj643 commented 4 years ago

Actually, this should just implement a wraper to control camera options in general.

scj643 commented 4 years ago

It is possible to implement it the same way as Copy Camera Descripton though we would need an implementation that runs while the camera is in live view.

scj643 commented 4 years ago

https://gitlab.com/entangle/entangle is a project using Gphoto2 that has controls while in live view. A way to send messages to the main of the SyPLiveViewSession would allow changing settings while in live view.

scj643 commented 4 years ago

This is my implementation in SyPGPhotoCamera.m

- (void)autofocus
{
    CameraWidget *widget = NULL, *child = NULL;

    int val = 0;

    int result = gp_camera_get_config(_camera, &widget, self.context.GPContext);

    if (result == GP_OK)
    {
        result = gp_widget_get_child_by_name(widget, "autofocusdrive", &child);
    }
    if (result == GP_OK)
    {
        CameraWidgetType type;
        result = gp_widget_get_type(widget, &type);
        if (result == GP_OK & type == GP_WIDGET_TOGGLE)
        {
            result = gp_widget_get_value (child, &val);
        }
        if (result == GP_OK)
        {
            // Invert the value to toggle it.
            val = !val;
            result = gp_widget_set_value(child, &val);
        }
        if (result == GP_OK)
        {
            result = gp_camera_set_config (_camera, widget, self.context.GPContext);
        }

    }
    gp_widget_free (widget);
}
scj643 commented 4 years ago

A quick hack is to use NSUserDefaults and set the properties you want changed as booleans there.

The implementation in main of SyPLiveViewSession

if (!error)
    {
        while (!self.isCancelled)
        {

            NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
            BOOL focus = [defaults boolForKey:@"focus"];

            @autoreleasepool {
                SyPImageBuffer *buffer = [camera getImageWithError:&error];
                if (buffer)
                {
                    self.buffer = buffer;
                    dispatch_source_merge_data(source, 1);
                }
                if (error)
                {
                    if ([SyPGPhotoContext errorIsFatal:error])
                    {
                        [self cancel];
                    }
                    self.errorHandler(error);
                }
                else if (focus == YES)
                {
                    [camera autofocus];
                    [defaults setBool:NO forKey:@"focus"];
                }
            }
        }
    }
scj643 commented 4 years ago

Ok, So I learned more Objective C and seems you could use NSNotificationCenter to trigger events on the camera. I am moving the camera in the live view session to another class called SyPCameraMessaging

SyPCameraMessaging.m

@implementation SyPCameraMessaging

- (SyPCameraMessaging *)initWithCamera:(SyPGPhotoCamera *)camera
{
    self.camera = camera;
    self.shouldGetFrames = YES;
    return self;
}

- (void) notificationHandler:(NSNotification *)notification
{
    if ([notification.object isEqual: @"focus"])
    {
        self.shouldGetFrames = NO;
        [self.camera autofocus];
        self.shouldGetFrames = YES;
    }
}
@end

SyPLiveViewSession.m

(inside main)

SyPCameraMessaging *messaging = [[SyPCameraMessaging alloc] initWithCamera: [_context cameraForDescription:_description withError:&error]];

// Code to create the queues is here

[messaging.camera startLiveView];
NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
    [center addObserver:messaging selector:@selector(notificationHandler:) name:@"camera" object:nil];

if (!error)
    {
        while (!self.isCancelled)
        {
            @autoreleasepool {
                SyPImageBuffer *buffer = nil;
                if (messaging.shouldGetFrames)
                {
                    buffer = [messaging.camera getImageWithError:&error];
                }
                if (buffer)
                {
                    self.buffer = buffer;
                    dispatch_source_merge_data(source, 1);
                }
                if (error)
                {
                    if ([SyPGPhotoContext errorIsFatal:error])
                    {
                        [self cancel];
                    }
                    self.errorHandler(error);
                }
            }
        }
    }

All functions like autofocussing would have to check for GP_ERROR_CAMERA_BUSY and wait since the frame loop holds it.

samuelbeek commented 4 years ago

@scj643 is it possible to run both programs at the same time? to control autofocus without it being part of cameralive?

scj643 commented 4 years ago

No it is not since cameralive has control of the camera.