Ben Heutmaker Ben Heutmaker - 6 months ago 79
Swift Question

Play video downloaded through CloudKit as CKAsset - iOS

I'm making an app that records video, uploads it to iCloud using CloudKit with a CKAsset, then downloads the file and plays it in an AVPlayer. This is all written in Swift 2.0

I have gotten the data downloaded, and I think I've been able to reference it but I'm not sure. Data/garbage does print when I convert the URL into an NSData object and print it to the console. The video files gets downloaded as a binary file however. I was able to go to the CloudKit dashboard and download the file and append '.mov' to it, and it opened in Quicktime no problem.

So I think my main issue is that I can't work out how to get the video file to actually play, since the file has no extension. I have tried appending '.mov' to the end with URLByAppendingPathExtension() to no avail. Let me know of any ideas!

Upload Video

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
let tempURL = info[UIImagePickerControllerMediaURL] as! NSURL

dismissViewControllerAnimated(true) { () -> Void in
self.uploadVideoToiCloud(tempURL)
print("\n Before Upload: \(tempURL)\n")
}
}

func uploadVideoToiCloud(url: NSURL) {
let videoRecord = CKRecord(recordType: "video", recordID: id)

videoRecord["title"] = "This is the title"

let videoAsset = CKAsset(fileURL: url)
videoRecord["video"] = videoAsset

CKContainer.defaultContainer().privateCloudDatabase.saveRecord(videoRecord) { (record, error) -> Void in
dispatch_async(dispatch_get_main_queue(), { () -> Void in
if error == nil {
print("upload successful")

} else {
print(error!)
}
})
}
}


Download Video

func downloadVideo(id: CKRecordID) {

privateDatabase.fetchRecordWithID(id) { (results, error) -> Void in

dispatch_async(dispatch_get_main_queue()) { () -> Void in
if error != nil {

print(" Error Fetching Record " + error!.localizedDescription)
} else {
if results != nil {
print("pulled record")

let record = results!
let videoFile = record.objectForKey("video") as! CKAsset

self.videoURL = videoFile.fileURL

print(" After Download: \(self.videoURL!)")

self.videoAsset = AVAsset(URL: self.videoURL!)
self.playVideo()

} else {
print("results Empty")
}
}
}
}
}

Answer

Solution ended up being that I forgot to specify the filename before I wrote the data to it. I was using URLByAppendingPathExtension and it messed up the URL, ended up using URLByAppendingPathComponent and adding a filename there. Here's the solution that worked for me! Thanks for the comments guys.

func downloadVideo(id: CKRecordID) {

    privateDatabase.fetchRecordWithID(id) { (results, error) -> Void in

        dispatch_async(dispatch_get_main_queue()) { () -> Void in
            if error != nil {

                    print(" Error Fetching Record  " + error!.localizedDescription)
            } else {
                if results != nil {
                    print("pulled record")

                    let record = results as CKRecord!
                    let videoFile = record.objectForKey("video") as! CKAsset

                    self.videoURL = videoFile.fileURL as NSURL!
                    let videoData = NSData(contentsOfURL: self.videoURL!)

                    let documentsPath = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
                    let destinationPath = NSURL(fileURLWithPath: documentsPath).URLByAppendingPathComponent("filename.mov", isDirectory: false) //This is where I messed up.

                    NSFileManager.defaultManager().createFileAtPath(destinationPath.path!, contents:videoData, attributes:nil)

                    self.videoURL = destinationPath

                    self.videoAsset = AVURLAsset(URL: self.videoURL!)
                    self.playVideo()

                } else {
                    print("results Empty")
                }
            }
        }
    }
}
Comments