我正在为MacOS(最新事物,Obj-C)编写一个显微镜应用程序。
我使用AVCaptureSession
从屏幕上的显微镜摄像机预览实时视频,但是我也想让用户在看到有趣的东西时拍摄静止图像。我希望将最高质量的图像保存到磁盘上的文件中。
为此,我尝试使用AVCaptureStillImageOutput
,它是标题所需要的。我进行了设置,并像下面这样将其添加到我的捕获会话中:
self.stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
NSDictionary *compressionSettings = @{AVVideoQualityKey : @(1.0)};
NSDictionary *outputSettings = @{ AVVideoCodecKey : AVVideoCodecJPEG,
AVVideoCompressionPropertiesKey : compressionSettings,
AVVideoWidthKey : @(1024),
AVVideoHeightKey : @(768)
};
[self.stillImageOutput setOutputSettings:outputSettings];
[self.session addOutput: stillImageOutput];
稍后,随着用户选择拍摄快照-我调用此方法尝试捕获静止图像:
// Capture a single video frame during a video capture
-(BOOL)captureStillImage: (CGRect)cropRect {
AVCaptureConnection *videoConnection = nil;
for (AVCaptureConnection *connection in stillImageOutput.connections) {
for (AVCaptureInputPort *port in [connection inputPorts]) {
if ([[port mediaType] isEqual:AVMediaTypeVideo] ) {
videoConnection = connection;
break;
}
}
if (videoConnection) { break; }
}
if (videoConnection == nil) { return NO };
[stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler:
^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
CVImageBufferRef imageBufferRef = CMSampleBufferGetImageBuffer(imageSampleBuffer);
if(imageBufferRef==nil) // <<< HERE I ALWAYS GET NULL
return;
NSCIImageRep *imageRep = [NSCIImageRep imageRepWithCIImage:[CIImage imageWithCVImageBuffer:imageBufferRef]];
NSImage *compositeImage = [[NSImage alloc] initWithSize:[imageRep size]];
NSImage *videoFrameImage = [[NSImage alloc] initWithSize:[imageRep size]];
[videoFrameImage addRepresentation:imageRep];
NSRect r = NSMakeRect(0.0f, 0.0f, [imageRep size].width, [imageRep size].height);
[compositeImage lockFocus];
[videoFrameImage drawAtPoint:NSMakePoint(0.0f, 0.0f) fromRect:r operation:NSCompositeSourceOver fraction:1.0f];
[compositeImage unlockFocus];
NSData *tiffImageData = [videoFrameImage TIFFRepresentation];
NSBitmapImageRep *tiffRep = [NSBitmapImageRep imageRepWithData:tiffImageData];
NSDictionary *imageProps = [NSDictionary dictionaryWithObject:[NSNumber numberWithFloat:1.0] forKey:NSImageCompressionFactor];
tiffImageData = [tiffRep representationUsingType:NSJPEGFileType properties:imageProps];
// Save data to file
static NSUInteger imageNumber = 0;
NSString *imageFilePath = [@"/Users/me/Desktop/" stringByAppendingPathComponent: [NSString stringWithFormat:@"image_%lu", imageNumber++]];
imageFilePath = [imageFilePath stringByAppendingPathExtension:@"JPG"];
[tiffImageData writeToFile: imageFilePath atomically: NO];
}];
return YES;
}
我发现其他用户也有类似的问题-但是答案始终涉及“您没有应用我所做的“ OutputSettings”-所以我真的很困惑”。
请注意:如果我使用“简写” API:
NSData *pixelData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
在我的回调中-成功,但是pixelData包含较差的,低分辨率的小图像-当然不是我在预览中看到的质量。此外-它是JPEG压缩的-因此,如果要裁剪,则需要先解码,然后裁剪,然后重新压缩-从而进一步降低本来就很低的质量。这就是为什么我尝试使用AVCaptureStillImageOutput
对象的原因。
任何人都可以阐明这一点,或将我定向到正确的文档上吗?我已经花了太多时间,而且涉及的过多框架(CoreMedia,CoreVideo,CoreImage,AVFoundation)确实没有得到很好的记录,或者没有任何可以掌握的合理架构。哎呀,我想念QuickTime组件和旧的APIS。
请帮助?有人吗?
答案 0 :(得分:0)
CMSampleBufferGetImageBuffer
返回nil,因为您通过使用AVVideoCodecJPEG请求了JPEG压缩的图像。样本缓冲区将不包含未压缩的原始图像缓冲区,而将包含单个包含jpeg数据的块缓冲区。
您不想在字典中使用AVVideoCodecKey,AVVideoCompressionPropertiesKey等,而是想指定CVPixelFormatType和其他设置,以便它返回未压缩的帧。请参阅AVVideoSettings.h标头顶部的讨论。