AVFoundationプログラミングガイド-編集



Avfoundation Programming Guide Editing



編集

AVFoundationフレームワークは、オーディオビジュアルリソースの編集を容易にする機能豊富なクラスのセットを提供します。 AVFoundationで編集されるAPIのコアはコンポジションです。組み合わせは、1つ以上の異なるメディアアセットのトラックの単なるコレクションです。AVMutableCompositionクラスは、トラックを挿入および削除し、それらの時系列を管理するためのインターフェイスを提供します。図3-1は、既存のリソースの組み合わせから新しい組み合わせをつなぎ合わせて新しいリソースを形成する方法を示しています。複数のリソースを順番に1つのファイルにマージするだけの場合は、必要に応じてより詳細な手順を実行できます。コンポジション内のトラックでカスタムオーディオまたはビデオ処理を実行する場合は、オーディオミキシングまたはビデオコンポジションをそれぞれマージする必要があります。



図3-1AVMutableCompositionはアセットをまとめます(AVMutableCompositionはリソースを一緒にアセンブルします)。

補足知識ポイント:



AVAsset:マテリアルライブラリ内のマテリアル
AVAssetTrack:素材のトラック
AVMutableComposition:ビデオの合成に使用されるプロジェクトファイル
AVMutableCompositionTrack:プロジェクトファイルのトラックには、オーディオトラック、ビデオトラックなどが含まれ、対応するさまざまな素材を挿入できます。


図3-2に示すように、AVMutableAudioMixクラスを使用すると、結合されたオーディオトラックでカスタムオーディオ処理を実行できます。現在、オーディオトラックの最大音量を指定したり、音量を設定したりできます。



図3-2AVMutableAudioMixはオーディオミキシングを実行します(AVMutableAudioMixはオーディオミキシングを実行します)。

補足知識

AVMutableComposition:ビデオの合成に使用されるプロジェクトファイル

AVMutableCompositionTrack:プロジェクトファイルのトラックには、オーディオトラック、ビデオトラックなどが含まれ、対応するさまざまな素材を挿入できます。

AVMutableVideoComposition:複数の命令を含む、ビデオの生成に使用される複合命令。最終的なビデオのサイズを決定することができ、トリミングはここで行う必要があります
AVMutableVideoCompositionInstruction:複数のlayerInstructionsを含む、timeRange内の各トラックの状態を判別するための命令
AVMutableVideoCompositionLayerInstruction:命令の時間範囲内のトラックの状態

AVAssetExportSession:オブジェクトのトランスコーディングと出力AVAssetオブジェクトは操作を実行し、ビデオ処理出力に使用されます。


AVMutableVideoCompositionクラスを使用できますグループ内のビデオトラックを直接処理して編集します、図3-3に示すように。単一のビデオコンポジションを使用して、出力ビデオに必要なレンダリングサイズと比率、およびフレーム期間を指定できます。ビデオ合成命令(AVMutableVideoCompositionInstructionクラスで表される)を使用して、ビデオの背景色を変更し、レイヤー命令を適用できます。これらのレイヤー命令(AVMutableVideoCompositionLayerInstructionクラスで表される)を使用して、コンポジション内のビデオトラックにグラデーション、不透明度、不透明度のグラデーションを適用して、変換を適用できます。ビデオコンポジションクラスでは、animationToolプロパティを使用して、CoreAnimationフレームワークの効果をビデオに導入することもできます。


図3-4に示すように、組み合わせをオーディオの組み合わせおよびビデオの組み合わせと組み合わせるには、AVAssetExportSessionオブジェクトを使用できます。この組み合わせを使用してエクスポートセッションを初期化し、オーディオの組み合わせとビデオの組み合わせをそれぞれaudioMixプロパティとvideoCompositionプロパティに割り当てます。

図3-4AVAssetExportSessionを使用して、メディア要素を出力ファイルに結合します(AVAssetExportSessionを使用して、メディア要素を出力ファイルに結合します)。


コンポジションの作成(組み合わせを作成する)。

独自のコンポジションを作成するには、AVMutableCompositionクラスを使用できます。メディアデータをコンポジションに追加するには、AVMutableCompositionTrackクラスで表される1つ以上のコンポジットトラックを追加する必要があります。最も単純なケースは変数の組み合わせを作成するを含むビデオトラックオーディオトラック

AVMutableComposition *mutableComposition = [AVMutableComposition composition] used to compose video // Create the video composition track. Create the video composition track. AVMutableCompositionTrack *mutableCompositionVideoTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid] // Create the audio composition track. Create the audio composition track AVMutableCompositionTrack *mutableCompositionAudioTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]

コンポジショントラックを初期化するためのオプション(複合トラックを初期化するためのオプション)。

新しいトラックを追加するときは、メディアタイプとトラックIDの両方を指定する必要があります。オーディオとビデオが最も一般的に使用されるメディアタイプですが、AVMediaTypeSubtitleやAVMediaTypeTextなどの他のメディアタイプを指定することもできます。特定の視聴覚データに関連する各トラックには、トラックIDと呼ばれる一意の識別子があります。優先トラックIDとしてkCMPersistentTrackID_Invalidを指定すると、トラックに関連付けられた一意の識別子が自動的に生成されます。

コンポジションへの視聴覚データの追加(視聴覚データをコンポジションに追加する)。

1つまたは複数のトラックの組み合わせがある場合メディアデータを適切なトラックに追加し始めることができますコンポジットトラックにメディアデータを追加するにはメディアデータにアクセスする必要がありますAVAssetオブジェクトあなたはできる可変コンビネーショントラックインターフェースを使用して、複数を組み合わせる基になるメディアタイプが同じオーディオトラックは、同じトラックに配置されます次の例は、同じ結合トラックに2つの異なるビデオリソーストラックを追加する方法

// You can retrieve AVAssets from a number of places, like the camera roll for example. You can retrieve AVAssets from a number of places, like the camera roll for example. AVAsset *videoAsset = AVAsset *anotherVideoAsset = // Get the first video track from each asset. 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つのトラックの組み合わせのみが存在できます。互換性のあるアセットトラックをこのように統合することで、リソースの使用量を最小限に抑えることができます。メディアデータを連続して表示する場合は、同じ種類のメディアデータを同じ場所に配置する必要があります合成トラックで変数の組み合わせを照会できます決定する必要なリソーストラックと互換性のあるコンビネーショントラックはありますか

AVMutableCompositionTrack *compatibleCompositionTrack = [mutableComposition mutableTrackCompatibleWithTrack:] if (compatibleCompositionTrack) { // Implementation continues. }注意同じ結合トラックに複数のビデオクリップを配置するビデオクリップになる可能性があります((特に組み込み機器)。変換プロセスにより、再生中にフレームが失われる可能性があります。ビデオクリップの結合トラック数を選択しますそれはすべて、アプリケーションの設計とその対象となるプラットフォームに依存します

ボリュームランプの生成(ボリュームランプを生成する)。

AVMutableAudioMixオブジェクトはグループ内のすべてのオーディオトラックに対して個別にカスタムオーディオ処理を実行しますaudioMixクラスメソッドを使用してオーディオミックスを作成し、AVMutableAudioMixInputParametersクラスのインスタンスを使用して、オーディオミックスをミックス内の特定のオーディオトラックに関連付けることができます。オーディオミキシングを使用して、オーディオトラックの音量を変更できます。次の例は特定のオーディオトラックに音量勾配を設定する方法組み合わせの期間中、オーディオを徐々にフェードアウトします。

AVMutableAudioMix *mutableAudioMix = [AVMutableAudioMix audioMix]Audio Mixing // 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. 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. Connect the input parameters to the audio mix mutableAudioMix.inputParameters = @[mixParameters]

カスタムビデオ処理の実行(カスタムビデオ処理を実行します)。

オーディオミキシングと同様に、必要なのはAVMutableVideoCompositionオブジェクトのみです。結合されたビデオトラックは、すべてのカスタムビデオ処理を実行しますビデオコンポジションを使用すると、コンポジットビデオトラックの適切なレンダリングサイズ、比率、およびフレームレートを直接設定できます。これらのプロパティに適切な値を設定する詳細な例については、を参照してください。レンダリングサイズとフレーム期間の設定

コンポジションの背景色の変更(コンポジションの背景色を変更する)。

すべてのビデオ構成には少なくとも1つが必要です含むビデオトラック命令用のAVVideoCompositionInstructionオブジェクトのセット。AVMutableVideoCompositionInstructionクラスを使用して、独自のビデオ合成命令を作成できます。ビデオ合成コマンドを使用して、合成の背景色を変更し、後処理コマンドとアプリケーション層コマンドのどちらが必要かを指定できます。

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

不透明ランプの適用(不透明度ランプを適用します)。

ビデオコンポジション命令を使用して、ビデオコンポジションレイヤー命令を適用することもできます。AVMutableVideoCompositionLayerInstructionオブジェクト変換を適用したり、勾配を変更したり、不透明度と不透明度は、コンポジットの特定のビデオトラックにフェードインします。ビデオ合成命令のlayerInstructions配列では、レイヤ命令の順序によって、合成命令の期間内にソーストラックからビデオフレームをレイヤリングして合成する方法が決まります。次のコードスニペットは次のとおりです。2番目のビデオを変換する前に最初のビデオを設定する方法不透明度の勾配コンポジションの最初のビデオをゆっくりとフェードアウトさせます//AVAssetTrack represents the first video clip played in the combination AVAsset *firstVideoAssetTrack = //AVAssetTrack represents the second video clip played in the combination AVAsset *secondVideoAssetTrack = // Create the first video composition instruction. Create the first video composition instruction. AVMutableVideoCompositionInstruction *firstVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction] // Set its time range to span the duration of the first video track. 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. //Create a layer instruction and associate it with the composite video track. AVMutableVideoCompositionLayerInstruction *firstVideoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:mutableCompositionVideoTrack] // Create the opacity ramp to fade out the first video track over its entire duration. //Create an opacity gradient to fade out the first video track for the 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. //Create a second video synthesis instruction so that the second video track is opaque. AVMutableVideoCompositionInstruction *secondVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction] // Set its time range to span the duration of the second video track. //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. //Create a second level instruction and associate it with the composite video track. AVMutableVideoCompositionLayerInstruction *secondVideoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:mutableCompositionVideoTrack] // Attach the first layer instruction to the first video composition instruction. //Append the first layer instruction to the first video synthesis instruction. firstVideoCompositionInstruction.layerInstructions = @[firstVideoLayerInstruction] // Attach the second layer instruction to the second video composition instruction. //Append the second layer instruction to the second video synthesis instruction. secondVideoCompositionInstruction.layerInstructions = @[secondVideoLayerInstruction] // Attach both of the video composition instructions to the video composition. //Append two video synthesis instructions to the video synthesis. AVMutableVideoComposition *mutableVideoComposition = [AVMutableVideoComposition videoComposition] mutableVideoComposition.instructions = @[firstVideoCompositionInstruction, secondVideoCompositionInstruction] Core AnimationEffectsを組み込む(組み合わせたアニメーション効果)。

ビデオ合成は、animationToolプロパティを介して、コアアニメーションのパワーをポートフォリオに追加できます。このアニメーションツールを使用すると、ビデオに透かしを入れたり、タイトルやアニメーションオーバーレイを追加したりするなどのタスクを完了することができます。 Core Animationは、2つの異なる方法でビデオコンポジションを使用できます。コアアニメーションレイヤーを独自の個別の結合トラックとして追加するか、コアアニメーションエフェクトを(コアアニメーションレイヤーを使用して)ビデオフレーム内の作業に直接レンダリングできます。以下のコードビデオの中央に透かしを追加して、後者のオプションを表示します

//CALayer represents the watermark image you want. CALayer *watermarkLayer = 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]

すべてをまとめる:複数のアセットを組み合わせて、結果をカメラロールに保存する(すべてをまとめる:複数のアセットをマージし、結果をカメラロールに保存します)。

この短いコード例は、2つのビデオリソーストラックと1つのオーディオリソーストラックを組み合わせてビデオファイルを作成する方法次の方法を示します。

1>。AVMutableCompositionオブジェクトを作成し、複数のAVMutableCompositionTrackオブジェクトを追加します

2>。AVAssetTrackオブジェクトの時間範囲を互換性のある複合トラックに追加します

3>。ビデオリソーストラックのpreferredTransformプロパティを確認して、ビデオの方向を決定します

4>。AVMutableVideoCompositionLayerInstructionオブジェクトを使用して変換(変換、変形)しますコンポジションのビデオトラックに適用されます。

5>。ビデオコンポジションのrenderSizeプロパティとframeDurationプロパティに適切な値を設定します

6>。ビデオファイルにエクスポートするときは、コンポジションとビデオコンポジションを組み合わせてください

7>。ビデオファイルをカメラロールに保存する

注:最も関連性の高いコードに注意してください。この例では、メモリ管理やエラー処理など、アプリケーション全体のいくつかの側面を省略しています。AVFoundationを使用するには、不足している部分を推測するのに十分なCocoaの経験が必要です。

コンポジションの作成

さまざまなリソースのトラックをつなぎ合わせるあなたが使うAVMutableCompositionオブジェクトコンポジションを作成し、オーディオとビデオのトラックを追加します

AVMutableComposition *mutableComposition = [AVMutableComposition composition] //Video track AVMutableCompositionTrack *videoCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid] //Audio track AVMutableCompositionTrack *audioCompositionTrack = [mutableComposition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid] アセットの追加

空の構図はあなたにとって良くありません。 2つのビデオリソーストラックとオーディオリソーストラックをコンポジションに追加します。

//The first video resource track AVAssetTrack *firstVideoAssetTrack = [[firstVideoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] //The second video resource track AVAssetTrack *secondVideoAssetTrack = [[secondVideoAsset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0] //Add them to the composition [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]

注:これは、それぞれに少なくとも1つのビデオトラックが含まれる2つのアセットがあり、3番目のアセットに少なくとも1つのオーディオトラックが含まれていることを前提としています。これらのビデオはカメラロールから取得でき、オーディオトラックは音楽ライブラリまたはビデオから取得することもできます。

ビデオの向きを確認する(ビデオの方向を確認してください)。

ビデオトラックとオーディオトラックをコンポジションに追加したら、両方のビデオトラックの向きが正しいことを確認する必要があります。デフォルトでは、すべてのビデオトラックはランドスケープモードであると想定されています。ビデオトラックがポートレートモードで撮影された場合、エクスポート時にビデオの向きが正しくなりません。同様に、ポートレートモードのビデオショットとランドスケープモードのビデオショットをマージしようとすると、エクスポートセッションは完了しません。

BOOL isFirstVideoPortrait = NO//Whether the first video is in portrait mode CGAffineTransform firstTransform = firstVideoAssetTrack.preferredTransform // Check the first video track's preferred transform to determine if it was recorded in portrait mode. //Check the preferred transformation of the first video track to determine if it is 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//Whether the second video is in portrait mode CGAffineTransform secondTransform = secondVideoAssetTrack.preferredTransform // Check the second video track's preferred transform to determine if it was recorded in portrait mode. //Check the preferred transformation of the second video track to determine if it is 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} //Judge whether the recording directions of the two video tracks are the same, and warn if they are inconsistent, because the recording directions of the two videos are inconsistent and cannot be synthesized 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 } ビデオコンポジションレイヤー命令の適用(ビデオコンポジションレイヤーの指示を適用する)。

あなたが知ったらビデオクリップには互換性のある方向性があります、 あなたは付け加えられます必要なレイヤーの指示が各ビデオクリップに適用されます段落、およびこれらのレイヤーの説明をビデオコンポジションに追加しますに。

//The first video synthesis instruction object AVMutableVideoCompositionInstruction *firstVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction] // Set the time range of the first instruction to span the duration of the first video track. //Set the time range of the first command to last to the duration of the first video track. firstVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, firstVideoAssetTrack.timeRange.duration) //The second video synthesis instruction object AVMutableVideoCompositionInstruction * secondVideoCompositionInstruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction] // Set the time range of the second instruction to span the duration of the second video track. //Set the time range of the second command to last to the duration of the first video track. secondVideoCompositionInstruction.timeRange = CMTimeRangeMake(firstVideoAssetTrack.timeRange.duration, CMTimeAdd(firstVideoAssetTrack.timeRange.duration, secondVideoAssetTrack.timeRange.duration)) //The first video synthesis layer instruction object AVMutableVideoCompositionLayerInstruction *firstVideoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoCompositionTrack] // Set the transform of the first layer instruction to the preferred transform of the first video track. //Set the transformation of the first layer instruction as the preferred transformation of the first video track. [firstVideoLayerInstruction setTransform:firstTransform atTime:kCMTimeZero] //The second video synthesis layer instruction object AVMutableVideoCompositionLayerInstruction *secondVideoLayerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:videoCompositionTrack] // Set the transform of the second layer instruction to the preferred transform of the second video track. //Set the transformation of the second layer instruction as the preferred transformation of the second video track. [secondVideoLayerInstruction setTransform:secondTransform atTime:firstVideoAssetTrack.timeRange.duration] //Append the first layer instruction to the first video synthesis instruction. firstVideoCompositionInstruction.layerInstructions = @[firstVideoLayerInstruction] //Append the second layer instruction to the second video combination instruction. secondVideoCompositionInstruction.layerInstructions = @[secondVideoLayerInstruction] //Append two video synthesis instructions to the video synthesis instruction. AVMutableVideoComposition *mutableVideoComposition = [AVMutableVideoComposition videoComposition]mutableVideoComposition.instructions = @[firstVideoCompositionInstruction, secondVideoCompositionInstruction]

すべてAVAssetTrackオブジェクトには1つありますPreferredTransform属性リソーストラックの方向情報が含まれていますリソーストラックが画面に表示されている限りこの変換を適用します前のコードではレイヤー命令の変換は、アセットトラックの変換に設定されますレンダリングのサイズを変更した後、新しいコンポジションのビデオが正しく表示されます

レンダリングサイズとフレーム期間の設定(レンダリングサイズとフレーム期間を設定する)。

ビデオの向きの修正を完了するには、それに応じてrenderSizeプロパティを調整する必要があります。また、1/30秒(または30フレーム/秒)など、frameDuration属性に適切な値を選択する必要があります。デフォルトでは、renderScaleプロパティは1.0に設定されています。これは、このコンポジションに適用されます。

CGSize naturalSizeFirst, naturalSizeSecond//The first natural size, the second natural size // If the first video asset was shot in portrait mode, then so was the second one if we made it here. //If the first video asset was shot in portrait (portrait) mode, then the second video asset should also be like this. if (isFirstVideoAssetPortrait) { // Invert the width and height for the video tracks to ensure that they display properly. //Reverse the width and height of the video track to ensure they are displayed correctly. 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. //If the video was not shot in portrait mode, we can use their natural size. naturalSizeFirst = firstVideoAssetTrack.naturalSize naturalSizeSecond = secondVideoAssetTrack.naturalSize } float renderWidth, renderHeight // Set the renderWidth and renderHeight to the max of the two videos widths and heights. //Set the renderWidth and renderHeight to the maximum of the width and height of the two videos. 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). //Set the frame duration to an appropriate value (ie 30 frames per second for the video). mutableVideoComposition.frameDuration = CMTimeMake(1,30)

コンポジションをエクスポートしてカメラロールに保存する(コンポジットファイルをエクスポートし、カメラロールに保存します)。

このプロセスの最後のステップは、コンポジション全体をビデオファイルにエクスポートし、ビデオをカメラロールに保存することです。AVAssetExportSessionオブジェクトを使用して新しいビデオファイルを作成し、それを出力ファイルに必要なURLに渡します。次に、ALAssetsLibraryクラスを使用して、生成されたビデオファイルをカメラロールに保存できます。

// 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. Use export session to create an export session 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. //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. //Set the output file type to 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. //Asynchronously export the synthesized video to a video file, and save the file to the camera roll after the export is complete. [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] } } }) }]