LoginSignup
12
9

More than 5 years have passed since last update.

AVAssetExportSessionで多数の動画を合成するときにハマッたお話

Posted at

AVAssetExportSessionの罠?

拙作のアプリふぉとむぐでは、AVAssetExportSessionを用いて多数の動画を合成する機能を実装したのですが、そこで思わぬ罠にはまってしまいました。

はじめに結果を申し上げると、この内容をApple Developer Technical Supportに報告したところ、iOS 10.3 の時点では不具合(というより制限?)のため、回避策を試して欲しいとのことでした。

ただ回答で来た方法ではうまくいかなったため、これをアレンジして回避することができたので、ここにその方法をまとめることにしました。

起こった問題

従来は動画の合成を行う際、下記の図のようにしていました。

old.png

  • 各入力動画(AVAsset)からAVAssetTrackを取り出し、その都度AVCompositionTrackを追加 (つまり動画の数だけAVCompositionTrackを生成していた)
  • AVCompositionTrackに対応するAVVideoCompositionLayerInstructionを生成し、TransformやOpacityRampを適用
  • ひとつのAVVideoCompositionInstructionに、各入力動画の対応するAVVideoCompositionLayerInstructionを設定し、これを書き出す

このような方法で動画の合成を行うと、 多数の動画を入力したとき以下のエラーで書き出しに失敗します!

Error Domain=AVFoundationErrorDomain Code=-11839 "Cannot Decode" UserInfo={NSUnderlyingError=0x174247020 {Error Domain=NSOSStatusErrorDomain Code=-12913 "(null)"}, NSLocalizedFailureReason=The decoder required for this media is busy., NSLocalizedRecoverySuggestion=Stop any other actions that decode media and try again., NSLocalizedDescription=Cannot Decode}

(iPhone 6sでは15〜16個の動画合成で発生。シミュレータでは発生しない)

エラー内容とAppleからの回答から、AVCompositionTrackはビデオデコーダのリソースを抑えたまま解放しない問題があるらしく、多量にインスタンス化するとリソース不足でエラーが起きてしまうようです。

解決策

お察しのとおり、AVCompositionTrackを使い回して、必要以上に生成しなければ解決できます。
Appleからの回答では、2つのAVCompositionTrackを交互に使えばいいとのことでしたがうまくいかなかったため、以下の図のようにしました。

new.png

  • AVCompositionTrackを3つ用意する
    • Main: トランジション時間にかからない、各動画単独再生のトラック
    • Transition Source: トランジション中の遷移元となる動画用トラック
    • Transition Destination: トランジション中の遷移先となる動画用トラック
  • AVVideoCompositionInstructionはトランジション時間ごとに別々に用意する
    • 非トランジション区間はMainトラックに追加したAVVideoCompositionLayerInsturctionのみ参照
    • トランジション区間はSource, Destinationトラック2つのAVVideoCompositionLayerInsturctionを参照

その他・注意しておきたいところ

AVAssetExportSessionでは他にも、こんなところが躓きやすい...

export中のエラー

時間の指定が間違っていないか確認しましょう。

  • AVVideoCompositionInstructiontimeRangeは"空白の区間"があってはいけない。つまりprevInstruction.timeRange.end == instruction.timeRange.startである必要がある
  • AVVideoCompositionInstructiontimeRangeと、insertTimeRange()で追加した動画の位置と長さは一致していなければならない(おそらく)

exportは成功したけど動画が真っ黒

AVVideoCompositionLayerInstructionのTransformを正しく設定しないとイイ位置に来てくれません。

  • Live Photosから取り出したAVAssetTrackpreferredTransform.tx, tyは画像解像度に準拠しない値になっていることがある (Live Photos動画の解像度とフレームレートが、リリース当初と最近で仕様が違うため?)
  • 出力解像度を変える(スケーリングする)場合、CropRectangleを指定しないとスケールしない場合がある
12
9
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
9