写过一篇博客介绍过处理音视频文件时各个类的分工。现已经实现了一个集视频剪辑,视频拼接保存于一身的小程序。此片中有如何导出已编辑好的视频和相关类的介绍。

一、思路

1、我们从系统相册中获取到对应的视频信息,通过AssetsLibrary,保存对应视频的URL。

2、使用对应的URL将视频导入AVAsset容器中。

self.leftAsset = [AVAsset assetWithURL:url];

3、创建一个AVAsset的子类AVMutableComposition对象,并往里面加入我们所需要的音频轨道和视频轨道。作为我们剪辑后视频的存放容器。

self.composition = [AVMutableComposition composition];  //创建轨道容器
AVMutableCompositionTrack *videoTrack = [self.composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];       //创建配置视频轨道,并加入到轨道容器总
AVMutableCompositionTrack *audioTrack = [self.composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];       //创建音频轨道,并加入到轨道容器中

4、使用AVAssetTrack对象从对应的AVAsset媒体容器中,抽取对应的视频文件和音频文件。

AVAssetTrack *assetTrackVideo;
AVAssetTrack *assetTrackAudio; 
assetTrackVideo = [[self.leftAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];  //从媒体容器中抽取得到视频信息
assetTrackAudio = [[self.leftAsset tracksWithMediaType:AVMediaTypeAudio] firstObject];  //从媒体容器中抽取得到音频信息

5、创建CMTime和CMTimeRange时间类型,剪辑操作抽取出来的AVAssetTrack对象。并加入到AVMutableComposition对象对应的轨道中。

//截取时间配置
CMTime leftTimeStart = CMTimeMake(leftST, 1);
CMTime leftTimeEnd   = CMTimeMake(leftET, 1);
CMTimeRange leftRangee = CMTimeRangeMake(leftTimeStart, leftTimeEnd); //用于截取视频,leftTimeStart代表截取的起点,leftTimeEnd表示持续时间

6、视频的拼接

self.leftAsset = [AVAsset assetWithURL:url];  //通过URL获取第二个媒体
CMTime cusorTime = kCMTimeZero;  //得到添加位置
cusorTime = CMTimeAdd(cusorTime, leftTimeEnd); //当拼接是得找到轨道尾部,轨道上最后一个文件的结尾,轨道上第一个视频是从0时开始的,持续时间为leftTimeEnd,所以我们第二个视频的起始时间就为这个
assetTrackVideo  = [[self.rightAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];   //抽取第二个视频的视频信息
assetTrackAudio  = [[self.rightAsset tracksWithMediaType:AVMediaTypeAudio] firstObject];   //抽取第二个视频的音频信息
[videoTrack insertTimeRange:rightRange ofTrack:assetTrackVideo atTime:cusorTime error:nil];  //插入到轨道容器视频轨道对应的位置
[audioTrack insertTimeRange:rightRange ofTrack:assetTrackAudio atTime:cusorTime error:nil];  //插入到轨道容器音频轨道对应的为值

7、使用AVAssetExportSession对象将将剪辑好的媒体文件导出,再保存到系统相册中。

//初始化配置导出实例
    self.exprot = [AVAssetExportSession exportSessionWithAsset:[self.composition copy] presetName:AVAssetExportPresetHighestQuality];
    self.exprot.outputURL      = [self saveSynteticAdress];  //保存地址
    self.exprot.outputFileType = AVFileTypeMPEG4;            //格式
    
    [self.exprot exportAsynchronouslyWithCompletionHandler:^{   //导出完成后
        
        dispatch_async(dispatch_get_global_queue(0, 0), ^{
            
            AVAssetExportSessionStatus status = self.exprot.status;
            
            //将文件存入系统相册
            if (status == AVAssetExportSessionStatusCompleted) {
                
                [self writeExportedVideoToassetsLibrary];
            }else {
                
                UIAlertView *alerView = [[UIAlertView alloc]initWithTitle:@"出现错误" message:@"saveSynthetic方法" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
                [alerView show];
            }
        });
    }];
}

//获取沙盒路径存储到沙河中
- (NSURL *)saveSynteticAdress {
    
    NSString *filePath = nil;
    NSUInteger count = 0;
    do {
        
        filePath = NSTemporaryDirectory();
        NSString *numberString = count >0 ? [NSString stringWithFormat:@"-%li",(unsigned long) count ]: @" ";
        NSString *fileNameString = [NSString stringWithFormat:@"Masterpiece-%@.mov",numberString];
        filePath = [filePath stringByAppendingPathComponent:fileNameString];
        count++;
    }while ([[NSFileManager defaultManager] fileExistsAtPath:filePath]);
        
        return [NSURL fileURLWithPath:filePath];
    
}

//将合成写入照片库中
- (void)writeExportedVideoToassetsLibrary {
    
    NSURL *url = self.exprot.outputURL;
    ALAssetsLibrary *library = [[ALAssetsLibrary alloc]init];
    if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:url]) {
        
        [library writeVideoAtPathToSavedPhotosAlbum:url completionBlock:^(NSURL *assetURL, NSError *error) {
            
            if (error) {
                
                UIAlertView *alerView = [[UIAlertView alloc]initWithTitle:@"出现错误" message:@"问题出在保存中" delegate:self cancelButtonTitle:@"取消" otherButtonTitles:@"确定", nil];
                [alerView show];
            }else {
                
                [[NSFileManager defaultManager] removeItemAtURL:url error:nil];
            
                [self alerViewShowMessage:@"已经保存到系统相册"];

            }
        }];
    }else {
        
        NSLog(@"保存失败");
    }
}