Creating A Custom Camera View (Create Half Screen Camera In Xamarin.Forms) - Xamarin

AV Foundation is an Apple system framework that exists on macOS and iOS, along with watchOS and tvOS. The goal of this tutorial will be to help you build a fully functional iOS app that’s capable of capturing photos and videos using the device’s cameras. We’ll also be following the principles of good object oriented programming and designing a utility class that can be reused and extended in all your projects.

What is AV Foundation?


"AV Foundation is the full featured framework for working with time-based audiovisual media on iOS, macOS, watchOS and tvOS. Using AV Foundation, you can easily play, create, and edit QuickTime movies and MPEG-4 files, play HLS streams, and build powerful media functionality into your apps." – Apple

So, there you have it. AV Foundation is a framework for capturing, processing, and editing audio and video on Apple devices. 
Your app should use the prebuilt camera and media control if,
  • You prioritize code sharing over customization.
  • Camera or media functionality is just a small part of your overall application.
Your app should use a custom camera control if,
  • You prioritize customization over code sharing.
  • You don’t want to navigate the user to a new view to take a photo.
  • The core experience of the app revolves around the camera.
AVFoundation is a namespace that contains classes for high-level recording and playback capabilities for audio and video on iOS.
 

How do you develop in Xamarin Forms ?

 
Step 1
 
You have to create CameraPreview which inherits from View and Bindable Property, 
  1. public class CameraPreview: View {  
  2.     public static readonly BindableProperty CameraProperty = BindableProperty.Create(propertyName: "Camera", returnType: typeof(CameraOptions), declaringType: typeof(CameraPreview), defaultValue: CameraOptions.Rear);  
  3.     public CameraOptions Camera {  
  4.         get {  
  5.             return (CameraOptions) GetValue(CameraProperty);  
  6.         }  
  7.         set {  
  8.             SetValue(CameraProperty, value);  
  9.         }  
  10.     }  
  11. }  
CameraOptions contains Enum,
  1. public enum CameraOptions {  
  2.     Rear,  
  3.     Front  
  4. }  
Step 3
 
Now we're using our own CamaraPreview in Xaml like below
  1. <Grid  
  2.   BackgroundColor="Transparent"  
  3.   HorizontalOptions="FillAndExpand"  
  4.   RowSpacing="0"  
  5.   VerticalOptions="FillAndExpand"  
  6. >  
  7.   <Grid.RowDefinitions>  
  8.     <RowDefinition Height="*" />  
  9.     <RowDefinition Height="250" />  
  10.   </Grid.RowDefinitions>  
  11.   <Grid.ColumnDefinitions>  
  12.     <ColumnDefinition Width="*" />  
  13.   </Grid.ColumnDefinitions>  
  14.   <local:CameraPreview  
  15.     Grid.Row="0"  
  16.     Grid.Column="0"  
  17.     Camera="Rear"  
  18.     HeightRequest="300"  
  19.     HorizontalOptions="FillAndExpand"  
  20.     VerticalOptions="FillAndExpand"  
  21.     WidthRequest="400"  
  22.   />  
  23.   <frame  
  24.     Grid.Row="0"  
  25.     Grid.Column="0"  
  26.     BackgroundColor="Transparent"  
  27.     BorderColor="White"  
  28.     HeightRequest="100"  
  29.     HorizontalOptions="Center"  
  30.     VerticalOptions="Center"  
  31.     WidthRequest="200"  
  32.   />  
  33.   
  34.   <StackLayout  
  35.     Grid.Row="1"  
  36.     Grid.Column="0"  
  37.     BackgroundColor="Black"  
  38.     Orientation="Vertical"  
  39.   >  
  40.     <label  
  41.       FontSize="Title"  
  42.       HorizontalOptions="CenterAndExpand"  
  43.       Text="Add Card"  
  44.       TextColor="White"  
  45.     />  
  46.     <label  
  47.       FontSize="Large"  
  48.       HorizontalOptions="CenterAndExpand"  
  49.       Text="Position your card in the frame"  
  50.       TextColor="White"  
  51.     />  
  52.   </StackLayout>  
  53. </Grid>  
Now the most important part to is to create renderer to write code in the platform part,
  • IOS
  • CameraPreviewRenderer & UICameraPreview
CameraPreviewRenderer.cs
  1. using System;  
  2. using AVFoundation;  
  3. using CustomRenderer;  
  4. using CustomRenderer.iOS;  
  5. using Foundation;  
  6. using Xamarin.Forms;  
  7. using Xamarin.Forms.Platform.iOS;  
  8. [assembly: ExportRenderer(typeof(CameraPreview), typeof(CameraPreviewRenderer))]  
  9. namespace CodeXamarin.iOS {  
  10.     public class CameraPreviewRenderer: ViewRenderer < CameraPreview, UICameraPreview > {  
  11.         UICameraPreview uiCameraPreview;  
  12.         private AVCaptureOutput cameraOutput;  
  13.         private AVCaptureStillImageOutput stillImageOutput;  
  14.         protected override void OnElementChanged(ElementChangedEventArgs < CameraPreview > e) {  
  15.             base.OnElementChanged(e);  
  16.             if (e.OldElement != null) {  
  17.                 // Unsubscribe  
  18.                 uiCameraPreview.Tapped -= OnCameraPreviewTapped;  
  19.             }  
  20.             if (e.NewElement != null) {  
  21.                 if (Control == null) {  
  22.                     uiCameraPreview = new UICameraPreview(e.NewElement.Camera);  
  23.                     SetNativeControl(uiCameraPreview);  
  24.                 }  
  25.                 // Subscribe  
  26.                 uiCameraPreview.Tapped += OnCameraPreviewTapped;  
  27.             }  
  28.         }  
  29.         async void OnCameraPreviewTapped(object sender, EventArgs e) {  
  30.             if (uiCameraPreview.IsPreviewing) {  
  31.                 var videoConnection = uiCameraPreview.stillImageOutput.ConnectionFromMediaType(AVMediaType.Video);  
  32.                 var sampleBuffer = await uiCameraPreview.stillImageOutput.CaptureStillImageTaskAsync(videoConnection);  
  33.                 var jpegImageAsNsData = AVCaptureStillImageOutput.JpegStillToNSData(sampleBuffer);  
  34.                 var jpegAsByteArray = jpegImageAsNsData.ToArray(); // you will get output of image here.  
  35.                 uiCameraPreview.CaptureSession.StopRunning();  
  36.                 uiCameraPreview.IsPreviewing = false;  
  37.             } else {  
  38.                 uiCameraPreview.CaptureSession.StartRunning();  
  39.                 uiCameraPreview.IsPreviewing = true;  
  40.             }  
  41.         }  
  42.         protected override void Dispose(bool disposing) {  
  43.             if (disposing) {  
  44.                 Control.CaptureSession.Dispose();  
  45.                 Control.Dispose();  
  46.             }  
  47.             base.Dispose(disposing);  
  48.         }  
  49.     }  
  50. }  
UICameraPreview.cs
  1. using System;  
  2. using System.Linq;  
  3. using AVFoundation;  
  4. using CoreGraphics;  
  5. using Foundation;  
  6. using UIKit;  
  7. namespace CustomRenderer.iOS {  
  8.     public class UICameraPreview: UIView {  
  9.         AVCaptureVideoPreviewLayer previewLayer;  
  10.         CameraOptions cameraOptions;  
  11.         public AVCaptureStillImageOutput stillImageOutput;  
  12.         public event EventHandler < EventArgs > Tapped;  
  13.         public AVCaptureSession CaptureSession {  
  14.             get;  
  15.             private set;  
  16.         }  
  17.         public bool IsPreviewing {  
  18.             get;  
  19.             set;  
  20.         }  
  21.         public UICameraPreview(CameraOptions options) {  
  22.             cameraOptions = options;  
  23.             IsPreviewing = false;  
  24.             Initialize();  
  25.         }  
  26.         public override void LayoutSubviews() {  
  27.             base.LayoutSubviews();  
  28.             if (previewLayer != null) previewLayer.Frame = Bounds;  
  29.         }  
  30.         public override void TouchesBegan(NSSet touches, UIEvent evt) {  
  31.             base.TouchesBegan(touches, evt);  
  32.             OnTapped();  
  33.         }  
  34.         protected virtual void OnTapped() {  
  35.             var eventHandler = Tapped;  
  36.             if (eventHandler != null) {  
  37.                 eventHandler(thisnew EventArgs());  
  38.             }  
  39.         }  
  40.         void Initialize() {  
  41.             CaptureSession = new AVCaptureSession();  
  42.             previewLayer = new AVCaptureVideoPreviewLayer(CaptureSession) {  
  43.                 Frame = Bounds,  
  44.                     VideoGravity = AVLayerVideoGravity.ResizeAspectFill  
  45.             };  
  46.             var videoDevices = AVCaptureDevice.DevicesWithMediaType(AVMediaType.Video);  
  47.             var cameraPosition = (cameraOptions == CameraOptions.Front) ? AVCaptureDevicePosition.Front : AVCaptureDevicePosition.Back;  
  48.             var device = videoDevices.FirstOrDefault(d => d.Position == cameraPosition);  
  49.             if (device == null) {  
  50.                 return;  
  51.             }  
  52.             var dictionary = new NSMutableDictionary();  
  53.             dictionary[AVVideo.CodecKey] = new NSNumber((int) AVVideoCodec.JPEG);  
  54.             stillImageOutput = new AVCaptureStillImageOutput() {  
  55.                 OutputSettings = new NSDictionary()  
  56.             };  
  57.             CaptureSession.AddOutput(stillImageOutput);  
  58.             NSError error;  
  59.             var input = new AVCaptureDeviceInput(device, out error);  
  60.             CaptureSession.AddInput(input);  
  61.             Layer.AddSublayer(previewLayer);  
  62.             CaptureSession.StartRunning();  
  63.             IsPreviewing = true;  
  64.         }  
  65.     }  
  66. }  
I am not writing here for Android Platform Code.  You can download the code and check it out. The CameraPreviewRenderer Android file is there. 
 
Source Code Link.
 
Please comment if you found this useful for you, or ask any query and I will try to provide you with more details on your query.
 
Reference
  • https://guides.codepath.com/ios/Creating-a-Custom-Camera-View
  • https://devblogs.microsoft.com/xamarin/custom-camera-display-avfoundation/