AV Foundation, 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?
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. -------------------------------------------------------------------------------------------------------------------------------------------
CameraOptions contains Enum :
public enum CameraOptions
{ Rear,
Front }
-------------------------------------------------------------------------------------------------------------------------------------------
Step 3: Now Using our own CamaraPreview in Xaml like below
<Grid
BackgroundColor="Transparent"
HorizontalOptions="FillAndExpand"
RowSpacing="0"
VerticalOptions="FillAndExpand">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="250" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<local:CameraPreview
Grid.Row="0"
Grid.Column="0"
Camera="Rear"
HeightRequest="300"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
WidthRequest="400" />
<Frame
Grid.Row="0"
Grid.Column="0"
BackgroundColor="Transparent"
BorderColor="White"
HeightRequest="100"
HorizontalOptions="Center"
VerticalOptions="Center"
WidthRequest="200" />
<StackLayout
Grid.Row="1"
Grid.Column="0"
BackgroundColor="Black"
Orientation="Vertical">
<Label
FontSize="Title"
HorizontalOptions="CenterAndExpand"
Text="Add Card"
TextColor="White" />
<Label
FontSize="Large"
HorizontalOptions="CenterAndExpand"
Text="Position your card in the frame"
TextColor="White" />
</StackLayout>
</Grid>
-------------------------------------------------------------------------------------------------------------------------------------------
Now the most important part to Create Renderer to write code in Platform part :
IOS
CameraPreviewRenderer & UICameraPreview
CameraPreviewRenderer.cs
using System;
using AVFoundation;
using CustomRenderer;
using CustomRenderer.iOS;
using Foundation;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;
[assembly: ExportRenderer(typeof(CameraPreview), typeof(CameraPreviewRenderer))]
namespace CodeXamarin.iOS
{
public class CameraPreviewRenderer : ViewRenderer<CameraPreview, UICameraPreview>
{
UICameraPreview uiCameraPreview;
private AVCaptureOutput cameraOutput;
private AVCaptureStillImageOutput stillImageOutput;
protected override void OnElementChanged(ElementChangedEventArgs<CameraPreview> e)
{
base.OnElementChanged(e);
if (e.OldElement != null)
{
// Unsubscribe
uiCameraPreview.Tapped -= OnCameraPreviewTapped;
}
if (e.NewElement != null)
{
if (Control == null)
{
uiCameraPreview = new UICameraPreview(e.NewElement.Camera);
SetNativeControl(uiCameraPreview);
}
// Subscribe
uiCameraPreview.Tapped += OnCameraPreviewTapped;
}
}
async void OnCameraPreviewTapped(object sender, EventArgs e)
{
if (uiCameraPreview.IsPreviewing)
{
var videoConnection = uiCameraPreview.stillImageOutput.ConnectionFromMediaType(AVMediaType.Video);
var sampleBuffer = await uiCameraPreview.stillImageOutput.CaptureStillImageTaskAsync(videoConnection);
var jpegImageAsNsData = AVCaptureStillImageOutput.JpegStillToNSData(sampleBuffer);
var jpegAsByteArray = jpegImageAsNsData.ToArray(); // you will get output of image here.
uiCameraPreview.CaptureSession.StopRunning();
uiCameraPreview.IsPreviewing = false;
}
else
{
uiCameraPreview.CaptureSession.StartRunning();
uiCameraPreview.IsPreviewing = true;
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
Control.CaptureSession.Dispose();
Control.Dispose();
}
base.Dispose(disposing);
}
}
}
UICameraPreview.cs
using System;
using System.Linq;
using AVFoundation;
using CoreGraphics;
using Foundation;
using UIKit;
namespace CustomRenderer.iOS
{
public class UICameraPreview : UIView
{
AVCaptureVideoPreviewLayer previewLayer;
CameraOptions cameraOptions;
public AVCaptureStillImageOutput stillImageOutput;
public event EventHandler<EventArgs> Tapped;
public AVCaptureSession CaptureSession { get; private set; }
public bool IsPreviewing { get; set; }
public UICameraPreview(CameraOptions options)
{
cameraOptions = options;
IsPreviewing = false;
Initialize();
}
public override void LayoutSubviews()
{
base.LayoutSubviews();
if (previewLayer != null)
previewLayer.Frame = Bounds;
}
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
base.TouchesBegan(touches, evt);
OnTapped();
}
protected virtual void OnTapped()
{
var eventHandler = Tapped;
if (eventHandler != null)
{
eventHandler(this, new EventArgs());
}
}
void Initialize()
{
CaptureSession = new AVCaptureSession();
previewLayer = new AVCaptureVideoPreviewLayer(CaptureSession)
{
Frame = Bounds,
VideoGravity = AVLayerVideoGravity.ResizeAspectFill
};
var videoDevices = AVCaptureDevice.DevicesWithMediaType(AVMediaType.Video);
var cameraPosition = (cameraOptions == CameraOptions.Front) ? AVCaptureDevicePosition.Front : AVCaptureDevicePosition.Back;
var device = videoDevices.FirstOrDefault(d => d.Position == cameraPosition);
if (device == null)
{ return; }
var dictionary = new NSMutableDictionary();
dictionary[AVVideo.CodecKey] = new NSNumber((int)AVVideoCodec.JPEG);
stillImageOutput = new AVCaptureStillImageOutput()
{ OutputSettings = new NSDictionary() };
CaptureSession.AddOutput(stillImageOutput);
NSError error;
var input = new AVCaptureDeviceInput(device, out error);
CaptureSession.AddInput(input);
Layer.AddSublayer(previewLayer);
CaptureSession.StartRunning();
IsPreviewing = true;
}
}
}
I am not writing here for Android Platform Code , You can download the code and check it out, CameraPreviewRenderer Android file is there. You can get more idea on that.
Full SourceCode Link
Please comment if you found it is useful for you, or ask any query i will try to provide you more details on your query.
Thank you
Thank you for your post. This is excellent information. It is amazing and wonderful to visit your site. For more info:- Xamarin App Development
ReplyDelete