Blog スタッフブログ

Swift システム開発

[iOS]選択した動画ファイルの指定秒のサムネイルを取得する

Swift

こんにちは、株式会社MIXシステム開発担当のBloomです。

早速本題の選択した動画ファイルの指定秒のサムネイル画像を取得する手順について、

お仕事の中で得た知見を共有させていただきたいと思います。

Androidでサムネイル生成はこちら

JavaScriptでサムネイル生成はこちら

動画ファイルの選択

今回はUIImagePickerではなくPHPickerViewControllerを利用して動画ファイルを選択します。

import PhotosUI
class ViewController: UIViewController {
    @IBOutlet weak var imageView: UIImageView!
    @IBAction func selectButtonTouchUpInside(_ sender: Any) {
        // ライブラリ権限取得 別途Privacy - Photo Library Usage Descriptionの設定を行なってください
        if PHPhotoLibrary.authorizationStatus() != .authorized {
            PHPhotoLibrary.requestAuthorization { status in
                switch status {
                case .notDetermined, .denied:
                    self.appearChangeStatusAlert()
                case .authorized:
                    self.showPicker()
                default:
                    break
                }
            }
        }
        else {
            showPicker()
        }
    }
    private func appearChangeStatusAlert() {
        // アクセス権限が取れなかった場合に表示
        let alert = UIAlertController(title: "ライブラリが開けませんでした", message: "設定からフォトライブラリへのアクセスを許可してください", preferredStyle: .alert)
        let settingAction = UIAlertAction(title: "設定", style: .default, handler: { (_) in
            guard let settingUrl = URL(string: UIApplication.openSettingsURLString) else { return }
            UIApplication.shared.open(settingUrl, options: [:], completionHandler: nil)
        })
        let closeAction = UIAlertAction(title: "キャンセル", style: .cancel, handler: nil)
        alert.addAction(settingAction)
        alert.addAction(closeAction)
        self.present(alert, animated: true, completion: nil)
    }
    private func showPicker() {
        // PHPickerViewControllerを表示
        DispatchQueue.main.async {
            var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
            configuration.filter = .videos
            configuration.selectionLimit = 1
            configuration.preferredAssetRepresentationMode = .current
            let picker = PHPickerViewController(configuration: configuration)
            picker.delegate = self
            self.present(picker, animated: true, completion: nil)
        }
    }
}

サムネイルを取得

PHPickerViewControllerDelegateから動画ファイルを受け取り、AVAssetを経由して静止画を取得します。

extension ViewController: PHPickerViewControllerDelegate {
    func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
        guard let provider = results.first?.itemProvider else { return }
        guard let typeIdentifier = provider.registeredTypeIdentifiers.first else { return }
        picker.dismiss(animated: true, completion: nil)
        if provider.hasItemConformingToTypeIdentifier(typeIdentifier) {
            provider.loadFileRepresentation(forTypeIdentifier: typeIdentifier) { (url, error) in
                if let error = error { print("*** error: \(error)") }
                if let url = url {
                    // サムネイル生成
                    let avAsset = AVAsset(url: url)
                    let generator = AVAssetImageGenerator(asset: avAsset)
                    generator.appliesPreferredTrackTransform = true
                    generator.requestedTimeToleranceAfter = .zero
                    generator.requestedTimeToleranceBefore = .zero
                    let duration = avAsset.duration
                    let seconds = 5.0 // 5秒で指定
                    let time = CMTime(seconds: seconds, preferredTimescale: duration.timescale)
                    let capturedImage = try! generator.copyCGImage(at: time, actualTime: nil)
                    let image = UIImage(cgImage: capturedImage)
                    DispatchQueue.main.async {
                        // 取得したimageを表示
                        self.imageView.image = image
                    }
                }
            }
        }
    }
}

実行結果

これで簡単にサムネイルが生成できました。良かったですね。

参考文献

【Swift5】動画のサムネイル画像生成時に画像が90度回転するときの対処法 – Qiita