How to convert video (in gallery) to NSData? in Swift

2 Solutions Collect From Internet About “How to convert video (in gallery) to NSData? in Swift”

Xcode 8.3 • Swift 3.1

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String: Any]) {
    let documentsDirectoryURL =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    if let fileURL =  info[UIImagePickerControllerMediaURL] as? URL {
        do {
            try  FileManager.default.moveItem(at: fileURL, to: documentsDirectoryURL.appendingPathComponent("videoName").appendingPathExtension("mov"))
            print("movie saved")
        } catch {
            print(error)
        }
    }
}

Swift 2

You should use if let to unwrap your optionals. Also NSData.dataWithContentsOfMappedFile was deprecated iOS8. Try using NSData method initializer contentsOfURL:

Note: You need also to change the didFinishPickingMediaWithInfo declaration from [NSObject : AnyObject] to [String : AnyObject]

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
    if let fileURL = info[UIImagePickerControllerMediaURL] as? NSURL {
        if let videoData = NSData(contentsOfURL: fileURL) {
            print(videoData.length)
        }
    }
}

as mentioned by Rob the data can be really large but instead of copying the file you should move the file to the documents folder as follow:

let documentsDirectoryURL =  try! NSFileManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: true)
if let fileURL =  info[UIImagePickerControllerMediaURL] as? NSURL {
    do {
        try  NSFileManagerdefaultManager().moveItemAtURL(fileURL, toURL: documentsDirectoryURL.URLByAppendingPathComponent("videoName").URLByAppendingPathExtension("mov"))
        print("movie saved")
    } catch let error as NSError {
        print(error.localizedDescription)
    }
}

There are a couple of issues:

  1. Consider this line:

    var videoDataURL = info[UIImagePickerControllerMediaURL] as! NSURL!
    

    This does a forced unwrapping of info[UIImagePickerControllerMediaURL] (which is bad, because if it was nil, the app would crash) and that casts it as an implicitly unwrapped optional NSURL!. That doesn’t make sense. Just do a conditional unwrapping (and unwrap to a NSURL, not a NSURL!):

    if let videoDataURL = info[UIImagePickerControllerMediaURL] as? NSURL { ... }
    
  2. The next line calls filePathURL:

    var videoFileURL = videoDataURL.filePathURL
    

    If you wanted a file URL, you already have one, so no conversion is needed, but instead just use videoDataURL. If you really wanted a path, you’d use path method:

    let videoPath = videoDataURL.path
    

    Frankly, Apple is trying to shift us away from using string paths, so just use the original videoDataURL and avoid the use of both path and filePathURL.

  3. You are using dataWithContentsOfMappedFile:

    var video = NSData.dataWithContentsOfMappedFile("\(videoDataURL)")
    

    If you really wanted to use dataWithContentsOfMappedFile, the proper Swift syntax is:

    let video = NSData(contentsOfMappedFile: videoPath!)
    

    But dataWithContentsOfMappedFile deprecated, so you should instead use:

    let video = try NSData(contentsOfFile: videoPath!, options: .DataReadingMappedIfSafe)
    

    Or, bypassing that videoPath altogether, you could:

    let video3 = try NSData(contentsOfURL: videoDataURL, options: .DataReadingMappedIfSafe)
    

    Obviously, those try renditions should be done within a do block with a catch block.

  4. By the way, as you’ll see in all of my above examples, one should use let where possible.

Quite frankly, I would advise against loading it into a NSData at all. Just copy it with NSFileManager, which is a more efficient use of memory. If the video is long, it could be quite large, and you should avoid loading the whole thing into memory at any given point in time.

So you could:

if let videoDataURL = info[UIImagePickerControllerMediaURL] as? NSURL {
    do {
        // build your destination URL however you want
        //
        // let tempFolder = NSURL(fileURLWithPath: NSTemporaryDirectory())
        // let destinationURL = tempFolder.URLByAppendingPathComponent("test.mov")

        // or 

        let documents = try NSFileManager.defaultManager().URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
        let destinationURL = documents.URLByAppendingPathComponent("test.mov")

        // but just copy from the video URL to the destination URL

        try NSFileManager.defaultManager().copyItemAtURL(videoDataURL, toURL: destinationURL)
    } catch {
        print(error)
    }
}

If you’re uploading this to a web service, you’d then use a NSURLSessionUploadTask, using file or stream options. The construction of this request is a separate question, but hopefully you get the idea: With large assets like photos or, especially, videos, don’t instantiate a NSData with the asset if you can possibly avoid it.