CALayer.contents werden in AVMutableComposition nicht richtig gerendert

Ich habe eine sehr einfache Methode, die ein Video mit einem statischen Hintergrundbild erzeugt, das die gesamte Videokomposition abdeckt, und einem kleineren, teilweise transparenten Bild (Wasserzeichenstil), das sich am unteren Rand des Videos befindet.

Das Hintergrundbild wird korrekt gerendert und sieht genauso aus wie in einem Bildbetrachter. Das Bild, das am unteren Rand des Videos gerendert werden soll, ist jedoch verzerrt.

Die Quelle kann hier auf GitHub heruntergeladen werden.

Die erwartete Ausgabe meines Codes (Modell der gewünschten Videoausgabe):

Die tatsächliche Ausgabe meines Codes (Teil-Screenshot vom iOS-Simulator):

Wie Sie sehen, ist das Fußzeilenbild in einem Winkel von 45 Grad verzerrt und leicht gewellt.

Unten ist der Code, den ich derzeit zum Generieren des Videos verwende. Ich habe jede mögliche Kombination von ContentsGravity für das Footer-Image ausprobiert, ohne Erfolg. In jedem anderen Beispiel, das ich gesehen habe, wird der Ebene einfach ein CGImageRef zugewiesencontents dann setzt diebounds, position undanchorPoint auf ihre entsprechenden Werte. Ich habe keine anderen Beispiele gesehen, die andere Eigenschaften festlegen. Ich habe fast die gesamte Dokumentation der AVFoundation durchgelesen, um festzustellen, ob eine Einstellung fehlt, bin aber noch auf nichts Offensichtliches gestoßen.

Anregungen wäre sehr dankbar. Vielen Dank!

Schnittstellenerklärungen:

CGSize _renderingSize;
float _displayDuration;

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

ViewDidLoad-Einstellungen:

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

Codeblock rendern:

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

Antworten auf die Frage(1)

Ihre Antwort auf die Frage