寫(xiě)在前面
喜歡AVFoundation資料的同學(xué)可以關(guān)注我的專題:《AVFoundation》專輯
也可以關(guān)注我的簡(jiǎn)書(shū)賬號(hào)
正文
AVFoundation
框架提供了一組功能豐富的類,以便于編輯audio visual assets
。AVFoundation
的編輯API
的核心是組合。合成只是來(lái)自一個(gè)或多個(gè)不同媒體assets
的tracks
的集合。 AVMutableComposition類提供用于插入和刪除tracks
以及管理其時(shí)間順序的接口。圖3-1
顯示了如何將新組合從現(xiàn)有assets
組合拼湊在一起以形成新的assets
。如果你只想將多個(gè)asset
按順序合并到一個(gè)文件中,那么就可以根據(jù)需要進(jìn)行詳細(xì)說(shuō)明。如果要在合成中的曲目上執(zhí)行任何自定義音頻或視頻處理,則需要分別合并音頻混合或視頻合成。
使用AVMutableAudioMix類,你可以在合成中的音軌上執(zhí)行自定義音頻處理,如圖3-2所示。目前,你可以為音軌指定
maximum volume
或設(shè)置volume ramp
。你可以使用AVMutableVideoComposition類直接處理合成中的視頻tracks
以進(jìn)行編輯,如圖3-3
所示。使用單個(gè)視頻合成,你可以為輸出視頻指定所需的渲染大小和比例以及幀持續(xù)時(shí)間。通過(guò)視頻合成的說(shuō)明(由AVMutableVideoCompositionInstruction類表示),你可以修改視頻的背景顏色并應(yīng)用圖層指令。這些圖層指令(由AVMutableVideoCompositionLayerInstruction類表示)可用于將變換,變換ramps
,opacity
和opacity ramps
應(yīng)用于合成中的視頻tracks
。視頻合成類還使你能夠使用·animationTool屬性將Core Animation
框架中的效果引入到視頻中。
要將合成與音頻混合和視頻合成相結(jié)合,可以使用AVAssetExportSession對(duì)象,如圖3-4
所示。使用合成初始化導(dǎo)出會(huì)話,然后分別將音頻混合和視頻合成分配給audioMix和videoComposition屬性。
創(chuàng)建Composition
要?jiǎng)?chuàng)建自己的合成,請(qǐng)使用AVMutableComposition類。要將媒體數(shù)據(jù)添加到composition
(合成)中,必須添加一個(gè)或多個(gè)composition tracks
(合成軌道),由AVMutableCompositionTrack類表示。最簡(jiǎn)單的情況是創(chuàng)建一個(gè)包含一個(gè)視頻track
和一個(gè)音頻track
的可變組合:
AVMutableComposition *mutableComposition = [AVMutableComposition composition];
// Create the video composition track.
AVMutableCompositionTrack *mutableCompositionVideoTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
// Create the audio composition track.
AVMutableCompositionTrack *mutableCompositionAudioTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]
初始化Composition Track選項(xiàng)
將新tracks
添加到合成時(shí),必須同時(shí)提供媒體類型和tracks
ID
。雖然音頻和視頻是最常用的媒體類型,但你也可以指定其他媒體類型,例如AVMediaTypeSubtitle或AVMediaTypeText。
與某些視聽(tīng)數(shù)據(jù)相關(guān)聯(lián)的每個(gè)track
都具有稱為track
ID
的唯一標(biāo)識(shí)符。如果指定kCMPersistentTrackID_Invalid作為首選track
ID
,則會(huì)自動(dòng)為你生成唯一標(biāo)識(shí)符并與track
關(guān)聯(lián)。
將Audiovisual數(shù)據(jù)添加到Composition中
一旦你有一個(gè)或多個(gè)tracks
的合成,你就可以開(kāi)始將媒體數(shù)據(jù)添加到適當(dāng)?shù)?code>track。要將媒體數(shù)據(jù)添加到合成軌道,你需要訪問(wèn)媒體數(shù)據(jù)所在的AVAsset對(duì)象。你可以使用可變組合track
接口將同一基礎(chǔ)媒體類型的多個(gè)track
放在同一track
上。以下示例說(shuō)明如何將兩個(gè)不同的視頻資源track
按順序添加到同一合成track
:
// You can retrieve AVAssets from a number of places, like the camera roll for example.
AVAsset *videoAsset = <#AVAsset with at least one video track#>;
AVAsset *anotherVideoAsset = <#another AVAsset with at least one video track#>;
// Get the first video track from each asset.
AVAssetTrack *videoAssetTrack = [[videoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVAssetTrack *anotherVideoAssetTrack = [[anotherVideoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
// Add them both to the composition.
[mutableCompositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,videoAssetTrack.timeRange.duration) ofTrack:videoAssetTrack atTime:kCMTimeZero error:nil];
[mutableCompositionVideoTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero,anotherVideoAssetTrack.timeRange.duration) ofTrack:anotherVideoAssetTrack atTime:videoAssetTrack.timeRange.duration error:nil];
檢索兼容的Composition Tracks
在可能的情況下,每種媒體類型只應(yīng)有一個(gè)composition track
。兼容asset
跟蹤的這種統(tǒng)一導(dǎo)致最小量的資源使用。在連續(xù)呈現(xiàn)媒體數(shù)據(jù)時(shí),你應(yīng)將相同類型的任何媒體數(shù)據(jù)放在同一composition track
上。你可以查詢可變組合以查明是否存在與所需asset
跟蹤兼容的任何合成track
:
AVMutableCompositionTrack *compatibleCompositionTrack = [mutableComposition mutableTrackCompatibleWithTrack:<#the AVAssetTrack you want to insert#>];
if (compatibleCompositionTrack) {
// Implementation continues.
}
注意:在同一合成
track
上放置多個(gè)視頻片段可能會(huì)導(dǎo)致視頻片段之間轉(zhuǎn)換時(shí)播放中丟幀,尤其是在嵌入式設(shè)備上。為視頻片段選擇合成track
的數(shù)量完全取決于你的應(yīng)用程序及其預(yù)期平臺(tái)的設(shè)計(jì)。
生成一個(gè)Volume Ramp
單個(gè)AVMutableAudioMix
對(duì)象可以單獨(dú)對(duì)合成中的所有音頻track
執(zhí)行自定義音頻處理。你可以使用audioMix類方法創(chuàng)建音頻混合,并使用AVMutableAudioMixInputParameters類的實(shí)例將音頻混合與合成中的特定track
相關(guān)聯(lián)。音頻混合可用于改變音頻track
的volume
。以下示例顯示如何在特定音頻軌道上設(shè)置volume ramp
,以便在合成期間緩慢淡出音頻:
AVMutableAudioMix *mutableAudioMix = [AVMutableAudioMix audioMix];
// Create the audio mix input parameters object.
AVMutableAudioMixInputParameters *mixParameters = [AVMutableAudioMixInputParameters audioMixInputParametersWithTrack:mutableCompositionAudioTrack];
// Set the volume ramp to slowly fade the audio out over the duration of the composition.
[mixParameters setVolumeRampFromStartVolume:1.f toEndVolume:0.f timeRange:CMTimeRangeMake(kCMTimeZero, mutableComposition.duration)];
// Attach the input parameters to the audio mix.
mutableAudioMix.inputParameters = @[mixParameters];
自定義視頻處理過(guò)程
和音頻混合一樣,你只需要一個(gè)AVMutableVideoComposition
對(duì)象即可在合成的視頻track
上執(zhí)行所有自定義視頻處理。使用視頻合成,你可以直接為合成的視頻track
設(shè)置適當(dāng)?shù)匿秩镜?code>size(尺寸),scale
(比例)和frame
(幀速率)。有關(guān)為這些屬性設(shè)置適當(dāng)值的詳細(xì)示例,請(qǐng)參閱Setting the Render Size and Frame Duration。
更改構(gòu)圖的背景顏色
所有視頻合成還必須具有包含至少一個(gè)視頻合成指令的AVVideoCompositionInstruction對(duì)象的數(shù)組。你可以使用AVMutableVideoCompositionInstruction類來(lái)創(chuàng)建自己的視頻合成指令。使用視頻合成指令,你可以修改合成的背景顏色,指定是否需要后期處理或應(yīng)用圖層指令。
以下示例說(shuō)明如何創(chuàng)建視頻合成指令,將整個(gè)合成的背景顏色更改為紅色。
AVMutableVideoCompositionInstruction *mutableVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
mutableVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, mutableComposition.duration);
mutableVideoCompositionInstruction.backgroundColor = [[UIColor redColor] CGColor]
Opacity Ramps的使用
視頻合成指令也可用于應(yīng)用視頻合成層指令。 AVMutableVideoCompositionLayerInstruction對(duì)象可以將變換,變換ramps
,opacity
和opacity ramps
應(yīng)用于合成中的某個(gè)視頻track
。視頻合成指令的layerInstructions數(shù)組中的層指令的順序決定了如何在該合成指令的持續(xù)時(shí)間內(nèi)對(duì)來(lái)自源track
的視頻幀進(jìn)行分層和組合。以下代碼片段顯示如何設(shè)置opacity ramp
漸變以在轉(zhuǎn)換到第二個(gè)視頻之前慢慢淡出合成中的第一個(gè)視頻:
AVAsset *firstVideoAssetTrack = <#AVAssetTrack representing the first video segment played in the composition#>;
AVAsset *secondVideoAssetTrack = <#AVAssetTrack representing the second video segment played in the composition#>;
// Create the first video composition instruction.
AVMutableVideoCompositionInstruction
*firstVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
// Set its time range to span the duration of the first video track.
firstVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, firstVideoAssetTrack.timeRange.duration);
// Create the layer instruction and associate it with the composition video track.
AVMutableVideoCompositionLayerInstruction *firstVideoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:mutableCompositionVideoTrack];
// Create the opacity ramp to fade out the first video track over its entire duration.
[firstVideoLayerInstruction setOpacityRampFromStartOpacity:1.f toEndOpacity:0.f timeRange:CMTimeRangeMake(kCMTimeZero, firstVideoAssetTrack.timeRange.duration)];
// Create the second video composition instruction so that the second video track isn't transparent.
AVMutableVideoCompositionInstruction *secondVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
// Set its time range to span the duration of the second video track.
secondVideoCompositionInstruction.timeRange = CMTimeRangeMake(firstVideoAssetTrack.timeRange.duration, CMTimeAdd(firstVideoAssetTrack.timeRange.duration, secondVideoAssetTrack.timeRange.duration));
// Create the second layer instruction and associate it with the composition video track.
AVMutableVideoCompositionLayerInstruction *secondVideoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:mutableCompositionVideoTrack];
// Attach the first layer instruction to the first video composition instruction.
firstVideoCompositionInstruction.layerInstructions = @[firstVideoLayerInstruction];
// Attach the second layer instruction to the second video composition instruction.
secondVideoCompositionInstruction.layerInstructions = @[secondVideoLayerInstruction];
// Attach both of the video composition instructions to the video composition.
AVMutableVideoComposition *mutableVideoComposition = [AVMutableVideoComposition videoComposition];
mutableVideoComposition.instructions = @[firstVideoCompositionInstruction, secondVideoCompositionInstruction]
結(jié)合核心動(dòng)畫(huà)效果
視頻合成可以通過(guò)animationTool屬性將Core Animation
的強(qiáng)大功能添加到合成中。通過(guò)此動(dòng)畫(huà)工具,你可以完成諸如水印視頻和添加標(biāo)題或動(dòng)畫(huà)疊加層等任務(wù)。核心動(dòng)畫(huà)可以通過(guò)兩種不同的方式用于視頻合成:你可以將核心動(dòng)畫(huà)圖層添加為其自己的composition track
,或者你可以直接將合成動(dòng)畫(huà)效果(使用核心動(dòng)畫(huà)圖層)渲染到合成中的視頻幀中。以下代碼通過(guò)在視頻中心添加水印來(lái)顯示后一個(gè)選項(xiàng):
CALayer *watermarkLayer = <#CALayer representing your desired watermark image#>;
CALayer *parentLayer = [CALayer layer];
CALayer *videoLayer = [CALayer layer];
parentLayer.frame = CGRectMake(0, 0, mutableVideoComposition.renderSize.width, mutableVideoComposition.renderSize.height);
videoLayer.frame = CGRectMake(0, 0, mutableVideoComposition.renderSize.width, mutableVideoComposition.renderSize.height);
[parentLayer addSublayer:videoLayer];
watermarkLayer.position = CGPointMake(mutableVideoComposition.renderSize.width/2, mutableVideoComposition.renderSize.height/4);
[parentLayer addSublayer:watermarkLayer];
mutableVideoComposition.animationTool = [AVVideoCompositionCoreAnimationTool videoCompositionCoreAnimationToolWithPostProcessingAsVideoLayer:videoLayer inLayer:parentLayer];
綜述:組合多個(gè)Asset并將結(jié)果保存到相冊(cè)中
此簡(jiǎn)短的代碼示例說(shuō)明了如何組合兩個(gè)視頻asset
track
和音頻asset
track
來(lái)創(chuàng)建單個(gè)視頻文件。它顯示了如何:
創(chuàng)建 AVMutableComposition對(duì)象并添加多個(gè)AVMutableCompositionTrack對(duì)象
將AVAssetTrack對(duì)象的時(shí)間范圍添加到兼容的
composition tracks
。檢查視頻
asset
track
的preferredTransform屬性以確定視頻的方向。使用AVMutableVideoCompositionLayerInstruction對(duì)象將變換應(yīng)用于合成中的視頻
tracks
。為視頻合成的renderSize和frameDuration屬性設(shè)置適當(dāng)?shù)闹怠?/p>
導(dǎo)出到視頻文件時(shí),將合成與視頻合成結(jié)合使用。
將視頻文件保存到相冊(cè)。
注意:為了專注于最相關(guān)的代碼,此示例省略了完整應(yīng)用程序的幾個(gè)方面,例如內(nèi)存管理和錯(cuò)誤處理。要使用
AVFoundation
,你應(yīng)該有足夠的經(jīng)驗(yàn)使用Cocoa
來(lái)推斷缺失的部分。
創(chuàng)建Composition
要將來(lái)自不同asset
的track
拼湊在一起,可以使用AVMutableComposition
對(duì)象。創(chuàng)建合成并添加一個(gè)音頻和一個(gè)視頻track
。
AVMutableComposition *mutableComposition = [AVMutableComposition composition];
AVMutableCompositionTrack *videoCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *audioCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];
添加Assets
一個(gè)空的composition
對(duì)你是沒(méi)有意義的。將兩個(gè)視頻asset
track
和音頻asset
track
添加到composition
中。
AVAssetTrack *firstVideoAssetTrack = [[firstVideoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
AVAssetTrack *secondVideoAssetTrack = [[secondVideoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
[videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, firstVideoAssetTrack.timeRange.duration) ofTrack:firstVideoAssetTrack atTime:kCMTimeZero error:nil];
[videoCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, secondVideoAssetTrack.timeRange.duration) ofTrack:secondVideoAssetTrack atTime:firstVideoAssetTrack.timeRange.duration error:nil];
[audioCompositionTrack insertTimeRange:CMTimeRangeMake(kCMTimeZero, CMTimeAdd(firstVideoAssetTrack.timeRange.duration, secondVideoAssetTrack.timeRange.duration)) ofTrack:[[audioAsset tracksWithMediaType:AVMediaTypeAudio] objectAtIndex:0] atTime:kCMTimeZero error:nil]
注意:這假設(shè)你有兩個(gè)
asset
,每個(gè)asset
至少包含一個(gè)視頻track
,第三個(gè)asset
包含至少一個(gè)音頻track
。可以從相機(jī)膠卷中檢索視頻,并且可以從音樂(lè)庫(kù)或視頻本身檢索音頻track
。
檢查視頻方向
將視頻和音頻曲目添加到合成后,你需要確保兩個(gè)視頻track
的方向都正確。默認(rèn)情況下,假設(shè)所有視頻track
都處于橫向模式。如果你的視頻track
是以縱向模式拍攝的,則導(dǎo)出時(shí)視頻將無(wú)法正確定位。同樣,如果你嘗試將縱向模式下的視頻鏡頭與橫向模式下的視頻鏡頭組合在一起,則導(dǎo)出會(huì)話將無(wú)法完成。
BOOL isFirstVideoPortrait = NO;
CGAffineTransform firstTransform = firstVideoAssetTrack.preferredTransform;
// Check the first video track's preferred transform to determine
if it was recorded in portrait mode.
if (firstTransform.a == 0 && firstTransform.d == 0 && (firstTransform.b == 1.0 || firstTransform.b == -1.0) && (firstTransform.c == 1.0 || firstTransform.c == -1.0)) {
isFirstVideoPortrait = YES;
}
BOOL isSecondVideoPortrait = NO;
CGAffineTransform secondTransform = secondVideoAssetTrack.preferredTransform;
// Check the second video track's preferred transform to determine if it was recorded in portrait mode.
if (secondTransform.a == 0 && secondTransform.d == 0 && (secondTransform.b == 1.0 || secondTransform.b == -1.0) && (secondTransform.c == 1.0 || secondTransform.c == -1.0)) {
isSecondVideoPortrait = YES;
}
if ((isFirstVideoAssetPortrait && !isSecondVideoAssetPortrait) || (!isFirstVideoAssetPortrait && isSecondVideoAssetPortrait)) {
UIAlertView *incompatibleVideoOrientationAlert = [[UIAlertView alloc] initWithTitle:@"Error!" message:@"Cannot combine a video shot in portrait mode with a video shot in landscape mode." delegate:self cancelButtonTitle:@"Dismiss" otherButtonTitles:nil];
[incompatibleVideoOrientationAlert show];
return;
}
應(yīng)用視頻合成層指令
一旦你知道視頻片段具有兼容的方向,你就可以對(duì)每個(gè)視頻片段應(yīng)用必要的圖層說(shuō)明,并將這些圖層說(shuō)明添加到視頻合成中。
AVMutableVideoCompositionInstruction *firstVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
// Set the time range of the first instruction to span the duration of the first video track.
firstVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, firstVideoAssetTrack.timeRange.duration);
AVMutableVideoCompositionInstruction * secondVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
// Set the time range of the second instruction to span the duration of the second video track.
secondVideoCompositionInstruction.timeRange = CMTimeRangeMake(firstVideoAssetTrack.timeRange.duration, CMTimeAdd(firstVideoAssetTrack.timeRange.duration, secondVideoAssetTrack.timeRange.duration));
AVMutableVideoCompositionLayerInstruction *firstVideoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoCompositionTrack];
// Set the transform of the first layer instruction to the preferred transform of the first video track.
[firstVideoLayerInstruction setTransform:firstTransform atTime:kCMTimeZero];
AVMutableVideoCompositionLayerInstruction *secondVideoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoCompositionTrack];
// Set the transform of the second layer instruction to the preferred transform of the second video track.
[secondVideoLayerInstruction setTransform:secondTransform atTime:firstVideoAssetTrack.timeRange.duration];
firstVideoCompositionInstruction.layerInstructions = @[firstVideoLayerInstruction];
secondVideoCompositionInstruction.layerInstructions = @[secondVideoLayerInstruction];
AVMutableVideoComposition *mutableVideoComposition = [AVMutableVideoComposition videoComposition];
mutableVideoComposition.instructions = @[firstVideoCompositionInstruction, secondVideoCompositionInstruction];
所有AVAssetTrack對(duì)象都具有preferredTransform屬性,該屬性包含該asset
track
的方向信息。只要asset
track
顯示在屏幕上,就會(huì)應(yīng)用此轉(zhuǎn)換。在前面的代碼中,圖層指令的變換設(shè)置為asset
track
的變換,以便在調(diào)整渲染大小后,新合成中的視頻可以正確顯示。
設(shè)置渲染Size和幀持續(xù)時(shí)間
要完成視頻方向修復(fù),你必須相應(yīng)地調(diào)整renderSize屬性。你還應(yīng)該為frameDuration屬性選擇合適的值,例如1/30
秒(或每秒30
幀)。默認(rèn)情況下,renderScale屬性設(shè)置為1.0
,這適用于此合成。
CGSize naturalSizeFirst, naturalSizeSecond;
// If the first video asset was shot in portrait mode, then so was the second one if we made it here.
if (isFirstVideoAssetPortrait) {
// Invert the width and height for the video tracks to ensure that they display properly.
naturalSizeFirst = CGSizeMake(firstVideoAssetTrack.naturalSize.height, firstVideoAssetTrack.naturalSize.width);
naturalSizeSecond = CGSizeMake(secondVideoAssetTrack.naturalSize.height, secondVideoAssetTrack.naturalSize.width);
}
else {
// If the videos weren't shot in portrait mode, we can just use their natural sizes.
naturalSizeFirst = firstVideoAssetTrack.naturalSize;
naturalSizeSecond = secondVideoAssetTrack.naturalSize;
}
float renderWidth, renderHeight;
// Set the renderWidth and renderHeight to the max of the two videos widths and heights.
if (naturalSizeFirst.width > naturalSizeSecond.width) {
renderWidth = naturalSizeFirst.width;
}
else {
renderWidth = naturalSizeSecond.width;
}
if (naturalSizeFirst.height > naturalSizeSecond.height) {
renderHeight = naturalSizeFirst.height;
}
else {
renderHeight = naturalSizeSecond.height;
}
mutableVideoComposition.renderSize = CGSizeMake(renderWidth, renderHeight);
// Set the frame duration to an appropriate value (i.e. 30 frames per second for video).
mutableVideoComposition.frameDuration = CMTimeMake(1,30);
導(dǎo)出合成并將其保存到相冊(cè)
此過(guò)程的最后一步是將整個(gè)構(gòu)圖導(dǎo)出到單個(gè)視頻文件中,并將該視頻保存到相機(jī)膠卷。你使用AVAssetExportSession對(duì)象來(lái)創(chuàng)建新的視頻文件,并將輸出文件的所需URL
傳遞給它。然后,你可以使用ALAssetsLibrary類將生成的視頻文件保存到相冊(cè)。
// Create a static date formatter so we only have to initialize it once.
static NSDateFormatter *kDateFormatter;
if (!kDateFormatter) {
kDateFormatter = [[NSDateFormatter alloc] init];
kDateFormatter.dateStyle = NSDateFormatterMediumStyle;
kDateFormatter.timeStyle = NSDateFormatterShortStyle;
}
// Create the export session with the composition and set the preset to the highest quality.
AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset:mutableComposition presetName:AVAssetExportPresetHighestQuality];
// Set the desired output URL for the file created by the export process.
exporter.outputURL = [[[[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:@YES error:nil] URLByAppendingPathComponent:[kDateFormatter stringFromDate:[NSDate date]]] URLByAppendingPathExtension:CFBridgingRelease(UTTypeCopyPreferredTagWithClass((CFStringRef)AVFileTypeQuickTimeMovie, kUTTagClassFilenameExtension))];
// Set the output file type to be a QuickTime movie.
exporter.outputFileType = AVFileTypeQuickTimeMovie;
exporter.shouldOptimizeForNetworkUse = YES;
exporter.videoComposition = mutableVideoComposition;
// Asynchronously export the composition to a video file and save this file to the camera roll once export completes.
[exporter exportAsynchronouslyWithCompletionHandler:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (exporter.status == AVAssetExportSessionStatusCompleted) {
ALAssetsLibrary *assetsLibrary = [[ALAssetsLibrary alloc] init];
if ([assetsLibrary videoAtPathIsCompatibleWithSavedPhotosAlbum:exporter.outputURL]) {
[assetsLibrary writeVideoAtPathToSavedPhotosAlbum:exporter.outputURL completionBlock:NULL];
}
}
});
}];
上一章 | 目錄 | 下一章 |
---|