I am working on more of mini-project that will be later included into a new project. It is basically a test unit.
What I am doing is creating an AVCaptureSession
and then creating a method for OutputSampleBufferDelegate
. In the method, I convert the sampleBuffer
into a UIImage
and save the UIImage
. When I run the application on my iPhone 4 it can only save 2-3 images per second. There must be a more efficient way to save the image.
Can someone help me speed it up?
Thanks!
lots of the code is from here
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
UIImage *resultUIImage = [self imageFromSampleBuffer:sampleBuffer];
NSData *imageData = [NSData dataWithData:UIImagePNGRepresentation(resultUIImage)];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
CMTime frameTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
NSString *filename = [NSString stringWithFormat:@"%f.png", CMTimeGetSeconds(frameTime)];
NSString *finalPath = [path stringByAppendingString:filename];
[imageData writeToFile:finalPath atomically:YES];
}
// 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 imageWithCGI开发者_运维百科mage:quartzImage];
// Release the Quartz image
CGImageRelease(quartzImage);
return image;
}
Using this code I can get the time it saves the image down to 0.1 sec.
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
double frameTime = CFAbsoluteTimeGetCurrent();
UIImage *resultUIImage = [self imageFromSampleBuffer:sampleBuffer];
// takes freaking forever to do.
double pre = CFAbsoluteTimeGetCurrent();
NSData *imageData = UIImageJPEGRepresentation(resultUIImage, 0.9);
NSLog(@"It took to write the file:%f",CFAbsoluteTimeGetCurrent()-pre);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory
,NSUserDomainMask
, YES);
NSString *path = [paths objectAtIndex:0];
NSString *filename = [NSString stringWithFormat:@"%f.png", frameTime];
NSString *finalPath = [path stringByAppendingString:filename];
[imageData writeToFile:finalPath atomically:YES];
}
Could you please see how many images you can generate if you comment out the following line in your first method:
[imageData writeToFile:finalPath atomically:YES];
The reason I say that is you are going to spend a lot of time writing that image off to disk. It would be interesting to see how this performs without writing the images to disk. At least that way you will know if all the time is spent in actually creating the image versus storing the image. Or you could do as another poster mentioned and use Instruments to time how long you are within each method.
If it turns out that writing the images to disk is taking too long, then I suggest trying to implement a caching mechanism that will cache images in memory and write them to disk later.
It might also help to try calling writeToFile:atomically: on a background thread.
精彩评论