AVVideoCompositionCoreAnimationTool 和 CALayer 在纵向模式下?

Posted

技术标签:

【中文标题】AVVideoCompositionCoreAnimationTool 和 CALayer 在纵向模式下?【英文标题】:AVVideoCompositionCoreAnimationTool and CALayer in portrait mode? 【发布时间】:2011-10-22 17:33:09 【问题描述】:

我正在尝试在 ios 4.3 上使用 AVMutableComposition、AVMutableVideoComposition 和 AVVideoCompositionCoreAnimationTool 将 CALayer 烘焙成纵向模式视频(导出时)。这一切都适用于景观。但是,如果我以纵向拍摄视频,则 AVVideoCompositionCoreAnimationTool 将忽略视频轨道上的变换。也就是说,对于纵向模式视频,我将 AVMutableCompositionTrack.preferredTransform 设置为来自原始资产视频轨道的 preferredTransform 值。只要我不使用 AVVideoCompositionCoreAnimationTool,它就可以工作,并且视频以纵向模式出现。但是,一旦我添加了 AVVideoCompositionCoreAnimationTool 和 CALayer,文件就会以横向形式出现。 (CALayer 显示正确,但其后面的视频在其一侧,并且文件的纵横比关闭)。我尝试将变换应用于 CALayer,并在 ACVideoComposition 中设置变换。这些都不会改变所生成文件的方向(它仍然是 480x369,而不是 360x480)。有没有办法使用 AVVideoCompositionCoreAnimationTool 渲染纵向模式视频?

首先我设置了一个 AVMutableComposition 和 AVMutableVideoComposition

AVMutableComposition *composition = [AVMutableComposition composition];
AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVURLAsset *videoAsset = [AVURLAsset URLAssetWithURL:url options:nil];
CMTimeRange timeRange = CMTimeRangeMake(kCMTimeZero, [videoAsset duration]);
AVAssetTrack *clipVideoTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];

CGSize videoSize = CGSizeApplyAffineTransform(clipVideoTrack.naturalSize, clipVideoTrack.preferredTransform);
videoSize.width = fabs(videoSize.width);
videoSize.height = fabs(videoSize.height);

CMTime titleDuration = CMTimeMakeWithSeconds(5, 600);
CMTimeRange titleRange = CMTimeRangeMake(kCMTimeZero, titleDuration);

[compositionVideoTrack insertTimeRange:titleRange ofTrack:nil atTime:kCMTimeZero error:nil];
[compositionVideoTrack insertTimeRange:timeRange ofTrack:clipVideoTrack atTime:titleDuration error:nil];
compositionVideoTrack.preferredTransform = clipVideoTrack.preferredTransform;

AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition];
AVMutableVideoCompositionInstruction *passThroughInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
passThroughInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, [composition duration]);
AVAssetTrack *videoTrack = [[composition tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVMutableVideoCompositionLayerInstruction *passThroughLayer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];    
passThroughInstruction.layerInstructions = [NSArray arrayWithObject:passThroughLayer];
videoComposition.instructions = [NSArray arrayWithObject:passThroughInstruction];       
videoComposition.frameDuration = CMTimeMake(1, 30); 
videoComposition.renderSize = videoSize;
videoComposition.renderScale = 1.0;

还有一个带有标题的 CALayer

CALayer *animationLayer = [CALayer layer];
animationLayer.bounds = CGRectMake(0, 0, videoSize.width, videoSize.height);

CATextLayer *titleLayer = [CATextLayer layer];
titleLayer.string = [effect valueForKey:@"title"];
titleLayer.font = [effect valueForKey:@"font"];
titleLayer.fontSize = 30;

titleLayer.alignmentMode = kCAAlignmentCenter;
titleLayer.bounds = CGRectMake(0, 0, videoSize.width, videoSize.height / 6);

[animationLayer addSublayer:titleLayer];
titleLayer.anchorPoint =  CGPointMake(0.5, 0.5);
titleLayer.position = CGPointMake(CGRectGetMidX(layer.bounds), CGRectGetMidY(layer.bounds));    

CABasicAnimation *fadeAnimation = [CABasicAnimation animationWithKeyPath:@"opacity"];
fadeAnimation.fromValue = [NSNumber numberWithFloat:1.0];
fadeAnimation.toValue = [NSNumber numberWithFloat:0.0];
fadeAnimation.additive = NO;
fadeAnimation.removedOnCompletion = NO;
fadeAnimation.beginTime = 3.5;
fadeAnimation.duration = 1.0;
fadeAnimation.fillMode = kCAFillModeBoth;
[titleLayer addAnimation:fadeAnimation forKey:nil];

最后我将 CALayer 添加到 AVMutableVideoComposition

CALayer *parentLayer = [CALayer layer];
CALayer *videoLayer = [CALayer layer];

parentLayer.bounds = CGRectMake(0, 0, videoSize.width, videoSize.height);
parentLayer.anchorPoint =  CGPointMake(0, 0);
parentLayer.position = CGPointMake(0, 0);

videoLayer.bounds = CGRectMake(0, 0, videoSize.width, videoSize.height);
[parentLayer addSublayer:videoLayer];
videoLayer.anchorPoint =  CGPointMake(0.5, 0.5);
videoLayer.position = CGPointMake(CGRectGetMidX(parentLayer.bounds), CGRectGetMidY(parentLayer.bounds));
[parentLayer addSublayer:layer];    
animationLayer.anchorPoint =  CGPointMake(0.5, 0.5);
animationLayer.position = CGPointMake(CGRectGetMidX(parentLayer.bounds), CGRectGetMidY(parentLayer.bounds));
videoComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];

然后导出!

AVAssetExportSession *exportSession = [[[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetMediumQuality] autorelease];
exportSession.videoComposition = videoComposition; 

NSURL *segmentFileURL = //some local URL
exportSession.outputFileType = @"com.apple.quicktime-movie";
exportSession.outputURL = segmentFileURL;


[exportSession exportAsynchronouslyWithCompletionHandler:^
    switch ([exportSession status]) 
        case AVAssetExportSessionStatusFailed:
            Log(@"Export failed: %@", [exportSession error]);
            break;
        case AVAssetExportSessionStatusCancelled:
            Log(@"Export canceled");
            break;
        case AVAssetExportSessionStatusCompleted:
            Log(@"Export done");
            break;
    
]; 

此代码在横向模式下工作,如果我删除 videoComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer]; 行,也可以在纵向模式下工作

【问题讨论】:

我遇到了同样的问题。你找到解决办法了吗? 是的,尽管我在纵向模式构图中也遇到了许多其他问题。诀窍是在 AVMutableVideoCompositionLayerInstruction 上设置变换。但是,正确的变换不是资产的首选变换。从首选变换开始,然后应用额外的平移和翻转。你会发现一些有用的东西(作为帧大小的函数)。不幸的是,每个方向的正确变换都是不同的。基本上,合成中有一个错误,我们正在通过定位导出层来解决它。我确实让它工作了。 【参考方案1】:

试试这个并添加您的其他说明。

///turn video 90 degrees
AVMutableVideoCompositionLayerInstruction *passThroughLayer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:clipVideoTrack];
CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(degreesToRadians(90.0));
CGAffineTransform rotateTranslate = CGAffineTransformTranslate(rotationTransform,320,0);
[passThroughLayer setTransform:rotateTranslate atTime:kCMTimeZero];

告诉我进展如何!

麦克麦克

【讨论】:

不好(我之前尝试过,将 compositionVideoTrack.preferredTransform 传递给 passThroughLayer setTransform)。纵横比仍然是横向的,没有视频帧显示(除了 CALayer 动画)。似乎 AVVideoCompositionCoreAnimationTool 不处理矩阵。 这可能适用于某些视频,但不适用于我测试过的视频。无论哪种方式,这对我都有很大帮助,因为这似乎是正确的方法。谢谢。

以上是关于AVVideoCompositionCoreAnimationTool 和 CALayer 在纵向模式下?的主要内容,如果未能解决你的问题,请参考以下文章