前回に引き続き。Assetを理解したら、次はCompositionの理解。
AVAssetのサブクラスにはAVURLAssetとAVCompositionの二つがある。
動画編集では必然的にCompositionを使うことになるので、まず基礎から。
CompositionとTrackとAsset
| 名称 | 説明 |
|---|---|
| Composition | 一つの映像作品 / プロジェクト |
| Track | Compositionを構成する映像/音声トラック |
| Asset | 各トラックの上にのせる素材 |
ここらへんは世の中の動画編集ソフトと基本的に同じ考え方なので、もしピンとこなかったらPremiere辺りを使ってみて感覚をつかんでおくとわかりやすい。なお、ややこしいがCompositionもAssetとして扱えるので注意。
読み込んだAssetのトラックを調べてみる
AVAssetのtracksプロパティを見ると、そのAssetに含まれるトラックの情報を見れる。
let asset = AVURLAsset(url: url)
debugPrint(asset.tracks)
大抵の動画ファイルは、2トラック(映像トラック1 + 音声トラック1)から構成される。
[<AVAssetTrack: 0x600000018080, trackID = 1, mediaType = soun>, <AVAssetTrack: 0x6000000181e0, trackID = 2, mediaType = vide>]
tracksの代わりに、tracks(withMediaType:)を使うとタイプを限定したトラックのリストを取得できる。
debugPrint(asset.tracks(withMediaType: .video))
Compositionを作る
ファイルからAssetをロードする際にはAVURLAssetを使ったが、ゼロからCompositionを作る場合はAVCompositionのサブクラスであるAVMutableCompositionを使う。
let composition = AVMutableComposition()
映像トラックを追加する
AVMutableComposition生成直後はトラックがない空のコンポジションとなっているので、映像トラックを一つ追加する。
guard let videoTrack = composition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid) else {
debugPrint("Failed to add video track.")
return
}
addMutableTrack(withMediaType:, preferredTrackID:)を呼ぶと、新しいトラックがCompositionに追加される。
- 今回は映像トラックなので
.videoを指定したが、.audioを指定すると音声トラックが追加される。 -
preferredTrackIDに値を指定すると、任意のトラックIDをつけることができるが、特に指定する必要がない時はkCMPersistentTrackID_Invalidを指定すると、自動的にユニークなIDをつけてくれる。(参考: https://developer.apple.com/documentation/avfoundation/avmutablecomposition/1387601-addmutabletrack)
映像トラックにAssetの映像を追加する
AVMutableCompositionTrackには、insertTimeRange:ofTrack:atTime:error:メソッドで他のAssetのトラックの内容を追加できる。
// 素材Assetの1個目のVideoトラックを使う
let srcVideoTrack = asset.tracks(withMediaType: .video)[0]
do {
// 0秒のタイミングに、映像全体を追加する
try videoTrack.insertTimeRange(srcVideoTrack.timeRange, of: srcVideoTrack, at: .zero)
} catch let error {
debugPrint(error)
}
大体メソッド名通りなので説明不要かもしれないが、
- TimeRange - 元素材トラックの方のどの範囲(0:30.000〜0:35.000 とか)を使うかをCMTimeRangeで指定する。今回は元素材トラック全体を指定した。
- ofTrack - 元素材トラックを指定
- atTime - 貼付ける先のトラックのどの位置に貼付けるか
例えば、元素材から最初の5秒間の映像(videoトラックのみ)をコピーしたい場合はこのように書ける。
let first5Seconds = CMTimeRange(start: .zero, end: CMTime(seconds: 5.0, preferredTimescale: srcVideoTrack.naturalTimeScale))
try videoTrack.insertTimeRange(first5Seconds, of: srcVideoTrack, at: .zero)
timescaleは特別な理由がなければ元素材に合わせておきたいので、元素材のnaturalTimeScaleを使用している。
CompositionをAVPlayerViewで再生する
作成したComposition(Asset)は、AVPlayerおよびAVPlayerViewを使って画面で再生させることができる。
let player = AVPlayer(playerItem: AVPlayerItem(asset: composition))
playerView.player = player // playerViewはStoryboardに設置したAVPlayerView
ファイルに書き出してから内容を確認するのが面倒な場合や、プレビュー機能を作るときはこの仕組みも活用したい。
Compositionの書き出し
AVMutableCompositionはAVAssetのサブクラスなので、AVAssetExportSessionを使ったファイルへの書き出しができる。
guard let session = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetPassthrough) else {
debugPrint("Failed to prepare session")
return
}
session.outputURL = url
session.outputFileType = .mp4
session.exportAsynchronously {
switch session.status {
case .completed:
debugPrint("completed")
case .failed:
debugPrint("error: \(session.error!.localizedDescription)")
default:
break
}
}
- 利用可能な
PresetNameはAVAssetExportSession.allExportPresets()で確認することができる。