0

I want to compress a depth map that has 16 bits of information per pixel. In general, such depth maps can be stored in different ways, e.g. p016le, gray16le, yuv420p16le, yuv444p16le, ... but for simplicity, let's assume the depth map is a yuv420p16le (where the y-channel contains the depth).

For some reason when encoding with hevc_nvenc (I use an NVIDIA GTX 1660 Ti GPU), ffmpeg (the command line tool) changes the pixel format to a 10 or 12 bit variant (p010le, gray12le, yuv420p10le, yuv444p12le, ...), but I would like to keep the full 16 bits, since this affects the quality of the depth stored.

For example:

ffmpeg.exe -s:v 1920x1080 -r 30 -pix_fmt yuv420p16le -i depth_yuv420p16le.yuv -c:v hevc_nvenc -pix_fmt yuv444p16le output.mp4

If I use ffprobe on the output.mp4, it tells me that the underlying pixel format is actually yuv444p10le. (Decoding and looking at the raw pixel data, I can confirm that the precision has decreased from 16 bits to 10 bits).

I hope 16 bit compression is possible, since according to

ffmpeg -h encoder=hevc_nvenc

the supported pixel formats are:

hevc_nvenc: yuv420p nv12 p010le yuv444p p016le yuv444p16le bgr0 rgb0 cuda d3d11

But p016le results in a p010le output, and yuv444p16le in yuv444p10le.

Does anyone know where the problem could lie? Should I re-install ffmpeg (version 4.3.2-2021-02-27-essentials_build-www.gyan.dev)? Is it because of Windows 10 having limited encoding/decoding capabilities? Will buying the HEVC Video Extensions help solve this problem?

Additional info: using libx256 does not look like it will work for this purpose, since the supported pixel formats are:

libx256 : yuv420p yuvj420p yuv422p yuvj422p yuv444p yuvj444p gbrp yuv420p10le yuv422p10le yuv444p10le gbrp10le yuv420p12le yuv422p12le yuv444p12le gbrp12le gray gray10le gray12le

Any help would be greatly appreciated.

Jl arto
  • 1
  • 1
  • 1
    According to [Wikipedia](https://en.wikipedia.org/wiki/High_Efficiency_Video_Coding#Profiles), only the "Main Intra" profile supports up to 16 bit depth (Intra means still-like pictures encoding). Searching Google for an encoder that supports the feature gives no results. `hevc_nvenc` uses hardware accelerated encoder, that maxed at 10 bits depth. – Rotem Aug 26 '21 at 20:23
  • I suppose your best option is using motion JPEG2000 codec. Example: `ffmpeg -y -s:v 1920x1080 -r 30 -pix_fmt yuv420p16le -i depth_yuv420p16le.yuv -c:v libopenjpeg -compression_level 10 -pix_fmt yuv444p16le output.mp4` – Rotem Aug 26 '21 at 20:37
  • Thank you @Rotem. As Wikipedia shows, HEVC has a Main 4:4:4 16 Intra mode that would be perfect, but I cannot find a way to force ffmpeg to use it? If I use something like `ffmpeg -s:v 1920x1080 -r 30 -pix_fmt yuv420p16le -i depth_yuv420p16le.yuv -c:v libx265 -x265-params lossless=1:keyint=1 -pix_fmt yuv420p16le output.mp4` , the output pixel format defaults to `yuv420p12le` . The JPEG2000 codec is a good suggestion for anyone with the same question as me. However, my goal is to decode the depth map on the GPU (hardware accelerated) using LibAV and CUDA. For now, I'll make do with 12 bit. – Jl arto Aug 27 '21 at 10:10

1 Answers1

0

I was attempting to encode 16-bit per channel RGB (48 bits per pixel) .exr frames into whatever video format supported it, and through trial & error I came to the conclusion that only the ffv1 codec supports this, using the gbrp16le or the yuv420p16le pixel formats and the .mkv container. Here are the commands I used:

ffmpeg -i {INPUT} -pix_fmt gbrp16le -c:v ffv1 -level 3 -coder 1 -context 1 -g 1 {OUTPUT.mkv}

ffmpeg -i {INPUT} -pix_fmt yuv420p16le -c:v ffv1 -level 3 -coder 1 -context 1 -g 1 {OUTPUT.mkv}

I can confirm that these formats indeed preserved the 16-bit info, as I decoded them back to .exr and examined the raw bytes.

I hope this helps!