2012年1月15日日曜日

CVPixelBuffer を保存する

CMSampleBuffer なんかから得られる CVPixelBuffer を保存したくなったのでしてみた。やってることは NSData を使って生のデータを保存しているだけ。このときに、再利用時に必要となりそうなパラメータをファイル名に埋め込んでいる。
- (BOOL)writeBuffer:(CVPixelBufferRef)imageBuffer
{
    CVPixelBufferLockBaseAddress(imageBuffer, 0);
    NSURL *fileURL = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDirectory] lastObject];
    int bufferSize = CVPixelBufferGetDataSize(imageBuffer);
    int width = CVPixelBufferGetWidth(imageBuffer);
    int height = CVPixelBufferGetHeight(imageBuffer);
    int bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
 
    NSString *fileName = [NSString stringWithFormat:@"buffer_%dx%d_%d_%d", width, height, bytesPerRow, bufferSize];
    
    unsigned char *baseAddress = (unsigned char *)CVPixelBufferGetBaseAddress(imageBuffer);
    NSData *data = [NSData dataWithBytes:baseAddress length:bufferSize];
    CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
    
    NSLog(@"PATH: %@", fileURL);
    if ([data writeToURL:[fileURL URLByAppendingPathComponent:fileName] atomically:YES]) {
        NSLog(@"success");
        return YES;
    }else{
        NSLog(@"fail");
        return NO;
    }
}
保存した生のデータを UIImage にするのはこんな感じ。決めうちで入れている値はファイル名から取得したもの。パースが必要なら NSScaner なり、ファイル名をもうちょっと工夫して -[NSString componentsSeparatedByString:] なりを使うとよさそう。
- (UIImage*)imageWithImageBufferContentsOfURL:(NSURL*)url
    NSData *data = [NSData dataWithContentsOfURL:url];
    if (!data) {
        NSLog(@"error");
        return nil;
    }
    CVPixelBufferRef imageBuffer = (CVPixelBufferRef)[data bytes];

    size_t bufferSize = 128808;
    size_t bytesPerRow = 2560;
    size_t width = 640;
    size_t height = 480;

    static CGColorSpaceRef colorSpace = NULL; if (colorSpace == NULL) {
        colorSpace = CGColorSpaceCreateDeviceRGB(); if (colorSpace == NULL) {
            NSLog(@"error");
            return nil;
        } }

    void *baseAddress = imageBuffer;
    CGDataProviderRef dataProvider =
    CGDataProviderCreateWithData(NULL, baseAddress, bufferSize, NULL);
    CGImageRef cgImage =
    CGImageCreate(width, height, 8, 32, bytesPerRow,
                  colorSpace, kCGImageAlphaNoneSkipFirst |
                  kCGBitmapByteOrder32Little,
                  dataProvider, NULL, true, kCGRenderingIntentDefault);
    CGDataProviderRelease(dataProvider);
    UIImage *image = [UIImage imageWithCGImage:cgImage];
    CGImageRelease(cgImage);

    return image
}