3

I want to animate images smoothly while converting them to video. Dispite of searching SO, I am unable to understand how to achive it. I tried changing the Rotation angle(CGAffineTransformRotation), Translations and Scaling but didn't found a way to for the smooth animations. Heres how I am converting array of photos to video :

- (void)createVideoWithArrayImages:(NSMutableArray*)images size:(CGSize)size time:(float)time output:(NSURL*)output {
    //getting a random path
    NSError *error;

    AVAssetWriter *videoWriter  = [[AVAssetWriter alloc] initWithURL:output fileType:AVFileTypeMPEG4 error: &error];
    NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: AVVideoCodecH264, AVVideoCodecKey,
                                   [NSNumber numberWithInt:size.width], AVVideoWidthKey,
                                   [NSNumber numberWithInt:size.height], AVVideoHeightKey,
                                   nil];

    AVAssetWriterInput* videoWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];

    AVAssetWriterInputPixelBufferAdaptor *adaptor = [AVAssetWriterInputPixelBufferAdaptor  assetWriterInputPixelBufferAdaptorWithAssetWriterInput: videoWriterInput sourcePixelBufferAttributes:nil];

    videoWriterInput.expectsMediaDataInRealTime = YES;
    [videoWriter addInput: videoWriterInput];
    [videoWriter startWriting];
    [videoWriter startSessionAtSourceTime:kCMTimeZero];


    CVPixelBufferRef buffer = NULL;
    //convert uiimage to CGImage.

    //convert uiimage to CGImage.
    NSInteger fps   = 30;
    int frameCount  = 0;

    for(UIImage *img  in images) {
        //for(VideoFrame * frm in imageArray)
        NSLog(@"**************************************************");
        //UIImage * img = frm._imageFrame;
        buffer                          = [self videoPixelBufferFromCGImage:[img CGImage] andSize:size andAngle:(int)[images indexOfObject:img]];
        double numberOfSecondsPerFrame  = time / images.count;
        double frameDuration            = fps * numberOfSecondsPerFrame;

        BOOL append_ok  = NO;
        int j           = 0;

        while (!append_ok && j < fps) {
            if (adaptor.assetWriterInput.readyForMoreMediaData) {
                //print out status:
                NSLog(@"Processing video frame (%d,%d)",frameCount,(int)[images count]);

                CMTime frameTime    = CMTimeMake(frameCount * frameDuration,(int32_t) fps);
                NSLog(@"Frame Time  : %f", CMTimeGetSeconds(frameTime));
                append_ok           = [adaptor appendPixelBuffer:buffer withPresentationTime:frameTime];
                if(!append_ok) {
                    NSError *error = videoWriter.error;
                    if(error!=nil) {
                        NSLog(@"Unresolved error %@,%@.", error, [error userInfo]);
                    }
                }
            }
            else {
                printf("adaptor not ready %d, %d\n", frameCount, j);
                [NSThread sleepForTimeInterval:0.1];
            }
            j++;
        }
        if (!append_ok) {
            printf("error appending image %d times %d\n, with error.", frameCount, j);
        }
        frameCount++;
        NSLog(@"**************************************************");
    }

    [videoWriterInput markAsFinished];
    [videoWriter finishWriting];

    videoWriter = nil;
    if(buffer != NULL)
        CVPixelBufferRelease(buffer);
    NSLog(@"************ write standard video successful ************");
}

Here CVPixelBufferRef is returned as follows :

- (CVPixelBufferRef)videoPixelBufferFromCGImage: (CGImageRef) image andSize:(CGSize) size andAngle:(int)angle {
    NSDictionary *options       = [NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithBool:YES], kCVPixelBufferCGImageCompatibilityKey, [NSNumber numberWithBool:YES],kCVPixelBufferCGBitmapContextCompatibilityKey, nil];

    CVPixelBufferRef pxbuffer   = NULL;
    CVReturn status             = CVPixelBufferCreate(kCFAllocatorDefault, size.width, size.height, kCVPixelFormatType_32ARGB, (__bridge CFDictionaryRef) options, &pxbuffer);

    NSParameterAssert(status == kCVReturnSuccess && pxbuffer != NULL);

    CVPixelBufferLockBaseAddress(pxbuffer, 0);
    void *pxdata = CVPixelBufferGetBaseAddress(pxbuffer);
    NSParameterAssert(pxdata != NULL);

    CGColorSpaceRef rgbColorSpace   = CGColorSpaceCreateDeviceRGB();
    CGContextRef context            = CGBitmapContextCreate(pxdata, size.width, size.height, 8, 4*size.width, rgbColorSpace, kCGImageAlphaPremultipliedFirst);
    NSParameterAssert(context);
    CGContextConcatCTM(context, CGAffineTransformMakeRotation(0));
    CGContextDrawImage(context, CGRectMake(0, 0, size.width, size.height), image);
    CGColorSpaceRelease(rgbColorSpace);
    CGContextRelease(context);
    CVPixelBufferUnlockBaseAddress(pxbuffer, 0);

    return pxbuffer;
}

I tried adding Translations to the CVPixelBufferRef but thing didn't worked out for me. Any guide, any help would be very useful.

Nikhil Lihla
  • 607
  • 6
  • 21

1 Answers1

1

YOu don't specify what you want to achieve, but I've used AVVideoCompositionCoreAnimationTool to include animated CALayers in a AVMutableVideoComposition.

Here is the reference to that class

Hope that helps!

yairsz
  • 438
  • 5
  • 15
  • I want to animate photos like fade in fade out, swip up down and other sort of animations. I will see the reference tomorrow and will reply if that was helpful. Thank-you for the initiative. – Nikhil Lihla Dec 03 '15 at 17:57
  • This class allows you to create animations just like you would for CALayers. It sounds like it will meet your needs. – yairsz Dec 03 '15 at 17:59
  • Could you please post some code In reference to your answer. An example would be very helpful. – Nikhil Lihla Dec 03 '15 at 18:02
  • this [question](http://stackoverflow.com/questions/29760283/avvideocompositioncoreanimationtool-not-adding-all-calayers) can give you an idea – yairsz Dec 03 '15 at 18:09
  • [here](http://stackoverflow.com/questions/5997677/mix-video-with-static-image-in-calayer-using-avvideocompositioncoreanimationtool?rq=1) is another good one – yairsz Dec 03 '15 at 18:11
  • If I am not wrong AVVideoCompositionCoreAnimationTool adds a CALayer over the video layer and then it merges all the layers together to form a video. But here I want to animate photos (that are the part of video itself). How would I do that. Please feel free to correct me if I am wrong. I haven't worked with AVfoundation before. – Nikhil Lihla Dec 03 '15 at 18:26
  • What is in the array of images? animation frames or individual pictures for a slide show? – yairsz Dec 03 '15 at 20:23
  • Each image can be a CALayer like [this](http://stackoverflow.com/questions/1564940/display-an-image-or-uiimage-with-a-plain-calayer). Then do position, opacity or scale animations with something like CABasicAnimation. – yairsz Dec 03 '15 at 20:28
  • Hi @yairsz, i tried adding each photo as a CALayer. but every time failed to achive the desired thing. I tried [this](http://www.raywenderlich.com/30200/avfoundation-tutorial-adding-overlays-and-animations-to-videos) tutorial from RayWenderlich, but the code from this tutorial also didn't worked for me. Any help would be just great. – Nikhil Lihla Dec 09 '15 at 08:53
  • I finally got it working. Thanks a ton. Things weren't working on simulator but eventually when i tested on device, it worked like a charm. – Nikhil Lihla Dec 10 '15 at 12:03
  • I am in stuck with the same :( any code snippet would be great @Nikhil Lihla – pigeon_39 Sep 25 '17 at 12:52