X265 main10 profile doesn't seem to work

Started by xyzzy, October 06, 2020, 02:05:39 AM

Previous topic - Next topic

xyzzy

If I select the main10 profile with the x265 codec it doesn't seem to take effect.  I'm using a recent git version, 2.7.6-203-g5869b5f30, on Linux.

Output when starting the encode in avidemux followed by ffprobe's info on the encoded file:
x265 [info]: Main profile, Level-3.1 (Main tier)
    Stream #0:0: Video: hevc (Main), yuv420p(tv), 1280x720, SAR 1:1 DAR 16:9, 59.94 fps, 59.94 tbr, 1k tbn, 59.94 tbc (default)

And the same when using x265 from Fedora 32 on the command line:
x265 [info]: Main 10 profile, Level-4 (Main tier)
    Stream #0:0: Video: hevc (Main 10), yuv420p10le(tv), 1920x1080, 30 fps, 30 tbr, 1200k tbn, 30 tbc

eumagga0x2a

Avidemux indeed hardcodes internalBitDepth to 8 so that the main10 is overruled even if the library happens to supports high bit depths.

I'll check later when I'm on Fedora whether x265_max_bit_depth value allows to use bit depth > 8. On Debian, even if the library claims to support 10 and 12 bits, x265_max_bit_depth is 8 when used from Avidemux so that requesting internalBitDepth = 10 just results in a failure to create an encoder instance.

Regardless of library and encoder plugin capabilities, the internal image format in Avidemux is YV12 which is 8-bit, so there is no gain from using a higher bit depth.

Quote from: xyzzy on October 06, 2020, 02:05:39 AMI'm using a recent git version, 2.7.6-203-g5869b5f30, on Linux.

This git revision doesn't match any commit in the repository, so I'm somewhat puzzled. 2.7.6 cannot be recent anyway, a lot of development happend already after the version was incremented to 2.7.7.

xyzzy

#2
It looks like a build of libx265 is bit depth specific.  In order to support 10 bit encodes one either needs to link with the 10 bit library, which is limited to 10 bit only, or use the x265_api_get() interface to have the appropriate library dlopened.  But if one does the latter, then all access to libx265 needs to be through the api pointer and avidemux doesn't use that.  So it's a bunch of code changes to support 10 bit.

Quote from: eumagga0x2a on October 06, 2020, 04:35:54 PMthe internal image format in Avidemux is YV12 which is 8-bit, so there is no gain from using a higher bit depth.
I know the source is just 8 bit, but from what I've read about encoding with x265, there seem to be a lot of people who think 10 bit is better.  Since the deblock filter is part of the encoder/decoder, allowing it to operate at 10bit can help to reduce banding in uniform color gradients, even if the source is just 8 bit.

Quote from: eumagga0x2a on October 06, 2020, 04:35:54 PMThis git revision doesn't match any commit in the repository, so I'm somewhat puzzled. 2.7.6 cannot be recent anyway, a lot of development happend already after the version was incremented to 2.7.7.
That is odd, as it's clearly in git.  I'm using https://github.com/mean00/avidemux2.git  Here is the commit referenced.  You can see the sha1 hash matches.
commit 5869b5f30c1f259c77867f10dc27c1df9e73dde7
Author: eumagga0x2a <eumagga0x2a@users.noreply.github.com>
Date:   Fri Oct 2 00:11:14 2020 +0200

    [build/createDeb] Add libtwolame-dev as build dependency, remove libfaad-dev and libdca-dev as we prefer libavcodec, regroup packages for clarity
That is the hash referenced by the git describe string.  As to the version number, there is no git tag for 2.7.7.  The last one present is for 2.7.6.  So git describe can only use 2.7.6 as a reference.

eumagga0x2a

Obiously, I never heard of git-describe and misparsed the given reference as the result.

Quote from: xyzzy on October 06, 2020, 05:35:52 PMIn order to support 10 bit encodes one either needs to link with the 10 bit library, which is limited to 10 bit only, or use the x265_api_get() interface to have the appropriate library dlopened.  But if one does the latter, then all access to libx265 needs to be through the api pointer and avidemux doesn't use that.

I guess, you nailed it. libavcodec/libx265.c shows clearly how to do it right. Thanks for the tip :-)


eumagga0x2a

Should be fixed now.

Bit depth being tied to profile and thus not configurable in advanced mode is probably a bug.

xyzzy

I think it can be made configurable with advanced mode.  Maybe just a bit depth spinbox with, 8, 10, 12, 16.  I don't know if there is a way to determine what depths are supported without trying to get the api.  I think x265 doesn't know until it finds out if the `dlopen()` fails or not, and loading all the different x265 libs seems unnecessarily inefficient to disable depth options.

One could allow profile in advanced mode.  Just call `x265_param_apply_profile()` after putting in all the params.  But then it could be that a setting is turned on in the UI, but disabled anyway because of the profile, which would be confusing.

From what I see, the profile isn't like the presets and tunings, which configure the encode.  All the profile does is check a few things which aren't allowed.  There is a profile field in the encoded bitstream, but x265 sets that automatically based on the actual bitstream contents.  The profile setting doesn't matter.

Profile really doesn't do that much.  From what I see, it just checks:
  • Bit depth must be ≤ the profile depth.
  • Main profiles just support 4:2:0.  main422-* and main444-* can go up to named chroma subsampling.
  • The *-intra and msp profiles need keyint 1, i.e. they are I-frame only
The first two cause a failure, while the last is automatically adjusted.

eumagga0x2a

Are the msp profile and bit depth > 8 mutually exclusive?

xyzzy

There are other profiles for I-frame only and >8 depth.

There are "mailstillpicture", "msp", and "main-intra", which are all the same thing.

The only other "stillpicture" profiles are for "main444" and "main444-16".  Nothing for 10, 12, 4:2:2, etc.

But there are "*-intra" profiles for all the chroma and depth combos.  I don't know why main444(-16) get a stillpicture alias but none of the other ones do.

The keyint == 1 requirement doesn't apply to "main444-stillpicture" or "main444-16-stillpicture".  It applies to mainstillpicture and all the *-intra profiles, but not those two.  Probably a bug.

eumagga0x2a

Thank you very much for the plentiful input.

Quote from: xyzzy on October 09, 2020, 06:15:32 AMOne could allow profile in advanced mode.  Just call `x265_param_apply_profile()` after putting in all the params.  But then it could be that a setting is turned on in the UI, but disabled anyway because of the profile, which would be confusing.

Exactly that. In this sense, a bit depth spin- or combo box (is it theoretically possible to have just the 8 and 12, but not 10 bits lib present?) for the advanced mode only is a way to try out.

xyzzy

x265 only supports one bit depth at a time.  Each depth is a totally independent build of libx265.  If you want 8, 10, and 12, then you build the lib three times and make three shared lib files.  So one could have any combo of depths depending on what libs are built and installed.

The function to get the api will call dlopen() and try to load another libx265 library for another depth.

eumagga0x2a

Thanks, to summarize, spinbox is a no-go, combo box can be populated depending on libs x265_api_get can dlopen() (but does it dlclose() the others?).

xyzzy

It doesn't dlclose() as far as I can see.

eumagga0x2a

Thank you for the valuable research and input. I think that the benefit for UX from hiding unsupported modes justify the cost of wasted resources from probing here, so I've thrown together a patch to choose bit depth in advanced mode + to hide main10 profile if unavailable (that part entirely untested, probably broken).

Now I have to add decoding support for yuv420p12le, it doesn't look good that Avidemux cannot display its own output :-D

xyzzy

It could wait until someone picks the mode and then do a validation with libx265 in the onchange signal handler.  That way the cost of loading and relocating every library isn't paid each time the dialog is loaded when virtually no one is really ever going to use 16-bit depth.

eumagga0x2a

#14
libx265 libs are probed only once, the first time the x265 plugin configuration dialog is opened. The results are stored in a function-static variable and re-used in subsequent queries.

edit: The encoder configuration can be provided via project script, so that x265Dialog::upload(), called in the dialog constructor, needs to know whether to agree to put whatever bit depth is specified in the script or not.