diff -Nru x265-3.4/debian/changelog x265-3.5/debian/changelog --- x265-3.4/debian/changelog 2020-07-23 17:29:37.000000000 +0000 +++ x265-3.5/debian/changelog 2021-05-07 00:37:03.000000000 +0000 @@ -1,3 +1,23 @@ +x265 (3.5-0ubuntu1~18.04.sav0) bionic; urgency=medium + + * New upstream release + * SONAME bump: 192 -> 199 + * Enable HDR10+ (previously disabled due build failure when enabled): + - debian/rules: Uncomment previous ENABLE_DYNAMIC_HDR10=ON config flag, + change this to new ENABLE_HDR10_PLUS=ON as used by current source + + Change -Wl,--as-needed to -Wl,--no-as-needed (DEB_LDFLAGS_MAINT_APPEND) + to fix link failure (missing dlopen) when building with HDR10+ enabled + + Add FLAGS_8BIT = -DENABLE_SHARED=ON as without explicitly passing this + config flag the shared library is not built when compiling with HDR10+ + - debian/libx265-199.install: Add usr/lib/*/libhdr10plus.so + - debian/libx265-dev.install: Add usr/lib/*/libhdr10plus.a + * Update libx265 symbols from logs (ignore libhdr10plus symbols for now) + * debian/watch: Update for new URL (using git for version control) + * debian/control: Add git BD to fix FTBFS due reworked compile-time version + determination (source/cmake/Version.cmake) using new x265Version.txt file + + -- Rob Savoury Thu, 06 May 2021 17:37:03 -0700 + x265 (3.4-2~18.04.sav0) bionic; urgency=medium * Backport to Bionic diff -Nru x265-3.4/debian/control x265-3.5/debian/control --- x265-3.4/debian/control 2020-07-23 17:29:37.000000000 +0000 +++ x265-3.5/debian/control 2021-05-07 00:13:18.000000000 +0000 @@ -6,6 +6,7 @@ Build-Depends: debhelper-compat (= 11), cmake, + git, libnuma-dev [amd64 arm64 i386 mips mips64 mips64el mipsel powerpc ppc64el], nasm (>= 2.13) [amd64 kfreebsd-amd64] Build-Depends-Indep: @@ -43,7 +44,7 @@ Multi-Arch: same Depends: ${misc:Depends}, - libx265-192 (= ${binary:Version}) + libx265-199 (= ${binary:Version}) Suggests: libx265-doc Description: H.265/HEVC video stream encoder (development files) @@ -53,7 +54,7 @@ This is the development package which contains headers and libraries for libx265. -Package: libx265-192 +Package: libx265-199 Section: libs Architecture: any Multi-Arch: same diff -Nru x265-3.4/debian/libx265-192.install x265-3.5/debian/libx265-192.install --- x265-3.4/debian/libx265-192.install 2020-06-21 15:52:15.000000000 +0000 +++ x265-3.5/debian/libx265-192.install 1970-01-01 00:00:00.000000000 +0000 @@ -1 +0,0 @@ -usr/lib/*/libx265.so.* diff -Nru x265-3.4/debian/libx265-192.symbols x265-3.5/debian/libx265-192.symbols --- x265-3.4/debian/libx265-192.symbols 2020-06-21 16:12:48.000000000 +0000 +++ x265-3.5/debian/libx265-192.symbols 1970-01-01 00:00:00.000000000 +0000 @@ -1,51 +0,0 @@ -libx265.so.192 libx265-192 #MINVER# -| libx265-192 (>= 3.4), libx265-192 (<< 3.5) -* Build-Depends-Package: libx265-dev - x265_alloc_analysis_data@Base 2.9 - x265_api_get_192@Base 3.2 - x265_api_query@Base 1.8 - x265_build_info_str@Base 1.4 - x265_cleanup@Base 1.4 - x265_csvlog_encode@Base 2.6 - x265_csvlog_frame@Base 2.6 - x265_csvlog_open@Base 2.6 - x265_dither_image@Base 2.6 - x265_encoder_close@Base 1.4 - x265_encoder_ctu_info@Base 2.5 - x265_encoder_encode@Base 1.4 - x265_encoder_get_stats@Base 1.4 - x265_encoder_headers@Base 1.4 - x265_encoder_intra_refresh@Base 1.9 - x265_encoder_log@Base 1.4 - x265_encoder_open_192@Base 3.2 - x265_encoder_parameters@Base 1.4 - x265_encoder_reconfig@Base 1.7 - x265_encoder_reconfig_zone@Base 3.4 - x265_free_analysis_data@Base 2.9 - x265_get_ref_frame_list@Base 2.6 - x265_get_slicetype_poc_and_scenecut@Base 2.6 - x265_max_bit_depth@Base 1.4 - x265_param_alloc@Base 1.4 - x265_param_apply_profile@Base 1.4 - x265_param_default@Base 1.4 - x265_param_default_preset@Base 1.4 - x265_param_free@Base 1.4 - x265_param_parse@Base 1.4 - x265_picture_alloc@Base 1.4 - x265_picture_free@Base 1.4 - x265_picture_init@Base 1.4 - x265_set_analysis_data@Base 2.6 - x265_version_str@Base 1.4 - x265_zone_alloc@Base 3.1 - x265_zone_free@Base 3.1 - x265_zone_param_parse@Base 3.0 - (optional)x265_cpu_cpuid@Base 0 1 - (optional)x265_cpu_cpuid_test@Base 0 1 - (optional)x265_cpu_emms@Base 0 1 - (optional)x265_cpu_fast_neon_mrc_test@Base 0 1 - (optional)x265_cpu_neon_test@Base 0 1 - (optional)x265_cpu_xgetbv@Base 0 1 - (optional)x265_entropyStateBits@Base 0 1 - (optional)x265_intel_cpu_indicator_init@Base 0 1 - (regex|optional)"^x265_(10|12)bit_.*@Base$" 0 1 - (regex|c++|optional)"^.*@Base$" 0 1 diff -Nru x265-3.4/debian/libx265-199.install x265-3.5/debian/libx265-199.install --- x265-3.4/debian/libx265-199.install 1970-01-01 00:00:00.000000000 +0000 +++ x265-3.5/debian/libx265-199.install 2021-05-06 23:47:42.000000000 +0000 @@ -0,0 +1,2 @@ +usr/lib/*/libhdr10plus.so +usr/lib/*/libx265.so.* diff -Nru x265-3.4/debian/libx265-199.symbols x265-3.5/debian/libx265-199.symbols --- x265-3.4/debian/libx265-199.symbols 1970-01-01 00:00:00.000000000 +0000 +++ x265-3.5/debian/libx265-199.symbols 2021-05-07 00:12:56.000000000 +0000 @@ -0,0 +1,51 @@ +libx265.so.199 libx265-199 #MINVER# +| libx265-199 (>= 3.5), libx265-199 (<< 3.6) +* Build-Depends-Package: libx265-dev + x265_alloc_analysis_data@Base 2.9 + x265_api_get_199@Base 3.5 + x265_api_query@Base 1.8 + x265_build_info_str@Base 1.4 + x265_cleanup@Base 1.4 + x265_csvlog_encode@Base 2.6 + x265_csvlog_frame@Base 2.6 + x265_csvlog_open@Base 2.6 + x265_dither_image@Base 2.6 + x265_encoder_close@Base 1.4 + x265_encoder_ctu_info@Base 2.5 + x265_encoder_encode@Base 1.4 + x265_encoder_get_stats@Base 1.4 + x265_encoder_headers@Base 1.4 + x265_encoder_intra_refresh@Base 1.9 + x265_encoder_log@Base 1.4 + x265_encoder_open_199@Base 3.5 + x265_encoder_parameters@Base 1.4 + x265_encoder_reconfig@Base 1.7 + x265_encoder_reconfig_zone@Base 3.4 + x265_free_analysis_data@Base 2.9 + x265_get_ref_frame_list@Base 2.6 + x265_get_slicetype_poc_and_scenecut@Base 2.6 + x265_max_bit_depth@Base 1.4 + x265_param_alloc@Base 1.4 + x265_param_apply_profile@Base 1.4 + x265_param_default@Base 1.4 + x265_param_default_preset@Base 1.4 + x265_param_free@Base 1.4 + x265_param_parse@Base 1.4 + x265_picture_alloc@Base 1.4 + x265_picture_free@Base 1.4 + x265_picture_init@Base 1.4 + x265_set_analysis_data@Base 2.6 + x265_version_str@Base 1.4 + x265_zone_alloc@Base 3.1 + x265_zone_free@Base 3.1 + x265_zone_param_parse@Base 3.0 + (optional)x265_cpu_cpuid@Base 0 1 + (optional)x265_cpu_cpuid_test@Base 0 1 + (optional)x265_cpu_emms@Base 0 1 + (optional)x265_cpu_fast_neon_mrc_test@Base 0 1 + (optional)x265_cpu_neon_test@Base 0 1 + (optional)x265_cpu_xgetbv@Base 0 1 + (optional)x265_entropyStateBits@Base 0 1 + (optional)x265_intel_cpu_indicator_init@Base 0 1 + (regex|optional)"^x265_(10|12)bit_.*@Base$" 0 1 + (regex|c++|optional)"^.*@Base$" 0 1 diff -Nru x265-3.4/debian/libx265-dev.install x265-3.5/debian/libx265-dev.install --- x265-3.4/debian/libx265-dev.install 2016-08-16 16:35:12.000000000 +0000 +++ x265-3.5/debian/libx265-dev.install 2021-05-06 23:47:34.000000000 +0000 @@ -1,4 +1,5 @@ usr/include/* +usr/lib/*/libhdr10plus.a usr/lib/*/libx265.a usr/lib/*/libx265.so usr/lib/*/pkgconfig diff -Nru x265-3.4/debian/rules x265-3.5/debian/rules --- x265-3.4/debian/rules 2020-06-21 15:52:15.000000000 +0000 +++ x265-3.5/debian/rules 2021-05-07 00:13:18.000000000 +0000 @@ -4,7 +4,7 @@ export DEB_BUILD_MAINT_OPTIONS=hardening=+all -export DEB_LDFLAGS_MAINT_APPEND=-Wl,--as-needed \ +export DEB_LDFLAGS_MAINT_APPEND=-Wl,--no-as-needed \ -L$(CURDIR)/x265-10bit \ -L$(CURDIR)/x265-12bit # see #789111 @@ -13,8 +13,9 @@ export DEB_CPPFLAGS_MAINT_APPEND=$(shell getconf LFS_CFLAGS) FLAGS = -DENABLE_PIC=ON -# currently fails to build -# FLAGS += -DENABLE_DYNAMIC_HDR10=ON +# HDR+ is now building fine +FLAGS += -DENABLE_HDR10_PLUS=ON +FLAGS_8BIT = -DENABLE_SHARED=ON FLAGS_OTHERBIT = -DENABLE_CLI=OFF FLAGS_OTHERBIT += -DENABLE_SHARED=OFF FLAGS_OTHERBIT += -DEXPORT_C_API=OFF diff -Nru x265-3.4/debian/watch x265-3.5/debian/watch --- x265-3.4/debian/watch 2018-04-17 18:13:05.000000000 +0000 +++ x265-3.5/debian/watch 2021-05-06 15:37:54.000000000 +0000 @@ -1,3 +1,3 @@ version=3 -http://ftp.videolan.org/pub/videolan/x265/ \ +https://bitbucket.org/multicoreware/x265_git/downloads/ \ x265_(\d.*).tar.gz diff -Nru x265-3.4/doc/reST/cli.rst x265-3.5/doc/reST/cli.rst --- x265-3.4/doc/reST/cli.rst 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/doc/reST/cli.rst 2021-03-16 12:53:00.000000000 +0000 @@ -36,13 +36,26 @@ .. option:: --help, -h - Display help text + Displays help text **CLI ONLY** .. option:: --version, -V - Display version details + Displays version details in the following manner *[Version Name]+/-[Number of commits from the release changeset]-/+[repository's head changeset SHA-1 paraphrase identifier]* + along with the compilation platform, build information and supported cpu capabilities. + + In case of release tar balls version information is partly derived from configuration file *x265Version.txt* + .. seeAlso:: For more information on how to configure the version file please refer to ``_ and Contribute pages for updates specific + release and version control management. + + **Example:** + + *x265 [info]: HEVC encoder version 3.4+27-'d9217cf00'* + + *x265 [info]: build info [Windows][MSVC 1916][64 bit] 10bit* + + *x265 [info]: using cpu capabilities: MMX2 SSE2Fast LZCNT SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2* **CLI ONLY** @@ -141,7 +154,7 @@ **Residual Energy** Average residual energy. SSE is calculated on fenc and pred(before quantization). - **Luma/Chroma Values** minumum, maximum and average(averaged by area) + **Luma/Chroma Values** minimum, maximum and average(averaged by area) luma and chroma values of source for each frame. **PU Statistics** percentage of PU modes at each depth. @@ -246,7 +259,7 @@ .. option:: --pools , --numa-pools - Comma seperated list of threads per NUMA node. If "none", then no worker + Comma separated list of threads per NUMA node. If "none", then no worker pools are created and only frame parallelism is possible. If NULL or "" (default) x265 will use all available threads on each NUMA node:: @@ -284,7 +297,7 @@ the last thread pool is spawned only if it has more than 32 threads for 64-bit machines, or 16 for 32-bit machines. If the total number of threads in the system doesn't obey this constraint, we may spawn fewer threads - than cores which has been emperically shown to be better for performance. + than cores which has been empirically shown to be better for performance. If the four pool features: :option:`--wpp`, :option:`--pmode`, :option:`--pme` and :option:`--lookahead-slices` are all disabled, @@ -409,7 +422,7 @@ Allow encoder to copy input x265 pictures to internal frame buffers. When disabled, x265 will not make an internal copy of the input picture and will work with the - application's buffers. While this allows for deeper integration, it is the responsbility + application's buffers. While this allows for deeper integration, it is the responsibility of the application to (a) ensure that the allocated picture has extra space for padding that will be done by the library, and (b) the buffers aren't recycled until the library has completed encoding this frame (which can be figured out by tracking NALs output by x265) @@ -554,7 +567,7 @@ .. option:: --chunk-start - First frame of the chunk. Frames preceeding this in display order will + First frame of the chunk. Frames preceding this in display order will be encoded, however, they will be discarded in the bitstream. This feature can be enabled only in closed GOP structures. Default 0 (disabled). @@ -562,7 +575,7 @@ .. option:: --chunk-end Last frame of the chunk. Frames following this in display order will be - used in taking lookahead decisions, but, they will not be encoded. + used in taking lookahead decisions, but they will not be encoded. This feature can be enabled only in closed GOP structures. Default 0 (disabled). @@ -638,7 +651,7 @@ If :option:`--level-idc` has been specified, --high-tier allows the support of high tier at that level. The encoder will first attempt to encode at the specified level, main tier first, turning on high tier only if - necessary and available at that level.If your requested level does not + necessary and available at that level. If your requested level does not support a High tier, high tier will not be supported. If --no-high-tier has been specified, then the encoder will attempt to encode only at the main tier. @@ -647,8 +660,8 @@ .. option:: --ref <1..16> Max number of L0 references to be allowed. This number has a linear - multiplier effect on the amount of work performed in motion search, - but will generally have a beneficial affect on compression and + multiplier effect on the amount of work performed in motion search + but will generally have a beneficial effect on compression and distortion. Note that x265 allows up to 16 L0 references but the HEVC @@ -668,7 +681,7 @@ .. option:: --allow-non-conformance, --no-allow-non-conformance Allow libx265 to generate a bitstream with profile and level NONE. - By default it will abort any encode which does not meet strict level + By default, it will abort any encode which does not meet strict level compliance. The two most likely causes for non-conformance are :option:`--ctu` being too small, :option:`--ref` being too high, or the bitrate or resolution being out of specification. @@ -727,7 +740,7 @@ used. The lower the value the faster the encode, the higher the value the smaller the bitstream (in general). Default 3 - Note that this table aims for accuracy, but is not necessarily our + Note that this table aims for accuracy but is not necessarily our final target behavior for each mode. +-------+---------------------------------------------------------------+ @@ -758,7 +771,7 @@ Maximum CU size (width and height). The larger the maximum CU size, the more efficiently x265 can encode flat areas of the picture, - giving large reductions in bitrate. However this comes at a loss of + giving large reductions in bitrate. However, this comes at a loss of parallelism with fewer rows of CUs that can be encoded in parallel, and less frame parallelism as well. Because of this the faster presets use a CU size of 32. Default: 64 @@ -799,7 +812,7 @@ For all non-zero values of limit-refs, the current depth will evaluate intra mode (in inter slices), only if intra mode was chosen as the best - mode for atleast one of the 4 sub-blocks. + mode for at least one of the 4 sub-blocks. You can often increase the number of references you are using (within your decoder level limits) if you enable one or @@ -863,13 +876,12 @@ Provides minimal quality degradation at good performance gains for non-zero modes. :option:`--rskip mode 0` means disabled. Default: 1, disabled when :option:`--tune grain` is used. - This is a integer value representing the edge-density percentage within the CU. Internally normalized to a number between 0.0 to 1.0 in x265. - Recommended low thresholds for slow encodes and high for fast encodes. .. option:: --rskip-edge-threshold <0..100> Denotes the minimum expected edge-density percentage within the CU, below which the recursion is skipped. - Default: 5, requires :option:`--rskip mode 2` to be enabled. + Internally normalized to decimal value in x265 library. Recommended low thresholds for slow encodes and high + for fast encodes. Default: 5, requires :option:`--rskip mode 2` to be enabled. .. option:: --splitrd-skip, --no-splitrd-skip @@ -928,7 +940,7 @@ .. option:: --analysis-load - Encoder reuses analysis information from the file specified. By reading the analysis data writen by + Encoder reuses analysis information from the file specified. By reading the analysis data written by an earlier encode of the same sequence, substantial redundant work may be avoided. Requires cutree, pmode to be off. Default disabled. @@ -1082,7 +1094,7 @@ Note that when the CU intra prediction is NxN (only possible with 8x8 CUs), a TU split is implied, and thus the residual quad-tree - begins at 4x4 and cannot split any futhrer. + begins at 4x4 and cannot split any further. .. option:: --tu-inter-depth <1..4> @@ -1101,7 +1113,7 @@ Enables early exit from TU depth recursion, for inter coded blocks. Level 1 - decides to recurse to next higher depth based on cost - comparison of full size TU and split TU. + comparison of full-size TU and split TU. Level 2 - based on first split subTU's depth, limits recursion of other split subTUs. @@ -1109,13 +1121,13 @@ Level 3 - based on the average depth of the co-located and the neighbor CUs' TU depth, limits recursion of the current CU. - Level 4 - uses the depth of the neighbouring/ co-located CUs TU depth + Level 4 - uses the depth of the neighboring/ co-located CUs TU depth to limit the 1st subTU depth. The 1st subTU depth is taken as the limiting depth for the other subTUs. Enabling levels 3 or 4 may cause a mismatch in the output bitstreams between :option:`--analysis-save` and :option:`--analysis-load` - as all neighbouring CUs TU depth may not be available in the + as all neighboring CUs TU depth may not be available in the :option:`--analysis-load` run as only the best mode's information is available to it. @@ -1216,14 +1228,14 @@ Motion search method. Generally, the higher the number the harder the ME method will try to find an optimal match. Diamond search is the simplest. Hexagon search is a little better. Uneven - Multi-Hexegon is an adaption of the search method used by x264 for - slower presets. Star is a three step search adapted from the HM + Multi-Hexagon is an adaption of the search method used by x264 for + slower presets. Star is a three-step search adapted from the HM encoder: a star-pattern search followed by an optional radix scan followed by an optional star-search refinement. Full is an exhaustive search; an order of magnitude slower than all other searches but not much better than umh or star. SEA is similar to x264's ESA implementation and a speed optimization of full search. - It is a three step motion search where the DC calculation is + It is a three-step motion search where the DC calculation is followed by ADS calculation followed by SAD of the passed motion vector candidates. @@ -1262,7 +1274,7 @@ At --subme values larger than 2, chroma residual cost is included in all subpel refinement steps and chroma residual is included in all motion estimation decisions (selecting the best reference - picture in each list, and chosing between merge, uni-directional + picture in each list, and choosing between merge, uni-directional motion and bi-directional motion). The 'slow' preset is the first preset to enable the use of chroma residual. @@ -1356,7 +1368,7 @@ do not match the visual energy of the source block. The higher the strength of :option:`--psy-rd` the more strongly it will favor similar energy over blur and the more aggressively it will ignore rate -distortion. If it is too high, it will introduce visal artifacts and +distortion. If it is too high, it will introduce visual artifacts and increase bitrate enough for rate control to increase quantization globally, reducing overall quality. psy-rd will tend to reduce the use of blurred prediction modes, like DC and planar intra and bi-directional @@ -1366,11 +1378,11 @@ rate-distortion optimized quantization (RDO quant), enabled by :option:`--rdoq-level` 1 or 2, favoring the preservation of energy in the reconstructed image. :option:`--psy-rdoq` prevents RDOQ from blurring -all of the encoding options which psy-rd has to chose from. At low +all of the encoding options which psy-rd has to choose from. At low strength levels, psy-rdoq will influence the quantization level decisions, favoring higher AC energy in the reconstructed image. As psy-rdoq strength is increased, more non-zero coefficient levels are -added and fewer coefficients are zeroed by RDOQ's rate distortion +added, and fewer coefficients are zeroed by RDOQ's rate distortion analysis. High levels of psy-rdoq can double the bitrate which can have a drastic effect on rate control, forcing higher overall QP, and can cause ringing artifacts. psy-rdoq is less accurate than psy-rd, it is @@ -1394,16 +1406,16 @@ is forced to code skip blocks (no residual) in areas of difficult motion because it is the best option psycho-visually (they have great amounts of energy and no residual cost). One can lower psy-rd settings when -judder is happening, and allow the encoder to use some blur in these +judder is happening and allow the encoder to use some blur in these areas of high motion. In 444, chroma gets twice as much resolution, so halve the quality when psy-rd is enabled. -So when psy-rd is enabled for 444 videos, cbQpOffset and crQpOffset are set to value 6, +So, when psy-rd is enabled for 444 videos, cbQpOffset and crQpOffset are set to value 6, if they are not explicitly set. .. option:: --psy-rd - Influence rate distortion optimizated mode decision to preserve the + Influence rate distortion optimized mode decision to preserve the energy of the source image in the encoded image at the expense of compression efficiency. It only has effect on presets which use RDO-based mode decisions (:option:`--rd` 3 and above). 1.0 is a @@ -1462,19 +1474,23 @@ .. option:: --hist-scenecut, --no-hist-scenecut Indicates that scenecuts need to be detected using luma edge and chroma histograms. - :option: `--hist-scenecut` enables scenecut detection using the histograms and disables the default scene cut algorithm. - :option: `--no-hist-scenecut` disables histogram based scenecut algorithm. + :option:`--hist-scenecut` enables scenecut detection using the histograms and disables the default scene cut algorithm. + :option:`--no-hist-scenecut` disables histogram based scenecut algorithm. -.. option:: --hist-threshold <0.0..2.0> +.. option:: --hist-threshold <0.0..1.0> This value represents the threshold for normalized SAD of edge histograms used in scenecut detection. - This requires :option: `--hist-scenecut` to be enabled. For example, a value of 0.2 indicates that a frame with normalized SAD value + This requires :option:`--hist-scenecut` to be enabled. For example, a value of 0.2 indicates that a frame with normalized SAD value greater than 0.2 against the previous frame as scenecut. - Default 0.01. + Increasing the threshold reduces the number of scenecuts detected. + Default 0.03. .. option:: --radl - Number of RADL pictures allowed infront of IDR. Requires fixed keyframe interval. + Number of RADL pictures allowed infront of IDR. Requires closed gop interval. + If enabled for fixed keyframe interval, inserts RADL at every IDR. + If enabled for closed gop interval, in case of :option:`--hist-scenecut` inserts RADL at every hard scenecut + whereas for the :option:`--scenecut`, inserts RADL at every scenecut. Recommended value is 2-3. Default 0 (disabled). **Range of values: Between 0 and `--bframes` @@ -1501,7 +1517,7 @@ Number of frames for slice-type decision lookahead (a key determining factor for encoder latency). The longer the lookahead buffer the more accurate scenecut decisions will be, and the more - effective cuTree will be at improving adaptive quant. Having a + effective cutree will be at improving adaptive quant. Having a lookahead larger than the max keyframe interval is not helpful. Default 20 @@ -1510,7 +1526,7 @@ .. option:: --gop-lookahead Number of frames for GOP boundary decision lookahead. If a scenecut frame is found - within this from the gop boundary set by `--keyint`, the GOP will be extented until such a point, + within this from the gop boundary set by `--keyint`, the GOP will be extended until such a point, otherwise the GOP will be terminated as set by `--keyint`. Default 0. **Range of values:** Between 0 and (`--rc-lookahead` - mini-GOP length) @@ -1629,7 +1645,7 @@ .. option:: --crf-min <0..51.0> - Specify an lower limit to the rate factor which may be assigned to + Specify a lower limit to the rate factor which may be assigned to any given frame (ensuring a min compression factor). .. option:: --vbv-bufsize @@ -1656,7 +1672,7 @@ Initial buffer occupancy. The portion of the decode buffer which must be full before the decoder will begin decoding. Determines absolute maximum frame size. May be specified as a fractional value - between 0 and 1, or in kbits. In other words these two option pairs + between 0 and 1, or in kbits. In other words, these two option pairs are equivalent:: --vbv-bufsize 1000 --vbv-init 900 @@ -1668,8 +1684,8 @@ .. option:: --vbv-end - Final buffer emptiness. The portion of the decode buffer that must be - available after all the specified frames have been inserted into the + Final buffer fullness. The portion of the decode buffer that must be + full after all the specified frames have been inserted into the decode buffer. Specified as a fractional value between 0 and 1, or in kbits. Default 0 (disabled) @@ -1681,8 +1697,26 @@ .. option:: --vbv-end-fr-adj Frame from which qp has to be adjusted to achieve final decode buffer - emptiness. Specified as a fraction of the total frames. Fractions > 0 are + fullness. Specified as a fraction of the total frames. Fractions > 0 are supported only when the total number of frames is known. Default 0. + +.. option:: --min-vbv-fullness + + Minimum VBV fullness percentage to be maintained. Specified as a fractional + value ranging between 0 and 100. Default 50 i.e, Tries to keep the buffer at least + 50% full at any point in time. + + Decreasing the minimum required fullness shall improve the compression efficiency, + but is expected to affect VBV conformance. Experimental option. + +.. option:: --max-vbv-fullness + + Maximum VBV fullness percentage to be maintained. Specified as a fractional + value ranging between 0 and 100. Default 80 i.e Tries to keep the buffer at max 80% + full at any point in time. + + Increasing the minimum required fullness shall improve the compression efficiency, + but is expected to affect VBV conformance. Experimental option. .. option:: --qp, -q @@ -1710,7 +1744,7 @@ Adaptive Quantization operating mode. Raise or lower per-block quantization based on complexity analysis of the source image. The - more complex the block, the more quantization is used. This offsets + more complex the block, the more quantization is used. These offsets the tendency of the encoder to spend too many bits on complex areas and not enough in flat areas. @@ -1737,8 +1771,8 @@ Enable adaptive quantization It scales the quantization step size according to the spatial activity of one coding unit relative to frame average spatial activity. This AQ method utilizes - the minimum variance of sub-unit in each coding unit to represent the coding - unit’s spatial complexity. + the minimum variance of sub-unit in each coding unit to represent the spatial + complexity of the coding unit. .. option:: --qp-adaptation-range @@ -1938,31 +1972,91 @@ The frame number indicates the beginning of a zone. The options following this is applied until another zone begins. The reconfigurable - options can be spcified as -- + options can be specified as -- **CLI ONLY** -.. option:: --scenecut-aware-qp, --no-scenecut-aware-qp - - Enables a ratecontrol algorithm for reducing the bits spent on the inter-frames - within the :option:`--scenecut-window` after a scenecut by increasing their QP - without any deterioration in visual quality. It also increases the quality of - scenecut I-Frames by reducing their QP. Default disabled. - -.. option:: --scenecut-window +.. option:: --scenecut-aware-qp - The duration(in milliseconds) for which there is a reduction in the bits spent - on the inter-frames after a scenecut by increasing their QP, when - :option:`--scenecut-aware-qp` is enabled. Default 500ms. - - **Range of values:** 0 to 1000 - -.. option:: --max-qp-delta + It reduces the bits spent on the inter-frames within the scenecut window + before and after a scenecut by increasing their QP in ratecontrol pass2 algorithm + without any deterioration in visual quality. If a scenecut falls within the window, + the QP of the inter-frames after this scenecut will not be modified. + :option:`--scenecut-aware-qp` works only with --pass 2. Default 0. - The offset by which QP is incremented for inter-frames - when :option:`--scenecut-aware-qp` is enabled. Default 5. - - **Range of values:** 0 to 10 + +-------+---------------------------------------------------------------+ + | Mode | Description | + +=======+===============================================================+ + | 0 | Disabled. | + +-------+---------------------------------------------------------------+ + | 1 | Forward masking. | + | | Applies QP modification for frames after the scenecut. | + +-------+---------------------------------------------------------------+ + | 2 | Backward masking. | + | | Applies QP modification for frames before the scenecut. | + +-------+---------------------------------------------------------------+ + | 3 | Bi-directional masking. | + | | Applies QP modification for frames before and after | + | | the scenecut. | + +-------+---------------------------------------------------------------+ + +.. option:: --masking-strength + + Comma separated list of values which specifies the duration and offset + for the QP increment for inter-frames when :option:`--scenecut-aware-qp` + is enabled. + + When :option:`--scenecut-aware-qp` is:: + * 1 (Forward masking): + --masking-strength + * 2 (Backward masking): + --masking-strength + * 3 (Bi-directional masking): + --masking-strength + + +-----------------+---------------------------------------------------------------+ + | Parameter | Description | + +=================+===============================================================+ + | fwdWindow | The duration(in milliseconds) for which there is a reduction | + | | in the bits spent on the inter-frames after a scenecut by | + | | increasing their QP. Default 500ms. | + | | **Range of values:** 0 to 1000 | + +-----------------+---------------------------------------------------------------+ + | fwdRefQPDelta | The offset by which QP is incremented for inter-frames | + | | after a scenecut. Default 5. | + | | **Range of values:** 0 to 10 | + +-----------------+---------------------------------------------------------------+ + | fwdNonRefQPDelta| The offset by which QP is incremented for non-referenced | + | | inter-frames after a scenecut. The offset is computed from | + | | fwdRefQPDelta when it is not explicitly specified. | + | | **Range of values:** 0 to 10 | + +-----------------+---------------------------------------------------------------+ + | bwdWindow | The duration(in milliseconds) for which there is a reduction | + | | in the bits spent on the inter-frames before a scenecut by | + | | increasing their QP. Default 100ms. | + | | **Range of values:** 0 to 1000 | + +-----------------+---------------------------------------------------------------+ + | bwdRefQPDelta | The offset by which QP is incremented for inter-frames | + | | before a scenecut. The offset is computed from | + | | fwdRefQPDelta when it is not explicitly specified. | + | | **Range of values:** 0 to 10 | + +-----------------+---------------------------------------------------------------+ + | bwdNonRefQPDelta| The offset by which QP is incremented for non-referenced | + | | inter-frames before a scenecut. The offset is computed from | + | | bwdRefQPDelta when it is not explicitly specified. | + | | **Range of values:** 0 to 10 | + +-----------------+---------------------------------------------------------------+ + + **CLI ONLY** + +.. option:: --vbv-live-multi-pass, --no-vbv-live-multi-pass + + It enables the Qp tuning at frame level based on real time VBV Buffer fullness + in the ratecontrol 2nd pass of multi pass mode to reduce the VBV violations. + It could only be enabled with rate control stat-read encodes with VBV and ABR + rate control mode. + + Default disabled. **Experimental feature** Quantization Options ==================== @@ -2010,7 +2104,7 @@ All other strings indicate a filename containing custom scaling lists in the HM format. The encode will abort if the file is not parsed correctly. Custom lists must be signaled in the SPS. A sample - scaling list file is available in `the downloads page `_ + scaling list file is available in `the downloads page `_ .. option:: --lambda-file @@ -2064,7 +2158,7 @@ .. option:: --sao-non-deblock, --no-sao-non-deblock - Specify how to handle depencency between SAO and deblocking filter. + Specify how to handle dependency between SAO and deblocking filter. When enabled, non-deblocked pixels are used for SAO analysis. When disabled, SAO analysis skips the right/bottom boundary areas. Default disabled @@ -2154,7 +2248,7 @@ 2. ntsc 3. secam 4. mac - 5. undefined + 5. unknown .. option:: --range @@ -2207,15 +2301,15 @@ Specify color matrix setting i.e set the matrix coefficients used in deriving the luma and chroma. Default undefined (not signaled) - 0. GBR + 0. gbr 1. bt709 - 2. undef + 2. unknown 3. **reserved** 4. fcc 5. bt470bg 6. smpte170m 7. smpte240m - 8. YCgCo + 8. ycgco 9. bt2020nc 10. bt2020c 11. smpte2085 @@ -2297,7 +2391,7 @@ to be encoded as Dynamic Tone Mapping into the bitstream. Click `here `_ - for the syntax of the metadata file. A sample JSON file is available in `the downloads page `_ + for the syntax of the metadata file. A sample JSON file is available in `the downloads page `_ .. option:: --dhdr10-opt, --no-dhdr10-opt @@ -2325,13 +2419,13 @@ Emit the alternative transfer characteristics SEI message where the integer is the preferred transfer characteristics. Required for HLG (Hybrid Log Gamma) - signalling. Not signalled by default. + signaling. Not signaled by default. .. option:: --pic-struct Set the picture structure and emits it in the picture timing SEI message. Values in the range 0..12. See D.3.3 of the HEVC spec. for a detailed explanation. - Required for HLG (Hybrid Log Gamma) signalling. Not signalled by default. + Required for HLG (Hybrid Log Gamma) signaling. Not signaled by default. Bitstream options ================= @@ -2362,7 +2456,7 @@ .. option:: --hrd, --no-hrd - Enable the signalling of HRD parameters to the decoder. The HRD + Enable the signaling of HRD parameters to the decoder. The HRD parameters are carried by the Buffering Period SEI messages and Picture Timing SEI messages providing timing information to the decoder. Default disabled @@ -2370,7 +2464,7 @@ .. option:: --hrd-concat, --no-hrd-concat - Set concantenation flag for the first keyframe in the HRD buffering period SEI. This + Set concatenation flag for the first keyframe in the HRD buffering period SEI. This is to signal the decoder if splicing is performed during bitstream generation. Recommended to enable this option during chunked encoding, except for the first chunk. Default disabled. @@ -2419,7 +2513,7 @@ Enable a temporal sub layer. All referenced I/P/B frames are in the base layer and all unreferenced B frames are placed in a temporal - enhancement layer. A decoder may chose to drop the enhancement layer + enhancement layer. A decoder may choose to drop the enhancement layer and only decode and display the base layer slices. If used with a fixed GOP (:option:`--b-adapt` 0) and :option:`--bframes` @@ -2457,7 +2551,7 @@ .. option:: --opt-cu-delta-qp, --no-opt-cu-delta-qp Optimize CU level QPs by pulling up lower QPs to value close to meanQP thereby - minimizing fluctuations in deltaQP signalling. Default disabled. + minimizing fluctuations in deltaQP signaling. Default disabled. Only effective at RD levels 5 and 6 @@ -2476,10 +2570,10 @@ .. option:: --lowpass-dct If enabled, x265 will use low-pass subband dct approximation instead of the - standard dct for 16x16 and 32x32 blocks. This approximation is less computational + standard dct for 16x16 and 32x32 blocks. This approximation is less computationally intensive but it generates truncated coefficient matrixes for the transformed block. Empirical analysis shows marginal loss in compression and performance gains up to 10%, - paticularly at moderate bit-rates. + particularly at moderate bit-rates. This approximation should be considered for platforms with performance and time constrains. @@ -2536,10 +2630,15 @@ if analysis reuse isn't preferred ), and reuse-level indicates the level ( :option:`--analysis-load-reuse-level`) at which analysis info has to be reused. - A sample config file is available in `the downloads page `_ - - Default: Disabled ( Conventional single encode generation ). Experimental feature. + Sample config file:: + + [540p:0:nil] --input 540pSource.y4m --ctu 16 --bitrate 1600 --vbv-maxrate 2400 --vbv-bufsize 4800 -o 540p.hevc --preset veryslow + [1080p:10:540p] --input 1080pSource.y4m --ctu 32 --bitrate 5800 --vbv-maxrate 8700 --vbv-bufsize 17400 -o 1080p.hevc --preset veryslow --scale-factor 2 + [2160p:10:1080p] --input 2160pSource.y4m --bitrate 16800 --vbv-maxrate 25200 --vbv-bufsize 50400 -o 2160p.hevc --preset veryslow --scale-factor 2 + The above sample config file is available in `the downloads page `_ + + Default: Disabled ( Conventional single encode generation ). Experimental feature. **CLI ONLY** @@ -2576,8 +2675,8 @@ .. option:: --svt-compressed-ten-bit-format, --no-svt-compressed-ten-bit-format In order to reduce the size of input YUV and to increase channel density, - SVT-HEVC accetps inputs in compressed-ten-bit-format. The conversion between - yuv420p10le and compressed ten bit format is a lossless operation. For more + SVT-HEVC accepts inputs in compressed-ten-bit-format. The conversion between + yuv420p10le and compressed ten-bit format is a lossless operation. For more details about the conversion refer `here'_. @@ -2629,7 +2728,7 @@ supports Low delay(P/B) and random access prediction structure. In a low delay structure, pictures within a mini-gop can only refer to the previous pictures in display order. In other words, picture with display order N can only refer - to pictures of display order lower than N. In random acccess method, pictures + to pictures of display order lower than N. In random access method, pictures can be referenced from both the directions. It accepts values in the range [0-2] diff -Nru x265-3.4/doc/reST/introduction.rst x265-3.5/doc/reST/introduction.rst --- x265-3.4/doc/reST/introduction.rst 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/doc/reST/introduction.rst 2021-03-16 12:53:00.000000000 +0000 @@ -43,7 +43,7 @@ features and optimizations from the x264 AVC encoder project. The x265 software is available for free under the GNU GPL 2 license, -from https://bitbucket.org/multicoreware/x265. For commercial companies +from https://bitbucket.org/multicoreware/x265_git. For commercial companies that wish to distribute x265 without being subject to the open source requirements of the GPL 2 license, commercial licenses are available with competitive terms. Contact license @ x265.com to inquire about diff -Nru x265-3.4/doc/reST/releasenotes.rst x265-3.5/doc/reST/releasenotes.rst --- x265-3.4/doc/reST/releasenotes.rst 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/doc/reST/releasenotes.rst 2021-03-16 12:53:00.000000000 +0000 @@ -2,6 +2,33 @@ Release Notes ************* +Version 3.5 +=========== + +Release date - 16th March, 2021. + +New feature +----------- +1. Real-time VBV for ABR (Average BitRate) encodes in –pass 2 using :option:`--vbv-live-multi-pass`: Improves VBV compliance with no significant impact on coding efficiency. + +Enhancements to existing features +--------------------------------- +1. Improved hist-based scene cut algorithm: Reduces false positives by leveraging motion and scene transition info. +2. Support for RADL pictures at IDR scene cuts: Improves coding efficiency with no significant impact on performance. +3. Bidirectional scene cut aware Frame Quantizer Selection: Saves bits than forward masking with no noticeable perceptual quality difference. + +API changes +----------- +1. Additions to x265_param structure to support the newly added features and encoder enhancements. +2. New x265_param options :option:`--min-vbv-fullness` and :option:`--max-vbv-fullness` to control min and max VBV fullness. + +Bug fixes +--------- +1. Incorrect VBV lookahead in :option:`--analysis-load` + :option:`--scale-factor`. +2. Encoder hang when VBV is used with slices. +3. QP spikes in the row-level VBV rate-control when WPP enabled. +4. Encoder crash in :option:`--abr-ladder`. + Version 3.4 =========== diff -Nru x265-3.4/.hg_archival.txt x265-3.5/.hg_archival.txt --- x265-3.4/.hg_archival.txt 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/.hg_archival.txt 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ -repo: 09fe40627f03a0f9c3e6ac78b22ac93da23f9fdf -node: 2a65b720985096bcb1664f7cb05c3d04aeb576f5 -branch: Release_3.4 -tag: 3.4 diff -Nru x265-3.4/.hgignore x265-3.5/.hgignore --- x265-3.4/.hgignore 1970-01-01 00:00:00.000000000 +0000 +++ x265-3.5/.hgignore 2021-03-16 12:53:00.000000000 +0000 @@ -0,0 +1,11 @@ +syntax: glob +doc/uncrustify/uncrustify.exe +build/ +**.rej +**.orig +**.hevc +**.yuv +**.y4m +**.out +**.swp +.DS_Store diff -Nru x265-3.4/.hgtags x265-3.5/.hgtags --- x265-3.4/.hgtags 1970-01-01 00:00:00.000000000 +0000 +++ x265-3.5/.hgtags 2021-03-16 12:53:00.000000000 +0000 @@ -0,0 +1,43 @@ +99fab2ef92be051cd3b3b2d817064cead282b42c 0.1 +b3471d9009f5cd487b23c8c61a6bfff8980e54f2 0.2 +3767fbfa970ff4b2dc2e8647db0274168727147e 0.3 +2ba6ec553f218d2b06ad803b87d6ec751fd639f7 0.4 +93707bc4fccdaa89a1f2da11db8808ca912a691c 0.4.1 +69acb3cb777f977f5edde908069ac565915dd366 0.5 +b970ffbdd696e3ce45c93b315902eb6366ff085e 0.6 +d24e2a8c4326b0cd01bfa6c414c5378481af9018 0.7 +527d03c56d6860dc979ddea1196f7e94d13d3e82 0.8 +82bbd2bf3b49ba086be0f0922f91fe0084896351 0.9 +cea97c4d79456842e00ade6be6fd5ec34610e5f8 1.0 +ae9609aeebdc3271114168ece003679e9b1dca1b 1.1 +d6257335c5370ee54317a0426a12c1f0724b18b9 1.2 +c1e4fc0162c14fdb84f5c3bd404fb28cfe10a17f 1.3 +5e604833c5aa605d0b6efbe5234492b5e7d8ac61 1.4 +9f0324125f53a12f766f6ed6f98f16e2f42337f4 1.5 +cbeb7d8a4880e4020c4545dd8e498432c3c6cad3 1.6 +8425278def1edf0931dc33fc518e1950063e76b0 1.7 +e27327f5da35c5feb660360336fdc94bd0afe719 1.8 +1d3b6e448e01ec40b392ef78b7e55a86249fbe68 1.9 +960c9991d0dcf46559c32e070418d3cbb7e8aa2f 2.0 +981e3bfef16a997bce6f46ce1b15631a0e234747 2.1 +be14a7e9755e54f0fd34911c72bdfa66981220bc 2.2 +3037c1448549ca920967831482c653e5892fa8ed 2.3 +e7a4dd48293b7956d4a20df257d23904cc78e376 2.4 +64b2d0bf45a52511e57a6b7299160b961ca3d51c 2.5 +0e9ea76945c89962cd46cee6537586e2054b2935 2.6 +e41a9bf2bac4a7af2bec2bbadf91e63752d320ef 2.7 +a158a3a029663133455268e2a63ae6b0af2df720 2.8 +f9681d731f2e56c2ca185cec10daece5939bee07 2.9 +bad4e598cac7cdd3df4623c68c91299c620471bd 3.0-rc +bad4e598cac7cdd3df4623c68c91299c620471bd 3.0-rc +0000000000000000000000000000000000000000 3.0-rc +1307fd7b2b9984f45179db01432305a416713049 3.0_RC +72188bd2f03447e71e789a5fd2f10364bb232c2c 3.0 +113518629fa54ffb491dd479e15c1f00dd39d376 3.1_RC1 +b4e38ce16d7c4b37a6482dc7ae61fd31071b6ff1 3.1_RC2 +20c9994e8bfbeb9443851b2b3a050cd98c8b147b 3.2_RC1 +353572437201d551381002aebf20d244bd49ef17 3.2 +5ee3593ebd82b4d8957909bbc1b68b99b59ba773 3.3_RC1 +96a10df63c0b778b480330bdf3be8da7db8a5fb1 3.3_RC2 +057215961bc4b51b6260a584ff3d506e6d65cfd6 3.3 +ee92f36782800f145970131e01c79955a3ed5c10 3.4_RC1 diff -Nru x265-3.4/source/abrEncApp.cpp x265-3.5/source/abrEncApp.cpp --- x265-3.4/source/abrEncApp.cpp 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/abrEncApp.cpp 2021-03-16 12:53:00.000000000 +0000 @@ -98,13 +98,15 @@ x265_picture_init(m_passEnc[pass]->m_param, m_inputPicBuffer[pass][idx]); } - m_analysisBuffer[pass] = X265_MALLOC(x265_analysis_data, m_queueSize); + CHECKED_MALLOC_ZERO(m_analysisBuffer[pass], x265_analysis_data, m_queueSize); m_picIdxReadCnt[pass] = new ThreadSafeInteger[m_queueSize]; m_analysisWrite[pass] = new ThreadSafeInteger[m_queueSize]; m_analysisRead[pass] = new ThreadSafeInteger[m_queueSize]; m_readFlag[pass] = X265_MALLOC(int, m_queueSize); } return true; + fail: + return false; } void AbrEncoder::destroy() @@ -315,6 +317,7 @@ x265_analysis_data *m_analysisInfo = &m_parent->m_analysisBuffer[m_id][index]; + x265_free_analysis_data(m_param, m_analysisInfo); memcpy(m_analysisInfo, src, sizeof(x265_analysis_data)); x265_alloc_analysis_data(m_param, m_analysisInfo); @@ -814,7 +817,7 @@ api->encoder_get_stats(m_encoder, &stats, sizeof(stats)); if (m_param->csvfn && !b_ctrl_c) #if ENABLE_LIBVMAF - api->vmaf_encoder_log(m_encoder, m_cliopt.argCount, m_cliopt.argString, m_cliopt.param, vmafdata); + api->vmaf_encoder_log(m_encoder, m_cliopt.argCnt, m_cliopt.argString, m_cliopt.param, vmafdata); #else api->encoder_log(m_encoder, m_cliopt.argCnt, m_cliopt.argString); #endif diff -Nru x265-3.4/source/cmake/version.cmake x265-3.5/source/cmake/version.cmake --- x265-3.4/source/cmake/version.cmake 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/cmake/version.cmake 1970-01-01 00:00:00.000000000 +0000 @@ -1,105 +0,0 @@ -if(CMAKE_VERSION VERSION_LESS "2.8.10") - find_program(HG_EXECUTABLE hg) -else() - find_package(Hg QUIET) -endif() -find_package(Git QUIET) # present in 2.8.8 - -# defaults, in case everything below fails -set(X265_VERSION "unknown") -set(X265_LATEST_TAG "0.0") -set(X265_TAG_DISTANCE "0") - -if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../.hg_archival.txt) - # read the lines of the archive summary file to extract the version - file(READ ${CMAKE_CURRENT_SOURCE_DIR}/../.hg_archival.txt archive) - STRING(REGEX REPLACE "\n" ";" archive "${archive}") - foreach(f ${archive}) - string(FIND "${f}" ": " pos) - string(SUBSTRING "${f}" 0 ${pos} key) - string(SUBSTRING "${f}" ${pos} -1 value) - string(SUBSTRING "${value}" 2 -1 value) - set(hg_${key} ${value}) - endforeach() - if(DEFINED hg_tag) - set(X265_LATEST_TAG ${hg_tag}) - elseif(DEFINED hg_node) - set(X265_LATEST_TAG ${hg_latesttag}) - set(X265_TAG_DISTANCE ${hg_latesttagdistance}) - string(SUBSTRING "${hg_node}" 0 12 X265_REVISION_ID) - endif() -elseif(HG_EXECUTABLE AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../.hg) - if(EXISTS "${HG_EXECUTABLE}.bat") - # mercurial source installs on Windows require .bat extension - set(HG_EXECUTABLE "${HG_EXECUTABLE}.bat") - endif() - message(STATUS "hg found at ${HG_EXECUTABLE}") - - execute_process(COMMAND - ${HG_EXECUTABLE} log -r. --template "{latesttag}" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - OUTPUT_VARIABLE X265_LATEST_TAG - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - execute_process(COMMAND - ${HG_EXECUTABLE} log -r. --template "{latesttagdistance}" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - OUTPUT_VARIABLE X265_TAG_DISTANCE - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - execute_process( - COMMAND - ${HG_EXECUTABLE} log -r. --template "{node}" - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - OUTPUT_VARIABLE X265_REVISION_ID - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - string(SUBSTRING "${X265_REVISION_ID}" 0 12 X265_REVISION_ID) - - if(X265_LATEST_TAG MATCHES "^r") - string(SUBSTRING ${X265_LATEST_TAG} 1 -1 X265_LATEST_TAG) - endif() -elseif(GIT_EXECUTABLE AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../.git) - execute_process( - COMMAND - ${GIT_EXECUTABLE} rev-list --tags --max-count=1 - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - OUTPUT_VARIABLE X265_LATEST_TAG_COMMIT - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - execute_process( - COMMAND - ${GIT_EXECUTABLE} describe --tags ${X265_LATEST_TAG_COMMIT} - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - OUTPUT_VARIABLE X265_LATEST_TAG - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - execute_process( - COMMAND - ${GIT_EXECUTABLE} rev-list ${X265_LATEST_TAG}.. --count --first-parent - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - OUTPUT_VARIABLE X265_TAG_DISTANCE - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) - execute_process( - COMMAND - ${GIT_EXECUTABLE} log -1 --format=g%h - WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} - OUTPUT_VARIABLE X265_REVISION_ID - ERROR_QUIET - OUTPUT_STRIP_TRAILING_WHITESPACE - ) -endif() -if(X265_TAG_DISTANCE STREQUAL "0") - set(X265_VERSION "${X265_LATEST_TAG}") -else() - set(X265_VERSION "${X265_LATEST_TAG}+${X265_TAG_DISTANCE}-${X265_REVISION_ID}") -endif() - -message(STATUS "x265 version ${X265_VERSION}") diff -Nru x265-3.4/source/cmake/Version.cmake x265-3.5/source/cmake/Version.cmake --- x265-3.4/source/cmake/Version.cmake 1970-01-01 00:00:00.000000000 +0000 +++ x265-3.5/source/cmake/Version.cmake 2021-03-16 12:53:00.000000000 +0000 @@ -0,0 +1,179 @@ + ################################################################################################################# + # + # Copyright (C) 2013-2020 MulticoreWare, Inc + # + # This program is free software; you can redistribute it and/or modify + # it under the terms of the GNU General Public License as published by + # the Free Software Foundation; either version 2 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU General Public License for more details. + # + # You should have received a copy of the GNU General Public License + # along with this program; if not, write to the Free Software + # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111, USA. + # + # This program is also available under a commercial proprietary license. + # For more information, contact us at license @ x265.com + # + # Authors: Janani T.E , Srikanth Kurapati + # + ################################################################################################################# + # PURPOSE: Identity version control software version display, also read version files to present x265 version. + ################################################################################################################# + #Default Settings, for user to be vigilant about x265 version being reported during product build. +set(X265_VERSION "unknown") +set(X265_LATEST_TAG "0.0") +set(X265_TAG_DISTANCE "0") + +#Find version control software to be used for live and extracted repositories from compressed tarballs +if(CMAKE_VERSION VERSION_LESS "2.8.10") + find_program(HG_EXECUTABLE hg) + if(EXISTS "${HG_EXECUTABLE}.bat") + set(HG_EXECUTABLE "${HG_EXECUTABLE}.bat") + endif() + message(STATUS "hg found at ${HG_EXECUTABLE}") +else() + find_package(Hg QUIET) +endif() +if(HG_EXECUTABLE) + #Set Version Control binary for source code kind + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../.hg_archival.txt) + set(HG_ARCHETYPE "1") + elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../.hg) + set(HG_ARCHETYPE "0") + endif() +endif(HG_EXECUTABLE) +find_package(Git QUIET) #No restrictions on Git versions used, any versions from 1.8.x to 2.2.x or later should do. +if(GIT_FOUND) + find_program(GIT_EXECUTABLE git) + message(STATUS "GIT_EXECUTABLE ${GIT_EXECUTABLE}") + if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../.git) + set(GIT_ARCHETYPE "0") + elseif(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/../x265Version.txt) + set(GIT_ARCHETYPE "1") + endif() +endif(GIT_FOUND) +if(HG_ARCHETYPE) + #Read the lines of the archive summary file to extract the version + message(STATUS "SOURCE CODE IS FROM x265 HG ARCHIVED ZIP OR TAR BALL") + file(READ ${CMAKE_CURRENT_SOURCE_DIR}/../.hg_archival.txt archive) + STRING(REGEX REPLACE "\n" ";" archive "${archive}") + foreach(f ${archive}) + string(FIND "${f}" ": " pos) + string(SUBSTRING "${f}" 0 ${pos} key) + string(SUBSTRING "${f}" ${pos} -1 value) + string(SUBSTRING "${value}" 2 -1 value) + set(hg_${key} ${value}) + endforeach() + if(DEFINED hg_tag) + set(X265_LATEST_TAG ${hg_tag}) + elseif(DEFINED hg_node) + set(X265_LATEST_TAG ${hg_latesttag}) + set(X265_TAG_DISTANCE ${hg_latesttagdistance}) + string(SUBSTRING "${hg_node}" 0 12 X265_REVISION_ID) + endif() + message(STATUS "HG ARCHIVAL INFORMATION PROCESSED") +elseif(NOT DEFINED GIT_ARCHETYPE) +# means that's its neither hg archive nor git clone/archive hence it has to be hg live repo as these are only four cases that need to processed in mutual exclusion. + execute_process(COMMAND + ${HG_EXECUTABLE} log -r. --template "{latesttag}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE X265_LATEST_TAG + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + execute_process(COMMAND + ${HG_EXECUTABLE} log -r. --template "{latesttagdistance}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE X265_TAG_DISTANCE + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + execute_process( + COMMAND + ${HG_EXECUTABLE} log -r. --template "{node}" + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE X265_REVISION_ID + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + string(SUBSTRING "${X265_REVISION_ID}" 0 12 X265_REVISION_ID) + if(X265_LATEST_TAG MATCHES "^r") + string(SUBSTRING ${X265_LATEST_TAG} 1 -1 X265_LATEST_TAG) + endif() + message(STATUS "HG LIVE REPO STATUS CHECK DONE") +elseif(GIT_ARCHETYPE) + message(STATUS "SOURCE CODE IS FROM x265 GIT ARCHIVED ZIP OR TAR BALL") + #Read the lines of the archive summary file to extract the version + file(READ ${CMAKE_CURRENT_SOURCE_DIR}/../x265Version.txt filebuf) + STRING(REGEX REPLACE "\n" ";" filebuf "${filebuf}") + foreach(line ${filebuf}) + string(FIND "${line}" ": " pos) + string(SUBSTRING "${line}" 0 ${pos} key) + string(SUBSTRING "${line}" ${pos} -1 value) + string(SUBSTRING "${value}" 2 -1 value) + set(git_${key} ${value}) + endforeach() + if(DEFINED git_releasetag) + set(X265_LATEST_TAG ${git_releasetag}) + if(DEFINED git_releasetagdistance) + set(X265_TAG_DISTANCE ${git_releasetagdistance}) + if(X265_TAG_DISTANCE STRGREATER "0" OR X265_TAG_DISTANCE STREQUAL "0") + #for x265 the repository changeset has to be a tag id or commit id after the tag + #hence mandating it's presence in version file always for valid tag distances. + if(DEFINED git_repositorychangeset) + string(SUBSTRING "${git_repositorychangeset}" 0 9 X265_REVISION_ID) + else() + message(WARNING "X265 LATEST COMMIT TIP INFORMATION NOT AVAILABLE") + endif() + else() + message(WARNING "X265 TAG DISTANCE INVALID") + endif() + else() + message(WARNING "COMMIT INFORMATION AFTER LATEST REVISION UNAVAILABLE") + endif() + else() + message(WARNING "X265 RELEASE VERSION LABEL MISSING: ${X265_LATEST_TAG}") + endif() + message(STATUS "GIT ARCHIVAL INFORMATION PROCESSED") +else() + execute_process( + COMMAND + ${GIT_EXECUTABLE} describe --abbrev=0 --tags + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE X265_LATEST_TAG + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + execute_process( + COMMAND + ${GIT_EXECUTABLE} rev-list ${X265_LATEST_TAG}.. --count --first-parent + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE X265_TAG_DISTANCE + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + execute_process( + COMMAND + ${GIT_EXECUTABLE} log --pretty=format:%h -n 1 + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE X265_REVISION_ID + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + message(STATUS "GIT LIVE REPO VERSION RETRIEVED") +endif() + +# formatting based on distance from tag +if(X265_TAG_DISTANCE STREQUAL "0") + set(X265_VERSION "${X265_LATEST_TAG}") +elseif(X265_TAG_DISTANCE STRGREATER "0") + set(X265_VERSION "${X265_LATEST_TAG}+${X265_TAG_DISTANCE}-${X265_REVISION_ID}") +endif() + +#will always be printed in its entirety based on version file configuration to avail revision monitoring by repo owners +message(STATUS "X265 RELEASE VERSION ${X265_VERSION}") diff -Nru x265-3.4/source/CMakeLists.txt x265-3.5/source/CMakeLists.txt --- x265-3.4/source/CMakeLists.txt 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/CMakeLists.txt 2021-03-16 12:53:00.000000000 +0000 @@ -29,7 +29,7 @@ option(STATIC_LINK_CRT "Statically link C runtime for release builds" OFF) mark_as_advanced(FPROFILE_USE FPROFILE_GENERATE NATIVE_BUILD) # X265_BUILD must be incremented each time the public API is changed -set(X265_BUILD 192) +set(X265_BUILD 199) configure_file("${PROJECT_SOURCE_DIR}/x265.def.in" "${PROJECT_BINARY_DIR}/x265.def") configure_file("${PROJECT_SOURCE_DIR}/x265_config.h.in" @@ -485,7 +485,7 @@ endif() endif() -include(version) # determine X265_VERSION and X265_LATEST_TAG +include(Version) # determine X265_VERSION and X265_LATEST_TAG include_directories(. common encoder "${PROJECT_BINARY_DIR}") option(ENABLE_PPA "Enable PPA profiling instrumentation" OFF) diff -Nru x265-3.4/source/common/frame.cpp x265-3.5/source/common/frame.cpp --- x265-3.4/source/common/frame.cpp 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/common/frame.cpp 2021-03-16 12:53:00.000000000 +0000 @@ -63,6 +63,7 @@ m_thetaPic = NULL; m_edgeBitPlane = NULL; m_edgeBitPic = NULL; + m_isInsideWindow = 0; } bool Frame::create(x265_param *param, float* quantOffsets) diff -Nru x265-3.4/source/common/frame.h x265-3.5/source/common/frame.h --- x265-3.4/source/common/frame.h 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/common/frame.h 2021-03-16 12:53:00.000000000 +0000 @@ -141,6 +141,8 @@ pixel* m_edgeBitPlane; pixel* m_edgeBitPic; + int m_isInsideWindow; + Frame(); bool create(x265_param *param, float* quantOffsets); diff -Nru x265-3.4/source/common/lowres.cpp x265-3.5/source/common/lowres.cpp --- x265-3.4/source/common/lowres.cpp 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/common/lowres.cpp 2021-03-16 12:53:00.000000000 +0000 @@ -266,6 +266,10 @@ indB = 0; memset(costEst, -1, sizeof(costEst)); memset(weightedCostDelta, 0, sizeof(weightedCostDelta)); + interPCostPercDiff = 0.0; + intraCostPercDiff = 0.0; + m_bIsMaxThres = false; + m_bIsHardScenecut = false; if (qpAqOffset && invQscaleFactor) memset(costEstAq, -1, sizeof(costEstAq)); diff -Nru x265-3.4/source/common/lowres.h x265-3.5/source/common/lowres.h --- x265-3.4/source/common/lowres.h 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/common/lowres.h 2021-03-16 12:53:00.000000000 +0000 @@ -234,6 +234,12 @@ uint16_t* propagateCost; double weightedCostDelta[X265_BFRAME_MAX + 2]; ReferencePlanes weightedRef[X265_BFRAME_MAX + 2]; + /* For hist-based scenecut */ + bool m_bIsMaxThres; + double interPCostPercDiff; + double intraCostPercDiff; + bool m_bIsHardScenecut; + bool create(x265_param* param, PicYuv *origPic, uint32_t qgSize); void destroy(); void init(PicYuv *origPic, int poc); diff -Nru x265-3.4/source/common/param.cpp x265-3.5/source/common/param.cpp --- x265-3.4/source/common/param.cpp 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/common/param.cpp 2021-03-16 12:53:00.000000000 +0000 @@ -168,7 +168,7 @@ param->bFrameAdaptive = X265_B_ADAPT_TRELLIS; param->bBPyramid = 1; param->scenecutThreshold = 40; /* Magic number pulled in from x264 */ - param->edgeTransitionThreshold = 0.01; + param->edgeTransitionThreshold = 0.03; param->bHistBasedSceneCut = 0; param->lookaheadSlices = 8; param->lookaheadThreads = 0; @@ -179,8 +179,12 @@ param->bEnableHRDConcatFlag = 0; param->bEnableFades = 0; param->bEnableSceneCutAwareQp = 0; - param->scenecutWindow = 500; - param->maxQpDelta = 5; + param->fwdScenecutWindow = 500; + param->fwdRefQpDelta = 5; + param->fwdNonRefQpDelta = param->fwdRefQpDelta + (SLICE_TYPE_DELTA * param->fwdRefQpDelta); + param->bwdScenecutWindow = 100; + param->bwdRefQpDelta = -1; + param->bwdNonRefQpDelta = -1; /* Intra Coding Tools */ param->bEnableConstrainedIntra = 0; @@ -254,6 +258,8 @@ param->rc.vbvBufferInit = 0.9; param->vbvBufferEnd = 0; param->vbvEndFrameAdjust = 0; + param->minVbvFullness = 50; + param->maxVbvFullness = 80; param->rc.rfConstant = 28; param->rc.bitrate = 0; param->rc.qCompress = 0.6; @@ -287,6 +293,7 @@ param->bResetZoneConfig = 1; param->reconfigWindowSize = 0; param->decoderVbvMaxRate = 0; + param->bliveVBV2pass = 0; /* Video Usability Information (VUI) */ param->vui.aspectRatioIdc = 0; @@ -1122,7 +1129,7 @@ p->vui.bEnableOverscanInfoPresentFlag = 1; p->vui.bEnableOverscanAppropriateFlag = 1; } - else if (!strcmp(value, "undef")) + else if (!strcmp(value, "unknown")) p->vui.bEnableOverscanInfoPresentFlag = 0; else bError = true; @@ -1340,9 +1347,72 @@ p->selectiveSAO = atoi(value); } OPT("fades") p->bEnableFades = atobool(value); - OPT("scenecut-aware-qp") p->bEnableSceneCutAwareQp = atobool(value); - OPT("scenecut-window") p->scenecutWindow = atoi(value); - OPT("max-qp-delta") p->maxQpDelta = atoi(value); + OPT("scenecut-aware-qp") p->bEnableSceneCutAwareQp = atoi(value); + OPT("masking-strength") + { + int window1; + double refQpDelta1, nonRefQpDelta1; + + if (p->bEnableSceneCutAwareQp == FORWARD) + { + if (3 == sscanf(value, "%d,%lf,%lf", &window1, &refQpDelta1, &nonRefQpDelta1)) + { + if (window1 > 0) + p->fwdScenecutWindow = window1; + if (refQpDelta1 > 0) + p->fwdRefQpDelta = refQpDelta1; + if (nonRefQpDelta1 > 0) + p->fwdNonRefQpDelta = nonRefQpDelta1; + } + else + { + x265_log(NULL, X265_LOG_ERROR, "Specify all the necessary offsets for masking-strength \n"); + bError = true; + } + } + else if (p->bEnableSceneCutAwareQp == BACKWARD) + { + if (3 == sscanf(value, "%d,%lf,%lf", &window1, &refQpDelta1, &nonRefQpDelta1)) + { + if (window1 > 0) + p->bwdScenecutWindow = window1; + if (refQpDelta1 > 0) + p->bwdRefQpDelta = refQpDelta1; + if (nonRefQpDelta1 > 0) + p->bwdNonRefQpDelta = nonRefQpDelta1; + } + else + { + x265_log(NULL, X265_LOG_ERROR, "Specify all the necessary offsets for masking-strength \n"); + bError = true; + } + } + else if (p->bEnableSceneCutAwareQp == BI_DIRECTIONAL) + { + int window2; + double refQpDelta2, nonRefQpDelta2; + if (6 == sscanf(value, "%d,%lf,%lf,%d,%lf,%lf", &window1, &refQpDelta1, &nonRefQpDelta1, &window2, &refQpDelta2, &nonRefQpDelta2)) + { + if (window1 > 0) + p->fwdScenecutWindow = window1; + if (refQpDelta1 > 0) + p->fwdRefQpDelta = refQpDelta1; + if (nonRefQpDelta1 > 0) + p->fwdNonRefQpDelta = nonRefQpDelta1; + if (window2 > 0) + p->bwdScenecutWindow = window2; + if (refQpDelta2 > 0) + p->bwdRefQpDelta = refQpDelta2; + if (nonRefQpDelta2 > 0) + p->bwdNonRefQpDelta = nonRefQpDelta2; + } + else + { + x265_log(NULL, X265_LOG_ERROR, "Specify all the necessary offsets for masking-strength \n"); + bError = true; + } + } + } OPT("field") p->bField = atobool( value ); OPT("cll") p->bEmitCLL = atobool(value); OPT("frame-dup") p->bEnableFrameDuplication = atobool(value); @@ -1373,6 +1443,9 @@ sscanf(value, "%d,%d,%d", &p->hmeRange[0], &p->hmeRange[1], &p->hmeRange[2]); p->bEnableHME = true; } + OPT("vbv-live-multi-pass") p->bliveVBV2pass = atobool(value); + OPT("min-vbv-fullness") p->minVbvFullness = atof(value); + OPT("max-vbv-fullness") p->maxVbvFullness = atof(value); else return X265_PARAM_BAD_NAME; } @@ -1643,23 +1716,23 @@ "Sample Aspect Ratio height must be greater than 0"); CHECK(param->vui.videoFormat < 0 || param->vui.videoFormat > 5, "Video Format must be component," - " pal, ntsc, secam, mac or undef"); + " pal, ntsc, secam, mac or unknown"); CHECK(param->vui.colorPrimaries < 0 || param->vui.colorPrimaries > 12 || param->vui.colorPrimaries == 3, - "Color Primaries must be undef, bt709, bt470m," + "Color Primaries must be unknown, bt709, bt470m," " bt470bg, smpte170m, smpte240m, film, bt2020, smpte-st-428, smpte-rp-431 or smpte-eg-432"); CHECK(param->vui.transferCharacteristics < 0 || param->vui.transferCharacteristics > 18 || param->vui.transferCharacteristics == 3, - "Transfer Characteristics must be undef, bt709, bt470m, bt470bg," + "Transfer Characteristics must be unknown, bt709, bt470m, bt470bg," " smpte170m, smpte240m, linear, log100, log316, iec61966-2-4, bt1361e," " iec61966-2-1, bt2020-10, bt2020-12, smpte-st-2084, smpte-st-428 or arib-std-b67"); CHECK(param->vui.matrixCoeffs < 0 || param->vui.matrixCoeffs > 14 || param->vui.matrixCoeffs == 3, - "Matrix Coefficients must be undef, bt709, fcc, bt470bg, smpte170m," - " smpte240m, GBR, YCgCo, bt2020nc, bt2020c, smpte-st-2085, chroma-nc, chroma-c or ictcp"); + "Matrix Coefficients must be unknown, bt709, fcc, bt470bg, smpte170m," + " smpte240m, gbr, ycgco, bt2020nc, bt2020c, smpte-st-2085, chroma-nc, chroma-c or ictcp"); CHECK(param->vui.chromaSampleLocTypeTopField < 0 || param->vui.chromaSampleLocTypeTopField > 5, "Chroma Sample Location Type Top Field must be 0-5"); @@ -1688,8 +1761,8 @@ "scenecutThreshold must be greater than 0"); CHECK(param->scenecutBias < 0 || 100 < param->scenecutBias, "scenecut-bias must be between 0 and 100"); - CHECK(param->edgeTransitionThreshold < 0.0 || 2.0 < param->edgeTransitionThreshold, - "hist-threshold must be between 0.0 and 2.0"); + CHECK(param->edgeTransitionThreshold < 0.0 || 1.0 < param->edgeTransitionThreshold, + "hist-threshold must be between 0.0 and 1.0"); CHECK(param->radl < 0 || param->radl > param->bframes, "radl must be between 0 and bframes"); CHECK(param->rdPenalty < 0 || param->rdPenalty > 2, @@ -1712,6 +1785,10 @@ "Valid vbv-end-fr-adj must be a fraction 0 - 1"); CHECK(!param->totalFrames && param->vbvEndFrameAdjust, "vbv-end-fr-adj cannot be enabled when total number of frames is unknown"); + CHECK(param->minVbvFullness < 0 && param->minVbvFullness > 100, + "min-vbv-fullness must be a fraction 0 - 100"); + CHECK(param->maxVbvFullness < 0 && param->maxVbvFullness > 100, + "max-vbv-fullness must be a fraction 0 - 100"); CHECK(param->rc.bitrate < 0, "Target bitrate can not be less than zero"); CHECK(param->rc.qCompress < 0.5 || param->rc.qCompress > 1.0, @@ -1756,11 +1833,9 @@ CHECK((param->rc.vbvMaxBitrate <= 0 || param->rc.vbvBufferSize <= 0), "Dolby Vision requires VBV settings to enable HRD.\n"); CHECK((param->internalBitDepth != 10), "Dolby Vision profile - 5, profile - 8.1 and profile - 8.2 is Main10 only\n"); CHECK((param->internalCsp != X265_CSP_I420), "Dolby Vision profile - 5, profile - 8.1 and profile - 8.2 requires YCbCr 4:2:0 color space\n"); - if (param->dolbyProfile == 81) CHECK(!(param->masteringDisplayColorVolume), "Dolby Vision profile - 8.1 requires Mastering display color volume information\n"); } - if (param->bField && param->interlaceMode) { CHECK( (param->bFrameAdaptive==0), "Adaptive B-frame decision method should be closed for field feature.\n" ); @@ -1768,13 +1843,38 @@ } CHECK(param->selectiveSAO < 0 || param->selectiveSAO > 4, "Invalid SAO tune level. Value must be between 0 and 4 (inclusive)"); - CHECK(param->scenecutWindow < 0 || param->scenecutWindow > 1000, - "Invalid scenecut Window duration. Value must be between 0 and 1000(inclusive)"); - CHECK(param->maxQpDelta < 0 || param->maxQpDelta > 10, - "Invalid maxQpDelta value. Value must be between 0 and 10 (inclusive)"); - for(int level = 0; level < 3; level++) - CHECK(param->hmeRange[level] < 0 || param->hmeRange[level] >= 32768, - "Search Range for HME levels must be between 0 and 32768"); + if (param->bEnableSceneCutAwareQp) + { + if (!param->rc.bStatRead) + { + param->bEnableSceneCutAwareQp = 0; + x265_log(param, X265_LOG_WARNING, "Disabling Scenecut Aware Frame Quantizer Selection since it works only in pass 2\n"); + } + else + { + CHECK(param->bEnableSceneCutAwareQp < 0 || param->bEnableSceneCutAwareQp > 3, + "Invalid masking direction. Value must be between 0 and 3(inclusive)"); + CHECK(param->fwdScenecutWindow < 0 || param->fwdScenecutWindow > 1000, + "Invalid forward scenecut Window duration. Value must be between 0 and 1000(inclusive)"); + CHECK(param->fwdRefQpDelta < 0 || param->fwdRefQpDelta > 10, + "Invalid fwdRefQpDelta value. Value must be between 0 and 10 (inclusive)"); + CHECK(param->fwdNonRefQpDelta < 0 || param->fwdNonRefQpDelta > 10, + "Invalid fwdNonRefQpDelta value. Value must be between 0 and 10 (inclusive)"); + + CHECK(param->bwdScenecutWindow < 0 || param->bwdScenecutWindow > 1000, + "Invalid backward scenecut Window duration. Value must be between 0 and 1000(inclusive)"); + CHECK(param->bwdRefQpDelta < -1 || param->bwdRefQpDelta > 10, + "Invalid bwdRefQpDelta value. Value must be between 0 and 10 (inclusive)"); + CHECK(param->bwdNonRefQpDelta < -1 || param->bwdNonRefQpDelta > 10, + "Invalid bwdNonRefQpDelta value. Value must be between 0 and 10 (inclusive)"); + } + } + if (param->bEnableHME) + { + for (int level = 0; level < 3; level++) + CHECK(param->hmeRange[level] < 0 || param->hmeRange[level] >= 32768, + "Search Range for HME levels must be between 0 and 32768"); + } #if !X86_64 CHECK(param->searchMethod == X265_SEA && (param->sourceWidth > 840 || param->sourceHeight > 480), "SEA motion search does not support resolutions greater than 480p in 32 bit build"); @@ -1801,6 +1901,15 @@ CHECK(param->confWinRightOffset < 0, "Conformance Window Right Offset must be 0 or greater"); CHECK(param->confWinBottomOffset < 0, "Conformance Window Bottom Offset must be 0 or greater"); CHECK(param->decoderVbvMaxRate < 0, "Invalid Decoder Vbv Maxrate. Value can not be less than zero"); + if (param->bliveVBV2pass) + { + CHECK((param->rc.bStatRead == 0), "Live VBV in multi pass option requires rate control 2 pass to be enabled"); + if ((param->rc.vbvMaxBitrate <= 0 || param->rc.vbvBufferSize <= 0)) + { + param->bliveVBV2pass = 0; + x265_log(param, X265_LOG_WARNING, "Live VBV enabled without VBV settings.Disabling live VBV in 2 pass\n"); + } + } return check_failed; } @@ -2115,8 +2224,8 @@ BOOL(p->rc.bEnableSlowFirstPass, "slow-firstpass"); if (p->rc.vbvBufferSize) { - s += sprintf(s, " vbv-maxrate=%d vbv-bufsize=%d vbv-init=%.1f", - p->rc.vbvMaxBitrate, p->rc.vbvBufferSize, p->rc.vbvBufferInit); + s += sprintf(s, " vbv-maxrate=%d vbv-bufsize=%d vbv-init=%.1f min-vbv-fullness=%.1f max-vbv-fullness=%.1f", + p->rc.vbvMaxBitrate, p->rc.vbvBufferSize, p->rc.vbvBufferInit, p->minVbvFullness, p->maxVbvFullness); if (p->vbvBufferEnd) s += sprintf(s, " vbv-end=%.1f vbv-end-fr-adj=%.1f", p->vbvBufferEnd, p->vbvEndFrameAdjust); if (p->rc.rateControlMode == X265_RC_CRF) @@ -2217,11 +2326,12 @@ BOOL(p->bEnableSvtHevc, "svt"); BOOL(p->bField, "field"); s += sprintf(s, " qp-adaptation-range=%.2f", p->rc.qpAdaptationRange); - BOOL(p->bEnableSceneCutAwareQp, "scenecut-aware-qp"); + s += sprintf(s, " scenecut-aware-qp=%d", p->bEnableSceneCutAwareQp); if (p->bEnableSceneCutAwareQp) - s += sprintf(s, " scenecut-window=%d max-qp-delta=%d", p->scenecutWindow, p->maxQpDelta); + s += sprintf(s, " fwd-scenecut-window=%d fwd-ref-qp-delta=%f fwd-nonref-qp-delta=%f bwd-scenecut-window=%d bwd-ref-qp-delta=%f bwd-nonref-qp-delta=%f", p->fwdScenecutWindow, p->fwdRefQpDelta, p->fwdNonRefQpDelta, p->bwdScenecutWindow, p->bwdRefQpDelta, p->bwdNonRefQpDelta); s += sprintf(s, "conformance-window-offsets right=%d bottom=%d", p->confWinRightOffset, p->confWinBottomOffset); s += sprintf(s, " decoder-max-rate=%d", p->decoderVbvMaxRate); + BOOL(p->bliveVBV2pass, "vbv-live-multi-pass"); #undef BOOL return buf; } @@ -2424,6 +2534,8 @@ dst->rc.vbvMaxBitrate = src->rc.vbvMaxBitrate; dst->rc.vbvBufferInit = src->rc.vbvBufferInit; + dst->minVbvFullness = src->minVbvFullness; + dst->maxVbvFullness = src->maxVbvFullness; dst->rc.cuTree = src->rc.cuTree; dst->rc.rfConstantMax = src->rc.rfConstantMax; dst->rc.rfConstantMin = src->rc.rfConstantMin; @@ -2570,12 +2682,17 @@ dst->bEnableSvtHevc = src->bEnableSvtHevc; dst->bEnableFades = src->bEnableFades; dst->bEnableSceneCutAwareQp = src->bEnableSceneCutAwareQp; - dst->scenecutWindow = src->scenecutWindow; - dst->maxQpDelta = src->maxQpDelta; + dst->fwdScenecutWindow = src->fwdScenecutWindow; + dst->fwdRefQpDelta = src->fwdRefQpDelta; + dst->fwdNonRefQpDelta = src->fwdNonRefQpDelta; + dst->bwdScenecutWindow = src->bwdScenecutWindow; + dst->bwdRefQpDelta = src->bwdRefQpDelta; + dst->bwdNonRefQpDelta = src->bwdNonRefQpDelta; dst->bField = src->bField; dst->confWinRightOffset = src->confWinRightOffset; dst->confWinBottomOffset = src->confWinBottomOffset; + dst->bliveVBV2pass = src->bliveVBV2pass; #ifdef SVT_HEVC memcpy(dst->svtHevcParam, src->svtHevcParam, sizeof(EB_H265_ENC_CONFIGURATION)); #endif diff -Nru x265-3.4/source/encoder/api.cpp x265-3.5/source/encoder/api.cpp --- x265-3.4/source/encoder/api.cpp 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/encoder/api.cpp 2021-03-16 12:53:00.000000000 +0000 @@ -33,7 +33,7 @@ #include "svt.h" #if ENABLE_LIBVMAF -#include "libvmaf.h" +#include "libvmaf/libvmaf.h" #endif /* multilib namespace reflectors */ diff -Nru x265-3.4/source/encoder/encoder.cpp x265-3.5/source/encoder/encoder.cpp --- x265-3.4/source/encoder/encoder.cpp 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/encoder/encoder.cpp 2021-03-16 12:53:00.000000000 +0000 @@ -222,12 +222,9 @@ uint32_t pixelbytes = m_param->internalBitDepth > 8 ? 2 : 1; m_edgePic = X265_MALLOC(pixel, m_planeSizes[0] * pixelbytes); m_edgeHistThreshold = m_param->edgeTransitionThreshold; - m_chromaHistThreshold = m_edgeHistThreshold * 10.0; - m_chromaHistThreshold = x265_min(m_chromaHistThreshold, MAX_SCENECUT_THRESHOLD); - m_scaledEdgeThreshold = m_edgeHistThreshold * SCENECUT_STRENGTH_FACTOR; - m_scaledEdgeThreshold = x265_min(m_scaledEdgeThreshold, MAX_SCENECUT_THRESHOLD); - m_scaledChromaThreshold = m_chromaHistThreshold * SCENECUT_STRENGTH_FACTOR; - m_scaledChromaThreshold = x265_min(m_scaledChromaThreshold, MAX_SCENECUT_THRESHOLD); + m_chromaHistThreshold = x265_min(m_edgeHistThreshold * 10.0, MAX_SCENECUT_THRESHOLD); + m_scaledEdgeThreshold = x265_min(m_edgeHistThreshold * SCENECUT_STRENGTH_FACTOR, MAX_SCENECUT_THRESHOLD); + m_scaledChromaThreshold = x265_min(m_chromaHistThreshold * SCENECUT_STRENGTH_FACTOR, MAX_SCENECUT_THRESHOLD); if (m_param->sourceBitDepth != m_param->internalBitDepth) { int size = m_param->sourceWidth * m_param->sourceHeight; @@ -1437,7 +1434,6 @@ } size_t bufSize = sizeof(pixel) * m_planeSizes[0]; - int32_t planeCount = x265_cli_csps[m_param->internalCsp].planes; memset(m_edgePic, 0, bufSize); if (!computeEdge(m_edgePic, src, NULL, pic->width, pic->height, pic->width, false, 1)) @@ -1448,88 +1444,96 @@ pixel pixelVal; int32_t *edgeHist = m_curEdgeHist; - memset(edgeHist, 0, 2 * sizeof(int32_t)); - for (int64_t i = 0; i < m_planeSizes[0]; i++) + memset(edgeHist, 0, EDGE_BINS * sizeof(int32_t)); + for (uint32_t i = 0; i < m_planeSizes[0]; i++) { - if (!m_edgePic[i]) - edgeHist[0]++; + if (m_edgePic[i]) + edgeHist[1]++; else - edgeHist[1]++; + edgeHist[0]++; + } + + /* Y Histogram Calculation */ + int32_t *yHist = m_curYUVHist[0]; + memset(yHist, 0, HISTOGRAM_BINS * sizeof(int32_t)); + for (uint32_t i = 0; i < m_planeSizes[0]; i++) + { + pixelVal = src[i]; + yHist[pixelVal]++; } if (pic->colorSpace != X265_CSP_I400) { /* U Histogram Calculation */ - int32_t *uHist = m_curUVHist[0]; - memset(uHist, 0, HISTOGRAM_BINS * sizeof(int32_t)); - - for (int64_t i = 0; i < m_planeSizes[1]; i++) + int32_t *uHist = m_curYUVHist[1]; + memset(uHist, 0, sizeof(m_curYUVHist[1])); + for (uint32_t i = 0; i < m_planeSizes[1]; i++) { pixelVal = planeU[i]; uHist[pixelVal]++; } /* V Histogram Calculation */ - if (planeCount == 3) + pixelVal = 0; + int32_t *vHist = m_curYUVHist[2]; + memset(vHist, 0, sizeof(m_curYUVHist[2])); + for (uint32_t i = 0; i < m_planeSizes[2]; i++) { - pixelVal = 0; - int32_t *vHist = m_curUVHist[1]; - memset(vHist, 0, HISTOGRAM_BINS * sizeof(int32_t)); - - for (int64_t i = 0; i < m_planeSizes[2]; i++) - { - pixelVal = planeV[i]; - vHist[pixelVal]++; - } - for (int i = 0; i < HISTOGRAM_BINS; i++) - { - m_curMaxUVHist[i] = x265_max(uHist[i], vHist[i]); - } - } - else - { /* in case of bi planar color space */ - memcpy(m_curMaxUVHist, m_curUVHist[0], HISTOGRAM_BINS * sizeof(int32_t)); + pixelVal = planeV[i]; + vHist[pixelVal]++; } } return true; } -void Encoder::computeHistogramSAD(double *maxUVNormalizedSad, double *edgeNormalizedSad, int curPoc) +void Encoder::computeHistogramSAD(double *normalizedMaxUVSad, double *normalizedEdgeSad, int curPoc) { if (curPoc == 0) { /* first frame is scenecut by default no sad computation for the same. */ - *maxUVNormalizedSad = 0.0; - *edgeNormalizedSad = 0.0; + *normalizedMaxUVSad = 0.0; + *normalizedEdgeSad = 0.0; } else { - /* compute sum of absolute difference of normalized histogram bins for maxUV and edge histograms. */ - int32_t edgefreqDiff = 0; - int32_t maxUVfreqDiff = 0; - double edgeProbabilityDiff = 0; + /* compute sum of absolute differences of histogram bins of chroma and luma edge response between the current and prev pictures. */ + int32_t edgeHistSad = 0; + int32_t uHistSad = 0; + int32_t vHistSad = 0; + double normalizedUSad = 0.0; + double normalizedVSad = 0.0; for (int j = 0; j < HISTOGRAM_BINS; j++) { if (j < 2) { - edgefreqDiff = abs(m_curEdgeHist[j] - m_prevEdgeHist[j]); - edgeProbabilityDiff = (double) edgefreqDiff / m_planeSizes[0]; - *edgeNormalizedSad += edgeProbabilityDiff; + edgeHistSad += abs(m_curEdgeHist[j] - m_prevEdgeHist[j]); } - maxUVfreqDiff = abs(m_curMaxUVHist[j] - m_prevMaxUVHist[j]); - *maxUVNormalizedSad += (double)maxUVfreqDiff / m_planeSizes[2]; + uHistSad += abs(m_curYUVHist[1][j] - m_prevYUVHist[1][j]); + vHistSad += abs(m_curYUVHist[2][j] - m_prevYUVHist[2][j]); } + *normalizedEdgeSad = normalizeRange(edgeHistSad, 0, 2 * m_planeSizes[0], 0.0, 1.0); + normalizedUSad = normalizeRange(uHistSad, 0, 2 * m_planeSizes[1], 0.0, 1.0); + normalizedVSad = normalizeRange(vHistSad, 0, 2 * m_planeSizes[2], 0.0, 1.0); + *normalizedMaxUVSad = x265_max(normalizedUSad, normalizedVSad); } /* store histograms of previous frame for reference */ - size_t bufsize = HISTOGRAM_BINS * sizeof(int32_t); - memcpy(m_prevMaxUVHist, m_curMaxUVHist, bufsize); - memcpy(m_prevEdgeHist, m_curEdgeHist, 2 * sizeof(int32_t)); + memcpy(m_prevEdgeHist, m_curEdgeHist, sizeof(m_curEdgeHist)); + memcpy(m_prevYUVHist, m_curYUVHist, sizeof(m_curYUVHist)); +} + +double Encoder::normalizeRange(int32_t value, int32_t minValue, int32_t maxValue, double rangeStart, double rangeEnd) +{ + return (double)(value - minValue) * (rangeEnd - rangeStart) / (maxValue - minValue) + rangeStart; } -void Encoder::findSceneCuts(x265_picture *pic, bool& bDup, double maxUVSad, double edgeSad) +void Encoder::findSceneCuts(x265_picture *pic, bool& bDup, double maxUVSad, double edgeSad, bool& isMaxThres, bool& isHardSC) { + double minEdgeT = m_edgeHistThreshold * MIN_EDGE_FACTOR; + double minChromaT = minEdgeT * SCENECUT_CHROMA_FACTOR; + double maxEdgeT = m_edgeHistThreshold * MAX_EDGE_FACTOR; + double maxChromaT = maxEdgeT * SCENECUT_CHROMA_FACTOR; pic->frameData.bScenecut = false; if (pic->poc == 0) @@ -1544,20 +1548,25 @@ { bDup = true; } - else if (edgeSad > m_edgeHistThreshold && maxUVSad >= m_chromaHistThreshold) + else if (edgeSad < minEdgeT && maxUVSad < minChromaT) + { + pic->frameData.bScenecut = false; + } + else if (edgeSad > maxEdgeT && maxUVSad > maxChromaT) { pic->frameData.bScenecut = true; - bDup = false; + isMaxThres = true; + isHardSC = true; } - else if (edgeSad > m_scaledEdgeThreshold || maxUVSad >= m_scaledChromaThreshold) + else if (edgeSad > m_scaledEdgeThreshold || maxUVSad >= m_scaledChromaThreshold + || (edgeSad > m_edgeHistThreshold && maxUVSad >= m_chromaHistThreshold)) { pic->frameData.bScenecut = true; bDup = false; + if (edgeSad > m_scaledEdgeThreshold || maxUVSad >= m_scaledChromaThreshold) + isHardSC = true; } } - - if (pic->frameData.bScenecut) - x265_log(m_param, X265_LOG_DEBUG, "scene cut at %d \n", pic->poc); } /** @@ -1588,6 +1597,8 @@ bool dontRead = false; bool bdropFrame = false; bool dropflag = false; + bool isMaxThres = false; + bool isHardSC = false; if (m_exportedPic) { @@ -1614,7 +1625,7 @@ { double maxUVSad = 0.0, edgeSad = 0.0; computeHistogramSAD(&maxUVSad, &edgeSad, pic_in->poc); - findSceneCuts(pic, bdropFrame, maxUVSad, edgeSad); + findSceneCuts(pic, bdropFrame, maxUVSad, edgeSad, isMaxThres, isHardSC); } } @@ -1782,6 +1793,7 @@ inFrame->m_lowres.bScenecut = false; inFrame->m_lowres.satdCost = (int64_t)-1; inFrame->m_lowresInit = false; + inFrame->m_isInsideWindow = 0; } /* Copy input picture into a Frame and PicYuv, send to lookahead */ @@ -1793,6 +1805,36 @@ if (m_param->bHistBasedSceneCut) { inFrame->m_lowres.bScenecut = (inputPic->frameData.bScenecut == 1) ? true : false; + inFrame->m_lowres.m_bIsMaxThres = isMaxThres; + if (m_param->radl && m_param->keyframeMax != m_param->keyframeMin) + inFrame->m_lowres.m_bIsHardScenecut = isHardSC; + } + + if ((m_param->bEnableSceneCutAwareQp & BACKWARD) && m_param->rc.bStatRead) + { + RateControlEntry * rcEntry = NULL; + rcEntry = &(m_rateControl->m_rce2Pass[inFrame->m_poc]); + if(rcEntry->scenecut) + { + int backwardWindow = X265_MIN(int((m_param->bwdScenecutWindow / 1000.0) * (m_param->fpsNum / m_param->fpsDenom)), p->lookaheadDepth); + for (int i = 1; i <= backwardWindow; i++) + { + int frameNum = inFrame->m_poc - i; + Frame * frame = m_lookahead->m_inputQueue.getPOC(frameNum); + if (frame) + frame->m_isInsideWindow = BACKWARD_WINDOW; + } + } + } + if (m_param->bHistBasedSceneCut && m_param->analysisSave) + { + memcpy(inFrame->m_analysisData.edgeHist, m_curEdgeHist, EDGE_BINS * sizeof(int32_t)); + memcpy(inFrame->m_analysisData.yuvHist[0], m_curYUVHist[0], HISTOGRAM_BINS *sizeof(int32_t)); + if (inputPic->colorSpace != X265_CSP_I400) + { + memcpy(inFrame->m_analysisData.yuvHist[1], m_curYUVHist[1], HISTOGRAM_BINS * sizeof(int32_t)); + memcpy(inFrame->m_analysisData.yuvHist[2], m_curYUVHist[2], HISTOGRAM_BINS * sizeof(int32_t)); + } } inFrame->m_forceqp = inputPic->forceqp; inFrame->m_param = (m_reconfigure || m_reconfigureRc) ? m_latestParam : m_param; @@ -1999,6 +2041,16 @@ pic_out->analysisData.poc = pic_out->poc; pic_out->analysisData.sliceType = pic_out->sliceType; pic_out->analysisData.bScenecut = outFrame->m_lowres.bScenecut; + if (m_param->bHistBasedSceneCut) + { + memcpy(pic_out->analysisData.edgeHist, outFrame->m_analysisData.edgeHist, EDGE_BINS * sizeof(int32_t)); + memcpy(pic_out->analysisData.yuvHist[0], outFrame->m_analysisData.yuvHist[0], HISTOGRAM_BINS * sizeof(int32_t)); + if (pic_out->colorSpace != X265_CSP_I400) + { + memcpy(pic_out->analysisData.yuvHist[1], outFrame->m_analysisData.yuvHist[1], HISTOGRAM_BINS * sizeof(int32_t)); + memcpy(pic_out->analysisData.yuvHist[2], outFrame->m_analysisData.yuvHist[2], HISTOGRAM_BINS * sizeof(int32_t)); + } + } pic_out->analysisData.satdCost = outFrame->m_lowres.satdCost; pic_out->analysisData.numCUsInFrame = outFrame->m_analysisData.numCUsInFrame; pic_out->analysisData.numPartitions = outFrame->m_analysisData.numPartitions; @@ -2190,8 +2242,23 @@ frameEnc = m_lookahead->getDecidedPicture(); if (frameEnc && !pass && (!m_param->chunkEnd || (m_encodedFrameNum < m_param->chunkEnd))) { - if (m_param->bEnableSceneCutAwareQp && frameEnc->m_lowres.bScenecut) - m_rateControl->m_lastScenecut = frameEnc->m_poc; + if ((m_param->bEnableSceneCutAwareQp & FORWARD) && m_param->rc.bStatRead) + { + RateControlEntry * rcEntry; + rcEntry = &(m_rateControl->m_rce2Pass[frameEnc->m_poc]); + + if (rcEntry->scenecut) + { + if (m_rateControl->m_lastScenecut == -1) + m_rateControl->m_lastScenecut = frameEnc->m_poc; + else + { + int maxWindowSize = int((m_param->fwdScenecutWindow / 1000.0) * (m_param->fpsNum / m_param->fpsDenom) + 0.5); + if (frameEnc->m_poc > (m_rateControl->m_lastScenecut + maxWindowSize)) + m_rateControl->m_lastScenecut = frameEnc->m_poc; + } + } + } if (m_param->analysisMultiPassRefine || m_param->analysisMultiPassDistortion) { @@ -4190,10 +4257,10 @@ p->unitSizeDepth = p->maxLog2CUSize - LOG2_UNIT_SIZE; p->num4x4Partitions = (1U << (p->unitSizeDepth << 1)); - if (p->radl && (p->keyframeMax != p->keyframeMin)) + if (p->radl && p->bOpenGOP) { p->radl = 0; - x265_log(p, X265_LOG_WARNING, "Radl requires fixed gop-length (keyint == min-keyint). Disabling radl.\n"); + x265_log(p, X265_LOG_WARNING, "Radl requires closed gop structure. Disabling radl.\n"); } if ((p->chunkStart || p->chunkEnd) && p->bOpenGOP && m_param->bResetZoneConfig) @@ -4248,7 +4315,7 @@ if (p->bHistBasedSceneCut && !p->edgeTransitionThreshold) { - p->edgeTransitionThreshold = 0.01; + p->edgeTransitionThreshold = 0.03; x265_log(p, X265_LOG_WARNING, "using default threshold %.2lf for scene cut detection\n", p->edgeTransitionThreshold); } @@ -4312,6 +4379,16 @@ analysis->frameRecordSize = frameRecordSize; X265_FREAD(&analysis->sliceType, sizeof(int), 1, m_analysisFileIn, &(picData->sliceType)); X265_FREAD(&analysis->bScenecut, sizeof(int), 1, m_analysisFileIn, &(picData->bScenecut)); + if (m_param->bHistBasedSceneCut) + { + X265_FREAD(&analysis->edgeHist, sizeof(int32_t), EDGE_BINS, m_analysisFileIn, &m_curEdgeHist); + X265_FREAD(&analysis->yuvHist[0], sizeof(int32_t), HISTOGRAM_BINS, m_analysisFileIn, &m_curYUVHist[0]); + if (m_param->internalCsp != X265_CSP_I400) + { + X265_FREAD(&analysis->yuvHist[1], sizeof(int32_t), HISTOGRAM_BINS, m_analysisFileIn, &m_curYUVHist[1]); + X265_FREAD(&analysis->yuvHist[2], sizeof(int32_t), HISTOGRAM_BINS, m_analysisFileIn, &m_curYUVHist[2]); + } + } X265_FREAD(&analysis->satdCost, sizeof(int64_t), 1, m_analysisFileIn, &(picData->satdCost)); X265_FREAD(&numCUsLoad, sizeof(int), 1, m_analysisFileIn, &(picData->numCUsInFrame)); X265_FREAD(&analysis->numPartitions, sizeof(int), 1, m_analysisFileIn, &(picData->numPartitions)); @@ -4634,6 +4711,16 @@ analysis->frameRecordSize = frameRecordSize; X265_FREAD(&analysis->sliceType, sizeof(int), 1, m_analysisFileIn, &(picData->sliceType)); X265_FREAD(&analysis->bScenecut, sizeof(int), 1, m_analysisFileIn, &(picData->bScenecut)); + if (m_param->bHistBasedSceneCut) + { + X265_FREAD(&analysis->edgeHist, sizeof(int32_t), EDGE_BINS, m_analysisFileIn, &m_curEdgeHist); + X265_FREAD(&analysis->yuvHist[0], sizeof(int32_t), HISTOGRAM_BINS, m_analysisFileIn, &m_curYUVHist[0]); + if (m_param->internalCsp != X265_CSP_I400) + { + X265_FREAD(&analysis->yuvHist[1], sizeof(int32_t), HISTOGRAM_BINS, m_analysisFileIn, &m_curYUVHist[1]); + X265_FREAD(&analysis->yuvHist[2], sizeof(int32_t), HISTOGRAM_BINS, m_analysisFileIn, &m_curYUVHist[2]); + } + } X265_FREAD(&analysis->satdCost, sizeof(int64_t), 1, m_analysisFileIn, &(picData->satdCost)); X265_FREAD(&analysis->numCUsInFrame, sizeof(int), 1, m_analysisFileIn, &(picData->numCUsInFrame)); X265_FREAD(&analysis->numPartitions, sizeof(int), 1, m_analysisFileIn, &(picData->numPartitions)); @@ -5399,6 +5486,17 @@ /* calculate frameRecordSize */ analysis->frameRecordSize = sizeof(analysis->frameRecordSize) + sizeof(depthBytes) + sizeof(analysis->poc) + sizeof(analysis->sliceType) + sizeof(analysis->numCUsInFrame) + sizeof(analysis->numPartitions) + sizeof(analysis->bScenecut) + sizeof(analysis->satdCost); + if (m_param->bHistBasedSceneCut) + { + analysis->frameRecordSize += sizeof(analysis->edgeHist); + analysis->frameRecordSize += sizeof(int32_t) * HISTOGRAM_BINS; + if (m_param->internalCsp != X265_CSP_I400) + { + analysis->frameRecordSize += sizeof(int32_t) * HISTOGRAM_BINS; + analysis->frameRecordSize += sizeof(int32_t) * HISTOGRAM_BINS; + } + } + if (analysis->sliceType > X265_TYPE_I) { numDir = (analysis->sliceType == X265_TYPE_P) ? 1 : 2; @@ -5543,6 +5641,17 @@ X265_FWRITE(&analysis->poc, sizeof(int), 1, m_analysisFileOut); X265_FWRITE(&analysis->sliceType, sizeof(int), 1, m_analysisFileOut); X265_FWRITE(&analysis->bScenecut, sizeof(int), 1, m_analysisFileOut); + if (m_param->bHistBasedSceneCut) + { + X265_FWRITE(&analysis->edgeHist, sizeof(int32_t), EDGE_BINS, m_analysisFileOut); + X265_FWRITE(&analysis->yuvHist[0], sizeof(int32_t), HISTOGRAM_BINS, m_analysisFileOut); + if (m_param->internalCsp != X265_CSP_I400) + { + X265_FWRITE(&analysis->yuvHist[1], sizeof(int32_t), HISTOGRAM_BINS, m_analysisFileOut); + X265_FWRITE(&analysis->yuvHist[2], sizeof(int32_t), HISTOGRAM_BINS, m_analysisFileOut); + } + } + X265_FWRITE(&analysis->satdCost, sizeof(int64_t), 1, m_analysisFileOut); X265_FWRITE(&analysis->numCUsInFrame, sizeof(int), 1, m_analysisFileOut); X265_FWRITE(&analysis->numPartitions, sizeof(int), 1, m_analysisFileOut); diff -Nru x265-3.4/source/encoder/encoder.h x265-3.5/source/encoder/encoder.h --- x265-3.4/source/encoder/encoder.h 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/encoder/encoder.h 2021-03-16 12:53:00.000000000 +0000 @@ -163,8 +163,11 @@ class ThreadPool; class FrameData; -#define MAX_SCENECUT_THRESHOLD 2.0 +#define MAX_SCENECUT_THRESHOLD 1.0 #define SCENECUT_STRENGTH_FACTOR 2.0 +#define MIN_EDGE_FACTOR 0.5 +#define MAX_EDGE_FACTOR 1.5 +#define SCENECUT_CHROMA_FACTOR 10.0 class Encoder : public x265_encoder { @@ -256,9 +259,8 @@ /* For histogram based scene-cut detection */ pixel* m_edgePic; pixel* m_inputPic[3]; - int32_t m_curUVHist[2][HISTOGRAM_BINS]; - int32_t m_curMaxUVHist[HISTOGRAM_BINS]; - int32_t m_prevMaxUVHist[HISTOGRAM_BINS]; + int32_t m_curYUVHist[3][HISTOGRAM_BINS]; + int32_t m_prevYUVHist[3][HISTOGRAM_BINS]; int32_t m_curEdgeHist[2]; int32_t m_prevEdgeHist[2]; uint32_t m_planeSizes[3]; @@ -373,7 +375,8 @@ bool computeHistograms(x265_picture *pic); void computeHistogramSAD(double *maxUVNormalizedSAD, double *edgeNormalizedSAD, int curPoc); - void findSceneCuts(x265_picture *pic, bool& bDup, double m_maxUVSADVal, double m_edgeSADVal); + double normalizeRange(int32_t value, int32_t minValue, int32_t maxValue, double rangeStart, double rangeEnd); + void findSceneCuts(x265_picture *pic, bool& bDup, double m_maxUVSADVal, double m_edgeSADVal, bool& isMaxThres, bool& isHardSC); void initRefIdx(); void analyseRefIdx(int *numRefIdx); diff -Nru x265-3.4/source/encoder/frameencoder.cpp x265-3.5/source/encoder/frameencoder.cpp --- x265-3.4/source/encoder/frameencoder.cpp 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/encoder/frameencoder.cpp 2021-03-16 12:53:00.000000000 +0000 @@ -47,8 +47,6 @@ m_slicetypeWaitTime = 0; m_activeWorkerCount = 0; m_completionCount = 0; - m_bAllRowsStop = false; - m_vbvResetTriggerRow = -1; m_outStreams = NULL; m_backupStreams = NULL; m_substreamSizes = NULL; @@ -88,6 +86,8 @@ delete[] m_outStreams; delete[] m_backupStreams; X265_FREE(m_sliceBaseRow); + X265_FREE((void*)m_bAllRowsStop); + X265_FREE((void*)m_vbvResetTriggerRow); X265_FREE(m_sliceMaxBlockRow); X265_FREE(m_cuGeoms); X265_FREE(m_ctuGeomMap); @@ -118,6 +118,8 @@ bool ok = !!m_numRows; m_sliceBaseRow = X265_MALLOC(uint32_t, m_param->maxSlices + 1); + m_bAllRowsStop = X265_MALLOC(bool, m_param->maxSlices); + m_vbvResetTriggerRow = X265_MALLOC(int, m_param->maxSlices); ok &= !!m_sliceBaseRow; m_sliceGroupSize = (uint16_t)(m_numRows + m_param->maxSlices - 1) / m_param->maxSlices; uint32_t sliceGroupSizeAccu = (m_numRows << 8) / m_param->maxSlices; @@ -438,8 +440,8 @@ m_stallStartTime = 0; m_completionCount = 0; - m_bAllRowsStop = false; - m_vbvResetTriggerRow = -1; + memset((void*)m_bAllRowsStop, 0, sizeof(bool) * m_param->maxSlices); + memset((void*)m_vbvResetTriggerRow, -1, sizeof(int) * m_param->maxSlices); m_rowSliceTotalBits[0] = 0; m_rowSliceTotalBits[1] = 0; @@ -1469,16 +1471,16 @@ curRow.bufferedEntropy.copyState(rowCoder); curRow.bufferedEntropy.loadContexts(rowCoder); } - if (bFirstRowInSlice && m_vbvResetTriggerRow != intRow) + if (bFirstRowInSlice && m_vbvResetTriggerRow[curRow.sliceId] != intRow) { curEncData.m_rowStat[row].rowQp = curEncData.m_avgQpRc; curEncData.m_rowStat[row].rowQpScale = x265_qp2qScale(curEncData.m_avgQpRc); } FrameData::RCStatCU& cuStat = curEncData.m_cuStat[cuAddr]; - if (m_param->bEnableWavefront && rowInSlice >= col && !bFirstRowInSlice && m_vbvResetTriggerRow != intRow) + if (m_param->bEnableWavefront && rowInSlice >= col && !bFirstRowInSlice && m_vbvResetTriggerRow[curRow.sliceId] != intRow) cuStat.baseQp = curEncData.m_cuStat[cuAddr - numCols + 1].baseQp; - else if (!m_param->bEnableWavefront && !bFirstRowInSlice && m_vbvResetTriggerRow != intRow) + else if (!m_param->bEnableWavefront && !bFirstRowInSlice && m_vbvResetTriggerRow[curRow.sliceId] != intRow) cuStat.baseQp = curEncData.m_rowStat[row - 1].rowQp; else cuStat.baseQp = curEncData.m_rowStat[row].rowQp; @@ -1655,7 +1657,7 @@ x265_log(m_param, X265_LOG_DEBUG, "POC %d row %d - encode restart required for VBV, to %.2f from %.2f\n", m_frame->m_poc, row, qpBase, curEncData.m_cuStat[cuAddr].baseQp); - m_vbvResetTriggerRow = row; + m_vbvResetTriggerRow[curRow.sliceId] = row; m_outStreams[0].copyBits(&m_backupStreams[0]); rowCoder.copyState(curRow.bufferedEntropy); @@ -1707,8 +1709,8 @@ m_frame->m_poc, row, qpBase, curEncData.m_cuStat[cuAddr].baseQp); // prevent the WaveFront::findJob() method from providing new jobs - m_vbvResetTriggerRow = row; - m_bAllRowsStop = true; + m_vbvResetTriggerRow[curRow.sliceId] = row; + m_bAllRowsStop[curRow.sliceId] = true; for (uint32_t r = m_sliceBaseRow[sliceId + 1] - 1; r >= row; r--) { @@ -1720,7 +1722,7 @@ stopRow.lock.acquire(); while (stopRow.active) { - if (dequeueRow(r * 2)) + if (dequeueRow(m_row_to_idx[r] * 2)) stopRow.active = false; else { @@ -1758,13 +1760,13 @@ curEncData.m_rowStat[r].sumQpAq = 0; } - m_bAllRowsStop = false; + m_bAllRowsStop[curRow.sliceId] = false; } } } if (m_param->bEnableWavefront && curRow.completed >= 2 && !bLastRowInSlice && - (!m_bAllRowsStop || intRow + 1 < m_vbvResetTriggerRow)) + (!m_bAllRowsStop[curRow.sliceId] || intRow + 1 < m_vbvResetTriggerRow[curRow.sliceId])) { /* activate next row */ ScopedLock below(m_rows[row + 1].lock); @@ -1779,7 +1781,7 @@ } ScopedLock self(curRow.lock); - if ((m_bAllRowsStop && intRow > m_vbvResetTriggerRow) || + if ((m_bAllRowsStop[curRow.sliceId] && intRow > m_vbvResetTriggerRow[curRow.sliceId]) || (!bFirstRowInSlice && ((curRow.completed < numCols - 1) || (m_rows[row - 1].completed < numCols)) && m_rows[row - 1].completed < curRow.completed + 2)) { curRow.active = false; diff -Nru x265-3.4/source/encoder/frameencoder.h x265-3.5/source/encoder/frameencoder.h --- x265-3.4/source/encoder/frameencoder.h 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/encoder/frameencoder.h 2021-03-16 12:53:00.000000000 +0000 @@ -140,9 +140,9 @@ int m_localTldIdx; bool m_reconfigure; /* reconfigure in progress */ volatile bool m_threadActive; - volatile bool m_bAllRowsStop; + volatile bool *m_bAllRowsStop; volatile int m_completionCount; - volatile int m_vbvResetTriggerRow; + volatile int *m_vbvResetTriggerRow; volatile int m_sliceCnt; uint32_t m_numRows; diff -Nru x265-3.4/source/encoder/ratecontrol.cpp x265-3.5/source/encoder/ratecontrol.cpp --- x265-3.4/source/encoder/ratecontrol.cpp 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/encoder/ratecontrol.cpp 2021-03-16 12:53:00.000000000 +0000 @@ -356,6 +356,8 @@ m_bufferFillFinal = m_bufferSize * m_param->rc.vbvBufferInit; m_bufferFillActual = m_bufferFillFinal; m_bufferExcess = 0; + m_minBufferFill = m_param->minVbvFullness / 100; + m_maxBufferFill = 1 - (m_param->maxVbvFullness / 100); m_initVbv = true; } @@ -580,7 +582,7 @@ double totalQpAq = 0; for (int i = 0; i < m_numEntries; i++) { - RateControlEntry *rce; + RateControlEntry *rce, *rcePocOrder; int frameNumber; int encodeOrder; char picType; @@ -597,13 +599,16 @@ return false; } rce = &m_rce2Pass[encodeOrder]; + rcePocOrder = &m_rce2Pass[frameNumber]; m_encOrder[frameNumber] = encodeOrder; if (!m_param->bMultiPassOptRPS) { - e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf q-noVbv:%lf q-Rceq:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf", + int scenecut = 0; + e += sscanf(p, " in:%*d out:%*d type:%c q:%lf q-aq:%lf q-noVbv:%lf q-Rceq:%lf tex:%d mv:%d misc:%d icu:%lf pcu:%lf scu:%lf sc:%d", &picType, &qpRc, &qpAq, &qNoVbv, &qRceq, &rce->coeffBits, &rce->mvBits, &rce->miscBits, &rce->iCuCount, &rce->pCuCount, - &rce->skipCuCount); + &rce->skipCuCount, &scenecut); + rcePocOrder->scenecut = scenecut != 0; } else { @@ -1311,7 +1316,8 @@ copyRceData(rce, &m_rce2Pass[index]); } rce->isActive = true; - rce->scenecut = false; + if (!m_param->rc.bStatRead) + rce->scenecut = false; rce->isFadeEnd = curFrame->m_lowres.bIsFadeEnd; bool isRefFrameScenecut = m_sliceType!= I_SLICE && m_curSlice->m_refFrameList[0][0]->m_lowres.bScenecut; m_isFirstMiniGop = m_sliceType == I_SLICE ? true : m_isFirstMiniGop; @@ -1751,34 +1757,32 @@ g_sliceTypeToChar[m_sliceType], g_sliceTypeToChar[rce->sliceType]); } } - else + + if ((m_param->bliveVBV2pass && m_param->rc.rateControlMode == X265_RC_ABR) || m_isAbr) { - if (m_isAbr) + int pos = m_sliderPos % s_slidingWindowFrames; + int addPos = (pos + s_slidingWindowFrames - 1) % s_slidingWindowFrames; + if (m_sliderPos > s_slidingWindowFrames) { - int pos = m_sliderPos % s_slidingWindowFrames; - int addPos = (pos + s_slidingWindowFrames - 1) % s_slidingWindowFrames; - if (m_sliderPos > s_slidingWindowFrames) - { - const static double base = pow(0.5, s_slidingWindowFrames - 1); - m_movingAvgSum -= m_lastRemovedSatdCost * base; - m_movingAvgSum *= 0.5; - m_movingAvgSum += m_satdCostWindow[addPos]; - } - else if (m_sliderPos == s_slidingWindowFrames) - { - m_movingAvgSum += m_satdCostWindow[addPos]; - } - else if (m_sliderPos > 0) - { - m_movingAvgSum += m_satdCostWindow[addPos]; - m_movingAvgSum *= 0.5; - } - - rce->movingAvgSum = m_movingAvgSum; - m_lastRemovedSatdCost = m_satdCostWindow[pos]; - m_satdCostWindow[pos] = rce->lastSatd; - m_sliderPos++; + const static double base = pow(0.5, s_slidingWindowFrames - 1); + m_movingAvgSum -= m_lastRemovedSatdCost * base; + m_movingAvgSum *= 0.5; + m_movingAvgSum += m_satdCostWindow[addPos]; + } + else if (m_sliderPos == s_slidingWindowFrames) + { + m_movingAvgSum += m_satdCostWindow[addPos]; + } + else if (m_sliderPos > 0) + { + m_movingAvgSum += m_satdCostWindow[addPos]; + m_movingAvgSum *= 0.5; } + + rce->movingAvgSum = m_movingAvgSum; + m_lastRemovedSatdCost = m_satdCostWindow[pos]; + m_satdCostWindow[pos] = rce->lastSatd; + m_sliderPos++; } if (m_sliceType == B_SLICE) @@ -1856,11 +1860,15 @@ { double lqmin = m_lmin[m_sliceType]; double lqmax = m_lmax[m_sliceType]; - qScale = scenecutAwareQp(curFrame, qScale); + if (m_param->bEnableSceneCutAwareQp & FORWARD) + qScale = forwardMasking(curFrame, qScale); + if (m_param->bEnableSceneCutAwareQp & BACKWARD) + qScale = backwardMasking(curFrame, qScale); qScale = x265_clip3(lqmin, lqmax, qScale); q = x265_qScale2qp(qScale); rce->qpNoVbv = q; } + if (m_isVbv) { lmin = m_lastQScaleFor[P_SLICE] / m_lstep; @@ -1882,7 +1890,7 @@ qScale = x265_clip3(lqmin, lqmax, qScale); } - if (!m_2pass) + if (!m_2pass || m_param->bliveVBV2pass) { /* clip qp to permissible range after vbv-lookahead estimation to avoid possible * mispredictions by initial frame size predictors */ @@ -1950,7 +1958,9 @@ else q /= zone->bitrateFactor; } - q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) / abrBuffer); + /*Existing ABR conformance check may not be valid with real time VBV*/ + if(!m_param->bliveVBV2pass) + q /= x265_clip3(0.5, 2.0, (double)(abrBuffer - diff) / abrBuffer); if (m_expectedBitsSum > 0) { /* Adjust quant based on the difference between @@ -1971,26 +1981,51 @@ m_avgPFrameQp = (m_avgPFrameQp + rce->qpNoVbv) / 2; } + /* Scenecut Aware QP offsets*/ + if (m_param->bEnableSceneCutAwareQp) + { + double qmin = m_lmin[m_sliceType]; + double qmax = m_lmax[m_sliceType]; + + if (m_param->bEnableSceneCutAwareQp & FORWARD) + q = forwardMasking(curFrame, q); + if (m_param->bEnableSceneCutAwareQp & BACKWARD) + q = backwardMasking(curFrame, q); + + q = x265_clip3(qmin, qmax, q); + rce->qpNoVbv = x265_qScale2qp(q); + } + if (m_isVbv) { - /* Do not overflow vbv */ - double expectedSize = qScale2bits(rce, q); - double expectedVbv = m_bufferFill + m_bufferRate - expectedSize; - double expectedFullness = rce->expectedVbv / m_bufferSize; - double qmax = q * (2 - expectedFullness); - double sizeConstraint = 1 + expectedFullness; - qmax = X265_MAX(qmax, rce->newQScale); - if (expectedFullness < .05) - qmax = lmax; - qmax = X265_MIN(qmax, lmax); - while (((expectedVbv < rce->expectedVbv/sizeConstraint) && (q < qmax)) || + if (!m_param->bliveVBV2pass) + { + /* Do not overflow vbv */ + double expectedSize = qScale2bits(rce, q); + double expectedVbv = m_bufferFill + m_bufferRate - expectedSize; + double expectedFullness = rce->expectedVbv / m_bufferSize; + double qmax = q * (2 - expectedFullness); + double sizeConstraint = 1 + expectedFullness; + qmax = X265_MAX(qmax, rce->newQScale); + if (expectedFullness < .05) + qmax = lmax; + qmax = X265_MIN(qmax, lmax); + while (((expectedVbv < rce->expectedVbv / sizeConstraint) && (q < qmax)) || ((expectedVbv < 0) && (q < lmax))) + { + q *= 1.05; + expectedSize = qScale2bits(rce, q); + expectedVbv = m_bufferFill + m_bufferRate - expectedSize; + } + } + else { - q *= 1.05; - expectedSize = qScale2bits(rce, q); - expectedVbv = m_bufferFill + m_bufferRate - expectedSize; + /* clip qp to permissible range after vbv-lookahead estimation to avoid possible + * mispredictions by Rate Control pass 1 statistics analysis */ + q = clipQscale(curFrame, rce, q); } } + q = x265_clip3(lmin, lmax, q); } else @@ -2120,13 +2155,17 @@ { double qmin = m_lmin[m_sliceType]; double qmax = m_lmax[m_sliceType]; - q = scenecutAwareQp(curFrame, q); + + if (m_param->bEnableSceneCutAwareQp & FORWARD) + q = forwardMasking(curFrame, q); + if (m_param->bEnableSceneCutAwareQp & BACKWARD) + q = backwardMasking(curFrame, q); + q = x265_clip3(qmin, qmax, q); rce->qpNoVbv = x265_qScale2qp(q); } q = clipQscale(curFrame, rce, q); - if (m_2pass) rce->frameSizePlanned = qScale2bits(rce, q); else @@ -2356,7 +2395,7 @@ { finalDur = x265_clip3(0.4, 1.0, totalDuration); } - targetFill = X265_MIN(m_bufferFill + totalDuration * m_vbvMaxRate * 0.5, m_bufferSize * (1 - 0.5 * finalDur)); + targetFill = X265_MIN(m_bufferFill + totalDuration * m_vbvMaxRate * 0.5, m_bufferSize * (1 - m_minBufferFill * finalDur)); if (bufferFillCur < targetFill) { q *= 1.01; @@ -2364,8 +2403,9 @@ continue; } /* Try to get the buffer not more than 80% filled, but don't set an impossible goal. */ - targetFill = x265_clip3(m_bufferSize * (1 - 0.2 * finalDur), m_bufferSize, m_bufferFill - totalDuration * m_vbvMaxRate * 0.5); - if (m_isCbr && bufferFillCur > targetFill && !m_isSceneTransition) + + targetFill = x265_clip3(m_bufferSize * (1 - m_maxBufferFill * finalDur), m_bufferSize, m_bufferFill - totalDuration * m_vbvMaxRate * 0.5); + if ((m_isCbr || m_2pass) && bufferFillCur > targetFill && !m_isSceneTransition) { q /= 1.01; loopTerminate |= 2; @@ -2381,7 +2421,7 @@ /* Fallback to old purely-reactive algorithm: no lookahead. */ if ((m_sliceType == P_SLICE || m_sliceType == B_SLICE || (m_sliceType == I_SLICE && m_lastNonBPictType == I_SLICE)) && - m_bufferFill / m_bufferSize < 0.5) + m_bufferFill / m_bufferSize < m_minBufferFill) { q /= x265_clip3(0.5, 1.0, 2.0 * m_bufferFill / m_bufferSize); } @@ -2418,7 +2458,7 @@ * lookahead vbv reduces its qscale by half its value. Be on safer side and avoid drastic * qscale reductions for frames high in complexity */ bool mispredCheck = rce->movingAvgSum && m_currentSatd >= rce->movingAvgSum && q <= q0 / 2; - if (!m_isCbr || (m_isAbr && mispredCheck)) + if (!m_isCbr || ((m_isAbr || m_2pass) && mispredCheck)) q = X265_MAX(q0, q); if (m_rateFactorMaxIncrement) @@ -2428,7 +2468,7 @@ return x265_clip3(lmin, qmax, q); } } - if (m_2pass) + if (!curFrame && m_2pass) { double min = log(lmin); double max = log(lmax); @@ -2529,13 +2569,7 @@ double qScaleVbv = x265_qp2qScale(qpVbv); uint64_t rowSatdCost = curEncData.m_rowStat[row].rowSatd; double encodedBits = curEncData.m_rowStat[row].encodedBits; - uint32_t rowInSlice = row - m_sliceBaseRow[sliceId]; - if (m_param->bEnableWavefront && rowInSlice == 1) - { - rowSatdCost += curEncData.m_rowStat[row - 1].rowSatd; - encodedBits += curEncData.m_rowStat[row - 1].encodedBits; - } rowSatdCost >>= X265_DEPTH - 8; updatePredictor(rce->rowPred[0], qScaleVbv, (double)rowSatdCost, encodedBits); if (curEncData.m_slice->m_sliceType != I_SLICE && !m_param->rc.bEnableConstVbv) @@ -2544,8 +2578,6 @@ if (qpVbv < refFrame->m_encData->m_rowStat[row].rowQp) { uint64_t intraRowSatdCost = curEncData.m_rowStat[row].rowIntraSatd; - if (m_param->bEnableWavefront && rowInSlice == 1) - intraRowSatdCost += curEncData.m_rowStat[row - 1].rowIntraSatd; intraRowSatdCost >>= X265_DEPTH - 8; updatePredictor(rce->rowPred[1], qScaleVbv, (double)intraRowSatdCost, encodedBits); } @@ -2964,7 +2996,7 @@ if (!curEncData.m_param->bMultiPassOptRPS) { if (fprintf(m_statFileOut, - "in:%d out:%d type:%c q:%.2f q-aq:%.2f q-noVbv:%.2f q-Rceq:%.2f tex:%d mv:%d misc:%d icu:%.2f pcu:%.2f scu:%.2f ;\n", + "in:%d out:%d type:%c q:%.2f q-aq:%.2f q-noVbv:%.2f q-Rceq:%.2f tex:%d mv:%d misc:%d icu:%.2f pcu:%.2f scu:%.2f sc:%d ;\n", rce->poc, rce->encodeOrder, cType, curEncData.m_avgQpRc, curEncData.m_avgQpAq, rce->qpNoVbv, rce->qRceq, @@ -2973,7 +3005,8 @@ curFrame->m_encData->m_frameStats.miscBits, curFrame->m_encData->m_frameStats.percent8x8Intra * m_ncu, curFrame->m_encData->m_frameStats.percent8x8Inter * m_ncu, - curFrame->m_encData->m_frameStats.percent8x8Skip * m_ncu) < 0) + curFrame->m_encData->m_frameStats.percent8x8Skip * m_ncu, + curFrame->m_lowres.bScenecut) < 0) goto writeFailure; } else @@ -3150,51 +3183,94 @@ } } -double RateControl::scenecutAwareQp(Frame* curFrame, double q) +double RateControl::forwardMasking(Frame* curFrame, double q) { - uint32_t maxWindowSize = uint32_t((m_param->scenecutWindow / 1000.0) * (m_param->fpsNum / m_param->fpsDenom) + 0.5); + double qp = x265_qScale2qp(q); + uint32_t maxWindowSize = uint32_t((m_param->fwdScenecutWindow / 1000.0) * (m_param->fpsNum / m_param->fpsDenom) + 0.5); uint32_t windowSize = maxWindowSize / 3; int lastScenecut = m_top->m_rateControl->m_lastScenecut; int lastIFrame = m_top->m_rateControl->m_lastScenecutAwareIFrame; - double maxQpDelta = x265_qp2qScale(double(m_param->maxQpDelta)); - double iSliceDelta = x265_qp2qScale(double(I_SLICE_DELTA)); - double sliceTypeDelta = SLICE_TYPE_DELTA * maxQpDelta; - double window2Delta = WINDOW2_DELTA * maxQpDelta; - double window3Delta = WINDOW3_DELTA * maxQpDelta; + double fwdRefQpDelta = double(m_param->fwdRefQpDelta); + double fwdNonRefQpDelta = double(m_param->fwdNonRefQpDelta); + double sliceTypeDelta = SLICE_TYPE_DELTA * fwdRefQpDelta; - bool isFrameInsideWindow = curFrame->m_poc > lastScenecut && curFrame->m_poc <= (lastScenecut + int(maxWindowSize)); - - if (isFrameInsideWindow && IS_X265_TYPE_I(curFrame->m_lowres.sliceType)) - { - m_top->m_rateControl->m_lastScenecutAwareIFrame = curFrame->m_poc; - } - else if (isFrameInsideWindow && (curFrame->m_lowres.sliceType == X265_TYPE_P)) + //Check whether the current frame is within the forward window + if (curFrame->m_poc > lastScenecut && curFrame->m_poc <= (lastScenecut + int(maxWindowSize))) + curFrame->m_isInsideWindow = FORWARD_WINDOW; + if (curFrame->m_isInsideWindow == FORWARD_WINDOW) { - if (!(lastIFrame > lastScenecut && lastIFrame <= (lastScenecut + int(maxWindowSize)) - && curFrame->m_poc > lastIFrame)) + if (IS_X265_TYPE_I(curFrame->m_lowres.sliceType) || curFrame->m_lowres.bScenecut) { - q += maxQpDelta - sliceTypeDelta; - if (((curFrame->m_poc) > (lastScenecut + int(windowSize))) && ((curFrame->m_poc) <= (lastScenecut + 2 * int(windowSize)))) - q -= window2Delta; - else if (curFrame->m_poc > lastScenecut + 2 * int(windowSize)) - q -= window3Delta; + m_top->m_rateControl->m_lastScenecutAwareIFrame = curFrame->m_poc; } - } - else if (isFrameInsideWindow && IS_X265_TYPE_B(curFrame->m_lowres.sliceType)) - { - if (!(lastIFrame > lastScenecut && lastIFrame <= (lastScenecut + int(maxWindowSize)) - && curFrame->m_poc > lastIFrame)) + else if (curFrame->m_lowres.sliceType == X265_TYPE_P) + { + if (!(lastIFrame > lastScenecut && lastIFrame <= (lastScenecut + int(maxWindowSize)) + && curFrame->m_poc >= lastIFrame)) + { + //Add offsets corresponding to the window in which the P-frame occurs + if (curFrame->m_poc <= (lastScenecut + int(windowSize))) + qp += WINDOW1_DELTA * (fwdRefQpDelta - sliceTypeDelta); + else if (((curFrame->m_poc) > (lastScenecut + int(windowSize))) && ((curFrame->m_poc) <= (lastScenecut + 2 * int(windowSize)))) + qp += WINDOW2_DELTA * (fwdRefQpDelta - sliceTypeDelta); + else if (curFrame->m_poc > lastScenecut + 2 * int(windowSize)) + qp += WINDOW3_DELTA * (fwdRefQpDelta - sliceTypeDelta); + } + } + else if (curFrame->m_lowres.sliceType == X265_TYPE_BREF) + { + if (!(lastIFrame > lastScenecut && lastIFrame <= (lastScenecut + int(maxWindowSize)) + && curFrame->m_poc >= lastIFrame)) + { + //Add offsets corresponding to the window in which the B-frame occurs + if (curFrame->m_poc <= (lastScenecut + int(windowSize))) + qp += WINDOW1_DELTA * fwdRefQpDelta; + else if (((curFrame->m_poc) > (lastScenecut + int(windowSize))) && ((curFrame->m_poc) <= (lastScenecut + 2 * int(windowSize)))) + qp += WINDOW2_DELTA * fwdRefQpDelta; + else if (curFrame->m_poc > lastScenecut + 2 * int(windowSize)) + qp += WINDOW3_DELTA * fwdRefQpDelta; + } + } + else if (curFrame->m_lowres.sliceType == X265_TYPE_B) { - q += maxQpDelta; - if (curFrame->m_lowres.sliceType == X265_TYPE_B) - q += sliceTypeDelta; - if (((curFrame->m_poc) > (lastScenecut + int(windowSize))) && ((curFrame->m_poc) <= (lastScenecut + 2 * int(windowSize)))) - q -= window2Delta; - else if (curFrame->m_poc > lastScenecut + 2 * int(windowSize)) - q -= window3Delta; + if (!(lastIFrame > lastScenecut && lastIFrame <= (lastScenecut + int(maxWindowSize)) + && curFrame->m_poc >= lastIFrame)) + { + //Add offsets corresponding to the window in which the b-frame occurs + if (curFrame->m_poc <= (lastScenecut + int(windowSize))) + qp += WINDOW1_DELTA * fwdNonRefQpDelta; + else if (((curFrame->m_poc) > (lastScenecut + int(windowSize))) && ((curFrame->m_poc) <= (lastScenecut + 2 * int(windowSize)))) + qp += WINDOW2_DELTA * fwdNonRefQpDelta; + else if (curFrame->m_poc > lastScenecut + 2 * int(windowSize)) + qp += WINDOW3_DELTA * fwdNonRefQpDelta; + } } } - if (IS_X265_TYPE_I(curFrame->m_lowres.sliceType) && curFrame->m_lowres.bScenecut) - q = q - iSliceDelta; - return q; + + return x265_qp2qScale(qp); +} +double RateControl::backwardMasking(Frame* curFrame, double q) +{ + double qp = x265_qScale2qp(q); + double fwdRefQpDelta = double(m_param->fwdRefQpDelta); + double bwdRefQpDelta = double(m_param->bwdRefQpDelta); + double bwdNonRefQpDelta = double(m_param->bwdNonRefQpDelta); + + if (curFrame->m_isInsideWindow == BACKWARD_WINDOW) + { + if (bwdRefQpDelta < 0) + bwdRefQpDelta = WINDOW3_DELTA * fwdRefQpDelta; + double sliceTypeDelta = SLICE_TYPE_DELTA * bwdRefQpDelta; + if (bwdNonRefQpDelta < 0) + bwdNonRefQpDelta = bwdRefQpDelta + sliceTypeDelta; + + if (curFrame->m_lowres.sliceType == X265_TYPE_P) + qp += bwdRefQpDelta - sliceTypeDelta; + else if (curFrame->m_lowres.sliceType == X265_TYPE_BREF) + qp += bwdRefQpDelta; + else if (curFrame->m_lowres.sliceType == X265_TYPE_B) + qp += bwdNonRefQpDelta; + } + + return x265_qp2qScale(qp); } diff -Nru x265-3.4/source/encoder/ratecontrol.h x265-3.5/source/encoder/ratecontrol.h --- x265-3.4/source/encoder/ratecontrol.h 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/encoder/ratecontrol.h 2021-03-16 12:53:00.000000000 +0000 @@ -47,11 +47,9 @@ #define CLIP_DURATION(f) x265_clip3(MIN_FRAME_DURATION, MAX_FRAME_DURATION, f) /*Scenecut Aware QP*/ -#define I_SLICE_DELTA 2 /* Subtracted from base QP for the scenecut I frames*/ -#define SLICE_TYPE_DELTA 0.3 /* The offset decremented or incremented for P-frames or b-frames respectively*/ -#define WINDOW1_DELTA 0 /* The offset for the frames coming in the window-1*/ -#define WINDOW2_DELTA 0.3 /* The offset for the frames coming in the window-2*/ -#define WINDOW3_DELTA 0.6 /* The offset for the frames coming in the window-3*/ +#define WINDOW1_DELTA 1.0 /* The offset for the frames coming in the window-1*/ +#define WINDOW2_DELTA 0.7 /* The offset for the frames coming in the window-2*/ +#define WINDOW3_DELTA 0.4 /* The offset for the frames coming in the window-3*/ struct Predictor { @@ -166,6 +164,8 @@ double m_avgPFrameQp; double m_bufferFillActual; double m_bufferExcess; + double m_minBufferFill; + double m_maxBufferFill; bool m_isFirstMiniGop; Predictor m_pred[4]; /* Slice predictors to preidct bits for each Slice type - I,P,Bref and B */ int64_t m_leadingNoBSatd; @@ -271,7 +271,8 @@ int writeRateControlFrameStats(Frame* curFrame, RateControlEntry* rce); bool initPass2(); - double scenecutAwareQp(Frame* curFrame, double q); + double forwardMasking(Frame* curFrame, double q); + double backwardMasking(Frame* curFrame, double q); protected: diff -Nru x265-3.4/source/encoder/slicetype.cpp x265-3.5/source/encoder/slicetype.cpp --- x265-3.4/source/encoder/slicetype.cpp 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/encoder/slicetype.cpp 2021-03-16 12:53:00.000000000 +0000 @@ -1497,14 +1497,15 @@ } } - if (m_lastNonB && !m_param->rc.bStatRead && + if (m_lastNonB && ((m_param->bFrameAdaptive && m_param->bframes) || m_param->rc.cuTree || m_param->scenecutThreshold || m_param->bHistBasedSceneCut || (m_param->lookaheadDepth && m_param->rc.vbvBufferSize))) { - slicetypeAnalyse(frames, false); + if(!m_param->rc.bStatRead) + slicetypeAnalyse(frames, false); bool bIsVbv = m_param->rc.vbvBufferSize > 0 && m_param->rc.vbvMaxBitrate > 0; - if (m_param->analysisLoad && m_param->scaleFactor && bIsVbv) + if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv) || m_param->bliveVBV2pass) { int numFrames; for (numFrames = 0; numFrames < maxSearch; numFrames++) @@ -1513,13 +1514,14 @@ if (!fenc) break; } - vbvLookahead(frames, numFrames, true); + vbvLookahead(frames, numFrames, false); } } int bframes, brefs; if (!m_param->analysisLoad || m_param->bAnalysisType == HEVC_INFO) { + bool isClosedGopRadl = m_param->radl && (m_param->keyframeMax != m_param->keyframeMin); for (bframes = 0, brefs = 0;; bframes++) { Lowres& frm = list[bframes]->m_lowres; @@ -1579,6 +1581,15 @@ else frm.sliceType = X265_TYPE_IDR; } + if (frm.sliceType == X265_TYPE_IDR && frm.bScenecut && isClosedGopRadl) + { + if (!m_param->bHistBasedSceneCut || (m_param->bHistBasedSceneCut && frm.m_bIsHardScenecut)) + { + for (int i = bframes; i < bframes + m_param->radl; i++) + list[i]->m_lowres.sliceType = X265_TYPE_B; + list[(bframes + m_param->radl)]->m_lowres.sliceType = X265_TYPE_IDR; + } + } if (frm.sliceType == X265_TYPE_IDR) { /* Closed GOP */ @@ -1739,7 +1750,7 @@ } } - bool isKeyFrameAnalyse = (m_param->rc.cuTree || (m_param->rc.vbvBufferSize && m_param->lookaheadDepth)) && !m_param->rc.bStatRead; + bool isKeyFrameAnalyse = (m_param->rc.cuTree || (m_param->rc.vbvBufferSize && m_param->lookaheadDepth)); if (isKeyFrameAnalyse && IS_X265_TYPE_I(m_lastNonB->sliceType)) { m_inputLock.acquire(); @@ -1754,9 +1765,10 @@ m_inputLock.release(); frames[j + 1] = NULL; - slicetypeAnalyse(frames, true); + if (!m_param->rc.bStatRead) + slicetypeAnalyse(frames, true); bool bIsVbv = m_param->rc.vbvBufferSize > 0 && m_param->rc.vbvMaxBitrate > 0; - if (m_param->analysisLoad && m_param->scaleFactor && bIsVbv) + if ((m_param->analysisLoad && m_param->scaleFactor && bIsVbv) || m_param->bliveVBV2pass) { int numFrames; for (numFrames = 0; numFrames < maxSearch; numFrames++) @@ -1774,7 +1786,7 @@ void Lookahead::vbvLookahead(Lowres **frames, int numFrames, int keyframe) { int prevNonB = 0, curNonB = 1, idx = 0; - while (curNonB < numFrames && frames[curNonB]->sliceType == X265_TYPE_B) + while (curNonB < numFrames && IS_X265_TYPE_B(frames[curNonB]->sliceType)) curNonB++; int nextNonB = keyframe ? prevNonB : curNonB; int nextB = prevNonB + 1; @@ -1841,7 +1853,7 @@ } prevNonB = curNonB; curNonB++; - while (curNonB <= numFrames && frames[curNonB]->sliceType == X265_TYPE_B) + while (curNonB <= numFrames && IS_X265_TYPE_B(frames[curNonB]->sliceType)) curNonB++; } @@ -2001,10 +2013,41 @@ int numAnalyzed = numFrames; bool isScenecut = false; - /* When scenecut threshold is set, use scenecut detection for I frame placements */ + /* Temporal computations for scenecut detection */ if (m_param->bHistBasedSceneCut) - isScenecut = frames[1]->bScenecut; - else + { + for (int i = numFrames - 1; i > 0; i--) + { + if (frames[i]->interPCostPercDiff > 0.0) + continue; + int64_t interCost = frames[i]->costEst[1][0]; + int64_t intraCost = frames[i]->costEst[0][0]; + if (interCost < 0 || intraCost < 0) + continue; + int times = 0; + double averagePcost = 0.0, averageIcost = 0.0; + for (int j = i - 1; j >= 0 && times < 5; j--, times++) + { + if (frames[j]->costEst[0][0] > 0 && frames[j]->costEst[1][0] > 0) + { + averageIcost += frames[j]->costEst[0][0]; + averagePcost += frames[j]->costEst[1][0]; + } + else + times--; + } + if (times) + { + averageIcost = averageIcost / times; + averagePcost = averagePcost / times; + frames[i]->interPCostPercDiff = abs(interCost - averagePcost) / X265_MIN(interCost, averagePcost) * 100; + frames[i]->intraCostPercDiff = abs(intraCost - averageIcost) / X265_MIN(intraCost, averageIcost) * 100; + } + } + } + + /* When scenecut threshold is set, use scenecut detection for I frame placements */ + if (!m_param->bHistBasedSceneCut || (m_param->bHistBasedSceneCut && frames[1]->bScenecut)) isScenecut = scenecut(frames, 0, 1, true, origNumFrames); if (isScenecut && (m_param->bHistBasedSceneCut || m_param->scenecutThreshold)) @@ -2018,17 +2061,16 @@ m_extendGopBoundary = false; for (int i = m_param->bframes + 1; i < origNumFrames; i += m_param->bframes + 1) { - if (!m_param->bHistBasedSceneCut) + if (!m_param->bHistBasedSceneCut || (m_param->bHistBasedSceneCut && frames[i + 1]->bScenecut)) scenecut(frames, i, i + 1, true, origNumFrames); for (int j = i + 1; j <= X265_MIN(i + m_param->bframes + 1, origNumFrames); j++) { - if ((!m_param->bHistBasedSceneCut && frames[j]->bScenecut && scenecutInternal(frames, j - 1, j, true)) || - (m_param->bHistBasedSceneCut && frames[j]->bScenecut)) - { - m_extendGopBoundary = true; - break; - } + if (frames[j]->bScenecut && scenecutInternal(frames, j - 1, j, true)) + { + m_extendGopBoundary = true; + break; + } } if (m_extendGopBoundary) break; @@ -2117,7 +2159,7 @@ } int zoneRadl = m_param->rc.zonefileCount && m_param->bResetZoneConfig ? m_param->rc.zones->zoneParam->radl : 0; - bool bForceRADL = (m_param->radl || zoneRadl) && !m_param->bOpenGOP; + bool bForceRADL = zoneRadl || (m_param->radl && (m_param->keyframeMax == m_param->keyframeMin)); bool bLastMiniGop = (framecnt >= m_param->bframes + 1) ? false : true; int radl = m_param->radl ? m_param->radl : zoneRadl; int preRADL = m_lastKeyframe + m_param->keyframeMax - radl - 1; /*Frame preceeding RADL in POC order*/ @@ -2133,14 +2175,15 @@ { for (int j = 1; j < numBFrames + 1; j++) { - if ((!m_param->bHistBasedSceneCut && scenecut(frames, j, j + 1, false, origNumFrames)) || - (m_param->bHistBasedSceneCut && frames[j + 1]->bScenecut) || - (bForceRADL && (frames[j]->frameNum == preRADL))) - { - frames[j]->sliceType = X265_TYPE_P; - numAnalyzed = j; - break; - } + bool isNextScenecut = false; + if (!m_param->bHistBasedSceneCut || (m_param->bHistBasedSceneCut && frames[j + 1]->bScenecut)) + isNextScenecut = scenecut(frames, j, j + 1, false, origNumFrames); + if (isNextScenecut || (bForceRADL && frames[j]->frameNum == preRADL)) + { + frames[j]->sliceType = X265_TYPE_P; + numAnalyzed = j; + break; + } } } resetStart = bKeyframe ? 1 : X265_MIN(numBFrames + 2, numAnalyzed + 1); @@ -2203,7 +2246,7 @@ * and not considered a scenecut. */ for (int cp1 = p1; cp1 <= maxp1; cp1++) { - if (!scenecutInternal(frames, p0, cp1, false)) + if (!scenecutInternal(frames, p0, cp1, false) && !m_param->bHistBasedSceneCut) { /* Any frame in between p0 and cur_p1 cannot be a real scenecut. */ for (int i = cp1; i > p0; i--) @@ -2212,7 +2255,7 @@ noScenecuts = false; } } - else if (scenecutInternal(frames, cp1 - 1, cp1, false)) + else if ((m_param->bHistBasedSceneCut && frames[cp1]->m_bIsMaxThres) || scenecutInternal(frames, cp1 - 1, cp1, false)) { /* If current frame is a Scenecut from p0 frame as well as Scenecut from * preceeding frame, mark it as a Scenecut */ @@ -2273,6 +2316,10 @@ if (!frames[p1]->bScenecut) return false; + /* Check only scene transitions if max threshold */ + if (m_param->bHistBasedSceneCut && frames[p1]->m_bIsMaxThres) + return frames[p1]->bScenecut; + return scenecutInternal(frames, p0, p1, bRealScenecut); } @@ -2289,7 +2336,19 @@ /* magic numbers pulled out of thin air */ float threshMin = (float)(threshMax * 0.25); double bias = m_param->scenecutBias; - if (bRealScenecut) + if (m_param->bHistBasedSceneCut) + { + double minT = TEMPORAL_SCENECUT_THRESHOLD * (1 + m_param->edgeTransitionThreshold); + if (frame->interPCostPercDiff > minT || frame->intraCostPercDiff > minT) + { + if (bRealScenecut && frame->bScenecut) + x265_log(m_param, X265_LOG_DEBUG, "scene cut at %d \n", frame->frameNum); + return frame->bScenecut; + } + else + return false; + } + else if (bRealScenecut) { if (m_param->keyframeMin == m_param->keyframeMax) threshMin = threshMax; diff -Nru x265-3.4/source/encoder/slicetype.h x265-3.5/source/encoder/slicetype.h --- x265-3.4/source/encoder/slicetype.h 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/encoder/slicetype.h 2021-03-16 12:53:00.000000000 +0000 @@ -42,6 +42,7 @@ #define LOWRES_COST_SHIFT 14 #define AQ_EDGE_BIAS 0.5 #define EDGE_INCLINATION 45 +#define TEMPORAL_SCENECUT_THRESHOLD 50 #if HIGH_BIT_DEPTH #define EDGE_THRESHOLD 1023.0 diff -Nru x265-3.4/source/test/rate-control-tests.txt x265-3.5/source/test/rate-control-tests.txt --- x265-3.4/source/test/rate-control-tests.txt 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/test/rate-control-tests.txt 2021-03-16 12:53:00.000000000 +0000 @@ -44,6 +44,9 @@ RaceHorses_416x240_30_10bit.yuv,--preset medium --crf 26 --vbv-maxrate 1000 --vbv-bufsize 1000 --pass 1::--preset fast --bitrate 1000 --vbv-maxrate 1000 --vbv-bufsize 700 --pass 3 -F4::--preset slow --bitrate 500 --vbv-maxrate 500 --vbv-bufsize 700 --pass 2 -F4 sita_1920x1080_30.yuv, --preset ultrafast --crf 20 --no-cutree --keyint 50 --min-keyint 50 --no-open-gop --pass 1 --vbv-bufsize 7000 --vbv-maxrate 5000:: --preset ultrafast --crf 20 --no-cutree --keyint 50 --min-keyint 50 --no-open-gop --pass 2 --vbv-bufsize 7000 --vbv-maxrate 5000 --repeat-headers sita_1920x1080_30.yuv, --preset medium --crf 20 --no-cutree --keyint 50 --min-keyint 50 --no-open-gop --pass 1 --vbv-bufsize 7000 --vbv-maxrate 5000 --repeat-headers --multi-pass-opt-rps:: --preset medium --crf 20 --no-cutree --keyint 50 --min-keyint 50 --no-open-gop --pass 2 --vbv-bufsize 7000 --vbv-maxrate 5000 --repeat-headers --multi-pass-opt-rps +sintel_trailer_2k_1920x1080_24.yuv,--preset medium --bitrate 6000 --no-cutree --aq-mode 0 --pass 1::--preset medium --bitrate 6000 --no-cutree --aq-mode 0 --pass 2 --scenecut-aware-qp 1 +sintel_trailer_2k_1920x1080_24.yuv,--preset medium --bitrate 6000 --no-cutree --aq-mode 0 --hist-scenecut --pass 1::--preset medium --bitrate 6000 --no-cutree --aq-mode 0 --hist-scenecut --pass 2 --scenecut-aware-qp 3 --masking-strength 300,-1,7,100,2,3 +sintel_trailer_2k_1920x1080_24.yuv,--preset medium --bitrate 6000 --no-cutree --aq-mode 0 --pass 1::--preset medium --bitrate 6000 --no-cutree --aq-mode 0 --pass 2 --scenecut-aware-qp 2 --masking-strength 100,-1,-1 # multi-pass rate control and analysis ducks_take_off_1080p50.y4m,--bitrate 6000 --pass 1 --multi-pass-opt-analysis --hash 1 --ssim --psnr:: --bitrate 6000 --pass 2 --multi-pass-opt-analysis --hash 1 --ssim --psnr diff -Nru x265-3.4/source/test/regression-tests.txt x265-3.5/source/test/regression-tests.txt --- x265-3.4/source/test/regression-tests.txt 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/test/regression-tests.txt 2021-03-16 12:53:00.000000000 +0000 @@ -158,7 +158,6 @@ ducks_take_off_420_1_720p50.y4m,--preset medium --selective-sao 4 --sao --crf 20 Traffic_4096x2048_30p.y4m, --preset medium --frame-dup --dup-threshold 60 --hrd --bitrate 10000 --vbv-bufsize 15000 --vbv-maxrate 12000 Kimono1_1920x1080_24_400.yuv,--preset superfast --qp 28 --zones 0,139,q=32 -Island_960x540_24.yuv,--no-cutree --aq-mode 0 --bitrate 6000 --scenecut-aware-qp sintel_trailer_2k_1920x1080_24.yuv, --preset medium --hist-scenecut --hist-threshold 0.02 --frame-dup --dup-threshold 60 --hrd --bitrate 10000 --vbv-bufsize 15000 --vbv-maxrate 12000 sintel_trailer_2k_1920x1080_24.yuv, --preset medium --hist-scenecut --hist-threshold 0.02 sintel_trailer_2k_1920x1080_24.yuv, --preset ultrafast --hist-scenecut --hist-threshold 0.02 diff -Nru x265-3.4/source/x265cli.cpp x265-3.5/source/x265cli.cpp --- x265-3.4/source/x265cli.cpp 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/x265cli.cpp 2021-03-16 12:53:00.000000000 +0000 @@ -127,9 +127,8 @@ H0(" --[no-]ssim-rd Enable ssim rate distortion optimization, 0 to disable. Default %s\n", OPT(param->bSsimRd)); H0(" --[no-]rd-refine Enable QP based RD refinement for rd levels 5 and 6. Default %s\n", OPT(param->bEnableRdRefine)); H0(" --[no-]early-skip Enable early SKIP detection. Default %s\n", OPT(param->bEnableEarlySkip)); - H0(" --rskip Set mode for early exit from recursion. Mode 1: exit using rdcost & CU homogenity. Mode 2: exit using CU edge density.\n" - " Mode 0: disabled. Default %d\n", param->recursionSkipMode); - H1(" --rskip-edge-threshold Threshold in terms of percentage (integer of range [0,100]) for minimum edge density in CUs used to prun the recursion depth. Applicable only for rskip mode 2. Value is preset dependent. Default: %.f\n", param->edgeVarThreshold*100.0f); + H0(" --rskip Enable recursion skip for early exit from CTU analysis during inter prediction. 1: exit using RD cost & CU homogeneity. 2: exit using CU edge density. 0: disabled. Default %d\n", param->recursionSkipMode); + H1(" --rskip-edge-threshold Threshold in terms of percentage (an integer of range [0,100]) for minimum edge density in CU's used to prune the recursion depth. Applicable only to rskip mode 2. Value is preset dependent. Default: %.f\n", param->edgeVarThreshold*100.0f); H1(" --[no-]tskip-fast Enable fast intra transform skipping. Default %s\n", OPT(param->bEnableTSkipFast)); H1(" --[no-]splitrd-skip Enable skipping split RD analysis when sum of split CU rdCost larger than one split CU rdCost for Intra CU. Default %s\n", OPT(param->bEnableSplitRdSkip)); H1(" --nr-intra An integer value in range of 0 to 2000, which denotes strength of noise reduction in intra CUs. Default 0\n"); @@ -175,11 +174,14 @@ H1(" --scenecut-bias <0..100.0> Bias for scenecut detection. Default %.2f\n", param->scenecutBias); H0(" --hist-scenecut Enables histogram based scene-cut detection using histogram based algorithm.\n"); H0(" --no-hist-scenecut Disables histogram based scene-cut detection using histogram based algorithm.\n"); - H1(" --hist-threshold <0.0..2.0> Luma Edge histogram's Normalized SAD threshold for histogram based scenecut detection Default %.2f\n", param->edgeTransitionThreshold); + H1(" --hist-threshold <0.0..1.0> Luma Edge histogram's Normalized SAD threshold for histogram based scenecut detection Default %.2f\n", param->edgeTransitionThreshold); H0(" --[no-]fades Enable detection and handling of fade-in regions. Default %s\n", OPT(param->bEnableFades)); - H1(" --[no-]scenecut-aware-qp Enable increasing QP for frames inside the scenecut window after scenecut. Default %s\n", OPT(param->bEnableSceneCutAwareQp)); - H1(" --scenecut-window <0..1000> QP incremental duration(in milliseconds) when scenecut-aware-qp is enabled. Default %d\n", param->scenecutWindow); - H1(" --max-qp-delta <0..10> QP offset to increment with base QP for inter-frames. Default %d\n", param->maxQpDelta); + H1(" --scenecut-aware-qp <0..3> Enable increasing QP for frames inside the scenecut window around scenecut. Default %s\n", OPT(param->bEnableSceneCutAwareQp)); + H1(" 0 - Disabled\n"); + H1(" 1 - Forward masking\n"); + H1(" 2 - Backward masking\n"); + H1(" 3 - Bidirectional masking\n"); + H1(" --masking-strength Comma separated values which specify the duration and offset for the QP increment for inter-frames when scenecut-aware-qp is enabled.\n"); H0(" --radl Number of RADL pictures allowed in front of IDR. Default %d\n", param->radl); H0(" --intra-refresh Use Periodic Intra Refresh instead of IDR frames\n"); H0(" --rc-lookahead Number of frames for frame-type lookahead (determines encoder latency) Default %d\n", param->lookaheadDepth); @@ -211,6 +213,8 @@ H0(" --vbv-bufsize Set size of the VBV buffer (kbit). Default %d\n", param->rc.vbvBufferSize); H0(" --vbv-init Initial VBV buffer occupancy (fraction of bufsize or in kbits). Default %.2f\n", param->rc.vbvBufferInit); H0(" --vbv-end Final VBV buffer emptiness (fraction of bufsize or in kbits). Default 0 (disabled)\n"); + H0(" --min-vbv-fullness Minimum VBV fullness percentage to be maintained. Default %.2f\n", param->minVbvFullness); + H0(" --max-vbv-fullness Maximum VBV fullness percentage to be maintained. Default %.2f\n", param->maxVbvFullness); H0(" --vbv-end-fr-adj Frame from which qp has to be adjusted to achieve final decode buffer emptiness. Default 0\n"); H0(" --chunk-start First frame of the chunk. Default 0 (disabled)\n"); H0(" --chunk-end Last frame of the chunk. Default 0 (disabled)\n"); @@ -220,6 +224,7 @@ " - 3 : Nth pass, overwrites stats file\n"); H0(" --[no-]multi-pass-opt-analysis Refine analysis in 2 pass based on analysis information from pass 1\n"); H0(" --[no-]multi-pass-opt-distortion Use distortion of CTU from pass 1 to refine qp in 2 pass\n"); + H0(" --[no-]vbv-live-multi-pass Enable realtime VBV in rate control 2 pass.Default %s\n", OPT(param->bliveVBV2pass)); H0(" --stats Filename for stats file in multipass pass rate control. Default x265_2pass.log\n"); H0(" --[no-]analyze-src-pics Motion estimation uses source frame planes. Default disable\n"); H0(" --[no-]slow-firstpass Enable a slow first pass in a multipass rate control mode. Default %s\n", OPT(param->rc.bEnableSlowFirstPass)); @@ -295,16 +300,16 @@ H0(" 5=40:33, 6=24:11, 7=20:11, 8=32:11, 9=80:33, 10=18:11, 11=15:11,\n"); H0(" 12=64:33, 13=160:99, 14=4:3, 15=3:2, 16=2:1 or custom ratio of . Default %d\n", param->vui.aspectRatioIdc); H1(" --display-window Describe overscan cropping region as 'left,top,right,bottom' in pixels\n"); - H1(" --overscan Specify whether it is appropriate for decoder to show cropped region: undef, show or crop. Default undef\n"); - H0(" --videoformat Specify video format from undef, component, pal, ntsc, secam, mac. Default undef\n"); + H1(" --overscan Specify whether it is appropriate for decoder to show cropped region: unknown, show or crop. Default unknown\n"); + H0(" --videoformat Specify video format from unknown, component, pal, ntsc, secam, mac. Default unknown\n"); H0(" --range Specify black level and range of luma and chroma signals as full or limited Default limited\n"); H0(" --colorprim Specify color primaries from bt709, unknown, reserved, bt470m, bt470bg, smpte170m,\n"); - H0(" smpte240m, film, bt2020, smpte428, smpte431, smpte432. Default undef\n"); + H0(" smpte240m, film, bt2020, smpte428, smpte431, smpte432. Default unknown\n"); H0(" --transfer Specify transfer characteristics from bt709, unknown, reserved, bt470m, bt470bg, smpte170m,\n"); H0(" smpte240m, linear, log100, log316, iec61966-2-4, bt1361e, iec61966-2-1,\n"); - H0(" bt2020-10, bt2020-12, smpte2084, smpte428, arib-std-b67. Default undef\n"); - H1(" --colormatrix Specify color matrix setting from undef, bt709, fcc, bt470bg, smpte170m,\n"); - H1(" smpte240m, GBR, YCgCo, bt2020nc, bt2020c, smpte2085, chroma-derived-nc, chroma-derived-c, ictcp. Default undef\n"); + H0(" bt2020-10, bt2020-12, smpte2084, smpte428, arib-std-b67. Default unknown\n"); + H1(" --colormatrix Specify color matrix setting from unknown, bt709, fcc, bt470bg, smpte170m,\n"); + H1(" smpte240m, gbr, ycgco, bt2020nc, bt2020c, smpte2085, chroma-derived-nc, chroma-derived-c, ictcp. Default unknown\n"); H1(" --chromaloc Specify chroma sample location (0 to 5). Default of %d\n", param->vui.chromaSampleLocTypeTopField); H0(" --master-display SMPTE ST 2086 master display color volume info SEI (HDR)\n"); H0(" format: G(x,y)B(x,y)R(x,y)WP(x,y)L(max,min)\n"); diff -Nru x265-3.4/source/x265cli.h x265-3.5/source/x265cli.h --- x265-3.4/source/x265cli.h 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/x265cli.h 2021-03-16 12:53:00.000000000 +0000 @@ -33,11 +33,9 @@ #include -#define CONSOLE_TITLE_SIZE 200 #ifdef _WIN32 #include #define SetThreadExecutionState(es) -static char orgConsoleTitle[CONSOLE_TITLE_SIZE] = ""; #else #define GetConsoleTitle(t, n) #define SetConsoleTitle(t) @@ -148,10 +146,8 @@ { "hist-threshold", required_argument, NULL, 0}, { "fades", no_argument, NULL, 0 }, { "no-fades", no_argument, NULL, 0 }, - { "scenecut-aware-qp", no_argument, NULL, 0 }, - { "no-scenecut-aware-qp", no_argument, NULL, 0 }, - { "scenecut-window",required_argument, NULL, 0 }, - { "max-qp-delta", required_argument, NULL, 0 }, + { "scenecut-aware-qp", required_argument, NULL, 0 }, + { "masking-strength", required_argument, NULL, 0 }, { "radl", required_argument, NULL, 0 }, { "ctu-info", required_argument, NULL, 0 }, { "intra-refresh", no_argument, NULL, 0 }, @@ -283,6 +279,8 @@ { "no-multi-pass-opt-analysis", no_argument, NULL, 0 }, { "multi-pass-opt-distortion", no_argument, NULL, 0 }, { "no-multi-pass-opt-distortion", no_argument, NULL, 0 }, + { "vbv-live-multi-pass", no_argument, NULL, 0 }, + { "no-vbv-live-multi-pass", no_argument, NULL, 0 }, { "slow-firstpass", no_argument, NULL, 0 }, { "no-slow-firstpass", no_argument, NULL, 0 }, { "multi-pass-opt-rps", no_argument, NULL, 0 }, @@ -373,6 +371,8 @@ { "no-cll", no_argument, NULL, 0 }, { "hme-range", required_argument, NULL, 0 }, { "abr-ladder", required_argument, NULL, 0 }, + { "min-vbv-fullness", required_argument, NULL, 0 }, + { "max-vbv-fullness", required_argument, NULL, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, diff -Nru x265-3.4/source/x265.cpp x265-3.5/source/x265.cpp --- x265-3.4/source/x265.cpp 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/x265.cpp 2021-03-16 12:53:00.000000000 +0000 @@ -46,9 +46,11 @@ using namespace X265_NS; #define X265_HEAD_ENTRIES 3 +#define CONSOLE_TITLE_SIZE 200 #ifdef _WIN32 #define strdup _strdup +static char orgConsoleTitle[CONSOLE_TITLE_SIZE] = ""; #endif #ifdef _WIN32 diff -Nru x265-3.4/source/x265.h x265-3.5/source/x265.h --- x265-3.4/source/x265.h 2020-05-29 17:39:35.000000000 +0000 +++ x265-3.5/source/x265.h 2021-03-16 12:53:00.000000000 +0000 @@ -204,6 +204,9 @@ }x265_analysis_distortion_data; #define MAX_NUM_REF 16 +#define EDGE_BINS 2 +#define MAX_HIST_BINS 1024 + /* Stores all analysis data for a single frame */ typedef struct x265_analysis_data { @@ -214,6 +217,8 @@ uint32_t numCUsInFrame; uint32_t numPartitions; uint32_t depthBytes; + int32_t edgeHist[EDGE_BINS]; + int32_t yuvHist[3][MAX_HIST_BINS]; int bScenecut; x265_weight_param* wt; x265_analysis_inter_data* interData; @@ -602,6 +607,13 @@ #define X265_ANALYSIS_SAVE 1 #define X265_ANALYSIS_LOAD 2 +#define FORWARD 1 +#define BACKWARD 2 +#define BI_DIRECTIONAL 3 +#define SLICE_TYPE_DELTA 0.3 /* The offset decremented or incremented for P-frames or b-frames respectively*/ +#define BACKWARD_WINDOW 1 /* Scenecut window before a scenecut */ +#define FORWARD_WINDOW 2 /* Scenecut window after a scenecut */ + typedef struct x265_cli_csp { int planes; @@ -1838,24 +1850,29 @@ Default 1 (Enabled). API only. */ int bResetZoneConfig; - /* Enables a ratecontrol algorithm for reducing the bits spent on the inter-frames - * within the scenecutWindow after a scenecut by increasing their QP without - * any deterioration in visual quality. It also increases the quality of scenecut I-Frames by reducing their QP. - * Default is disabled. */ + /* It reduces the bits spent on the inter-frames within the scenecutWindow before and / or after a scenecut + * by increasing their QP in ratecontrol pass2 algorithm without any deterioration in visual quality. + * 0 - Disabled (default). + * 1 - Forward masking. + * 2 - Backward masking. + * 3 - Bi-directional masking. */ int bEnableSceneCutAwareQp; /* The duration(in milliseconds) for which there is a reduction in the bits spent on the inter-frames after a scenecut - * by increasing their QP, when bEnableSceneCutAwareQp is set. Default is 500ms.*/ - int scenecutWindow; + * by increasing their QP, when bEnableSceneCutAwareQp is 1 or 3. Default is 500ms.*/ + int fwdScenecutWindow; - /* The offset by which QP is incremented for inter-frames when bEnableSceneCutAwareQp is set. + /* The offset by which QP is incremented for inter-frames after a scenecut when bEnableSceneCutAwareQp is 1 or 3. * Default is +5. */ - int maxQpDelta; + double fwdRefQpDelta; + + /* The offset by which QP is incremented for non-referenced inter-frames after a scenecut when bEnableSceneCutAwareQp is 1 or 3. */ + double fwdNonRefQpDelta; /* A genuine threshold used for histogram based scene cut detection. * This threshold determines whether a frame is a scenecut or not * when compared against the edge and chroma histogram sad values. - * Default 0.01. Range: Real number in the interval (0,2). */ + * Default 0.03. Range: Real number in the interval (0,1). */ double edgeTransitionThreshold; /* Enables histogram based scenecut detection algorithm to detect scenecuts. Default disabled */ @@ -1909,6 +1926,28 @@ /* Maxrate that could be signaled to the decoder. Default 0. API only. */ int decoderVbvMaxRate; + + /*Enables Qp tuning with respect to real time VBV buffer fullness in rate + control 2 pass. Experimental.Default is disabled*/ + int bliveVBV2pass; + + /* Minimum VBV fullness to be maintained. Default 50. Keep the buffer + * at least 50% full */ + double minVbvFullness; + + /* Maximum VBV fullness to be maintained. Default 80. Keep the buffer + * at max 80% full */ + double maxVbvFullness; + + /* The duration(in milliseconds) for which there is a reduction in the bits spent on the inter-frames before a scenecut + * by increasing their QP, when bEnableSceneCutAwareQp is 2 or 3. Default is 100ms.*/ + int bwdScenecutWindow; + + /* The offset by which QP is incremented for inter-frames before a scenecut when bEnableSceneCutAwareQp is 2 or 3. */ + double bwdRefQpDelta; + + /* The offset by which QP is incremented for non-referenced inter-frames before a scenecut when bEnableSceneCutAwareQp is 2 or 3. */ + double bwdNonRefQpDelta; } x265_param; /* x265_param_alloc: diff -Nru x265-3.4/x265Version.txt x265-3.5/x265Version.txt --- x265-3.4/x265Version.txt 1970-01-01 00:00:00.000000000 +0000 +++ x265-3.5/x265Version.txt 2021-03-16 12:53:00.000000000 +0000 @@ -0,0 +1,4 @@ +#Attribute: Values +repositorychangeset: f0c1022b6 +releasetagdistance: 1 +releasetag: 3.5