Swift应用中AVPlayer播放Documents目录MP4视频无显示问题
老哥,我之前也踩过类似的坑!结合你说的情况——视频存相册能正常查看,但存在Documents文件夹里的MP4在自定义UIView用AVPlayer播放时没反应,还能输出FILE AVAILABLE,咱们一步步排查问题:
排查步骤与解决方案
1. 先确认AVPlayerLayer是否正确挂载到自定义View
这是最容易漏的环节!你得把AVPlayer对应的AVPlayerLayer加到自定义View的layer上,还要保证它的尺寸和View匹配:
// 假设你的自定义View叫playerView,AVPlayer实例是player let playerLayer = AVPlayerLayer(player: player) playerLayer.frame = playerView.bounds playerLayer.masksToBounds = true // 避免视频内容超出View范围 playerView.layer.addSublayer(playerLayer) // 如果你用AutoLayout布局,记得重写自定义View的layoutSubviews来更新layer尺寸 extension PlayerView { override func layoutSubviews() { super.layoutSubviews() playerLayer?.frame = bounds } }
另外!千万别忘了调用player.play(),很多人配置完所有东西,唯独忘了启动播放😂
2. 检查Documents路径的完整性与文件有效性
你输出的路径是截断的,得先确认是不是拿到了完整的文件URL,还有文件是不是真的写完了:
// 获取Documents目录的正确姿势,别用字符串拼接,容易出错 guard let documentsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else { print("Failed to access documents directory") return } let videoURL = documentsDir.appendingPathComponent("your_video.mp4") // 打印完整URL确认 print("Full video path: \(videoURL.path)") // 检查文件大小,确认不是空文件或者未写完的文件 if let fileSize = try? videoURL.resourceValues(forKeys: [.fileSizeKey]).fileSize { print("Video file size: \(fileSize) bytes") }
注意:AVCaptureMovieFileOutput保存视频是异步的,如果你在保存完成前就初始化AVPlayer,会导致播放损坏的文件。一定要在AVCaptureMovieFileOutput.didFinishRecordingTo回调里再去初始化播放器!
3. 监听AVPlayer的加载状态,抓具体错误
有时候播放器没反应是因为加载失败了,但你没收到错误提示。给AVPlayerItem加个状态监听:
let playerItem = AVPlayerItem(url: videoURL) // 添加监听 playerItem.addObserver(self, forKeyPath: "status", options: [.old, .new], context: nil) // 在observeValue里处理状态变化 override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { guard keyPath == "status", let item = object as? AVPlayerItem else { super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) return } switch item.status { case .readyToPlay: print("视频加载完成,可以播放") player.play() case .failed: print("播放器加载失败:\(item.error?.localizedDescription ?? "未知错误")") case .unknown: print("播放器状态未知,正在加载中") @unknown default: break } } // 记得在deinit里移除观察者,避免内存泄漏 deinit { playerItem.removeObserver(self, forKeyPath: "status") }
如果这里输出.failed,就能拿到具体错误信息,比如文件损坏、编码不兼容之类的。
4. 检查视频编码兼容性
虽然你说存相册能看,但AVCaptureMovieFileOutput直接存到Documents的视频,可能编码格式和系统相册自动处理后的有差异?试试用AVAssetExportSession重新导出一次,转成标准MP4:
let asset = AVAsset(url: videoURL) guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) else { print("无法创建导出会话") return } let outputURL = documentsDir.appendingPathComponent("exported_video.mp4") exportSession.outputURL = outputURL exportSession.outputFileType = .mp4 exportSession.exportAsynchronously { DispatchQueue.main.async { switch exportSession.status { case .completed: print("导出完成,试试播放这个新视频:\(outputURL)") let newPlayer = AVPlayer(url: outputURL) // 用这个newPlayer去初始化你的播放器试试 case .failed: print("导出失败:\(exportSession.error?.localizedDescription ?? "未知错误")") default: break } } }
如果导出后的视频能正常播放,那就是原视频的编码或容器格式有问题。
5. 快速调试小技巧
- 把自定义View的背景色改成红色,确认它确实显示在界面上了,不是View本身没渲染导致的“无任何显示”
- 检查视频轨是否存在:
let asset = AVAsset(url: videoURL) asset.loadValuesAsynchronously(forKeys: ["tracks"]) { DispatchQueue.main.async { var error: NSError? let status = asset.statusOfValue(forKey: "tracks", error: &error) if status == .loaded { let videoTracks = asset.tracks(withMediaType: .video) print("视频轨数量:\(videoTracks.count)") } else { print("加载视频轨失败:\(error?.localizedDescription ?? "未知错误")") } } }
内容的提问来源于stack exchange,提问作者Luis Margher
相关产品推荐
相关产品推荐

