Reputation: 41
Currently when I tap capture photo button it takes a photo and the preview pops up and I can save the photo to my camera roll.
I want to do the same thing with video, but I am having trouble getting video to record or even know how to get started.
I have used button.addTarget(self, action: #selector(handleCaptureVideo), for: .touchDown)
and it prints "Video is recording..." so I see it working but I don't know what to put in there to get video to actually start recording.
import UIKit
import AVFoundation
class cameraController: UIViewController, AVCapturePhotoCaptureDelegate {
let capturePhotoButton: UIButton = {
let button = UIButton(type: .system)
button.setImage(#imageLiteral(resourceName: "capture_photo"), for: .normal)
button.addTarget(self, action: #selector(handleCapturePhoto), for: .touchUpInside)
button.addTarget(self, action: #selector(handleCaptureVideo), for: .touchDown)
return button
}()
let settingsButton: UIButton = {
let button = UIButton(type: .system)
button.setImage(#imageLiteral(resourceName: "gear"), for: .normal)
button.addTarget(self, action: #selector(handleSettings), for: .touchUpInside)
return button
}()
let cameraFlipButton: UIButton = {
let button = UIButton(type: .system)
button.setImage(#imageLiteral(resourceName: "right_arrow_shadow"), for: .normal)
button.addTarget(self, action: #selector(handleReversingCamera), for: .touchUpInside)
return button
}()
override func viewDidLoad() {
super.viewDidLoad()
setupCameraSession()
setupHUD()
handleSettings()
handleReversingCamera()
}
override var prefersStatusBarHidden: Bool {
return true
}
fileprivate func setupHUD() {
view.addSubview(capturePhotoButton)
capturePhotoButton.anchor(top: nil, left: nil, bottom: view.bottomAnchor, right: nil, paddingTop: 0, paddingLeft: 0, paddingBottom: 24, paddingRight: 0, width: 80, height: 80)
capturePhotoButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
}
@objc func handleCaptureVideo() {
print("Video is recording...")
}
@objc func handleCapturePhoto() {
print("Capturing Photo...")
let settings = AVCapturePhotoSettings()
guard let previewFormatType = settings.availablePreviewPhotoPixelFormatTypes.first else { return }
settings.previewPhotoFormat = [kCVPixelBufferPixelFormatTypeKey as String: previewFormatType]
output.capturePhoto(with: settings, delegate: self)
}
@objc func handleReversingCamera() {
view.addSubview(cameraFlipButton)
cameraFlipButton.anchor(top: nil, left: nil, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 48, paddingRight: 24, width: 50, height: 50)
print("Camera just flipped...")
}
@objc func handleSettings() {
view.addSubview(settingsButton)
settingsButton.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: nil, right: nil, paddingTop: 12, paddingLeft: 12, paddingBottom: 0, paddingRight: 0, width: 50, height: 50)
let goToSettings = settingsViewController()
let settingsController = UINavigationController(rootViewController: goToSettings)
present(settingsController, animated: true, completion: nil)
print("Settings Opened Up...")
}
func photoOutput(_ captureOutput: AVCapturePhotoOutput, didFinishProcessingPhoto photoSampleBuffer:
CMSampleBuffer?, previewPhoto previewPhotoSampleBuffer: CMSampleBuffer?, resolvedSettings: AVCaptureResolvedPhotoSettings, bracketSettings: AVCaptureBracketedStillImageSettings?, error: Error?) {
let imageData = AVCapturePhotoOutput.jpegPhotoDataRepresentation(forJPEGSampleBuffer: photoSampleBuffer!, previewPhotoSampleBuffer: previewPhotoSampleBuffer!)
let previewImage = UIImage(data: imageData!)
let containerView = PreviewPhotoContainerView()
containerView.previewImageView.image = previewImage
view.addSubview(containerView)
containerView.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
/* let previewImageView = UIImageView(image: previewImage)
view.addSubview(previewImageView)
previewImageView.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: view.bottomAnchor, right: view.rightAnchor, paddingTop: 0, paddingLeft: 0, paddingBottom: 0, paddingRight: 0, width: 0, height: 0)
print("Did finish processing sample image buffer") */
}
// Capture Photo
let output = AVCapturePhotoOutput()
fileprivate func setupCameraSession() {
let captureSession = AVCaptureSession()
// 1. Setup Inputs
let captureDevice = AVCaptureDevice.default(for: AVMediaType.video)
do {
let input = try AVCaptureDeviceInput(device: captureDevice!)
if captureSession.canAddInput(input) {
captureSession.addInput(input)
}
} catch let err {
print("Could not print camera input:", err)
}
// 2. Setup Output
if captureSession.canAddOutput(output) {
captureSession.addOutput(output)
}
// 3. Setup Output Preview
let previewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
previewLayer.frame = view.frame
view.layer.addSublayer(previewLayer)
previewLayer.videoGravity = .resizeAspectFill
captureSession.startRunning()
}
Upvotes: 2
Views: 3980
Reputation: 3488
You need to use AVCaptureMovieFileOutput
and add it to your capture session. To use the same button - you could have a long tap gesture recognizer on the button and start recording when long tap and stop recording when releasing the long tap. Something like Instagram stories.
Add movie file output
var movieFileOutput = AVCaptureMovieFileOutput()
captureSession?.addOutput(movieFileOutput)
Add long press gesture to your button
let longPressGesture = UILongPressGestureRecognizer.init(target: self, action: #selector(handleLongPress))
self.capturePhotoButton.addGestureRecognizer(longPressGesture);
Start and stop recording video on long tap
func handleLongPress(gestureRecognizer: UILongPressGestureRecognizer) {
if gestureRecognizer.state == UIGestureRecognizerState.began {
debugPrint("long press started")
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as URL
let filePath = documentsURL.appendingPathComponent("tempMovie.mp4")
if FileManager.default.fileExists(atPath: filePath.absoluteString) {
do {
try FileManager.default.removeItem(at: filePath)
}
catch {
// exception while deleting old cached file
// ignore error if any
}
}
movieFileOutput?.startRecording(toOutputFileURL: filePath, recordingDelegate: self)
}
else if gestureRecognizer.state == UIGestureRecognizerState.ended {
debugPrint("longpress ended")
movieFileOutput?.stopRecording()
}
}
Upvotes: 4