视频轨道背后的AVFoundation UIImage

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了视频轨道背后的AVFoundation UIImage相关的知识,希望对你有一定的参考价值。

我目前正在渲染一个小于输出尺寸的视频轨道。我想在背景中绘制UIImage,以便视频位于顶部,图像显示在视频不在的区域。我尝试过使用CoreAnimation图层以及videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:inLayer:但是视频图层下方的图层似乎没有显示(上面的图片显示正常) - 只是黑色或我在AVMutableVideoCompositionInstruction对象上设置的任何背景颜色。我也尝试将背景颜色设置为[UIColor clearColor] .CGColor,但它只是以黑色显示。

有人做过类似的事并有建议吗?

CALayer *parentLayer = [CALayer layer];
CALayer *videoLayer = [CALayer layer];
CALayer *backgroundLayer = [CALayer layer];
backgroundLayer.frame = rect;
parentLayer.frame = rect;
videoLayer.frame = rect;
videoLayer.backgroundColor = [UIColor clearColor].CGColor;
backgroundLayer.backgroundColor = [UIColor purpleColor].CGColor;
[parentLayer addSublayer:backgroundLayer];
[parentLayer addSublayer:videoLayer];

mainCompositionInst.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
答案

在尝试了几件事之后我终于找到了一种方法。要使其工作,需要使用空白视频/音频轨道。然后将背景图像添加到此空白视频图层。然后将其导出并合并原始资产(视频)和导出的资产(资产)并导出最终资产(视频)。希望它能为您提供帮助。

添加叠加层

- (void)addOverlayImage:(UIImage *)overlayImage ToVideo:(AVMutableVideoComposition *)composition inSize:(CGSize)size {
    // 1 - set up the overlay
    CALayer *overlayLayer = [CALayer layer];

    [overlayLayer setContents:(id)[overlayImage CGImage]];
    overlayLayer.frame = CGRectMake(0, 0, size.width, size.height);
    [overlayLayer setMasksToBounds:YES];

    // 2 - set up the parent layer
    CALayer *parentLayer = [CALayer layer];
    CALayer *videoLayer = [CALayer layer];
    parentLayer.frame = CGRectMake(0, 0, size.width, size.height);
    videoLayer.frame = CGRectMake(0, 0, size.width, size.height);
    [parentLayer addSublayer:videoLayer];
    [parentLayer addSublayer:overlayLayer];

    // 3 - apply magic
    composition.animationTool = [AVVideoCompositionCoreAnimationTool
                                 videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
}

- (void)getBackgroundVideoAssetWithcompletion:(void (^)(AVAsset *bgAsset))completionBlock {

    NSString *path = [[NSBundle mainBundle] pathForResource:@"blank_video" ofType:@"mp4"];
    NSURL *trackUrl = [NSURL fileURLWithPath:path];
    AVAsset *asset = [AVAsset assetWithURL:trackUrl];
    AVAssetTrack *track = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];

    CMTimeRange range = CMTimeRangeMake(kCMTimeZero, [asset duration]);
    AVMutableComposition* mixComposition = [AVMutableComposition composition];

    AVMutableCompositionTrack *compositionVideoTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    [compositionVideoTrack insertTimeRange:range ofTrack:[[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:nil];


    CGAffineTransform videoTransform = track.preferredTransform;
    CGSize naturalSize = CGSizeApplyAffineTransform(track.naturalSize, videoTransform);
    naturalSize = CGSizeMake(fabs(naturalSize.width), fabs(naturalSize.height));


    AVMutableVideoComposition *composition = [AVMutableVideoComposition videoCompositionWithPropertiesOfAsset:asset];
    UIImage *img = [self imageWithImage:[UIImage imageNamed:@"white_image"] convertToSize:naturalSize];
    [self addOverlayImage:img ToVideo:composition inSize:naturalSize];


    AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    instruction.timeRange = range;
    composition.instructions = @[instruction];


    AVAssetExportSession *_assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetMediumQuality];
    _assetExport.videoComposition = composition;



    NSString *exportPath = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSString stringWithFormat:@"exported-%d.mov", arc4random() % 100000]];
    unlink([exportPath UTF8String]);
    NSURL *exportUrl = [NSURL fileURLWithPath:exportPath];

    _assetExport.outputFileType = AVFileTypeQuickTimeMovie;
    _assetExport.outputURL = exportUrl;
    _assetExport.shouldOptimizeForNetworkUse = YES;

    [_assetExport exportAsynchronouslyWithCompletionHandler:^{

        switch (_assetExport.status) {

            case AVAssetExportSessionStatusFailed:
                 break;

            case AVAssetExportSessionStatusExporting:
                break;

            case AVAssetExportSessionStatusCompleted:{

                dispatch_async(dispatch_get_main_queue(), ^{
                    NSLog(@"Successful!!!");
                    AVAsset *finalAsset = [AVAsset assetWithURL:_assetExport.outputURL];
                    completionBlock(finalAsset);
                });
            }
                break;

            default:
                break;
        }
    }];
}

现在有一个带叠加图像的视频资产。只保留原始视频和导出的视频资产的组合。导出的资产应该是底层,原始应该是顶层。

以上是关于视频轨道背后的AVFoundation UIImage的主要内容,如果未能解决你的问题,请参考以下文章

在 OS X 上使用 AVFoundation AVPlayer 显示字幕

在 iOS 中动态包含视频文件的字幕?

AVAudioFoundation:音视频编辑

Mac OS X 上的 AVFoundation + GC

如何使用 AVFoundation 修剪视频

使用 AVFoundation 混合图像和视频