iPhone撮影HDR(HEVC)動画の読み込み遅延に困ったけど、PHPickerViewController設定で解決した話(iOSアプリ開発)の巻

はじめに
個人開発しているiOSアプリ(Clip-A-Doodle-Draw)で、PhotosUIのPHPickerViewControllerを使ってフォトライブラリから動画を選んでから再生する機能を実装しているのですが、動画の読み込みにものすごく時間がかかることがある、という現象に気づきました。これは困った。。。
どうも「iPhoneでHDRオンにして撮ったHEVC(H.265)形式の動画」の読み込みのときだけえらい時間がかかる。なんでじゃー?
で、調べていくと、PHPickerConfiguration のデフォルトの設定によって裏でH.265がH.264にトランスコード(変換)されていたことが原因だとわかりました。
というわけで、「iPhoneでHDRオンにして撮ったHEVC(H.265)形式の動画」をPHPickerViewControllerで選択したときの読み込みに時間がかかっていたことを解消した時のメモです。
実施環境
Xcode: Version 16.4 (16F6)
UIKitのPhotosUIのPHPickerViewController
原因:PHPickerが自動でH.264に変換していた
iPhoneでHDRをオンにして撮影すると、動画は高画質かつ効率的に圧縮されたHEVCフォーマット(H.265)で保存されます(iPhone 12以降)。
んで、PHPickerViewController 経由で動画を選択すると、互換性重視で H.264 に自動変換されてしまうことがわかりました。いらんことを。。。いや、必要なのか。。。
この変換処理がけっこう重くて、動画の読み込みに時間がかかる原因になっていました。
例えば、 Clip-A-Doodle-Drawにおいて、HEVC フォーマットの5分の動画の読み込みに3分近くかかってしまっていました。これじゃアプリがフリーズしたと勘違いされますわな。。。
解決策: .preferredAssetRepresentationMode = .current
を設定
ありがたいことに、PHPickerConfiguration にひと手間加えるだけで回避できることがわかりました
import SwiftUI
import PhotosUI
struct PhotoPickerView: UIViewControllerRepresentable {
@Binding var videoURL: URL? // 選択されたビデオのURL
func makeUIViewController(context: Context) -> PHPickerViewController {
var configuration = PHPickerConfiguration()
configuration.filter = .videos // ビデオのみを対象とするフィルターを設定
configuration.selectionLimit = 1 // 選択可能なアイテム数を制限
configuration.preferredAssetRepresentationMode = .current // <= これ!
let picker = PHPickerViewController(configuration: configuration)
picker.delegate = context.coordinator
return picker
.preferredAssetRepresentationMode のデフォルトは .automatic で、未設定だとワタシのケースではHEVC(H.265)はH.264に変換されていました。
これを。。。
configuration.preferredAssetRepresentationMode = .current
として指定することで、オリジナル(HEVC形式)のまま取得できるようになります。
iPhone 12以降だと、HEVC形式の動画を再生できるので、H.264に変換せずともHEVC(H.265)のままでOKなのでした。
この設定により、不必要(?)なトランスコード処理がなくなり、読み込みの遅延が劇的に解消されました。 よかったー。
補足:Info.plist の記述もしておく
なお、PPHPickerViewControllerHPicker を使うには、XcodeでInfoのCustom iOS Target Propertiesに、以下のような説明文を追加しておく必要があります(やってなかった💦):
<key>
Privacy - Photo Library Usage Description</key>
<string>ビデオを読み込むためにフォトライブラリへのアクセスを許可してください</string>
*記載例です。ユーザーに表示される文章なので、わかりやすく丁寧に書かなきゃです。
おまけ:シミュレーターで白飛びして焦った話
実は、
configuration.preferredAssetRepresentationMode = .current
の設定をしたら、読み込み時間は改善したものの、iOSシミュレーターでHEVC(H.265)のビデオを再生すると画面が白っぽく飛んでしまいます。
いろいろ調べた結果、実機で再生すればちゃんと表示されることがわかりました。気付くまですごい時間かかった。。。
どうやらシミュレーターは HDR 表示に完全対応していないようで、この手の確認は実機でやるべきだと学びましたよ。。。
おわりに
はい、iOSアプリでのHEVC(H.265)動画をPhotosUIのPHPickerViewController経由で読み込むときの遅延が生じていたけど、
.preferredAssetRepresentationMode = .current
を指定することで遅延が解消できたという話でした。
同じケースで悩んでいる方の参考になればうれしいです 。
さて、iOS16から導入されたPhotosPickerだとどうなるんだろう。。。そもそも問題が起きなかったりして。。。
ともあれ、めでたしめでたし、と。おしまい。
参考
🔗 react-native-image-picker issue #2278
React Native 向けの話ではありますが、PHPickerViewController の仕組み自体が原因だったことにたどり着いたのは、参考情報のおかげです。ありがたやー。