我正在使用前置摄像头在iPhone 4上拍摄视频,并将视频与其他媒体资产相结合。我希望这个视频是纵向的 - 所有视频的默认方向都是横向的,在某些情况下,你必须手动管理。
我正在使用AVFoundation,特别是AVAssetExportSession和AVMutableVideoComposition。基于WWDC视频,当我将视频组合成新的合成时,我必须自己处理“修正”方向。
所以,我已经创建了一个附加到我的AVMutableVideoCompositionInstruction的AVMutableVideoCompositionLayerInstruction,我正在使用setTransform:atTime:方法设置一个用于旋转视频的转换:
AVMutableVideoCompositionLayerInstruction *passThroughLayer = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
CGAffineTransform portraitRotationTransform = CGAffineTransformMakeRotation(degreesToRadians(90.0));
[passThroughLayer setTransform:portraitRotationTransform atTime:kCMTimeZero];
问题在于,当我查看导出的视频时,屏幕上没有任何实际内容。如果我将旋转角度减小到45度,我可以在屏幕上看到部分视频 - 它几乎就像它不在中心点旋转一样。我在下面包含图片,以便更清楚地说明我在说什么。
视频的自然尺寸将恢复为480x360。我已经尝试将其更改为360x480并且它不会影响核心问题。
0度轮换:
45度轮换:
90度旋转只是全绿色。
无论如何,我希望之前做过此事的人可以指出我正确的方向。我找不到关于AVFoundation合成和出口中一些更高级主题的任何文档。
答案 0 :(得分:11)
以目前为止的答案为基础。我发现了一种非常好的调试方法,可以找出变换出了什么问题。使用可用的渐变方法,您可以设置变换的动画,以便更容易地查看转换正在执行的操作。
大多数时候,我发现自己的变换似乎什么也没做,直到我意识到仅仅使用视频轨道的preferredTransform属性可能会导致视频输出移出渲染屏幕。
AVMutableVideoCompositionLayerInstruction *videoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
[videoLayerInstruction setTransformRampFromStartTransform:CGAffineTransformIdentity
toEndTransform:videoTrack.preferredTransform
timeRange:CMTimeRangeMake(projectClipStart, projectClipDuration)];
最终,我发现在某些情况下,我需要应用翻译以将旋转的视频带回渲染屏幕。
CGAffineTransformConcat(videoTrack.preferredTransform, CGAffineTransformMakeTranslation(0, renderSize.height))
注意:您的翻译价值可能会有所不同。
答案 1 :(得分:6)
试试这个:
AVMutableVideoCompositionLayerInstruction *passThroughLayer = AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
CGAffineTransform rotationTransform = CGAffineTransformMakeRotation(degreesToRadians(90.0));
CGAffineTransform rotateTranslate = CGAffineTransformTranslate(rotateTransform,320,0);
[passThroughLayer setTransform:rotateTranslate atTime:kCMTimeZero];
本质上,我们的想法是创建一个旋转和平移矩阵。您将其旋转到正确的方向,然后将其转换为视图。当我浏览API时,我没有看到任何指定中心点的方法。
答案 2 :(得分:2)
AVAssetTrack *videoAssetTrack= [[videoAsset tracksWithMediaType:AVMediaTypeVideo] lastObject];
AVMutableCompositionTrack *videoCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, videoAsset.duration) ofTrack:videoAssetTrack atTime:kCMTimeZero error:&error];
videoCompositionTrack.preferredTransform = videoAssetTrack.preferredTransform;
答案 3 :(得分:1)
也可能相关,但在使用前置摄像头时,preferredTransform中存在一个错误。例如,请参阅此处,SDAVAssetExportSession项目中的人员编写了一个解决方法:
答案 4 :(得分:0)
我在Flutter插件项目中找到了解决方案。
- (CGAffineTransform)fixTransform:(AVAssetTrack*)videoTrack {
CGAffineTransform transform = videoTrack.preferredTransform;
if (transform.tx == 0 && transform.ty == 0) {
NSInteger rotationDegrees = (NSInteger)round(radiansToDegrees(atan2(transform.b, transform.a)));
NSLog(@"TX and TY are 0. Rotation: %ld. Natural width,height: %f, %f", (long)rotationDegrees,
videoTrack.naturalSize.width, videoTrack.naturalSize.height);
if (rotationDegrees == 90) {
NSLog(@"Setting transform tx");
transform.tx = videoTrack.naturalSize.height;
transform.ty = 0;
} else if (rotationDegrees == 270) {
NSLog(@"Setting transform ty");
transform.tx = 0;
transform.ty = videoTrack.naturalSize.width;
}
}
return transform;
}
// set layerInstruction
[firstVideoLayerInstruction setTransform:[self fixTransform:firstVideoAssetTrack] atTime:kCMTimeZero];