【问题标题】:AVAssetReader trouble getting pixel buffer from copyNextSampleBuffer(), SwiftAVAssetReader 从 copyNextSampleBuffer() 获取像素缓冲区时遇到问题,Swift
【发布时间】:2018-07-11 05:06:10
【问题描述】:

我正在尝试在 macOSX 上使用 AVFoundation 和 AVAssetReader 从 Quicktime 电影文件中读取图像帧。我想通过 Metal 中的纹理贴图显示帧。有很多在线使用 AVAssetReader 的示例,但我无法让它为我想要的工作。

我可以从电影中读取基本帧数据——打印输出中的时间值、大小和持续时间看起来正确。但是,当我尝试获取 pixelBuffer 时,CMSampleBufferGetImageBuffer 返回 NULL。

    let track = asset.tracks(withMediaType: AVMediaType.video)[0]
    let videoReaderSettings : [String : Int] = [kCVPixelBufferPixelFormatTypeKey as String : Int(kCVPixelFormatType_32BGRA)]

    let output = AVAssetReaderTrackOutput(track:track, outputSettings:nil)  // using videoReaderSettings causes it to no longer report frame data
    guard let reader = try? AVAssetReader(asset: asset) else {exit(1)}
    output.alwaysCopiesSampleData = true
    reader.add(output)
    reader.startReading()


    while(reader.status == .reading){

        if let sampleBuffer = output.copyNextSampleBuffer(), CMSampleBufferIsValid(sampleBuffer) {
            let frameTime = CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer)
            if (frameTime.isValid){
                print("frame: \(frameNumber), time: \(String(format:"%.3f", frameTime.seconds)), size: \(CMSampleBufferGetTotalSampleSize(sampleBuffer)), duration: \(                CMSampleBufferGetOutputDuration(sampleBuffer).value)")

                if let pixelBuffer : CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
                    getTextureFromCVBuffer(pixelBuffer)
                    //   break

                }
                frameNumber += 1
            }
        }
    }

此问题已在此处 (Why does CMSampleBufferGetImageBuffer return NULL) 得到解决,建议问题是必须在设置参数中指定视频格式,而不是“nil”。所以我尝试用上面的'videoReaderSettings'替换'nil',格式有各种值:kCVPixelFormatType_32BGRA、kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange等。

结果是帧“时间”值仍然正确,但“大小”和“持续时间”值为 0。但是,CMSampleBufferGetImageBuffer 确实返回了一些内容,之前为 0。但屏幕上出现了垃圾。

这里是将pixelBuffer转换为Metal纹理的函数。

func getTextureFromCVBuffer(_ pixelBuffer:CVPixelBuffer) {
    // Get width and height for the pixel buffer
    let width = CVPixelBufferGetWidth(pixelBuffer)
    let height = CVPixelBufferGetHeight(pixelBuffer)

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

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

当我能够将 pixelBuffer 传递给此函数时,它会报告正确的图像大小。但正如我所说,出现在屏幕上的是垃圾——实际上它是由最近的 Safari 浏览器页面组成的。我不确定问题出在第一个函数还是第二个函数中。 CMSampleBufferGetImageBuffer 的非零返回值令人鼓舞,但大小和持续时间的 0 则不是。

我发现这个线程 (Buffer size of CMSampleBufferRef) 表明大小和持续时间显示 0 可能不是问题,所以问题可能在于转换为金属纹理?

知道我做错了什么吗?
谢谢!

【问题讨论】:

    标签: swift avfoundation metal avassetreader cvpixelbuffer


    【解决方案1】:

    将 videoReaderSetting 放入 AVAssetReaderTrackOutput。

    let videoReaderSettings : [String : Int] = [kCVPixelBufferPixelFormatTypeKey as String : Int(kCVPixelFormatType_32BGRA)]
    
    let output = AVAssetReaderTrackOutput(track:track, outputSettings: videoReaderSettings)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-06
      • 1970-01-01
      • 2014-07-13
      • 1970-01-01
      • 2014-12-05
      • 1970-01-01
      • 2015-07-02
      • 1970-01-01
      相关资源
      最近更新 更多