はつねむさんぽのパンくずたち

エンジニアになる人生で通った道のあしあと

【Swift】動画撮影&保存&取得【UIImagePickerController】

やりたいこと

アプリ内で動画を撮影し保存。
また、アプリ内で撮影した動画のみを取得。

実装方法

動画撮影

動画周りはややこしいイメージがあったが、
UIImagePickerControllerを使えば意外と簡単に実装できた。

let sourceType = UIImagePickerController.SourceType.camera
// 端末でカメラが利用可能か調べる
if UIImagePickerController.isSourceTypeAvailable(sourceType) {
    let pickerController = UIImagePickerController()
    pickerController.delegate = self
    pickerController.sourceType = sourceType

    // ここで動画を選択
    pickerController.mediaTypes = ["public.movie"]
    // 以下のようにすると、利用可能な全てのmediaTypeが選択できる
    // pickerController.mediaTypes = UIImagePickerController.availableMediaTypes(for: sourceType) ?? []

    // 動画を高画質で保存する
    pickerController.videoQuality = .typeHigh
    present(pickerController, animated: true, completion: nil)
}

動画保存

撮影した動画はAppData内のtmpフォルダ(一時フォルダ)に置かれているので、
Documentフォルダに移動する。
カメラロールに保存するよりもアプリ内動画一覧の取得が実装しやすい。
あとで必要なものだけカメラロールにエクスポートする方法をとった。

func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
    picker.dismiss(animated: true, completion: nil)
    
    // 一時フォルダに保存されたファイルのURL
    guard let fileUrl = info[.mediaURL] as? URL else { return }
    // DocumentフォルダのURL
    let documentsDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    do {
        //  tmpに保存された動画をDocumentに移動
        try FileManager.default.moveItem(at: fileUrl, to: documentsDirectoryURL.appendingPathComponent(fileUrl.lastPathComponent))
        print("動画の保存に成功しました。")
    } catch {
        print("動画の保存に失敗しました。")
    }
}

動画取得

Documentフォルダ内のファイルのURLを全て取得する。

var videoUrls = [URL]()

let documentDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
do {
    // Documentから動画ファイルのURLを取得
    videoUrls = try FileManager.default.contentsOfDirectory(at: documentDirectoryURL, includingPropertiesForKeys: nil)
} catch {
    print("フォルダが空です。")
}

取得したURLを使って、動画を再生したり、一覧を表示したりできる。
Collection Viewにサムネイル一覧を表示するならこんな感じ。

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = self.collectionView.dequeueReusableCell(withReuseIdentifier: "videoCell", for: indexPath)
    
    // URLから動画を取得
    let video = AVURLAsset(url: videoUrls[indexPath.row])
    // 動画から静止画を切り出すジェネレータ
    let generator = AVAssetImageGenerator(asset: video)
    // 今回は00:00の部分を切り出し
    let thumbnail = try! generator.copyCGImage(at: .zero, actualTime: nil)
    
    let thumbnailView = cell.viewWithTag(1) as! UIImageView
    thumbnailView.image = UIImage(cgImage: thumbnail)
    
    let label = cell.viewWithTag(2) as! UILabel
    let sec = Int(video.duration.seconds)
    label.text = String(format:"%02d:%02d", sec/60, sec%60)
    
    return cell
}