AVFoundation 能支持非線性、無損的編輯工具,而且能夠在原始媒體資源不破壞的狀況下無約束地編輯。async
AVFoundation 有關資源組合的功能均須要用到 AVComposition 類,這個類將其餘幾種媒體資源組合成一個臨時的排列,這個臨時排列能夠像 AVAsset 同樣使用。一個 AVComposition 中的軌道都是 AVCompositionTrack,而 AVCompositionTrack 又由多個 AVCompositionTrackSegment 組成,表明這個組合中的實際媒體區域。AVComposition 及其相關類沒有遵循 NSCoding 協議,所以不能將其簡單歸檔到存儲磁盤裏,須要自定義數據模型來保存。ide
爲了不浮點數的不精確性致使的偏差,AVFoundation 廣泛使用 CMTime 數據類型來表達時間格式。工具
{
CMTimeValue value;
CMTimeScale timescale;
CMTimeFlags flags;// 表示時間狀態,如是否有效、是否有舍入值
CMTimeEpoch epoch;
} CMTime;
複製代碼
另外使用 CMTimeRange 來表達時間範圍ui
{
CMTime start;
CMTime duration;
} CMTimeRange;
複製代碼
下面是一些經常使用方法spa
組合媒體資源時要注意對一個 AVAsset 的 videoTrack 和 audioTrack 分別進行組合。首先須要初始化一個 AVMutableComposition,還須要初始化兩個 AVMutableCompositionTrack,一個用於附加 video,一個用於附加 audio。code
AVMutableComposition *composition = [AVMutableComposition composition];
__block CMTime cursor = kCMTimeZero;// 標識當前附加資源的時間軸位置
AVMutableCompositionTrack *videoCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *audioCompositionTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
複製代碼
對於每個 AVAsset,須要取出其中的 videoTrack 和 audioTrack,分別加入到對應的 AVMutableCompositionTrack 中orm
[mediaAssets enumerateObjectsUsingBlock:^(MTBKDBImerchantMediaAsset * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
AVAsset *targetAsset = obj.videoAsset;
AVAssetTrack *videoTrack = [[targetAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];
[videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, targetAsset.duration) ofTrack:videoTrack atTime:cursor error:nil];
AVAssetTrack *audioTracck = [[targetAsset tracksWithMediaType:AVMediaTypeAudio] firstObject];
[audioCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, targetAsset.duration) ofTrack:audioTracck atTime:cursor error:nil];
cursor = CMTimeAdd(cursor, targetAsset.duration);
}];
複製代碼
這樣就完成了一個臨時排列 AVMutableComposition,能夠將其直接用於播放。視頻
AVMutableComposition 能夠在內存中進行使用,可是若是想持久化到磁盤中,就須要進行導出,導出後的媒體資源是一個完整的獨立資源。內存
{
NSString *preset = AVAssetExportPresetHighestQuality;
AVAssetExportSession *export = [AVAssetExportSession exportSessionWithAsset:[composition copy] presetName:preset];
export.outputURL = [self outputUrl];
export.outputFileType = AVFileTypeMPEG4;
[export exportAsynchronouslyWithCompletionHandler:^{
AVAssetExportSessionStatus status = export.status;
if (status == AVAssetExportSessionStatusCompleted) {
[self saveVideo:export.outputURL];
}
}];
}
- (NSURL *)outputUrl
{
NSString *filePath = nil;
NSUInteger count = 0;
do {
filePath = NSTemporaryDirectory();
NSString *numberString = count > 0 ?
[NSString stringWithFormat:@"-%li", (unsigned long) count] : @"";
NSString *fileNameString =
[NSString stringWithFormat:@"Masterpiece-%@.m4v", numberString];
filePath = [filePath stringByAppendingPathComponent:fileNameString];
count++;
} while ([[NSFileManager defaultManager] fileExistsAtPath:filePath]);
return [NSURL fileURLWithPath:filePath];
}
複製代碼
最終在導出結束後,經過導出 URL 能夠將目標視頻保存到系統相冊裏。資源
__block NSString *imageIdentifier;
@weakify(self)
[[PHPhotoLibrary sharedPhotoLibrary] performChanges:^{
PHAssetChangeRequest *changeRequest = [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:videoURL];
imageIdentifier = changeRequest.placeholderForCreatedAsset.localIdentifier;
} completionHandler:^( BOOL success, NSError * _Nullable error ) {
dispatch_async(dispatch_get_main_queue(), ^{
[MTBProgressHUD dismiss];
if (!success) {
} else {
}
});
}];
複製代碼