使用 AVVideoCompositionCoreAnimationTool 在 CALayer 中将视频与静态图像混合

发布于 2024-11-07 19:17:39 字数 3377 浏览 0 评论 0原文

我正在尝试将来自相机的视频与静态图像(水印)混合。

我已经检查了这里的问题/答案和一些示例,包括来自 Apple 的 WWDC AVEditDemo,并以以下代码结束。 不幸的是,导出的视频不包含带有图像的图层。 有什么想法吗?

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

/// incoming video
NSURL *videoURL = [info valueForKey:UIImagePickerControllerMediaURL];

/// UIImage into CALayer
UIImage *myImage = [UIImage imageNamed:@"m1h.png"];
CALayer *aLayer = [CALayer layer];
aLayer.contents = (id)myImage.CGImage;

AVURLAsset* url = [AVURLAsset URLAssetWithURL:videoURL options:nil];
AVMutableComposition *videoComposition = [AVMutableComposition composition];
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];

AVMutableCompositionTrack *compositionVideoTrack = [videoComposition  addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVAssetTrack *clipVideoTrack = [[url tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [url duration])  ofTrack:clipVideoTrack atTime:kCMTimeZero error:&error];

AVMutableVideoComposition* videoComp = [[AVMutableVideoComposition videoComposition] retain];
videoComp.renderSize = CGSizeMake(640, 480);
videoComp.frameDuration = CMTimeMake(1, 30);
videoComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithAdditionalLayer:aLayer asTrackID:2];


/// instruction
AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(60, 30) );
AVMutableVideoCompositionLayerInstruction* layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:clipVideoTrack];
instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction];
videoComp.instructions = [NSArray arrayWithObject: instruction];

/// outputs
NSString *filePath = nil;
filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
filePath = [filePath stringByAppendingPathComponent:@"temp.mov"]; 
NSLog(@"exporting to: %@", filePath);
if ([fileManager fileExistsAtPath:filePath]) 
{
        BOOL success = [fileManager removeItemAtPath:filePath error:&error];
        if (!success) NSLog(@"FM error: %@", [error localizedDescription]);
}

/// exporting
AVAssetExportSession *exporter;
exporter = [[AVAssetExportSession alloc] initWithAsset:videoComposition presetName:AVAssetExportPresetHighestQuality] ;
exporter.videoComposition = videoComp;
exporter.outputURL=[NSURL fileURLWithPath:filePath];
exporter.outputFileType=AVFileTypeQuickTimeMovie;

[statusLabel setText:@"processing..."];

[exporter exportAsynchronouslyWithCompletionHandler:^(void){
    switch (exporter.status) {
        case AVAssetExportSessionStatusFailed:
            NSLog(@"exporting failed");
            break;
        case AVAssetExportSessionStatusCompleted:
            NSLog(@"exporting completed");
            UISaveVideoAtPathToSavedPhotosAlbum(filePath, self, @selector(video:didFinishSavingWithError:contextInfo:), NULL);
            break;
        case AVAssetExportSessionStatusCancelled:
            NSLog(@"export cancelled");
            break;
    }
}];

}

I am trying to mix video, coming from the camera with a static image (watermarking).

I have checked around questions/answers here and some examples, including WWDC AVEditDemo from Apple and ended with the following code.
Unfortunately, the exported video does not contain the layer with the image.
Any ideas?

- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {

/// incoming video
NSURL *videoURL = [info valueForKey:UIImagePickerControllerMediaURL];

/// UIImage into CALayer
UIImage *myImage = [UIImage imageNamed:@"m1h.png"];
CALayer *aLayer = [CALayer layer];
aLayer.contents = (id)myImage.CGImage;

AVURLAsset* url = [AVURLAsset URLAssetWithURL:videoURL options:nil];
AVMutableComposition *videoComposition = [AVMutableComposition composition];
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];

AVMutableCompositionTrack *compositionVideoTrack = [videoComposition  addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVAssetTrack *clipVideoTrack = [[url tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
[compositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, [url duration])  ofTrack:clipVideoTrack atTime:kCMTimeZero error:&error];

AVMutableVideoComposition* videoComp = [[AVMutableVideoComposition videoComposition] retain];
videoComp.renderSize = CGSizeMake(640, 480);
videoComp.frameDuration = CMTimeMake(1, 30);
videoComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithAdditionalLayer:aLayer asTrackID:2];


/// instruction
AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
instruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMakeWithSeconds(60, 30) );
AVMutableVideoCompositionLayerInstruction* layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:clipVideoTrack];
instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction];
videoComp.instructions = [NSArray arrayWithObject: instruction];

/// outputs
NSString *filePath = nil;
filePath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
filePath = [filePath stringByAppendingPathComponent:@"temp.mov"]; 
NSLog(@"exporting to: %@", filePath);
if ([fileManager fileExistsAtPath:filePath]) 
{
        BOOL success = [fileManager removeItemAtPath:filePath error:&error];
        if (!success) NSLog(@"FM error: %@", [error localizedDescription]);
}

/// exporting
AVAssetExportSession *exporter;
exporter = [[AVAssetExportSession alloc] initWithAsset:videoComposition presetName:AVAssetExportPresetHighestQuality] ;
exporter.videoComposition = videoComp;
exporter.outputURL=[NSURL fileURLWithPath:filePath];
exporter.outputFileType=AVFileTypeQuickTimeMovie;

[statusLabel setText:@"processing..."];

[exporter exportAsynchronouslyWithCompletionHandler:^(void){
    switch (exporter.status) {
        case AVAssetExportSessionStatusFailed:
            NSLog(@"exporting failed");
            break;
        case AVAssetExportSessionStatusCompleted:
            NSLog(@"exporting completed");
            UISaveVideoAtPathToSavedPhotosAlbum(filePath, self, @selector(video:didFinishSavingWithError:contextInfo:), NULL);
            break;
        case AVAssetExportSessionStatusCancelled:
            NSLog(@"export cancelled");
            break;
    }
}];

}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

酷遇一生 2024-11-14 19:17:39

经过一番尝试后,除了上述代码之外,我最终得到了类似的结果,还将使用的方法更改为 videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:

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];
videoComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];

希望它对某人有帮助。

After playing around I ended up with something like this in a addition to the above code, also changing the used method to videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:

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];
videoComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];

Hope it helps somebody.

離殇 2024-11-14 19:17:39

我让这个工作!这是代码!我没有写大部分内容,我只是调整了一些,但唯一的问题是视频本身在纵向模式下旋转为横向?然后是横向的纵向视频,但图像是正面朝上的!

CALayer *aLayer = [CALayer layer];
    aLayer.frame = CGRectMake(5, 0, 320, 480);
    aLayer.bounds = CGRectMake(5, 0, 320, 480);
    aLayer.contents = (id) [UIImage imageNamed:@"image.png"].CGImage;
    aLayer.opacity = 0.5;
    aLayer.backgroundColor = [UIColor clearColor].CGColor;
    NSURL *url = [NSURL fileURLWithPath:[urlsOfVideos objectAtIndex:self.pageControl.currentPage]];
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
    cmp = [AVMutableComposition composition]; 

    AVMutableCompositionTrack *trackA = [cmp addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    AVAssetTrack *sourceVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    [trackA insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:sourceVideoTrack atTime:kCMTimeZero error:nil] ;

    animComp = [AVMutableVideoComposition videoComposition];
    animComp.renderSize = CGSizeMake(320, 480);
    animComp.frameDuration = CMTimeMake(1,30);
    CALayer *parentLayer = [CALayer layer];
    CALayer *videoLayer = [CALayer layer];
    parentLayer.frame = CGRectMake(0, 0, 320, 480);
    videoLayer.frame = CGRectMake(0, 0, 320, 480);
    [parentLayer addSublayer:videoLayer];
    [parentLayer addSublayer:aLayer];
    animComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
    AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, [asset duration]);
    AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:trackA];
    //[layerInstruction setTrackID:2];
    [layerInstruction setOpacity:1.0 atTime:kCMTimeZero];
    instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction] ;
    animComp.instructions = [NSArray arrayWithObject:instruction];
    [self exportMovie:self];

这是导出代码

-(IBAction) exportMovie:(id)sender{
NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *tempPath = [docPaths objectAtIndex:0];
NSLog(@"Temp Path: %@",tempPath);

NSString *fileName = [NSString stringWithFormat:@"%@/output-anot.MOV",tempPath];
NSFileManager *fileManager = [NSFileManager defaultManager] ;
if([fileManager fileExistsAtPath:fileName ]){
    //NSError *ferror = nil ;
    //BOOL success = [fileManager removeItemAtPath:fileName error:&ferror];
}

NSURL *exportURL = [NSURL fileURLWithPath:fileName];

AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:cmp presetName:AVAssetExportPresetHighestQuality]  ;
exporter.outputURL = exportURL;
exporter.videoComposition = animComp;
exporter.outputFileType= AVFileTypeQuickTimeMovie;
[exporter exportAsynchronouslyWithCompletionHandler:^(void){
    switch (exporter.status) {
        case AVAssetExportSessionStatusFailed:{
            NSLog(@"Fail");
            break;
        }
        case AVAssetExportSessionStatusCompleted:{
            NSLog(@"Success");
            break;
        }

        default:
            break;
    } 
}];

}

i got this to work! heres the code! i didn't write most of it, i just tweaked some, but the only issue is the video itself is rotated for landscape in portrait mode? and then in landscape its portrait video, but the image is right side up!

CALayer *aLayer = [CALayer layer];
    aLayer.frame = CGRectMake(5, 0, 320, 480);
    aLayer.bounds = CGRectMake(5, 0, 320, 480);
    aLayer.contents = (id) [UIImage imageNamed:@"image.png"].CGImage;
    aLayer.opacity = 0.5;
    aLayer.backgroundColor = [UIColor clearColor].CGColor;
    NSURL *url = [NSURL fileURLWithPath:[urlsOfVideos objectAtIndex:self.pageControl.currentPage]];
    AVURLAsset *asset = [AVURLAsset URLAssetWithURL:url options:nil];
    cmp = [AVMutableComposition composition]; 

    AVMutableCompositionTrack *trackA = [cmp addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
    AVAssetTrack *sourceVideoTrack = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
    [trackA insertTimeRange:CMTimeRangeMake(kCMTimeZero, [asset duration]) ofTrack:sourceVideoTrack atTime:kCMTimeZero error:nil] ;

    animComp = [AVMutableVideoComposition videoComposition];
    animComp.renderSize = CGSizeMake(320, 480);
    animComp.frameDuration = CMTimeMake(1,30);
    CALayer *parentLayer = [CALayer layer];
    CALayer *videoLayer = [CALayer layer];
    parentLayer.frame = CGRectMake(0, 0, 320, 480);
    videoLayer.frame = CGRectMake(0, 0, 320, 480);
    [parentLayer addSublayer:videoLayer];
    [parentLayer addSublayer:aLayer];
    animComp.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
    AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
    instruction.timeRange = CMTimeRangeMake(kCMTimeZero, [asset duration]);
    AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:trackA];
    //[layerInstruction setTrackID:2];
    [layerInstruction setOpacity:1.0 atTime:kCMTimeZero];
    instruction.layerInstructions = [NSArray arrayWithObject:layerInstruction] ;
    animComp.instructions = [NSArray arrayWithObject:instruction];
    [self exportMovie:self];

and here is the exporting code

-(IBAction) exportMovie:(id)sender{
NSArray *docPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *tempPath = [docPaths objectAtIndex:0];
NSLog(@"Temp Path: %@",tempPath);

NSString *fileName = [NSString stringWithFormat:@"%@/output-anot.MOV",tempPath];
NSFileManager *fileManager = [NSFileManager defaultManager] ;
if([fileManager fileExistsAtPath:fileName ]){
    //NSError *ferror = nil ;
    //BOOL success = [fileManager removeItemAtPath:fileName error:&ferror];
}

NSURL *exportURL = [NSURL fileURLWithPath:fileName];

AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:cmp presetName:AVAssetExportPresetHighestQuality]  ;
exporter.outputURL = exportURL;
exporter.videoComposition = animComp;
exporter.outputFileType= AVFileTypeQuickTimeMovie;
[exporter exportAsynchronouslyWithCompletionHandler:^(void){
    switch (exporter.status) {
        case AVAssetExportSessionStatusFailed:{
            NSLog(@"Fail");
            break;
        }
        case AVAssetExportSessionStatusCompleted:{
            NSLog(@"Success");
            break;
        }

        default:
            break;
    } 
}];

}

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文