我想拍摄一段视频(例如:使用 iPhone 拍摄的 16:9 视频)并将其放置在具有自定义背景颜色的正方形中并居中。我的代码是这样的:
- (void)videoOutput
{
if (!self.firstAsset) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Error" message:@"Please Load a Video Asset First"
delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
[alert show];
return;
}
AVMutableComposition *mixComposition = [[AVMutableComposition alloc] init];
AVMutableCompositionTrack *videoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
preferredTrackID:kCMPersistentTrackID_Invalid];
[videoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, self.firstAsset.duration)
ofTrack:[[self.firstAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
atTime:kCMTimeZero error:nil];
AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, self.firstAsset.duration);
AVMutableVideoCompositionLayerInstruction *videolayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];
AVAssetTrack *videoAssetTrack = [[self.firstAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
CGSize videoSize = [[[firstAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] naturalSize];
NSLog(@"Video Size W:%f, H:%f",videoSize.width,videoSize.height);
float scaleRatio = 600/videoSize.width;
[videolayerInstruction setTransform:CGAffineTransformMakeScale(scaleRatio, scaleRatio) atTime:kCMTimeZero];
[videolayerInstruction setOpacity:0.0 atTime:self.firstAsset.duration];
mainInstruction.layerInstructions = [NSArray arrayWithObjects:videolayerInstruction,nil];
AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition];
float renderWidth, renderHeight;
renderWidth = 600;
renderHeight = 600;
mainCompositionInst.renderSize = CGSizeMake(renderWidth, renderHeight);
mainCompositionInst.instructions = [NSArray arrayWithObject:mainInstruction];
mainCompositionInst.frameDuration = CMTimeMake(1, 30);
[self applyVideoEffectsToComposition:mainCompositionInst size:CGSizeMake(600, 600)];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *myPathDocs = [documentsDirectory stringByAppendingPathComponent:
[NSString stringWithFormat:@"FinalVideo-%d.mov",arc4random() % 1000]];
NSURL *url = [NSURL fileURLWithPath:myPathDocs];
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mixComposition
presetName:AVAssetExportPresetHighestQuality];
exporter.outputURL=url;
exporter.outputFileType = AVFileTypeQuickTimeMovie;
exporter.shouldOptimizeForNetworkUse = YES;
exporter.videoComposition = mainCompositionInst;
[exporter exportAsynchronouslyWithCompletionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
[self exportDidFinish:exporter];
});
}];
}
- (void)applyVideoEffectsToComposition:(AVMutableVideoComposition *)composition size:(CGSize)size
{
UIImage *borderImage = nil;
borderImage = [self imageWithColor:[UIColor greenColor] rectSize:CGRectMake(0, 0, size.width, size.height)];
CALayer *backgroundLayer = [CALayer layer];
[backgroundLayer setContents:(id)[borderImage CGImage]];
backgroundLayer.frame = CGRectMake(0, 0, size.width, size.height);
[backgroundLayer setMasksToBounds:YES];
AVPlayerItem *playerItem2 = [[AVPlayerItem alloc] initWithAsset:secondAsset];
AVPlayer *videoPlayer2 = [AVPlayer playerWithPlayerItem:playerItem2];
AVPlayerLayer *videoLayer = [AVPlayerLayer playerLayerWithPlayer:videoPlayer2];
CGSize videoSize = [[[secondAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] naturalSize];
[videoLayer setBackgroundColor:[UIColor whiteColor].CGColor];
videoLayer.frame = CGRectMake(0, (600-337.5)/2, 600, 337.5);
CALayer *parentLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, size.width, size.height);
[parentLayer addSublayer:backgroundLayer];
[parentLayer addSublayer:videoLayer];
composition.animationTool = [AVVideoCompositionCoreAnimationTool
videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
}
原始视频和导出的结果如下图。正如您在导出的视频中看到的那样,叠加视频的帧是正确的。但是其中的视频并没有保持其纵横比。如果我选择使 videolayer 帧为正方形,纵横比保持正常。
我卡在了这个早期水平。最终,我正在尝试为方形视频构建一个 WYSIWYG 编辑器,并将缩放、平移和旋转转换应用于将在方形视频中呈现的 videoLayer。非常感谢对这个具体问题和转发的任何帮助。
最佳答案
这正是我正在经历的。现在我有一个解决方案。如果您想将视频从矩形更改为正方形。您需要裁剪视频并将 AVMutableVideoCompositionInstruction 的 backgroundColor 设置为您想要的颜色。
- 确认视频的“UIImageOrientation”。
- 按“videoComposition.renderSize”裁剪视频,renderSize.width 等于 renderSize.height。并且 renderSize.width 是原始视频大小的较大一侧。
- AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.backgroundColor =/CGColorRef/;
苹果引述:
/* 表示合成的背景色。仅支持纯 BGRA 颜色;不支持的图案和其他颜色引用将被忽略。 如果未指定背景颜色,视频合成器将使用不透明黑色的默认背景颜色。 如果渲染的像素缓冲区没有 alpha,则 backgroundColor 的 alpha 值将被忽略。 */ @property (nonatomic, retain, nullable) attribute((NSObject)) CGColorRef backgroundColor CF_RETURNS_RETAINED;
设置指令背景颜色的错误方法是:
instruction.backgroundColor = [UIColor blueColor].CGColor;
正确的是:
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
const CGFloat myColor[] = {1.0, 1.0, 1.0, 1.0}; //white
CGColorRef ref = CGColorCreate(rgb, myColor);
instruction.backgroundColor = ref;
- 导出视频。
完成!
顺便说一下,videolayer 和videoComposition.renderSize 必须设置原始视频的naturalSize。您不能将 videolayer.frame 设置为自定义的 CGRect。
关于ios - 使用 AVFoundation 在顶部创建具有自定义背景颜色和适合纵横比的视频的方形视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30730770/