Post 57. Post 49 8-bit H.264’ü NV12 plane’leri olarak import etmişti. Çoğu modern IP kamera ve HDR içerik bunun yerine HEVC Main10 sunar — P010 olarak paketlenmiş 10-bit luma/chroma. İyi haber: pipeline aynı — sadece DRM katman formatları ve Vulkan formatları değişir.
$ ./app --headless out.ppm
decoded 15 frames, 1280x720 hw=vaapi sw=p010le
layer0 fmt=R16 planes=1: off=0 pitch=2560
layer1 fmt=GR32 planes=1: off=1966080 pitch=2560
surface is P010 (10-bit) -> R16 + R16G16
wrote out.ppm
Example: VulkanExamples/p57_hevc
8-bit’e göre gerçekte ne değişir
VA-API mantıksal plane başına bir DRM katmanı export eder (Mesa/GBM’deki gibi tek bir multi-plane katman değil). Katman fourcc’si bit derinliğini söyler:
sw_format | layer0 (luma) | layer1 (UV) | VkImage formatları |
|---|---|---|---|
nv12 (8-bit) | DRM_FORMAT_R8 | DRM_FORMAT_GR88 | R8Unorm + R8G8Unorm |
p010le (10-bit) | DRM_FORMAT_R16 | DRM_FORMAT_GR1616 | R16Unorm + R16G16Unorm |
P010 her 10-bit örneği 16 bit içinde MSB-hizalı (bit 15..6) saklar.
R16Unorm olarak import etmek otomatik [0,1] normalize eder —
shader hiç değişmez:
float Y = texture(texY, vUV).r; // R16_UNORM, zaten [0,1]
vec2 UV = texture(texUV, vUV).rg; // R16G16_UNORM
vec3 yuv = vec3(Y, UV.x, UV.y) - vec3(0.0625, 0.5, 0.5);
vec3 rgb = clamp(mat3( 1.164, 1.164, 1.164,
0.000, -0.392, 2.017,
1.596, -0.813, 0.000) * yuv, 0.0, 1.0);Chroma image’ı hâlâ W/2 × H/2 — ama her texel artık 4 bayt (R16G16),
bu yüzden aynı piksel boyutlarında bile pitch NV12’ye kıyasla iki katına
çıkar.
Descriptor’dan otomatik tespit
auto* fctx = reinterpret_cast<AVHWFramesContext*>(
frame->hw_frames_ctx->data);
// fctx->sw_format == AV_PIX_FMT_P010 veya AV_PIX_FMT_NV12
// ya da doğrudan DRM descriptor'dan:
const bool is10 = desc->layers[0].format == DRM_FORMAT_R16;
const vk::Format fmtY = is10 ? vk::Format::eR16Unorm
: vk::Format::eR8Unorm;
const vk::Format fmtUV = is10 ? vk::Format::eR16G16Unorm
: vk::Format::eR8G8Unorm;frame->hw_frames_ctx (bir AVHWFramesContext*) sw_format‘ı — gerçek
surface yerleşimini — açığa çıkarır; AVFrame‘in kendisinin taşımadığı
FFmpeg sürümlerinde bile.
Test klibi
ffmpeg -f lavfi -i "testsrc2=size=1280x720:rate=30" -t 0.5 \
-c:v libx265 -pix_fmt yuv420p10le -preset medium -crf 22 \
-x265-params keyint=15 -f hevc test.h265Post 49’dan hâlâ geçerli tuzaklar
mapped->format = AV_PIX_FMT_DRM_PRIME—av_hwframe_map‘ten önce.arrayPitch/depthPitchsıfır değil, plane boyutu olmalı.max(req.size, offset + planeSize)ayırın — UV plane dma-buf içinde sıfır olmayan bir offset’te durur.eDeviceLocalistemeyin — dma-buf belleği host-visible GTT olabilir.- Aynı GPU: VA-API render node’u (
/dev/dri/renderD12x) Vulkan’ın seçtiği fiziksel cihaza ait olmalı. Vendor’lar arası bir modifier sessizce import olur ve çöp örnekler. - Modifier-tiled image’lar: yalnızca
eGeneral(veyaePresentSrcKHR) layout.
VA-API yoksa
10-bit yazılım decode yuv420p10le/p010le‘dir — sırasıyla LSB-hizalı
vs MSB-hizalı. p010le‘nin bir staging-buffer upload’u
R16Unorm/R16G16Unorm image’a aynı shader’la çalışır; sadece
kaynak-kopya döngüsü farklıdır. Bu bir kamera duvarının istediği
zarif-degradasyon yoludur: bir kez uyar, render’a devam et.