Skip to content

Instantly share code, notes, and snippets.

@trinnguyen
Created February 1, 2016 10:52
Show Gist options
  • Save trinnguyen/637eb49a2fcdf1db0099 to your computer and use it in GitHub Desktop.
Save trinnguyen/637eb49a2fcdf1db0099 to your computer and use it in GitHub Desktop.
CameraPreviewView
using AVFoundation;
using Foundation;
using Masonry;
using System.Threading.Tasks;
using UIKit;
namespace UICode.Camera
{
internal class CameraPreviewView : UIView
{
private AVCaptureDevice backCamera;
private AVCaptureDevice frontCamera;
private AVCaptureSession session;
private AVCaptureStillImageOutput stillCameraOutput;
private AVCaptureVideoPreviewLayer previewLayer;
private AVCaptureDeviceInput currentInput;
private bool isBack;
private UIView overLayView;
private UIColor _borderColor;
public UIColor BorderColor
{
get { return _borderColor; }
set
{
if (_borderColor != value)
{
_borderColor = value;
if (overLayView != null)
{
overLayView.Layer.MasksToBounds = true;
overLayView.Layer.BorderColor = _borderColor.CGColor;
overLayView.Layer.BorderWidth = 1f;
overLayView.Layer.CornerRadius = 3f;
}
}
}
}
private int padding;
public int Padding
{
get { return padding; }
set
{
if (padding != value)
{
padding = value;
SetNeedsUpdateConstraints();
}
}
}
public CameraPreviewView()
{
//Create overlay
overLayView = new UIView();
AddSubview(overLayView);
//init Camera
InitializeAndSetUp();
//bring overlay to front
BringSubviewToFront(overLayView);
}
private async void InitializeAndSetUp()
{
bool accessable = await RequestAuthorization();
if (accessable)
{
SetUp();
}
else
{
ShowAlert("not allowed to access the camera devices");
}
}
private Task<bool> RequestAuthorization()
{
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
var authorizationStatus = AVCaptureDevice.GetAuthorizationStatus(AVMediaType.Video);
switch (authorizationStatus)
{
case AVAuthorizationStatus.NotDetermined:
AVCaptureDevice.RequestAccessForMediaType(AVMediaType.Video, (granted) =>
{
tcs.SetResult(granted);
});
break;
case AVAuthorizationStatus.Authorized:
tcs.SetResult(true);
break;
case AVAuthorizationStatus.Denied:
case AVAuthorizationStatus.Restricted:
tcs.SetResult(false);
break;
default:
tcs.SetResult(false);
break;
}
return tcs.Task;
}
private void SetUp()
{
//session
session = new AVCaptureSession();
var availableCameraDevices = AVCaptureDevice.DevicesWithMediaType(AVMediaType.Video);
if (availableCameraDevices == null || availableCameraDevices.Length == 0)
{
ShowAlert("No Camera");
return;
}
foreach (var device in availableCameraDevices)
{
if (device.Position == AVCaptureDevicePosition.Back)
{
backCamera = device;
}
else if (device.Position == AVCaptureDevicePosition.Front)
{
frontCamera = device;
}
}
//input
NSError error;
var backCameraInput = AVCaptureDeviceInput.FromDevice(backCamera, out error);
if (backCameraInput != null)
{
if (session.CanAddInput(backCameraInput))
session.AddInput(backCameraInput);
currentInput = backCameraInput;
}
isBack = true;
//Preview
previewLayer = AVCaptureVideoPreviewLayer.FromSession(session);
previewLayer.Frame = Bounds;
previewLayer.VideoGravity = AVLayerVideoGravity.ResizeAspectFill;
Layer.AddSublayer(previewLayer);
//Configure
session.SessionPreset = AVCaptureSession.PresetPhoto;
//output
stillCameraOutput = new AVCaptureStillImageOutput();
if (session.CanAddOutput(stillCameraOutput))
{
session.AddOutput(stillCameraOutput);
}
//Start
Start();
}
private void ShowAlert(string message)
{
UIAlertView alertView = new UIAlertView("Error", message, null, "OK", null);
alertView.Show();
}
public override void LayoutIfNeeded()
{
base.LayoutIfNeeded();
if (previewLayer != null)
previewLayer.Frame = Bounds;
}
public override void UpdateConstraints()
{
overLayView.RemakeConstraints((maker) =>
{
maker.Edges.EqualTo(this).Insets(new UIEdgeInsets(Padding, Padding, Padding, Padding));
});
base.UpdateConstraints();
if (previewLayer != null)
previewLayer.Frame = Bounds;
}
public void ForceLayout()
{
System.Diagnostics.Debug.WriteLine("Force Layout: " + Bounds);
if (previewLayer != null)
{
previewLayer.Frame = Bounds;
if (previewLayer.Connection.SupportsVideoOrientation)
{
previewLayer.Connection.VideoOrientation = RefreshDeviceOrientation();
}
}
}
private AVCaptureVideoOrientation RefreshDeviceOrientation()
{
var orientation = UIApplication.SharedApplication.StatusBarOrientation;
switch (orientation)
{
case UIInterfaceOrientation.Portrait:
return AVCaptureVideoOrientation.Portrait;
case UIInterfaceOrientation.PortraitUpsideDown:
return AVCaptureVideoOrientation.PortraitUpsideDown;
case UIInterfaceOrientation.LandscapeLeft:
return AVCaptureVideoOrientation.LandscapeLeft;
case UIInterfaceOrientation.LandscapeRight:
return AVCaptureVideoOrientation.LandscapeRight;
default:
break;
}
return AVCaptureVideoOrientation.Portrait;
}
public void Start()
{
if (session != null)
session.StartRunning();
}
public void Stop()
{
if (session != null)
session.StopRunning();
}
public void ToggleCamera()
{
if (previewLayer == null)
return;
session.BeginConfiguration();
NSError error = null;
session.RemoveInput(currentInput);
if (isBack)
{
var frontCameraInput = AVCaptureDeviceInput.FromDevice(frontCamera, out error);
if (frontCameraInput != null)
{
if (session.CanAddInput(frontCameraInput))
session.AddInput(frontCameraInput);
currentInput = frontCameraInput;
}
}
else
{
var backCameraInput = AVCaptureDeviceInput.FromDevice(backCamera, out error);
if (backCameraInput != null)
{
if (session.CanAddInput(backCameraInput))
session.AddInput(backCameraInput);
currentInput = backCameraInput;
}
}
isBack = !isBack;
session.CommitConfiguration();
}
public Task<UIImage> Capture()
{
if (previewLayer == null)
return new Task<UIImage>(() => null);
TaskCompletionSource<UIImage> tcs = new TaskCompletionSource<UIImage>();
var connection = stillCameraOutput.ConnectionFromMediaType(AVMediaType.Video);
connection.VideoOrientation = (AVCaptureVideoOrientation)((long)(UIDevice.CurrentDevice.Orientation));
stillCameraOutput.CaptureStillImageAsynchronously(connection, delegate (CoreMedia.CMSampleBuffer imageDataSampleBuffer, NSError error)
{
if (error == null)
{
var imageData = AVCaptureStillImageOutput.JpegStillToNSData(imageDataSampleBuffer);
var uiimage = new UIImage(imageData);
tcs.SetResult(uiimage);
}
else
{
ShowAlert("error while capturing still image: " + error.Description);
tcs.SetResult(null);
}
});
return tcs.Task;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment