导出视频时,CAKeyframeAnimation不动画CATextLayer

时间:2013-11-28 02:22:34

标签: ios7 core-animation avfoundation cakeyframeanimation avassetexportsession

我有一个应用程序,我试图在视频上加上时间戳。为此,我使用AVFoundation和Core Animation将CATextLayer放在视频层上。如果我将文本放入CATextLayer的字符串属性,则字符串将正确显示在导出的视频中。如果我然后将动画添加到CATextLayer,则文本永远不会更改。我认为我忽略了一些东西,但我能找到它是什么。

提前感谢您的帮助。

这是一个代码示例。

AVMutableComposition *composition = [AVMutableComposition composition];

AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
videoComposition.frameDuration = CMTimeMake(1, 30);

AVMutableCompositionTrack *videoCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableAudioMix *audioMix = [AVMutableAudioMix audioMix];

AVMutableCompositionTrack *audioCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
NSDictionary *assetOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithBool:YES] forKey:AVURLAssetPreferPreciseDurationAndTimingKey];

AVAsset *asset = [[AVURLAsset alloc] initWithURL:myUrl options:assetOptions];

AVAssetTrack *audioAssetTrack = [[asset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0];
[audioCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:audioAssetTrack atTime:kCMTimeZero error:nil];

AVAssetTrack *videoAssetTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
[videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:videoAssetTrack atTime:kCMTimeZero error:nil];

videoComposition.renderSize = videoCompositionTrack.naturalSize;

AVMutableVideoCompositionInstruction *videoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
videoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, composition.duration);

AVMutableVideoCompositionLayerInstruction *videoCompositionLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoCompositionTrack];
[videoCompositionLayerInstruction setOpacity:1.0f atTime:kCMTimeZero];
videoCompositionInstruction.layerInstructions = @[videoCompositionLayerInstruction];

videoComposition.instructions = @[videoCompositionInstruction];

CALayer *parentLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0.0f, 0.0f, videoComposition.renderSize.width, videoComposition.renderSize.height);

CALayer *videoLayer = [CALayer layer];
videoLayer.frame = CGRectMake(0.0f, 0.0f, videoComposition.renderSize.width, videoComposition.renderSize.height);
[parentLayer addSublayer:videoLayer];

CATextLayer *textLayer = [CATextLayer layer];
textLayer.font = (__bridge CFTypeRef)([UIFont fontWithName:@"Helvetica Neue" size:45.0f]);
textLayer.fontSize = 45.0f;
textLayer.foregroundColor = [UIColor colorWithRed:1.0f green:1.0f blue:1.0f alpha:1.0f].CGColor;
textLayer.shadowColor = [UIColor colorWithRed:0.0f green:0.0f blue:0.0f alpha:1.0f].CGColor;
textLayer.shadowOffset = CGSizeMake(0.0f, 0.0f);
textLayer.shadowOpacity = 1.0f;
textLayer.shadowRadius = 4.0f;
textLayer.alignmentMode = kCAAlignmentCenter;
textLayer.truncationMode = kCATruncationNone;

CAKeyframeAnimation *keyFrameAnimation = [CAKeyframeAnimation animationWithKeyPath:@"string"];

// Step 8: Set the animation values to the object.
keyFrameAnimation.calculationMode = kCAAnimationLinear;
keyFrameAnimation.values = @[@"12:00:00", @"12:00:01", @"12:00:02", @"12:00:03",
                             @"12:00:04", @"12:00:05", @"12:00:06", @"12:00:07",
                             @"12:00:08", @"12:00:09"];
keyFrameAnimation.keyTimes = @[[NSNumber numberWithFloat:0.0f], [NSNumber numberWithFloat:0.1f],
                               [NSNumber numberWithFloat:0.2f], [NSNumber numberWithFloat:0.3f],
                               [NSNumber numberWithFloat:0.4f], [NSNumber numberWithFloat:0.5f],
                               [NSNumber numberWithFloat:0.6f], [NSNumber numberWithFloat:0.7f],
                               [NSNumber numberWithFloat:0.8f], [NSNumber numberWithFloat:0.9f]];
keyFrameAnimation.beginTime = AVCoreAnimationBeginTimeAtZero;
keyFrameAnimation.duration = CMTimeGetSeconds(composition.duration);
keyFrameAnimation.removedOnCompletion = YES;

[textLayer addAnimation:keyFrameAnimation forKey:@"string"];
textLayer.frame = CGRectMake(0.0f, 20.0f, videoComposition.renderSize.width, 55.0f);
[parentLayer addSublayer:textLayer];
videoComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];

AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:composition presetName:AVAssetExportPreset1920x1080];
exportSession.videoComposition = videoComposition;
exportSession.audioMix = audioMix;
exportSession.outputFileType = [exportSession.supportedFileTypes objectAtIndex:0];
exportSession.outputURL = mySaveUrl;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
    self.delegate = nil;

    switch (exportSession.status) {
        case AVAssetExportSessionStatusCancelled:
            NSLog(@"Export session cancelled.");
            break;
        case AVAssetExportSessionStatusCompleted:
            NSLog(@"Export session completed.");
            break;
        case AVAssetExportSessionStatusFailed:
            NSLog(@"Export session failed.");
            break;
        case AVAssetExportSessionStatusUnknown:
            NSLog(@"Export session unknown status.");
            break;
        case AVAssetExportSessionStatusWaiting:
            NSLog(@"Export session waiting.");
            break;
        default:
            break;
    }
    NSError *error = exportSession.error;
    if (error != nil) {
        NSLog(@"An error ocurred while exporting.  Error: %@: %@", error.localizedDescription, error.localizedFailureReason);
    }
}];

2 个答案:

答案 0 :(得分:2)

我与苹果支持保持联系并告诉我这是他的SDK中的一个错误。他们正试图解决这个问题。

此外,我在苹果臭虫记者中打开了一个事件,如果你是苹果开发者,我建议你开一个新的事件来对这一事件施加更大的压力。

https://bugreport.apple.com/logon

最好的问候。

答案 1 :(得分:2)

最后,我喜欢CATextLayer和动画中的解决方案。可能它不是最好的解决方案,但至少它工作正常。

要解决这个问题,我们应该将NSString传递给UIImage或CALayer,然后将所有这些图像(CGImage)放在NSMutableArray中,并在CAKeyAnimation中加载这个可变数组并修改内容变量

 -(UIImage *)imageFromText:(NSString *)text
 {
UIGraphicsBeginImageContextWithOptions(sizeImageFromText,NO,0.0);//Better resolution (antialiasing)
//UIGraphicsBeginImageContext(sizeImageFromText); // iOS is < 4.0

[text drawInRect:aRectangleImageFromText withAttributes:attributesImageFromText];

UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

return image;
}

将图像添加到NSMutableArray

 [NSMutableArrayAux addObject:(__bridge id)[self imageFromText:@"Hello"].CGImage];

设置CAKeyAnimation以修改图像内容(更改图像)

 CAKeyframeAnimation *overlay = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
 overlay.values = [[NSArray alloc] initWithArray:NSMutableArrayAux];

它的工作原理非常好,但是在阵列中需要1或2秒到5000或6000个图像,并且在导出视频时它还需要15000/16000个图像,它会因溢出错误而崩溃。这是框架中的另一个错误。

如您所知,这是框架中的一个问题,至少在Apple修复CATextLayer和动画问题之前,这是一个解决方案,我也将此解决方案提供给苹果。