ios - 如何同步 AVPlayer 和 MTKView

标签 ios swift synchronization avplayer metal

我有一个项目,用户可以在其中拍摄视频,然后为他们添加滤镜或更改亮度和对比度等基本设置。为此,我使用 BBMetalImage ,它基本上返回 MTKView 中的视频(在项目中命名为 BBMetalView)。

一切都很好——我可以播放视频、添加过滤器和所需的效果,但没有音频。我 asked the author关于这个,谁推荐使用 AVPlayer (或 AVAudioPlayer )为此。所以我做了。但是,视频和音频不同步。可能首先是因为不同的比特率,并且库的作者还提到帧率可能会因为过滤过程而有所不同(这消耗的时间是可变的):

The render view FPS is not exactly the same to the actual rate. Because the video source output frame is processed by filters and the filter process time is variable.



首先,我将视频裁剪为所需的宽高比 (4:5)。我在本地保存这个文件 (480x600),使用 AVVideoProfileLevelH264HighAutoLevelAVVideoProfileLevelKey .我的音频配置,使用 NextLevelSessionExporter ,具有以下设置:AVEncoderBitRateKey: 128000 , AVNumberOfChannelsKey: 2 , AVSampleRateKey: 44100 .

然后,BBMetalImage 库获取这个保存的音频文件并提供一个 MTKView (BBMetalView) 来显示视频,让我可以实时添加滤镜和效果。设置类型如下所示:
self.metalView = BBMetalView(frame: CGRect(x: 0, y: self.view.center.y - ((UIScreen.main.bounds.width * 1.25) / 2), width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.width * 1.25))
self.view.addSubview(self.metalView)
self.videoSource = BBMetalVideoSource(url: outputURL)
self.videoSource.playWithVideoRate = true
self.videoSource.audioConsumer = self.metalAudio
self.videoSource.add(consumer: self.metalView)
self.videoSource.add(consumer: self.videoWriter)
self.audioItem = AVPlayerItem(url: outputURL)                            
self.audioPlayer = AVPlayer(playerItem: self.audioItem)
self.playerLayer = AVPlayerLayer(player: self.audioPlayer)
self.videoPreview.layer.addSublayer(self.playerLayer!)
self.playerLayer?.frame = CGRect(x: 0, y: 0, width: 0, height: 0)
self.playerLayer?.backgroundColor = UIColor.black.cgColor
self.startVideo()

startVideo()像这样:
audioPlayer.seek(to: .zero)
audioPlayer.play()
videoSource.start(progress: { (frameTime) in
    print(frameTime)
}) { [weak self] (finish) in
guard let self = self else { return }
    self.startVideo()
}

由于外部库/库,这一切可能都非常模糊。但是,我的问题很简单:有什么方法可以同步 MTKView和我的AVPlayer ?这对我有很大帮助,我敢肯定Silence-GitHub还将将此功能实现到库中以帮助许多其他用户。欢迎任何有关如何解决此问题的想法!

最佳答案

我按如下方式自定义了 BBMetalVideoSource 然后它起作用了:

  • 在 BBMetalVideoSource 中创建一个委托(delegate),以获取我们要与之同步的音频播放器的当前时间
  • 在函数 private func processAsset(progress:, completion:) , 我把这段代码替换成 if useVideoRate { //... }经过:
    if useVideoRate {
        if let playerTime = delegate.getAudioPlayerCurrentTime() {
            let diff = CMTimeGetSeconds(sampleFrameTime) - playerTime
            if diff > 0.0 {
                sleepTime = diff
                if sleepTime > 1.0 {
                    sleepTime = 0.0
                }
                usleep(UInt32(1000000 * sleepTime))
            } else {
                sleepTime = 0
            }
        }
    }
    

  • 这段代码帮助我们解决了两个问题:1.预览视频效果时没有音频,2.音频与视频同步。

    关于ios - 如何同步 AVPlayer 和 MTKView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58317954/

    相关文章:

    ios - 使用 CameraRoll.saveToCameraRoll 将图像保存到相册?

    swift - SwiftUI如何自定义Slider蓝线?

    multithreading - 类实例 "owning"TMultiReadExclusiveWriteSynchronizer 实例?

    ios - 使用 xCode 8 和 Swift 2.3 的 Realm 失败

    ios - UITabBar swift 中缺少按钮

    ios - 设备旋转时的 Swift UIcollectionViewcell 网格布局 subview 未正确更新(以编程方式)

    ios - locationManager.location 始终为零

    iphone - 更多 iCloud 核心数据同步问题

    java - Java Web 应用程序中的并发

    ios - 在 Swift 中动画 MapKit 注释坐标变化?