Skip to main content
Language

To Camera Roll

VideoEditor SDK supports saving videos to the camera roll.

For the sake of this example, we create a video from a URL and present the video editor in a modal. Note, that we have to make the current class the delegate of the VideoEditViewController in order to handle export and cancellation there.

Implementing the Video Export Delegate Method#

When a video export is successful the method videoEditViewControllerDidFinish is invoked on the delegate class and a VideoEditorResult object is passed as an argument.

If no modifications have been made to the original video, we will not process the original video at all and also not reencode it. In this case, result.output.url will point to the original video that was passed to the editor, if available.

If you want to ensure that the original video is always reencoded, even if no modifications have been made to it, you can set VideoEditViewControllerOptions.forceExport to true, in which case result.output.url will always point to a newly generated video.

Request Authorization#

In order to access a user's camera roll we have to request access using the PHPhotoLibrary. We check the status that is passed to the closure to ascertain whether authorization has been granted and handle the case when it is denied. In a production app you would display an alert explicitly requesting that the user edit their settings to grant access.

Move to Shared Library#

Once access has been granted, we can perform changes in the shared video library. To that end we create a PHAssetCreationRequest and invoke the addResource method passing the video URL and options. If the options contain shouldMoveFile = true, this moves the video file to the shared library instead of copying it and saving the copy avoiding the need to manually delete the exported video file.

Note that the check we perform beforehand whether the video file was passed without changes handles a quirk of the simulator and is unnecessary in production.

Finally, we handle the completion of the change operation. Accessing the status arguments success and error allows us to log errors and display messages to our users before we dispatch to main queue and dismiss the editor.

import Photos
import UIKit
import VideoEditorSDK
class SaveVideoToCameraRollSwift: Example, VideoEditViewControllerDelegate {
override func invokeExample() {
// Create a `Video` from a URL to a video in the app bundle.
let video = Video(url: Bundle.main.url(forResource: "Skater", withExtension: "mp4")!)
// Create and present the video editor. Make this class the delegate of it to handle export and cancelation.
let videoEditViewController = VideoEditViewController(videoAsset: video)
videoEditViewController.delegate = self
videoEditViewController.modalPresentationStyle = .fullScreen
presentingViewController?.present(videoEditViewController, animated: true, completion: nil)
}
// MARK: - VideoEditViewControllerDelegate
func videoEditViewControllerShouldStart(_ videoEditViewController: VideoEditViewController, task: VideoEditorTask) -> Bool {
// Implementing this method is optional. You can perform additional validation and interrupt the process by returning `false`.
true
}
func videoEditViewControllerDidFinish(_ videoEditViewController: VideoEditViewController, result: VideoEditorResult) {
// The user exported a new video successfully and the newly generated video is located at `result.output.url`.
// If **no modifications** have been made to the original video, we will not process the original video at all
// and also not reencode it. In this case `result.output.url` will point to the original video that was passed to the editor,
// if available. If you want to ensure that the original video is always reencoded, even if no modifications have
// been made to it, you can set `VideoEditViewControllerOptions.forceExport` to `true`, in which case `result.output.url` will
// always point to a newly generated video.
// Request access to save to the user's camera roll.
PHPhotoLibrary.requestAuthorization(for: .addOnly) { [weak self] status in
if status != .authorized {
// Authorization hasn't been granted. In production you could now for example show an alert asking the user
// to open their Settings.app to grant permissions. Dismissing the editor.
print("Authorization to write to the camera roll has not been granted.")
self?.presentingViewController?.dismiss(animated: true, completion: nil)
return
}
// Perform changes in the shared photo library.
PHPhotoLibrary.shared().performChanges {
// Create a `PHAssetCreationRequest`.
let assetCreationRequest = PHAssetCreationRequest.forAsset()
// Move the video file instead of copying if possible, so that we don't have to delete it manually.
// If you wish to keep the original file, you don't need this.
// If the video wasn't modified, we won't move the file.
// In production this check would not be needed because the app bundle is read-only.
// Unfortunately, with the Simulator it is not read-only so we need to include this check
// or the example will crash when opened a second time.
let options = PHAssetResourceCreationOptions()
if result.status != .passedWithoutRendering {
options.shouldMoveFile = true
}
// Add the video file.
assetCreationRequest.addResource(with: .video, fileURL: result.output.url, options: options)
} completionHandler: { success, error in
if success {
print("Successfully saved video to camera roll.")
} else if let error = error {
print("Error saving video to camera roll: \(error)")
}
// Dispatching to the main queue and dismissing the editor.
DispatchQueue.main.async { [weak self] in
self?.presentingViewController?.dismiss(animated: true, completion: nil)
}
}
}
}
func videoEditViewControllerDidFail(_ videoEditViewController: VideoEditViewController, error: VideoEditorError) {
// There was an error generating the video.
print(error.localizedDescription)
// Dismissing the editor.
presentingViewController?.dismiss(animated: true, completion: nil)
}
func videoEditViewControllerDidCancel(_ videoEditViewController: VideoEditViewController) {
// The user tapped on the cancel button within the editor. Dismissing the editor.
presentingViewController?.dismiss(animated: true, completion: nil)
}
}