是否可以将两个视频文件合并为一个文件,iOS 中的一个屏幕?

Moo*_*Soo 5 iphone video objective-c avfoundation ios

我是视频编程的新手。我正在尝试练习它,但遇到了问题,将两个视频文件合并为一个。

我的意思是合并如下..

我有第一个这样的视频 输入图像描述它我

第二个视频也喜欢这个 在此处输入图片说明

我希望他们像这样合并 在此处输入图片说明

我不想使用 2 个视频播放器,因为我想将合并的视频文件发送给某人。我搜索了一整天来解决这个问题,但我找不到如何解决。

我编写了引用链接的代码,但它仅显示第一个视频,未合并。

我的代码:

NSURL *firstURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"video1" ofType:@"mp4"]]
AVURLAsset  *firstAsset = [[AVURLAsset alloc]initWithURL:firstURL options:nil];

NSURL *secondURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"video2" ofType:@"mp4"]];
VURLAsset  *secondAsset = [[AVURLAsset alloc]initWithURL:secondURL options:nil];

AVMutableComposition* mixComposition = [AVMutableComposition composition];
AVMutableCompositionTrack *firstTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
                                                                  preferredTrackID:kCMPersistentTrackID_Invalid];
[firstTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, firstAsset.duration)
                    ofTrack:[[firstAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
                     atTime:kCMTimeZero error:nil];

AVMutableCompositionTrack *secondTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo
                                                                   preferredTrackID:kCMPersistentTrackID_Invalid];

[secondTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, secondAsset.duration)
                     ofTrack:[[secondAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0]
                      atTime:kCMTimeZero error:nil];

[secondTrack setPreferredTransform:CGAffineTransformMakeScale(0.25f,0.25f)];

NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docsDir = [dirPaths objectAtIndex:0];
NSString *outputFilePath = [docsDir stringByAppendingPathComponent:[NSString stringWithFormat:@"FinalVideo.mov"]];

NSLog(@"%@", outputFilePath);

NSURL *outputFileUrl = [NSURL fileURLWithPath:outputFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:outputFilePath])
    [[NSFileManager defaultManager] removeItemAtPath:outputFilePath error:nil];


AVAssetExportSession* assetExport = [[AVAssetExportSession alloc] initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];
assetExport.outputFileType = @"com.apple.quicktime-movie";
assetExport.outputURL = outputFileUrl;

[assetExport exportAsynchronouslyWithCompletionHandler: ^(void ) {

     switch (assetExport.status) {
         case AVAssetExportSessionStatusFailed:
             NSLog(@"AVAssetExportSessionStatusFailed");
             break;
         case AVAssetExportSessionStatusCompleted:
             NSLog(@"AVAssetExportSessionStatusCompleted");
             break;
         case AVAssetExportSessionStatusWaiting:
             NSLog(@"AVAssetExportSessionStatusWaiting");
             break;
         default:
             break;
     }
 }
 ];
Run Code Online (Sandbox Code Playgroud)

我错过了什么?我不知道如何解决这个问题。

欣赏任何想法。谢谢。

编辑:

我制作了一个新代码,它引用了马特写的链接,谢谢马特。但是当我尝试导出它时,只导出了第一个视频。不在一起.. :(

我的新代码是..

NSURL *originalVideoURL1 = [[NSBundle mainBundle] URLForResource:@"video1" withExtension:@"mov"];
NSURL *originalVideoURL2 = [[NSBundle mainBundle] URLForResource:@"video2" withExtension:@"mov"];


AVURLAsset *firstAsset = [AVURLAsset URLAssetWithURL:originalVideoURL1 options:nil];
AVURLAsset *secondAsset = [AVURLAsset URLAssetWithURL:originalVideoURL2 options:nil];

AVMutableComposition* mixComposition = [[AVMutableComposition alloc] init]; //[AVMutableComposition composition];

NSError *error = nil;
AVMutableCompositionTrack *firstTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[firstTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, firstAsset.duration) ofTrack:[[firstAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:&error];

if(error) {
    NSLog(@"firstTrack error!!!. %@", error.localizedDescription);
}

AVMutableCompositionTrack *secondTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[secondTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, secondAsset.duration) ofTrack:[[secondAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:&error];

if(error) {
    NSLog(@"secondTrack error!!!. %@", error.localizedDescription);
}


AVMutableVideoCompositionInstruction *mainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, firstAsset.duration);

AVMutableVideoCompositionLayerInstruction *firstLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:firstTrack];
CGAffineTransform scale = CGAffineTransformMakeScale(0.7, 0.7);
CGAffineTransform move = CGAffineTransformMakeTranslation(230, 230);
[firstLayerInstruction setTransform:CGAffineTransformConcat(scale, move) atTime:kCMTimeZero];

AVMutableVideoCompositionLayerInstruction *secondLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:secondTrack];
CGAffineTransform secondScale = CGAffineTransformMakeScale(1.2, 1.5);
CGAffineTransform secondMove = CGAffineTransformMakeTranslation(0, 0);
[secondLayerInstruction setTransform:CGAffineTransformConcat(secondScale, secondMove) atTime:kCMTimeZero];

mainInstruction.layerInstructions = @[firstLayerInstruction, secondLayerInstruction];

AVMutableVideoComposition *mainCompositionInst = [AVMutableVideoComposition videoComposition];
mainCompositionInst.instructions = @[mainInstruction];
mainCompositionInst.frameDuration = CMTimeMake(1, 30);
mainCompositionInst.renderSize = CGSizeMake(640, 480);

AVPlayerItem *newPlayerItem = [AVPlayerItem playerItemWithAsset:mixComposition];
newPlayerItem.videoComposition = mainCompositionInst;

AVPlayer *player = [[AVPlayer alloc] initWithPlayerItem:newPlayerItem];

AVPlayerLayer *playerLayer =[AVPlayerLayer playerLayerWithPlayer:player];

[playerLayer setFrame:self.view.bounds];
[self.view.layer addSublayer:playerLayer];
[player seekToTime:kCMTimeZero];
[player play]; // play is Good!!


NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];

NSString *tempS2 = [documentsDirectory stringByAppendingPathComponent:@"FinalVideo.mov"];

if([[NSFileManager defaultManager] fileExistsAtPath:tempS2])
{
    [[NSFileManager defaultManager] removeItemAtPath:tempS2 error:nil];
}


NSURL *url = [[NSURL alloc] initFileURLWithPath: tempS2];

AVAssetExportSession *exportSession = [[AVAssetExportSession alloc]
                                       initWithAsset:mixComposition presetName:AVAssetExportPresetHighestQuality];

exportSession.outputURL=url;

NSLog(@"%@", [exportSession supportedFileTypes]);

exportSession.outputFileType = AVFileTypeQuickTimeMovie;
[exportSession exportAsynchronouslyWithCompletionHandler:^{
    if (exportSession.status==AVAssetExportSessionStatusFailed) {
        NSLog(@"failed");
    }
    else {
        NSLog(@"AudioLocation : %@",tempS2);
    }
}];
Run Code Online (Sandbox Code Playgroud)

如何同时导出 mixComposition 和 layerInstruction?

请给我更多的想法。

谢谢。

Rhy*_*man 1

参考第二次编辑中的代码,就像您告诉 的AVPlayerItem有关您的一样AVMutableVideoComposition,您还需要告诉AVAssetExportSession

exportSession.videoComposition = mainCompositionInst;
// exportAsynchronouslyWithCompletionHandler etc
Run Code Online (Sandbox Code Playgroud)

请注意,在设置指令持续时间时,请确保选择两个轨道持续时间中较长的一个:

mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeMaximum(firstAsset.duration, secondAsset.duration));
Run Code Online (Sandbox Code Playgroud)

AVPlayer不介意你是否犯了这个错误,但AVAssetExportSession会返回一个AVErrorInvalidVideoComposition(-11841)错误。

NB 2AVPlayer实际上并没有超出范围,但当我看到它时,它让我感到紧张。如果我是你,我会把它分配给一个财产。