AVPlayerItem.seek(to:cmTime,toleranceBefore:,toleranceAfter :)获取特定的视频帧?

时间:2018-02-02 22:18:26

标签: avfoundation avplayer metal avplayeritem

本周,我有一段悲惨的时间试图从Quicktime电影中获取视频帧并将其显示在Metal纹理中。它比我预想的要困难得多。我只想显示第0帧,然后使用箭头键在视频帧中前后移动。在使用AVPlayererItemVideoOutput.hasNewPixelBuffer(forItemTime:time)函数失败后,我现在尝试使用seek()函数。这几乎可行。视频暂停后,我会在我想要的时间内调用搜索功能,并说它成功了。

但是,每隔几帧,hasNewPixelBuffer()函数返回'false',而copyPixelBuffer()函数只返回与当前显示的帧相同的数据。起初,认为它可能与视频(h264)具有帧重新排序的事实有关。但是当我以正确的顺序使用所有帧的视频时,我得到相同的结果。我已经尝试将搜索容差设置为0,然后尝试各种值,如半帧或更少,以防万一我的计算时间有一些浮点舍入问题。似乎没什么用。

任何人都知道如何做到这一点?它应该是如此简单,但我已经尝试了我能想到的一切。我也尝试了AVAssetImageGenerator,它做了同样的事情。 AVAssetReader将按顺序报告所有帧,但如果您只是想随机访问这些帧,则无法提供帮助。

本周之后我讨厌AVFoundation - 为什么这么简单的视频任务必须如此困难......

任何建议表示赞赏。这是我现在代码的基础知识。

func gotoFrame(_ frame:Int) {
        frameNanoseconds = Int64( (Double(frame)/Double(BigRender.framerate)) * Double(1_000_000_000))
        let cmTime = CMTimeMake(frameNanoseconds ,1_000_000_000)

        playerItem.seek(to: cmTime, toleranceBefore:tolerance, toleranceAfter:tolerance) {
                (result: Bool) in
                if result {
                    //print("seek got back: \(result)")
                    self.needFrame = true
                    self.videoTime = cmTime
                }
                else {
                    print("bad seek!")
                }
        }
}

当搜索回调完成时,我的渲染器将尝试抓取视频帧。寻求总是会成功。它抓住了似乎失败的新视频帧......每隔几帧,'hasNewPixelBuffer'返回false。我每按一次键只想尝试一次新帧,所以这不是无法跟上播放速度的问题。它也是可重复的 - 它跳过的帧总是和我来回走动一样。

我感谢任何人的建议。

 if playerItemVideoOutput.hasNewPixelBuffer(forItemTime: time), let pixelBuffer = playerItemVideoOutput.copyPixelBuffer(forItemTime: time, itemTimeForDisplay: nil) {

    // Get width and height for the pixel buffer
    let width = CVPixelBufferGetWidth(pixelBuffer)
    let height = CVPixelBufferGetHeight(pixelBuffer)

    // Converts the pixel buffer in a Metal texture.
    if CVMetalTextureCacheCreateTextureFromImage(kCFAllocatorDefault, self.textureCache!, pixelBuffer, nil, .bgra8Unorm, width, height, 0, &cvTextureOut) != kCVReturnSuccess {
        print ("texture create failed!")
    }

    guard let cvTexture = cvTextureOut, let inputTexture = CVMetalTextureGetTexture(cvTexture) else {
        print("Failed to create metal texture")
        return
    }

    texture = inputTexture    

 }

0 个答案:

没有答案