Skip to content

cudacodec::VideoReader Add python binding for videoFullRangeFlag to VideoReaderInitParams #3982

@alex-service-ml

Description

@alex-service-ml

Recently, I have been exploring video processing on the GPU and wish to implement my own gamma correction function. However, the results look awful and I believe it's related to the python binding for cudacodec::VideoReader not supporting videoFullRangeFlag

Test Scenarios

  • Input video: h264, y420p(pc), bt.709 colorspace
  • Output video: same, but with an mp4 container and custom gamma correction
  • All cases are using FFmpeg as the backend
  • gamma_lut is just a reimplementation of FFmpeg's create_lut and returns a cv2.cuda.createLookupTable()

The following will produce a poorly-corrected video:

def pure_cv2_cuda(local_filename: str, output_filename: str = None, size=(1640, 1232)):
    read_params = cv2.cudacodec.VideoReaderInitParams()
    read_params.minNumDecodeSurfaces = 4
    read_params.targetSz = size
    
    reader = cv2.cudacodec.createVideoReader(
        local_filename,
        sourceParams=[],
        params=read_params,
    )
    reader.set(colorFormat=cv2.cudacodec.BGR, bitDepth=cv2.CV_8UC3)

    # Initialize VideoWriter
    params = cv2.cudacodec.EncoderParams()
    params.targetQuality = 10
    params.videoFullRangeFlag = True
    writer = cv2.cudacodec.createVideoWriter(
        f"data/{output_filename}",
        size,
        cv2.cudacodec.H264,
        25,
        colorFormat=cv2.cudacodec.BGR,
        params=params,
    )

    input_frame = cv2.cuda.GpuMat(size, cv2.CV_8UC3)
    gamma_frame = cv2.cuda.GpuMat(size, cv2.CV_8UC3)
    gamma_table = gamma_lut(gamma=2.5, mode="cv2")

    while reader.nextFrame(input_frame)[0]:
        gamma_table.transform(input_frame, gamma_frame)
        writer.write(gamma_frame)
    writer.release()

However, the following scenario appears to work as intended:

def ffmpeg_to_cv2_cuda_using_gamma_table(local_filename: str, output_filename: str = None, size=(1640, 1232)):
    command = [
        "ffmpeg",
        "-hwaccel",
        "cuda",
        "-i",
        local_filename,
        "-pix_fmt",
        "bgr24",
        "-vf",
        "colorspace=all=bt709:iall=bt709:irange=pc:fast=1",
        # "eq=gamma=2.5",  # Using this instead of specifying colorspace and the gamma_lut also works
        "-f",
        "rawvideo",
        "pipe:",
    ]

    pipe = subprocess.Popen(
        command,
        stdout=subprocess.PIPE,
        stderr=subprocess.DEVNULL,
    )

    params = cv2.cudacodec.EncoderParams()
    params.targetQuality = 10
    writer = cv2.cudacodec.createVideoWriter(
        f"data/{output_filename}",
        size,
        cv2.cudacodec.H264,
        25,
        colorFormat=cv2.cudacodec.BGR,
        params=params,
    )

    gamma_table = gamma_lut(gamma=2.5)

    frame = np.zeros((size[1], size[0], 3), dtype=np.uint8)
    gpu_frame = cv2.cuda.GpuMat(size, cv2.CV_8UC3)
    output_frame = cv2.cuda.GpuMat(size, cv2.CV_8UC3)
    while pipe.stdout.readinto(frame):  # returns bytes_read, breaks on 0 bytes
        gpu_frame.upload(frame)
        gamma_table.transform(gpu_frame, output_frame)
        writer.write(output_frame)
    writer.release()
    pipe.terminate()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions