写过一篇博客介绍过处理音视频文件时各个类的分工。现已经实现了一个集视频剪辑,视频拼接保存于一身的小程序。此片中有如何导出已编辑好的视频和相关类的介绍。
一、思路
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(@"保存失败");
}
}