今回は動画に音を追加する。
音は短い効果音であっても良いし、長いBGMであっても良い。
ここでは動画よりも長い曲をBGMとして追加することにする。
元動画とBGM、出力動画のイメージはこのようになる。

音は短い効果音であっても良いし、長いBGMであっても良い。
ここでは動画よりも長い曲をBGMとして追加することにする。
元動画とBGM、出力動画のイメージはこのようになる。

ソースコードはこうだ。
異なっている箇所を中心に説明していく。
1.今回は元動画の長さはそのままで、そこにBGMを追加するので開始時間とデュレーションは必要無い。
不要な変数は混乱のもととなるので、削除してある。
2.出力動画の長さを変えないということは、元動画と出力動画の長さが同じということなので、CMTimeRange変数はrangeという一つに統一しておく。
3.やっていることは以前の記事と基本的には同じだ。
BGM用のアセットとトラックを準備して、追加しているだけである。
これで処理は完成だ。
実行してみよう。
元動画にBGMが追加されているはずである。
関連記事
[iOS] 動画を加工・編集する(1) 指定した時間の範囲を切り出す
[iOS] 動画を加工・編集する(2) エラーコード-11841に気をつける
[iOS] 動画を加工・編集する(4) 動画をクリッピングする
[iOS] 動画を加工・編集する(5) 動画を拡大縮小する
[iOS] 動画を加工・編集する(6) 複数の動画を連結する
const int kVideoFPS = 30; - (void)addSoundToMovie { // 1 NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0]; NSString *inputPath = [[path stringByAppendingPathComponent:@"portrait1"] stringByAppendingPathExtension:@"mov"]; NSString *outputPath = [[path stringByAppendingPathComponent:@"result"] stringByAppendingPathExtension:@"mov"]; AVMutableComposition *composition = [AVMutableComposition composition]; AVMutableCompositionTrack *compositionVideoTrack = [composition addMutableTrackWithMediaType:AVMediaTypeVideo preferredTrackID:kCMPersistentTrackID_Invalid]; AVMutableCompositionTrack *compositionAudioTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; NSError *error; NSURL *inputURL = [NSURL fileURLWithPath:inputPath]; AVURLAsset *asset = [[AVURLAsset alloc] initWithURL:inputURL options:nil]; // 2 CMTimeRange range = CMTimeRangeMake(kCMTimeZero, asset.duration); AVAssetTrack *videoTrack = [asset tracksWithMediaType:AVMediaTypeVideo][0]; AVAssetTrack *audioTrack = [asset tracksWithMediaType:AVMediaTypeAudio][0]; [compositionVideoTrack insertTimeRange:range ofTrack:videoTrack atTime:kCMTimeZero error:&error]; [compositionAudioTrack insertTimeRange:range ofTrack:audioTrack atTime:kCMTimeZero error:&error]; AVMutableVideoCompositionInstruction *instruction = [AVMutableVideoCompositionInstruction videoCompositionInstruction]; instruction.timeRange = range; AVMutableVideoCompositionLayerInstruction *layerInstruction = [AVMutableVideoCompositionLayerInstruction videoCompositionLayerInstructionWithAssetTrack:compositionVideoTrack]; // 3 NSString *soundPath = [[NSBundle mainBundle] pathForResource:@"sound" ofType:@"caf"]; NSURL *soundURL = [NSURL fileURLWithPath:soundPath]; AVURLAsset *soundAsset = [[AVURLAsset alloc] initWithURL:soundURL options:nil]; AVAssetTrack *soundTrack = [soundAsset tracksWithMediaType:AVMediaTypeAudio][0]; AVMutableCompositionTrack *compositionSoundTrack = [composition addMutableTrackWithMediaType:AVMediaTypeAudio preferredTrackID:kCMPersistentTrackID_Invalid]; [compositionSoundTrack insertTimeRange:range ofTrack:soundTrack atTime:kCMTimeZero error:&error]; CGSize videoSize = videoTrack.naturalSize; CGAffineTransform transform = videoTrack.preferredTransform;; if (transform.a == 0 && transform.d == 0 && (transform.b == 1.0 || transform.b == -1.0) && (transform.c == 1.0 || transform.c == -1.0)) { videoSize = CGSizeMake(videoSize.height, videoSize.width); } [layerInstruction setTransform:transform atTime:kCMTimeZero]; instruction.layerInstructions = @[layerInstruction]; AVMutableVideoComposition *videoComposition = [AVMutableVideoComposition videoComposition]; videoComposition.renderSize = videoSize; videoComposition.instructions = @[instruction]; videoComposition.frameDuration = CMTimeMake(1, kVideoFPS); NSFileManager *fm = [NSFileManager defaultManager]; if ([fm fileExistsAtPath:outputPath]) { [fm removeItemAtPath:outputPath error:&error]; } AVAssetExportSession *session = [[AVAssetExportSession alloc] initWithAsset:composition presetName:AVAssetExportPresetHighestQuality]; session.outputURL = [NSURL fileURLWithPath:outputPath]; session.outputFileType = AVFileTypeQuickTimeMovie; session.videoComposition = videoComposition; [session exportAsynchronouslyWithCompletionHandler:^{ if (session.status == AVAssetExportSessionStatusCompleted) { NSLog(@"output complete!"); } else { NSLog(@"output error! : %@", session.error); } }]; }基本的には以前の記事([iOS] 動画を加工・編集する(1) 指定した時間の範囲を切り出す)と大差ない。
異なっている箇所を中心に説明していく。
1.今回は元動画の長さはそのままで、そこにBGMを追加するので開始時間とデュレーションは必要無い。
不要な変数は混乱のもととなるので、削除してある。
2.出力動画の長さを変えないということは、元動画と出力動画の長さが同じということなので、CMTimeRange変数はrangeという一つに統一しておく。
3.やっていることは以前の記事と基本的には同じだ。
BGM用のアセットとトラックを準備して、追加しているだけである。
これで処理は完成だ。
実行してみよう。
元動画にBGMが追加されているはずである。
関連記事
[iOS] 動画を加工・編集する(1) 指定した時間の範囲を切り出す
[iOS] 動画を加工・編集する(2) エラーコード-11841に気をつける
[iOS] 動画を加工・編集する(4) 動画をクリッピングする
[iOS] 動画を加工・編集する(5) 動画を拡大縮小する
[iOS] 動画を加工・編集する(6) 複数の動画を連結する
コメント
コメント一覧 (2)
大変参考になる記事を書いていただきありがとうございます。
こちらの記事を参考に音声合成した動画を作成したのですが、シミュレータのカメラロールで確認しようとすると「The operation could not be completed」と言われてしまい再生ができません。
ネットの海をさまよったのですが解決法が全くわからず、、
対策として何かご存知でしたらご教示いただけると幸いです。
よろしくお願いします。
私の環境ではそういった事象は起きなかったので、正直わかりません。
とりあえず、問題を切り分けてみてはいかがでしょうか。
◯作成した動画はOS X上では再生できるのか、またiPhone実機で再生できるのか
◯実機でそのプログラムは動作するのか
◯音声を合成せずに、元の動画をプログラムを通して出力するだけのものではどうか
◯その場合、元の動画の音声を入れずに出力する等のことを試す
等々
なお、そのメッセージでググってみると、海外のサイトではちらほら情報があるようです。
それらを見てみると参考になるかもしれません。