如何创建样本缓冲区实例(CMSampleBufferRef)?

6

我试着写iOS相机,参考了一些苹果官方文档的代码:

- (void)captureOutput:(AVCaptureOutput *)captureOutput
         didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
         fromConnection:(AVCaptureConnection *)connection
{
    // Create a UIImage from the sample buffer data
    UIImage *image = [self imageFromSampleBuffer:sampleBuffer];

     < Add your code here that uses the image >

}

我需要在程序的任何地方调用这个函数。但是它需要创建一个(CMSampleBufferRef)类型的对象。如何做到这一点?

我尝试写了以下代码:

buf1 = [[CMSampleBufferRef alloc]init] 

但这是错误的方式。

在你的代理方法中,你不需要创建 CMSampleBuffer 的实例。你可以获得对现有缓冲区的引用(sampleBuffer 参数)。 - stefos
@stefos 在我看来,调用方法需要传递3个参数。或者我错了吗? - Andrew Kachalin
这是一个AVCaptureVideoDataOutputSampleBufferDelegate方法,当新的视频帧被写入时会调用它。你不需要显式地调用这个方法。 - Xcoder
正如@Xcoder所说,你不需要调用这个方法。你只需要使用[captureOutput setSampleBufferDelegate: self queue:]将你的控制器设置为代理即可。 - stefos
@stefos 谢谢。我会考虑的。 - Andrew Kachalin
4个回答

14

这是我目前在 Swift3 中用于模拟 CMSampleBuffer 进行单元测试的代码片段:

fileprivate func getCMSampleBuffer() -> CMSampleBuffer {
    var pixelBuffer : CVPixelBuffer? = nil
    CVPixelBufferCreate(kCFAllocatorDefault, 100, 100, kCVPixelFormatType_32BGRA, nil, &pixelBuffer)

    var info = CMSampleTimingInfo()
    info.presentationTimeStamp = kCMTimeZero
    info.duration = kCMTimeInvalid
    info.decodeTimeStamp = kCMTimeInvalid


    var formatDesc: CMFormatDescription? = nil
    CMVideoFormatDescriptionCreateForImageBuffer(kCFAllocatorDefault, pixelBuffer!, &formatDesc)

    var sampleBuffer: CMSampleBuffer? = nil

    CMSampleBufferCreateReadyWithImageBuffer(kCFAllocatorDefault,
                                             pixelBuffer!,
                                             formatDesc!,
                                             &info,
                                             &sampleBuffer);

    return sampleBuffer!
}

1
谢谢你的回答。我已经不记得问题的实质了。 - Andrew Kachalin

3

@Rotem Tamir回答的Swift 5版本

fileprivate func getCMSampleBuffer() -> CMSampleBuffer {
    var pixelBuffer: CVPixelBuffer?
    CVPixelBufferCreate(kCFAllocatorDefault, 100, 100, kCVPixelFormatType_32BGRA, nil, &pixelBuffer)

    var info = CMSampleTimingInfo()
    info.presentationTimeStamp = CMTime.zero
    info.duration = CMTime.invalid
    info.decodeTimeStamp = CMTime.invalid

    var formatDesc: CMFormatDescription?
    CMVideoFormatDescriptionCreateForImageBuffer(allocator: kCFAllocatorDefault,
                                                 imageBuffer: pixelBuffer!,
                                                 formatDescriptionOut: &formatDesc)

    var sampleBuffer: CMSampleBuffer?

    CMSampleBufferCreateReadyWithImageBuffer(allocator: kCFAllocatorDefault,
                                             imageBuffer: pixelBuffer!,
                                             formatDescription: formatDesc!,
                                             sampleTiming: &info,
                                             sampleBufferOut: &sampleBuffer)

    return sampleBuffer!
}

1

Swift 5.6

public func convertCMSampleBuffer(_ cvPixelBuffer: CVPixelBuffer?) -> CMSampleBuffer {
    
    var pixelBuffer = cvPixelBuffer
    CVPixelBufferCreate(kCFAllocatorDefault, 100, 100, kCVPixelFormatType_32BGRA, nil, &pixelBuffer)

    var info = CMSampleTimingInfo()
    info.presentationTimeStamp = CMTime.zero
    info.duration = CMTime.invalid
    info.decodeTimeStamp = CMTime.invalid

    var formatDesc: CMFormatDescription?
    CMVideoFormatDescriptionCreateForImageBuffer(allocator: kCFAllocatorDefault,
                                                 imageBuffer: pixelBuffer!,
                                                 formatDescriptionOut: &formatDesc)

    var sampleBuffer: CMSampleBuffer?

    CMSampleBufferCreateReadyWithImageBuffer(allocator: kCFAllocatorDefault,
                                             imageBuffer: pixelBuffer!,
                                             formatDescription: formatDesc!,
                                             sampleTiming: &info,
                                             sampleBufferOut: &sampleBuffer)

    return sampleBuffer!
}

0

尝试这些方法中的所有方法(其中一种可能有效):

UIImage *image = [self imageFromSampleBuffer:&sampleBuffer];
UIImage *image = [self imageFromSampleBuffer:(id)sampleBuffer];
UIImage *image = [self imageFromSampleBuffer:(__bridge CMSampleBufferRef)sampleBuffer];
UIImage *image = [self imageFromSampleBuffer:(__bridge id)sampleBuffer];

如果上述方法都不起作用,可以创建一个对CMSampleBuffer的CVImageBuffer的引用,而不添加任何上述内容来替换UIImage方法中的sampleBuffer。
CVImageBufferRef cvImageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);

如果那不起作用,您可以创建一个单独的方法,将CMSampleBuffer转换为UIImage,如下所示:
// Create a UIImage from sample buffer data
- (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer
{
    // Get a CMSampleBuffer's Core Video image buffer for the media data
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    // Lock the base address of the pixel buffer
    CVPixelBufferLockBaseAddress(imageBuffer, 0);

    // Get the number of bytes per row for the pixel buffer
    void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);

    // Get the number of bytes per row for the pixel buffer
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
    // Get the pixel buffer width and height
    size_t width = CVPixelBufferGetWidth(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);

    // Create a device-dependent RGB color space
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    // Create a bitmap graphics context with the sample buffer data
    CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8,
      bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
    // Create a Quartz image from the pixel data in the bitmap graphics context
    CGImageRef quartzImage = CGBitmapContextCreateImage(context);
    // Unlock the pixel buffer
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);

    // Free up the context and color space
    CGContextRelease(context);
    CGColorSpaceRelease(colorSpace);

    // Create an image object from the Quartz image
    UIImage *image = [UIImage imageWithCGImage:quartzImage];

    // Release the Quartz image
    CGImageRelease(quartzImage);

    return (image);
}

这个方法有效,实际上我就是用的这个。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接