В Mac OS X 10.7 Apple представила AVFoundation, и я пытаюсь создать простой быстрый фильм, содержащий анимированные фигуры. Проблема в том, что основная анимация не рендерится, и в итоге я получаю только чистое «черное» видео. Ниже приведен код, который я использовал. Я перепробовал много вариантов, но, увы, ни один из них не работает. Состояние экспорта всегда «Завершено».
Странно то, что представление пользовательского интерфейса содержит другую настройку слоя с тем же способом, но добавленной к AVSynchronizedLayer, и она отображается очень хорошо, и я могу прокручивать вперед и назад в анимации.
// NOTE: composition is an AVMutableComposition containing a single video
// track (30s of black in 1280 x 720).
// Create the animated layer
CALayer *renderAnimLayer = [CALayer layer];
renderAnimLayer.frame = CGRectMake(0, 0, 1280, 720);
// -- EDIT: Added animated square (now animates)
renderAnimLayer.backgroundColor = CGColorCreateGenericRGB(0.3, 0.0, 0.0, 0.5);
// -- Removed
// [self setupAnimationOnLayer:renderAnimLayer];
CALayer *square = [CALayer layer];
square.backgroundColor = CGColorCreateGenericRGB(0, 0, 1, 0.8);
square.frame = CGRectMake(100, 100, 100, 100);
[CATransaction begin];
[CATransaction setDisableActions:YES];
[CATransaction setAnimationDuration:30.0];
CABasicAnimation *animation = [CABasicAnimation animation];
animation.fromValue = [NSValue valueWithPoint:square.position];
animation.toValue = [NSValue valueWithPoint:CGPointOffset(square.position, 800, 400)];
animation.removedOnCompletion = NO;
animation.beginTime = AVCoreAnimationBeginTimeAtZero;
animation.duration = 30.0;
[CATransaction commit];
[square addAnimation:animation forKey:@"position"];
[renderAnimLayer addSublayer:square];
// -- End of Edit
// Create a composition
AVMutableVideoCompositionLayerInstruction *layerInstr1 =
[AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstruction];
layerInstr1.trackID = 2;
AVMutableVideoCompositionInstruction *instr = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instr.timeRange = CMTimeRangeMake(kCMTimeZero, composition.duration);
instr.layerInstructions = [NSArray arrayWithObject:layerInstr1];
AVMutableVideoComposition *renderComp = [AVMutableVideoComposition videoComposition];
renderComp.renderSize = renderAnimLayer.frame.size;
renderComp.frameDuration = CMTimeMake(1, 30); // Normally 1,30
renderComp.instructions = [NSArray arrayWithObject:instr];
renderComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithAdditionalLayer:renderAnimLayer asTrackID:2];
// Create an export session and export
AVAssetExportSession *exportSession = [AVAssetExportSession exportSessionWithAsset:composition presetName:@"AVAssetExportPreset1280x720"];
exportSession.outputURL = [NSURL URLWithString:@"file:///Users/eric/Desktop/toto.mov"];
exportSession.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMake(30, 1));
exportSession.shouldOptimizeForNetworkUse = YES;
exportSession.videoComposition = renderComp;
// Just see how things have finished.
[exportSession exportAsynchronouslyWithCompletionHandler:^() {
NSLog(@"Export completed with status: %ld", exportSession.status);
}];
// TODO: remove once everything works and objects have been retained.
while (exportSession.progress < 1.0)
usleep(200000);
Найдена причина проблемы
Спасибо @ChristianK за указатель. После добавления анимации синего квадрата и проверки ее работоспособности я должен был сделать вывод, как и ChritianK, что проблема связана с моим setupAnimationOnLayer. Сначала я подумал, что это способ настройки анимации по ключевым кадрам, но это тоже сработало. Оказывается, что я использовал CAShapeLayers и согласно этот вопрос CAShapeLayers не рендерится при вызове renderInContext, что, как я полагаю, AVExportSession пытается сделать в фоновом режиме. Это также объясняет, почему у меня нет этой проблемы, когда я смотрю на настройку вида с поддержкой слоя с тем же вызовом setupAnimationOnLayer:.
Спасибо вам обоим за помощь.