简体   繁体   English

在 Swift 中创建 CMSampleBuffer 的副本返回 OSStatus -12743(无效的媒体格式)

[英]Creating copy of CMSampleBuffer in Swift returns OSStatus -12743 (Invalid Media Format)

I am attempting to perform a deep clone of CMSampleBuffer to store the output of a AVCaptureSession .我正在尝试执行CMSampleBuffer的深度克隆来存储AVCaptureSession的输出。 I am receiving the error kCMSampleBufferError_InvalidMediaFormat (OSStatus -12743) when I run the function CMSampleBufferCreateForImageBuffer .当我运行函数CMSampleBufferCreateForImageBuffer时,我收到错误kCMSampleBufferError_InvalidMediaFormat (OSStatus -12743) I don't see how I've mismatched the CVImageBuffer and the CMSampleBuffer format description.我看不出我是如何与CVImageBufferCMSampleBuffer格式描述不匹配的。 Anyone know where I've gone wrong?有谁知道我哪里出错了? Her is my test code.她是我的测试代码。

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)")
                }
            }
        }
    }
}

I was able to fix the problem by creating a format description off the newly created image buffer and using it instead of the format description off the original sample buffer.我能够通过从新创建的图像缓冲区创建格式描述并使用它而不是原始样本缓冲区的格式描述来解决问题。 Unfortunately while that fixes the problem here, the format descriptions don't match and causes problem further down.不幸的是,虽然这解决了这里的问题,但格式描述不匹配并导致问题进一步深入。

I recently came across the same issue.我最近遇到了同样的问题。 After a bit of investigation, the CMVideoFormatDescriptionMatchesImageBuffer() function documentation gave a bit of insight.经过一番调查, CMVideoFormatDescriptionMatchesImageBuffer()函数文档给出了一些见解。

This function uses the keys returned by CMVideoFormatDescriptionGetExtensionKeysCommonWithImageBuffers to compares the extensions of the given format description to the attachments of the given image buffer (if an attachment is absent in either it must be absent in both).此函数使用 CMVideoFormatDescriptionGetExtensionKeysCommonWithImageBuffers 返回的键将给定格式描述的扩展名与给定图像缓冲区的附件进行比较(如果附件不存在,则两者都必须不存在)。 It also checks kCMFormatDescriptionExtension_BytesPerRow against CVPixelBufferGetBytesPerRow, if applicable.如果适用,它还根据 CVPixelBufferGetBytesPerRow 检查 kCMFormatDescriptionExtension_BytesPerRow。

In my case, I didn't copy over some of the format description extensions as CVBuffer attachments of the copied pixel buffer.就我而言,我没有将某些格式描述扩展复制为复制像素缓冲区的 CVBuffer 附件。 Running this bit of code after creating the new CVPixelBufferRef resolved the issue for me (Objective-C, but shouldn't be hard to convert to Swift)在创建新的 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);
    }
}];

The Swift version for the answer of Raymanman. 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)
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM