Создание копии CMSampleBuffer в Swift возвращает OSStatus -12743 (неверный формат мультимедиа)

Я пытаюсь выполнить глубокий клон CMSampleBuffer хранить выходные данные AVCaptureSession, Я получаю ошибку kCMSampleBufferError_InvalidMediaFormat(OSStatus -12743) когда я запускаю функцию CMSampleBufferCreateForImageBuffer, Я не вижу, как я не соответствовал CVImageBuffer и CMSampleBuffer описание формата. Кто-нибудь знает, где я ошибся? Это мой тестовый код.

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

1 ответ

Решение

Я смог решить проблему, создав описание формата из вновь созданного буфера изображения и используя его вместо описания формата из исходного буфера сэмплов. К сожалению, хотя это решает проблему здесь, описания форматов не совпадают и вызывают проблему дальше.

Недавно я столкнулся с той же проблемой. После небольшого расследования, CMVideoFormatDescriptionMatchesImageBuffer() Документация по функциям дала немного понимания.

Эта функция использует ключи, возвращаемые CMVideoFormatDescriptionGetExtensionKeysCommonWithImageBuffers, для сравнения расширений данного описания формата с вложениями данного буфера изображения (если вложение отсутствует в любом из них, оно должно отсутствовать в обоих). Он также проверяет kCMFormatDescriptionExtension_BytesPerRow с CVPixelBufferGetBytesPerRow, если это применимо.

В моем случае я не копировал некоторые расширения описания формата в качестве вложений 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);
    }
}];

Версия Swift для ответа Raymanman.

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)
    }
}
Другие вопросы по тегам