Log in

View Full Version : zscale WEBP Error


Pages : [1] 2

jay123210599
10th December 2024, 13:53
But when I tried to used zscale when converting a video to lossless animated WEBP, I got this error:

[Parsed_zscale_0 @ 0000020b7458bd80] code 3074: no path between colorspaces
Last message repeated 25 times
[vf#0:0 @ 0000020b74005240] Error while filtering: Generic error in an external library
[vf#0:0 @ 0000020b74005240] Task finished with error code: -542398533 (Generic error in an external library)
[vf#0:0 @ 0000020b74005240] Terminating thread with return code -542398533 (Generic error in an external library)
[vost#0:0/libwebp_anim @ 0000020b74004700] Could not open encoder before EOF
[vost#0:0/libwebp_anim @ 0000020b74004700] Task finished with error code: -22 (Invalid argument)
[vost#0:0/libwebp_anim @ 0000020b74004700] Terminating thread with return code -22 (Invalid argument)
[out#0/webp @ 0000020b74004380] Nothing was written into output file, because at least one of its streams received no packets.
frame= 0 fps=0.0 q=0.0 Lsize= 0KiB time=N/A bitrate=N/A speed=N/A
Conversion failed!

How do I fix that?

Here is the information for the video:
Format : AVC
Format/Info : Advanced Video Codec
Format profile : High@L4.1
Format settings : CABAC / 4 Ref Frames
Format settings, CABAC : Yes
Format settings, Reference frames : 4 frames
Format settings, Slice count : 4 slices per frame
Codec ID : V_MPEG4/ISO/AVC
Duration : 10 s 886 ms
Bit rate mode : Variable
Maximum bit rate : 40.0 Mb/s
Width : 1 920 pixels
Height : 1 080 pixels
Display aspect ratio : 16:9
Frame rate mode : Constant
Frame rate : 23.976 (24000/1001) FPS
Color space : YUV
Chroma subsampling : 4:2:0
Bit depth : 8 bits
Scan type : Progressive
Time code of first frame : 01:37:05:07
Default : Yes
Forced : No

Here is the command I used:
ffmpeg -i video.mkv -vf zscale=pin=2:p=2:tin=2:t=2:min=709,format=bgra output.webp

Z2697
10th December 2024, 13:58
Oh no, not again!

Z2697
10th December 2024, 14:00
By the way, why not use rgb24 instead of gbrp?


zscale works with planar formats, gbrp is the pixel format identifier for planar rgb. If you use rgb24, it will go through a different path and introduce rounding errors - the values will be slightly off from expected or proper conversion


:rolleyes:

jay123210599
10th December 2024, 14:27
:rolleyes:

I replaced bgra with gbrp and now it works. It looks like use bgra as the format was the problem. But will using gbrp have rounding errors?

poisondeathray
10th December 2024, 14:33
I replaced bgra with gbrp and now it works. It looks like use bgra as the format was the problem. But will using gbrp have rounding errors?


Only the expected rounding errors. Not the additional errors on top of the expected ones like default swscale without accurate flags

You expect some accuracy and rounding issues with 8bit YUV to 8bit RGB. This is discussed in other threads in detail. The only way it's completely lossless is if you use RGB float and use nearest neighbor for chroma scaling. This preserves negative RGB values, and values over 1 on a 0 to 1 scale. This can be "reversed" as a lossless round trip so you get the original 8bit YUV data

Z2697
10th December 2024, 14:45
Only the expected rounding errors. Not the additional errors on top of the expected ones like default swscale without accurate flags

You expect some accuracy and rounding issues with 8bit YUV to 8bit RGB. This is discussed in other threads in detail. The only way it's completely lossless is if you use RGB float and use nearest neighbor for chroma scaling. This preserves negative RGB values, and values over 1 on a 0 to 1 scale. This can be "reversed" as a lossless round trip so you get the original 8bit YUV data

If that YUV originates from RGB (which is the most likely case), the YUV-RGB-YUV conversion is reversible as well... because the "in-between" YUV code values are just not used, but if some editing is done in YUV space, and the encoding, distortion might cause slight error.

I don't think rounding errors disqualify the point of lossless encoding though, I mean of course no rounding error is much more optimal but lossless encoding prevents generational loss and other stuff as well.

poisondeathray
10th December 2024, 15:10
If that YUV originates from RGB (which is the most likely case), the YUV-RGB-YUV conversion is reversible as well... because the "in-between" YUV code values are just not used, but if some editing is done in YUV space, and the encoding, distortion might cause slight error.


Not in his case, because the YUV is chroma downsampled 4:2:0. If you started with RGB source before his, it would still be lossy - You can't discard information and be "lossless" . The exception for chroma up/down/up sampling would be if the RGB source was 1 color . Also, the YUV step would need +2 bits to be lossless. If you start from 8bit RGB master source, the YUV step would need to be YUV444P10




I don't think rounding errors disqualify the point of lossless encoding though, I mean of course no rounding error is much more optimal but lossless encoding prevents generational loss and other stuff as well.

Yes, the point was not about lossless compression - it was about the pre processing steps

The encoding itself is lossless, but if the operations used to convert to RGB cause a color shift compared to the expected values, it's incorrect .

=>The incorrect values and color shifts are preserved losslessly :D

My point was if you're going to jump through the hoops for a lossless workflow, why introduce other avoidable errors and color shifts and preserver them ?

jay123210599
10th December 2024, 15:39
So should I use APNG instead to avoid rounding errors?

poisondeathray
10th December 2024, 15:44
So should I use APNG instead to avoid rounding errors?

The rounding errors being referred to do not pertain to the compression step. APNG, PNG, and webp in lossless mode - all use lossless RGB compression , no additional rounding errors are introduced. ie. If you use the same preprocessing steps, all 3 formats should produce the same results (assuming there are no other display problems like PNG chunks)

The additional rounding errors discussed were from suboptimal YUV to RGB conversions, which can cause slight color and brightness shifts

Z2697
10th December 2024, 16:33
Not in his case, because the YUV is chroma downsampled 4:2:0. If you started with RGB source before his, it would still be lossy - You can't discard information and be "lossless" . The exception for chroma up/down/up sampling would be if the RGB source was 1 color . Also, the YUV step would need +2 bits to be lossless. If you start from 8bit RGB master source, the YUV step would need to be YUV444P10

I'm not talking about lossless to original RGB, I'm talking about lossless to original YUV which originated from RGB, after the conversion to and from RGB.

The "+2 bits" rule of thumb also applies to "native YUV to RGB", or maybe even worse, I don't know. Since there's no real "native YUV", we just ignore this fact.

poisondeathray
10th December 2024, 16:55
I'm not talking about lossless to original RGB, I'm talking about lossless to original YUV which originated from RGB, after the conversion to and from RGB.

The "+2 bits" rule of thumb also applies to "native YUV to RGB", or maybe even worse, I don't know. Since there's no real "native YUV", we just ignore this fact.


"losslessness" depends on what you define as the "original"

If you consider his source the "original" (regardless of what came before that) 8bit 4:2:0 YUV => RGB => 8bit 4:2:0 YUV is only reversible if you use float RGB, and nearest neighbor up/downsampling . You can't just ignore the out of gamut values, and clipping to 8bit RGB 0 and 255, otherwise it's not "lossless". Many values map to negative RGB, and values greater than 255, which would be clipped, and therefore not lossless

10bit YUV is required for exact 8bit RGB values, also because of the precision. Many 8bit YUV "map" to the same 8bit RGB values

huhn
10th December 2024, 16:55
Not in his case, because the YUV is chroma downsampled 4:2:0. If you started with RGB source before his, it would still be lossy - You can't discard information and be "lossless" . The exception for chroma up/down/up sampling would be if the RGB source was 1 color . Also, the YUV step would need +2 bits to be lossless. If you start from 8bit RGB master source, the YUV step would need to be YUV444P10




Yes, the point was not about lossless compression - it was about the pre processing steps

The encoding itself is lossless, but if the operations used to convert to RGB cause a color shift compared to the expected values, it's incorrect .

=>The incorrect values and color shifts are preserved losslessly :D

My point was if you're going to jump through the hoops for a lossless workflow, why introduce other avoidable errors and color shifts and preserver them ?

while bilinear scaling is only adding an error of up to 0.25 so 2 bits does this still count when chroma subsample positions are fixed?

and now going to use philosophy...
is chroma scaled by bilinear actually an image?

I'm not talking about lossless to original RGB, I'm talking about lossless to original YUV which originated from RGB, after the conversion to and from RGB.

The "+2 bits" rule of thumb also applies to "native YUV to RGB", or maybe even worse, I don't know. Since there's no real "native YUV", we just ignore this fact.

for a round trip you can do it lossless with an intermediates that is high bit deep.

RGB red 255 0 0 is 62.56 102.34 240 . they don't fit in 10 bit that doesn't mean the rounded version of this in a round trip that is also rounded will not be lossless but the RGB wanted here will never be lossless.

poisondeathray
10th December 2024, 17:01
while bilinear scaling is only adding an error of up to 0.25 so 2 bits does this still count when chroma subsample positions are fixed?


You can still measure the error

But for nearest neighbor : Duplicating and discarding the exact samples you just duplicated results in the same thing you started with = lossless . (And this is with powers of 2, such as those used in the chroma sampling context)


and now going to use philosophy...
is chroma scaled by bilinear actually an image?


Yes, in the respect that it's just a resampled image

jay123210599
10th December 2024, 17:11
The rounding errors being referred to do not pertain to the compression step. APNG, PNG, and webp in lossless mode - all use lossless RGB compression , no additional rounding errors are introduced. ie. If you use the same preprocessing steps, all 3 formats should produce the same results (assuming there are no other display problems like PNG chunks)

The additional rounding errors discussed were from suboptimal YUV to RGB conversions, which can cause slight color and brightness shifts

So the already present rounding errors are inevitable no matter what I do or there aren't any rounding errors at all?

poisondeathray
10th December 2024, 17:24
So the already present rounding errors are inevitable no matter what I do or there aren't any rounding errors at all?

Yes , there are expected errors for converting 8bit YUV to 8bit RGB.

8bit YUV to 8bit RGB is a mathematically lossy conversion (going to 16bit RGB is lossy too, just less lossy) - you can never get back the original YUV values. There are rounding, clipping and precision errors, but some of them are expected errors . The point was you want to avoid adding extra errors on top of that, especially the avoidable errors due to poor workflow choices

It doesn't really matter for a viewing format like PNG/webp, because you are viewing on a 8bit RGB or 10bit RGB display anyways . Those are lossy RGB representations of the 8bit YUV data . Even if you viewed your original video source - it's not being displayed as YUV - What you see is a RGB converted representation of the YUV source on the display. So don't worry about it

Z2697
10th December 2024, 17:38
"losslessness" depends on what you define as the "original"

If you consider his source the "original" (regardless of what came before that) 8bit 4:2:0 YUV => RGB => 8bit 4:2:0 YUV is only reversible if you use float RGB, and nearest neighbor up/downsampling . You can't just ignore the out of gamut values, and clipping to 8bit RGB 0 and 255, otherwise it's not "lossless". Many values map to negative RGB, and values greater than 255, which would be clipped, and therefore not lossless

10bit YUV is required for exact 8bit RGB values, also because of the precision. Many 8bit YUV "map" to the same 8bit RGB values

My point is that there's no real native YUV material. The out of gamut, negative and > 1.0 values are just non-existence in the first place when the source is converted from RGB.
If you accept 8bit RGB to 10bit YUV is "lossless", then this is "lossless" as well. Apart from the distortions introduced by editing and encoding in YUV space (let's not discuss that for a sec).

poisondeathray
10th December 2024, 17:53
My point is that there's no real native YUV material. The out of gamut, negative and > 1.0 values are just non-existence in the first place when the source is converted from RGB.

Yes, no native YUV material. That's irrelevant

Do you have the same values or not ? That' s one definition of losslessness

You can argue some values "shouldn't be there", but your feelings do not define whether or not something is lossless :D


If you accept 8bit RGB to 10bit YUV is "lossless", then this is "lossless" as well.
No.

8bit RGB to 10bit YUV can be a lossless conversion if done properly, because you can get back the original 8bit RGB values

But 8bit YUV to 8bit RGB - you cannot get back the original 8bit YUV values, so it's not lossless conversion

The other point you probably missed is many 8bit YUV map to the same 8bit RGB value irrespective of the out of gamut values. The precision is not high enough. 10bit YUV is required for the original, original 8bit RGB source if that was your reference point

Z2697
10th December 2024, 18:15
The other point you probably missed is many 8bit YUV map to the same 8bit RGB value irrespective of the out of gamut values.

What is out of gamut value in this case?

Z2697
10th December 2024, 18:19
8bit RGB to 10bit YUV can be a lossless conversion if done properly, because you can get back the original 8bit RGB values


So, this implies that the 10 bit YUV (originated from 8 bit RGB) to 8 bit RGB is "lossless" as well.
How does 8 bit YUV (originated from 8 bit RGB, but of course not full 8 bit RGB values are represented) to 8 bit RGB is not "lossless", even when there's less precision in the source?

poisondeathray
10th December 2024, 18:24
What is out of gamut value in this case?

Out of gamut errors are the YUV values that map outside of the RGB defined color cube. eg. 8bit YUV value maps to something less than RGB 0 or greater than RGB 255

You can argue that YUV value shouldn't have been there in the first place - and I agree with you - but that has no bearing on whether something is "lossless" or not


The 8bit YUV precision errors are different category than out of gamut . You can have several YUV values that map to the same RGB value which are in gamut , in the range [0-255]

poisondeathray
10th December 2024, 18:29
So, this implies that the 10 bit YUV (originated from 8 bit RGB) to 8 bit RGB is "lossless" as well.


Yes it can be if done properly.

eg. Your point of reference is is 8bit RGB. If you convert to 10bit YUV, you can get back the original 8bit RGB values

8bit RGB => 10bit YUV => 8bit RGB can be lossless if done properly


How does 8 bit YUV (originated from 8 bit RGB, but of course not full 8 bit RGB values are represented) to 8 bit RGB is not "lossless", even when there's less precision in the source?

It' s just math and what you are comparing

If the 8bit YUV is considered the "source" or starting point - after you do a conversion, can you get back the same values or not ?

That's what "lossless" means - you have the same values.

8bit YUV => 8bit RGB is not lossless because you cannot get back the 8bit YUV values



Similarly, all these steps are lossy and not reversible, you cannot get back any of the original values from a preceding step

8bit RGB original, original source => 8bit YUV (already lossy compared to previous step) => 8bit RGB (2 generation lossy steps)

huhn
10th December 2024, 20:41
You can still measure the error
you can easily see that error

Yes, in the respect that it's just a resampled image

the joke was i do not respect the existents of bilinear chroma scaling.

Yes it can be if done properly.

eg. Your point of reference is is 8bit RGB. If you convert to 10bit YUV, you can get back the original 8bit RGB values

8bit RGB => 10bit YUV => 8bit RGB can be lossless if done properly



It' s just math and what you are comparing

If the 8bit YUV is considered the "source" or starting point - after you do a conversion, can you get back the same values or not ?

That's what "lossless" means - you have the same values.

8bit YUV => 8bit RGB is not lossless because you cannot get back the 8bit YUV values



Similarly, all these steps are lossy and not reversible, you cannot get back any of the original values from a preceding step

8bit RGB original, original source => 8bit YUV (already lossy compared to previous step) => 8bit RGB (2 generation lossy steps)
while you can do stuff like this for something that supposed to stay RGB you should dither. because that's now "correct".

Z2697
11th December 2024, 02:02
Yes it can be if done properly.

eg. Your point of reference is is 8bit RGB. If you convert to 10bit YUV, you can get back the original 8bit RGB values

8bit RGB => 10bit YUV => 8bit RGB can be lossless if done properly



It' s just math and what you are comparing

If the 8bit YUV is considered the "source" or starting point - after you do a conversion, can you get back the same values or not ?

That's what "lossless" means - you have the same values.

8bit YUV => 8bit RGB is not lossless because you cannot get back the 8bit YUV values



Similarly, all these steps are lossy and not reversible, you cannot get back any of the original values from a preceding step

8bit RGB original, original source => 8bit YUV (already lossy compared to previous step) => 8bit RGB (2 generation lossy steps)


I keep saying my reference point is YUV (originated from RGB, but the loss is done, doesn't matter at all now), and you just keep saying my reference point is RGB.
What can I say.
You have your "if done properly", I have mine. Let's not bother it too much.

poisondeathray
11th December 2024, 03:16
I keep saying my reference point is YUV (originated from RGB, but the loss is done, doesn't matter at all now), and you just keep saying my reference point is RGB.


It doesn't matter - because each of those steps is lossy with respect to the one directly before, and the generations before that

ie. 8bit YUV (from a 8bit RGB source) to 8bit RGB is still lossy, when using 8bit YUV as the reference point - for the reasons already mentioned.

If you want definitive proof, you can test with all 16777216 8bit RGB color combinations as a pre starting point (A) - all "out of gamut values" are culled by definition

Make your 8bit YUV444 starting point (B), and convert to 8bit RGB (C) -

There is no way you can get back the YUV444 (B) , (or original RGB colors (A) ), from (C)

You can generate the pattern see this thread , or use ffmpeg allrgb
https://forum.doom9.org/showthread.php?t=183816
https://ffmpeg.org/ffmpeg-filters.html#allrgb_002c-allyuv_002c-color_002c-colorchart_002c-colorspectrum_002c-haldclutsrc_002c-nullsrc_002c-pal75bars_002c-pal100bars_002c-rgbtestsrc_002c-smptebars_002c-smptehdbars_002c-testsrc_002c-testsrc2_002c-yuvtestsrc


For (C) - the attempt to convert back to YUV444P8 to achieve (B) "your" original values, the PSNR is about 86db. It would have been infinity if it was lossless for ffmpeg psnr. Now slightly different methods will give slightly higher or lower, but it's always expected to be lossy (unless you have some weird source with 1 color that just happens to map correctly)

FranceBB
11th December 2024, 07:59
Yes but the scenario you're describing has more to do with the fact that you have out of range values than it has to do with RGB in general, but I understand your logic.
One however could therefore argue that scaling YUV to Studio RGB (that is, RGB in limited TV range) is therefore lossy 'cause both of them are limited. In other words:

YUV Limited TV range to Studio RGB limited TV range = lossless
YUV Full PC range to RGB full PC range = lossless
YUV Limited TV range to RGB Full PC Range = lossless as long as the original YUV stays within 0.0-0.7V, as it should.

In general, even when you're receiving a feed from your favourite TV station, letting anything get to out of range values, so above 0.7V (i.e 700 mV) or 235 for those who prefer the 8bit value reference is a sin 'cause all customer's TV are RGB anyway, so they would lose whatever is above 235 as that value is expanded to 255 and you run out of room. One of the things that is generally done is the soft highlights rollback to basically dim down the highlights of the elements going out of range to make them get back within the limited TV range. Even during live events, where you have potentially fast and unpredictable movement compared to interviews, you generally regulate the thing and then you put hardware clipping on the signal in anyway.

This is checked using real time hardware waveform monitors like the ones from Tektronix https://imgur.com/HRLItw3 and is what led me to create VideoTek() in Avisynth https://forum.doom9.org/showthread.php?p=1832846 - https://github.com/FranceBB/VideoTek

poisondeathray
11th December 2024, 15:43
Yes but the scenario you're describing has more to do with the fact that you have out of range values than it has to do with RGB in general, but I understand your logic.


No - it has everything to do with RGB color model, and the relationship with YUV in general, not out of range values. "Legal range YUV/RGB", "full range YUV/RGB" , all combinations are lossy with 8bit conversions

"out of gamut" is a separate topic than "legal range" , "full range" . You can produce out of gamut values, even when you have legal range YUV values


One however could therefore argue that scaling YUV to Studio RGB (that is, RGB in limited TV range) is therefore lossy 'cause both of them are limited. In other words:

YUV Limited TV range to Studio RGB limited TV range = lossless
YUV Full PC range to RGB full PC range = lossless
YUV Limited TV range to RGB Full PC Range = lossless as long as the original YUV stays within 0.0-0.7V, as it should.


These statements are incorrect in 8bit . You can demonstrate that with avisynth or ffmpeg or matlab

Prove it to yourself. Start with that RGB image in the post above and run through these 3 scenarios . Make sure you use YUV444P8 so we avoid discussing subsampling issues for now


Even if you remove out of gamut values - 8bit YUV => 8bit RGB does not have enough precision to map to a specific RGB value - there are multiple YUV values that map to a single RGB value that is within gamut. You end up with +/- 3 errors , and rounding errors. This is one of the contributing reasons behind 8bit "banding" . With 10bit YUV, there is enough precision to map exactly to each 8bit RGB 16777216 values

huhn
12th December 2024, 01:13
ycbcr to limited range RGB is lossless for a grey scale.
it is a well known edge case you can ignore it.

it only has Y values the other do not "matter" wrong word but the best i have.
and Y only also exists.

Z2697
12th December 2024, 19:10
No - it has everything to do with RGB color model, and the relationship with YUV in general, not out of range values. "Legal range YUV/RGB", "full range YUV/RGB" , all combinations are lossy with 8bit conversions

"out of gamut" is a separate topic than "legal range" , "full range" . You can produce out of gamut values, even when you have legal range YUV values



These statements are incorrect in 8bit . You can demonstrate that with avisynth or ffmpeg or matlab

Prove it to yourself. Start with that RGB image in the post above and run through these 3 scenarios . Make sure you use YUV444P8 so we avoid discussing subsampling issues for now


Even if you remove out of gamut values - 8bit YUV => 8bit RGB does not have enough precision to map to a specific RGB value - there are multiple YUV values that map to a single RGB value that is within gamut. You end up with +/- 3 errors , and rounding errors. This is one of the contributing reasons behind 8bit "banding" . With 10bit YUV, there is enough precision to map exactly to each 8bit RGB 16777216 values

The "multiple mapping" problem which causes banding is irrelevant in my argument, I use the result YUV as reference, the banding is a distortion only when you use RGB as reference in this case.

The real problem is rounding. Take 8bit RGB value (210,87,0) as example. When converted to full range 8bit YUV using BT.709 matrix you get (107,70,193), the "floting point" result is (0.419092,-0.225852,0.256818).
When this 8bit YUV value takes a roundtrip, the 8bit RGB value is (209,87,0), the 8bit YUV value is (107,71,193), fp result is (0.418258,-0.225403,0.254858) (which if +0.5*255 is (106.65579,70.022235,192.48624) I don't know why zimg (vapoursynth core.resize) rounds the 8bit value this way, or I'm doing the math wrong, but you get the point, I guess)

There's only a small fraction of this kind of values, most of them in "extreme values" like the Blue being 0 in the example, so if the image does not contain such pixels or some special treatment is done to the image, the 8bit YUV to RGB converion can be lossless. You don't need very special "1 color" image to achieve that.

10bit YUV lossless"ness" is much easier to achieve. But if any postprocessing including encoding is done to the image the lossless"ability" will likely be ruined even for 10bit.

poisondeathray
12th December 2024, 20:36
The "multiple mapping" problem which causes banding is irrelevant in my argument, I use the result YUV as reference, the banding is a distortion only when you use RGB as reference in this case.


It's relevant in general for YUV as starting reference - because the converted 8bit RGB values become the "incorrect ones" . The "distortion" means that it's lossy. ie. You can no longer derive the original YUV number , from the converted 8bit RGB - therefore it's a lossy conversion.

The analogy would be like a 3 different YUV pixel "mail delivery addresses" to 3 different RGB pixel "house numbers" 101,102,103 (simplified example, consider just 1 channel for now, not a RGB triplet). Because 8bit YUV precision isn't high enough you end up getting something like RGB 101,101,103 - which is one of the reasons you get 8bit "banding " - multiple YUV values can map to the same RGB number. From that RGB 101,101,103 , there is no way you can go back to 3 different original YUV numbers using standard methods from 2 duplicate, 1 unique RGB pixels (maybe using "AI" or guessing)


The real problem is rounding.

Yes - and the 10bit YUV precision overcomes the rounding issue when coming from an 8bit RGB source ("when done properly" :D - I have to include that because there are many ways, in many software, where it can go wrong )



There's only a small fraction of this kind of values, most of them in "extreme values" like the Blue being 0 in the example, so if the image does not contain such pixels or some special treatment is done to the image, the 8bit YUV to RGB converion can be lossless. You don't need very special "1 color" image to achieve that.


Starting from RGB is a "best-case" scenario - You're starting with "perfect" numbers that have already culled "bad" RGB values to produce lossless YUV444 values for starting point (B) . This does not happen often in real life

The fact is 99.99% of of type "regular" YUV sources for a YUV starting point will not be lossless for 8bit YUV to 8bit RGB conversion , and have many pixel values that become "lossy", changing from the original values

Because in real life , many more "problematic" YUV values occur naturally :
- chroma resampling . Chroma resampling to generate the YUV 4:2:0 "source" can produce millions of values that were "good" YUV values that will become "bad" YUV values and lossy in the round trip when tested against the YUV 4:2:0 source. (I'm not referring to duplicating and discarding using nearest neighbor for the RGB step, I'm referring to generating different YUV values due to resampling a pre non subsampled source to the 420 source by resampling say, a 4x4 grid of pixels using bicubic ). Most "sources" will be 4:2:0, and that is hardly considered "special treatment"

- lossy compression (most sources you start with are going to have lossy compression), multiple generations. Even if a value is slightly off due to lossy compression in a channel from "good" YUV triplet from a prior lossless conversion, that can cause next RGB conversion step to go out of gamut , which makes it irreversible

Millions of "bad" YUV values occur within "legal range" Y 16-235 CbCr 16-240 that can produce out of gamut RGB and clip (and therefore not reversible, not lossless) . There are fewer that occur in a full range conversion but they still potentially in the number of millions.



10bit YUV lossless"ness" is much easier to achieve. But if any postprocessing including encoding is done to the image the lossless"ability" will likely be ruined even for 10bit.

Yes - lossy encoding, chroma subsampling . Lossy compressed 8bit4:2:0 YUV are very common source materials . Like the OP's. As already mentioned, 8bit YUV to 8bit RGB is lossy. It's only the edge cases that can be lossless. Float RGB is required to be lossless for YUV to RGB - because this preserves the out of gamut, negative RGB, that are required for the lossless round trip

To be clear - 10bit YUV "losslessness" refers to 8bit RGB => 10bit YUV. By definition , all the "illegal" , out of gamut such as negative RGB values are already "culled" from 8bit RGB source. ie. all 8bit RGB 16777216 values can be properly and precisely coded for with 10bit YUV. It should be always lossless for all 8bit RGB values (when done properly :D )

Gavino
12th December 2024, 22:36
Millions of "bad" YUV values occur within "legal range" Y 16-235 CbCr 16-240 that can produce out of gamut RGB and clip (and therefore not reversible, not lossless) . There are fewer that occur in a full range conversion but they still potentially in the number of millions.
This was demonstrated dramatically in this (classic?) thread: U and V ranges for valid RGB

poisondeathray
13th December 2024, 03:13
This was demonstrated dramatically in this (classic?) thread: U and V ranges for valid RGB

Yes it's classic, and the animated GIF version is still alive in post #3. Nice to see you around Gavino - That thread is what inspired me down the learning path looking at YUV/RGB issues in more detail, so thanks. At the time we couldn't handle reading negative RGB or float values in open source programs until vapoursynth came along (and eventually later version avs+ with avspmod ) - you had to rely on programs like nuke/ae at the time - and there were (can still be) a lot of bugs /issues with various YUV/RGB conversions .

Gavino
13th December 2024, 20:42
Yes it's classic, and the animated GIF version is still alive in post #3. Nice to see you around Gavino - That thread is what inspired me down the learning path looking at YUV/RGB issues in more detail, so thanks. At the time we couldn't handle reading negative RGB or float values in open source programs until vapoursynth came along (and eventually later version avs+ with avspmod ) - you had to rely on programs like nuke/ae at the time - and there were (can still be) a lot of bugs /issues with various YUV/RGB conversions .
Thanks, pdr!
I have long thought that your detailed knowledge and understanding of these issues is second to none on these forums, so I'm humbled to learn that my own curiosity about them helped to inspire your journey down that path.

FranceBB
15th December 2024, 19:02
I see! I've actually been having this doubt for a very long time! One of the things that always baffled me was that I could have a completely perfect limited tv range source and even insert like

Limiter(min_luma=16, max_luma=235, min_chroma=16, max_chroma=240)

to have limited tv range yuv and yet, when displayed on a Tektronix Waveform monitor, it would still display the chroma to be out of range. I was always baffled 'cause I was like "how can it be out of range if I limited the chroma to be between 16 and 240"? Is this because of the lossy conversion between 8bit YUV and 8bit RGB due to the rounding so that the YUV values end up in "bad" RGB regions and are therefore reported as illegal despite them being "legal" in YUV?

I'm asking 'cause this would finally clarify one of the doubts I've been having for a very, very, very long time.
That would also explain why Limiter() is able to always bring luma in the legal range, but not chroma. This would then lead to the question: what do I do in those cases? I mean, when the QC guys occasionally got back to me with a FAIL due to out of range chroma (they never got back to me with a failure in luma given that Limiter always worked), the only thing I could do was something like Tweak(sat=0.80, dither=true) to reduce the saturation of the colors and make the program pass, but this always seemed like a drastic approach.

rwill
15th December 2024, 20:16
This would then lead to the question: what do I do in those cases?

What these QC people most of the time mean when they say 'illegal chroma' they mean according to EBU R103 or similar (https://tech.ebu.ch/docs/r/r103.pdf).

As it is quite possible to generate YUV values that point outside the valid RGB space this should be fixed in RGB space.

I am not going to go into details here but when you have a YUV that has this problem you can fix it by converting to RGB, clip the RGB values to the valid range, and convert back to YUV again. If you want to be pedantic clip YUV to legal before converting to RGB.

This way YUV and RGB are both in legal range.

I know you sometimes like to do things with ffmpeg, a possible filter chain would maybe look like this:

"format=<somergbformat>,lutrgb=r=clipval:g=clipval:b=clipval,format=<someyuvformat>.

Note that ffmpeg needs the correct colorspace information for the YUV->RGB->YUV conversation to work - one might need to specify "colorspace" as well at the start of the filter chain as well.

poisondeathray
15th December 2024, 22:42
Yes, clipping in RGB is usually what is done, and the simplest solution

"Auto" QC software for EBU r103 compliance has a RGB gamut check portion - and usually there is a 1% allowed margin of error

Important to note that SDI full range Y,RGB is being used (Y and limited range RGB 16-235 reference black to white, but 1-254 max for 8bit; for 10bit Y and limited range RGB 64-940, 4-1019 max) . Translation for avisynth/vapoursynth/ffmpeg - it would be limited range RGB conversion, clipped to [1,254] (or [4,1019] for 10bit) for the "base" RGB conversion.

Usually broadcast signals are lowpassed and go through a band filter - so many of the "bad, but legal range YUV" values that were generated are already reduced before QC check. As an alternative or complimentary route you can apply a convolution filter if you wanted to - EBU have some recommended values for filter coefficients

There are various "legalizer" software and plugins - and they usually have various options besides clipping like reduce saturation, reduce luminance. "Auto" legalizing/clipping can sometimes look bad with patchy artifacts - compared to a colorist doing it - but "auto" software is way faster and cheaper.

In general, the less you clip, the "less bad" the potential artifacts - so it would be useful to be guided by a visualizer to get away with the least amount of "damage". For freeware, _Al_ wrote a vapoursynth script where you can toggle a visualizer node to colorize the problem areas red, within a configurable range and it reports a percentage of out of range (also configurable). So you can adjust clipping or whatever filter on the fly and get feedback. You'd have to PM him for the most recent version, I don't think he put it on github yet. Another feature improvement would be to write accumulated/aggregate stats for analyzing a whole video, the version I tested in the past did it per frame

The preferred min/max range for EBU is [5,246] - clipping to those values in SDI full range RGB will get rid of most of problems for most sources automatically, and you can clip farther if you needed to. Converting back to YUV and subsampling can bring back new "legal range bad YUV values" , but rarely >1%

Gavino
16th December 2024, 14:19
Is this because of the lossy conversion between 8bit YUV and 8bit RGB due to the rounding so that the YUV values end up in "bad" RGB regions and are therefore reported as illegal despite them being "legal" in YUV?
No, it's not because of rounding - it's inherent in the way the YUV and RGB spaces are defined and the relationship between them, and it would happen even with an idealized fully accurate floating point representation.

Take a look a the thread I referred to above (and even run the script to see for yourself). It shows that most of the YUV space is in fact unused (ie does not correspond to a valid RGB color), especially for low and high values of Y, and that for no value of Y is the entire range of U or V valid. For Y=0 or Y=255 of course, it shrinks to a single point (black or white) with U=V=128.

Ah, you might say, but if we start with the YUV values limited to 'TV range'... ?
That cuts out the extreme values, but still leave a large part of the YUV space that corresponds to out-of-range RGB.

Gavino
17th December 2024, 11:10
@FranceBB, with your broadcasting background, you might find interesting this old BBC paper on 'Limiting of YUV digital video signals' (also cited in my 2010 thread).

http://downloads.bbc.co.uk/rd/pubs/reports/1987-22.pdf

Emulgator
17th December 2024, 12:45
From that BBC paper page8/22 Fig.2 shows beautifully how hairy it gets if one attempts to manipulate YUV.
And many thanks, Gavino, for making that classic valid range script back then.
As I started to correct analog hue shifts in YUV it helped me understanding those intricacies.
It became a must-see-before-work.

Sharc
21st December 2024, 13:39
And many thanks, Gavino, for making that classic valid range script back then.
+1.
This classic has been an eye-opener to me, together with the "RGB block in the YUV cube" discussions in this and the Videohelp forum. Many thanks Gavino !
I am still using the extended version (including 709 and real sources) to visualize "hot pixels" in my VHS sources - eventually trying to legalize the same.
:thanks:

Edit: FWIW here an example how I use it
https://mega.nz/file/eIEBSKrK#_41-zaFBGfN1owf5zsRW1Mgg3q6vcpb1eqAVTn-ATX0

poisondeathray
21st December 2024, 20:16
For AVS+, you could probably modify gavino's original "ShowBadRGB" function for the "broadcast" case .

The main differences for the "broadcast" r103 gamut check

1) "limited range YUV" to "limited range RGB" equations are used (not the same thing as "PC" matrix) - possible with avsresize or fmtc directly, not with internal "Convert" functions directly (but you could apply additional offset to achieve similar result) . There was a "studio RGB" function by Trevlac way back, but otherwise limited range RGB was not really used in avisynth back then

2) for 8bit data , 0 and 255 are reserved code values and placed in the "illegal gamut" definition for broadcast

But in the non broadcast delivery, "computer RGB" case, 0,255 are "legal" and actually important required values e.g.masks, compositing, keying/alpha channel. 0,255 are also important for some types of intermediate calculations, some types of filters for accuracy.



Pure rounding errors for 8bit YUV444<=>RGB only account for +/-3 delta code values. But chroma subsampling can push min/max deltas much larger , over 20 code values (!) with typical resamplers such as bicubic when using commonly used b,c values. A group of pixels with YUV values that would have passed as YUV444P8 can become "legal range YUV, but out of gamut" when they are in proximity to certain other pixels when chroma resampling is applied. It also depends on the kernel used. eg. bicubic/cubic resamplers use a 4x4 grid. "bilinear" uses 2x2. "Sharper" kernels, "negative lobe" resamplers - tend to generate more problematic YUV combinations with larger magnitude over/undershoots - they can create larger max, lower min values. People tend to "turn their nose up" at bilinear for chroma subsampling, but bilinear is safer for broadcast scenario . So you can have something legal in the RGB legalization/check step, but once it's converted back to YUV422P8 or YUV420P8, you can generate new illegal values, again - hence that 1% leeway is important, otherwise there would be a lot of back and forth vicious cycle checking

Z2697
21st December 2024, 21:15
May I ask why it's so important to keep legal range? Are the industrial equipments that picky?

rwill
21st December 2024, 23:15
May I ask why it's so important to keep legal range? Are the industrial equipments that picky?

It is a requirement of the broadcast people. It just has to be that way. I guess the 'why' has been lost in time...

Sharc
21st December 2024, 23:19
May I ask why it's so important to keep legal range? Are the industrial equipments that picky?
Simply speaking, illegal YUV will produce upon conversion out-of-gamut RGB (depending on matrix), means for example:
- color distortions because out-of-gamut RGB components are typically just clipped at 255 or 0 (8 bit realm).
- loss of details, loss of fine structures due to the clipping
See my uploaded example. While the YUV components are within allowed range each (see the histogram), the bad red pixels are "red" represented by clipped red component 255 but fine red details are totally lost in that area. Same for the dark areas with bad pixels where the blue component is clipped at 0.

On the other hand legalizing can be a pita as the fully legalized picture may look desaturated or "milky". For home use one may prefer to live with a compromise.

FranceBB
22nd December 2024, 02:21
I guess the 'why' has been lost in time...

I'm unfortunately way too young and this story should be narrated by those who were there, but I'm gonna try to put things together and narrate the tale of those people I met before they retired.

May I ask why it's so important to keep legal range? Are the industrial equipments that picky?

It's not about industrial equipments being "picky" but rather the fact that you can't physically carry a full pc range signal via SDI cables. Actually, to be entirely true, you couldn't carry full pc range signals via SDI cables back when the first revision was introduced. Those cables carry an uncompressed A/V stream along with some metadata to keep the signal synced like the timecode, the TTX (Teletext subtitles) etc. Unfortunately, because of this, some bits are reserved for metadata, which means that you can't possibly carry a Full PC Range signal as you don't have quite as many bits available.

Some of you may be familiar with VideoTek() (https://forum.doom9.org/showthread.php?t=175249) the function I made (alongside StainlessS, magiblot and algie) to have a Tektronix-like waveform monitor back in 2018.

Although I've introduced other scales (especially for HDR) like nits, by default if you don't specify anything, VideoTek() defaults to "volts" as a scale rather than bits or nits, just like in the actual Tektronix waveform monitor. In an SDR Limited TV Range signal you have the signal going from 16 to 235 and this corresponds to 0.0V-0.7V or 700 mV. Now, an SDI cable can carry signals up to 0.8V or 800 mV however due to the fact that you need to have some parts reserved and that you can't use the whole available range for video (also think about audio, teletext subtitles etc, not just the timecode and other syncing stuff), you can't truly carry a full pc range signal.

https://i.imgur.com/rJD8jEG.png

Now, let's forget about millivolt and let's focus on bandwidth, which is a good way to measure what a cable can carry. After all, we use that for all other kind of cables like USB, Thunderbolt etc, so we can use the same method for SDI cables as well. SDI cables went through quite a bit of a journey and, just like other cables that have been around for a very long time, there are several different revisions:

1) 270 Mbit/s
2) 540 Mbit/s
3) 1.4 Gbit/s
4) 2.9 Gbit/s
5) 6 Gbit/s
6) 12 Gbit/s
7) 24 Gbit/s
8) 48 Gbit/s

Those revision are more commonly named by the bandwidth they carry, for instance revision 4 is also called 3G-SDI as it carries almost 3 Gbit/s, revision 5 is called 6G-SDI as it carries 6 Gbit/s and so on for all the other revisions, namely 12G-SDI, 24G-SDI, 48G-SDI. The most skilled of you would have realized by now that 48G-SDI has the same bandwidth as the latest HDMI revision, namely HDMI 2.1b, as they can both carry 48 Gbit/s, although nobody calls the latter 48G-HDMI which would have made much more sense than the "2.1b" revision number they went for (I'm looking at you, HDMI consortium!). Anyway, while 48 Gbit/s may sound a lot, when you consider the fact that the signals are uncompressed (both video and audio) and that you also need additional bandwidth for syncing purposes, they aren't really much at all. Anyway, while the initial SDI revision allowed for enough bandwidth to carry only SD streams, as we moved on with revisions we were able to carry larger resolution, larger bit depth and more fps, but we're still limited.

The first revision was introduced in 1989, I wasn't even born, let alone being in the broadcast world (I started working at Sky on January 6th, 2016), but to get a sense of the limitation our ancestors faced, let's take 48G-SDI, the latest revision, as an example.

If we were to try to display an 8K signal - which is what revision 8, 48G-SDI, is for - we would have a bit of a problem.

To perform the calculations, we can use the following formula:

(Width * Height) * (Bit Depth) * (Planes) * (frames per second) = video bitrate

Calculation 1
7680x4320 4:4:4 Full PC Range 10bit 60fps

(7680 * 4320) * (10) * (3) * (60) = 59,719,680,000 bits per second

In other words, 59.7 Gbit/s, so we're out of luck.
What if we try Limited TV Range, though?

Calculation 2
7680x4320 4:2:2 Limited TV Range 10bit 60fps

(7680 * 4320) * (10) * (2) * (60) = 39,813,120,000 bits per second

In other words, 39.8 Gbit/s.

Here the 2 for the planes comes from the fact that in 4:2:2 we have 1 luma channel at full resolution (Y) and 2 subsampled chroma channels (Cb and Cr) by a factor of two, so it would be:

1 + 2/2 = 1 + 1 = 2.

Anyway, we've finally got to a feasible bitrate!
Do we wanna include 8 stereo 2ch PCM 24bit 48000Hz audio tracks in the mix as well carrying the various languages (i.e Dub) for the movie/tv series? No problem, that would be:

(Channels) * (Sample Rate) * (Bit Depth)

(16) * (48000) * (24) = 18,432,000 bits per second

so, just 18.4 Mbit/s or 0.0184 Gbit/s which, when added to our 39.8 Gbit/s video, makes it still insignificant and way below the 48 Gbit/s threshold. Wanna add subtitles? No problem, that would be around 300 kbit/s (294 kbit/s if we wanna be picky). For 8 subtitles, one per audio language, we would have 8 * 300 = 2400 kbit/s or 0.0024 Gbit/s. That still leaves us with plenty of room for the timecode and other syncing stuff that can be carried through.


Obviously one could say "oh, well, but if we can carry a 7680x4320 4:2:2 Limited TV Range 10bit 60fps with 8 Stereo PCM 48000Hz 24bit tracks and 8 subtitles on modern cables, then we could totally use those modern ones to carry Full PC Range FULL HD 10bit 4:4:4 60fps video instead as that would just be 3.7 Gbit/s!".

The answer is... yes, yes we could, given that the calculation for

1920x1080 4:4:4 Full PC Range 10bit 60fps

would be

(1920 * 1080) * (10) * (3) * (60) = 3,732,480,000 bits per second

or 3.7 Gbit/s just for the video (excluding audio), but that's not the point. You see, back when FULL HD was a thing, revision 4 was in place, so the overall bandwidth was 2.9 Gbit/s (3G-SDI, basically 3 Gbit/s), so we couldn't. This is to say that just like engineers were limited by the things available at their time back in 1989, 35 years later we're still limited by what we have available in our time. Even now, 48G-SDI is really targeted to be the standard for 8K not 4K, so before we could even dare to attempt to move to something like 4:4:4 Full PC Range, the "next big thing / next hot thing" comes along and we're limited again. This is why, realistically, I don't see 4:4:4 Full PC Range ever becoming a standard, unfortunately. It's just not possible.

Sharc
22nd December 2024, 09:43
In analog TV broadcast times there were no bits, no bitdepth, no bitrate, no x:y:z subsampling, but there were spectral bandwidth constraints, backward compatibility issues with existing B&W TV systems, and amplitude constraints to prevent overmodulation (clipping) of analog transmitters. That's when and why "YUV" was born as a technical solution to cope with these constraints. YUV (or component Y, Pb, Pr) is basically an analog concept which later became Y,Cb,Cr in the course of digitization.
Secondly, with respect to analog signal levels and signal excursions ("swing"), analog gear required some headroom/footroom to accommodate signal over- and undershoots due to filtering (ringing, Gibb's phenomenon) and analog circuitry imperfections to prevent clipping.

Sharc
22nd December 2024, 16:12
For AVS+, you could probably modify gavino's original "ShowBadRGB" function for the "broadcast" case .

The main differences for the "broadcast" r103 gamut check

1) "limited range YUV" to "limited range RGB" equations are used (not the same thing as "PC" matrix) ....
You mean as amended here:
https://forum.doom9.org/showthread.php?p=1405496#post1405496 ?
Or change the equations for "Studio Matrix" ?

Z2697
22nd December 2024, 17:43
That's a nice reading, thanks!
Is it the cable can't evolve fast enough, or people always want to squeeze more pixels into that poor cable... well, maybe both ;)

The naming after speed is like a dream, in consumer grade cables / ports they probably just want to confuse consumers and profit from information asymmetry.

By the way, somehow the Limited Range signal uses less bandwidth is not making sense to me, I mean, in digital domain, that's still 10 or 8 bits each plane pixel?

FranceBB
22nd December 2024, 19:09
Is it the cable can't evolve fast enough, or people always want to squeeze more pixels into that poor cable... well, maybe both ;)


A little bit of both, but mostly the fact that businesses want to jump on the "next big thing" all the time, where the "next big thing" now is 8K. I really wanted the 8K standard to be 12bit, but it looks like we're gonna be constrained to 10bit once again... :(


The naming after speed is like a dream


I know, right? If only everything could be like this... :(


By the way, somehow the Limited Range signal uses less bandwidth is not making sense to me, I mean, in digital domain, that's still 10 or 8 bits each plane pixel?

Yes, I should stop writing posts at 1AM, but what my head wanted to try to show was the original motivation, so the fact that you could only carry 800mV and a signal in limited tv range peaked at 700mV (0.7V) so you had enough headroom. In digital when carrying a signal as uncompressed both 8bit and 10bit full pc range and limited tv range would use the same bandwidth in the cable. After all, those cables are now mostly fiber based, they're not 75-ohm coaxial cables any longer, but yeah, back when I wasn't even born (and then for a while afterwards) they were and limiting the signal was a must, which is why we're stuck with it. I wish I could have some other people from that time here, but they all retired. Even algie, whose real name is Livio Aloja, one of the people I mentioned in VideoTek and one of my colleagues, retired in 2021. He had some incredible stories to tell. Unfortunately there's no one from the old generation any longer... :(

(no, they're not dead, they're just retired and 64+ miles away from where I work)

poisondeathray
22nd December 2024, 20:42
You mean as amended here:
https://forum.doom9.org/showthread.php?p=1405496#post1405496 ?
Or change the equations for "Studio Matrix" ?

The latter;

Those amendments were for Rec709 , PC.709 and they map to full range RGB ; limited range RGB is not included there

It would need an option for the "bad RGB" range for r103, which is different than the "bad RGB" range for other scenarios

Sharc
22nd December 2024, 20:53
The latter;

Those amendments were for Rec709 , PC.709 and they map to full range RGB ; limited range RGB is not included there

It would need an option for the "bad RGB" range for r103, which is different than the "bad RGB" range for other scenarios
Ah, mapping to limited range RGB is missing there. Some food for thought. Thanks.