Проблема AVFoundation с базовой анимацией в Mac OS X 10.7 Lion - PullRequest
3 голосов
/ 23 сентября 2011

В 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:.

Спасибо вам обоим за помощь.

Ответы [ 2 ]

0 голосов
/ 08 октября 2011

Частичное решение

Приведенный выше код теперь работает для экспорта простых анимаций слоев, но он не будет экспортировать пользовательские CALayers, содержимое которых определяется drawInContext: или его делегированной версией drawLayer: inContext :. CAShapeLayer не будет экспортировать его содержимое, как и MyCustomLayer (насколько я мог видеть).

Следующий шаг: узнайте, как экспортировать пользовательские слои в AVExportSession.

0 голосов
/ 30 сентября 2011

Ааа, вам нужно использовать NSView в качестве основы для вашего слоя анимации.CALayers - очень причудливые звери, и менее известный факт о них заключается в том, что у них есть проблемы с рендерингом, которые иногда требуют, чтобы компонент Quicktime перетаскивался за пределы рамки браузера до его запуска.

Вам придется провести некоторый рефакторинг, но NSView - это абсолютно то, с чего стоит начать.Удачи!

...