Swift: Save Video from Nsurl to User Camera Roll

Download and Save Video to Camera Roll

Unfortunately there is a bug related to UISaveVideoAtPathToSavedPhotosAlbum and the format mp4, which is the format used by Instagram.

There is a helper method called UIVideoAtPathIsCompatibleWithSavedPhotosAlbum to help indicate whether a video is compatible with the method UISaveVideoAtPathToSavedPhotosAlbum. This returns false for the video downloaded from Instagram.


Luckily it is still possible to store the videos into the camera roll. This is possible using ALAssetsLibrary. I've tried to take your sample code and adapt it to use ALAssetsLibrary, hopefully this can help you to get it working.

import AssetsLibrary

...
...

func downloadVideoToCameraRoll() {

// Local variable pointing to the local file path for the downloaded video
var localFileUrl: String?

// A closure for generating the local file path for the downloaded video. This will be pointing to the Documents directory with a unique UDID file name.
let destination: (NSURL, NSHTTPURLResponse) -> (NSURL) = {
(temporaryURL, response) in

if let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as? NSURL {
let finalPath = directoryURL.URLByAppendingPathComponent("\(NSUUID()).\(response.suggestedFilename!)")
localFileUrl = finalPath.absoluteString
return finalPath
}

return temporaryURL
}

// The media post which should be downloaded
let postURL = NSURL(string: "https://api.instagram.com/v1/media/" + "952201134785549382_250131908" + "?access_token=" + InstagramEngine.sharedEngine().accessToken)!

// Then some magic happens that turns the postURL into the videoURL, which is the actual url of the video media:
let videoURL = NSURL(string: "https://scontent.cdninstagram.com/hphotos-xfp1/t50.2886-16/11104555_1603400416544760_416259564_s.mp4")!

// Download starts
let request = Alamofire.download(.GET, videoURL, destination)

// Completion handler for the download
request.response { (request, response, data, error) -> Void in
if let path = localFileUrl {
let isVideoCompatible = UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(path)
println("bool: \(isVideoCompatible)") // This logs out "bool: false"

let library = ALAssetsLibrary()

library.writeVideoAtPathToSavedPhotosAlbum(NSURL(string: path), completionBlock: { (url, error) -> Void in
// Done! Go check your camera roll
})
}
}
}

How can i save a video to the camera roll with a specific date?

It's quite easy, you need to pass the Date while daving the PHAsset.

PHPhotoLibrary.shared().performChanges({
let changeRequest = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoUrl)
changeRequest.creationDate = Date() //Pass whichever Date you want
}) { (success, error) in
debugPrint(success)
debugPrint(error)
}

How to save a video from my app in to the users photo library in iOS?

You can save the video to the gallery using UISaveVideoAtPathToSavePhotosAlbum
This function adds videos to the user's camera roll album in the specified path.

func UISaveVideoAtPathToSavedPhotosAlbum(_ videoPath: String, 
_ completionTarget: Any?,
_ completionSelector: Selector?,
_ contextInfo: UnsafeMutableRawPointer?)

In VideoPath, insert the path of the video you want to save.

In addition, you can first use the function UIVideoAtPathCompatibleWithSavedPhotosAlbum(_:) to check for unsaved errors to see if the video can be stored in the gallery.

For more information, see the apple developer site.

Save video to the gallery and get the path for the video stored to Gallery

This worked for me perfectly.

Swift 3.1 ->

PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: url!)
}) { saved, error in
if saved {
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]

// After uploading we fetch the PHAsset for most recent video and then get its current location url

let fetchResult = PHAsset.fetchAssets(with: .video, options: fetchOptions).lastObject
PHImageManager().requestAVAsset(forVideo: fetchResult!, options: nil, resultHandler: { (avurlAsset, audioMix, dict) in
let newObj = avurlAsset as! AVURLAsset
print(newObj.url)
// This is the URL we need now to access the video from gallery directly.
})
}
}

Swift - Download a video from distant URL and save it in an photo album

Update

Wanted to update the answer for Swift 3 using URLSession and figured out that the answer already exists in related topic here. Use it.

Original Answer

The code below saves a video file to Camera Roll. I reused your code with a minor change - I removed let fileName = videoImageUrl; because it leads to incorrect file path.

I tested this code and it saved the asset into camera roll. You asked what to place into creationRequestForAssetFromVideoAtFileURL - put a link to downloaded video file as in the example below.

let videoImageUrl = "http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4"

DispatchQueue.global(qos: .background).async {
if let url = URL(string: urlString),
let urlData = NSData(contentsOf: url) {
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0];
let filePath="\(documentsPath)/tempFile.mp4"
DispatchQueue.main.async {
urlData.write(toFile: filePath, atomically: true)
PHPhotoLibrary.shared().performChanges({
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: filePath))
}) { completed, error in
if completed {
print("Video is saved!")
}
}
}
}
}

Save video in Photo Library Swift

  • Use following func to save video to documents directory

    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [NSObject : AnyObject]) 
    {
    // *** store the video URL returned by UIImagePickerController *** //
    let videoURL = info[UIImagePickerControllerMediaURL] as! NSURL

    // *** load video data from URL *** //
    let videoData = NSData(contentsOfURL: videoURL)

    // *** Get documents directory path *** //
    let paths = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory, NSSearchPathDomainMask.UserDomainMask, true)[0]

    // *** Append video file name *** //
    let dataPath = documentsDirectory.stringByAppendingPathComponent("/videoFileName.mp4")

    // *** Write video file data to path *** //
    videoData?.writeToFile(dataPath, atomically: false)
    }
  • now save this video in photo gellary

    PHPhotoLibrary.shared().performChanges({
    PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: Your document directory file)
    }) { saved, error in
    if saved {
    let fetchOptions = PHFetchOptions()
    fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]

    let fetchResult = PHAsset.fetchAssets(with: .video, options: fetchOptions).firstObject
    // fetchResult is your latest video PHAsset
    // To fetch latest image replace .video with .image
    }
    }

after it if you don't need then delete the image from document directory
, I hope it will work for you ...:)

How to save a video from AVAssetExportSession to Camera Roll?

You can't save your video directly to the camera roll simply by using session.outputURL = .... You'll have to save the video to a file path (temporary or otherwise) then write the video at that url to your camera roll using writeVideoAtPathToSavedPhotosAlbum:, ex:

var exportPath: NSString = NSTemporaryDirectory().stringByAppendingFormat("/video.mov")
var exportUrl: NSURL = NSURL.fileURLWithPath(exportPath)!

var exporter = AVAssetExportSession(asset: myasset, presetName: AVAssetExportPresetHighestQuality)
exporter.outputURL = exportUrl

exporter.exportAsynchronouslyWithCompletionHandler({
let library = ALAssetsLibrary()
library.writeVideoAtPathToSavedPhotosAlbum(exportURL, completionBlock: { (assetURL:NSURL!, error:NSError?) -> Void in
// ...
})
})


Related Topics



Leave a reply



Submit