Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
53
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

AV Foundationを使った動画編集(Composition)

前回に引き続き。Assetを理解したら、次はCompositionの理解。

AVAssetのサブクラスにはAVURLAssetAVCompositionの二つがある。
動画編集では必然的にCompositionを使うことになるので、まず基礎から。

CompositionとTrackとAsset

名称 説明
Composition 一つの映像作品 / プロジェクト
Track Compositionを構成する映像/音声トラック
Asset 各トラックの上にのせる素材

ここらへんは世の中の動画編集ソフトと基本的に同じ考え方なので、もしピンとこなかったらPremiere辺りを使ってみて感覚をつかんでおくとわかりやすい。なお、ややこしいがCompositionAssetとして扱えるので注意。

読み込んだAssetのトラックを調べてみる

AVAssettracksプロパティを見ると、その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:)を使うとタイプを限定したトラックのリストを取得できる。

videoタイプのトラックのみ取得
debugPrint(asset.tracks(withMediaType: .video))

Compositionを作る

ファイルからAssetをロードする際にはAVURLAssetを使ったが、ゼロからCompositionを作る場合はAVCompositionのサブクラスであるAVMutableCompositionを使う。

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に追加される。

映像トラックにAssetの映像を追加する

AVMutableCompositionTrackには、insertTimeRange:ofTrack:atTime:error:メソッドで他のAssetのトラックの内容を追加できる。

映像トラックに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トラックのみ)をコピーしたい場合はこのように書ける。

最初の5秒間だけを元素材からとってくる
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の書き出し

AVMutableCompositionAVAssetのサブクラスなので、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
    }
}
  • 利用可能なPresetNameAVAssetExportSession.allExportPresets()で確認することができる。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
53
Help us understand the problem. What are the problem?