AVCaptureVideoPreviewLayer frame in Swift - ios

I'm trying to get the video output on my screen in Swift. But the screen stays completely white. I found this tutorial in ObjC and I followed it (only in Swift style syntax).
In there there is a line previewLayer.frame = myView.bounds;
But the field .frame seems to be read only in swift. And I think this might be why I don't see anything on the screen.
How can I set the frame for the previewLayer in Swift?

I see three points in that tutorial where you could end up not displaying the preview, and thus getting a white screen. Below are the Obj-C and Swift counterparts.
1) You might have missed adding the input to the capture session:
// [session addInput:input];
session.addInput(input)
2) You might not have initialized the preview layer's bounds to that of your view controller:
// UIView *myView = self.view;
// previewLayer.frame = myView.bounds;
previewLayer.frame = self.view.bounds
3) You might not have added the preview layer as a sublayer of your view:
// [self.view.layer addSublayer:previewLayer];
self.view.layer.addSublayer(previewLayer)

Related

Draw overlay on camera iOS

Users need to be able to take photo of their ID. I need to add a blue frame to camera view as a guide. Guide should have same aspect ratio on all device sizes and fit a label with instructions. Can I accomplish this using UIImagePicker?
Here is some incomplete code. Thanks for any help.
UIImageView *overlayImage = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#""]];
CGRect overlayRect = CGRectMake(0, 0, self.view.frame.size.height - 16, self.view.frame.size.width - 16);
[overlayImage setFrame:overlayRect];
[self.imagePicker setCameraOverlayView:overlayImage];
Use AVCaptureDevice, AVCaptureSession, AVCaptureVideoPreviewLayer and AVCapturePhotoOutput.
Set AVCaptureDeviceInput as input of capture session, and photo output as output of capture session. Initialize AVCaptureVideoPreviewLayer with AVCaptureSession and add to your view.layer thought addSublayer. You can use UIViewController from storyboard or programmatically instantiated controller, add picture of overlay or cornered view.layer.borderWidth or UIBezierPath. Set up controller as AVCapturePhotoCaptureDelegate, add delegate methods. Use capturePhoto(with:delegate:) method. Enjoy.

AVfoundation Camera goes off screen Obj-C

I am working on scanning barcode ios App that uses AVFoundation
So i have created a square box with constraint using the interface builder. The square box is all good with the constraints. Perfectly fine.
i have this following code to add the avcapturelayer to the square box.
self.captureLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession];
[self.captureLayer setFrame:self.cameraPreviewView.layer.bounds];
[self.captureLayer setVideoGravity:AVLayerVideoGravityResizeAspectFill];
[self.cameraPreviewView.layer addSublayer:self.captureLayer];
the layer follows the leading space from the square box constraint, but not with the trailing. The new added AVlayer goes off the screen(to the right) while the square box itself is all good. What am I missing here?
thanks!
I think you should try to set self.captureLayer bounds/position instead of frame ?
Cheers!
This might be happening if you are setting the frame in viewDidLoad. If so, try doing it in viewWillAppear:instead.
This may solve your problem
CGRect bounds=view.layer.bounds;
captureLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
captureLayer.bounds=bounds;
captureLayer.position=CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
Or
as you are you are using AVLayerVideoGravityResizeAspectFill so it will go out of screen , you can use AVLayerVideoGravityResizeAspectFit instead.
you need to set clipToBound=YES; when using AVLayerVideoGravityResizeAspectFill (when using you View )
view.clipToBound=YES;
and than add Sublayer to view
view.layer.masksToBounds = YES;

Is Apple using black magic to accomplish camera's preview orientation?

I have this AVFoundation camera app of mine. The camera preview is the result of a filter, applied by didOutputSampleBuffer method.
When I setup the camera I am following what apple did on one of their sample codes (CIFunHouse):
// setting up the camera
CGRect bounds = [self.containerOpenGL bounds];
_eaglContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES3];
_videoPreviewView = [[GLKView alloc] initWithFrame:bounds
context:_eaglContext];
[self.containerOpenGL addSubview:_videoPreviewView];
[self.containerOpenGL sendSubviewToBack:_videoPreviewView];
id<MTLDevice> device = MTLCreateSystemDefaultDevice();
NSDictionary *options = #{kCIContextUseSoftwareRenderer : #(NO),
kCIContextPriorityRequestLow : #(YES),
kCIContextWorkingColorSpace : [NSNull null]};
_ciContext = [CIContext contextWithEAGLContext:_eaglContext options:options];
[_videoPreviewView bindDrawable];
_videoPreviewViewBounds = CGRectZero;
_videoPreviewViewBounds.size.width = _videoPreviewView.drawableWidth;
_videoPreviewViewBounds.size.height = _videoPreviewView.drawableHeight;
dispatch_async(dispatch_get_main_queue(), ^(void) {
CGAffineTransform transform = CGAffineTransformMakeRotation(M_PI);
_videoPreviewView.transform = transform;
_videoPreviewView.frame = bounds;
});
self.containerOpenGL is a full screen view and is constrained to the four corners of the screen. Autorotation is on.
But this is the problem...
When I setup the GLKView and self.ciContext it is created assuming the device is on a particular orientation. If the device is on a particular orientation and I run the application, the previewView will fit the entire self.containerOpenGL area but when I rotate the device the previewView will be out center.
I see that Apple code works perfectly and they don't use any constraints. They do not use any autorotation method, no didLayoutSubviews and when you rotate the device, running their code, everything rotates except the preview view. And worse than that, my previewView appears to rotate but not their's.
Is this black magic? How do I they do that?
They add their preview view to a uiwindow and that is why it does not rotate. I hope this answers the question. If not I will continue to look through their source code.
Quote from source code.
we make our video preview view a subview of the window, and send it to the back; this makes FHViewController's view (and its UI elements) on top of the video preview, and also makes video preview unaffected by device rotation
They also add this
_videoPreviewView.enableSetNeedsDisplay = NO;
This may keep it from responding as well
Edit: It appears that now the preview rotates and the UI does as well so to combat this you can add a second window and send it to the back and make the main window clear and add the previewView to the second window with a dummyViewController that tells it not to autorotate by overriding the appropriate method. This will allow the preview to not rotate but the UI to rotate.

AVPreviewLayer contentsGravity not filling Layer

I'm using AVFoundation to do some video recording and I've looked all over for how to get the video to aspect fill. I've read through avfoundation guide by apple and class referene for AVCaptureVideoPreviewLayer. I also read this question here AVFoundation camera preview layer not working . Here is my code
videoPreviewLayer.frame = captureView.frame
videoPreviewLayer.frame.origin = CGPoint(x: 0, y: 0)
videoPreviewLayer.backgroundColor = UIColor.redColor().CGColor
videoPreviewLayer.contentsGravity = AVLayerVideoGravityResizeAspectFill
videoPreviewLayer.masksToBounds = true
captureView.layer.addSublayer(videoPreviewLayer)
I put this in viewDidLayoutSubviews() so that I can get the correct size for captureView.frame which is the UIView my previewLayer is inside of. Any clue why aspectFill isn't working? As you can see from the red background the layer is the correct size but the contentsGravity isn't filling the layer.
Found my answer in this link AVCaptureVideoPreviewLayer . I needed to use videoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill instead of videoPreviewLayer.contentsGravity = AVLayerVideoGravityResizeAspectFill
For me, the answer for my problem was provided by NSGangster in the question:
I put this in viewDidLayoutSubviews() so that I can get the correct size for captureView.frame which is the UIView my previewLayer is inside of.
I originally had the code in viewDidLoad() which meant the layer was resizing before the true bounds of the view was determined.
Thanks for sharing.

Cropping an AVCaptureSession preview

I'm displaying a video preview of a 320x320 capture window, and using videoGravity to have it fill the square:
captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
I'm then grabbing a photo quality image from the session and cropping it, starting at 0, 0. The problem I have is the saved image shows more to the top (but not left) of the frame than the preview. I'd like to basically only see the top of the frame, it seems I'm seeing the middle section, hope I'm explaining myself properly.
Here is the code snippet if it helps:
AVCaptureVideoPreviewLayer *captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:session];
captureVideoPreviewLayer.frame = _cameraView.bounds;
[_cameraView.layer addSublayer:captureVideoPreviewLayer];
captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
Thanks in advance for any help.
Cheers.
I couldn't figure out how to do this, so I decided to fix it by changing the cropping region instead of the preview region.

Resources