Log in

View Full Version : How do I check if my 10 bit video contains actual 10 bit details


lansing
15th April 2026, 18:52
I have some videos that were encoded in 10 bit depth but I don't know if they were created with pseudo 10 bit or legit high bit depth source. How do I check them?

Selur
15th April 2026, 19:29
my 2 cents:

short: You can not reliably.

longer:
Likely REAL 10-bit source, has:
* smooth gradients
* no contour bands
* minimal dithering noise

Likely UPSCALED 8-bit → 10-bit:
* visible banding (steps in gradients)
* artificial dithering (grain-like pattern added by encoder)
* “posterized” skies or shadows

=> when properly done, you can't differentiate between 'native' and 'generated' high bit content, especially if the video was filtered or lossy (re-)encoded.

Cu Selur

Emulgator
16th April 2026, 15:09
In AviSynth I use a small trick: ConvertToStacked(), then examine the plane containing the LSBs.
Maybe there is a bitshifting filter in VapourSynth too, I did not follow the recent development.

lansing
17th April 2026, 02:09
In AviSynth I use a small trick: ConvertToStacked(), then examine the plane containing the LSBs.
Maybe there is a bitshifting filter in VapourSynth too, I did not follow the recent development.

Can you elaborate more? Like what do you look for from the convertToStack function?

Z2697
18th April 2026, 18:16
Round to 8 bit and make diff (and then maybe ENHANCE it to make more visibility LOL)
But you can't really, if 8 bit source is encoded lossy in 10 bit it will have some "high depth" bits due to the, lossy nature.
Well, maybe not as much. You can have some guess based on the amount.

fmtconv has a filter nativetostack16.

But if just want to view it you might not need a frame server.
In FFmpeg there's a filter lets you see the bit plane.
ffplay -i vid -vf bitplanenoise=bitplane=1:filter=1

_Al_
19th April 2026, 05:33
Would not be the easiest just to see actual 10bit values?
If values are even, or rather divisible by four, it is fake, if values are more spread from 0 to 1023 they are real, just easy check in a previewer that shows actual pixel values.

Emulgator
19th April 2026, 18:25
Can you elaborate more? Like what do you look for from the convertToStack function?
ConvertToStacked() in AvsPmod presents the 8MSB plane on top of the 8LSB plane.
For a 10bit source the lower LSB plane will show bits 9 and 10 (better LSB and LSB+1)
If these are meaningful they will show moving patterns coinciding with the 8 bit content on top.
If these contain dither they will look like noise.
Perfect black bars or <no difference> will result in (invalid) yuv 0,0,0 decoded to RGB 0,77,0 green.

lansing
21st April 2026, 03:30
ConvertToStacked() in AvsPmod presents the 8MSB plane on top of the 8LSB plane.
For a 10bit source the lower LSB plane will show bits 9 and 10 (better LSB and LSB+1)
If these are meaningful they will show moving patterns coinciding with the 8 bit content on top.
If these contain dither they will look like noise.
Perfect black bars or <no difference> will result in (invalid) yuv 0,0,0 decoded to RGB 0,77,0 green.

Thanks. This is what I got from the ConvertToStacked function. Looks like my videos are all fake 10 bit.

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

_Al_
21st April 2026, 04:48
In vapoursynth this could be used to visualize if those last two bits are used in 10bit video:

import vapoursynth as vs
from vapoursynth import core
clip = core.ffms2.Source(r"E:/sources/10bit.mp4")
clip = core.akarin.Expr(clip, ["x 4 % not 512 x ?"])
clip.set_output()
It puts value to 512 for any plane, if value is divisible by 4 (no last two bits). So for up-scaled bits (8bit value is multiplied by four) it is all gray. If dithering, there might be noise. But for true 10bit video a patterns will emerge, same like in original video.

huhn
21st April 2026, 06:22
this is a waste of time with a lossy encoder.

the encoder will put something into that and that alone will make 10 bit "beneficial". if it is barely anything to quite a lot is a different story.

Z2697
21st April 2026, 22:10
this is a waste of time with a lossy encoder.

the encoder will put something into that and that alone will make 10 bit "beneficial". if it is barely anything to quite a lot is a different story.

Exactly.
At least 2 replies said this or similar and no OP didn't listen. :rolleyes:

short: You can not reliably.

But you can't really, if 8 bit source is encoded lossy in 10 bit it will have some "high depth" bits due to the, lossy nature.


This doesn't work as well for the same reason and more:
If these are meaningful they will show moving patterns coinciding with the 8 bit content on top.
If these contain dither they will look like noise.
Again lossy encoding, and the videos won't always have perfect smooth gradient for you to spot this way.
"Dither", strictly speaking, shouldn't and wouldn't be used (by most implementations) when converting from 8 to 10 (low to high).
So if the lossy encoding part is taken out, what you'll have left is "green screen" if "fake 10" or "anything" if "real 10".

huhn
22nd April 2026, 08:51
even lossless doing just a x4 is done by software but plain wrong and there is no need to dither to get better results.

uint8_t input_pixel = input
uint16_t output = input_pixel << 2
output = output + inputpixel >> 6

if you want the value not the data format.

Emulgator
22nd April 2026, 10:48
https://ibb.co/CpwPdm3D
Anybody ready to spot a 4 step gradient in this picture, worth 2 LSB bits ? Bleh.

huhn
22nd April 2026, 16:20
that's an RGB image...

just the conversation alone will add all that noise.

hello_hello
22nd April 2026, 21:29
Last week I encoded a video twice with x265 as 10 bit. The source was 8 bit.

The scripts were identical aside from the first one ending with this line:

ConvertBits(16).GradFun3Plus().ConvertBits(8, Dither=0)

While the second one ended with:

ConvertBits(16).GradFun3Plus().ConvertBits(10, Dither=0, Dither_Bits=8)

As they were both encoded as 10 bit using the same encoder settings and I'm quite sure the output file sizes were identical, it caused me to conclude/assume (maybe incorrectly?) that x265 converts an 8 bit input video to 10 bit before encoding it that way.

I'd added --profile main10 to the command line, which as far as I know produces the same result as --output-depth 10.

The x265 help file says:

--output-depth, -D 8|10|12
Bitdepth of output HEVC bitstream, which is also the internal bit depth of the encoder.

--input-depth <integer>
YUV only: Bit-depth of input file or stream
Values: any value between 8 and 16. Default is internal depth.

I can't imagine it'd be possible to reliably determine of a source was really 10 bit before it was encoded or if it was up-converted from 8 bit.

huhn
23rd April 2026, 04:12
I can't imagine it'd be possible to reliably determine of a source was really 10 bit before it was encoded or if it was up-converted from 8 bit.

the only chance to check would be a lossless encode with bad converted 8 bit to 10 bit.

HEVC uses 16 bit internal there where very old builds of HEVC 8 bit with 8 bit internal which are just bad. --output-depth has no massive impact anymore. cause HEVC uses 16 bit internal there is some benefit to --output-depth 10 12 no matter the source bit deep.

try AVC if you want to see massive difference. 10 bit AVC is a different beast.

and if your really want to know if they have the same size encode with one thread.

Z2697
24th April 2026, 10:26
HEVC uses 16 bit internal there where very old builds of HEVC 8 bit with 8 bit internal which are just bad. --output-depth has no massive impact anymore. cause HEVC uses 16 bit internal there is some benefit to --output-depth 10 12 no matter the source bit deep.

No, depending on the compile-time configuration,
The 3 supported depths are essentially same code compiled 3 times, each with different defines.

#if HIGH_BIT_DEPTH
typedef uint16_t pixel;
typedef uint32_t sum_t;
typedef uint64_t sum2_t;
typedef uint64_t pixel4;
typedef int64_t ssum2_t;
#define SHIFT_TO_BITPLANE 9
#else
typedef uint8_t pixel;
typedef uint16_t sum_t;
typedef uint32_t sum2_t;
typedef uint32_t pixel4;
typedef int32_t ssum2_t; // Signed sum
#define SHIFT_TO_BITPLANE 7
#endif // if HIGH_BIT_DEPTH

#if X265_DEPTH < 10
typedef uint32_t sse_t;
#else
typedef uint64_t sse_t;
#endif


There's basically no difference between how x264 and x265 handles 8b vs above.

Z2697
24th April 2026, 10:36
Last week I encoded a video twice with x265 as 10 bit. The source was 8 bit.

The scripts were identical aside from the first one ending with this line:

ConvertBits(16).GradFun3Plus().ConvertBits(8, Dither=0)

While the second one ended with:

ConvertBits(16).GradFun3Plus().ConvertBits(10, Dither=0, Dither_Bits=8)

As they were both encoded as 10 bit using the same encoder settings and I'm quite sure the output file sizes were identical, it caused me to conclude/assume (maybe incorrectly?) that x265 converts an 8 bit input video to 10 bit before encoding it that way.

I'd added --profile main10 to the command line, which as far as I know produces the same result as --output-depth 10.

The x265 help file says:

--output-depth, -D 8|10|12
Bitdepth of output HEVC bitstream, which is also the internal bit depth of the encoder.

--input-depth <integer>
YUV only: Bit-depth of input file or stream
Values: any value between 8 and 16. Default is internal depth.

I can't imagine it'd be possible to reliably determine of a source was really 10 bit before it was encoded or if it was up-converted from 8 bit.

The reason of this is not related to the topic, actually.
Your video is 8b (effective) in 10b, there's no difference if you pass this result to encoder or let encoder do the math.
The result is the same. Because the math works and it's the only (normal) way.

OP knows this already and asks about 8b in 10b vs 10b in 10b (a.k.a. just 10b?).

Z2697
24th April 2026, 10:38
https://ibb.co/CpwPdm3D
Anybody ready to spot a 4 step gradient in this picture, worth 2 LSB bits ? Bleh.

Now you convert this to 8b and encode it lossy as 10b and do the same.

Z2697
24th April 2026, 10:41
even lossless doing just a x4 is done by software but plain wrong and there is no need to dither to get better results.

uint8_t input_pixel = input
uint16_t output = input_pixel << 2
output = output + inputpixel >> 6

if you want the value not the data format.

This is one way of doing it, especially with full range input and output.
For limited range it's not plain wrong to do a mere x4. Actually it's plain correct.

huhn
24th April 2026, 12:00
No, depending on the compile-time configuration,
The 3 supported depths are essentially same code compiled 3 times, each with different defines.

#if HIGH_BIT_DEPTH
typedef uint16_t pixel;
typedef uint32_t sum_t;
typedef uint64_t sum2_t;
typedef uint64_t pixel4;
typedef int64_t ssum2_t;
#define SHIFT_TO_BITPLANE 9
#else
typedef uint8_t pixel;
typedef uint16_t sum_t;
typedef uint32_t sum2_t;
typedef uint32_t pixel4;
typedef int32_t ssum2_t; // Signed sum
#define SHIFT_TO_BITPLANE 7
#endif // if HIGH_BIT_DEPTH

#if X265_DEPTH < 10
typedef uint32_t sse_t;
#else
typedef uint64_t sse_t;
#endif


There's basically no difference between how x264 and x265 handles 8b vs above.

back in the very very old days with 3 executable x265 had a terrible build with lower internal precision (it was fast at the time) and a 16 bit internal precision build also for 8 bit. the 16 bit is now the default but wasn't.

that's one of the reasons the 10 bit AVC is massively better then 8 bit AVC they have different internal precisions.
This is one way of doing it, especially with full range input and output.
For limited range it's not plain wrong to do a mere x4. Actually it's plain correct.
to avoid any conversation you need to render Y as R, B and G in limited range. to get away with a simple x4 and look at it.
even with limited range to limited range you will not get away here thanks to the 240 cb and cr range.

Z2697
24th April 2026, 15:54
back in the very very old days with 3 executable x265 had a terrible build with lower internal precision (it was fast at the time) and a 16 bit internal precision build also for 8 bit. the 16 bit is now the default but wasn't.

that's one of the reasons the 10 bit AVC is massively better then 8 bit AVC they have different internal precisions.

to avoid any conversation you need to render Y as R, B and G in limited range. to get away with a simple x4 and look at it.
even with limited range to limited range you will not get away here thanks to the 240 cb and cr range.

There's no conversion involved in 8 to 10.
(235<<2) + (235>>6) is 943.
You don't know what you are talking about.

This thing is because 255 * 4 != 1023, very specific problem.
Limited to full or YUV to RGB don't need this.
And you can of course not give it a f*ck and it will be fine still.

huhn
24th April 2026, 16:30
There's no conversion involved in 8 to 10.
(235<<2) + (235>>6) is 943.
You don't know what you are talking about.

This thing is because 255 * 4 != 1023, very specific problem.
Limited to full or YUV to RGB don't need this.
And you can of course not give it a f*ck and it will be fine still.

ycbcr conversation it is lossy and creates massive noise. if you want to look into the image and want to make sure the lower last pixel are not used you can not do any conversation.

the only lossless conversation to RGB available so it can be looked at is limited range to limited range Y only.

Z2697
25th April 2026, 18:29
ycbcr conversation it is lossy and creates massive noise. if you want to look into the image and want to make sure the lower last pixel are not used you can not do any conversation.

the only lossless conversation to RGB available so it can be looked at is limited range to limited range Y only.

Stop mixing bitdepth and colorspace conversion ffs.

Z2697
25th April 2026, 18:36
https://ibb.co/CpwPdm3D
Anybody ready to spot a 4 step gradient in this picture, worth 2 LSB bits ? Bleh.

Now you convert this to 8b and encode it lossy as 10b and do the same.

Any teeny tiny distortion caused by lossy encoding will "leak" into LSB and "ruin" your view.

Also don't ignore that only a small portion of your image, where it's mostly smooth, have the obvious gradient, the rest is like noise.

(In addition to my reply as a new reply... because this is a new page now...)