AVIFを試す

 H.264ことAVC(Advanced Video Coding)の後継として開発された、H.265ことHEVC(High Efficiency Video Coding)を静止画に転用したHEIF(High Efficiency Image File Format)がiPhone 7で採用されて以降、徐々にサポートするソフトウェアが増えてきています。が、広く普及しているとは言い難い状況でしょう。これは、H.265を使用するにあたり必要なライセンス費用が高額であったり、パテントホルダーが複数団体に分かれていたりすることがその一因とされています。
 これに対して、ロイヤリティフリーな映像コーデックとして、The Alliance for Open Mediaによって開発が進められているAV1コーデックがあります。そして、AV1を静止画用に転用したAVIF(AV1 Image File Format)が今年2月にリリースされています。
AV1 Image File Format (AVIF)

 現状ではAV1自体が開発途上にあるため、HEIF以上にサポートするソフトウェアが少ないAVIFですが、生成することは可能なようですので、実際に試してみました。
 

AVIFの作り方

 現状では主要な画像/映像処理ソフトウェアはプロプライエタリだろうとオープンソースだろうとAVIFに対応していません。例えば、PhotoshopImageMagickffmpegも対応していません。

使用ツール

 AVIFを作ることに特化したツールは存在するようですが、汎用性のないツールは個人的に好みではないため、できるだけ一般的なソフトウェアを組み合わせてAVIFを作成してみようと思い、試行錯誤しました。結果、以下のツール群で生成することが可能ですので、できるだけ最新版をご用意ください*1

Software Purpose Mandatory
ffmpeg (with libaom-av1) AV1 encode Yes
mp4box store AV1 bitstream into AVIF file Yes
ImageMagick measure PSNR No
ExifTool Write metadata to AVIF No

処理フロー

 大まかに、以下の流れです。エンコードとAVIF変換までは必須で、後はそれぞれオプショナルと理解して問題ありません。

  1. エンコード
    1. libaom-av1を有効化したffmpegで画像をAV1でエンコードし、MP4に出力
  2. AVIF変換
    1. MP4からAV1 bitstreamを抽出し、AVIFに出力
  3. 画質検証
    1. ffmpegでMP4からPNGにデコード
    2. ImageMagickで元画像とデコードしたPNGを比較、PSNRを測定
  4. メタデータ複製
    1. ExifToolで元画像のメタデータをAVIFに複製
エンコード

 以下のようなコマンドで、INFILEをAV1でエンコードし、OUTFILE.mp4に記録します。
 CRFVALUEには0~63の値を指定します。値が小さいほど高画質・大ファイルサイズ、値が大きいほど低画質・小ファイルサイズとなります。
 ffmpegを使い慣れている方には説明不要かと思いますが、やっていることはAV1でエンコードされた1フレームだけの映像を生成しているだけです。そもそも、AVIFとはAV1のIフレーム圧縮を転用しているだけですので。

ffmpeg -r 1 -i INFILE -c:v libaom-av1 -g 1 -frames 1 -crf CRFVALUE -b:v 0 -an -strict experimental -y OUTFILE.mp4
AVIF変換

 以下のようなコマンドで、OUTFILE.mp4をmp4boxを使用してOUTFILE.avifに変換します。
 OUTFILE.mp4は先述の通り生成していれば、目的の1フレームしかありませんが、それは先頭0秒目に該当しますので、それを抽出してAVIFに記録します。

mp4box -add-image OUTFILE.mp4:time=0 -brand avif OUTFILE.avif

 単にAVIFに変換したいだけであればここまでで完了ですが、以下の処理で変換されたAVIFの画質の検証を行うことができます。

画質検証

 以下のようなコマンドで、ffmpegを使用してAV1エンコードされたMP4からPNGにデコードし、ImageMagickでオリジナル画像と比較してPSNRを測定することができます。

ffmpeg -i OUTFILE.mp4 DECODE.png
compare -metric PSNR INFILE DECODE.png nul

 さらに、デジタルカメラで撮影した画像のEXIFデータのように、オリジナル画像に撮影日時やF値シャッタースピードのようなメタデータが記録されているならば、以下の処理でメタデータを複製することもできます。

メタデータ複製

 以下のようなコマンドで、AVIFにメタデータを複製することができます。

exiftool -overwrite_original -TagsFromFile INFILE OUTFILE.avif
自動処理する例

 1ファイルずつ上記処理を行うのは面倒なので自動化しましょう。
 Windows環境を対象としてバッチファイル化し、以下の内容をavifenc.batとして保存しておくと便利です。前提として、ffmpeg、mp4box、ImageMagick、ExifToolの各ランタイムにPATHが通っている必要があります。

@Echo off
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM Check args
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
IF "%1" equ "" GOTO ERR_ARG
IF "%2" equ "" SET CRF=20
IF NOT EXIST "%1" GOTO ERR_NO_INPUT_FILE


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM Definition
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
SET INFILE=%1
SET CRF=%2
SET WORKFILE=~tmp_%~n1.mp4
SET OUTFILE=%~n1.avif
SET DECFILE=~tmp_%~n1.png
SET PIX_FMT=yuv444p


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM Validate
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
IF EXIST %OUTFILE% GOTO ERR_OUTFILE_EXISTS


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM Main process
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM Encode single image by AV1 into MP4 container
Echo %DATE% %TIME% AV1 Encoding start, please be patient...
ffmpeg -hide_banner -r 1 -i %INFILE% -c:v libaom-av1 -pix_fmt %PIX_FMT% -g 1 -frames 1 -crf %CRF% -b:v 0 -an -strict experimental -y %WORKFILE% >nul 2>&1
Echo %DATE% %TIME% AV1 Encoding end.

REM Generate avif file from MP4
Echo %DATE% %TIME% Container conversion start...
mp4box -quiet -add-image %WORKFILE%:time=0 -brand avif %OUTFILE% >nul 2>&1
Echo %DATE% %TIME% Container conversion end.

REM Measure PSNR
ffmpeg -hide_banner -i %WORKFILE% -y %DECFILE% >nul 2>&1
Echo PSNR of %OUTFILE% (AV1 CRF:%CRF%) against %INFILE%:
compare -metric PSNR %INFILE% %DECFILE% nul 2>&1
Echo;

REM Copy metadata
exiftool -overwrite_original -TagsFromFile %INFILE% %OUTFILE%

REM Purge workfiles
del %WORKFILE%
del %DECFILE%
exit /b


::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
REM Error output
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:ERR_ARG
echo Usage: %0 INFILE CRF
echo CRF: 0-63(default 0), Lower values mean better quality and greater file size.
exit /b

:ERR_NO_INPUT_FILE
echo ERROR: %INFILE% not found.
exit /b

:ERR_OUTFILE_EXISTS
echo ERROR: %OUTFILE% already exists.
exit /b

 使い方は、以下のように処理対象ファイル名を第1引数に指定し、CRFを第2引数に指定して実行するだけです(CRFはデフォルト20で省略可能)。すると、処理対象ファイル名の拡張子がavifの出力ファイルが得られます。

avifenc 処理対象ファイル名 CRF

 

検証

 AV1はロイヤリティフリーなだけではなく、H.265(HEVC)よりも高圧縮率または高画質であることが訴求されています。一方で、エンコード処理が激重なことも知られています。ここでは、H.265(HEVC)との直接の比較はしませんが、パフォーマンスと画質について検証してみます。

検証環境

CPU
Intel Core i5-4300U 1.9GHz (~2.5GHz)
Memory
12GB
OS
Windows 10 Pro 1903
ffmpeg
ffmpeg version 4.2

データパターン

 以下の2つの画像データを基に検証を行いました。

入力データ1(PNG)
Resolution:1024x768, (approx. 0.8MP), Bit depth: 24bit/pixel, Format: PNG
Input data 1
入力データ2(JPEG)
Resolution:683x1024 (approx. 0.7MP), Bit depth: 24bit/pixel, Format: JPEG
Input data 2

処理パフォーマンス

 ffmpegによるlibaom-av1コーデックでのエンコード時間を測定します。

  • 入力データ1の場合

Encode speed of Input data1
 CRF0~CRF63まで順次エンコードを実施すると、所要時間は概ね綺麗な変化をしました。CRFが小さい(=高画質)ほど遅く、CRFが大きい(=低画質)ほど高速となっています。

  • 入力データ2の場合

Encode speed of Input data2
 (CRF0~2を除き、)CRF28をピークとした山なり形状となり、入力データ1とは明らかに異なる傾向となりました。

画質・出力ファイルサイズ

 AVIFファイルのサイズに加え、入力データとAV1エンコード後の画像をPNGにデコードした結果のPSNRを測定して画質評価の指標とします。
 なお、PSNRは値だけ見てもどのような画質か想像しにくいと思いますが、以下の投稿でJPEGエンコーダについても同様の評価を行っています。
wave.hatenablog.com
 Photoshopもlibjpegも最高画質でJPEG出力時にPSNR≒55となります。主観ですがざっくりと、PSNR>50なら閲覧時に違和感を感じることは通常ありませんし、PSNR>40も普通に実用的に閲覧できる画質と感じます。

  • 入力データ1の場合

Filesize and PSNR of Input data1

  • 入力データ2の場合

Filesize and PSNR of Input data2
 入力データ1,2共にCRF=20付近が閲覧に必要十分な画質と、コンパクトなファイルサイズを兼ね備えていると言えるのではないでしょうか。

画質の補足

 JPEGの場合は圧縮率を高めるとブロックノイズが酷いことになりますが、AV1の場合はJPEGとは異なる劣化を示します。主観ですが、特にエッジ周りの破綻が目立つとともに、微妙なグラデーション領域にバンディングノイズが現れてくるのが視認できます。
 入力データ2を各CRFでエンコードした結果をピクセル等倍でクロップして、GIFアニメーション化したものが以下になります。GIF化に伴う減色処理などに伴い、AV1エンコード起因ではないノイズも含まれてしまいますが、AV1のCRF設定値によってどのように画質が劣化するのかのイメージは掴めると思います。
AV1 Image quality degrade in each CRF
 

まとめ

雑感

 互換性について、今回生成したAVIFファイルは、
avif.js demo
 で正常に表示が可能なことを確認できています。一方、
AV1 Video Extension (Beta) を入手 - Microsoft Store ja-JP
 を導入してもWindows 10環境では開けないことを確認しています。
 AVIF自体のフォーマットは固まっていても、AV1自体が開発途上にあるため現状では時期早々で致し方ないのかなという気がします。

 パフォーマンスについて、前掲のグラフの通り概ね10数秒~数10秒でエンコードできています。が、インプットデータは1MPにも満たない小さな画像1枚です。これが、約2MPのFullHDや8MPの4K解像度となったら、所要時間は伸びます(単純にピクセル数に比例して伸びるのかは要検証)。そもそも、AV1は映像のエンコードを目的としているわけですが、30fpsなら映像の長さ1秒あたり30枚をエンコードする必要があり、1分なら1800枚です。IフレームとPフレームでのエンコード時間の差異なども考慮する必要はありますが、普通のPCでのソフトウェアエンコードは現状では絶望的な遅さと考えて問題ありません(H.264/H.265映像のAV1へのトランスコード品質の検証などを実施したいのですが、本投稿でAVIFの検証に留めているのは、この絶望的に遅い所要時間の長さによるものです)。
 このため、intel QSV、AMD AMF、nVidia NVENC或いはQualcomm Snapdragonに集積されているようなハードウェアエンコーダでAV1に対応した製品が出てくるか、マルチスレッドに最適化したうえで劇的なソフトウェアアルゴリズムの改善が為されたりしないと普及しないように思えます。
 ちなみにAV1でエンコードされた1フレームだけ収めたMP4の再生や、前述のブラウザでのAVIFの表示など、デコードについては特にストレスを感じずに今のPCでもできています(静止画ではなく動画になるとまた違ってくると思いますが)。
 



以上。

*1:古いバージョンでは一部の機能が対応していなかったりします。