So, I want to be able to switch between the front and rear camera while the video is being recorded, and without any interruption in the video stream. I notice that even the iOS built-in camera app doesn't do this, but I've heard that some third-party apps do. Below is the sample code in xamarin.ios.
AVCaptureMovieFileOutput movieFileOutput;
AVCaptureDevice CurrentCamera { get; set; }
AVCaptureDevice BackCamera { get; set; }
AVCaptureDevice FrontCamera { get; set; }
AVCaptureDevice Mic { get; set; }
bool HasBackCamera { get { return BackCamera != null; } }
bool HasFrontCamera { get { return FrontCamera != null; } }
bool HasMic { get { return Mic != null; } }
void SetDeviceProperties()
{
//Set up the devices
foreach(var device in AVCaptureDevice.DevicesWithMediaType(AVMediaType.Video))
{
if(device.Position == AVCaptureDevicePosition.Back)
{
BackCamera = device;
}
else
{
FrontCamera = device;
}
}
Mic = AVCaptureDevice.DefaultDeviceWithMediaType(AVMediaType.Audio);
}
public bool SwapCameras()
{
if(HasBackCamera && HasFrontCamera)
{
var nextCamera = CurrentCamera == BackCamera ? FrontCamera : BackCamera;
NSError error = null;
var newInput = new AVCaptureDeviceInput(nextCamera, out error);
if(error != null)
{
throw new Exception(error.ToString());
}
session.BeginConfiguration();
//Remove current video input
foreach(AVCaptureDeviceInput input in session.Inputs)
{
if(input.Device.HasMediaType(AVMediaType.Video))
{
session.RemoveInput(input);
}
}
if(session.CanAddInput(newInput))
{
session.AddInput(newInput);
}
session.CommitConfiguration();
CurrentCamera = nextCamera;
CameraConfigured(this, new TArgs<AVCaptureDevice>(CurrentCamera));
}
return CurrentCamera == FrontCamera;
}
Below is the configuration of the output of the video
var layer = new AVCaptureVideoPreviewLayer (session);
layer.VideoGravity = AVLayerVideoGravity.ResizeAspectFill;
var cameraView = new UIView ();
cameraView.Layer.AddSublayer (layer);
var filePath = Path.Combine (Path.GetTempPath (), "temporary.mov");
var fileUrl = NSUrl.FromFilename (filePath);
var movieFileOutput = new AVCaptureMovieFileOutput ();
var recordingDelegate = new MyRecordingDelegate ();
session.AddOutput (movieFileOutput);
movieFileOutput.StartRecordingToOutputFile (fileUrl, recordingDelegate);
Delegate that is called when the recording is stopped(from the removeInput of the first session):
public class MyRecordingDelegate : AVCaptureFileOutputRecordingDelegate
{
public override void FinishedRecording (AVCaptureFileOutput captureOutput, NSUrl outputFileUrl, NSObject [] connections, NSError error)
{
if (UIVideo.IsCompatibleWithSavedPhotosAlbum (outputFileUrl.Path))
{
var library = new ALAssetsLibrary ();
library.WriteVideoToSavedPhotosAlbum (outputFileUrl, (path, e2) =>
{
if (e2 != null)
{
new UIAlertView ("Error", e2.ToString (), null, "OK", null).Show ();
}
else
{
new UIAlertView ("Saved", "Saved to Photos", null, "OK", null).Show ();
File.Delete (outputFileUrl.Path);
}
});
}
else
{
new UIAlertView ("Incompatible", "Incompatible", null, "OK", null).Show ();
}
}
}
So is this really possible and If so, how would I change the code above to not stop the recording while I switch the camera?