CALayer.contents not rendering correctly in AVMutableComposition

旧城冷巷雨未停 提交于 2019-12-03 19:28:44

问题


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.

The expected output of my code (mockup of the desired video output):

The actual output of my code (partial screenshot from the iOS Simulator):

As you can see, the footer image appears skewed at a 45 degree angle and a little wavy.

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. 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.

Any suggestions would be greatly appreciated. Thanks!

Interface declarations:

CGSize _renderingSize;
float _displayDuration;

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

ViewDidLoad settings:

_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;
        }
    }];

回答1:


iOS Simulator 7.0 and above has this bug of rendering video using AVExportSession. If you will test this on actual device, the output will be as you want, it will not skew.



来源:https://stackoverflow.com/questions/20391651/calayer-contents-not-rendering-correctly-in-avmutablecomposition

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!