iphone - 从 CMSampleBufferRef 创建的 UIImage 未显示在 UIImageView 中?

标签 iphone uiimageview uiimage ios4 avfoundation

我正在尝试实时显示来自相机的 UIImage,但我的 UIImageView 似乎无法正确显示图像。这是 AVCaptureVideoDataOutputSampleBufferDelegate 必须实现的方法

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
       fromConnection:(AVCaptureConnection *)connection
{ 
    // Create a UIImage from the sample buffer data
    UIImage *theImage = [self imageFromSampleBuffer:sampleBuffer];
//    NSLog(@"Got an image! %f %f", theImage.size.width, theImage.size.height);
//    NSLog(@"The image view is %@", imageView);
//    UIImage *theImage = [[UIImage alloc] initWithData:[NSData 
//        dataWithContentsOfURL:[NSURL 
//        URLWithString:@"http://farm4.static.flickr.com/3092/2915896504_a88b69c9de.jpg"]]];
    [self.session stopRunning];
    [imageView setImage: theImage];
}

要解决简单的问题:

  • 使用 UIImagePickerController 不是一个选项(最终我们将实际对图像执行操作)
  • 我知道正在调用处理程序(进行了 NSLog 调用,并且我看到了输出)
  • 我知道我已正确设置 IBOutlet 声明。如果我使用上面的注释代码从网络加载任意图像,而不是简单地将 setImage:theImage 发送到 imageView,则图像会正确加载(并且第二次调用 NSLog 会报告非零对象)。
  • 至少在基本程度上,我从 imageFromSampleBuffer: 获得的图像很好,因为 NSLog 报告的大小为 360x480,这是我预期的大小。

我使用的代码是 Apple 最近发布的 AVFoundation 代码片段 here .

特别是,这是我使用的代码,它设置了 AVCaptureSession 对象和 friend (我对此知之甚少),并从核心视频缓冲区创建了 UIImage 对象(即 imageFromSampleBuffer方法)。

最后,如果我尝试使用 imageFromSamplerBuffer 返回的 UIImagedrawInRect: 发送到普通 UIView 子类,我可能会导致应用程序崩溃>,而如果我使用上面 URL 中的 UIImage ,它不会崩溃。这是崩溃内调试器的堆栈跟踪(我收到 EXC_BAD_ACCESS 信号):

#0  0x34a977ee in decode_swap ()
#1  0x34a8f80e in decode_data ()
#2  0x34a8f674 in img_decode_read ()
#3  0x34a8a76e in img_interpolate_read ()
#4  0x34a63b46 in img_data_lock ()
#5  0x34a62302 in CGSImageDataLock ()
#6  0x351ab812 in ripc_AcquireImage ()
#7  0x351a8f28 in ripc_DrawImage ()
#8  0x34a620f6 in CGContextDelegateDrawImage ()
#9  0x34a61fb4 in CGContextDrawImage ()
#10 0x321fd0d0 in -[UIImage drawInRect:blendMode:alpha:] ()
#11 0x321fcc38 in -[UIImage drawInRect:] ()

编辑:以下是有关该代码返回的 UIImage 的更多信息。

使用here描述的方法,我可以获取像素并打印它们,乍一看它们看起来不错(例如,Alpha channel 中的每个值都是 255)。然而,缓冲区大小略有偏差。我通过该 URL 从 Flickr 获取的图像为 375x500,其 [pixelData length] 为我提供了 750000 = 375*500*4,这是预期值。然而,从 imageFromSampleBuffer: 返回的图像像素数据的大小为 691208 = 360*480*4 + 8,因此像素数据中有 8 个额外字节。 CVPixelBufferGetDataSize 本身返回这个偏移 8 的值。我想了一下,这可能是由于在内存中的对齐位置分配了缓冲区,但 691200 是 256 的倍数,所以这也不能解释它。这种大小差异是我可以区分的两个 UIImage 之间的唯一区别,并且它可能会导致麻烦。尽管如此,为缓冲区分配额外内存没有理由导致 EXC_BAD_ACCESS 违规。

非常感谢您的帮助,如果您需要更多信息,请告诉我。

最佳答案

我也遇到了同样的问题...但我发现了这篇旧文章,它创建 CGImageRef 的方法有效!

http://forum.unity3d.com/viewtopic.php?p=300819

这是一个工作示例:

app has a member UIImage theImage;

// Delegate routine that is called when a sample buffer was written
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer  fromConnection:(AVCaptureConnection *)connection
{
        //... just an example of how to get an image out of this ...

    CGImageRef cgImage = [self imageFromSampleBuffer:sampleBuffer];
    theImage.image =     [UIImage imageWithCGImage: cgImage ];
    CGImageRelease( cgImage );
}

- (CGImageRef) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer // Create a CGImageRef from sample buffer data
{
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    CVPixelBufferLockBaseAddress(imageBuffer,0);        // Lock the image buffer 

    uint8_t *baseAddress = (uint8_t *)CVPixelBufferGetBaseAddressOfPlane(imageBuffer, 0);   // Get information of the image 
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer); 
    size_t width = CVPixelBufferGetWidth(imageBuffer); 
    size_t height = CVPixelBufferGetHeight(imageBuffer); 
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 

    CGContextRef newContext = CGBitmapContextCreate(baseAddress, width, height, 8, bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst); 
    CGImageRef newImage = CGBitmapContextCreateImage(newContext); 
    CGContextRelease(newContext); 

    CGColorSpaceRelease(colorSpace); 
    CVPixelBufferUnlockBaseAddress(imageBuffer,0); 
    /* CVBufferRelease(imageBuffer); */  // do not call this!

    return newImage;
}

关于iphone - 从 CMSampleBufferRef 创建的 UIImage 未显示在 UIImageView 中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3305862/

相关文章:

iphone - Dropbox 显示文件修改日期

iphone - 如何获取自定义tableViewCell中UIButton的indexPath?

ios - 检测带有圆角的卡片边缘

ios - 将 CMSampleBuffer 转换为 UIImage

ios - 将图像添加到ios工具栏的UIBarButtonItem

iphone - 测试理解 Objective-C 与指针

iphone - 不希望电话链接在浏览器中仅通过电话调用

ios - tableviewcell 中的异步图像下载?

iphone - 在iPhone游戏中隐藏图像的一部分

iphone - 无法在 didFinishLaunchingWithOptions 中制作动画