Hi I followed a course by Jared Davidson to create a custom camera view and save pictures using AVFoundation. https://www.youtube.com/watch?v=w0O3ZGUS3pk
However I would
For the sound recording issue,
Add this code when creating the captureSession
askMicroPhonePermission(completion: { (isMicrophonePermissionGiven) in
if isMicrophonePermissionGiven {
do {
try self.captureSession.addInput(AVCaptureDeviceInput(device: self.captureAudio))
} catch {
print("Error creating the database")
}
}
})
////////////////////////////////////////////////////////////////
askMicroPhonePermission function is as follows
func askMicroPhonePermission(completion: @escaping (_ success: Bool)-> Void) {
switch AVAudioSession.sharedInstance().recordPermission() {
case AVAudioSessionRecordPermission.granted:
completion(true)
case AVAudioSessionRecordPermission.denied:
completion(false) //show alert if required
case AVAudioSessionRecordPermission.undetermined:
AVAudioSession.sharedInstance().requestRecordPermission({ (granted) in
if granted {
completion(true)
} else {
completion(false) // show alert if required
}
})
default:
completion(false)
}
}
And you have to add NSMicrophoneUsageDescription key value in info.plist file.
func getCurrentFrame(url:String) -> UIImage? {
let asset = AVAsset(url: URL(string: url)!)
let assetImgGenerate = AVAssetImageGenerator(asset: asset)
assetImgGenerate.appliesPreferredTrackTransform = true
//Can set this to improve performance if target size is known before hand
//assetImgGenerate.maximumSize = CGSize(width,height)
let time = CMTimeMakeWithSeconds(1.0, preferredTimescale: 600)
do {
let img = try assetImgGenerate.copyCGImage(at: time, actualTime: nil)
let thumbnail = UIImage(cgImage: img)
return thumbnail
} catch {
print(error.localizedDescription)
return nil
}
}
after if (device as AnyObject).position == AVCaptureDevicePosition.front{
add
// Audio Input
let audioInputDevice = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio)
do
{
let audioInput = try AVCaptureDeviceInput(device: audioInputDevice)
// Add Audio Input
if captureSession.canAddInput(audioInput)
{
captureSession.addInput(audioInput)
}
else
{
NSLog("Can't Add Audio Input")
}
}
catch let error
{
NSLog("Error Getting Input Device: \(error)")
}
Thanks
Thank you for this. It was very helpful to me. Here is a version of Rhythmic Fistman's answer ported to Swift 3 with the required import statements and delegate methods.
import UIKit
import AVFoundation
class ViewController: UIViewController,
AVCaptureFileOutputRecordingDelegate {
var captureSession = AVCaptureSession()
var sessionOutput = AVCaptureStillImageOutput()
var movieOutput = AVCaptureMovieFileOutput()
var previewLayer = AVCaptureVideoPreviewLayer()
@IBOutlet var cameraView: UIView!
override func viewWillAppear(_ animated: Bool) {
self.cameraView = self.view
let devices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo)
for device in devices! {
if (device as AnyObject).position == AVCaptureDevicePosition.front{
do{
let input = try AVCaptureDeviceInput(device: device as! AVCaptureDevice)
if captureSession.canAddInput(input){
captureSession.addInput(input)
sessionOutput.outputSettings = [AVVideoCodecKey : AVVideoCodecJPEG]
if captureSession.canAddOutput(sessionOutput){
captureSession.addOutput(sessionOutput)
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.portrait
cameraView.layer.addSublayer(previewLayer)
previewLayer.position = CGPoint(x: self.cameraView.frame.width / 2, y: self.cameraView.frame.height / 2)
previewLayer.bounds = cameraView.frame
}
captureSession.addOutput(movieOutput)
captureSession.startRunning()
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let fileUrl = paths[0].appendingPathComponent("output.mov")
try? FileManager.default.removeItem(at: fileUrl)
movieOutput.startRecording(toOutputFileURL: fileUrl, recordingDelegate: self)
let delayTime = DispatchTime.now() + 5
DispatchQueue.main.asyncAfter(deadline: delayTime) {
print("stopping")
self.movieOutput.stopRecording()
}
}
}
catch{
print("Error")
}
}
}
}
//MARK: AVCaptureFileOutputRecordingDelegate Methods
func capture(_ captureOutput: AVCaptureFileOutput!, didStartRecordingToOutputFileAt fileURL: URL!, fromConnections connections: [Any]!) {
}
func capture(_ captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAt outputFileURL: URL!, fromConnections connections: [Any]!, error: Error!) {
print("FINISHED \(error)")
// save video to camera roll
if error == nil {
UISaveVideoAtPathToSavedPhotosAlbum(outputFileURL.path, nil, nil, nil)
}
}
}
you can use this code to save your videos in the photo library , You have to give the follwing parameters in which the most important is OutputURL.path which is filesystem path to the movie file you want to save to the Camera Roll album , For the rest of the parameters you can either pass there respective values or you can also assign nil that depends on your need
func fileOutput(_ output: AVCaptureFileOutput, didFinishRecordingTo outputFileURL: URL, from connections: [AVCaptureConnection], error: Error?) {
if (error != nil) {
print("Error recording movie: \(error!.localizedDescription)")
} else {
UISaveVideoAtPathToSavedPhotosAlbum(outputFileURL.path, nil, #selector(CameraController.video(_:didFinishSavingWithError:contextInfo:)), nil)
}
outputURL = nil
}
You can save record your video to file by creating and adding an AVCaptureMovieFileOutput
to your capture session, and making your ViewController
conform to the AVCaptureFileOutputRecordingDelegate
.
This example records 5 seconds of video to a file called "output.mov" in the app's Documents directory.
class ViewController: UIViewController, AVCaptureFileOutputRecordingDelegate {
var captureSession = AVCaptureSession()
var sessionOutput = AVCaptureStillImageOutput()
var movieOutput = AVCaptureMovieFileOutput()
var previewLayer = AVCaptureVideoPreviewLayer()
@IBOutlet var cameraView: UIView!
override func viewWillAppear(animated: Bool) {
self.cameraView = self.view
let devices = AVCaptureDevice.devicesWithMediaType(AVMediaTypeVideo)
for device in devices {
if device.position == AVCaptureDevicePosition.Front{
do{
let input = try AVCaptureDeviceInput(device: device as! AVCaptureDevice)
if captureSession.canAddInput(input){
captureSession.addInput(input)
sessionOutput.outputSettings = [AVVideoCodecKey : AVVideoCodecJPEG]
if captureSession.canAddOutput(sessionOutput){
captureSession.addOutput(sessionOutput)
previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill
previewLayer.connection.videoOrientation = AVCaptureVideoOrientation.Portrait
cameraView.layer.addSublayer(previewLayer)
previewLayer.position = CGPoint(x: self.cameraView.frame.width / 2, y: self.cameraView.frame.height / 2)
previewLayer.bounds = cameraView.frame
}
captureSession.addOutput(movieOutput)
captureSession.startRunning()
let paths = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
let fileUrl = paths[0].URLByAppendingPathComponent("output.mov")
try? NSFileManager.defaultManager().removeItemAtURL(fileUrl)
movieOutput.startRecordingToOutputFileURL(fileUrl, recordingDelegate: self)
let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(5 * Double(NSEC_PER_SEC)))
dispatch_after(delayTime, dispatch_get_main_queue()) {
print("stopping")
self.movieOutput.stopRecording()
}
}
}
catch{
print("Error")
}
}
}
}
func captureOutput(captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAtURL outputFileURL: NSURL!, fromConnections connections: [AnyObject]!, error: NSError!) {
print("FINISHED \(error)")
// save video to camera roll
if error == nil {
UISaveVideoAtPathToSavedPhotosAlbum(outputFileURL.path!, nil, nil, nil)
}
}
}