Log in

View Full Version : Possible color/brightness bug in MPC-HC


nji
11th April 2024, 13:38
Recently I noticed a slightly different presentation of videos
compared to VirtualDub2 (VD2), Avidemux (ADM) and ffmpeg.

I tried to trace it down systematically, starting with simple notes.
Doing that, realisation slowly dawns that it is complex - the tools
for examination themselves can't be relied on.
Second I built a table... and finally ended with a graph with arbitrary
transitions between codec formats etc.

It turns out that
ADM and ffmpeg nearly always do identical.
MPC-HC was always too bright (viewing and screenshot, with all renderers):
about the same value (2,2,2).
VD2 (4 y/o) was inbetween.

MPC-HC 2.1.5 @ Win7-64 SP1

clsid
11th April 2024, 14:53
The bug isn't in the player.

I can not help you and I do not care.

Sunspark
11th April 2024, 17:15
You can say this in a different way, "I can not help you because it's upstream".

nji
11th April 2024, 18:05
@Sunspark: Thank you for translating. :)

May I ask you then, how this is meant, "not in the player but upstream"?

I understand it this way:
There are inputs to a program.
These inputs are done all about the same with other programs,
but not with the first one.

In this situation there is an indication the first program does something wrong, I might think. (?)

So I really don't understand why "not in the program, but upstream".
Now I'm really curious.

huhn
11th April 2024, 20:58
because it doesn't do anything of this.
decoding is done by ffmpeg and video renderer is done by the video renderer.

all video renderer are supposed to be to bright what does that even mean?

Emulgator
12th April 2024, 02:27
nji: Video Renderer -> Ausgabebereich 0-255

nji
12th April 2024, 09:49
Woops - beats me!

Some times ago I had a single brainwave on that (vanished instantely).
But (of course) I tested on several movies.
Is this only on "restricted type"...

But what does it mean concrete?

In practise MPC-HC shows the videos systematically brighter than all other tested apps.
This won't be just for me I might think...?

Can you drop some more thoughts on that please,
so I know where to look at?

And: Thank you! :)

EDIT:
It can't be just an (inconsistent) using of linear mapping unrestricted [0,255] to restricted [16,255],
as this wouldn't cause average +2, but +8...

huhn
12th April 2024, 15:26
it's 16-235 or 0-255.
this is 36 level and the max deference in this case is 20 with a minimum of 0.

now you want other to compare that to "all other tested apps" what ever that means? so let have a look:
VirtualDub2 (VD2), Avidemux (ADM) and ffmpeg.

none of these is a video player...

so i got vurtualdub2 load a file and no i doesn't care about colorspace HDR or what ever. so i got a different image...
bt 709 and still got a different image.
so i took bt 601 source and the result was the "same" ~90%...
knowing that 50% of all data is upscaled with a different chroma scaler i take that as the same.

so my current conclusion here is that virtualdub2 just uses one ycbcr to RGB formula for everything. and my best guess is 601 to RGB 709 full range.

there is nothing to look at anymore with the case of virtualdub2 it is not made to show something correctly because it is not a video player.

nji
12th April 2024, 16:37
Thank you very much for your valuable information.

As I'm not too deep into the media material, I wasn't aware about the details
(Exact values of restricted interval and bt-types...).

What I am aware of course is that ADM, VD2 are video editors in first place.
And ffmpeg... is about everything :)
But it shouldn't make any difference if you're watching or "watching by editing"
a video, when it is about different colors, don't you agree?

All should be (about) the same, when working correctly.
And a difference of about (2,2,2) is well perceivable, when you have a close look.
It matters.

I cannot assess the insides, but maybe VD2 isn't the best example to compare against.
Sadly it isn't developed anymore, since 4 years. To my experience with VD2 it is
well possible that it doesn't do right. ADM is more reliable, to my experience.

ADM and ffmpeg produce both about the same results (viewing, playing, screenshot,
you name it). Moreover the difference to MPC-HC is the largest - see my first post.
And ffmpeg might be about the reference.
It seems very unlikely it shouldn't handle video types correct.

I'm grateful for your help on that.
But I can't agree with your conclusion.
"There is something wrotten in the state of Denmark",
and the more complex situation because of bt-types and restricted intervals
by no means can justify the differences.

I don't want to blame anything/ anyone.
I'm just about to try generating correct results.
All is meant constructive.

clsid
12th April 2024, 17:06
VD2 and ADM both use FFmpeg...
And FFmpeg swscale is well known for its crappy quality colorspace conversion...

So you are actually comparing ONE against multiple renderers made by different people...

nji
12th April 2024, 17:35
VD2 and ADM both use FFmpeg...
And FFmpeg swscale is well known for its crappy quality colorspace conversion...

This is all new to me.

If this should be true... we have a horrible situation:

Many videos are treated by VD2, ADM and ffmpeg.
A source of worsening movies.

It's hard to believe that everybody accepts that.

huhn
12th April 2024, 20:57
What I am aware of course is that ADM, VD2 are video editors in first place.
And ffmpeg... is about everything :)
But it shouldn't make any difference if you're watching or "watching by editing"
a video, when it is about different colors, don't you agree?
no there is farm ore to this then this and for a video editor this doesn't have to be an issue it. it can be an issue.
All should be (about) the same, when working correctly.
And a difference of about (2,2,2) is well perceivable, when you have a close look.
It matters.
if you have an option to define the state of your display and the source has proper information yes else no impossible.

I cannot assess the insides, but maybe VD2 isn't the best example to compare against.
Sadly it isn't developed anymore, since 4 years. To my experience with VD2 it is
well possible that it doesn't do right. ADM is more reliable, to my experience.

because the preview is wrong doesn't mean the encode is.
if you use a bad conversation but at the end use the same inverse conversation you still have the "same" image.

ADM and ffmpeg produce both about the same results (viewing, playing, screenshot,
you name it). Moreover the difference to MPC-HC is the largest - see my first post.
And ffmpeg might be about the reference.
It seems very unlikely it shouldn't handle video types correct.
that's not even funny.
I'm grateful for your help on that.
But I can't agree with your conclusion.
"There is something wrotten in the state of Denmark",
and the more complex situation because of bt-types and restricted intervals
by no means can justify the differences.
madVR has been verified by calibrator and by people that write calibrator software. so yes that's pretty accurate.

I don't want to blame anything/ anyone.
I'm just about to try generating correct results.
All is meant constructive.
then why are you comparing a video editor with a video player?

the fat that multiply renderer according to you have the same output should tell you a lot.

poisondeathray
13th April 2024, 00:14
How do you know which one is "correct" ?

Use a known reference video, such as SMPTE bars . You have known YCbCr and their expected RGB values , so you can diagnose which of your software are not setup correctly .

MPCHC produces correct values for me. If you're not getting the correct expected values, there is something wrong with your setup - hardware, or configuration settings .

VDub2 uses Rec601 for the RGB conversion by default, unless input video colorimetry matrix is flagged => therefore it can be wrong .

Avidemux always produces the incorrect values. I've never seen it produce correct values.

ffmpeg can be correct if you use the correct flags . SWScale has improved and is fine for most standard conversions, with a few exceptions. But ZScale (zimg) is usually the better choice . If you don't use correct flags, obviously you get the wrong results .

huhn
13th April 2024, 02:36
it's called a colorimeter. that how you know.

You have known YCbCr and their expected RGB values
that's not a given sadly too.
you need to know the corresponding RGB values (which are dithered BTW. so good luck with that) for your target display colorspace.

madVR has an error of 0.3 level or something in relative % between limited and full range this ignores errors from linear light dithering stuff that's to high for me

poisondeathray
13th April 2024, 02:57
you need to know the corresponding RGB values (which are dithered BTW. so good luck with that) for your target display colorspace.


If you are using madVR, you can set the dithering options to none in the settings

huhn
13th April 2024, 03:33
which would be even more inaccurate.

poisondeathray
13th April 2024, 03:40
which would be even more inaccurate.

Dithering is less accurate for diagnostic tests on patterns such as color bars

huhn
13th April 2024, 07:35
and how do you put a combination of 219(220) level of luma on 255(256) level and how do you put 224(225) level of chroma on 255(256) levels at the same time without dithering?

as an example a bad IRE 30 file is a mix of 75 and 76 or 75.68 if it isn't dithered it is just 76 which is a massively bigger error.

Alexkral
13th April 2024, 07:57
Maybe just using integer values in the test patterns that with the conversion formulas should produce integer values (or very close to integer)?

huhn
13th April 2024, 08:43
that's why we dither they will not produce integer and not close to it too.

nji
13th April 2024, 11:36
Hopefully I'm not too impolite if I return to the initial question?
(To my observation MPC-HC shows all videos systematical too bright).

In a post above @poisondeathray asked how I do know what is correct.
Well, I tried to state that in my very first post already:
I DO NOT know.
I tried to find matchings that might provide plausibilities.

Quite obviously there are different experiences about the reliabilies
of the different apps and codecs.
To me it seems like a terrible confusion.
And saying that, this discussion wasn't of practical help for me.

To sum-up what I know:

Just recently I updated MPC-HC
(by de-installing the old version, cleaning up eventual remainings
in file system and registry, and re-installed the new version).
I didn't change anything at its default configuration.

My "graphic-system" is as simple as an Intel on-chip graphic.
I never touched the config either.

Concerning ffmpeg
I'm unable to assess its reliability.
But it is developed for about 25 years and wide spreaded.
It is used in a great majority of viewers and editors.
For me it is hard to believe that it should be "crappy" in any way.

Due to my comparison tests ADM matches to ffmpeg.

VD2 generates slightly brighter frames (1,1,1) compared to this.

MPC-HC adds another (1,1,1), which makes the difference noticeable.
(BTW I'm talking about systematically changes).

MPC-HC's renderers
Both users @huhn and @clsid assume that I doubt the correctness
of all the renderes, although they generate the same result.
Well, may I ask to read my very first post again?
I did the opposite, taking the independence of the renderers
as hint, that a possible bug isn't due to them.


The most plausible explanation for all that for me
(not having much experiences in it):

- ffmpeg will most probably be reliable
- so will ADM
- MPC-HC itself seems to have a bug (using/ driving ffmpeg, the renderers etc.)

I don't want to offend anyone by that.

My aim was just to help clearing up things,
and hopefully assist in revealing a bug.
All-in-all for a naive user like me an unsatisfying situation.

poisondeathray
13th April 2024, 15:18
It's just math. YCbCr <=> RGB equations. For any given YCbCr value there is an expected RGB value (given some assumptions eg. Rec709, full range sRGB).

A large region of solid color should be 1 RGB value [R,G,B]. Dithering adds error to the expected value. Dither will reduce the accuracy, because large solid regions now have added "noise" and are no longer a single RGB value - you now have fluctuations in pixel values. You expect some error for 8bit conversion (due to lower precision and rounding), but perfect values for 10bit YCbCr pipeline for 8bit RGB

e.g a solid 75% red bar would produce RGB[191,0,0] exactly in 8bit sRGB full range (e.g. a typical computer monitor) on every pixel in that region. The actual R value is 191.25 , but it's rounded down - you cannot display a 191.25 pixel value in 8bit. Dithering adds error, because you get fluctuating values like RGB [192,0,0] , RGB[191,0,0], RGB[192,0,1] - even when there is no color value in a channel , you can now get color due to dithering . The error added by dithering can be measured, because the expected end result is known on bars . Some dithering algorithms add more deviation , more error, some less. BU they all add error

Color bars like SMPTE bars are just one of many standarized battery of tests . The point is you need a starting reference to help diagnose problems - not some random videos which you have no idea what the values should actually be

huhn
13th April 2024, 18:09
My "graphic-system" is as simple as an Intel on-chip graphic.
I never touched the config either.
ohh no.
you know for EVR the GPU driver is in charge of most things including the messing up of images. but you said you tested them all and madVR avoids these issues.

MPC-HC's renderers
Both users @huhn and @clsid assume that I doubt the correctness
of all the renderes, although they generate the same result.
Well, may I ask to read my very first post again?
I did the opposite, taking the independence of the renderers
as hint, that a possible bug isn't due to them.
no you said they are to bright which means they are doing it wrong.
your words:
MPC-HC was always too bright (viewing and screenshot, with all renderers):
and you said all renderer so you tested madVR.

It's just math. YCbCr <=> RGB equations. For any given YCbCr value there is an expected RGB value (given some assumptions eg. Rec709, full range sRGB).
yes and that number is a float point number needing unlimited bit deep to be shown.

sRGb ahh sRGB ywah like any renderer here targets sRGB...

A large region of solid color should be 1 RGB value [R,G,B]. Dithering adds error to the expected value. Dither will reduce the accuracy, because large solid regions now have added "noise" and are no longer a single RGB value - you now have fluctuations in pixel values. You expect some error for 8bit conversion (due to lower precision and rounding), but perfect values for 10bit YCbCr pipeline for 8bit RGB
you can not dither an error that doesn't exist.
e.g a solid 75% red bar would produce RGB[191,0,0] exactly in 8bit sRGB full range (e.g. a typical computer monitor) on every pixel in that region. but video are not RGB and rarely if ever sRGB. The actual R value is 191.25 , but it's rounded down - you cannot display a 191.25 pixel value in 8bit. but dithering can Dithering adds error, because you get fluctuating values like RGB [192,0,0] , RGB[191,0,0], RGB[192,0,1] - even when there is no color value in a channel ,
depends on the algorithm and this is still RGB to RGB not a real use case you can now get color due to dithering . then use a proper dithering algorithm...

The error added by dithering can be measured, because the expected end result is known on bars . Some dithering algorithms add more deviation , more error, some less. BU they all add error
no they don't showing 191.25 as 191 is objectively wrong. and the example is also totally terrible because video codex don't store float point numbers for output...
Color bars like SMPTE bars are just one of many standarized battery of tests . The point is you need a starting reference to help diagnose problems - not some random videos which you have no idea what the values should actually be
and that's why dithering is forced for calibration so the pattern can be displayed accurately and the colorimeter is actually reading what is is supposed to read.

do you really think one can not look at the YCbCr values of a video frame?

a YCbCr -> RGB conversation is lossy in nature even at 32 bit per component.

poisondeathray
13th April 2024, 19:05
sRGb ahh sRGB ywah like any renderer here targets sRGB...


This is a starting point for analysis because nji mentioned vdub, avidemux - they are using 8bit sRGB . If he's saving a bmp or png , it's converted to 8bit sRGB


but video are not RGB and rarely if ever sRGB. but dithering can
depends on the algorithm and this is still RGB to RGB not a real use case then use a proper dithering algorithm...


Of course

YCbCr video is converted to RGB for display...

This is a real use case. SMPTE bars . The actual 8bit and 10bit YCbCr values are given in RP219... and from those known values, there are expected RGB values




no they don't showing 191.25 as 191 is objectively wrong. and the example is also totally terrible because video codex don't store float point numbers for output...


exactly - The expected value on a 8bit sRGB display for the 75% red bar is RGB 191 ,0,0 . Not some dithered values like RGB 192,0,1



do you really think one can not look at the YCbCr values of a video frame?


Of course you can - eg. you can use avspmod or vsedit color picker



a YCbCr -> RGB conversation is lossy in nature even at 32 bit per component.

No, it's lossless and reversible at float if done properly

ie. integer YCbCr <=> 32bit RGB <=> integer YCbCr

"Lossy" implies the round trip is not reversible, which of course is wrong

huhn
14th April 2024, 07:45
This is a starting point for analysis because nji mentioned vdub, avidemux - they are using 8bit sRGB . If he's saving a bmp or png , it's converted to 8bit sRGB
so we do a gamma conversion lossless too. this is getting better and better. and the lossless 4:2:0 to 4:4:4 upscale and the lossless chromaloc fix. these float point operation there is no way an error will build up.

Of course

YCbCr video is converted to RGB for display...

This is a real use case. SMPTE bars . The actual 8bit and 10bit YCbCr values are given in RP219... and from those known values, there are expected RGB values

ohh yes the analog smpte bars.
let's take the newer digital one using:
https://en.wikipedia.org/wiki/SMPTE_color_bars
and this calculator
https://res18h39.netlify.app/color


ohh no:
studio RGB 180-16-16
result ycbcr 50.87 108.78 211.87
let's not dither. time to round it. yes 51 109 212
wow perfect match let's press the thingy again ohh no 180.33 16.04 16.53
well we can still fix this did i said round before? i mean truncate what else...

there is no way ycbcr->RGB and RGB->ycbcr is lossy.


exactly - The expected value on a 8bit sRGB display for the 75% red bar is RGB 191 ,0,0 . Not some dithered values like RGB 192,0,1
yes and that's why it is 180-16-16 for 8 bit studio and 4 times that at 10 721-64-64 wait... it's like they used 180.25 to calculate that number so the 10 bit pattern is actually more red. calibration magic i guess. my colorimeter will actual show me a bigger number if i use 10 bit. this wouldn't have happen when i would have dithered from 75%.

and don't forget on an sRGB display so the pure gamma and sRGB transfer function are one and the same right?

No, it's lossless and reversible at float if done properly

ie. integer YCbCr <=> 32bit RGB <=> integer YCbCr

"Lossy" implies the round trip is not reversible, which of course is wrong
well it isn't reversible.
it's computer and float yes that's pretty lossy...
i guess it's just the calculator a top that is wrong.
and that 10 bit official sampte bars have a different red between 8 bit and 10 bit is just magic there is no way the 8 bit is already compromised by rounding.

poisondeathray
14th April 2024, 14:33
ohh no:
studio RGB 180-16-16
result ycbcr 50.87 108.78 211.87
let's not dither. time to round it. yes 51 109 212
wow perfect match let's press the thingy again ohh no 180.33 16.04 16.53
well we can still fix this did i said round before? i mean truncate what else...

there is no way ycbcr->RGB and RGB->ycbcr is lossy.

yes and that's why it is 180-16-16 for 8 bit studio and 4 times that at 10 721-64-64 wait... it's like they used 180.25 to calculate that number so the 10 bit pattern is actually more red. calibration magic i guess. my colorimeter will actual show me a bigger number if i use 10 bit. this wouldn't have happen when i would have dithered from 75%.

and don't forget on an sRGB display so the pure gamma and sRGB transfer function are one and the same right?

well it isn't reversible.
it's computer and float yes that's pretty lossy...
i guess it's just the calculator a top that is wrong.
and that 10 bit official sampte bars have a different red between 8 bit and 10 bit is just magic there is no way the 8 bit is already compromised by rounding.

integer YCbCr => RGB float => integet YCbCr is lossless if done correctly. That means no dithering or rounding for a lossless trip

You're going the wrong way, starting with 8bit RGB pattern. I'll post more info later, but to generate the proper YCbCr 8,10,12 bit test patterns, you start with RGB float, apply the equations . The HD SMPTE bar are in YCbCr, not RGB ; and the actual YCbCr values are listed in the document, but you can verify them by apply the equations to a a perfect test signal (e.g. 75% red would be [0.75,0,0] in float)

In integer YCbCr=> RGB integer , there are values greater than 255, or less than 0 produced (negative RGB) for 8bit. (Or greater than 1023 for 10bit etc....)

Those out of range values lie outside the RGB color cube. ie. there are some YCbCr values that produce invalid RGB numbers. On a normal 8bit or 10bit RGB display, those would be clipped to [0,255] , or [0,1023] respectively - that produces loss . Any rounding or dithering would produce loss as well

But float RGB for that intermediate step keeps those negative RGB values, and values greater than 1.0 on a [0.0, 1.0] scale. So the round trip from/to YCbCr integer is lossless if done properly. Float RGB is used everyday in high end post production. e.g EXR intermediates . You can demonstrate that it's lossless in vapoursynth

poisondeathray
14th April 2024, 14:45
The actual R value is 191.25 , but it's rounded down - you cannot display a 191.25 pixel value in 8bit.


but dithering can



Not for single pixels .

Dithering adds noise. There are different dithering algorithms , but they all add noise to a certain extent . Adding noise produces a lower signal to noise ratio in general . There are more algorithms than madvr has access to - look at fmtc for some others . The question boils down to: Is dithering more accurate than rounding ? - It depends on how you are measuring it, and how you are defining "accuracy". On standard bars dithering is worse by metrics

The 75% signal values in YCbCr are explicitly given in SMPTE RP219 . e.g. 75% red in 10bit values is YCbCr [204,435,848] .

You can check this by converting RGB float [0.75,0,0] to 10bitYUV444 (444 to avoid a subsampling discussion) using the standard Rec709 equations, or double check with vapoursynth - indeed you get YCbCr [204,435,848]

If you wanted to extend the analysis to actual RGB 191.25 (191.25 because we're using full range RGB, not studio RGB or limited range RGB, but you can demonstrate this for either) in that example, you can convert the resulting 8bit RGB values to float and compare that against the expected perfect value 75% red float signal [0.75,0,0] . Does the rounded down [191,0,0] 8bit RGB result have higher accuracy than the 8bit RGB dithered result when compared to the perfect signal in 32bit float? You can do this calculation in vapoursynth or matlab

You can get slightly lower/higher values with different dithering algorithms, but dithering is usually going to be less accurate when measuring by metrics on standard SMPTE bars.

32bit PSNR dB (0-100 scale)
no dither
r 60.172136
g 100
b 100

ordered dither
r 54.435368
g 69.643532
b 69.887006

error diffusion
r 54.432824
g 58.361931
b 58.558901


32bit SSIM (0-1 scale)
no dither
r 0.999933
g 1
b 1

ordered dither
r 0.999893
g 0.999958
b 0.999960

error_diffusion
r 0.999887
g 0.998365
b 0.998489


Another reason you want to disable dithering for debugging purposes - There are many different algorithms. Different programs have can have slightly different implementations of the same dithering algorithm. Also many have a noise seed - so on the same exact same frame, using the exact same program - the noise pattern can be different.

When you comparing program A vs. B vs. C. You don't want to introduce other variables and noise by dithering. You want to keep it as simple and consistent as possible - rounding is preferable and the most consistent between programs. It also is more accurate on bars

Normal viewing is different situation - there dithering has subjective benefits, reducing banding

huhn
14th April 2024, 15:14
integer YCbCr => RGB float => integet YCbCr is lossless if done correctly. That means no dithering or rounding for a lossless trip

it's not lossless even if it is only arthmetic limitation and most importantly show me a video render that does this...
i mean you are showing PSNR comparted to knowly flawed test pattern which are literally rounded... and i have already proven that

this is truely outrages to take YCbCr RGB YCbCr into a video render accuracy talk. you can't dither a single pixel but is is still supposed to be less accurate... just take the high roll of the dithering not the avg.

sampte red 75% is studio RGB 180 16 16
from sampte ycbcr to rgb in float is 180.33 16.04 16.53
dithering it will avg the same and rounding it will be 180 16 17...

we are actually going from limited range ycbcr to full range RGB and the exact same thing will happen... which
191.34 0.04 0.62 nothing changed.

the sampte bar results are not the wanted results they are rounded because they don't have enough precision...
the studio rgb smapte is niot 75 % it is ~74.886

poisondeathray
14th April 2024, 15:40
it's not lossless even if it is only arthmetic limitation


Again, integer YCbCr => float RGB => integer YCbCr is a lossless transform when done properly

This is known fact. It's easily demonstratable for any YCbCr integer .

Even 4:2:0 chroma subsampled YCbCr is lossless for the upsample/downsample because nearest neighbor is used

Deal with it



and most importantly show me a video render that does this...


Think before your write...

You cannot display RGB float with any current display . Nor do you display YCbCr directly with any common display

You can read off RGB float values and YCbCr values in vsedit , but the actual display pixel technology is integer RGB




i mean you are showing PSNR comparted to knowly flawed test pattern which are literally rounded... and i have already proven that


Yes , and PSNR or SSIM is not a perfect test either. If you want to test another metric say the word

SMPTE bars are used everyday in professional production for studios, TV, web . It's attached to every submission for professional content providers (Netflix, Amazon, Disney, TV stations) . It's a very common test pattern. UHD / HDR /HLG variants have a different set of bars.

The test shows using real 10bit YCbCr video - which has closer approximation to the perfect test signal . Of course 10bit YCbCr is already rounded compared to the perfect float signal. If you started with perfect, you wouldn't need to round anything would you? If you added dithering noise to the perfect signal, you would still get more errors



we are actually going from limited range ycbcr to full range RGB and the exact same thing will happen... which
191.34 0.04 0.62 nothing changed.

You can show this in vapoursynth for either limited or full RGB, or any integer YCbCr value



the sampte bar results are not the wanted results they are rounded because they don't have enough precision...
the studio rgb smapte is niot 75 % it is ~74.886

It has nothing to do about "wanting" . It has to do with using real video values, with real encoding

poisondeathray
14th April 2024, 15:52
we are actually going from limited range ycbcr to full range RGB and the exact same thing will happen... which
191.34 0.04 0.62 nothing changed.





import vapoursynth as vs
core = vs.core

clip = core.std.BlankClip(width=1920, height=1080, format=vs.YUV444P10, color=[204,435,848])

clip3 = core.resize.Point(clip, format=vs.RGBS, matrix_in_s="709") #RGB [0.750367, 0.000368908, 0.000351697]
clip3 = core.resize.Point(clip3, format=vs.YUV444P10, matrix_s="709") #YCbCr [204,435,848]

clip3.set_output()





This one is an "easy" YCbCr value because there is no negative RGB produced or values >1 . ie. it's not a YCbCr value that produces out of gamut RGB. This means you don't even need float RGB for a round trip . 16Bit RGB should be "enough" for the lossless round trip.

There are millions of YCbCr values that "map" to out of gamut RGB values - those require RGB float for the lossless roundtrip

Asmodian
14th April 2024, 19:14
- ffmpeg will most probably be reliable
- so will ADM
- MPC-HC itself seems to have a bug (using/ driving ffmpeg, the renderers etc.)

ffmpeg is not great at color handling, even though it is used everywhere, sad but true.

As someone who has spent thousands of dollars and hundreds of hours on calibration hardware and software, I can assure you that madVR does it right.

The players do not mess with the color at all. They might load filters that do, or when using DXVA2 etc. the GPU driver often does with default settings, but MPC-HC does not have a bug that is messing up all color conversions. This has been verified with hardware calibration meters and test patterns.

VD2 does not display the correct colors, it doesn't even try. If you want to test a video it is better to play it with something that does color conversions correctly.


My aim was just to help clearing up things,
and hopefully assist in revealing a bug.
All-in-all for a naive user like me an unsatisfying situation.

You simply don't understand how to check what correct is and your guessing is very wrong. Then you do not believe those who do know what is going on.

Dithering is less accurate for diagnostic tests on patterns such as color bars

A colorimeter will measure more than one pixel at a time, so dithering is better than no dithering. This is also the way it will be viewed because banding is so much more visible than the slightly increased noise due to 8 or 10 bit dithering.

poisondeathray
14th April 2024, 21:08
A colorimeter will measure more than one pixel at a time, so dithering is better than no dithering.


It's not either / or - you need to perform all the tests including without dithering

Dithering adds another layer of complexity , randomness and inconsistency between programs. The discussion was about program A vs. B vs. C . If you one uses one variant of floyd-steinberg, but another uses another variant such as ordered, or perhaps a different seed, or program D does not dither - you're going to have more problems figuring out where the problem is .

You need to examine all processes in the pipeline, look for upstream problems as well, flag mishandling, wrong matrix etc... I already mentioned this for vdub2 - flag vs. no flag exact same video results in very different results because Rec601 is used by default



This is also the way it will be viewed because banding is so much more visible than the slightly increased noise due to 8 or 10 bit dithering.

Yes of course, normal viewing vs. diagnosis


Normal viewing is different situation - there dithering has subjective benefits, reducing banding

nji
14th April 2024, 21:23
@Asmodian: Thank you very much for your feedback.


... You simply don't understand how to check what correct is and your guessing is very wrong.


You are right.
I don't have much experience with that.
I did my best and tried to derive plausibilities.

As already said
in my tests it shows that ffmpeg and ADM produce identical frames.
MPC-HC does it systematically abt. (2,2,2) brighter.
So one of them must be wrong.
The probability of ffmeg (in all its aspects) being correct
seems to be much larger, than MPC-HC's.
I might think this should be plausible?


Then you do not believe those who do know what is going on.


I agree to that too.
I don't think it's a good idea just to believe anyone when there is no convincing reasoning,
but only just (rude) claims he is right/ he knows.
The world of full of people who just claim (due to their personal motivations).

Your reply is the first that has a weight.
Thank you for that!

In consequence this would mean that ffmpeg does wrong...(?)

Maybe finally anyone does the simple test, if he can reproduce:
Take an arbitrary video, say this one:
https://c.gmx.net/@1155842887640945833/pRh5F4zqT7mMtrBVWAxzXQ
Export first frame by ffmpeg and by MPC-HC.
==> MPC-HC's is brighter.

poisondeathray
14th April 2024, 22:13
@nji :

Here are 10bit444 AVC colorbars based on the SMPTE HD pattern. One version has colorimetry flags, other is unflagged
https://www.mediafire.com/file/9zp8pg1p1fzrh7w/colorbars_YUV444P10_AVC.zip/file

When testing , close all other applications . An application will sometimes switch to another renderer if another application or instance is open with one renderer. To be consistent, disable dithering in all applications if possible

Take BMP screenshot and examine using a color picker (such as instant eyedropper or similar). Also compare to what you "see" on a monitor directly (again using a color picker) . Do not use PNG, because some applications write gAMA and cHRM tags which can cause the PNG to display differently in some applications . If you do use PNG, make sure it does not have tags or the application does not write PNG tags


When you write "export by ffmpeg" - what is the command line ?

nji
14th April 2024, 22:41
Unflagged video
Exported first frame with ffmpeg and MPC-HC.
Gray values are identical,
green values are darker/ reds are lighter at MPC-HC.
(I.e. the other way round than in all my tests)
No matter if PNG or BMP.

Flagged video
MPC and ffmpeg exporting identical frames.
They are the same as MPC's frames.

==> ffmpeg exports green-brigher frames with the unflagged video.
(ffmpeg -i input.mp4 -frames:v 1 ffmpeg.bmp)

EDIT:
Quantified (average of channels), A is ffmpeg:

A: Orig: B = 104.255 G = 106.74 R = 102.573
B: Orig: B = 104.628 G = 102.821 R = 102.967

A-B: Orig: B = 1.04994 G = 4.1036 R = 2.27106
B-A: Orig: B = 1.42289 G = 0.184964 R = 2.66542

DOD: Orig: B = -0.372956 G = 3.91864 R = -0.39436

poisondeathray
14th April 2024, 22:49
Maybe finally anyone does the simple test, if he can reproduce:
Take an arbitrary video, say this one:
https://c.gmx.net/@1155842887640945833/pRh5F4zqT7mMtrBVWAxzXQ
Export first frame by ffmpeg and by MPC-HC.
==> MPC-HC's is brighter.

Same for me, but maybe you are not using the correct commandline

There is no material difference in terms of "brightness" (even if you apply any of the dithering algos)



ffmpeg -i color-test.mp4 -vf zscale=min=709,format=gbrp -frames:v 1 -start_number 0 ffmpeg_zscale_%04d.bmp



bmp output for color-test
https://www.mediafire.com/file/nseksz68fhfvmsq/color-test_mpchc_vs_ffmpegzscale.zip/file

nji
14th April 2024, 23:23
If you have to know and specify the parameters for ffmpeg always that way...
Guarantee for generating wrong frames.

Moreover - it can't be just the command line, as ADM for example
exports/ shows the same frames as "default command line".
But maybe ffmpeg API has to be called by the hosts also in the specific way respectively?
... and isn't...

poisondeathray
14th April 2024, 23:37
If you have to know and specify the parameters for ffmpeg always that way...
Guarantee for generating wrong frames.

Not necessarily ; It also depends on the source flags and ffmpeg version...

ffmpeg is constantly evolving project - sometimes stuff gets broken, then fixed or behaviour changed

There are many "gotchas" and pitfalls with ffmpeg - it's not for beginners

The PNG gAMA and cHRM that ffmpeg exports is another common problem




Moreover - it can't be just the command line, as ADM for example
exports/ shows the same frames as "default command line".
But maybe ffmpeg API has to be called by the hosts also in the specific way respectively?
... and isn't...

Not sure about avidemux, but it doesn't use ffmpeg directly, perhaps some shared libvcodec libraries

avidemux never has the correct color for me in any of the versions going back 10 years. I couldn't figure the correct combinations twiddling in the settings / open GL / QT/ DXVA . If anyone is able to get avidemux to have correct colors, please post the setup configuration

huhn
15th April 2024, 00:51
Again, integer YCbCr => float RGB => integer YCbCr is a lossless transform when done properly

This is known fact. It's easily demonstratable for any YCbCr integer .

Even 4:2:0 chroma subsampled YCbCr is lossless for the upsample/downsample because nearest neighbor is used

Deal with it
yes just ignore the chroma location yes NN the mathematical wrong scaler.
https://en.wikipedia.org/wiki/Floating-point_error_mitigation



Think before your write...

You cannot display RGB float with any current display . Nor do you display YCbCr directly with any common display

You can read off RGB float values and YCbCr values in vsedit , but the actual display pixel technology is integer RGB

yes you display 8 or 10 bit
now do that in your round trip.
someone didn't think before.
because i literally wanted you to embarrass give me that answer...


Yes , and PSNR or SSIM is not a perfect test either. If you want to test another metric say the word
you didn't test anything because you don't have a reference

SMPTE bars are used everyday in professional production for studios, TV, web . It's attached to every submission for professional content providers (Netflix, Amazon, Disney, TV stations) . It's a very common test pattern. UHD / HDR /HLG variants have a different set of bars. sure... we have never moved on from that ohh wait we have...
and not the point.
why would you not dither them that's the point.

The test shows using real 10bit YCbCr video - which has closer approximation to the perfect test signal . Of course 10bit YCbCr is already rounded compared to the perfect float signal. If you started with perfect, you wouldn't need to round anything would you? If you added dithering noise to the perfect signal, you would still get more errors
if there is no error it can not dither... how do you dither an error of zero. and why do you need the 10 bit YCbCr? i wonder...
just like something is lossy.
You can show this in vapoursynth for either limited or full RGB, or any integer YCbCr value

you just like to ignore that they literally disagree don't you?



It has nothing to do about "wanting" . It has to do with using real video values, with real encoding[/QUOTE]
my point is they are inaccurate.
you know you can encode a dithered image.
well i can...


import vapoursynth as vs
core = vs.core

clip = core.std.BlankClip(width=1920, height=1080, format=vs.YUV444P10, color=[204,435,848])

clip3 = core.resize.Point(clip, format=vs.RGBS, matrix_in_s="709") #RGB [0.750367, 0.000368908, 0.000351697]
clip3 = core.resize.Point(clip3, format=vs.YUV444P10, matrix_s="709") #YCbCr [204,435,848]

clip3.set_output()





This one is an "easy" YCbCr value because there is no negative RGB produced or values >1 . ie. it's not a YCbCr value that produces out of gamut RGB. This means you don't even need float RGB for a round trip . 16Bit RGB should be "enough" for the lossless round trip.

There are millions of YCbCr values that "map" to out of gamut RGB values - those require RGB float for the lossless roundtrip

ohh 16 is enough i see i see.
well i give you 8 because most of these renderer can't render at more. i guess you simply didn't know that.
not that your round trip ever matter.
for some reasons you really care for illegal colors... a renderer obviously can't show.

and that's why it is basic knowledge that YCbCr -> RGB is lossy in the video renderer realm. why do i have to say this out loud...
It's not either / or - you need to perform all the tests including without dithering

Dithering adds another layer of complexity , randomness and inconsistency between programs. The discussion was about program A vs. B vs. C . If you one uses one variant of floyd-steinberg, but another uses another variant such as ordered, or perhaps a different seed, or program D does not dither - you're going to have more problems figuring out where the problem is .

You need to examine all processes in the pipeline, look for upstream problems as well, flag mishandling, wrong matrix etc... I already mentioned this for vdub2 - flag vs. no flag exact same video results in very different results because Rec601 is used by default




Yes of course, normal viewing vs. diagnosis

you are just ignoring your statement that dithering makes an image inaccurate...
Dithering is less accurate for diagnostic tests on patterns such as color bars
so 191 0 1 is more accurate then 191.34 0.04 0.62 dithered over the entire image.
and the best part sampte say it should be 191 0 0.
what a grand and intoxicating innocents.
it's just like YCbCr -> RGB is lossy when it is actually used to look at it in you know a video renderer.

BTW. because for some reasons you really don't get it.
MPC-HC can not change any color inaccurate in renderer they are all up stream it just loads them. EVR everything is in the hand of the GPU driver and the rest is 3rd party.
this is like complaining to a post worker that the weather is bad.

poisondeathray
15th April 2024, 01:37
yes just ignore the chroma location yes NN the mathematical wrong scaler.
https://en.wikipedia.org/wiki/Floating-point_error_mitigation


Sure but, you can demonstrate the round trip 8 or 10 but integer YCbCr => RGB float =>same integer YCbCr is lossless , when done properly



yes you display 8 or 10 bit
now do that in your round trip.
someone didn't think before.
because i literally wanted you to embarrass give me that answer...


The round trip returns the original YCbCr values . You have the same video. Bit identical. It's lossless. So when you display that, it's the same as the original

To do the round trip properly you must use RGB float for the intermediate step e.g. a vapoursynth script. A regular player setup will clip values for the YCbCr => RGB intermediate step



why do you need the 10 bit YCbCr? i wonder...


The reason for choosing 10bit is you need +2 bits YCbCr to produce the perfect expected (rounded) 8bit RGB values - I was following up with nji with the colorbars




It has nothing to do about "wanting" . It has to do with using real video values, with real encoding
my point is they are inaccurate.


Yes, 8 or 10bit YCbCr are inaccurate compared to the perfect float signal .


ohh 16 is enough i see i see.


For that specific YCbCr value, 16bit happens to be enough. For millions of other YCbCr values, it is not


well i give you 8 because most of these renderer can't render at more. i guess you simply didn't know that.

Yes I was the one that pointed that out to you earlier


not that your round trip ever matter.
for some reasons you really care for illegal colors... a renderer obviously can't show.




=> This part of discussion with the round trip all started with your statement:


a YCbCr -> RGB conversation is lossy in nature even at 32 bit per component.

YCbCr => RGB => YCbCr an be lossless, when the RGB step is done properly at 32bit float




and that's why it is basic knowledge that YCbCr -> RGB is lossy in the video renderer realm. why do i have to say this out loud...


Yes that's correct..."in the renderer realm". Because the renderer isn't working in 32 bit float RGB

I wrote integer YCbCr => float RGB => integer YCbCr is lossless when done properly. Do you see the difference ?






you are just ignoring your statement that dithering makes an image inaccurate...


Not at all - The values are mathematically less accurate when dithered on patterns such as bars - that was demonstrated that above using metrics - rounding has less error than several type of dithering when compared to the float signal

The point about disabling dithering for diagnosis/analysis is about comparing to different programs, some using different dithering algorithms or not. You need to compare "apples to apples". If you have some random seed producing different results, it's going to mess up the analysis .

You need to perform multiple tests to determine the underlying problem. Not just 1 test with dithering. There can be many reasons for an observation. eg. It looks to me here this was user error for nji




so 191 0 1 is more accurate then 191.34 0.04 0.62 dithered over the entire image.

Again it depends ...

The question boils down to: Is dithering more accurate than rounding ? - It depends on how you are measuring it, and how you are defining "accuracy". On standard bars dithering is worse by metrics





and the best part sampte say it should be 191 0 0.


That's the expected value rounded. And that's what you expect for all programs rounding. Consistent behaviour vs. inconsistent behaviour. You need consistency for analysis and repeatable results .

poisondeathray
15th April 2024, 02:56
why do you need the 10 bit YCbCr? i wonder...
.
.
.

so 191 0 1 is more accurate then 191.34 0.04 0.62 dithered over the entire image.



Ahh I glossed over this and missed it - 192,0,1 , not 191,0,0 - ie. you're referring to the 8bit case. I see what you're getting at...

Same methodology comparing to float signal

8bit "75% red" YCbCr[51,109,212]
PSNR 32bit (0-100 scale)

no dither
r 50.629359
g 100
b 48.130803

ordered dither
r 54.435493
g 71.785649
b 52.805518


and the best part sampte say it should be 191 0 0.


To clarify - that is the expected rounded value for 10bit YCbCr [204,435,848] to 8bit RGB . Not 8bit YCbCr to 8bit RGB

nji
15th April 2024, 11:42
If I get it right, the question about dithering etc. is independent
from the one I originally raised (potentially brightening by MPC).
As my effects are much larger than the ones discussed above..

A short sum-up.

@poisondeathray confirms my observation at his configuration.
==> Either MPC or ffmpeg is wrong.

What does it mean that ffmpeg produces this overall different
and especilly green-brighter frames with unflagged videos?
Is this another bug of ffmpeg?
https://forum.doom9.org/showthread.php?p=2000426#post2000426

To my opinion it is important to come to a conclusion to
have consequences. If not, everything is blown in the wind.

For me it seems unacceptable ffmpeg has to be fed carefully
by stream information externally to produce a correct output.
Identifying the streams in detail and correctly should be
its origin ability.

The central question:

Is ffmpeg doing wrong?
If yes - there should be filed an issue.

huhn
15th April 2024, 12:05
without metadata you have to guess.
and a guess will never ever be 100 % correct. it is still a guess.

so it can do "better" guessing by seeing ohh 720p that not a DVD that's a bd resolution so bt 601 or the many other dvd colorpspace thingies are unlikely let's take bt 709. not worth to do to break older scripts that rely on the old guessing.

it can still be bt 601 anyway or what ever ycocg anyone?
the solution is tell it what it is.

poisondeathray
15th April 2024, 12:52
What does it mean that ffmpeg produces this overall different
and especilly green-brighter frames with unflagged videos?
Is this another bug of ffmpeg?
https://forum.doom9.org/showthread.php?p=2000426#post2000426

To my opinion it is important to come to a conclusion to
have consequences. If not, everything is blown in the wind.

For me it seems unacceptable ffmpeg has to be fed carefully
by stream information externally to produce a correct output.
Identifying the streams in detail and correctly should be
its origin ability.

The central question:

Is ffmpeg doing wrong?
If yes - there should be filed an issue.


The explanation is wrong matrix is used . It's similar to the behaviour I mentioned earlier with vdub2 with Rec601 . If no flags (or unknown), then assume Rec601.

But.... by convention, HD video uses Rec709 , SD video uses Rec601. So you can see that will be a problem in actual usage for unflagged videos... and there are many unflagged in the wild .

Some video players use an additional level of logic - if height > 576 then use Rec709 for the RGB conversion

It's not considered a bug, and this one has been reported dozens of times

The other problem is wrongly flagged videos - it happens a lot more than you think. Another can of worms

nji
15th April 2024, 13:41
Your explanation seems very plausible to me.

If it should be right
(with my very limited knowledge and experience I can't assess,
but as we're in a forum maybe there will be other posts on this).
... so IF that should be right..

... then it's a built-in source of wrong color changes.

It's not me having a solution for it.

Still I wonder if a wrong/ missing flagging actually explains the (2,2,2) at my movie?
It is a 720p flagged BT.709, limited range. The orig movie is from 1989.

poisondeathray
15th April 2024, 15:36
Your explanation seems very plausible to me.

If it should be right
(with my very limited knowledge and experience I can't assess,
but as we're in a forum maybe there will be other posts on this).
... so IF that should be right..


You can learn to test it - you can control each parameter of the YCbCr<=>RGB conversions in avisynth or vapoursynth for example to diagnose the issue.


... then it's a built-in source of wrong color changes.

To be fair, that statement is true for any type of "auto" behaviour



It's not me having a solution for it.

Still I wonder if a wrong/ missing flagging actually explains the (2,2,2) at my movie?
It is a 720p flagged BT.709, limited range. The orig movie is from 1989.


Were you referring to color-test.mp4 ? Using default settings ?

Your video is flagged, you can see in mediainfo for example
Color range : Limited
Color primaries : BT.709
Transfer characteristics : BT.709
Matrix coefficients : BT.709

The default ffmpeg scaler responsible for the YUV=>RGB conversion is swscale. The important flags for swscale higher accuracy are


-sws_flags accurate_rnd+full_chroma_int


If the input file is not in planar pixel format - e.g. if it was interleaved such as YUY2 , then full_chroma_inp is also needed otherwise the chroma is downsampled before conversion

Why isn't this the "default" setting ? I don't know . I'm guessing probably a speed / performance tradeoff

I think most regular ffmpeg users prefer zscale these days. It's faster, more accurate, fewer problems with cases .

Why is swscale still the default ? Not sure, legacy, nostalgia - It's the one that everyone complains about and historically had many errors and problems

nji
15th April 2024, 16:39
I checked and... 100% approvement! :)

With the flags of swscale you mentioned the (2,2,2) difference is gone.

I can't tell if "most regular ffmpeg user prefer zscale" as you said.

I would have thought that most typical (occational) ffmpeg users like me
never even heard about that, and use the default config.
Trusting that ffmpeg does the right thing.
The way it is now unwanted changing spread more and more.

To my opinion worth an issue in ffmpeg.
But you said it isn't taken as bug.

Call me naive, but I'm kind of disgusted by that situation.

And grateful to you :)

Emulgator
15th April 2024, 23:10
Good thread, many thanks for getting into that detail, poisondeathray, and the others.
I might have stumbled into that one (ffmpeg) too one day.