4

AVCaptureDataOutputSynchronizerDelegate用来处理捕获视频、深度和元数据的数据

    private let videoDataOutput = AVCaptureVideoDataOutput()
    private let depthDataOutput = AVCaptureDepthDataOutput()
    private let metadataOutput = AVCaptureMetadataOutput()

因此,使用下面的代码,我可以在使用的委托方法中获得专门的视频数据AVCaptureDataOutputSynchronizerDelegate

func dataOutputSynchronizer(_ synchronizer: AVCaptureDataOutputSynchronizer, didOutput synchronizedDataCollection: AVCaptureSynchronizedDataCollection) {

    guard let syncedVideoData = synchronizedDataCollection.synchronizedData(for: self.videoDataOutput) as? AVCaptureSynchronizedSampleBufferData else { return }

问题是,当我尝试将 videoData 保存到如下数组中时,出现OutOfBuffers错误。如果我尝试保存视频数据/关联的图像/与此数据相关的任何内容,此问题仍然存在。

let array:[CMSampleBuffer] = []

...

array.append(syncedVideoData)
//Gets to about 5-6 sets of data, then it runs out of buffers. 
//I think the buffer is being retained permanently since I am saving to a global variable here.
//Leading to out of buffer error

所以,我在想的事情是,由于我将任何相关数据保存到一个数组中,它会将数据保存在内存中的缓冲区中,而它通常是被释放的。

之前为 OutOfBuffers 链接的网页表明我可以

如果您需要对捕获的数据执行扩展处理,请将该数据复制到您管理其生命周期的缓冲区中,而不是依赖于捕获输出提供的缓冲区。

我试图创建一个新的CMSampleBuffer

extension VideoCapture: AVCaptureDataOutputSynchronizerDelegate {

func dataOutputSynchronizer(_ synchronizer: AVCaptureDataOutputSynchronizer, didOutput synchronizedDataCollection: AVCaptureSynchronizedDataCollection) {

    var newData:CMSampleBuffer?

    guard let syncedVideoData = synchronizedDataCollection.synchronizedData(for: self.videoDataOutput) as? AVCaptureSynchronizedSampleBufferData else { return }
    guard !syncedVideoData.sampleBufferWasDropped else {
        print(syncedVideoData.droppedReason.rawValue)
        return
    }
    let videoSampleBuffer = syncedVideoData.sampleBuffer

    CMSampleBufferCreateCopy(allocator: kCFAllocatorDefault, sampleBuffer: videoSampleBuffer, sampleBufferOut: &newData)
    if(newData != nil) {
        self.buffer.append(newData!)
    }
}

但这会导致同样的问题——videoData 仍然停留在缓冲区中。我得到了大约 5-6 组 videoData,然后我就没有更多的数据了。

关于如何“将数据复制到您管理其生命周期的缓冲区而不是依赖于捕获输出提供的缓冲区”的任何指导。outOfBuffers 网站所示?

4

1 回答 1

2

我能够在此缓冲区本指南以及 Apple Docs 中的其他一些内容之后创建一个缓冲区。

...
guard let imagePixelBuffer = CMSampleBufferGetImageBuffer(videoSampleBuffer) else { fatalError() }


//First lock buffer
CVPixelBufferLockBaseAddress(imagePixelBuffer,
                                     CVPixelBufferLockFlags.readOnly)

//Do something with buffer
self.buffer = createMyBuffer(pixelBuffer: imagePixelBuffer)

//Unlock buffer
CVPixelBufferUnlockBaseAddress(imagePixelBuffer,
                                       CVPixelBufferLockFlags.readOnly)
self.doSomething(self.buffer)

...

func createMyBuffer(pixelBuffer: CVPixelBuffer) -> CVPixelBuffer? {
    let scaleWidth:Int = CVPixelBufferGetWidth(pixelBuffer)
    let scaleHeight:Int = CVPixelBufferGetHeight(pixelBuffer)

    let flags = CVPixelBufferLockFlags(rawValue: 0)
    guard kCVReturnSuccess == CVPixelBufferLockBaseAddress(pixelBuffer, flags) else {
        return nil
    }

    defer { CVPixelBufferUnlockBaseAddress(pixelBuffer, flags) }

    guard let srcData = CVPixelBufferGetBaseAddress(pixelBuffer) else {
        print("Error: could not get pixel buffer base address")
        return nil
    }

    let srcBytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer)
    var srcBuffer = vImage_Buffer(data: srcData,
                                      height: vImagePixelCount(CVPixelBufferGetHeight(pixelBuffer)),
                                      width: vImagePixelCount(CVPixelBufferGetWidth(pixelBuffer)),
                                      rowBytes: srcBytesPerRow)

    let destBytesPerRow = scaleWidth*4
    guard let destData = malloc(scaleHeight*destBytesPerRow) else {
        print("Error: out of memory")
        return nil
    }

    var destBuffer = vImage_Buffer(data: destData,
                                       height: vImagePixelCount(scaleHeight),
                                       width: vImagePixelCount(scaleWidth),
                                       rowBytes: destBytesPerRow)

    let error = vImageScale_ARGB8888(&srcBuffer, &destBuffer, nil, vImage_Flags(kvImageLeaveAlphaUnchanged))
    if error != kvImageNoError {
        print("Error:", error)
        free(destData)
        return nil
    }

    let releaseCallback: CVPixelBufferReleaseBytesCallback = { _, ptr in
        if let ptr = ptr {
            free(UnsafeMutableRawPointer(mutating: ptr))
        }
    }

    let pixelFormat = CVPixelBufferGetPixelFormatType(pixelBuffer)
    var dstPixelBuffer: CVPixelBuffer?
    let status = CVPixelBufferCreateWithBytes(nil, scaleWidth, scaleHeight,
                                                  pixelFormat, destData,
                                                  destBytesPerRow, releaseCallback,
                                                  nil, nil, &dstPixelBuffer)
    if status != kCVReturnSuccess {
        print("Error: could not create new pixel buffer")
        free(destData)
        return nil
    }
    return dstPixelBuffer
}

这行得通——但似乎是多余的。我正在使用一个我发现“缩放”缓冲区的函数,但我只是将它缩放到与当前缓冲区完全相同的大小,它会返回一个新的缓冲区,当我选择删除它时。它是重复的,但功能有效。

于 2019-07-30T02:18:45.260 回答