soranoba
soranoba Author of soranoba.net
programming

iOSでh264エンコード時にフリッカーが発生する問題への対応

iPhone11ぐらいからiOSでは特定条件でh.264エンコード後の映像にフリッカーが発生するという問題があります.
この対処法について紹介します.

発生条件


カメラから取得したCVPixelBufferを直接エンコーダーに渡す場合と, Metalなどで加工したCVPixelBufferを渡す2つの経路が動的に変わる場合に発生します.
より具体的には, 最初のフレームが(2)の経路を通り, その後(1)の経路に変更し, 再度(2)の経路に変更した場合に発生するようです.
100%再現できますが, より細かな条件 (例えば加工時のCVPixelBufferのオプションなど) がある可能性もあります.

対処方法

h.264エンコード時の色変換周りのオプションを明示的に指定することで回避できます.

AVAssetWriterInput(mediaType: .video,
                   outputSettings: [
                      AVVideoWidthKey: width,
                      AVVideoHeightKey: height,
                      AVVideoCodecKey: AVVideoCodecType.h264,
                      // 以下の3つ
                      AVVideoColorPropertiesKey: [
                          AVVideoColorPrimariesKey: AVVideoColorPrimaries_ITU_R_709_2,
                          AVVideoTransferFunctionKey: AVVideoTransferFunction_ITU_R_709_2,
                          AVVideoYCbCrMatrixKey: AVVideoYCbCrMatrix_ITU_R_709_2,
                      ],
                   ])
VTSessionSetProperties(session,
                       propertyDictionary: [
                          // 省略

                          // 以下の3つ
                          kVTCompressionPropertyKey_ColorPrimaries: kCMFormatDescriptionColorPrimaries_ITU_R_709_2,
                          kVTCompressionPropertyKey_TransferFunction: kCMFormatDescriptionTransferFunction_ITU_R_709_2,
                          kVTCompressionPropertyKey_YCbCrMatrix: kCMFormatDescriptionYCbCrMatrix_ITU_R_709_2,
                       ] as CFDictionary)

AVAssetWriterVTSessionの場合は上記のプロパティ3つを設定することでフリッカーを回避できます.
上記の値は, AVVideoSettings.hに記載されている推奨値にしています. 他にも推奨値の記載があるので必要に応じて参照してください.

Clients who specify AVVideoColorPropertiesKey must specify a color primary, transfer function, and Y’CbCr matrix. Most clients will want to specify HD, which consists of:

	AVVideoColorPrimaries_ITU_R_709_2
	AVVideoTransferFunction_ITU_R_709_2
	AVVideoYCbCrMatrix_ITU_R_709_2

OSに関わらず, 端末依存で発生する問題なのでハードウェアエンコーダー周りを疑っていますが, 原因はよく分かりません.
今回は再現コードを作るのが結構面倒な関係上, バグレポートを提出していません.
なので詳しい情報を知っている方がいたら, ご一報いただけると喜びます.

(Updated: )

comments powered by Disqus