4

我正在尝试执行深度克隆CMSampleBuffer来存储AVCaptureSession. kCMSampleBufferError_InvalidMediaFormat (OSStatus -12743)运行该功能时收到错误消息CMSampleBufferCreateForImageBuffer。我看不出我是如何CVImageBufferCMSampleBuffer格式描述不匹配的。有谁知道我哪里出错了?她是我的测试代码。

func captureOutput(captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, fromConnection connection: AVCaptureConnection!) {

    let allocator: CFAllocator = CFAllocatorGetDefault().takeRetainedValue()

    func cloneImageBuffer(imageBuffer: CVImageBuffer!) -> CVImageBuffer? {
        CVPixelBufferLockBaseAddress(imageBuffer, 0)
        let bytesPerRow: size_t = CVPixelBufferGetBytesPerRow(imageBuffer)
        let width: size_t = CVPixelBufferGetWidth(imageBuffer)
        let height: size_t = CVPixelBufferGetHeight(imageBuffer)
        let baseAddress = CVPixelBufferGetBaseAddress(imageBuffer)
        let pixelFormatType = CVPixelBufferGetPixelFormatType(imageBuffer)

        let data = NSMutableData(bytes: baseAddress, length: bytesPerRow * height)
        CVPixelBufferUnlockBaseAddress(imageBuffer, 0)

        var clonedImageBuffer: CVPixelBuffer?
        let refCon = NSMutableData()

        if CVPixelBufferCreateWithBytes(allocator, width, height, pixelFormatType, data.mutableBytes, bytesPerRow, nil, refCon.mutableBytes, nil, &clonedImageBuffer) == noErr {
            return clonedImageBuffer
        } else {
            return nil
        }
    }

    if let oldImageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) {
        if let newImageBuffer = cloneImageBuffer(oldImageBuffer) {
            if let formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer) {
                let dataIsReady = CMSampleBufferDataIsReady(sampleBuffer)
                let refCon = NSMutableData()
                var timingInfo: CMSampleTimingInfo = kCMTimingInfoInvalid
                let timingInfoSuccess = CMSampleBufferGetSampleTimingInfo(sampleBuffer, 0, &timingInfo)
                if timingInfoSuccess == noErr {
                    var newSampleBuffer: CMSampleBuffer?
                    let success = CMSampleBufferCreateForImageBuffer(allocator, newImageBuffer, dataIsReady, nil, refCon.mutableBytes, formatDescription, &timingInfo, &newSampleBuffer)
                    if success == noErr {
                        bufferArray.append(newSampleBuffer!)
                    } else {
                        NSLog("Failed to create new image buffer. Error: \(success)")
                    }
                } else {
                    NSLog("Failed to get timing info. Error: \(timingInfoSuccess)")
                }
            }
        }
    }
}
4

3 回答 3

3

我能够通过在新创建的图像缓冲区中创建格式描述并使用它而不是原始样本缓冲区中的格式描述来解决此问题。不幸的是,虽然这解决了这里的问题,但格式描述不匹配并导致问题进一步下降。

于 2016-03-01T02:16:24.913 回答
1

我最近遇到了同样的问题。经过一番调查,CMVideoFormatDescriptionMatchesImageBuffer()功能文档给出了一些见解。

此函数使用由 CMVideoFormatDescriptionGetExtensionKeysCommonWithImageBuffers 返回的键来比较给定格式描述的扩展名和给定图像缓冲区的附件(如果附件不存在,则两者都必须不存在)。如果适用,它还会根据 CVPixelBufferGetBytesPerRow 检查 kCMFormatDescriptionExtension_BytesPerRow。

在我的例子中,我没有复制一些格式描述扩展作为复制像素缓冲区的 CVBuffer 附件。在创建新的 CVPixelBufferRef 后运行这段代码为我解决了这个问题(Objective-C,但应该不难转换为 Swift)

NSSet *commonKeys = [NSSet setWithArray:(NSArray *)CMVideoFormatDescriptionGetExtensionKeysCommonWithImageBuffers()];
NSDictionary *attachments = (NSDictionary *)CVBufferGetAttachments(originalPixelBuffer, kCVAttachmentMode_ShouldPropagate);
[attachments enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop)
{
    if ([commonKeys containsObject:key])
    {
        CVBufferSetAttachment(pixelBufferCopy, (__bridge CFStringRef)(key), (__bridge CFTypeRef)(obj), kCVAttachmentMode_ShouldPropagate);
    }
}];
attachments = (NSDictionary *)CVBufferGetAttachments(originalPixelBuffer, kCVAttachmentMode_ShouldNotPropagate);
[attachments enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop)
{
    if ([commonKeys containsObject:key])
    {
        CVBufferSetAttachment(pixelBufferCopy, (__bridge CFStringRef)(key), (__bridge CFTypeRef)(obj), kCVAttachmentMode_ShouldNotPropagate);
    }
}];
于 2018-12-02T10:26:56.420 回答
0

Raymanman 答案的 Swift 版本。

let commonKeys = NSSet(array: CMVideoFormatDescriptionGetExtensionKeysCommonWithImageBuffers() as! [Any])

let propagatedAttachments = NSDictionary(dictionary: CVBufferGetAttachments(pixelBuffer, .shouldPropagate)!)
propagatedAttachments.enumerateKeysAndObjects { key, obj, stop in
    if commonKeys.contains(key) {
        CVBufferSetAttachment(outputPixelBuffer, key as! CFString, obj as AnyObject, .shouldPropagate)
    }
}

let nonPropagatedAttachments = NSDictionary(dictionary: CVBufferGetAttachments(pixelBuffer, .shouldPropagate)!)
nonPropagatedAttachments.enumerateKeysAndObjects { key, obj, stop in
    if commonKeys.contains(key) {
        CVBufferSetAttachment(outputPixelBuffer, key as! CFString, obj as AnyObject, .shouldNotPropagate)
    }
}
于 2020-07-28T13:08:41.413 回答