AVFoundation框架解析(六)—— 視頻音頻的合成(一)

版本記錄

版本號(hào) 時(shí)間
V1.0 2017.08.30

前言

AVFoundation框架是ios中很重要的框架,所有與視頻音頻相關(guān)的軟硬件控制都在這個(gè)框架里面,接下來(lái)這幾篇就主要對(duì)這個(gè)框架進(jìn)行介紹和講解倚舀。感興趣的可以看我上幾篇。
1. AVFoundation框架解析(一)—— 基本概覽
2. AVFoundation框架解析(二)—— 實(shí)現(xiàn)視頻預(yù)覽錄制保存到相冊(cè)
3. AVFoundation框架解析(三)—— 幾個(gè)關(guān)鍵問(wèn)題之關(guān)于框架的深度概括
4. AVFoundation框架解析(四)—— 幾個(gè)關(guān)鍵問(wèn)題之AVFoundation探索(一)
5. AVFoundation框架解析(五)—— 幾個(gè)關(guān)鍵問(wèn)題之AVFoundation探索(二)

AVFoundation 編輯

AVFoundation框架提供了一組功能豐富的類,以便于編輯視聽(tīng)資源段直。 AVFoundation的編輯API的核心是組合。 組合僅僅是來(lái)自一個(gè)或多個(gè)不同媒體資產(chǎn)的軌道的集合溶诞。 AVMutableComposition類提供了一個(gè)用于插入和刪除軌道以及管理其時(shí)間順序的接口鸯檬。 下圖顯示了如何將新組合從現(xiàn)有資產(chǎn)的組合中拼湊起來(lái)形成新的資產(chǎn)。 如果您想要做的是將多個(gè)資產(chǎn)合并到單個(gè)文件中螺垢,那么就是您需要的細(xì)節(jié)喧务。 如果您想在合成的軌道上執(zhí)行任何自定義音頻或視頻處理,則需要分別包含音頻混合或視頻合成枉圃。

使用AVMutableAudioMix類,您可以對(duì)合成中的音軌執(zhí)行自定義音頻處理讯蒲,如下圖所示痊土。 目前,您可以指定最大音量或設(shè)置音軌的音量斜坡墨林。

您可以使用AVMutableVideoComposition類直接與組合中的視頻軌進(jìn)行編輯赁酝,如下圖所示。 使用單個(gè)視頻構(gòu)圖旭等,您可以為輸出視頻指定所需的渲染大小和縮放以及幀持續(xù)時(shí)間酌呆。 通過(guò)視頻作品的指示(由AVMutableVideoCompositionInstruction類表示),您可以修改視頻的背景顏色并應(yīng)用圖層說(shuō)明搔耕。 這些層指令(由AVMutableVideoCompositionLayerInstruction類表示)可用于將轉(zhuǎn)換隙袁,變換斜坡痰娱,不透明度和不透明度斜坡應(yīng)用于組合中的視頻軌道。 視頻構(gòu)圖類還使您能夠使用animationTool屬性將Core Animation框架的效果引入到視頻中菩收。

要將您的合成與音頻混合和視頻合成相結(jié)合梨睁,請(qǐng)使用AVAssetExportSession對(duì)象,如下圖所示娜饵。 您可以使用您的合成初始化導(dǎo)出會(huì)話坡贺,然后分別將音頻混合和視頻構(gòu)圖分配給audioMixvideoComposition屬性。


Creating a Composition

要?jiǎng)?chuàng)建自己的組合箱舞,可以使用AVMutableComposition類遍坟。 要向組合添加媒體數(shù)據(jù),您必須添加一個(gè)或多個(gè)由AVMutableCompositionTrack類表示的組合軌道晴股。 最簡(jiǎn)單的情況是創(chuàng)建一個(gè)具有一個(gè)視頻軌道和一個(gè)音軌的可變組合:

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];

1. Options for Initializing a Composition Track

在組合中添加新曲目時(shí)愿伴,您必須同時(shí)提供媒體類型和曲目ID。 雖然音頻和視頻是最常用的媒體類型电湘,但您也可以指定其他媒體類型隔节,如AVMediaTypeSubtitleAVMediaTypeText

與某些視聽(tīng)數(shù)據(jù)相關(guān)聯(lián)的每個(gè)軌道都具有稱為軌跡ID的唯一標(biāo)識(shí)符胡桨。 如果您指定kCMPersistentTrackID_Invalid作為首選軌道ID官帘,則會(huì)為您自動(dòng)生成唯一標(biāo)識(shí)符并與軌道相關(guān)聯(lián)瞬雹。


Adding Audiovisual Data to a Composition

一旦您有一個(gè)或多個(gè)軌道的合成昧谊,您可以開(kāi)始將您的媒體數(shù)據(jù)添加到相應(yīng)的軌道上。 要將媒體數(shù)據(jù)添加到合成軌道酗捌,您需要訪問(wèn)媒體數(shù)據(jù)所在的AVAsset對(duì)象呢诬。 您可以使用可變組合軌道界面將同一底層介質(zhì)類型的多個(gè)軌道放在同一軌道上。 以下示例說(shuō)明如何按順序?qū)蓚€(gè)不同的視頻資源軌道添加到相同的構(gòu)圖軌道中:

// 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];

1. Retrieving Compatible Composition Tracks

在可能的情況下胖缤,每個(gè)媒體類型應(yīng)該只有一個(gè)合成軌跡尚镰。 兼容資產(chǎn)軌道的統(tǒng)一導(dǎo)致資源使用量最少。 當(dāng)連續(xù)呈現(xiàn)媒體數(shù)據(jù)時(shí)哪廓,您應(yīng)該將相同類型的任何媒體數(shù)據(jù)放在同一組合軌上狗唉。 您可以查詢可變的合成涡真,以確定是否有任何合成軌道與您所需的素材資源軌道兼容:

AVMutableCompositionTrack *compatibleCompositionTrack = [mutableComposition mutableTrackCompatibleWithTrack:<#the AVAssetTrack you want to insert#>];
if (compatibleCompositionTrack) {
    // Implementation continues.
}

將多個(gè)視頻片段放置在相同的合成軌道上可能會(huì)導(dǎo)致視頻片段之間的轉(zhuǎn)換丟幀哆料,特別是在嵌入式設(shè)備上缸剪。 為您的視頻片段選擇合成軌道的數(shù)量完全取決于您的app的設(shè)計(jì)及其預(yù)期平臺(tái)。


Generating a Volume Ramp

單個(gè)AVMutableAudioMix對(duì)象可以對(duì)您單獨(dú)組成的所有音軌執(zhí)行自定義音頻處理杏节。 您可以使用audioMix類方法創(chuàng)建音頻混合,并使用AVMutableAudioMixInputParameters類的實(shí)例將音頻混合與組合中的特定軌道相關(guān)聯(lián)奋渔。 可以使用音頻混合來(lái)改變音軌的音量镊逝。 以下示例顯示如何在特定音軌上設(shè)置音量斜坡,以在組合的持續(xù)時(shí)間內(nèi)慢慢淡出音頻:

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];

Performing Custom Video Processing

與音頻混合一樣蹋半,您只需要一個(gè)AVMutableVideoComposition對(duì)象來(lái)對(duì)您的組合視頻軌道執(zhí)行所有自定義視頻處理充坑。 使用視頻構(gòu)圖捻爷,您可以直接為構(gòu)圖視頻軌道設(shè)置適當(dāng)?shù)匿秩敬笮。s放比例和幀速率也榄。

1. Changing the Composition’s Background Color

所有視頻構(gòu)圖還必須包含至少包含一個(gè)視頻構(gòu)圖指令的AVVideoCompositionInstruction對(duì)象數(shù)組甜紫。 您可以使用AVMutableVideoCompositionInstruction類創(chuàng)建自己的視頻構(gòu)圖說(shuō)明。 使用視頻合成指令腰根,您可以修改構(gòu)圖的背景顏色拓型,指定是否需要后處理或應(yīng)用圖層指令劣挫。

以下示例說(shuō)明如何創(chuàng)建一個(gè)視頻合成指令,將整個(gè)構(gòu)圖的背景顏色更改為紅色球拦。

AVMutableVideoCompositionInstruction *mutableVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction];
mutableVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, mutableComposition.duration);
mutableVideoCompositionInstruction.backgroundColor = [[UIColor redColor] CGColor];

2. Applying Opacity Ramps

視頻合成指令也可用于應(yīng)用視頻合成圖層指令帐我。 AVMutableVideoCompositionLayerInstruction對(duì)象可以對(duì)組合中的某個(gè)視頻軌道應(yīng)用變換坎炼,變換斜坡焚刚,不透明度和不透明度斜坡。 視頻合成指令的layerInstructions數(shù)組中的圖層指令的順序決定了在構(gòu)圖指令的持續(xù)時(shí)間內(nèi)抢肛,來(lái)自源軌道的視頻幀應(yīng)如何分層和組合捡絮。 以下代碼片段顯示如何設(shè)置不透明度斜坡以在轉(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];

3. Incorporating Core Animation Effects

視頻構(gòu)圖可以通過(guò)animationTool屬性添加核心動(dòng)畫(huà)的功能福稳。 通過(guò)這個(gè)動(dòng)畫(huà)工具的圆,您可以完成水印視頻和添加標(biāo)題或動(dòng)畫(huà)疊加等任務(wù)。 核心動(dòng)畫(huà)可以以兩種不同的方式與視頻合成一起使用:您可以添加一個(gè)核心動(dòng)畫(huà)圖層作為自己的個(gè)人作品軌跡季俩,或者您可以將Core Animation效果(使用核心動(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];

Putting It All Together: Combining Multiple Assets and Saving the Result to the Camera Roll

這個(gè)簡(jiǎn)短的代碼示例說(shuō)明了如何組合兩個(gè)視頻資產(chǎn)軌道和音頻資產(chǎn)軌道來(lái)創(chuàng)建單個(gè)視頻文件酪我。 它顯示如何:

  • 創(chuàng)建一個(gè)AVMutableComposition對(duì)象并添加多個(gè)AVMutableCompositionTrack對(duì)象
  • AVAssetTrack對(duì)象的時(shí)間范圍添加到兼容的組合軌道
  • 檢查視頻資產(chǎn)軌道的preferredTransform屬性以確定視頻的方向
  • 使用AVMutableVideoCompositionLayerInstruction對(duì)象將變換應(yīng)用到合成中的視頻軌道
  • 為視頻構(gòu)圖的renderSizeframeDuration屬性設(shè)置適當(dāng)?shù)闹?/li>
  • 導(dǎo)出到視頻文件時(shí)且叁,使用組合與視頻合成
  • 將視頻文件保存到相機(jī)膠卷

要關(guān)注最相關(guān)的代碼谴古,這個(gè)例子省略了一個(gè)完整的應(yīng)用程序的幾個(gè)方面稠歉,如內(nèi)存管理和錯(cuò)誤處理怒炸。 要使用AVFoundation,您將有足夠的經(jīng)驗(yàn)與Cocoa推斷丟失的部分勺疼。

1. Creating the Composition

要從單獨(dú)的資源組合軌道捏鱼,您可以使用AVMutableComposition對(duì)象导梆。 創(chuàng)建構(gòu)圖并添加一個(gè)音頻和一個(gè)視頻軌道迂烁。

AVMutableComposition *mutableComposition = [AVMutableComposition composition];
AVMutableCompositionTrack *videoCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid];
AVMutableCompositionTrack *audioCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid];

2. Adding the Assets

一個(gè)空的組合對(duì)你來(lái)說(shuō)沒(méi)有用盟步。 將兩個(gè)視頻資產(chǎn)軌道和音頻資產(chǎn)軌道添加到組合躏结。

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è)資產(chǎn)包含至少一個(gè)視頻軌道媳拴,每個(gè)資產(chǎn)包含至少一個(gè)音軌屈溉。 可以從相機(jī)膠卷中檢索視頻,并且可以從音樂(lè)庫(kù)或視頻本身檢索音軌描孟。

3. Checking the Video Orientations

將視頻和音軌添加到組合中后砰左,您需要確保兩個(gè)視頻軌道的方向正確缠导。 默認(rèn)情況下,所有視頻軌道都假定為橫向模式憋他。 如果您的視頻軌道以縱向模式拍攝髓削,導(dǎo)出時(shí)視頻將無(wú)法正確定向立膛。 同樣,如果您嘗試將以縱向模式拍攝的視頻與橫向模式下的視頻拍攝相結(jié)合好啰,導(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;
}

4. Applying the Video Composition Layer Instructions

一旦您知道視頻片段具有兼容的方向椰弊,您可以對(duì)每個(gè)視頻片段應(yīng)用必要的圖層指令,并將這些圖層指令添加到視頻構(gòu)圖闹司。

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ì)象都有一個(gè)preferredTransform屬性游桩,其中包含該資產(chǎn)軌道的方向信息借卧。 每當(dāng)資產(chǎn)軌跡顯示在屏幕上時(shí)筛峭,就會(huì)應(yīng)用此轉(zhuǎn)換影晓。 在以前的代碼中,層指令的變換設(shè)置為資產(chǎn)軌道的變換疤祭,以便在調(diào)整渲染大小后饵婆,新構(gòu)圖中的視頻會(huì)正確顯示。

5. Setting the Render Size and Frame Duration

要完成視頻方向修復(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);

6. Exporting the Composition and Saving it to the Camera Roll

此過(guò)程的最后一步包括將整個(gè)組合導(dǎo)出到單個(gè)視頻文件中虑灰,并將該視頻保存到相機(jī)卷穆咐。 您可以使用AVAssetExportSession對(duì)象來(lái)創(chuàng)建新的視頻文件,并將其傳遞給輸出文件所需的URL崖叫。 然后拍柒,您可以使用ALAssetsLibrary類將生成的視頻文件保存到相機(jī)膠卷拆讯。

// 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];
            }
        }
    });
}];

后記

有關(guān)視頻音頻合成的原理理論就這么多种呐,后期會(huì)給大家具體工程上的演示陕贮,希望對(duì)大家有所幫助,謝謝~~~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末掉缺,一起剝皮案震驚了整個(gè)濱河市眶明,隨后出現(xiàn)的幾起案子筐高,更是在濱河造成了極大的恐慌柑土,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件扮宠,死亡現(xiàn)場(chǎng)離奇詭異坛增,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)届案,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)罢艾,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)昆婿,“玉大人,你說(shuō)我怎么就攤上這事睁冬】锤恚” “怎么了能庆?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)弥搞。 經(jīng)常有香客問(wèn)我攀例,道長(zhǎng)顾腊,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮吗垮,結(jié)果婚禮上抱既,老公的妹妹穿的比我還像新娘。我一直安慰自己蚀之,他們只是感情好捷泞,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布锁右。 她就那樣靜靜地躺著,像睡著了一般拂到。 火紅的嫁衣襯著肌膚如雪码泞。 梳的紋絲不亂的頭發(fā)上余寥,一...
    開(kāi)封第一講書(shū)人閱讀 52,255評(píng)論 1 308
  • 那天宋舷,我揣著相機(jī)與錄音,去河邊找鬼音诈。 笑死绎狭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的谒兄。 我是一名探鬼主播社付,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼鸥咖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼啼辣!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起党远,我...
    開(kāi)封第一講書(shū)人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤沟娱,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后矫废,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體砰蠢,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡台舱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年柿赊,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片诡蜓。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蔓罚,死狀恐怖瞻颂,靈堂內(nèi)的尸體忽然破棺而出贡这,到底是詐尸還是另有隱情,我是刑警寧澤丽惭,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布辈双,位于F島的核電站湃望,受9級(jí)特大地震影響痰驱,放射性物質(zhì)發(fā)生泄漏瞳浦。R本人自食惡果不足惜术幔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一诅挑、第九天 我趴在偏房一處隱蔽的房頂上張望泛源。 院中可真熱鬧,春花似錦没龙、人聲如沸缎玫。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至莹菱,卻和暖如春吱瘩,著一層夾襖步出監(jiān)牢的瞬間使碾,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工娜汁, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留兄朋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓缕允,卻偏偏與公主長(zhǎng)得像蹭越,于是被迫代替她去往敵國(guó)和親响鹃。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 版本記錄 前言 AVFoundation框架是ios中很重要的框架,所有與視頻音頻相關(guān)的軟硬件控制都在這個(gè)框架里面...
    刀客傳奇閱讀 1,409評(píng)論 0 3
  • Editing(編輯) AVFoundation框架提供了一組功能豐富的類蓉冈,以便于編輯視聽(tīng)資料轩触。AVFoundat...
    張芳濤閱讀 1,378評(píng)論 0 2
  • AVFoundation框架提供了一組功能豐富的類脱柱,以簡(jiǎn)化音視頻的編輯褐捻。compositions是AVFounda...
    smm987閱讀 615評(píng)論 0 0
  • 原文:AVFoundation Programming Guide 寫(xiě)在前面 簡(jiǎn)單翻譯一下AVFoundation...
    朦朧1919閱讀 1,604評(píng)論 0 1
  • 一天時(shí)間里柠逞,在簡(jiǎn)書(shū)上面寫(xiě)下了10篇文。 這樣說(shuō)出來(lái)逗鸣,肯定會(huì)被很多人罵死掉绰精。有數(shù)量沒(méi)質(zhì)量。湊數(shù)的發(fā)文笨使,為了騙取簡(jiǎn)書(shū)鉆...
    斧正堂閱讀 285評(píng)論 2 7