CALayer.contents não são processados corretamente no AVMutableComposition
Eu tenho um método muito simples que gera um vídeo com uma imagem de fundo estática que cobre toda a composição de vídeo e uma imagem menor e parcialmente transparente (estilo de marca d'água) localizada na parte inferior do vídeo.
A imagem de fundo é processada corretamente e aparece exatamente da mesma forma que parece em um visualizador de imagens. No entanto, a imagem supostamente renderizada na parte inferior do vídeo é distorcida.
A fonte pode ser baixada aqui, no GitHub.
A saída esperada do meu código (maquete da saída de vídeo desejada):
A saída real do meu código (captura de tela parcial do iOS Simulator):
Como você pode ver, a imagem do rodapé aparece inclinada em um ângulo de 45 graus e um pouco ondulada.
Abaixo está o código que estou usando atualmente para gerar o vídeo. Eu tentei todas as combinações possíveis do conteúdo Grave para a imagem do rodapé, sem sorte. Todos os outros exemplos que eu vi simplesmente definem um CGImageRef para a camadacontents
em seguida, define obounds
, position
eanchorPoint
aos seus valores apropriados. Eu não vi nenhum outro exemplo que defina outras propriedades. Eu li quase toda a documentação para o AVFoundation para ver se há definição de que estou perdendo, mas eu não encontrei nada óbvio ainda.
Qualquer sugestão seria muito apreciada. Obrigado!
Declarações de interface:
CGSize _renderingSize;
float _displayDuration;
AVMutableComposition *mutableComposition;
AVMutableVideoComposition *videoComposition;
AVMutableCompositionTrack *mutableCompositionVideoTrack;
AVAssetExportSession *exporter;
Configurações de ViewDidLoad:
_renderingSize = CGSizeMake(640, 360);
_displayDuration = 2.0;
Bloco de código de renderização:
mutableComposition = [AVMutableComposition composition];
mutableCompositionVideoTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
videoComposition = [AVMutableVideoComposition videoComposition];
videoComposition.renderSize = _renderingSize;
videoComposition.frameDuration = CMTimeMake(1, 30);
CALayer *parentLayer = [CALayer layer];
CALayer *videoLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, videoComposition.renderSize.width, videoComposition.renderSize.height);
videoLayer.frame = CGRectMake(0, 0, videoComposition.renderSize.width, videoComposition.renderSize.height);
[parentLayer addSublayer:videoLayer];
videoComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
NSString *path = [[NSBundle mainBundle] pathForResource:@"blank_1080p" ofType:@"mp4"];
NSURL *url = [NSURL fileURLWithPath:path];
AVAsset *asset = [AVAsset assetWithURL:url];
AVAssetTrack *track = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
[mutableCompositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,CMTimeMakeWithSeconds(_displayDuration, 600)) ofTrack:track atTime:kCMTimeZero error:nil];
CALayer *imageLayer = [CALayer layer];
imageLayer.bounds = parentLayer.frame;
imageLayer.anchorPoint = CGPointMake(0.5, 0.5);
imageLayer.position = CGPointMake(CGRectGetMidX(imageLayer.bounds), CGRectGetMidY(imageLayer.bounds));
imageLayer.contents = (id)[UIImage imageNamed:@"background.png"].CGImage;
imageLayer.contentsGravity = kCAGravityResizeAspectFill;
[parentLayer addSublayer:imageLayer];
UIImage *testImage = [UIImage imageNamed:@"bannerTextLayer.png"];
CALayer *footerLayer = [CALayer layer];
footerLayer.bounds = CGRectMake(0, 0, 540, 40);
footerLayer.anchorPoint = CGPointMake(0.5, 0.5);
footerLayer.position = CGPointMake(CGRectGetMidX(footerLayer.bounds), CGRectGetMidY(footerLayer.bounds));
footerLayer.contents = (id)testImage.CGImage;
footerLayer.contentsGravity = kCAGravityResizeAspectFill;
[parentLayer addSublayer:footerLayer];
AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(_displayDuration, 600));
videoComposition.instructions = @[instruction];
exporter = [[AVAssetExportSession alloc] initWithAsset:mutableComposition presetName:AVAssetExportPresetHighestQuality];
exporter.outputURL = videoURL ;
exporter.videoComposition = videoComposition;
exporter.outputFileType= AVFileTypeMPEG4;
exporter.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(_displayDuration, 600));
exporter.shouldOptimizeForNetworkUse = YES;
[exporter exportAsynchronouslyWithCompletionHandler:^(void){
switch (exporter.status) {
case AVAssetExportSessionStatusFailed:{
NSLog(@"Fail: %@", exporter.error);
break;
}
case AVAssetExportSessionStatusCompleted:{
NSLog(@"Success");
dispatch_async(dispatch_get_main_queue(), ^{
if (self.moviePlayer)
[self.moviePlayer.view removeFromSuperview];
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:videoURL];
self.moviePlayer.view.frame = CGRectMake(0, 0, 320, 180);
[self.moviePlayer setControlStyle:MPMovieControlStyleNone];
[self.previewView addSubview:self.moviePlayer.view];
[self.moviePlayer play];
});
break;
}
default:
break;
}
}];