macOS下AVSynchronizedLayer无法播放动画、同代码iOS运行正常问题求助
问题原因
macOS 平台的 AVSynchronizedLayer 对仅包含音频的 AVPlayerItem 时间同步存在平台层兼容缺陷,不会主动同步纯音频轨道的时间进度,而 iOS 系统内部做了对应兼容,所以相同代码在 iOS 可以正常运行。
修复方案1:给音频资产插入空视频轨道
该方案兼容纯音频场景,不需要修改原有动画逻辑,适配性更强:
// 原音频加载逻辑修改为如下 let url = Bundle.main.url(forResource: "debugAudio", withExtension: "m4a")! let asset = AVURLAsset(url: url) // 创建可变资产插入空视频轨道,激活AVSynchronizedLayer的时间同步能力 let composition = AVMutableComposition() // 插入原有音频轨道 try! composition.insertTimeRange(CMTimeRangeMake(start: .zero, duration: asset.duration), of: asset, at: .zero) // 新增1x1尺寸的空视频轨道 let videoTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid)! videoTrack.preferredTransform = .identity // 生成AVPlayerItem,后续原有逻辑完全不变 let item = AVPlayerItem(asset: composition) avPlayer.replaceCurrentItem(with: item) // 原有同步层、子层、动画、播放逻辑全部保持不变即可
修复方案2:等待AVPlayerItem准备完成后再添加动画
如果不想修改资产结构,也可以通过监听播放器 item 状态,配合补充动画配置解决问题:
// 音频加载、同步层创建、子层创建逻辑保持不变 let url = Bundle.main.url(forResource: "debugAudio", withExtension: "m4a")! let asset = AVURLAsset(url: url) let item = AVPlayerItem(asset: asset) avPlayer.replaceCurrentItem(with: item) let syncLayer = AVSynchronizedLayer(playerItem: avPlayer.currentItem!) view.layer!.addSublayer(syncLayer) syncLayer.frame = CGRect(x: 60, y: 60, width: 200, height: 200) let progressLayer = CALayer() progressLayer.backgroundColor = NSColor.purple.cgColor progressLayer.borderColor = NSColor.orange.cgColor syncLayer.addSublayer(progressLayer) progressLayer.frame = syncLayer.bounds // 新增监听playerItem的就绪状态 item.addObserver(self, forKeyPath: #keyPath(AVPlayerItem.status), options: [.new], context: nil) // 监听回调处理 override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { guard keyPath == #keyPath(AVPlayerItem.status), let item = object as? AVPlayerItem, item.status == .readyToPlay else { super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) return } // 移除监听避免内存泄漏 item.removeObserver(self, forKeyPath: #keyPath(AVPlayerItem.status)) // 动画配置补充fillMode let anim = CABasicAnimation(keyPath: "borderWidth") anim.fromValue = 3.0 anim.toValue = 20.0 anim.duration = 5.0 anim.isRemovedOnCompletion = false anim.fillMode = .forwards anim.beginTime = AVCoreAnimationBeginTimeAtZero progressLayer.add(anim, forKey: nil) // 播放 self.avPlayer.play() }
内容的提问来源于stack exchange,提问作者msmialko
相关产品推荐
相关产品推荐

