ios - 使用 AVFoundation 在顶部创建具有自定义背景颜色和适合纵横比的视频的方形视频

标签 ios objective-c video avfoundation

我想拍摄一段视频(例如:使用 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 帧为正方形,纵横比保持正常。

Original Video (1920x1080) Cropped video (600x600) with original video overlaid.

我卡在了这个早期水平。最终,我正在尝试为方形视频构建一个 WYSIWYG 编辑器,并将缩放、平移和旋转转换应用于将在方形视频中呈现的 videoLayer。非常感谢对这个具体问题和转发的任何帮助。

最佳答案

这正是我正在经历的。现在我有一个解决方案。如果您想将视频从矩形更改为正方形。您需要裁剪视频并将 AVMutableVideoCompositionInstruction 的 backgroundColor 设置为您想要的颜色。

  1. 确认视频的“UIImageOrientation”。
  2. 按“videoComposition.renderSize”裁剪视频,renderSize.width 等于 renderSize.height。并且 renderSize.width 是原始视频大小的较大一侧。
  3. 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;
  1. 导出视频。

完成!

顺便说一下,videolayer 和videoComposition.renderSize 必须设置原始视频的naturalSize。您不能将 videolayer.frame 设置为自定义的 CGRect。

关于ios - 使用 AVFoundation 在顶部创建具有自定义背景颜色和适合纵横比的视频的方形视频,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30730770/

相关文章:

c# - 将图像从 Ios 应用程序发送到 Web API 服务

ios - UIButton 不会执行 CATransform3DMakeScale

Android,快速视频处理

dictionary - FFMPEG 多路复用视频和音频(来自另一个视频) - 映射问题

ios - 无法为我的应用启用 Game Center

ios textFieldDidEndEditing 触发,但 textFieldShouldReturn 不触发

objective-c - 将文本与 UITableViewCell 对齐时出现问题

ios - 如何将 Objective-C 行转换为 Swift?

iOS 代码保护 - C 静态库还是 Objective-C 框架?

java - 我希望这段代码从 android studio 循环