Swift 5视频文件压缩求助:将相册视频转为低质量压缩视频
Hey there! I totally feel your pain—this is such a common task, but finding modern, working Swift solutions can be surprisingly tough. Let’s build a reliable, up-to-date implementation using Apple’s native AVFoundation and Photos frameworks to handle video compression from the photo library.
Step 1: Set Up Photo Library Permissions
First, you need to request access to the user’s photo library. Add these keys to your Info.plist (right-click → Open As → Source Code) with a clear explanation for why you need access:
<key>NSPhotoLibraryUsageDescription</key> <string>Need access to your videos to compress them</string> <key>NSPhotoLibraryAddUsageDescription</key> <string>Need access to save the compressed video back to your library (optional)</string>
Step 2: Fetch the Video URL from the Photo Library
Assuming you’ve already selected a PHAsset (video) from the photo library, use this code to get its local file URL:
import Photos func getVideoURL(from asset: PHAsset, completion: @escaping (URL?) -> Void) { let options = PHVideoRequestOptions() options.isNetworkAccessAllowed = false // Only fetch local videos options.version = .original PHImageManager.default().requestAVAsset(forVideo: asset, options: options) { avAsset, _, error in guard let urlAsset = avAsset as? AVURLAsset, error == nil else { completion(nil) return } completion(urlAsset.url) } }
Step 3: Core Video Compression Function
This function takes the input video URL, compresses it to a low-quality preset, and returns the URL of the compressed output file (stored in your app’s Documents directory):
import AVFoundation func compressVideo(inputURL: URL, completion: @escaping (URL?, Error?) -> Void) { // Create a temporary output URL in the app's Documents folder let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] let outputURL = documentsDir.appendingPathComponent("compressed_video_\(UUID().uuidString).mp4") guard let asset = AVAsset(url: inputURL) else { completion(nil, NSError(domain: "CompressionError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid video asset"])) return } guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetLowQuality) else { completion(nil, NSError(domain: "CompressionError", code: -2, userInfo: [NSLocalizedDescriptionKey: "Failed to create export session"])) return } exportSession.outputURL = outputURL exportSession.outputFileType = .mp4 exportSession.shouldOptimizeForNetworkUse = true // Helps with faster streaming/sharing exportSession.exportAsynchronously { switch exportSession.status { case .completed: completion(outputURL, nil) case .failed, .cancelled: completion(nil, exportSession.error ?? NSError(domain: "CompressionError", code: -3, userInfo: [NSLocalizedDescriptionKey: "Export failed or cancelled"])) default: break } } }
Step 4: Putting It All Together
Here’s how to use the two functions above in your workflow (e.g., after selecting a video from the photo library):
// Example: Assume you have a selected PHAsset named 'selectedVideoAsset' getVideoURL(from: selectedVideoAsset) { inputURL in guard let inputURL = inputURL else { print("Failed to get video URL from photo library") return } compressVideo(inputURL: inputURL) { outputURL, error in if let error = error { print("Compression failed: \(error.localizedDescription)") return } guard let compressedURL = outputURL else { print("No compressed video URL returned") return } // Use the compressedURL for your needs (upload, share, etc.) print("Compressed video ready at: \(compressedURL)") // Optional: Save the compressed video back to the photo library PHPhotoLibrary.shared().performChanges({ PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: compressedURL) }) { success, error in if success { print("Compressed video saved to photo library") } else if let error = error { print("Failed to save compressed video: \(error.localizedDescription)") } } } }
Key Notes
- Customization: If
AVAssetExportPresetLowQualityisn’t low enough for your needs, you can create a custom export preset with lower bitrates usingAVAssetWriter(it’s more code, but gives full control). - Cleanup: Remember to delete temporary compressed files from the Documents directory when you’re done with them to save storage space.
- Background Handling: If you’re compressing large videos, consider wrapping the export task in a background session to avoid interruptions when the app is in the background.
This solution is fully Swift-based, uses Apple’s modern frameworks, and handles local photo library videos reliably—no outdated Obj-C hacks required.
内容的提问来源于stack exchange,提问作者user13290768

