Load video from PHPhotoPicker without photo library permissions?
Once you get the item provider back, you can check if a video is available with:
Code Block itemProvider.hasItemConformingToTypeIdentifier("public.movie")
And then you can get access to the URL to the video file on disk with:
Code Block itemProvider.loadItem(forTypeIdentifier: "public.movie", options: nil) { /* do stuff */ }
That should get you access to the file without needing photo library access. Hope this helps!
Here's my code:
Code Block swift import AVKit import PhotosUI import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() } @IBAction func selectMovieTapped(_ sender: UIButton) { var config = PHPickerConfiguration() config.filter = .videos let picker = PHPickerViewController(configuration: config) picker.delegate = self present(picker, animated: true, completion: nil) } } extension ViewController: PHPickerViewControllerDelegate { func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { picker.dismiss(animated: true, completion: nil) guard let provider = results.first?.itemProvider else { return } if provider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) { provider.loadItem(forTypeIdentifier: UTType.movie.identifier, options: [:]) { [self] (videoURL, error) in print("resullt:", videoURL, error) DispatchQueue.main.async { if let url = videoURL as? URL { let player = AVPlayer(url: url) let playerVC = AVPlayerViewController() playerVC.player = player present(playerVC, animated: true, completion: nil) } } } } } }
It prints the following when I pick a video on the simulator:
Code Block text resullt: Optional(file:///Users/zev/Library/Developer/CoreSimulator/Devices/C5BEBCF2-D16A-41F7-B788-6CC208B02D4C/data/Containers/Shared/AppGroup/D7862E29-F13B-42A8-A74B-721676090D8D/File%20Provider%20Storage/47F700FF-7501-49A0-B84B-23E701A758F9.mov) nil 2020-07-01 07:56:34.992199-0400 DeflickerPOC[20292:373394] [] [07:56:34.992] FigFileForkOpenMainByCFURL signalled err=2 (errno) (open failed) at /Library/Caches/com.apple.xbs/Sources/EmbeddedCoreMediaFramework_Sim/EmbeddedCoreMedia-2729.5.1.3/Sources/Platform/Darwin/DarwinFile.c:564
And the player VC presents, but is not playable. It shows a ▶️ with a 🚫 through it (roughly; I can't attach or link to a screenshot on this forum, apparently).
Is the new photo picker suitable for apps that allow selecting multiple photos/videos and putting them together into a single project? This requires being able to download multiple photos/videos (showing progress) and then manipulating the photos as UIImages and the videos as AVAssets.
I have a bunch of photo/video apps and am struggling to see my way through all this without just asking the user to please give access to all photos.
Since you are working with a file representation of the item, I'd also recommend to switch to loadFileRepresentation(forTypeIdentifier:completionHandler:) which guarantees a URL as type.
The documentation of that method also states the copy requirement more explicitly:
This method writes a copy of the file’s data to a temporary file, which the system deletes when the completion handler returns.
On my side, this:
Code Block swift itemProvider.loadItem(forTypeIdentifier: "public.movie", options: nil) { /* do stuff */ }
Gives me a URL pointing to a file that does not exist. So until now, it seems impossible to load a video from the new PHPickerViewController.
Is this a known issue?
For some reason loadItem fails until I've used loadFileRepresentation on that same video.
Code Block itemProvider.loadItem(forTypeIdentifier: "public.movie", options: nil) { url, error in guard let url = url as? URL else { return } print(FileManager.default.fileExists(atPath: url.path)) }
This prints false.
Code Block itemProvider.loadFileRepresentation(forTypeIdentifier: "public.movie") { url, error in print(FileManager.default.fileExists(atPath: url.path)) }
This prints true.
Now if I change the code to use loadItem and select the video that I just used loadFileRepresentation on, it works correctly.
I would happily use loadFileRepresentation all the time, but it loads extremely slowly. ~20 seconds for a minute long video, while loadItem takes about .1 seconds for the same video.
What's going on here?
Now if I change the code to use loadItem and select the video that I just used loadFileRepresentation on, it works correctly.
I would happily use loadFileRepresentation all the time, but it loads extremely slowly. ~20 seconds for a minute long video, while loadItem takes about .1 seconds for the same video.
What's going on here?
You should always use itemProvider.loadFileRepresentation because itemProvider.loadItem is not designed for this use case.
It's likely that the picker is transcoding the video for you on the fly. You can set preferredAssetRepresentationMode to .current to avoid transcoding if your app can handle arbitrary video formats (HEVC, H264, etc).