简体   繁体   English

CALayer.contents无法在AVMutableComposition中正确呈现

[英]CALayer.contents not rendering correctly in AVMutableComposition

I have a very simple method that generates a video with a static background image which covers the entire video composition and a smaller, partially transparent image (watermark style) that's located at the bottom of the video. 我有一个非常简单的方法,可以生成一个视频,其中包含覆盖整个视频合成的静态背景图像,以及位于视频底部的较小的,部分透明的图像(水印样式)。

The background image renders correctly and appears exactly the same as it looks in an image viewer. 背景图像正确渲染,看起来与图像查看器中的外观完全相同。 However, the image that's supposed to be rendered at the bottom of the video is skewed/distorted. 但是,应该在视频底部呈现的图像是倾斜/失真的。

The source can be downloaded here, on GitHub. 源代码可以在这里下载,在GitHub上。

The expected output of my code (mockup of the desired video output): 我的代码的预期输出(所需视频输出的模型):

视频的预期输出

The actual output of my code (partial screenshot from the iOS Simulator): 我的代码的实际输出(来自iOS模拟器的部分屏幕截图):

我视频输出的实际屏幕截图

As you can see, the footer image appears skewed at a 45 degree angle and a little wavy. 如您所见,页脚图像以45度角和一点波浪状倾斜。

Below is the code that I'm currently using to generate the video. 以下是我目前用于生成视频的代码。 I've tried every possible combination of contentsGravity for the footer image, with no luck. 我已经尝试了每个可能的内容组合的重力为页脚图像,没有运气。 Every other example that I've seen simply sets a CGImageRef to the layer's contents then sets the bounds , position and anchorPoint to their appropriate values. 我见过的每个其他示例只是将CGImageRef设置为图层的contents然后将boundspositionanchorPoint为适当的值。 I haven't seen any other examples that set any other properties. 我没有看到任何其他设置任何其他属性的示例。 I've read through almost all of the documentation for the AVFoundation to see if there setting that I'm missing, but I haven't come across anything obvious yet. 我已经阅读了几乎所有AVFoundation的文档,看看是否有我失踪的设置,但我还没有看到任何明显的东西。

Any suggestions would be greatly appreciated. 任何建议将不胜感激。 Thanks! 谢谢!

Interface declarations: 接口声明:

CGSize _renderingSize;
float _displayDuration;

AVMutableComposition *mutableComposition;
AVMutableVideoComposition *videoComposition;
AVMutableCompositionTrack *mutableCompositionVideoTrack;
AVAssetExportSession *exporter;

ViewDidLoad settings: ViewDidLoad设置:

_renderingSize = CGSizeMake(640, 360);
_displayDuration = 2.0;

Rendering code block: 渲染代码块:

    mutableComposition = [AVMutableComposition composition];
    mutableCompositionVideoTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];

    videoComposition = [AVMutableVideoComposition videoComposition];
    videoComposition.renderSize = _renderingSize;
    videoComposition.frameDuration = CMTimeMake(1, 30);

    CALayer *parentLayer = [CALayer layer];
    CALayer *videoLayer = [CALayer layer];
    parentLayer.frame = CGRectMake(0, 0, videoComposition.renderSize.width, videoComposition.renderSize.height);
    videoLayer.frame = CGRectMake(0, 0, videoComposition.renderSize.width, videoComposition.renderSize.height);
    [parentLayer addSublayer:videoLayer];

    videoComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];

    NSString *path = [[NSBundle mainBundle] pathForResource:@"blank_1080p" ofType:@"mp4"];
    NSURL *url = [NSURL fileURLWithPath:path];
    AVAsset *asset = [AVAsset assetWithURL:url];
    AVAssetTrack *track = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    [mutableCompositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,CMTimeMakeWithSeconds(_displayDuration, 600)) ofTrack:track atTime:kCMTimeZero error:nil];

    CALayer *imageLayer = [CALayer layer];
    imageLayer.bounds = parentLayer.frame;
    imageLayer.anchorPoint = CGPointMake(0.5, 0.5);
    imageLayer.position = CGPointMake(CGRectGetMidX(imageLayer.bounds), CGRectGetMidY(imageLayer.bounds));
    imageLayer.contents = (id)[UIImage imageNamed:@"background.png"].CGImage;
    imageLayer.contentsGravity = kCAGravityResizeAspectFill;
    [parentLayer addSublayer:imageLayer];

    UIImage *testImage = [UIImage imageNamed:@"bannerTextLayer.png"];

    CALayer *footerLayer = [CALayer layer];
    footerLayer.bounds = CGRectMake(0, 0, 540, 40);
    footerLayer.anchorPoint = CGPointMake(0.5, 0.5);
    footerLayer.position = CGPointMake(CGRectGetMidX(footerLayer.bounds), CGRectGetMidY(footerLayer.bounds));
    footerLayer.contents = (id)testImage.CGImage;
    footerLayer.contentsGravity = kCAGravityResizeAspectFill;
    [parentLayer addSublayer:footerLayer];

    AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(_displayDuration, 600));
    videoComposition.instructions = @[instruction];

    exporter = [[AVAssetExportSession alloc] initWithAsset:mutableComposition presetName:AVAssetExportPresetHighestQuality];
    exporter.outputURL = videoURL ;
    exporter.videoComposition = videoComposition;
    exporter.outputFileType= AVFileTypeMPEG4;
    exporter.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(_displayDuration, 600));
    exporter.shouldOptimizeForNetworkUse = YES;

    [exporter exportAsynchronouslyWithCompletionHandler:^(void){
        switch (exporter.status) {
            case AVAssetExportSessionStatusFailed:{
                NSLog(@"Fail: %@", exporter.error);
                break;
            }
            case AVAssetExportSessionStatusCompleted:{
                NSLog(@"Success");

                dispatch_async(dispatch_get_main_queue(), ^{
                    if (self.moviePlayer)
                        [self.moviePlayer.view removeFromSuperview];

                    self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:videoURL];

                    self.moviePlayer.view.frame = CGRectMake(0, 0, 320, 180);
                    [self.moviePlayer setControlStyle:MPMovieControlStyleNone];

                    [self.previewView addSubview:self.moviePlayer.view];
                    [self.moviePlayer play];

                });

                break;
            }
            default:
                break;
        }
    }];

iOS Simulator 7.0 and above has this bug of rendering video using AVExportSession. iOS模拟器7.0及更高版本存在使用AVExportSession呈现视频的错误。 If you will test this on actual device, the output will be as you want, it will not skew. 如果你将在实际设备上测试它,输出将是你想要的,它不会倾斜。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM