Reputation: 807
in one of my projects I download a remote mp4 video from a server and save it in the "Documents" folder of the iOS device (Swift 3, iOS 10). I've tried to play the local video using AVPlayer in several ways (with the URL, using AVPlayerItem/AVAsset, etc.) but I always end up with a screen like this:
This is the last version of the code I'm trying to use to play the file:
let urls = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
if let docDir : URL = urls.first {
let component = self.videoTutorialsEntries[indexPath.row].filename
let videoUrl = docDir.appendingPathComponent(component)
do {
let videoExists : Bool = try videoUrl.checkResourceIsReachable()
if videoExists {
let player = AVPlayer(url: videoUrl)
let playerController = AVPlayerViewController()
playerController.player = player
self.present(playerController, animated: true) {
playerController.player!.play()
}
} else {
print("Video doesn't exist")
}
} catch let error as NSError {
print(error)
}
}
I've checked that the Documents folder contains the video, and that the URL/path is correct, and it seems so.
I've also tried to handle this with a separate AVKit view controller from the storyboard, using segue, but the result doesn't change.
I'm wondering if something is necessary such as the change that for security reasons you have to perform on the Info.plist to play remote files, but in this case it's a local file therefore I'm short of ideas.
Does anyone know the reason why the video file doesn't play?
UPDATE: I just realized, analyzing the sandbox of the app (There's a way to access the document folder in iphone/ipad (real device, no simulator)?), that the file I've saved is somehow corrupted (it's supposed to be something like 22 MB but in the sandbox it's just a few KB, meaning that the problem should be in the saving procedure). I have my remote file on Dropbox, and save the file with this technique:
// Necessary when the remote server doesn't send the file size
var request = URLRequest(url: self.videoUrl, cachePolicy: NSURLRequest.CachePolicy.reloadIgnoringCacheData, timeoutInterval: 30.0)
request.httpMethod = "HEAD";
request.timeoutInterval = 5;
let group = DispatchGroup()
group.enter()
URLSession.shared.dataTask(with: request, completionHandler: { (data, response, error) -> Void in
if error != nil {
DispatchQueue.main.async(execute: {
self.showAlert(title: NSLocalizedString("Video Unreachable", comment: "Video Unreachable Title"), message: NSLocalizedString("It was not possible to download the video file!", comment: "Video Not Downloaded Title"))
})
} else {
DispatchQueue.main.async(execute: {
self.contentLength = response?.expectedContentLength ?? NSURLSessionTransferSizeUnknown
group.leave()
self.progressLabel?.center = CGPoint(x:UIScreen.main.bounds.size.width / 2, y:(self.pointInTable.y/2)+40)
self.progressLabel?.isHidden = false
})
self.downloadVideo()
}
}).resume()
func downloadVideo() {
self.isVideo = true
downloadTask = backgroundSession.downloadTask(with: self.videoUrl)
downloadTask.resume()
}
Since I've used this asynchronous handling also for pdf files (where the download works) I'm assuming that the issue could be the dropbox link to the video. Any ideas about possible issues with that?
UPDATE: I finally managed to play the file! The issue was related to the Dropbox url form I was using. In order to download the file you need a link like this: https://www.dropbox.com/s/xxxxxxxxxxxx/xxxxxx.mp4?dl=1
with the final "?dl=1" that means that you want to download the file, and not just visualize it. I was missing that.
Finally, everything worked with this piece of code:
let fileManager = FileManager.default
let docsUrl = try! fileManager.url(for:.documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
let component = self.videoTutorialsEntries[indexPath.row].filename
let fileUrl = docsUrl.appendingPathComponent(component)
performSegue(withIdentifier: "showLocalVideo", sender: fileUrl)
(I have used the view controller from the storyboard and the segue, just with urls (no need of items and assets).
Hope this helps somebody else struggling with saving remote video from Dropbox and playing them locally.
Upvotes: 2
Views: 2624
Reputation: 1878
Try like this :
let asset = AVAsset(URL: your_videoUrl)
let item = AVPlayerItem(asset: asset)
let player = AVPlayer(playerItem: item)
Upvotes: 1