使用自定义背景颜色和带有AVFoundation的纵横比视频创建方形视频

时间:2015-06-09 11:30:04

标签: 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];
}

原始视频和导出的结果如下图所示。正如您在导出的视频中看到的那样,重叠视频的帧是正确的。但其中的视频并未保持其宽高比。如果我选择使视频图像框为方形,则宽高比保持正常。

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

我陷入了这个早期阶段。最终,我正在尝试为方形视频构建一个WYSIWYG编辑器,并将缩放,平移和旋转变换应用于将在方形视频中呈现的videoLayer。对此特定问题和前进的任何帮助都非常感谢。

2 个答案:

答案 0 :(得分:1)

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

  1. 确认' UIImageOrientation'视频。
  2. 通过' videoComposition.renderSize'裁剪视频,renderSize.width等于renderSize.height。而renderSize.width是原始视频大小的一侧。
  3. AVMutableVideoCompositionInstruction * instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
  4. instruction.backgroundColor = / CGColorRef /;

    Apple引用:

    / *表示合成的背景颜色。仅支持实心BGRA颜色;不支持的模式和其他颜色引用将被忽略。    如果未指定背景颜色,则视频合成器将使用不透明黑色的默认backgroundColor。    如果渲染的像素缓冲区没有alpha,则将忽略backgroundColor的alpha值。 * / @property(非原子,保留,可为空)属性((NSObject))CGColorRef backgroundColor CF_RETURNS_RETAINED;

    设置指令backgroundColor的错误方法是:

    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. 导出视频。
    2. 完成!

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

答案 1 :(得分:0)

var transform: CGAffineTransform
if isVideoAssetPortrait == true {
    let scale = naturalSize.height / naturalSize.width
    transform = CGAffineTransformMakeScale(scale, 1)
    transform = CGAffineTransformConcat(videoTrack.preferredTransform, transform)
} else {
    let scale = naturalSize.width / naturalSize.height
    transform = CGAffineTransformMakeScale(1, scale)
}
videoLayerInstruction.setTransform(transform, atTime: kCMTimeZero)

我受到https://www.snip2code.com/Snippet/42212/Crop-video-to-square-with-a-specified-si的启发。但是,我实际上并不知道这是做什么的。我复制了代码但它不起作用。
我看到视频变形,因此,我试图让它变形,并且它有效。如果你还有任何问题。请联系我。这是我为自己编写的示例代码: