LoginSignup
5

More than 5 years have passed since last update.

iOSで動画編集中にプログレスバーを表示する

Posted at

AVFoundationで動画作成中にプログレスバーを表示する方法

動画編集について記事を記載していますが、作成中のプログレスバーを表示する方法について説明します。

AVAssetExportSession.progressで簡単に取得できます。例としてはこんな感じです。

class SampleController: UIViewController {    
    var assetExport: AVAssetExportSession!
    let timeInterval = 0.1          // プログレスバーの表示間隔 (0.1秒)

    @IBOutlet weak var progressBar: UIProgressView! // storyboardで作成

    override func viewDidLoad() {
        super.viewDidLoad()

        // タイマーをセット
        Timer.scheduledTimer(
            timeInterval: timeInterval,
            target: self,
            selector: #selector(self.step),
            userInfo: nil,
            repeats: true
        )

        // 動画作成のメイン関数
        self.makeMovie()
    }

    //タイマー関数
    @objc func step() {        
        //プログレス表示
        if assetExport != nil {    // タイミングによってはnilの場合もあり
            //動画作成処理中 
            progressBar.setProgress(assetExport.progress, animated: true)
        }
        else {
            // 動画作成前
        }
    }

    // 動画作成の関数
    func makeMovie() {
        //
        // 色々省略
        //

        // 動画のコンポジションをベースにAVAssetExportを生成
        assetExport = AVAssetExportSession.init(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)
        // 合成用コンポジションを設定
        assetExport?.videoComposition = videoComp

        // エクスポートファイルの設定
        assetExport?.outputFileType = AVFileType.mov
        assetExport?.outputURL = exportUrl
        assetExport?.shouldOptimizeForNetworkUse = true

        // エクスポート実行
        assetExport?.exportAsynchronously(completionHandler: {() -> Void in
            //処理省略
            //このあとプログレス情報が取得可能
        })
    }
}

解説

AVAssetExportSession.exportAsynchronouslyで動画の作成を開始した後にAVAssetExportSession.progressで取得できるようになります。
progressは0.0から1.0の値で取得できるので、そのままUIProgressViewに突っ込めます。

取得できる値はそこそこ正確なので、特に細工をせずそのまま使って大丈夫と思います。
動画作成の処理時間は、作成する動画の長さと画質に比例する様子で、それ以外のアニメーション処理などによる処理時間の変動はほとんどない様子。(全てのパターンを試した訳ではないですが、今のところそのような感覚です)

動画の前処理が長い場合は少し工夫が必要です。

動画の前処理が長い場合

ちょっと工夫してこんな感じです。

class SampleController: UIViewController {    
    var assetExport: AVAssetExportSession!
    let timeInterval = 0.1          // プログレスバーの表示間隔 (0.1秒)
    let processTime : Float = 0.10    // 前処理にかかる割合(10%の場合)   
    var progressTimer: Float = 0.0    // 前処理中のプログレスバーの数値

    @IBOutlet weak var progressBar: UIProgressView! // storyboardで作成

    override func viewDidLoad() {
        super.viewDidLoad()

        // タイマーをセット
        Timer.scheduledTimer(
            timeInterval: timeInterval,
            target: self,
            selector: #selector(self.step),
            userInfo: nil,
            repeats: true
        )

        // 動画作成のメイン関数
        // 前処理をプログレスバーに反映させるために非同期処理にする
        DispatchQueue.global(qos: .default).async {
            self.makeMovie()
        }
    }

    //タイマー関数
    @objc func step() {        
        //プログレス表示
        if assetExport != nil {    // タイミングによってはnilの場合もあり
            //動画作成処理中 
            progressBar.setProgress((assetExport.progress * (1.0 - processTime)) + processTime, animated: true)
        }
        else {
            // 動画作成前
            if self.progressTimer < processTime {
                self.progressTimer = self.progressTimer + 0.01 // (数値はちょうどよくなるように調整)
                progressBar.setProgress(self.progressTimer, animated: true)
            }
        }
    }

    // 動画作成の関数
    func makeMovie() {
        // ここは変更なし
    }
}

解説

まずはDispatchQueue.global(qos: .default).asyncで時間がかかる部分を非同期処理に。
assetExportがnilかどうかで前処理中かどうかが分かるので、nilの場合のプログレスバーの計算をしています。
let processTime : Float = 0.10 は動画編集にかかる前処理の割合です。何度か実機で試してみて、この数値は出せば大丈夫。ただし、動画作成の長さや画質が動的に変えられるアプリの場合は、この比率が動的に変わるので、その計算もしないといけなくなるはずです。
いくつかの機種で試したところ、処理時間はCPU性能にのみ比例するようなので、どれか一つの機種で試せばOKと思われます。

self.progressTimer = self.progressTimer + 0.01 でインクリメントしているのですが、この数値はタイマーの更新間隔や実際に処理が終了する時間によって調整が必要です。一番処理がかかる機種をベースにして計算しておけば安心です。

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
5