我正在使用UIImagePickerController
录制视频。我正在使用AVPlayer
播放视频选择的图书馆,将AVPlayerLayer
添加到cameraOverlayView
以便在录制时观看视频。
但我需要导出合并2个视频的视频(一个是录制视频,一个是库视频)。在录制时(包括2个视频),结果视频应与视图相同。
请帮助我做到这一点。
答案 0 :(得分:0)
最后,我找到了解决方案。比我想象的简单,AVFoundation完全满足了我的要求。
//Load video using AVURLAsset
AVURLAsset *firstAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource: @"file1" ofType: @"mp4"]] options:nil];
AVURLAsset *secondAsset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource: @"file2" ofType: @"mp4"]] options:nil];
//Create AVMutableComposition Object.This object will hold our multiple AVMutableCompositionTrack.
AVMutableComposition* mixComposition = [[AVMutableComposition alloc] init];
//Here we are creating the first AVMutableCompositionTrack.See how we are adding a new track to our AVMutableComposition.
AVMutableCompositionTrack *firstTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
//Now we set the length of the firstTrack equal to the length of the firstAsset and add the firstAsset to out newly created track at kCMTimeZero so video plays from the start of the track.
[firstTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, firstAsset.duration) ofTrack:[[firstAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:nil];
//Now we repeat the same process for the 2nd track as we did above for the first track.Note that the new track also starts at kCMTimeZero meaning both tracks will play simultaneously.
AVMutableCompositionTrack *secondTrack = [mixComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
[secondTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, secondAsset.duration) ofTrack:[[secondAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] atTime:kCMTimeZero error:nil];
//Create instruction
AVMutableVideoCompositionInstruction * MainInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
MainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, secondAsset.duration);
//Create layer instruction for first video
AVMutableVideoCompositionLayerInstruction *FirstlayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:firstTrack];
CGAffineTransform Scale = CGAffineTransformMakeScale(0.7f,0.7f);
CGAffineTransform Move = CGAffineTransformMakeTranslation(200,120);
[FirstlayerInstruction setTransform:CGAffineTransformConcat(Scale,Move) atTime:kCMTimeZero];
//Create layer instruction for second video
AVMutableVideoCompositionLayerInstruction *SecondlayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:secondTrack];
CGAffineTransform SecondScale = CGAffineTransformMakeScale(1.2f,1.2f);
CGAffineTransform SecondMove = CGAffineTransformMakeTranslation(0,0);
[SecondlayerInstruction setTransform:CGAffineTransformConcat(SecondScale,SecondMove) atTime:kCMTimeZero];
//Add the layer instruction to the composition instruction
MainInstruction.layerInstructions = [NSArray arrayWithObjects:FirstlayerInstruction,SecondlayerInstruction,nil];;
//Add composition instruction to video composition
AVMutableVideoComposition *MainCompositionInst = [AVMutableVideoComposition videoComposition];
MainCompositionInst.instructions = [NSArray arrayWithObject:MainInstruction];
MainCompositionInst.frameDuration = CMTimeMake(1, 30);
MainCompositionInst.renderSize = CGSizeMake(640, 480);
如果您想播放视频合成
AVPlayerItem * newPlayerItem = [AVPlayerItem playerItemWithAsset:mixComposition];
newPlayerItem.videoComposition = MainCompositionInst;
self.mPlayer = [[AVPlayer alloc] initWithPlayerItem:newPlayerItem];
[self.mPlayer addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionNew context:nil];
AVPlayerLayer *layer = [AVPlayerLayer playerLayerWithPlayer:self.mPlayer];
self.mPlayer.actionAtItemEnd = AVPlayerActionAtItemEndNone;
layer.frame = CGRectMake(0, 0, 640, 480);
[self.view.layer addSublayer: layer];
[self.mPlayer play];
如果您要将视频合成导出到文档目录
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString* path = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"outputFile_%@.mp4",@"Main"]];
NSURL* outputFileUrl = [NSURL fileURLWithPath:path];
exportSession = [[AVAssetExportSession alloc]initWithAsset:mixComposition presetName:AVAssetExportPreset640x480];
exportSession.videoComposition = MainCompositionInst;
exportSession.outputFileType = @"public.mpeg-4";
exportSession.outputURL = outputFileUrl;
NSLog(@"duration = %f", CMTimeGetSeconds(mixComposition.duration));
exportSession.timeRange=CMTimeRangeMake(kCMTimeZero, mixComposition.duration);
[exportSession exportAsynchronouslyWithCompletionHandler:^{
switch(exportSession.status){
case AVAssetExportSessionStatusExporting:
NSLog(@"Exporting...");
break;
case AVAssetExportSessionStatusCompleted:
NSLog(@"Export completed, wohooo!! \n Check %@", path2);
break;
case AVAssetExportSessionStatusWaiting:
NSLog(@"Waiting...");
break;
case AVAssetExportSessionStatusCancelled:
NSLog(@"Cancelled");
break;
case AVAssetExportSessionStatusUnknown:
NSLog(@"Unknown");
break;
case AVAssetExportSessionStatusFailed:
NSLog(@"Failed with error: %@, try to save on %@", exportSession.error, path2);
break;
}
}];
最后,如果你想跟踪进度
//Add a NSTimer for refresh checking the progress of AVAssetExportSession
exportProgressBarTimer = [NSTimer scheduledTimerWithTimeInterval:.1 target:self selector:@selector(updateExportDisplay) userInfo:nil repeats:YES];
并显示进度
- (void)updateExportDisplay {
NSLog(@"Exporting: %f", exportSession.progress);
if (exportSession.progress > .99) {
[exportProgressBarTimer invalidate];
}
}