2014年4月24日木曜日

10fpsで動画を作成

- (void)writeImagesAsMovie:(NSArray *)images
                    toPath:(NSString *)path
{
    NSParameterAssert(images);
    NSParameterAssert(path);
    NSAssert((images.count > 0), @"Set least one image.");
    
    NSFileManager *fileManager = [NSFileManager defaultManager];
    
    // 既にファイルがある場合は削除する
    if ([fileManager fileExistsAtPath:path]) {
        [fileManager removeItemAtPath:path error:nil];
    }
    
    // 最初の画像から動画のサイズ指定する
    CGSize size = ((UIImage *)images[0]).size;
    
    NSError *error = nil;
    
    self.videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:path]
                                                 fileType:AVFileTypeQuickTimeMovie
                                                    error:&error];
    
    if (error) {
        NSLog(@"%@", [error localizedDescription]);
        return;
    }
    
    NSDictionary *outputSettings =
    @{
      AVVideoCodecKey  : AVVideoCodecH264,
      AVVideoWidthKey  : @(size.width),
      AVVideoHeightKey : @(size.height),
      };
    
    AVAssetWriterInput *writerInput = [AVAssetWriterInput
                                       assetWriterInputWithMediaType:AVMediaTypeVideo
                                       outputSettings:outputSettings];
    
    [self.videoWriter addInput:writerInput];
    
    NSDictionary *sourcePixelBufferAttributes =
    @{
      (NSString *)kCVPixelBufferPixelFormatTypeKey : @(kCVPixelFormatType_32ARGB),
      (NSString *)kCVPixelBufferWidthKey           : @(size.width),
      (NSString *)kCVPixelBufferHeightKey          : @(size.height),
      };
    
    AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor
                                                     assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput
                                                     sourcePixelBufferAttributes:sourcePixelBufferAttributes];
    
    writerInput.expectsMediaDataInRealTime = YES;
    
    // 動画生成開始
    if (![self.videoWriter startWriting]) {
        NSLog(@"Failed to start writing.");
        return;
    }
    
    [self.videoWriter startSessionAtSourceTime:kCMTimeZero];
    
    CVPixelBufferRef buffer = NULL;
    
    int frameCount = 0;
    double durationForEachImage = 0.05;
    int32_t fps = 20;
    
    for (UIImage *image in images) {
        if (adaptor.assetWriterInput.readyForMoreMediaData) {
            //CMTime frameTime = CMTimeMake((int64_t)frameCount * fps * durationForEachImage, fps);
            //CMTime frameTime = CMTimeMake((int64_t)frameCount * 60, 600);
            CMTime frameTime = CMTimeMake(1, 10);
            CMTime lastTime=CMTimeMake(frameCount, 10);
            CMTime presentTime=CMTimeAdd(lastTime, frameTime);

            buffer = [self pixelBufferFromCGImage:image.CGImage];
            
            if (![adaptor appendPixelBuffer:buffer withPresentationTime:presentTime]) {
                NSLog(@"Failed to append buffer. [image : %@]", image);
            }
            
            if(buffer) {
                CVBufferRelease(buffer);
            }
            
            frameCount++;
            NSLog(@"%d",frameCount);
        }
    }
    
    // 動画生成終了
    [writerInput markAsFinished];
    [self.videoWriter finishWritingWithCompletionHandler:^{
        NSLog(@"Finish writing!");
        NSURL *url = [NSURL URLWithString:path];
        
        if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:url])
        {
            [library writeVideoAtPathToSavedPhotosAlbum:url
                                        completionBlock:^(NSURL *assetURL, NSError *assetError)
             {
                 if (assetError) { }
             }];
        }
    }];
    CVPixelBufferPoolRelease(adaptor.pixelBufferPool);
    
}

- (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image
{
    NSDictionary *options = @{
                              (NSString *)kCVPixelBufferCGImageCompatibilityKey : @(YES),
                              (NSString *)kCVPixelBufferCGBitmapContextCompatibilityKey: @(YES),
                              };
    
    CVPixelBufferRef pxbuffer = NULL;
    
    CVPixelBufferCreate(kCFAllocatorDefault,
                        CGImageGetWidth(image),
                        CGImageGetHeight(image),
                        kCVPixelFormatType_32ARGB,
                        (__bridge CFDictionaryRef)options,
                        &pxbuffer);
    
    CVPixelBufferLockBaseAddress(pxbuffer, 0);
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
    
    CGColorSpaceRef rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    CGContextRef context = CGBitmapContextCreate(pxdata,
                                                 CGImageGetWidth(image),
                                                 CGImageGetHeight(image),
                                                 8,
                                                 4 * CGImageGetWidth(image),
                                                 rgbColorSpace,
                                                 (CGBitmapInfo)kCGImageAlphaNoneSkipFirst);
    
    CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));
    
    CGAffineTransform flipVertical = CGAffineTransformMake(1, 0, 0, -1, 0, CGImageGetHeight(image));
    
    CGContextConcatCTM(context, flipVertical);
    
    CGAffineTransform flipHorizontal = CGAffineTransformMake(-1.0, 0.0, 0.0, 1.0, CGImageGetWidth(image), 0.0);
    
    CGContextConcatCTM(context, flipHorizontal);
    
    CGContextDrawImage(context, CGRectMake(0, 0, CGImageGetWidth(image), CGImageGetHeight(image)), image);
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);
    
    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);
    
    return pxbuffer;

}

0 件のコメント:

コメントを投稿