首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >适当地从AVCaptureDataOutputSynchronizerDelegate释放缓冲区,原因是缓冲区超出缓冲区

适当地从AVCaptureDataOutputSynchronizerDelegate释放缓冲区,原因是缓冲区超出缓冲区
EN

Stack Overflow用户
提问于 2019-07-21 16:21:00
回答 1查看 423关注 0票数 4

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

代码语言:javascript
复制
    private let videoDataOutput = AVCaptureVideoDataOutput()
    private let depthDataOutput = AVCaptureDepthDataOutput()
    private let metadataOutput = AVCaptureMetadataOutput()

因此,使用下面的代码,我能够在从AVCaptureDataOutputSynchronizerDelegate中使用的委托方法中获得具体的视频数据。

代码语言:javascript
复制
func dataOutputSynchronizer(_ synchronizer: AVCaptureDataOutputSynchronizer, didOutput synchronizedDataCollection: AVCaptureSynchronizedDataCollection) {

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

问题是,当我试图按下面的方式将videoData保存到一个数组中时,我会得到一个OutOfBuffers错误。如果我试图保存与此数据相关的视频数据/图像/任何与此数据相关的内容,则此问题仍然存在。

代码语言:javascript
复制
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

代码语言:javascript
复制
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网站所示

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-07-30 02:18:45

我能够在这个缓冲器本指南以及其他几个苹果文档中创建一个缓冲区。

代码语言:javascript
复制
...
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
}

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

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57134958

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档