Inheritance: NSObject, IAVCapturePhotoCaptureDelegate
		void CapturePhoto (UIButton photoButton)
		{
			// Retrieve the video preview layer's video orientation on the main queue before
			// entering the session queue. We do this to ensure UI elements are accessed on
			// the main thread and session configuration is done on the session queue.
			var videoPreviewLayerOrientation = PreviewView.VideoPreviewLayer.Connection.VideoOrientation;

			sessionQueue.DispatchAsync (() => {
				// Update the photo output's connection to match the video orientation of the video preview layer.
				var photoOutputConnection = photoOutput.ConnectionFromMediaType (AVMediaType.Video);
				if (photoOutputConnection != null)
					photoOutputConnection.VideoOrientation = videoPreviewLayerOrientation;

				// Capture a JPEG photo with flash set to auto and high resolution photo enabled.
				var photoSettings = AVCapturePhotoSettings.Create ();
				photoSettings.FlashMode = AVCaptureFlashMode.Auto;
				photoSettings.IsHighResolutionPhotoEnabled = true;
				// TODO: request strong typed API
				if (photoSettings.AvailablePreviewPhotoPixelFormatTypes.Length > 0)
					photoSettings.PreviewPhotoFormat = new NSDictionary<NSString, NSObject> (CVPixelBuffer.PixelFormatTypeKey, photoOutput.AvailablePhotoPixelFormatTypes [0]);
				// Live Photo capture is not supported in movie mode.
				if (livePhotoMode == LivePhotoMode.On && photoOutput.IsLivePhotoCaptureSupported) {
					var livePhotoMovieFileName = new NSUuid ().AsString ();
					var livePhotoMovieFilePath = Path.Combine (Path.GetTempPath (), Path.ChangeExtension (livePhotoMovieFileName, "mov"));
					photoSettings.LivePhotoMovieFileUrl = NSUrl.FromFilename (livePhotoMovieFilePath);
				}

				// Use a separate object for the photo capture delegate to isolate each capture life cycle.
				var photoCaptureDelegate = new PhotoCaptureDelegate (photoSettings, () => DispatchQueue.MainQueue.DispatchAsync (() => {
					PreviewView.VideoPreviewLayer.Opacity = 0;
					UIView.Animate (0.25, () => PreviewView.VideoPreviewLayer.Opacity = 1);
				}), capturing => {
					// Because Live Photo captures can overlap, we need to keep track of the
					// number of in progress Live Photo captures to ensure that the
					// Live Photo label stays visible during these captures.
					sessionQueue.DispatchAsync (() => {
						if (capturing)
							inProgressLivePhotoCapturesCount += 1;
						else
							inProgressLivePhotoCapturesCount -= 1;

						var count = inProgressLivePhotoCapturesCount;
						DispatchQueue.MainQueue.DispatchAsync (() => {
							if (count > 0)
								CapturingLivePhotoLabel.Hidden = false;
							else if (count == 0)
								CapturingLivePhotoLabel.Hidden = true;
							else
								Console.WriteLine ("Error: In progress live photo capture count is less than 0");
						});
					});
				}, photoDelegate => {
					// When the capture is complete, remove a reference to the photo capture delegate so it can be deallocated.
					sessionQueue.DispatchAsync (() => inProgressPhotoCaptureDelegates.Remove (photoDelegate.RequestedPhotoSettings.UniqueID));
				});

				// The Photo Output keeps a weak reference to the photo capture delegate so
				// we store it in an array to maintain a strong reference to this object
				// until the capture is completed.
				inProgressPhotoCaptureDelegates [photoCaptureDelegate.RequestedPhotoSettings.UniqueID] = photoCaptureDelegate;
				photoOutput.CapturePhoto (photoSettings, photoCaptureDelegate);
			});
		}
        void CapturePhoto(UIButton photoButton)
        {
            // Retrieve the video preview layer's video orientation on the main queue before
            // entering the session queue. We do this to ensure UI elements are accessed on
            // the main thread and session configuration is done on the session queue.
            var videoPreviewLayerOrientation = PreviewView.VideoPreviewLayer.Connection.VideoOrientation;

            sessionQueue.DispatchAsync(() => {
                // Update the photo output's connection to match the video orientation of the video preview layer.
                var photoOutputConnection = photoOutput.ConnectionFromMediaType(AVMediaType.Video);
                if (photoOutputConnection != null)
                {
                    photoOutputConnection.VideoOrientation = videoPreviewLayerOrientation;
                }

                // Capture a JPEG photo with flash set to auto and high resolution photo enabled.
                var photoSettings       = AVCapturePhotoSettings.Create();
                photoSettings.FlashMode = AVCaptureFlashMode.Auto;
                photoSettings.IsHighResolutionPhotoEnabled = true;
                // TODO: request strong typed API
                if (photoSettings.AvailablePreviewPhotoPixelFormatTypes.Length > 0)
                {
                    photoSettings.PreviewPhotoFormat = new NSDictionary <NSString, NSObject> (CVPixelBuffer.PixelFormatTypeKey, photoOutput.AvailablePhotoPixelFormatTypes [0]);
                }
                // Live Photo capture is not supported in movie mode.
                if (livePhotoMode == LivePhotoMode.On && photoOutput.IsLivePhotoCaptureSupported)
                {
                    var livePhotoMovieFileName          = new NSUuid().AsString();
                    var livePhotoMovieFilePath          = Path.Combine(Path.GetTempPath(), Path.ChangeExtension(livePhotoMovieFileName, "mov"));
                    photoSettings.LivePhotoMovieFileUrl = NSUrl.FromFilename(livePhotoMovieFilePath);
                }

                // Use a separate object for the photo capture delegate to isolate each capture life cycle.
                var photoCaptureDelegate = new PhotoCaptureDelegate(photoSettings, () => DispatchQueue.MainQueue.DispatchAsync(() => {
                    PreviewView.VideoPreviewLayer.Opacity = 0;
                    UIView.Animate(0.25, () => PreviewView.VideoPreviewLayer.Opacity = 1);
                }), capturing => {
                    // Because Live Photo captures can overlap, we need to keep track of the
                    // number of in progress Live Photo captures to ensure that the
                    // Live Photo label stays visible during these captures.
                    sessionQueue.DispatchAsync(() => {
                        if (capturing)
                        {
                            inProgressLivePhotoCapturesCount += 1;
                        }
                        else
                        {
                            inProgressLivePhotoCapturesCount -= 1;
                        }

                        var count = inProgressLivePhotoCapturesCount;
                        DispatchQueue.MainQueue.DispatchAsync(() => {
                            if (count > 0)
                            {
                                CapturingLivePhotoLabel.Hidden = false;
                            }
                            else if (count == 0)
                            {
                                CapturingLivePhotoLabel.Hidden = true;
                            }
                            else
                            {
                                Console.WriteLine("Error: In progress live photo capture count is less than 0");
                            }
                        });
                    });
                }, photoDelegate => {
                    // When the capture is complete, remove a reference to the photo capture delegate so it can be deallocated.
                    sessionQueue.DispatchAsync(() => inProgressPhotoCaptureDelegates.Remove(photoDelegate.RequestedPhotoSettings.UniqueID));
                });

                // The Photo Output keeps a weak reference to the photo capture delegate so
                // we store it in an array to maintain a strong reference to this object
                // until the capture is completed.
                inProgressPhotoCaptureDelegates [photoCaptureDelegate.RequestedPhotoSettings.UniqueID] = photoCaptureDelegate;
                photoOutput.CapturePhoto(photoSettings, photoCaptureDelegate);
            });
        }