AV基金会动画永远不会开始播放

时间:2014-02-13 16:34:30

标签: ios animation core-animation avfoundation

我正在尝试加载视频,在其上添加动画然后将其导出, 但动画永远不会在导出的视频中播放。 它只显示图像" dogge_icon.png"原样。

我尝试过不同类型的动画,不确定我做错了什么。 任何帮助将不胜感激。

代码:

-(void) createCompositionWithPicture {
    AVMutableComposition* composition = [AVMutableComposition composition];

    NSString *videoPath = [[NSBundle mainBundle] pathForResource:@"Movie" ofType:@"m4v"];

    NSLog(@"Path: %@", videoPath);
    NSURL *videoURL = [[NSURL alloc] initFileURLWithPath:videoPath];
    AVURLAsset *videoAsset = [AVURLAsset URLAssetWithURL:videoURL options:nil];

    AVMutableCompositionTrack *videoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

    [videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:[[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:nil];

    // Create an AVMutableVideoCompositionLayerInstruction for the video track.
    AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, videoAsset.duration);

    AVMutableVideoCompositionLayerInstruction *videolayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];

    // Setup video composition
    AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
    videoComposition.renderSize = CGSizeMake(videoTrack.naturalSize.width,videoTrack.naturalSize.height);
    videoComposition.frameDuration = CMTimeMake(1, 30);

    mainInstruction.layerInstructions = [NSArray arrayWithObject:videolayerInstruction];
    videoComposition.instructions = [NSArray arrayWithObject:mainInstruction];

    NSLog(@"Width: %f Height: %f", videoTrack.naturalSize.width, videoTrack.naturalSize.height);

    // Setup animation layer
    UIImage* image = [UIImage imageNamed:@"dogge_icon.png"];
    CALayer *animationLayer = [CALayer layer];
    animationLayer.frame = CGRectMake(0, 0, image.size.width,  image.size.height);
    [animationLayer setMasksToBounds:YES];
    [animationLayer setContents: (id)image.CGImage];

    // Add animation
    CABasicAnimation *animation =
    [CABasicAnimation animationWithKeyPath:@"transform.scale"];

    animation.duration=5.0;
    animation.autoreverses=YES;
    animation.fromValue = [NSNumber numberWithFloat:1.0f];
    animation.toValue = [NSNumber numberWithFloat:2.0f];
    animation.repeatCount=10;
    animation.beginTime = AVCoreAnimationBeginTimeAtZero;
    [animationLayer addAnimation:animation forKey:@"scale"];
    NSLog(@"animationLayer animations: %@", [animationLayer animationKeys]);

    // Build layer hierarchy
    CALayer *parentLayer = [CALayer layer];
    CALayer *videoLayer = [CALayer layer];

    parentLayer.frame = CGRectMake(0, 0, videoTrack.naturalSize.width, videoTrack.naturalSize.height);
    videoLayer.frame = CGRectMake(0, 0, videoTrack.naturalSize.width, videoTrack.naturalSize.height);

    [parentLayer addSublayer:videoLayer];
    [parentLayer addSublayer:animationLayer];

    videoComposition.animationTool = [AVVideoCompositionCoreAnimationTool
                             videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];

    // Export 
    AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetHighestQuality];

    NSString *exportVideoPath =  [STPFileUtilities getPathToFileIn: NSDocumentDirectory WithName: @"composition.mov"];
    [STPFileUtilities deleteFileIfExists:exportVideoPath];
    NSURL *exportURL = [NSURL fileURLWithPath:exportVideoPath];

    exportSession.outputURL = exportURL;
    exportSession.outputFileType = AVFileTypeQuickTimeMovie;
    exportSession.videoComposition =  videoComposition;
    [exportSession exportAsynchronouslyWithCompletionHandler:^{
        switch (exportSession.status) {
            case AVAssetExportSessionStatusFailed:{
                NSLog(@"FAIL: %@", exportSession.error);
                break;
            }
            case AVAssetExportSessionStatusCompleted: {
                NSLog (@"SUCCESS");
            }
        };
    }];
}

2 个答案:

答案 0 :(得分:2)

我不确定我做了什么。 我从头开始重写了整个代码并添加了

animation.removedOnCompletion = NO;

所有动画现在都有效。

答案 1 :(得分:1)

文档说明:

  

使用AVVideoCompositionCoreAnimationTool对象进行合并   视频合成中的核心动画。

     

任何动画都将在视频的时间轴上解释,而不是   实时,所以你应该:

     
      
  1. 将动画的beginTime属性设置为AVCoreAnimationBeginTimeAtZero而不是0(CoreAnimation替换为CACurrentMediaTime);
  2.   
  3. 将动画上的removedOnCompletion设置为NO,这样就不会自动删除;
  4.   
  5. 避免使用与UIView对象关联的图层。
  6.   

https://developer.apple.com/library/ios/documentation/AVFoundation/Reference/AVVideoCompositionCoreAnimationTool_Class/Reference/Reference.html#//apple_ref/doc/uid/TP40009744-CH1-DontLinkElementID_1

因此添加

的原因
animation.removedOnCompletion = NO;

按照您对自己问题的回答中的说明工作。虽然我不是100%肯定这里发生了什么,但如果我不得不猜测,我会说核心动画是经过预处理然后与视频层合成的。如果删除它,则在视频合成发生之前将其删除。

当使用带有合成的CALayers和Animations时,如果我想让它们“关闭”,我必须将它们设置为0不透明度以隐藏它们。


如何在特定时间开始动画。

以下示例(未经测试)实质上是将整个图层设置为透明(不透明度为0.0)。在2秒(startTime)时,它开始动画并在3秒内将不透明度从0.5减少到1.0(半透明到完全不透明)。它应该在结束时“关闭” - 它将默认返回到它的初始化(完全透明)值。

float startTime = 2.0f;
float duration = 3.0f;
CALayer layerToAnimate = [CALayer layer];
layerToAnimate.opacity = 0.0;

// Just turn it on then off.
CABasicAnimation *myAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
[myAnimation setBeginTime: startTime];
[myAnimation setDuration: duration];
[myAnimation setFromValue:[NSNumber numberWithFloat:0.5]];
[myAnimation setToValue:[NSNumber numberWithFloat:1.0]];
[myAnimation setRemovedOnCompletion:NO];

[layerToAnimate addAnimation:myAnimation forKey:@"myUniqueAnimationKey"];

// NB You may not need to be specific on track ID. I like to do so to use to sort layers in to the proper order.
AVVideoCompositionCoreAnimationTool *aniTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithAdditionalLayer:_layerToAnimate asTrackID:intTrackID];

基本上就是这样,只需设置开始和持续时间,以秒为单位。它可以在帧和时间之间进行“有趣”的跟踪,但是你可以做到。我使用大量的动画层连接到一个层,所有动画层都有多个时间。最大的麻烦就是跟踪什么是什么以及何时发生。