RomanArzumanyan / VALI

Video processing in Python
Apache License 2.0
21 stars 1 forks source link

P10 to RGB surface conversion? #25

Closed geheiligt closed 3 months ago

geheiligt commented 3 months ago

Hi, does VALI support 10bit decoding? The code below does work in VPF, but fails for P10 surfaces in VALI.

Is this not supported (yet)? Is there a better way to get a video frame to vRAM?

import PyNvCodec as nvc
gpu_id=0
nvDec=nvc.PyNvDecoder("video.MP4", gpu_id)
width = nvDec.Width()
hight = nvDec.Height()
video10bit=True
try:
    to_nv12 = nvc.PySurfaceConverter(width, hight, nvDec.Format(), nvc.PixelFormat.NV12, gpu_id)  
    to_yuv = nvc.PySurfaceConverter(width, hight, nvc.PixelFormat.NV12, nvc.PixelFormat.YUV420, gpu_id)
except ValueError:
    video10bit=False
    to_yuv = nvc.PySurfaceConverter(width, hight, nvc.PixelFormat.NV12, nvc.PixelFormat.YUV420, gpu_id)
to_rgb = nvc.PySurfaceConverter(width, hight, nvc.PixelFormat.YUV420, nvc.PixelFormat.RGB, gpu_id)
RomanArzumanyan commented 3 months ago

Hi @geheiligt

It should since VALI still share significant part of it's codebase with VPF. I assume it was broken at some point during the refactoring.

I'll repro on my side and will give you an update a bit later. Hopefully it shall be a quick-ish fix.

RomanArzumanyan commented 3 months ago

Hi @geheiligt

My apologies, it took a bit longer then I've expected. But the fix is ready. Please check the latest VALI v. 2.1.2. Locally I was able to decode 10 bit HEVC and convert it to 8 bit YUV420:

import PyNvCodec as nvc
import numpy as np

gpu_id=0

nvDec=nvc.PyNvDecoder(
    "/home/user/Videos/hdr_hevc_10bit.mp4", gpu_id)

width = nvDec.Width()
height = nvDec.Height()
format = nvDec.Format()

cc_ctx = nvc.ColorspaceConversionContext(
    nvc.ColorSpace.BT_709, nvc.ColorRange.MPEG)

to_nv12 = nvc.PySurfaceConverter(
    width, height, format, nvc.PixelFormat.NV12, gpu_id)  

to_yuv = nvc.PySurfaceConverter(
    width, height, to_nv12.Format(), nvc.PixelFormat.YUV420, gpu_id)

nvDwn = nvc.PySurfaceDownloader(
    width, height, to_yuv.Format(), gpu_id)

yuv420_frame = np.ndarray(dtype=np.uint8, shape=())
fout = open("sdr_hevc_8bit.yuv", "wb")
while True:
    surf, _ = nvDec.DecodeSingleSurface()
    if not surf or surf.Empty():
        break

    surf, _ = to_nv12.Execute(surf, cc_ctx)
    if not surf or surf.Empty():
        break

    surf, _ = to_yuv.Execute(surf, cc_ctx)
    if not surf or surf.Empty():
        break

    success = nvDwn.DownloadSingleSurface(surf, yuv420_frame)
    if not success:
        break

    fout.write(yuv420_frame)

fout.close()
geheiligt commented 3 months ago

Thanks, it works now.