How to create instance of Sample Buffer (CMSampleBufferRef)?
Asked Answered
H

4

6

I try to write ios camera, and I took some part of code from apple:

- (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 >

}

I need to call this function, from anywhere in my program. But for it demands to create an object type of (CMSampleBufferRef). How to do it?

I tried to write something like:

buf1 = [[CMSampleBufferRef alloc]init] 

But it's wrong way.

Hellenism answered 2/6, 2016 at 14:0 Comment(5)
In your delegate method you don't need to create instance of CMSampleBuffer. You get a reference to an existing buffer (sampleBuffer param).Thickskinned
@Thickskinned IMHO, to call method need to transfer into 3 arguments. Or i'm wrong?Hellenism
This is an AVCaptureVideoDataOutputSampleBufferDelegate method which is called when a new video frame has been written. You don't explicitly call this method.Consecrate
As @Consecrate said you don't call this method. You just set your controller as delegate with [captureOutput setSampleBufferDelegate: self queue:].Thickskinned
@Thickskinned thanks. i will think about itHellenism
B
14

This is a snippet I'm currently using for mocking CMSampleBuffer for unit tests in swift3:

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!
}
Bandur answered 21/8, 2017 at 8:3 Comment(1)
thanks for your answer. I no longer remember the essence of the matter.Hellenism
C
3

Swift 5 version of @Rotem Tamir's Answer

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!
}
Cohligan answered 15/2, 2021 at 13:50 Comment(0)
D
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!
}
Drunken answered 30/5, 2022 at 11:21 Comment(0)
T
0

Try all of these (one might work):

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];

If none of those work, create a reference to the CMSampleBuffer's CVImageBuffer without adding any of the above to replace sampleBuffer in the UIImage method:

CVImageBufferRef cvImageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);

If that does not work, you can create a separate method that converts a CMSampleBuffer to a UIImage like so:

// 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);
}

This method works; it's the one I use, in fact.

Towne answered 13/8, 2016 at 9:40 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.