From 485d73cb63f6072c0e0736007f491a044d533773 Mon Sep 17 00:00:00 2001 From: "L. E. Segovia" Date: Fri, 21 Nov 2025 17:23:35 +0000 Subject: [PATCH] Add x265 4.1 --- releases.json | 8 + subprojects/packagefiles/x265/LICENSE.build | 28 + subprojects/packagefiles/x265/meson.build | 25 + subprojects/packagefiles/x265/meson.options | 159 ++++ .../x265/source/common/meson.build | 440 ++++++++++ .../source/common/primitives-placeholders.cpp | 8 + .../dynamicHDR10/json11/gcc15-workaround.cpp | 2 + .../x265/source/dynamicHDR10/meson.build | 38 + .../x265/source/encoder/meson.build | 63 ++ .../packagefiles/x265/source/meson.build | 793 ++++++++++++++++++ .../packagefiles/x265/source/meson/intrin.h | 1 + .../packagefiles/x265/source/meson/makever.py | 61 ++ .../packagefiles/x265/source/meson/version.py | 98 +++ .../packagefiles/x265/source/test/meson.build | 75 ++ subprojects/x265.wrap | 9 + tools/sanity_checks.py | 7 + 16 files changed, 1815 insertions(+) create mode 100644 subprojects/packagefiles/x265/LICENSE.build create mode 100644 subprojects/packagefiles/x265/meson.build create mode 100644 subprojects/packagefiles/x265/meson.options create mode 100644 subprojects/packagefiles/x265/source/common/meson.build create mode 100644 subprojects/packagefiles/x265/source/common/primitives-placeholders.cpp create mode 100644 subprojects/packagefiles/x265/source/dynamicHDR10/json11/gcc15-workaround.cpp create mode 100644 subprojects/packagefiles/x265/source/dynamicHDR10/meson.build create mode 100644 subprojects/packagefiles/x265/source/encoder/meson.build create mode 100644 subprojects/packagefiles/x265/source/meson.build create mode 100644 subprojects/packagefiles/x265/source/meson/intrin.h create mode 100755 subprojects/packagefiles/x265/source/meson/makever.py create mode 100755 subprojects/packagefiles/x265/source/meson/version.py create mode 100644 subprojects/packagefiles/x265/source/test/meson.build create mode 100644 subprojects/x265.wrap diff --git a/releases.json b/releases.json index e33e237a9..3bd2595c9 100644 --- a/releases.json +++ b/releases.json @@ -4680,6 +4680,14 @@ "4.0.1-1" ] }, + "x265": { + "dependency_names": [ + "x265" + ], + "versions": [ + "4.1-1" + ] + }, "xdelta3": { "program_names": [ "xdelta3" diff --git a/subprojects/packagefiles/x265/LICENSE.build b/subprojects/packagefiles/x265/LICENSE.build new file mode 100644 index 000000000..9d90c0020 --- /dev/null +++ b/subprojects/packagefiles/x265/LICENSE.build @@ -0,0 +1,28 @@ +BSD 3-Clause License + +Copyright (c) 2025 L. E. Segovia (amyspark) + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/subprojects/packagefiles/x265/meson.build b/subprojects/packagefiles/x265/meson.build new file mode 100644 index 000000000..0572d5778 --- /dev/null +++ b/subprojects/packagefiles/x265/meson.build @@ -0,0 +1,25 @@ +project( + 'x265', + 'c', + 'cpp', + version: '4.1', + meson_version: '>= 1.3.0', + license: 'GPL-2.0-or-later', + license_files: 'COPYING', + default_options: ['cpp_std=gnu++14,c++14', 'warning_level=2'], +) + +if get_option('optimization') != '3' + message( + 'This library expects to be built with -Doptimization=3. If you find any visual artifacts, consider adding this flag.', + ) +endif + +subdir('source') + +x265_dep = declare_dependency( + link_with: x265_lib, + include_directories: include_dirs, +) + +meson.override_dependency('x265', x265_dep) diff --git a/subprojects/packagefiles/x265/meson.options b/subprojects/packagefiles/x265/meson.options new file mode 100644 index 000000000..fd70860a9 --- /dev/null +++ b/subprojects/packagefiles/x265/meson.options @@ -0,0 +1,159 @@ +option( + 'native_build', + type: 'boolean', + value: false, + description: 'Target the build CPU', +) +option( + '10bit', + type: 'boolean', + value: true, + description: 'Build x265 including 10 bit depth support', +) +option( + 'hdr10_plus', + type: 'boolean', + value: true, + description: 'Enable dynamic HDR10 compilation', +) +option( + '12bit', + type: 'boolean', + value: true, + description: 'Build x265 including 12 bit depth support', +) +option( + 'asm', + type: 'feature', + value: 'auto', + description: 'Enable use of assembly coded primitives', +) + +option( + 'libnuma', + type: 'feature', + value: 'auto', + description: 'Enable libnuma usage (Linux only)', +) +option( + 'no_atomics', + type: 'boolean', + value: false, + description: 'Use a slow mutex to replace atomics', +) +option( + 'libvmaf', + type: 'feature', + value: 'disabled', + description: 'Enable VMAF', +) + +# Options for manually enabling/disabling AArch64 SIMD extensions. +option( + 'aarch64_warnings_as_errors', + type: 'boolean', + description: 'Build with -Werror for AArch64 Intrinsics files', + value: false, +) +option( + 'aarch64_runtime_cpu_detect', + type: 'feature', + description: 'Enable AArch64 run-time CPU feature detection', + value: 'auto', +) +option( + 'neon', + type: 'feature', + description: 'Enable Neon', + value: 'auto', +) +option( + 'neon_dotprod', + type: 'feature', + description: 'Enable Neon DotProd', + value: 'auto', +) +option( + 'neon_i8mm', + type: 'feature', + description: 'Enable Neon I8MM', + value: 'auto', +) +option( + 'sve', + type: 'feature', + description: 'Enable SVE', + value: 'auto', +) +option( + 'sve2', + type: 'feature', + description: 'Enable SVE2', + value: 'auto', +) + +option( + 'checked_build', + type: 'boolean', + description: 'Enable run-time sanity checks (debugging)', + value: false, +) + +option( + 'high_bit_depth', + type: 'feature', + description: 'Store pixel samples as 16bit values (Main10/Main12)', + value: 'auto', +) + +option( + 'altivec', + type: 'boolean', + description: 'Enable ALTIVEC profiling instrumentation', + value: true, +) +option( + 'cpu_power8', + type: 'boolean', + description: 'Enable CPU POWER8 profiling instrumentation', + value: true, +) + +option( + 'detailed_cu_stats', + type: 'boolean', + description: 'Enable internal profiling of encoder work', + value: false, +) +option( + 'alpha', + type: 'boolean', + description: 'Enable alpha encoding in x265', + value: false, +) +option( + 'multiview', + type: 'boolean', + description: 'Enable Multi-view encoding in HEVC', + value: false, +) +option( + 'scc_ext', + type: 'boolean', + description: 'Enable screen content coding extension in HEVC', + value: false, +) + +option( + 'cli', + type: 'feature', + description: 'Build standalone CLI application', + value: 'auto', +) + +option( + 'tests', + type: 'feature', + description: 'Enable Unit Tests', + value: 'auto', +) diff --git a/subprojects/packagefiles/x265/source/common/meson.build b/subprojects/packagefiles/x265/source/common/meson.build new file mode 100644 index 000000000..81a263cf7 --- /dev/null +++ b/subprojects/packagefiles/x265/source/common/meson.build @@ -0,0 +1,440 @@ +vflags = ['-DX265_VERSION=@0@'.format(x265_version)] + +if enable_assembly.allowed() + c_args += ['-DENABLE_ASSEMBLY=1'] +endif + +primitives_libs = [] + +if enable_assembly.allowed() and host_arch.startswith('x86') + sse3 = files('vec/dct-sse3.cpp') + ssse3 = files('vec/dct-ssse3.cpp') + sse41 = files('vec/dct-sse41.cpp') + + if cpp.get_id() == 'msvc' + primitives = sse3 + ssse3 + sse41 + warndisable = cpp.get_supported_arguments('/wd4100') + # x64 implies SSE4, so only add /arch:SSE2 if building for Win32 + primitives_arch_args = [] + + if host_arch == 'x86' + primitives_arch_args = ['/arch:SSE2'] + endif + foreach bit, depth : bit_depths + primitives_args = c_args + get_variable(f'@depth@_args') + vflags + warndisable + primitives_arch_args + primitives_libs += static_library( + f'primitives-@depth@', + primitives, + c_args: primitives_args, + cpp_args: primitives_args, + include_directories: include_dirs, + build_by_default: false, + # gnu_symbol_visibility: 'inlineshidden', + ) + endforeach + endif + + if cpp.get_id() in ['gcc', 'clang'] + # llvm intrinsic headers cause shadow warnings + warndisable = cpp.get_supported_arguments( + '-Wno-shadow', + '-Wno-unused-parameter', + ) + + if cpp.get_id() == 'clang' or cpp.version().version_compare('>= 4.3') + primitives = sse3 + ssse3 + sse41 + primitives_arch_args = { + 'sse3': ['-msse3'], + 'ssse3': ['-mssse3'], + 'sse41': ['-msse4.1'], + } + + foreach bit, depth : bit_depths + foreach k, arch_args : primitives_arch_args + primitives_args = c_args + get_variable(f'@depth@_args') + vflags + warndisable + arch_args + primitives_libs += static_library( + 'primitives-@0@-@1@'.format(depth, k), + get_variable(k), + c_args: primitives_args, + cpp_args: primitives_args, + include_directories: include_dirs, + build_by_default: false, + # gnu_symbol_visibility: 'inlineshidden', + ) + endforeach + endforeach + endif + endif + + vec_primitives = files('vec/vec-primitives.cpp') + + c_srcs = files( + 'x86/asm-primitives.cpp', + 'x86/blockcopy8.h', + 'x86/dct8.h', + 'x86/ipfilter8.h', + 'x86/loopfilter.h', + 'x86/mc.h', + 'x86/pixel.h', + 'x86/seaintegral.h', + ) + + a_srcs = files( + 'x86/blockcopy8.asm', + 'x86/const-a.asm', + 'x86/cpu-a.asm', + 'x86/dct8.asm', + 'x86/mc-a.asm', + 'x86/mc-a2.asm', + 'x86/pixel-a.asm', + 'x86/pixel-util8.asm', + 'x86/pixeladd8.asm', + 'x86/seaintegral.asm', + 'x86/ssd-a.asm', + ) + + hdr10_a_srcs = a_srcs + files( + 'x86/h-ipfilter16.asm', + 'x86/h4-ipfilter16.asm', + 'x86/intrapred16.asm', + 'x86/ipfilter16.asm', + 'x86/loopfilter.asm', + 'x86/sad16-a.asm', + 'x86/v4-ipfilter16.asm', + ) + hdr12_a_srcs = hdr10_a_srcs + + sdr_a_srcs = a_srcs + files( + 'x86/h-ipfilter8.asm', + 'x86/intrapred8.asm', + 'x86/intrapred8_allangs.asm', + 'x86/ipfilter8.asm', + 'x86/loopfilter.asm', + 'x86/sad-a.asm', + 'x86/v4-ipfilter8.asm', + ) + + if host_arch != 'x86_64' + pixel32_srcs = files('x86/pixel-32.asm') + hdr10_a_srcs += pixel32_srcs + hdr12_a_srcs += pixel32_srcs + sdr_a_srcs += pixel32_srcs + endif + + add_languages( + 'nasm', + required: true, + native: false, + ) + + include_dirs += include_directories('x86') + if host_arch == 'x86_64' + nasm_args += ['-DARCH_X86_64=1'] + # -DPIC was handled earlier + else + nasm_args += ['-DARCH_X86_64=0'] + endif + + foreach bit, depth : bit_depths + primitives_libs += static_library( + f'nasm-primitives-@depth@', + get_variable(f'@depth@_a_srcs') + c_srcs, + c_args: c_args + get_variable(f'@depth@_args') + vflags + warndisable, + cpp_args: c_args + get_variable(f'@depth@_args') + vflags + warndisable, + nasm_args: nasm_args + get_variable(f'@depth@_asm_args'), + include_directories: include_dirs, + build_by_default: false, + # gnu_symbol_visibility: 'inlineshidden', + ) + endforeach +endif + +# have_aligned_stack isn't used anywhere + +if enable_assembly.allowed() and host_arch == 'arm' + c_srcs = files( + 'arm/asm-primitives.cpp', + 'arm/blockcopy8.h', + 'arm/dct8.h', + 'arm/ipfilter8.h', + 'arm/loopfilter.h', + 'arm/mc.h', + 'arm/pixel.h', + 'arm/seaintegral.h', + ) + + # these are only for 8-bit + sdr_a_srcs = files( + 'arm/asm.S', + 'arm/blockcopy8.S', + 'arm/cpu-a.S', + 'arm/dct-a.S', + 'arm/mc-a.S', + 'arm/opfilter8.S', + 'arm/pixel-util.S', + 'arm/sad-a.S', + 'arm/ssd-a.S', + ) +endif + +if enable_assembly.allowed() and host_arch == 'aarch64' + if get_option('optimization') == '3' + message('Detected CXX compiler using -O3 optimization level') + c_args += '-DAUTO_VECTORIZE=1' + endif + + c_srcs_neon = files( + 'aarch64/arm64-utils.cpp', + 'aarch64/arm64-utils.h', + 'aarch64/asm-primitives.cpp', + 'aarch64/dct-prim.cpp', + 'aarch64/dct-prim.h', + 'aarch64/filter-prim.cpp', + 'aarch64/filter-prim.h', + 'aarch64/fun-decls.h', + 'aarch64/intrapred-prim.cpp', + 'aarch64/loopfilter-prim.cpp', + 'aarch64/loopfilter-prim.h', + 'aarch64/mem-neon.h', + 'aarch64/pixel-prim.cpp', + 'aarch64/pixel-prim.h', + 'aarch64/sao-prim.cpp', + ) + c_srcs_neon_dotprod = files('aarch64/filter-neon-dotprod.cpp') + c_srcs_neon_i8mm = files('aarch64/filter-neon-i8mm.cpp') + c_srcs_sve = files('aarch64/dct-prim-sve.cpp' + , 'aarch64/sao-prim-sve.cpp') + c_srcs_sve2 = files('aarch64/sao-prim-sve2.cpp') + + arm_asms = files( + 'aarch64/asm.S', + 'aarch64/blockcopy8-common.S', + 'aarch64/blockcopy8.S', + 'aarch64/dct.S', + 'aarch64/intrapred.S', + 'aarch64/mc-a-common.S', + 'aarch64/mc-a.S', + 'aarch64/p2s-common.S', + 'aarch64/p2s.S', + 'aarch64/pixel-util-common.S', + 'aarch64/pixel-util.S', + 'aarch64/sad-a.S', + 'aarch64/ssd-a-common.S', + 'aarch64/ssd-a.S', + ) + arm_asms_neon_dotprod = files( + 'aarch64/sad-neon-dotprod.S', + 'aarch64/ssd-neon-dotprod.S', + ) + arm_asms_sve = files( + 'aarch64/asm-sve.S', + 'aarch64/blockcopy8-sve.S', + 'aarch64/p2s-sve.S', + 'aarch64/pixel-util-sve.S', + ) + arm_asms_sve2 = files( + 'aarch64/mc-a-sve2.S', + 'aarch64/pixel-util-sve2.S', + 'aarch64/ssd-a-sve2.S', + ) + + aarch64_override_opts = [] + if get_option('aarch64_warnings_as_errors') + aarch64_override_opts += 'werror=true' + endif + + foreach bit, depth : bit_depths + if cpu_has_neon + primitives_args = c_args + arm_args + get_variable(f'@depth@_args') + vflags + aarch64_neon_flag + primitives_libs += static_library( + f'asm-primitives-neon-@depth@', + c_srcs_neon + arm_asms, + c_args: primitives_args + arm_args + get_variable(f'@depth@_asm_args'), + cpp_args: primitives_args, + include_directories: include_dirs, + override_options: aarch64_override_opts, + build_by_default: false, + # gnu_symbol_visibility: 'inlineshidden', + ) + endif + if cpu_has_neon_dotprod + primitives_args = c_args + arm_args + get_variable(f'@depth@_args') + vflags + aarch64_neon_dotprod_flag + primitives_libs += static_library( + f'asm-primitives-neon-dotprod-@depth@', + c_srcs_neon_dotprod + arm_asms_neon_dotprod, + c_args: primitives_args + get_variable(f'@depth@_asm_args'), + cpp_args: primitives_args, + include_directories: include_dirs, + override_options: aarch64_override_opts, + build_by_default: false, + # gnu_symbol_visibility: 'inlineshidden', + ) + endif + if cpu_has_neon_i8mm + primitives_args = c_args + get_variable(f'@depth@_args') + vflags + aarch64_neon_i8mm_flag + primitives_libs += static_library( + f'asm-primitives-neon-i8mm-@depth@', + c_srcs_neon_i8mm, + c_args: primitives_args + get_variable(f'@depth@_asm_args'), + cpp_args: primitives_args, + include_directories: include_dirs, + override_options: aarch64_override_opts, + build_by_default: false, + # gnu_symbol_visibility: 'inlineshidden', + ) + endif + if cpu_has_sve and have_sve_bridge + primitives_args = c_args + arm_args + get_variable(f'@depth@_args') + vflags + aarch64_sve_flag + primitives_libs += static_library( + f'asm-primitives-sve-@depth@', + c_srcs_sve + arm_asms_sve, + c_args: primitives_args + get_variable(f'@depth@_asm_args'), + cpp_args: primitives_args, + include_directories: include_dirs, + override_options: aarch64_override_opts, + build_by_default: false, + # gnu_symbol_visibility: 'inlineshidden', + ) + endif + if cpu_has_sve2 and have_sve_bridge + primitives_args = c_args + arm_args + get_variable(f'@depth@_args') + vflags + aarch64_sve2_flag + primitives_libs += static_library( + f'asm-primitives-sve2-@depth@', + c_srcs_sve2 + arm_asms_sve2, + c_args: primitives_args + get_variable(f'@depth@_asm_args'), + cpp_args: primitives_args, + include_directories: include_dirs, + override_options: aarch64_override_opts, + build_by_default: false, + # gnu_symbol_visibility: 'inlineshidden', + ) + endif + endforeach +endif + +if host_arch.startswith('ppc') and get_option('altivec') + altivec_srcs = files( + 'ppc/dct_altivec.cpp', + 'ppc/intrapred_altivec.cpp', + 'ppc/ipfilter_altivec.cpp', + 'ppc/pixel_altivec.cpp', + ) + foreach bit, depth : bit_depths + primitives_args = c_args + get_variable(f'@depth@_args') + vflags + warndisable + [ + '-Wno-unused', + '-Wno-unknown-pragmas', + '-Wno-maybe-uninitialized', + ] + primitives_libs += static_library( + f'asm-primitives-altivec-@depth@', + altivec_srcs, + c_args: primitives_args, + cpp_args: primitives_args, + build_by_default: false, + # gnu_symbol_visibility: 'inlineshidden', + ) + endforeach +endif + +common = primitives_libs + +foreach bit, depth : bit_depths + common += static_library( + f'version-@depth@', + files('version.cpp'), + cpp_args: c_args + get_variable(f'@depth@_args') + vflags, + include_directories: include_dirs, + build_by_default: false, + # gnu_symbol_visibility: 'inlineshidden', + ) +endforeach + +if cc.has_header_symbol('string.h', 'strtok_r') + c_args += ['-DHAVE_STRTOK_R=1'] +endif + +if get_variable('cc_has_no_narrowing', false) + c_args += ['-Wno-narrowing'] +endif + +common_files = files( + 'bitstream.cpp', + # FIXME: the x265_cpu_neon_test and x265_cpu_fast_neon_mrc_test + # are defined in primitives under armv7a, but the gating is never + # checked because they were defined under x86! o.O? --Amy + 'bitstream.h', + 'common.cpp', + 'common.h', + 'constants.cpp', + 'constants.h', + 'contexts.h', + 'cpu.cpp', + 'cpu.h', + 'cudata.cpp', + 'cudata.h', + 'dct.cpp', + 'deblock.cpp', + 'deblock.h', + 'frame.cpp', + 'frame.h', + 'framedata.cpp', + 'framedata.h', + 'intrapred.cpp', + 'ipfilter.cpp', + 'loopfilter.cpp', + 'lowpassdct.cpp', + 'lowres.cpp', + 'lowres.h', + 'md5.cpp', + 'md5.h', + 'mv.h', + 'param.cpp', + 'param.h', + 'piclist.cpp', + 'piclist.h', + 'picyuv.cpp', + 'picyuv.h', + 'pixel.cpp', + 'predict.cpp', + 'predict.h', + 'primitives-placeholders.cpp', + 'primitives.cpp', + 'primitives.h', + 'quant.cpp', + 'quant.h', + 'ringmem.cpp', + 'ringmem.h', + 'scaler.cpp', + 'scaler.h', + 'scalinglist.cpp', + 'scalinglist.h', + 'shortyuv.cpp', + 'shortyuv.h', + 'slice.cpp', + 'slice.h', + 'temporalfilter.cpp', + 'temporalfilter.h', + 'threading.cpp', + 'threading.h', + 'threadpool.cpp', + 'threadpool.h', + 'wavefront.cpp', + 'wavefront.h', + 'yuv.cpp', + 'yuv.h', +) + +if host_machine.system() in ['windows', 'cygwin'] + common_files += files('winxp.cpp', 'winxp.h') +endif + +foreach bit, depth : bit_depths + common += static_library( + f'common-@depth@', + common_files + get_variable('vec_primitives', []), + cpp_args: c_args + get_variable(f'@depth@_args') + vflags, + include_directories: include_dirs, + build_by_default: false, + # gnu_symbol_visibility: 'inlineshidden', + ) +endforeach diff --git a/subprojects/packagefiles/x265/source/common/primitives-placeholders.cpp b/subprojects/packagefiles/x265/source/common/primitives-placeholders.cpp new file mode 100644 index 000000000..6fd121514 --- /dev/null +++ b/subprojects/packagefiles/x265/source/common/primitives-placeholders.cpp @@ -0,0 +1,8 @@ +#include "cpu.h" + +#if !defined(ENABLE_ASSEMBLY) && defined(X265_ARCH_ARM) +extern "C" { +void PFX(cpu_neon_test)(void) {} +int PFX(cpu_fast_neon_mrc_test)(void) { return 0; } +} // extern "C" +#endif // X265_ARCH_ARM diff --git a/subprojects/packagefiles/x265/source/dynamicHDR10/json11/gcc15-workaround.cpp b/subprojects/packagefiles/x265/source/dynamicHDR10/json11/gcc15-workaround.cpp new file mode 100644 index 000000000..b7ef2f108 --- /dev/null +++ b/subprojects/packagefiles/x265/source/dynamicHDR10/json11/gcc15-workaround.cpp @@ -0,0 +1,2 @@ +#include +#include "json11.cpp" diff --git a/subprojects/packagefiles/x265/source/dynamicHDR10/meson.build b/subprojects/packagefiles/x265/source/dynamicHDR10/meson.build new file mode 100644 index 000000000..4d9f51a6c --- /dev/null +++ b/subprojects/packagefiles/x265/source/dynamicHDR10/meson.build @@ -0,0 +1,38 @@ +dynamicHDR10_srcs = files( + 'BasicStructures.h', + # 'json11/json11.cpp', + 'JsonHelper.cpp', + 'JsonHelper.h', + 'SeiMetadataDictionary.cpp', + 'SeiMetadataDictionary.h', + 'api.cpp', + 'hdr10plus.h', + 'json11/json11.h', + 'metadataFromJson.cpp', + 'metadataFromJson.h', +) + +# FIXME: is now required for building with new GCC --Amy +# https://gitlab.archlinux.org/archlinux/packaging/packages/x265/-/commit/9d27978355453de977f7ac88144857525a2fb5cc +needs_cstdint_workaround = cpp.has_type( + 'uint8_t', + prefix: ''' +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +''', +) +if cc.get_id() == 'gcc' + dynamicHDR10_srcs += files('json11/gcc15-workaround.cpp') +else + dynamicHDR10_srcs += files('json11/json11.cpp') +endif + +install_headers('hdr10plus.h') diff --git a/subprojects/packagefiles/x265/source/encoder/meson.build b/subprojects/packagefiles/x265/source/encoder/meson.build new file mode 100644 index 000000000..b73fbad77 --- /dev/null +++ b/subprojects/packagefiles/x265/source/encoder/meson.build @@ -0,0 +1,63 @@ +if cc.get_id() in ['gcc', 'clang'] + c_args += ['-Wno-uninitialized'] +endif + +if cc.get_argument_syntax() == 'msvc' + # potentially uninitialized local variable 'foo' used + c_args += ['/wd4701'] +endif + +encoder_srcs = files( + '../x265.h', + 'analysis.cpp', + 'analysis.h', + 'api.cpp', + 'bitcost.cpp', + 'bitcost.h', + 'dpb.cpp', + 'dpb.h', + 'encoder.cpp', + 'encoder.h', + 'entropy.cpp', + 'entropy.h', + 'frameencoder.cpp', + 'frameencoder.h', + 'framefilter.cpp', + 'framefilter.h', + 'level.cpp', + 'level.h', + 'motion.cpp', + 'motion.h', + 'nal.cpp', + 'nal.h', + 'ratecontrol.cpp', + 'ratecontrol.h', + 'rdcost.h', + 'reference.cpp', + 'reference.h', + 'sao.cpp', + 'sao.h', + 'search.cpp', + 'search.h', + 'sei.cpp', + 'sei.h', + 'slicetype.cpp', + 'slicetype.h', + 'svt.h', + 'weightPrediction.cpp', +) + +encoders = [] + +foreach bit, depth : bit_depths + encoder_args = c_args + get_variable(f'@depth@_args') + encoders += static_library( + f'encoder-@depth@', + encoder_srcs, + c_args: encoder_args, + cpp_args: encoder_args, + include_directories: include_dirs, + build_by_default: false, + # gnu_symbol_visibility: 'inlineshidden', + ) +endforeach diff --git a/subprojects/packagefiles/x265/source/meson.build b/subprojects/packagefiles/x265/source/meson.build new file mode 100644 index 000000000..d0db331ef --- /dev/null +++ b/subprojects/packagefiles/x265/source/meson.build @@ -0,0 +1,793 @@ +x265_build = '215' + +x265_def = configure_file( + input: 'x265.def.in', + output: 'x265.def', + configuration: { + 'X265_BUILD': x265_build, + }, + format: 'cmake', +) + +x265_ver = [] +vflag = [] + +cc = meson.get_compiler('c') +cpp = meson.get_compiler('cpp') + +host_system = host_machine.system() +host_arch = host_machine.cpu_family() + +if not ['windows', 'cygwin'].contains(host_system) + makever_py = find_program( + 'meson/makever.py', + native: true, + ) + makedef_args = [makever_py] + + if host_system in ['darwin', 'ios'] + makedef_args += ['--os', 'darwin'] + elif host_system in ['windows', 'cygwin'] + makedef_args += ['--os', 'win'] + else + makedef_args += ['--os', 'linux'] + endif + + if cc.symbols_have_underscore_prefix() + makedef_args += ['--prefix', '_'] + else + makedef_args += ['--prefix', ''] + endif + + x265_ver = custom_target( + 'x265.ver', + command: makedef_args + ['@INPUT@'], + input: x265_def, + output: '@BASENAME@.ver', + capture: true, + ) + + if host_system in ['darwin', 'ios'] + vflag = '-Wl,-exported_symbols_list,@0@'.format(x265_ver.full_path()) + else + vflag = '-Wl,--version-script,@0@'.format(x265_ver.full_path()) + endif +endif + +x265_config = configure_file( + input: 'x265_config.h.in', + output: 'x265_config.h', + configuration: { + 'X265_BUILD': x265_build, + }, + format: 'cmake', +) + +ptr_size = cpp.sizeof('void*') + +c_args = [] +include_dirs = [] + +aarch64_runtime_cpu_detect = get_option('aarch64_runtime_cpu_detect') + +if host_arch.startswith('x86') + c_args += '-DX265_ARCH_X86=1' + if ptr_size == 4 + message('Detected x86 target processor') + else + c_args += '-DX86_64=1' + message('Detected x86_64 target processor') + endif +elif host_arch.startswith('ppc') + c_args += '-DX265_ARCH_POWER=1' + if ptr_size == 8 + c_args += '-DPPC64=1' + message('Detected POWER PPC64 target processor') + else + message('Detected POWER target processor') + endif +elif host_arch == 'arm' + if meson.is_cross_build() + message('Cross compiling for ARM arch') + else + message('Detected ARM target processor') + endif + c_args += ['-DX265_ARCH_ARM=1', '-DHAVE_ARMV6=1'] +elif host_arch == 'aarch64' + message('Detected ARM64 target processor') + + aarch64_runtime_cpu_detect = aarch64_runtime_cpu_detect.disable_if( + not ['linux', 'darwin', 'ios', 'windows'].contains(host_system), + ) + + enable_neon = get_option('neon') + enable_neon_dotprod = get_option('neon_dotprod') + enable_neon_i8mm = get_option('neon_i8mm') + enable_sve = get_option('sve') + enable_sve2 = get_option('sve2') + + # Compiler flags for AArch64 extensions. + aarch64_neon_flag = '-march=armv8-a' + # Neon DotProd is mandatory from Armv8.4. + aarch64_neon_dotprod_flag = '-march=armv8.2-a+dotprod' + # Neon I8MM is mandatory from Armv8.6. + aarch64_neon_i8mm_flag = '-march=armv8.2-a+dotprod+i8mm' + aarch64_sve_flag = '-march=armv8.2-a+dotprod+i8mm+sve' + # SVE2 is only available from Armv9.0, and armv9-a implies +dotprod and +sve. + aarch64_sve2_flag = '-march=armv9-a+i8mm+sve2' +else + error('Unknown processor @0@'.format(host_arch)) +endif + +platform_libs = [ + dependency('threads'), + cc.find_library( + 'rt', + required: false, + ), +] + +dl_lib = cc.find_library( + 'dl', + required: false, +) +if dl_lib.found() + platform_libs += [dl_lib] +endif + +numa_lib = dependency( + 'numa', + required: get_option('libnuma'), +) +if numa_lib.found() + # Try to detect the NUMA V2 API (numa_node_of_cpu symbol) + have_numa_v2 = cc.has_function( + 'numa_node_of_cpu', + includes: ['numa.h'], + dependencies: numa_lib, + ) + if have_numa_v2 + message('libnuma found, building with support for NUMA nodes') + c_args += '-DHAVE_LIBNUMA' + platform_libs += [numa_lib] + endif +endif + +if get_option('no_atomics') + c_args += '-DNO_ATOMICS=1' +endif + +vmaf_lib = cc.find_library( + 'vmaf', + required: get_option('libvmaf'), +) +if vmaf_lib.found() + c_args += '-DENABLE_LIBVMAF' + platform_libs += vmaf_lib +endif + +if host_system in ['darwin', 'ios'] + c_args += '-DMACOS=1' +endif + +if cc.get_id() == 'msvc' + c_args += '/Ob2' # always inline + # disable Microsofts suggestions for proprietary secure APIs + c_args += '/D_CRT_SECURE_NO_WARNINGS' + + if not cc.has_header('stdint.h') + include_dirs += include_directories('compat/msvc') + endif +endif + +if cc.has_header('inttypes.h') + c_args += '-DHAVE_INT_TYPES_H=1' +endif + +enable_hdr10_plus = get_option('hdr10_plus') + +nasm_args = [] +# On Meson, it is not possible to build shared libraries without PIC. +# Also, PIC on static libraries is governed by b_staticpic. +# This means that we can get the case where we would need a static_library +# that builds itself with and without PIC. +# So let's disable that case altogether. +if get_option('default_library') == 'both' and not get_option('b_staticpic') + error('Mixing b_staticpic=false and default_library=both is not allowed.') +elif (get_option('default_library') == 'static' and get_option('b_staticpic')) or get_option( + 'default_library', +) != 'static' + c_args += ['-DPIC'] + nasm_args += ['-DPIC'] +endif + +if cc.symbols_have_underscore_prefix() + nasm_args += ['-DPREFIX'] +endif + +if host_system == 'linux' + cpuinfo = run_command( + 'cat', + '/proc/cpuinfo', + capture: true, + check: true, + ).stdout() +elif host_system == 'darwin' + cpuinfo = run_command( + 'sysctl', + '-a', + capture: true, + check: true, + ).stdout() +endif + +if cc.get_id() in ['gcc', 'clang'] + c_args += ['-Wshadow', '-D__STDC_LIMIT_MACROS=1'] + c_args += cpp.get_supported_arguments('-Wno-class-memaccess') + + if get_option('native_build') + c_args += '-march=native' + elif host_arch == 'x86' + if not cc.has_define('__i686__') + c_args += ['-march=i686'] + cc_version = cc.version() + if host_system == 'windows' and cc.get_id() == 'gcc' and cc_version.version_compare( + '>= 6.0', + ) and cc_version.version_compare( + '< 7.0', + ) + c_args += [-'mpreferred-stack-boundary=2'] + endif + endif + endif + + if host_arch == 'arm' and meson.is_cross_build() + arm_args = ['-march=armv6', '-mfloat-abi=soft', '-mfpu=vfp', '-marm'] + elif host_arch == 'arm' + if host_system == 'linux' + cpu_has_neon = 'neon' in cpuinfo + elif host_system == 'darwin' + cpu_has_neon = 'hw.optional.neon: 1' in cpuinfo + endif + if cpu_has_neon + arm_args = [ + '-mcpu=native', + '-mfloat-abi=hard', + '-mfpu=neon', + '-marm', + '-DHAVE_NEON', + ] + else + arm_args = ['-mcpu=native', '-mfloat-abi=hard', '-mfpu=vfp', '-marm'] + endif + elif host_arch == 'aarch64' + c_args += ['-DX265_ARCH_ARM64=1'] + cpu_has_neon = true + + if aarch64_runtime_cpu_detect.allowed() + c_args += ['-DAARCH64_RUNTIME_CPU_DETECT=1'] + message('Configuring build for run-time CPU feature detection') + endif + + if aarch64_runtime_cpu_detect.allowed() or meson.is_cross_build() + cpu_has_neon_dotprod = true + cpu_has_neon_i8mm = true + cpu_has_sve = true + cpu_has_sve2 = true + elif host_system == 'linux' + cpu_has_neon_dotprod = 'asimddp' in cpuinfo + cpu_has_neon_i8mm = 'i8mm' in cpuinfo + cpu_has_sve = 'sve ' in cpuinfo.split() + cpu_has_sve2 = 'sve2' in cpuinfo + elif host_system == 'darwin' + cpu_has_neon_dotprod = 'hw.optional.arm.FEAT_DotProd: 1' in cpuinfo + cpu_has_neon_i8mm = 'hw.optional.arm.FEAT_I8MM: 1' in cpuinfo + cpu_has_sve = 'hw.optional.sve: 1' in cpuinfo.split() + cpu_has_sve2 = 'hw.optional.sve2: 1' in cpuinfo + else + warning('Compile-time CPU feature detection unsupported on this platform') + endif + + if enable_sve.allowed() or enable_sve2.allowed() + # Check whether the compiler can compile SVE functions that require + # backup/restore of SVE registers according to AAPCS. + # https://github.com/llvm/llvm-project/issues/80009. + sve_compilation_test = ''' +#include +void other(); +svfloat32_t func(svfloat32_t a) { + other(); + return a; +} +int main() { return 0; }''' + + sve_compilation_c_test_compiled = cc.compiles( + sve_compilation_test, + args: c_args + aarch64_sve_flag, + ) + sve_compilation_cpp_test_compiled = cpp.compiles( + sve_compilation_test, + args: c_args + aarch64_sve_flag, + ) + + # Check if arm_neon_sve_bridge.h is available. + sve_header_test = ''' +#ifndef __ARM_NEON_SVE_BRIDGE +#error 1 +#endif +#include +#include +int main() { return 0; }''' + sve_header_c_test_compiled = cc.compiles( + sve_header_test, + args: c_args + aarch64_sve_flag, + name: 'arm_neon_sve_bridge.h is available in C', + ) + sve_header_cpp_test_compiled = cpp.compiles( + sve_header_test, + args: c_args + aarch64_sve_flag, + name: 'arm_neon_sve_bridge.h is available in C++', + ) + + enable_sve = enable_sve.disable_if( + not sve_compilation_c_test_compiled or not sve_compilation_cpp_test_compiled, + ) + enable_sve2 = enable_sve2.disable_if( + not sve_compilation_c_test_compiled or not sve_compilation_cpp_test_compiled, + ) + + if sve_compilation_c_test_compiled and sve_compilation_cpp_test_compiled and sve_header_c_test_compiled and sve_header_cpp_test_compiled + c_args += '-DHAVE_SVE_BRIDGE=1' + have_sve_bridge = true + else + have_sve_bridge = false + endif + + # Impose constraint that disabling one extension disables all 'higher order' ones. + if enable_neon.disabled() + message('Disabling Neon') + cpu_has_neon = false + endif + enable_neon_dotprod = enable_neon.disable_if(enable_neon.disabled()) + if enable_neon_dotprod.disabled() + message('Disabling Neon DotProd') + cpu_has_neon_dotprod = false + endif + enable_neon_i8mm = enable_neon_i8mm.disable_if( + enable_neon_dotprod.disabled(), + ) + if enable_neon_i8mm.disabled() + message('Disabling Neon I8MM') + cpu_has_neon_i8mm = false + endif + # FIXME: have_sve_bridge needs to be taken into account in + # asm-primitives.cpp, not here --Amy + enable_sve = enable_sve.disable_if( + enable_neon_i8mm.disabled() or not have_sve_bridge, + ) + if enable_sve.disabled() + message('Disabling SVE') + cpu_has_sve = false + endif + enable_sve2 = enable_sve2.disable_if( + enable_sve.disabled() or not have_sve_bridge, + ) + if enable_sve2.disabled() + message('Disabling SVE2') + cpu_has_sve2 = false + endif + + if cpu_has_neon + message('Found Neon') + c_args += '-DHAVE_NEON=1' + endif + if cpu_has_neon_dotprod + message('Found Neon DotProd') + c_args += '-DHAVE_NEON_DOTPROD=1' + endif + if cpu_has_neon_i8mm + message('Found Neon I8MM') + c_args += '-DHAVE_NEON_I8MM=1' + endif + if cpu_has_sve + message('Found SVE') + c_args += '-DHAVE_SVE=1' + endif + if cpu_has_sve2 + message('Found SVE2') + c_args += '-DHAVE_SVE2=1' + endif + # Do not allow implicit vector type conversions in Clang builds (this + # is already the default in GCC builds). + arm_args = cc.get_supported_arguments('-flax-vector-conversions=none') + endif + endif + + # See earlier for handling of DPIC + + # skipping profiling, that's Meson managed afaiu + # skipping static CRT, same as above + cc_has_no_strict_overflow = cc.has_argument('-Wno-strict-overflow') + cc_has_no_narrowing = cc.has_argument('-Wno-narrowing') + c_args += cc.get_supported_arguments('-Wno-array-bounds') + c_args += cc.get_supported_arguments('-ffast-math') + if host_arch == 'aarch64' # host_arch already considers cross build + c_args += cc.get_supported_arguments('-mstackrealign') + endif + c_args += cc.get_supported_arguments('-fno-exceptions') + # skipping fsanitize etc., same as above +endif + +# FIXME: upstream on armv7 doesn't include -frtti for Android --Amy +# https://gitlab.freedesktop.org/gstreamer/cerbero/-/commit/01dfa050fd9d659b6fddc5238d42e893b728c414 +# FIXME: Meson thinks that all code tolerates _FILE_OFFSET_BITS=64... not! --Amy +# https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md +if host_system == 'android' + c_args += '-frtti' + if host_arch == 'arm' and cc.get_define('_FILE_OFFSET_BITS') != '' + c_args += '-U_FILE_OFFSET_BITS' + endif +endif + +nasm_found = add_languages( + 'nasm', + required: false, + native: false, +) + +enable_assembly = get_option('asm') + +# FIXME: Upstream always disables assembly when armv7. They didn't check +# that ENABLE_NEON as an option never exists there! --Amy +if host_arch == 'aarch64' # in ['arm', 'aarch64'] + # Force ENABLE_ASSEMBLY to be OFF when all SIMD extensions are disabled. + enable_assembly = enable_assembly.disable_if(enable_neon.disabled()) + + # FIXME: there are no checks for visual studio! + # (for the time being, let's disable only with cl, we'll see if someone + # report success with clang-cl or LLVM...) --Amy + enable_assembly = enable_assembly.disable_if(cc.get_id() == 'msvc') +elif nasm_found and host_arch == 'x86' + nasm = meson.get_compiler('nasm') + nasm_version = nasm.version() + enable_assembly = enable_assembly.disable_if( + nasm_version.version_compare('>= 2.13.0'), + ) +else + enable_assembly = enable_assembly.disable_if(not nasm_found) +endif + +if enable_assembly.allowed() + c_args += '-DENABLE_ASSEMBLY' +endif + +if get_option('checked_build') + c_args += '-DCHECKED_BUILD=1' +endif + +high_bit_depth = get_option('high_bit_depth').disable_if( + not ['x86_64', 'aarch64', 'ppc64'].contains(host_arch), +) + +bit_depths = { + '8': 'sdr', +} + +sdr_args = ['-DHIGH_BIT_DEPTH=0', '-DX265_DEPTH=8'] +if high_bit_depth.allowed() + if get_option('12bit') + hdr12_args = ['-DHIGH_BIT_DEPTH=1', '-DX265_DEPTH=12'] + sdr_args += ['-DLINKED_12BIT=1'] + bit_depths += { + '12': 'hdr12', + } + endif + if get_option('10bit') + hdr10_args = ['-DHIGH_BIT_DEPTH=1', '-DX265_DEPTH=10'] + sdr_args += ['-DLINKED_10BIT=1'] + bit_depths += { + '10': 'hdr10', + } + endif +endif + +if enable_hdr10_plus + include_dirs += [ + include_directories('.'), + include_directories('dynamicHDR10'), + ] + subdir('dynamicHDR10') + c_args += ['-DENABLE_HDR10_PLUS'] +endif + +# svt-hevc unsupported as of Aug 2024 +# https://www.phoronix.com/news/Intel-Discontinues-SVT-HEVC + +if high_bit_depth.allowed() + if get_option('12bit') + hdr12_args += ['-DX265_NS=x265_12bit', '-DEXPORT_C_API=0'] + hdr12_asm_args = hdr12_args + ['-DHIGH_BIT_DEPTH=1', '-DBIT_DEPTH=12'] + endif + if get_option('10bit') + hdr10_args += ['-DX265_NS=x265_10bit', '-DEXPORT_C_API=0'] + hdr10_asm_args = hdr10_args + ['-DHIGH_BIT_DEPTH=1', '-DBIT_DEPTH=10'] + endif +endif +# This Meson port ships with 8-bit by default. 10 and 12-bit are additive --Amy +sdr_args += ['-DX265_NS=x265', '-DEXPORT_C_API=1'] +sdr_asm_args = sdr_args + ['-DHIGH_BIT_DEPTH=0', '-DBIT_DEPTH=8'] + +# skipping windows XP support etc. + +if host_arch.startswith('ppc') + # IBM Power8 + if get_option('altivec') + c_args += [ + '-DHAVE_ALTIVEC=1', + '-maltivec', + '-mabi=altivec', + '-flax-vector-conversions', + '-fpermissive', + ] + else + c_args += ['-DHAVE_ALTIVEC=0'] + endif + + if get_option('cpu_power8') + c_args += ['-mcpu=power8', '-DX265_ARCH_POWER8=1'] + endif +endif + +git = find_program( + 'git', + native: true, +) + +version_py = find_program( + 'meson/version.py', + native: true, +) + +version_data = run_command( + version_py, + '--git', + git, + meson.project_source_root(), + capture: true, + check: true, +) + +message(version_data.stderr().strip()) + +x265_version = '' +x265_latest_tag = '' +foreach line : version_data.stdout().splitlines() + if '=' in line + kv = line.split('=') + set_variable(kv[0].strip().to_lower(), kv[1].strip()) + endif +endforeach + +include_dirs += [ + include_directories('.'), + include_directories('common'), + include_directories('encoder'), +] + +if get_option('detailed_cu_stats') + c_args += '-DDETAILED_CU_STATS' +endif + +if get_option('alpha') + c_args += '-DENABLE_ALPHA' +endif + +if get_option('multiview') + c_args += '-DENABLE_MULTIVIEW' +endif + +if get_option('scc_ext') + c_args += '-DENABLE_SCC_EXT' +endif + +subdir('encoder') +subdir('common') + +x265_rc = [] + +if host_system == 'windows' + windows = import('windows') + version_list = x265_version.split('+')[0].split('.') + + x265_rc_file = configure_file( + input: 'x265.rc.in', + output: 'x265.rc', + configuration: { + 'X265_VERSION': x265_version, + 'X265_VERSION_MAJOR': version_list[0], + 'X265_VERSION_MINOR': version_list[1], + 'X265_BRANCH_ID': 0, # TODO: 0 - stable, 1 - default or other + 'X265_TAG_DISTANCE': x265_tag_distance, + }, + ) + x265_rc = windows.compile_resources(x265_rc_file) +endif + +x265_objs = [] +foreach l : encoders + x265_objs += l.extract_all_objects( + recursive: true, + ) +endforeach +foreach l : common + x265_objs += l.extract_all_objects( + recursive: true, + ) +endforeach + +x265_version = x265_build + +if x265_latest_tag != '' or not git.found() + x265_version = x265_latest_tag +endif + +if enable_hdr10_plus + # FIXME: hdr10plus doesn't export any symbol on Windows, i don't think + # Multicoreware intended this --Amy + if host_system == 'windows' + dynamicHDR10_lib = static_library( + 'hdr10plus', + dynamicHDR10_srcs, + c_args: c_args, + cpp_args: c_args, + include_directories: include_dirs, + override_options: ['cpp_std=c++11', 'warning_level=2'], + dependencies: platform_libs, + # gnu_symbol_visibility: 'inlineshidden', + install: true, + ) + else + dynamicHDR10_lib = library( + 'hdr10plus', + dynamicHDR10_srcs, + c_args: c_args, + cpp_args: c_args, + include_directories: include_dirs, + override_options: ['cpp_std=c++11', 'warning_level=2'], + link_args: cc.get_supported_link_arguments('-Wl,-Bsymbolic,-znoexecstack'), + dependencies: platform_libs, + # gnu_symbol_visibility: 'inlineshidden', + install: true, + ) + endif + x265_objs += dynamicHDR10_lib.extract_all_objects( + recursive: true, + ) + x265_lib = library( + 'x265', + [x265_config, x265_rc], + include_directories: include_dirs, + objects: x265_objs, + link_args: cc.get_supported_link_arguments('-Wl,-Bsymbolic,-znoexecstack') + vflag, + dependencies: platform_libs, + link_depends: x265_ver, + vs_module_defs: x265_def, + soversion: x265_build, + version: x265_version, + # FIXME: https://github.com/mesonbuild/meson/issues/15234 + # prelink: true, + # FIXME: inlineshidden takes effect on prelinking + # And on macOS, -exported_symbols_list cannot unhide the symbols + # gnu_symbol_visibility: 'inlineshidden', + install: true, + ) +else + x265_lib = library( + 'x265', + [x265_config, x265_rc], + include_directories: include_dirs, + link_whole: encoders + common, + link_args: cc.get_supported_arguments('-Wl,-Bsymbolic,-znoexecstack') + vflag, + dependencies: platform_libs, + link_depends: x265_ver, + vs_module_defs: x265_def, + soversion: x265_build, + version: x265_version, + # FIXME: https://github.com/mesonbuild/meson/issues/15234 + # prelink: true, + # FIXME: inlineshidden takes effect on prelinking + # And on macOS, -exported_symbols_list cannot unhide the symbols + # gnu_symbol_visibility: 'inlineshidden', + install: true, + ) +endif + +pkg = import('pkgconfig') + +pc_file = pkg.generate( + x265_lib, + description: 'H.265/HEVC video encoder', +) + +cli = get_option('cli') + +# FIXME: y4m.cpp also forces _FILE_OFFSET_BITS. See above as to why that's a +# nono --Amy +cli = cli.disable_if(host_system == 'android' and host_arch == 'arm') + +if cli.allowed() + input_files = files( + 'input/input.cpp', + 'input/input.h', + 'input/y4m.cpp', + 'input/y4m.h', + 'input/yuv.cpp', + 'input/yuv.h', + ) + output_files = files( + 'output/output.cpp', + 'output/output.h', + 'output/raw.cpp', + 'output/raw.h', + 'output/reconplay.cpp', + 'output/reconplay.h', + 'output/y4m.cpp', + 'output/y4m.h', + 'output/yuv.cpp', + 'output/yuv.h', + ) + + getopt_lib = [] + if not cc.has_header('getopt.h') + include_dirs += include_directories('compat/getopt') + getopt_lib = static_library( + 'getopt', + files('compat/getopt/getopt.c', 'compat/getopt/getopt.h'), + c_args: cc.get_supported_arguments('/wd4100', '/wd4131') + '-DHAVE_STRING_H=1', + include_directories: include_dirs, + # gnu_symbol_visibility: 'inlineshidden', + ) + endif + + cli = executable( + 'x265', + input_files + output_files + files( + 'abrEncApp.cpp', + 'abrEncApp.h', + 'x265.cpp', + 'x265.h', + 'x265cli.cpp', + 'x265cli.h', + ), + extra_files: files('../COPYING'), + # FIXME: what happens when the CLI uses 10 or 12-bit depth? + # Is it supposed to be built under 8-bit? --Amy + cpp_args: [c_args, sdr_args], + # The CLI cannot link to the shared library on Windows, it + # requires internal APIs not exported from the DLL + objects: x265_lib.extract_all_objects( + recursive: true, + ), + include_directories: include_dirs, + link_whole: [getopt_lib], + install: true, + ) +endif + +install_headers(files('x265.h') + x265_config) + +# FIXME: testbench.cpp force requires x265::setupAssemblyPrimitives, +# which is not available on armv7 when not ENABLE_ASSEMBLY --Amy +# FIXME: the above should use "and host_arch.startswith('x86')" --Amy +# FIXME: upstream doesn't do any detection for runnable binaries --Amy +# FIXME: upstream test for addAvg[8x8] 10-bit on NEON doesn't tolerate anything +# other than optimization=3 --Amy +enable_tests = get_option('tests').disable_if( + enable_assembly.disabled() or not meson.can_run_host_binaries() or get_option( + 'optimization', + ) != '3', +) + +if enable_tests.allowed() + subdir('test') +endif diff --git a/subprojects/packagefiles/x265/source/meson/intrin.h b/subprojects/packagefiles/x265/source/meson/intrin.h new file mode 100644 index 000000000..a2633e3eb --- /dev/null +++ b/subprojects/packagefiles/x265/source/meson/intrin.h @@ -0,0 +1 @@ +#include_next diff --git a/subprojects/packagefiles/x265/source/meson/makever.py b/subprojects/packagefiles/x265/source/meson/makever.py new file mode 100755 index 000000000..ad7b53080 --- /dev/null +++ b/subprojects/packagefiles/x265/source/meson/makever.py @@ -0,0 +1,61 @@ +#!/usr/bin/env python3 + +# SPDX-FileCopyrightText: 2025 L. E. Segovia +# SPDX-License-Ref: BSD-3-Clause + +from argparse import ArgumentParser +import pathlib + + +def output(platform, symbols): + if platform == 'win': + print('EXPORTS') + print(*[f' {symbol}' for symbol in sorted(set(symbols))], sep='\n') + elif platform == 'darwin': + print(*[f'{symbol}' for symbol in sorted(set(symbols))], sep='\n') + else: + print('{') + print(' global:') + print( + *[f' {symbol};' for symbol in sorted(set(symbols))], sep='\n') + print(' local:') + print(' *;') + print('};') + + +if __name__ == '__main__': + parser = ArgumentParser(description='Convert Windows .def file to a GNU version script or Mach-O exported symbols list.') + parser.add_argument('--prefix', metavar='PREFIX', + help='Prefix for extern symbols') + parser.add_argument('--os', type=str, choices=('win', 'linux', 'darwin'), + default='linux', required=True, + help='Target operating system for the exports file (win = MSVC module definition file, linux = version script, darwin = exported symbols list)') + parser.add_argument('input', metavar='FILE', type=pathlib.Path, help='Module definition file to parse') + + args = parser.parse_args() + + lines = args.input.open('r', encoding='utf-8').readlines() + + symbols: list[str] = [] + found_exports = False + for line in lines: + stripped = line.strip() + if not found_exports: + if stripped.upper().startswith('EXPORTS'): + found_exports = True + continue + # After EXPORTS – ignore blanks or comment lines + if stripped == '' or stripped.startswith(';'): + continue + # Strip inline comments + symbol = stripped.split(';', 1)[0].strip() + if symbol: + symbols.append(symbol) + + if not symbols: + raise RuntimeError('Error: No symbols found after EXPORTS') + + if args.prefix: + symbols = [f'_{s}' for s in symbols] + + output(args.os, symbols) diff --git a/subprojects/packagefiles/x265/source/meson/version.py b/subprojects/packagefiles/x265/source/meson/version.py new file mode 100755 index 000000000..d30ef8cba --- /dev/null +++ b/subprojects/packagefiles/x265/source/meson/version.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python3 + +# SPDX-FileCopyrightText: 2025 L. E. Segovia +# SPDX-License-Ref: BSD-3-Clause + +from argparse import ArgumentParser +from pathlib import Path +import subprocess +import sys + + +def parse_key_value_file(path: Path): + data = {} + with path.open('r', encoding='utf-8') as f: + for line in f: + line = line.strip() + if not line or ':' not in line: + continue + key, value = line.split(':', 1) + data[key.strip()] = value.strip() + return data + + +if __name__ == '__main__': + parser = ArgumentParser( + description='Identity version control software version display, also read version files to present x265 version.') + parser.add_argument('--git', required=False, type=Path) + parser.add_argument('src_dir', type=Path) + args = parser.parse_args() + + # Default Settings, for user to be vigilant about x265 version being reported during product build. + x265_version = 'unknown' + x265_latest_tag = '0.0' + x265_tag_distance = '0' + x265_revision_id = '' + + archive_file = Path(args.src_dir) / 'x265Version.txt' + git_dir = Path(args.src_dir) / '.git' + + # FIXME: the original cannot parse shallow clones --Amy + can_describe_tags = False + if git_dir.exists() and args.git: + can_describe_tags = subprocess.run([args.git, + 'describe', '--abbrev=0', + '--tags'], + cwd=args.src_dir, + encoding='utf-8', + ).returncode == 0 + + if can_describe_tags: + x265_latest_tag = subprocess.check_output( + [args.git, 'describe', '--abbrev=0', '--tags'], + cwd=args.src_dir, + encoding='utf-8', + ).strip() + # Convert “v1.8.0” → “1.8.0” + if x265_latest_tag.startswith('v'): + x265_latest_tag = x265_latest_tag[1:] + + x265_tag_distance = subprocess.check_output( + [args.git, 'rev-list', f'{x265_latest_tag}..', + '--count', '--first-parent'], + cwd=args.src_dir, + encoding='utf-8', + ).strip() + + x265_revision_id = subprocess.check_output( + [args.git, 'log', '--pretty=format:%h', '-n', '1'], + cwd=args.src_dir, + encoding='utf-8', + ).strip() + print("GIT LIVE REPO VERSION RETRIEVED", file=sys.stderr) + elif archive_file.exists(): + print("SOURCE CODE IS FROM x265 GIT ARCHIVED ZIP OR TAR BALL", file=sys.stderr) + # Read the lines of the archive summary file to extract the version + git_meta = parse_key_value_file(archive_file) + # releasetag: 1.8.0 + # releasetagdistance: 2 + # repositorychangeset: abcdef123456... + x265_latest_tag = git_meta.get('releasetag', x265_latest_tag) + x265_tag_distance = git_meta.get( + 'releasetagdistance', x265_tag_distance) + commit = git_meta.get('repositorychangeset', '') + if commit: + x265_revision_id = commit[:9] # 9‑char abbreviated hash + print("GIT ARCHIVAL INFORMATION PROCESSED", file=sys.stderr) + + # formatting based on distance from tag + if x265_tag_distance == '0': + x265_version = x265_latest_tag + elif int(x265_tag_distance) > 0: + x265_version = f'{x265_latest_tag}+{x265_tag_distance}-{x265_revision_id}' + + # will always be printed in its entirety based on version file configuration to avail revision monitoring by repo owners + print(f'X265_VERSION={x265_version}') + print(f'X265_LATEST_TAG={x265_latest_tag}') + print(f'X265_TAG_DISTANCE={x265_tag_distance}') + print(f"X265 RELEASE VERSION {x265_version}", file=sys.stderr) diff --git a/subprojects/packagefiles/x265/source/test/meson.build b/subprojects/packagefiles/x265/source/test/meson.build new file mode 100644 index 000000000..f39aaec41 --- /dev/null +++ b/subprojects/packagefiles/x265/source/test/meson.build @@ -0,0 +1,75 @@ +have_rdtsc = cc.has_header_symbol('intrin.h', '__rdtsc') +if have_rdtsc + c_args += '-DHAVE_RDTSC=1' +elif host_arch.startswith('x86') + # FIXME: On AppleClang x86_64 __rdtsc is a builtin --Amy + if cc.compiles( + 'int main() { return __rdtsc(); }', + name: 'Has __rdtsc as a builtin', + ) + c_args += '-DHAVE_RDTSC=1' + # Cheats forced inclusion of intrin.h with HAVE_RDTSC + include_dirs += include_directories('../meson') + endif +endif + +# add X86 assembly files +if host_arch.startswith('x86') + nasm_src = files('checkasm-a.asm') + # add ARM assembly files +elif host_arch == 'arm' + nasm_src = files('checkasm-arm.S') +else + nasm_src = [] +endif + +testbench_srcs = nasm_src + files( + 'intrapredharness.cpp', + 'intrapredharness.h', + 'ipfilterharness.cpp', + 'ipfilterharness.h', + 'mbdstharness.cpp', + 'mbdstharness.h', + 'pixelharness.cpp', + 'pixelharness.h', + 'testbench.cpp', + 'testharness.h', +) + +# FIXME: on CMake checkasm-arm uses NASM_FLAGS, +# that was wrong since day one! --Amy +if enable_assembly.allowed() and host_arch.startswith('x86') + foreach bit, depth : bit_depths + testbench_args = c_args + get_variable(f'@depth@_args') + testbench = executable( + f'TestBench-@depth@', + testbench_srcs, + c_args: testbench_args, + cpp_args: testbench_args, + nasm_args: nasm_args + get_variable(f'@depth@_asm_args'), + objects: x265_lib.extract_all_objects( + recursive: true, + ), + include_directories: include_dirs, + dependencies: platform_libs, + ) + test(f'TestBench-@depth@', testbench) + endforeach +else + # FIXME: let me know if this needs getting @depth@_asm_args --Amy + foreach bit, depth : bit_depths + testbench_args = c_args + get_variable(f'@depth@_args') + testbench = executable( + f'TestBench-@depth@', + testbench_srcs, + c_args: testbench_args, + cpp_args: testbench_args, + objects: x265_lib.extract_all_objects( + recursive: true, + ), + include_directories: include_dirs, + dependencies: platform_libs, + ) + test(f'TestBench-@depth@', testbench) + endforeach +endif diff --git a/subprojects/x265.wrap b/subprojects/x265.wrap new file mode 100644 index 000000000..2648fc39d --- /dev/null +++ b/subprojects/x265.wrap @@ -0,0 +1,9 @@ +[wrap-file] +directory = x265_4.1 +source_url = https://bitbucket.org/multicoreware/x265_git/downloads/x265_4.1.tar.gz +source_filename = x265_4.1.tar.gz +source_hash = a31699c6a89806b74b0151e5e6a7df65de4b49050482fe5ebf8a4379d7af8f29 +patch_directory = x265 + +[provide] +dependency_names = x265 diff --git a/tools/sanity_checks.py b/tools/sanity_checks.py index 42ae20079..d0e337ab2 100755 --- a/tools/sanity_checks.py +++ b/tools/sanity_checks.py @@ -160,6 +160,13 @@ 'makedef.py', 'stddef.h.in', }, + 'x265': { + 'version.py', + 'intrin.h', + 'makever.py', + 'primitives-placeholders.cpp', + 'gcc15-workaround.cpp', + }, 'zlib-ng': { 'get-version.py', 'process-zconf.py',