H.264 と HEVC のデコード(VK_KHR_video_decode_h264/h265)は
レガシーコーデックをカバーする。AV1(VK_KHR_video_decode_av1)は
モダンなものだ。YouTube/Netflix が配信しているコーデックで、その
8Kストリームはソフトウェアデコーダーを窒息させる。Vulkan 経路は
H.264 と同じパターンだ。ビデオセッション、DPB、
vkCmdDecodeVideoKHR。AV1 固有のパラメータは VkVideoDecodeAV1*
構造体を通して配管される。
セッションセットアップ
session.cpp
// コーデック固有のプロファイル + ケーパビリティ:
vk::VideoDecodeAV1ProfileInfoKHR av1prof{};
av1prof.stdProfile = STD_VIDEO_AV1_PROFILE_MAIN; // または _HIGH/_PROFESSIONAL
av1prof.filmGrainSupport = VK_FALSE; // フィルムグレイン合成を
// GPU で?高コスト。
vk::VideoProfileInfoKHR prof{};
prof.pNext = &av1prof;
prof.videoCodecOperation =
vk::VideoCodecOperationFlagBitsKHR::eDecodeAV1;
auto caps = phys.getVideoCapabilitiesKHR(prof);
// caps.maxDpbSlots, caps.maxActiveReferencePictures,
// caps.maxCodedExtent, …
vk::VideoSessionCreateInfoKHR vs{};
vs.queueFamilyIndex = decQueue; // eVideoDecodeKHR を持つキュー
vs.pVideoProfile = &prof;
vs.pictureFormat = vk::Format::eG8B8R82Plane420Unorm;
vs.referencePictureFormat = vs.pictureFormat;
vs.maxDpbSlots = caps.maxDpbSlots;
vs.maxActiveReferencePictures = caps.maxActiveReferencePictures;
auto sess = dev.createVideoSessionKHR(vs);フレームのデコード
decode.cpp
// AV1 のフレームパラメータは STD ヘッダーから来る
// (vulkan_video_codec_av1std.h — StdVideoAV1SequenceHeader、…):
vk::VideoDecodeAV1PictureInfoKHR pic{};
pic.pStdPictureInfo = &stdPic; // パース済みフレームヘッダー
pic.pNext = nullptr;
pic.pReferenceNameSlotIndices… // どの DPB スロットが参照か
vk::VideoDecodeInfoKHR dec{};
dec.pNext = &pic;
dec.srcBuffer = bitstreamBuf; // OBU フレームデータ
dec.srcBufferOffset = off;
dec.srcBufferRange = len;
dec.dstPictureResource = {imgView, eVideoDecodeDstKHR};
dec.referenceSlotCount = n;
dec.pReferenceSlots = refs; // VkVideoReferenceSlotInfoKHR
cmd.beginVideoCodingKHR(begin);
cmd.decodeVideoKHR(dec); // 本命の呼び出し
cmd.endVideoCodingKHR({});H.264 との違い
diffs.txt
セグメンテーションマップ — AV1 にはセグメントごとのフィーチャーフラグ
がある。デコーダーがそれを出力する。
caps.needsExtraSourceImage?/セグメント
マップを確認
フィルムグレイン — AV1 の代名詞的機能:デコード後に適用される
合成グレイン。filmGrainSupport=false =
デコーダーはグレインをオフのまま。
true = GPU がやる(追加パス)
タイル/ストリップデコード — AV1 のタイルモデルはデコードコマンドの
スライス/セグメント分割へのマップが異なる
フレームヘッダーパース — OBU ヘッダーは依然として CPU 側でパースし、
StdVideoAV1SequenceHeader/FrameHeader を渡す実用的な道 — FFmpeg に任せる
ffmpeg.sh
# FFmpeg ≥7 は hwcontext_vulkan デコードで AV1 を公開:
ffmpeg -init_hw_device vulkan=vk0 -hwaccel vulkan \
-hwaccel_output_format vulkan -i in.av1.webm -f null -
# → 完全に GPU 上。フレームは AV_PIX_FMT_VULKAN の VkImage として届くAVVkFrame が VkImage を直接渡す仕組みは hwcontext_vulkan の
記事を参照。同じ配管でコーデック非依存だ。
実践的なルール
- AV1 にはデコード対応キューが必要だ。
QueueFlagBitsKHR::eVideoDecodeKHRとeDecodeAV1を指定したvkGetPhysicalDeviceVideoCapabilitiesKHRを確認する。一部の ドライバーではサポートが遅れて入った。 - フィルムグレイン(
filmGrainSupport)が高コストな部分だ。 デコード後のソフトウェアグレインパスの方がドライバーに頼むより 安いことが多い。 - AV1 の参照モデル(8つの参照フレーム、show_existing_frame の技)は、
AV1 の
maxActiveReferencePicturesが H.264 より大きいことを 意味する。2をハードコードしない。 - セッションパラメータ(
VkVideoDecodeAV1SessionParametersCreateInfoKHR) はシーケンスヘッダーを運ぶ。OBU を自分でパースするか FFmpeg のav1パーサーを使う。 - 実際の使用には
hwcontext_vulkanと組み合わせる。AV1 デコード配管を 手で実装するのは数日の作業だ。FFmpeg の hwaccel がすでに解決している。
この記事が役に立った場合は、TechOverflow での新しい記事の調査と公開を支援するため、「Buy Me a Coffee」でのご支援、または PayPal 経由でのご寄付をご検討ください