Converting DCPs to ProRes: Banding in dark areas

Anything and everything to do with DCP-o-matic.
farbenblind
Posts: 4
Joined: Wed Apr 23, 2025 6:59 pm

Converting DCPs to ProRes: Banding in dark areas

Post by farbenblind »

dear dcp-o-matic community,

i hope this message does not look too pedantic, i just want to present what i
learned in the last weeks when trying to convert DCPs to movs.

this all stems from problems i've seen with real life dcp, but i can not share
material from those dcps, that's why i created an artificial image to
demonstrate the same problem. i could see similar effects with the dcps i handled.

preparation: generate a dcp with dcp-o-matic

generate a test image as 16bit png:
it shows a color gradient in 1024 steps from black to white.
below three other gradients are generated from black to dark and from black to
even darker. only the first black to white gradient is used to generate the
graphs below, the other gradients are provided for visual inspection.

Code: Select all

from wand.image import Image
from wand.drawing import Drawing
from wand.color import Color

with Drawing() as draw:
    c = 0
    for x in range(0, 1025):
        c = x * 2**6
        if x == 1024:
            c = 2**16 - 1
        print(f"{c:0>4x}")
        for y in range(0, 100):
            draw.fill_color = Color(f"#{c:0>4x}{c:0>4x}{c:0>4x}")
            draw.point(x, y)

    for y_offset, m in enumerate([8, 4, 2, 1], 1):
        for x in range(0, 1025):
            for y in range(100):
                c = x * m
                draw.fill_color = Color(f"#{c:0>4x}{c:0>4x}{c:0>4x}")
                draw.point(x, y + y_offset * 100)

    with Image(width=1998, height=1080, depth=64, background=Color("gray50")) as image:
        draw(image)
        image.format = "png"
        image.save(filename="PNG64:generated.png")
(see next post for the image, as i can only attach three images)

load this generated png into dcp-o-matic and generate a dcp

generate a ProRes mov from this DCP using dcp-o-matic

load the dcp into dcp-o-matic and generate a prores mov from it.

when i open this generated mov with mpv, the additional black to gray gradients
already show artifacts clearly visible on my not calibrated monitor.

to further inspect the gradient i'm extracting a single frame from the video using ffmpeg:

Code: Select all

ffmpeg -i *.mov -vf "select=eq(n\,4)" -vframes 1 frame-4.png
dom-frame-4.png
according to gimp this is a 16 bit png.

this png is then inspected using another python script

Code: Select all

import argparse

from wand.image import Image
from wand.display import display


def load(filename):
    with Image(filename=filename) as img:
        for x in range(1025):
            c = img[x, 0]
            # red, green, blue are float values between 0 and 1 so we have to
            # convert them back to the 16 bit values
            gray = ((c.red + c.green + c.blue) / 3) * (2**16 - 1)
            print("{}, {:10.2f}".format(x * 2**6, gray))


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("filename")
    args = parser.parse_args()
    load(args.filename)


if __name__ == "__main__":
    main()
and then plotted using gnuplot

Code: Select all

#!/usr/bin/gnuplot

reset

set border 3 back 
set tics nomirror 8192

set terminal pngcairo size 1920, 1080
set output 'plot.png'

set object 1 rectangle from screen 0,0 to screen 1,1 fillcolor rgb "#ffffff" behind

set style line 1 linecolor rgb '#0060ad' linetype 1 linewidth 2 pointtype 7 pointsize 0

set rmargin 10

plot '../final/dom-frame-4.csv' title 'dom' at end with line linecolor rgb '#006600' linewidth 1, \
     '../final/generated.csv' title '' at end with line linecolor rgb '#000000' linewidth 1
dom.png
(the "original" line is generated using the same python code but with the
generated.png image used as input for the DCP)

this shows that there are some modifications to the dark areas of the image,
and that there are artifacts in the curve. the pattern is in line of what i can
see on my monitor.

generate a ProRes mov from the DCP using ffmpeg and libplacebo

you need to use a very new libplacebo to see the same results, older versions
had a bug that show a blue tint. i'm using libplacebo compiled from git commit
2bd627f823ba1cedbc51a0ee6eb7a9fb433d912e for this demo.

Code: Select all

ffmpeg -i j2c_df390784-f932-437c-a7af-018d3cf21a25.mxf -vframes 1 -filter_complex "select=eq(n\,4),libplacebo=format=yuv444p10le:colorspace=bt709:color_primaries=bt709:color_trc=bt709:range=pc" -y libplacebo-frame-4.png
no artifacts are visible (see next post, can only add three images per post)

and the graph shows that the line of the gradient is closer to the original,
although some small artifacts are still visible.
libplacebo.png
conclusion

we converted a 16 bit sRGB image into the XYZ color space for the DCP and then
convert it back to yuv444p12 and then back to a png. as far as i understand
this could work perfectly for the concrete example, as we know that we only
expect sRGB values in the XYZ color space in the DCP, but for the general
solution the ProRes/YUV can not reproduce the colors stored in DCP/XYZ, so some
color distortion is expected. therefor i'm kind of impressed by the result of
libplacebo.

from the visual appearance with my (not calibrated) monitor i would prefer the
color adaption used by libplacebo, also the generated graphs are in favour of
libplacebo.

maybe vanilla ffmpeg can also be tuned in a way that it provides similar
results as libplacebo, but i stopped looking when i was satisfied with the
result.

maybe this post can help improve dcp-o-matic, or it can improve my
understanding of colorspaces, ffmpeg and dcps. please let me know if there is a
flaw in my analysis.

all the best,
benedikt
You do not have the required permissions to view the files attached to this post.
farbenblind
Posts: 4
Joined: Wed Apr 23, 2025 6:59 pm

Re: Converting DCPs to ProRes: Banding in dark areas

Post by farbenblind »

this is the original image used to generate a dcp from:
generated.png
this is the result of loading the above image into dcp-o-matic, generating a dcp, converting this dcp with ffmpeg and libplacebo to a ProRes mov, and then using ffmpeg to extract a single frame from this mov:
libplacebo-frame-4.png
You do not have the required permissions to view the files attached to this post.
carl
Site Admin
Posts: 2759
Joined: Thu Nov 14, 2013 2:53 pm

Re: Converting DCPs to ProRes: Banding in dark areas

Post by carl »

Thanks for the notes. I just wanted to say that I will look at this as soon as I can, but I've been a bit busy.