Introduction

WebM 形式の動画は iOS アプリの標準コンポーネントでは再生できない。
もし WebM 動画にアルファチャネルが設定されている場合は、他の形式に変えるとアルファチャネルを失ってしまう。
ただ幸いにして、アルファチャネル付きの HEVC コーデックの動画なら iOS アプリで再生できる。

Using HEVC Video with Alpha

なので、WebM 動画を HECV コーデックの MP4 に変換さえできれば目的を達成できる。

How to do?

ffmpeg を使って WebM 動画を HEVC コーデックの動画に変換する。
とはいえ、ダイレクトに変換はできないため

上記の Stackoverflow 手順を参考にする。

  1. WebM 動画をアルファチャネルを保持した PNG 画像に変換
  2. アルファチャネルを保持した PNG 画像をHEVC コーデックの動画に変換

サンプルの WebM 動画は https://rotato.netlify.app/alpha-demo/movie-webm.webm を使用。
ライセンスは不明なので注意。

なお、アルファチャネル付きの HEVC 動画を作るため MacOS 上で実行する。
ffmpeg は brew を使ってインストールしておく。

まず、 ffprobe で入力 WebM 動画の情報を調べる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
% ffprobe movie-webm.webm                                                                                                                          
ffprobe version 7.1 Copyright (c) 2007-2024 the FFmpeg developers
built with Apple clang version 16.0.0 (clang-1600.0.26.3)
configuration: --prefix=/opt/homebrew/Cellar/ffmpeg/7.1 --enable-shared --enable-pthreads --enable-version3 --cc=clang --host-cflags= --host-ldflags='-Wl,-ld_classic' --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libaribb24 --enable-libbluray --enable-libdav1d --enable-libharfbuzz --enable-libjxl --enable-libmp3lame --enable-libopus --enable-librav1e --enable-librist --enable-librubberband --enable-libsnappy --enable-libsrt --enable-libssh --enable-libsvtav1 --enable-libtesseract --enable-libtheora --enable-libvidstab --enable-libvmaf --enable-libvorbis --enable-libvpx --enable-libwebp --enable-libx264 --enable-libx265 --enable-libxml2 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-libspeex --enable-libsoxr --enable-libzmq --enable-libzimg --disable-libjack --disable-indev=jack --enable-videotoolbox --enable-audiotoolbox --enable-neon
libavutil 59. 39.100 / 59. 39.100
libavcodec 61. 19.100 / 61. 19.100
libavformat 61. 7.100 / 61. 7.100
libavdevice 61. 3.100 / 61. 3.100
libavfilter 10. 4.100 / 10. 4.100
libswscale 8. 3.100 / 8. 3.100
libswresample 5. 3.100 / 5. 3.100
libpostproc 58. 3.100 / 58. 3.100
Input #0, matroska,webm, from 'movie-webm.webm':
Metadata:
COMPATIBLE_BRANDS: qt
MAJOR_BRAND : qt
MINOR_VERSION : 0
ENCODER : Lavf58.45.100
Duration: 00:00:09.02, start: 0.000000, bitrate: 2552 kb/s
Stream #0:0: Video: vp9 (Profile 0), yuv420p(tv), 1280x720, SAR 1:1 DAR 16:9, 60 fps, 60 tbr, 1k tbn (default)
Metadata:
alpha_mode : 1
HANDLER_NAME : Core Media Video
ENCODER : Lavc58.91.100 libvpx-vp9
DURATION : 00:00:09.017000000

そして、下記が変換スクリプトであり、コーデックの hevc_videotoolbox が MacOS でしか使えない引数になる。
また、入力の WebM が 60 fps なので、入力、出力に -r 60 を付与している。
-alpha_quality でアルファチャネルの品質を 0.0 から 1.0 の範囲で指定できる。

1
2
3
$ mkdir tmp
$ ffmpeg -vcodec libvpx-vp9 -i movie-webm.webm -pix_fmt rgba tmp/image_%04d.png
$ ffmpeg -r 60 -i tmp/image_%04d.png -c:v hevc_videotoolbox -allow_sw 1 -alpha_quality 0.75 -vtag hvc1 -r 60 movie-webm_0.75.mov

アルファチャネルの品質とファイルサイズの関係は下記になった。

BuildError

実際に画質を確認して、納得できるパラメータを選定することになる。

後は、Swift コードで下記に用に view の layer で動画を再生すればよい。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import AVFoundation
import UIKit

class ViewController: UIViewController {

var player: AVPlayer!

var overlayerView: UIView!

var label: UILabel!

override func viewDidLoad() {
super.viewDidLoad()

self.label = UILabel()
self.label.text = """
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
"""
self.label.numberOfLines = 0
self.label.lineBreakMode = .byWordWrapping
self.label.translatesAutoresizingMaskIntoConstraints = false

self.view.addSubview(self.label)

NSLayoutConstraint.activate([
self.label.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 16),
self.label.leadingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leadingAnchor, constant: 16),
self.label.trailingAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.trailingAnchor, constant: -16),
self.label.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor, constant: -16)
])

// Do any additional setup after loading the view.
let path = Bundle.main.path(forResource: "movie-webm_1.00", ofType: "mov")!
self.player = AVPlayer(url: URL(fileURLWithPath: path))
let playerLayer = AVPlayerLayer(player: self.player)
playerLayer.frame = self.view.bounds
playerLayer.videoGravity = .resizeAspect
playerLayer.zPosition = 1
// auto repeat
NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: self.player.currentItem, queue: .main) { [weak self] _ in
self?.player?.seek(to: CMTime.zero)
self?.player?.play()
}
self.view.layer.insertSublayer(playerLayer, at: 0)

self.player.play()
}

}

これでOK…とはいかない。

How to happend?

原因が不明だが、先の変換スクリプトで作成される動画ファイルは Windows 上では再生できるが、 MacOS や iOS 上では再生できないファイルになってしまう。

BuildError

ただ、同じ変換元の WebM 動画を使用し、同じスクリプトを実行してもこの現象が再現しない環境もある。
具体的には

再生できる 再生できない
OS macOS Sonoma macOS Sequoia
ffmpeg 7.0 7.1.0

というのがわかっているところ。

では、Sequoia で ffmpeg のバージョンを下げれば、と思ったが依存パッケージが複雑過ぎて環境が壊れてしまってどうにもならなかった。
なので代替策として、静止画から Apple ProRes 動画を作成し、ffmpeg 以外から HECV 動画に変換するという方式を取る。
まず、下記のスクリプトを実行で Apple ProRes 動画を作成する。
-bits_per_mb で動画のビットレートを 200 から 8000 の範囲で指定できる。

1
2
3
$ mkdir tmp
$ ffmpeg -vcodec libvpx-vp9 -i movie-webm.webm -pix_fmt rgba tmp/image_%04d.png
$ ffmpeg -r 60 -i tmp/image_%04d.png -c:v prores_ks -profile:v 5 -bits_per_mb 8000 -pix_fmt yuva444p10le -r 60 movie-webm_prores_8000.mov

そして、finder 上から動画を選択しメニューから 選択したビデオファイルをエンコード を選択。

BuildError

メディアをエンコード ダイアログで、 HEVC 形式を選択し、 透明度を保持 にチェック、 続行 ボタンを押下。

BuildError

これによりアルファチャネル付きの HEVC 動画ファイルが出力される。
ただし、先の -bits_per_mb に関係なく、出力される動画ファイルのサイズに差はなく、かつ -alpha_quality を最大にしたものよりも大きくなってしまう。