【问题标题】:Add a text overlay with AVMutableVideoComposition to a specific timerange将带有 AVMutableVideoComposition 的文本叠加层添加到特定时间范围
【发布时间】:2014-02-10 17:57:49
【问题描述】:

我找到了一些示例来展示如何在视频上添加文本覆盖。

Ray 的教程 - http://www.raywenderlich.com/30200/avfoundation-tutorial-adding-overlays-and-animations-to-videos

这个 SO 答案 - How can I add a watermark in a captured video on iOS

我还引用了其他一些内容。我的代码看起来几乎与该答案相同,我一直在尝试调整它以使文本覆盖仅在视频开头显示一两秒钟。对我如何做到这一点有任何帮助吗?

这是我的代码。这可以按原样导出视频,并在整个持续时间内显示叠加层。

if(vA) {
    videoCompositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    [videoCompositionTrack insertTimeRange:videoTimerange ofTrack:[[vA tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:&error];
    [videoCompositionTrack setPreferredTransform:[[[vA tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] preferredTransform]];
    if(error)
        NSLog(@"%@", error);
}

if(aA) {
    audioCompositionTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
    [audioCompositionTrack insertTimeRange:audioTimerange ofTrack:[[aA tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:&error];
    if(error)
        NSLog(@"%@", error);
}

CGSize videoSize = [videoCompositionTrack naturalSize];

UIImage *myImage = [UIImage imageNamed:@"cover.png"];
CALayer *aLayer = [CALayer layer];
aLayer.contents = (id)myImage.CGImage;
aLayer.frame = CGRectMake(5, 25, 100, 56);
aLayer.opacity = 0.7;

CATextLayer *titleLayer = [CATextLayer layer];
titleLayer.string = titleText;
titleLayer.fontSize = 18;
titleLayer.foregroundColor = titleColor.CGColor;
titleLayer.alignmentMode = kCAAlignmentCenter;
titleLayer.frame = CGRectMake(20, 10, videoSize.width - 40, 20);
[titleLayer displayIfNeeded];

CALayer *parentLayer = [CALayer layer];
CALayer *videoLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
videoLayer.frame = CGRectMake(0, 0, videoSize.width, videoSize.height);
[parentLayer addSublayer:videoLayer];
[parentLayer addSublayer:aLayer];
if(titleText && [titleText length] > 0) {
    [parentLayer addSublayer:titleLayer];
}

AVMutableVideoComposition *videoComp = [AVMutableVideoComposition videoComposition];
videoComp.renderSize = videoSize;
videoComp.frameDuration = CMTimeMake(1, 30);
videoComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];

AVAssetTrack *videoTrack = [[mixComposition tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoTrack];

AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
[instruction setTimeRange:CMTimeRangeMake(kCMTimeZero, [mixComposition duration])];
instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction];
videoComp.instructions = [NSArray arrayWithObject:instruction];

AVAssetExportSession *_assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetMediumQuality];
_assetExport.videoComposition = videoComp;
_assetExport.outputFileType = AVFileTypeMPEG4;
_assetExport.outputURL = outputFileUrl;

[_assetExport exportAsynchronouslyWithCompletionHandler:^{
    AVAssetExportSessionStatus status = [_assetExport status];
    switch (status) {
        case AVAssetExportSessionStatusFailed:
            NSLog(@"Export Failed");
            NSLog(@"Export Error: %@", [_assetExport.error localizedDescription]);
            NSLog(@"Export Error Reason: %@", [_assetExport.error localizedFailureReason]);
            break;
        case AVAssetExportSessionStatusCompleted:
            NSLog(@"Export Completed");
            [self performSelectorOnMainThread:@selector(updateProgressIndicator:) withObject:[NSNumber numberWithFloat:2] waitUntilDone:YES];
            break;
        case AVAssetExportSessionStatusUnknown:
            NSLog(@"Export Unknown");
            break;
        case AVAssetExportSessionStatusExporting:
            NSLog(@"Export Exporting");
            break;
        case AVAssetExportSessionStatusWaiting:
            NSLog(@"Export Waiting");
            break;
    }
}];

【问题讨论】:

    标签: ios xcode avfoundation avmutablecomposition


    【解决方案1】:

    我知道我需要做什么。真的没什么特别的。它只是需要更好地理解所有可能的事情。

    基本上,我所要做的就是向其中包含文本的图层添加一个基本的不透明动画。

    // My original code for creating the text layer
    CATextLayer *titleLayer = [CATextLayer layer];
    .
    .
    .
    [titleLayer displayIfNeeded];
    
    // the code for the opacity animation which then removes the text
    CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"opacity"];
    [animation setDuration:0];
    [animation setFromValue:[NSNumber numberWithFloat:1.0]];
    [animation setToValue:[NSNumber numberWithFloat:0.0]];
    [animation setBeginTime:1];
    [animation setRemovedOnCompletion:NO];
    [animation setFillMode:kCAFillModeForwards];
    [titleLayer addAnimation:animation forKey:@"animateOpacity"];
    

    【讨论】:

    • 不能直接在titleLayer上设置alpha值?为什么需要使用 CABasicAnimation?
    • @scott F 如何提供具体的时间范围?
    • @PayalManiyar,通过设置动画开始时间和持续时间
    【解决方案2】:

    我们应该在特定时间范围内为视频叠加添加两个不透明动画。 开始时显示覆盖的第一个动画和结束时隐藏覆盖的第二个动画。我们应该注意设置动画的填充模式。

    特定时间的视频叠加示例代码 Rang。

                let textLayer = CATextLayer()
                textLayer.opacity = 0.0
                .
                .
                textLayer.frame = CGRect(x: 0.0, y: 0.0, width: 150.0, height:100.0)
                textLayer.string = "Overlay Text"
    
                let startVisible = CABasicAnimation.init(keyPath:"opacity")
                startVisible.duration = 0.1    // for fade in duration
                startVisible.repeatCount = 1
                startVisible.fromValue = 0.0  
                startVisible.toValue = 1.0
                startVisible.beginTime = overlay.startTime.seconds // overlay time range start duration
                startVisible.isRemovedOnCompletion = false 
                startVisible.fillMode = kCAFillModeForwards 
                textLayer.add(startVisible, forKey: "startAnimation")
    
                let endVisible = CABasicAnimation.init(keyPath:"opacity")
                endVisible.duration = 0.1
                endVisible.repeatCount = 1
                endVisible.fromValue = 1.0
                endVisible.toValue = 0.0
                endVisible.beginTime = overlay.endTime.seconds
                endVisible.fillMode = kCAFillModeForwards
                endVisible.isRemovedOnCompletion = false
                textLayer.add(endVisible, forKey: "endAnimation")
    

    【讨论】:

    • 完美,这正是我所需要的,效果很好。感谢分享
    猜你喜欢
    • 1970-01-01
    • 2015-07-27
    • 1970-01-01
    • 1970-01-01
    • 2011-09-23
    • 1970-01-01
    • 2016-08-23
    • 2019-12-27
    相关资源
    最近更新 更多