diff --git a/.github/workflows/build-decoders.yml b/.github/workflows/build-decoders.yml new file mode 100644 index 00000000..78b848dc --- /dev/null +++ b/.github/workflows/build-decoders.yml @@ -0,0 +1,121 @@ +# Fluster - testing framework for decoders conformance +# Copyright (C) 2025, Fluendo, S.A. +# +# CI workflow to build all reference decoders on multiple platforms + +name: Build Reference Decoders + +on: + push: + branches: + - master + paths: + - 'subprojects/**' + - 'meson.build' + - 'meson_options.txt' + - 'build/**' + - '.github/workflows/build-decoders.yml' + pull_request: + branches: + - master + paths: + - 'subprojects/**' + - 'meson.build' + - 'meson_options.txt' + - 'build/**' + - '.github/workflows/build-decoders.yml' + workflow_dispatch: + +jobs: + build: + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + defaults: + run: + shell: ${{ matrix.shell }} + + strategy: + fail-fast: false + matrix: + include: + - name: Linux x86_64 + os: ubuntu-22.04 + arch: x86_64 + artifact: decoders-linux-x86_64 + shell: bash + + - name: Linux ARM64 + os: ubuntu-22.04-arm + arch: arm64 + artifact: decoders-linux-arm64 + shell: bash + + - name: Windows x86_64 + os: windows-2022 + arch: x64 + artifact: decoders-windows-x86_64 + shell: msys2 {0} + + - name: macOS ARM64 + os: macos-14 + arch: arm64 + artifact: decoders-macos-arm64 + shell: bash + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + # Linux dependencies + - name: Install dependencies (Linux) + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y ninja-build cmake build-essential unzip curl + pip install meson + + # macOS dependencies + - name: Install dependencies (macOS) + if: runner.os == 'macOS' + run: brew install ninja cmake meson + + # Windows dependencies + - name: Install dependencies (Windows) + if: runner.os == 'Windows' + uses: msys2/setup-msys2@v2 + with: + msystem: UCRT64 + update: true + install: >- + mingw-w64-ucrt-x86_64-toolchain + mingw-w64-ucrt-x86_64-cmake + mingw-w64-ucrt-x86_64-ninja + mingw-w64-ucrt-x86_64-meson + mingw-w64-ucrt-x86_64-python + mingw-w64-ucrt-x86_64-python-pip + git + unzip + curl + + - name: Download dependencies + run: python3 build/download_deps.py + + - name: Configure Meson + run: meson setup builddir + + - name: Build decoders + run: meson compile -C builddir + + - name: Upload decoders + uses: actions/upload-artifact@v4 + with: + name: ${{ matrix.artifact }} + path: decoders/ + if-no-files-found: warn diff --git a/.gitignore b/.gitignore index 3a88670b..dfaf1a91 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,14 @@ results contrib decoders !*fluster/decoders +subprojects/hm/ +subprojects/isobmff/ +subprojects/jm/ +subprojects/libtsp-v7r0 +subprojects/mpeg2aac +subprojects/mpeg2video +subprojects/vvcsoftware_vtm/ +subprojects/vvdec/ ### Python ### # Byte-compiled / optimized / DLL files diff --git a/README.md b/README.md index 584b9565..acfb2d77 100644 --- a/README.md +++ b/README.md @@ -59,9 +59,9 @@ but they could actually be decoders written in Python as far as Fluster is concerned. The [decoders](https://github.com/fluendo/fluster/tree/master/fluster/decoders) directory contains all supported decoders. -**Fluster includes a pixel comparison method for testing decoders that don't generate identical outputs.** -This is essential for older video decoders with IDCT implementations where, -according to the standard specifications, MD5 verification cannot be used unlike newer decoder implementations, +**Fluster includes a pixel comparison method for testing decoders that don't generate identical outputs.** +This is essential for older video decoders with IDCT implementations where, +according to the standard specifications, MD5 verification cannot be used unlike newer decoder implementations, ensuring accurate conformance testing across different decoder generations. In order to run the tests for the different test suites and decoders, a @@ -101,10 +101,22 @@ For complete setup, usage examples, hardware acceleration configuration, and tro - `./fluster.py download` downloads all available test suites 2. (Optional) Build the reference decoders for AAC, H.264/AVC, H.265/HEVC, - H.266/VVC running `make all_reference_decoders`. This is available and has been - tested with x86_64 and Linux. It assumes you have CMake and a native compiler - such as gcc or clang installed so that they can be built. The resulting binaries - will be moved to a new `decoders` directory in the root. + H.266/VVC. First, download the ISO reference software: + + ```bash + python3 build/download_deps.py + ``` + + Then build using meson: + + ```bash + meson setup builddir + ninja -C builddir + ``` + + This requires meson, ninja, and a native compiler (gcc or clang). The resulting + binaries will be placed in the `decoders` directory. This has been tested on + Linux and macOS (both x86_64 and ARM64). 3. List the test suites and the decoders available `./fluster.py list`. Tip: You can list the decoders that can run in the current system with `./fluster.py list -c`. @@ -181,7 +193,7 @@ MPEG2_AAC-ADIF Codec: AAC Description: ISO IEC 13818-4 MPEG2 AAC ADIF test suite Test vectors: 492 - + MPEG2_AAC-ADTS Codec: AAC Description: ISO IEC 13818-4 MPEG2 AAC ADTS test suite @@ -571,7 +583,7 @@ subcommands: ```bash ./fluster.py list --help -usage: fluster.py list [-h] [-ts TESTSUITES [TESTSUITES ...]] [-tv] [-c] [-v] +usage: fluster.py list [-h] [-ts TESTSUITES [TESTSUITES ...]] [-tv] [-c] [-v] [-d {None,Dummy,H.264,H.265,H.266,VP8,VP9,AAC,AV1,MPEG2_VIDEO,MPEG4_VIDEO}] optional arguments: @@ -598,7 +610,7 @@ usage: fluster.py run [-h] [-j JOBS] [-t TIMEOUT] [-ff] [-q] optional arguments: -h, --help show this help message and exit - -j JOBS, --jobs JOBS number of parallel jobs to use (by default 1x logical cores, + -j JOBS, --jobs JOBS number of parallel jobs to use (by default 1x logical cores, value 0 is interpreted as the same) -t TIMEOUT, --timeout TIMEOUT timeout in secs for each decoding. Defaults to 30 secs @@ -640,7 +652,7 @@ positional arguments: optional arguments: -h, --help show this help message and exit - -j JOBS, --jobs JOBS number of parallel jobs to use (upper limit of 16, by default 2x logical cores). + -j JOBS, --jobs JOBS number of parallel jobs to use (upper limit of 16, by default 2x logical cores). value 0 is interpreted as 1x logical cores -k, --keep keep original downloaded file after extracting. Only applicable to compressed files such as .zip, .tar.gz, etc -r RETRIES, --retries RETRIES @@ -668,7 +680,7 @@ positional arguments: optional arguments: -h, --help show this help message and exit - -j JOBS, --jobs JOBS number of parallel jobs to use (by default 1x logical cores, + -j JOBS, --jobs JOBS number of parallel jobs to use (by default 1x logical cores, value 0 is interpreted as the same) -t TIMEOUT, --timeout TIMEOUT timeout in secs for each decoding. Defaults to 30 secs @@ -737,11 +749,11 @@ Check out the JSON format they follow in the [test_suites](https://github.com/fl directory. Add a new json file within, Fluster will automatically pick it up. -There is also a [generator script (MPEG2 video)](https://github.com/fluendo/fluster/blob/master/scripts/gen_mpeg2_video.py), -[generator script (MPEG4 video)](https://github.com/fluendo/fluster/blob/master/scripts/gen_mpeg4_video.py), -[generator script (H.264)](https://github.com/fluendo/fluster/blob/master/scripts/gen_jvt.py), -[generator script (H.265)](https://github.com/fluendo/fluster/blob/master/scripts/gen_jct_vc.py), and a -[generator script (H.266)](https://github.com/fluendo/fluster/blob/master/scripts/gen_jvet.py) for the +There is also a [generator script (MPEG2 video)](https://github.com/fluendo/fluster/blob/master/scripts/gen_mpeg2_video.py), +[generator script (MPEG4 video)](https://github.com/fluendo/fluster/blob/master/scripts/gen_mpeg4_video.py), +[generator script (H.264)](https://github.com/fluendo/fluster/blob/master/scripts/gen_jvt.py), +[generator script (H.265)](https://github.com/fluendo/fluster/blob/master/scripts/gen_jct_vc.py), and a +[generator script (H.266)](https://github.com/fluendo/fluster/blob/master/scripts/gen_jvet.py) for the [conformance test suites](#test-suites) that you can use as a base to generate automatically new ones. ### How can I use it to test regressions? @@ -814,8 +826,8 @@ results are obtained, we can do the following procedure: ### How can I report an issue? -In case you find any problem or want to report something, please search for similar -[issues](https://github.com/fluendo/fluster/issues) first. If you find none, go ahead to create one. +In case you find any problem or want to report something, please search for similar +[issues](https://github.com/fluendo/fluster/issues) first. If you find none, go ahead to create one. Please try to provide as many details and context as possible to help us diagnose it. ## License diff --git a/build/build_iso_decoders.py b/build/build_iso_decoders.py new file mode 100755 index 00000000..def6ac6c --- /dev/null +++ b/build/build_iso_decoders.py @@ -0,0 +1,239 @@ +#!/usr/bin/env python3 +# Fluster - testing framework for decoders conformance +# Copyright (C) 2025, Fluendo, S.A. +# +# Helper script to build ISO reference decoders +# Usage: build_iso_decoders.py +# +# Arguments: +# build_dir - Meson build directory +# cflags - Extra CFLAGS to pass to compiler +# ldflags - Extra LDFLAGS to pass to linker +# decoders... - Space-separated list of decoders to build (or 'all') +# +# Supported decoders: +# mpeg4-aac - MPEG-4 AAC decoder (mp4audec_mc) +# mpeg4-aac-er - MPEG-4 AAC Error Resilient decoder (mp4audec) +# all - Build all decoders + +import os +import platform +import shutil +import subprocess +import sys +from pathlib import Path + + +def find_file(search_dir, filename): + """Find a file in directory tree""" + for root, dirs, files in os.walk(search_dir): + if filename in files: + return Path(root) / filename + return None + + +def should_build(decoder, decoders_list): + """Check if a decoder should be built""" + return "all" in decoders_list or decoder in decoders_list + + +def run_make(target, cwd, env): + """Run make with the given target""" + try: + subprocess.run(["make", "clean"], cwd=cwd, env=env, check=False, capture_output=True) + result = subprocess.run( + ["make", target], + cwd=cwd, + env=env, + check=True, + capture_output=False, + ) + return result.returncode == 0 + except subprocess.CalledProcessError as e: + print(f"Error building {target}: {e}") + return False + + +def build_mpeg4_aac(mpeg4_dir, decoders_dir, env): + """Build MPEG-4 AAC decoder (mp4audec_mc)""" + print() + print("=== Building MPEG-4 AAC decoder (mp4audec_mc) ===") + mp4mcdec_dir = mpeg4_dir / "mp4mcDec" + env["MAKELEVEL"] = "0" + if run_make("mp4audec_mc", mp4mcdec_dir, env): + # Binary location varies by platform + for binary in (mpeg4_dir / "bin").rglob("mp4audec_mc"): + if binary.is_file(): + shutil.copy2(binary, decoders_dir / "mp4audec_mc") + break + print("mp4audec_mc built successfully!") + return True + else: + print("Failed to build mp4audec_mc") + return False + + +def build_mpeg4_aac_er(mpeg4_dir, decoders_dir, env): + """Build MPEG-4 AAC Error Resilient decoder (mp4audec)""" + print() + print("=== Building MPEG-4 AAC Error Resilient decoder (mp4audec) ===") + mp4audvm_dir = mpeg4_dir / "mp4AudVm_Rewrite" + env["MAKELEVEL"] = "0" + if run_make("mp4audec", mp4audvm_dir, env): + # Binary location varies by platform + for binary in (mpeg4_dir / "bin").rglob("mp4audec"): + if binary.is_file(): + shutil.copy2(binary, decoders_dir / "mp4audec") + break + print("mp4audec built successfully!") + return True + else: + print("Failed to build mp4audec") + return False + + +def main(): + # Parse arguments + if len(sys.argv) < 4: + print("Usage: build_iso_decoders.py ") + sys.exit(1) + + build_dir = Path(sys.argv[1]).resolve() + cflags_extra = sys.argv[2] + ldflags_extra = sys.argv[3] + decoders_arg = sys.argv[4] if len(sys.argv) > 4 else "all" + decoders_list = decoders_arg.split() + + # Get script directory and calculate paths + script_dir = Path(__file__).parent.resolve() + root_dir = script_dir.parent + + # Set directory paths + contrib_dir = root_dir / "contrib" + decoders_dir = root_dir / "decoders" + isobmff_dir = root_dir / "subprojects" / "isobmff" + + # Auto-detect MP4OSMACROS_SUBDIR based on platform + system = platform.system() + if system == "Darwin": + mp4osmacros_subdir = "macosx" + elif system == "Linux": + mp4osmacros_subdir = "linux" + elif system == "Windows": + mp4osmacros_subdir = "w32" + else: + mp4osmacros_subdir = "linux" + + # Create decoders directory + decoders_dir.mkdir(parents=True, exist_ok=True) + + print("=== ISO Reference Decoders Build Script ===") + print(f"Contrib directory: {contrib_dir}") + print(f"Decoders directory: {decoders_dir}") + print(f"isobmff directory: {isobmff_dir}") + print(f"MP4OSMacros subdir: {mp4osmacros_subdir}") + print(f"Build directory: {build_dir}") + print(f"CFLAGS: {cflags_extra if cflags_extra else 'default'}") + print(f"LDFLAGS: {ldflags_extra if ldflags_extra else 'default'}") + print(f"Decoders to build: {' '.join(decoders_list)}") + print() + + # Setup CFLAGS/LDFLAGS for MPEG-4 AAC dependencies + mpeg4_dir = contrib_dir / "C050470e_Electronic_inserts" / "audio" / "natural" + + # ISOBMFF library + if not isobmff_dir.exists(): + print(f"Error: isobmff subproject not found at {isobmff_dir}") + print("Enable it with: meson configure builddir -Disobmff=true") + sys.exit(1) + + # Add isobmff include paths (from source directory) + cflags_extra += f" -I{isobmff_dir}/IsoLib/libisomediafile/src" + cflags_extra += f" -I{isobmff_dir}/IsoLib/libisomediafile/{mp4osmacros_subdir}" + + # Find the built library in the build directory + isobmff_build_dir = build_dir / "subprojects" / "isobmff" + isobmff_lib = find_file(isobmff_build_dir, "liblibisomediafile.a") + if not isobmff_lib: + print("Error: isobmff library not found in build directory") + print(f"Expected at: {isobmff_build_dir}/liblibisomediafile.a") + sys.exit(1) + print(f"Using isobmff library: {isobmff_lib}") + + isobmff_lib_dir = isobmff_lib.parent + # Note: The library is named liblibisomediafile.a but we link with -lisomediafile + # Create a symlink if needed + libisomediafile_symlink = isobmff_lib_dir / "libisomediafile.a" + if not libisomediafile_symlink.exists(): + try: + libisomediafile_symlink.symlink_to("liblibisomediafile.a") + except (OSError, NotImplementedError): + # On Windows, copy instead of symlink + shutil.copy2(isobmff_lib, libisomediafile_symlink) + ldflags_extra += f" -L{isobmff_lib_dir}" + + # libtsp library + # Find libtsp library built by meson + libtsp_lib = find_file(build_dir / "subprojects" / "libtsp-v7r0", "libtsp.a") + if not libtsp_lib: + print("Error: libtsp library not found in build directory") + print(f"Expected at: {build_dir}/subprojects/libtsp-v7r0/libtsp.a") + sys.exit(1) + print(f"Using libtsp library: {libtsp_lib}") + + # Find libtsp include directory + libtsp_src = root_dir / "subprojects" / "libtsp-v7r0" + if not (libtsp_src / "include").exists(): + print(f"Error: libtsp headers not found at {libtsp_src}/include") + sys.exit(1) + libtsp_inc = libtsp_src / "include" + print(f"Using libtsp headers: {libtsp_inc}") + + # Add libtsp include paths + cflags_extra += f" -I{libtsp_inc}" + + # Add libtsp library path + libtsp_lib_dir = libtsp_lib.parent + ldflags_extra += f" -L{libtsp_lib_dir}" + + # Setup environment for makefiles + env = os.environ.copy() + env["CFLAGS"] = cflags_extra.strip() + env["LDFLAGS"] = ldflags_extra.strip() + + # Export MPEG-4 AAC makefile variables + # These are expected by the ISO reference software makefiles + env["ISOMP4_PATH"] = str(isobmff_lib_dir) + env["ISOMP4_NAME"] = "isomediafile" + env["AFSP_INCLUDE_PATH"] = str(libtsp_inc) + env["AFSP_LIBRARY_PATH"] = str(libtsp_lib_dir) + + print(f"CFLAGS: {env['CFLAGS']}") + print(f"LDFLAGS: {env['LDFLAGS']}") + print(f"ISOMP4_PATH: {env['ISOMP4_PATH']}") + print(f"ISOMP4_NAME: {env['ISOMP4_NAME']}") + print(f"AFSP_INCLUDE_PATH: {env['AFSP_INCLUDE_PATH']}") + print(f"AFSP_LIBRARY_PATH: {env['AFSP_LIBRARY_PATH']}") + + print() + print("=== Preparing MPEG-4 AAC build environment ===") + + # Create output directories + (mpeg4_dir / "lib").mkdir(parents=True, exist_ok=True) + (mpeg4_dir / "bin").mkdir(parents=True, exist_ok=True) + + # Build decoders + if should_build("mpeg4-aac", decoders_list): + if not build_mpeg4_aac(mpeg4_dir, decoders_dir, env): + sys.exit(1) + + if should_build("mpeg4-aac-er", decoders_list): + if not build_mpeg4_aac_er(mpeg4_dir, decoders_dir, env): + sys.exit(1) + + print() + print("=== ISO Reference Decoders build complete ===") + + +if __name__ == "__main__": + main() diff --git a/build/compat/common/legacy_compat.h b/build/compat/common/legacy_compat.h new file mode 100644 index 00000000..08e2313b --- /dev/null +++ b/build/compat/common/legacy_compat.h @@ -0,0 +1,17 @@ +/* + * Fluster - testing framework for decoders conformance + * Copyright (C) 2025, Fluendo, S.A. + * + * Compatibility header for legacy K&R C code + * These old codebases rely on implicit function declarations. + * This header provides the missing standard includes. + */ + +#ifndef _COMPAT_LEGACY_H +#define _COMPAT_LEGACY_H + +#include +#include +#include + +#endif /* _COMPAT_LEGACY_H */ diff --git a/build/compat/macos/malloc.h b/build/compat/macos/malloc.h new file mode 100644 index 00000000..4b565cc6 --- /dev/null +++ b/build/compat/macos/malloc.h @@ -0,0 +1,14 @@ +/* + * Fluster - testing framework for decoders conformance + * Copyright (C) 2025, Fluendo, S.A. + * + * Compatibility header for macOS + * malloc.h doesn't exist on macOS - redirect to stdlib.h + */ + +#ifndef _COMPAT_MALLOC_H +#define _COMPAT_MALLOC_H + +#include + +#endif /* _COMPAT_MALLOC_H */ diff --git a/build/download_deps.py b/build/download_deps.py new file mode 100755 index 00000000..846eccba --- /dev/null +++ b/build/download_deps.py @@ -0,0 +1,270 @@ +#!/usr/bin/env python3 +# Fluster - testing framework for decoders conformance +# Copyright (C) 2025, Fluendo, S.A. +# +# Helper script to download all ISO reference decoder dependencies +# Downloads: MPEG-2 AAC, MPEG-2 video, MPEG-4 AAC, and libtsp + +import os +import shutil +import ssl +import subprocess +import sys +import tarfile +import zipfile +from http.cookiejar import CookieJar +from pathlib import Path +from urllib.request import HTTPCookieProcessor, Request, build_opener, urlopen + + +def download_with_cookies(url, output_file, cookie_jar=None): + """Download a file with cookie support""" + if cookie_jar is None: + cookie_jar = CookieJar() + + opener = build_opener(HTTPCookieProcessor(cookie_jar)) + + print(f"Downloading {output_file.name}...") + request = Request(url, data=b"ok=I+accept" if "ok=" not in url else None, headers={"User-Agent": "Mozilla/5.0"}) + + with opener.open(request) as response: + with open(output_file, "wb") as f: + f.write(response.read()) + + return cookie_jar + + +def extract_zip(zip_file, dest_dir): + """Extract a zip file""" + print(f"Extracting {zip_file.name}...") + with zipfile.ZipFile(zip_file, "r") as zip_ref: + zip_ref.extractall(dest_dir) + + +def extract_tar_gz(tar_file, dest_dir): + """Extract a tar.gz file""" + print(f"Extracting {tar_file.name}...") + with tarfile.open(tar_file, "r:gz") as tar_ref: + tar_ref.extractall(dest_dir) # noqa: S202 + + +def apply_patch(patch_file, target_dir): + """Apply a patch file using patch command or git apply""" + print(f"Applying patch: {patch_file.name}") + + # Try patch command first + try: + subprocess.run(["patch", "-d", str(target_dir), "-p1", "-i", str(patch_file)], check=True, capture_output=True) + return True + except (subprocess.CalledProcessError, FileNotFoundError): + pass + + # Try git apply as fallback + try: + subprocess.run( + ["git", "apply", "--directory", str(target_dir), str(patch_file)], check=True, capture_output=True + ) + return True + except (subprocess.CalledProcessError, FileNotFoundError): + print(f"Warning: Could not apply patch {patch_file.name}") + return False + + +def check_patch_applied(file_path, marker): + """Check if a patch has already been applied""" + if not file_path.exists(): + return False + with open(file_path, "r", encoding="utf-8", errors="ignore") as f: + return marker in f.read() + + +def download_mpeg2(contrib_dir): + """Download MPEG-2 reference software (AAC and video)""" + print() + print("=== Downloading MPEG-2 reference software ===") + + cookie_jar = CookieJar() + mpeg2_url = ( + "https://standards.iso.org/ittf/PubliclyAvailableStandards/c039486_ISO_IEC_13818-5_2005_Reference_Software.zip" + ) + mpeg2_zip = contrib_dir / "c039486_ISO_IEC_13818-5_2005_Reference_Software.zip" + + # Get cookies first + opener = build_opener(HTTPCookieProcessor(cookie_jar)) + opener.open(mpeg2_url) + + # Download with cookies and form data + download_with_cookies(mpeg2_url, mpeg2_zip, cookie_jar) + + # Extract main archive + extract_zip(mpeg2_zip, contrib_dir) + mpeg2_zip.unlink() + + # Clean up unwanted files + for unwanted in ["iso_cookies.txt", "ipmp.zip", "mpeg2audio.zip", "systems.zip"]: + (contrib_dir / unwanted).unlink(missing_ok=True) + + # Extract MPEG-2 AAC + print("Extracting MPEG-2 AAC...") + mpeg2aac_zip = contrib_dir / "mpeg2aac.zip" + extract_zip(mpeg2aac_zip, contrib_dir) + mpeg2aac_zip.unlink() + + # Extract MPEG-2 video + print("Extracting MPEG-2 video...") + video_zip = contrib_dir / "video.zip" + extract_zip(video_zip, contrib_dir) + video_zip.unlink() + + +def download_mpeg4(contrib_dir): + """Download MPEG-4 reference software""" + print() + print("=== Downloading MPEG-4 reference software ===") + + cookie_jar = CookieJar() + mpeg4_url = "https://standards.iso.org/ittf/PubliclyAvailableStandards/c050470__ISO_IEC_14496-5_2001_Amd_20_2009_Reference_Software.zip" + mpeg4_zip = contrib_dir / "c050470__ISO_IEC_14496-5_2001_Amd_20_2009_Reference_Software.zip" + + # Get cookies first + opener = build_opener(HTTPCookieProcessor(cookie_jar)) + opener.open(mpeg4_url) + + # Download with cookies and form data + download_with_cookies(mpeg4_url, mpeg4_zip, cookie_jar) + + # Extract archive + extract_zip(mpeg4_zip, contrib_dir) + mpeg4_zip.unlink() + (contrib_dir / "iso_cookies.txt").unlink(missing_ok=True) + + # Create obj directory for MPEG-4 AAC build + obj_dir = contrib_dir / "C050470e_Electronic_inserts" / "audio" / "natural" / "obj" + obj_dir.mkdir(parents=True, exist_ok=True) + + +def download_libtsp(contrib_dir): + """Download libtsp audio library""" + print() + print("=== Downloading libtsp audio library ===") + + libtsp_url = "https://www-mmsp.ece.mcgill.ca/Documents/Downloads/libtsp/libtsp-v7r0.tar.gz" + libtsp_tar = contrib_dir / "libtsp-v7r0.tar.gz" + + # Create an SSL context that does not verify certificates using the public API + ssl_context = ssl.create_default_context() + ssl_context.check_hostname = False + ssl_context.verify_mode = ssl.CERT_NONE + + request = Request(libtsp_url, headers={"User-Agent": "Mozilla/5.0"}) + + with urlopen(request, context=ssl_context) as response: + with open(libtsp_tar, "wb") as f: + f.write(response.read()) + + # Extract archive + extract_tar_gz(libtsp_tar, contrib_dir) + libtsp_tar.unlink() + + # Set permissions (on Unix systems) + if os.name != "nt": + os.chmod(contrib_dir / "libtsp-v7r0", 0o755) + + +def main(): + # Get script directory and calculate paths + script_dir = Path(__file__).parent.resolve() + root_dir = script_dir.parent + + # Get contrib directory from argument or default + contrib_dir = Path(sys.argv[1]) if len(sys.argv) > 1 else root_dir / "contrib" + contrib_dir = contrib_dir.resolve() + + subprojects_dir = root_dir / "subprojects" + packagefiles_dir = subprojects_dir / "packagefiles" + + print("=== Fluster Dependencies Download Script ===") + print("This script will download ISO reference software for:") + print(" - MPEG-2 AAC decoder") + print(" - MPEG-2 video decoder") + print(" - MPEG-4 AAC decoders") + print(" - libtsp audio library") + print() + + # Create contrib directory + contrib_dir.mkdir(parents=True, exist_ok=True) + + # Download dependencies + download_mpeg2(contrib_dir) + download_mpeg4(contrib_dir) + download_libtsp(contrib_dir) + + # Copy meson.build files to contrib directories + print() + print("=== Setting up meson build files ===") + + print("Copying meson.build for MPEG-2 video") + shutil.copy2(packagefiles_dir / "mpeg2video" / "meson.build", contrib_dir / "video" / "meson.build") + + print("Copying meson.build for MPEG-2 AAC") + shutil.copy2(packagefiles_dir / "mpeg2aac" / "meson.build", contrib_dir / "mpeg2aac" / "meson.build") + + # Copy compat headers + print("Copying compat headers for MPEG-2 AAC") + compat_src = script_dir / "compat" / "macos" + compat_dst = contrib_dir / "mpeg2aac" / "compat" + shutil.copytree(compat_src, compat_dst) + + print("Copying meson.build for libtsp") + shutil.copy2(packagefiles_dir / "libtsp" / "meson.build", contrib_dir / "libtsp-v7r0" / "meson.build") + + # Create symlinks for meson subprojects + print() + print("=== Creating symlinks for meson subprojects ===") + + symlinks = [ + ("mpeg2video", "../contrib/video"), + ("mpeg2aac", "../contrib/mpeg2aac"), + ("libtsp-v7r0", "../contrib/libtsp-v7r0"), + ] + + for link_name, target in symlinks: + link_path = subprojects_dir / link_name + # Remove existing symlink if it's broken + if link_path.is_symlink() and not link_path.exists(): + print(f"Removing broken symlink: subprojects/{link_name}") + link_path.unlink() + + if not link_path.exists(): + print(f"Creating symlink: subprojects/{link_name} -> {target}") + # On Windows, try symlink first, fall back to junction + try: + link_path.symlink_to(target) + except (OSError, NotImplementedError): + if os.name == "nt": + # Use junction on Windows if symlink fails + subprocess.run( + ["mklink", "/J", str(link_path), str(link_path.parent / target)], shell=True, check=True + ) + else: + raise + + # Apply patches to MPEG-4 AAC + print() + print("=== Patching MPEG-4 AAC ===") + + mpeg4_dir = contrib_dir / "C050470e_Electronic_inserts" / "audio" / "natural" + patches_dir = script_dir / "patches" + + apply_patch(patches_dir / "mpeg4aac-windows-headers.patch", contrib_dir / "C050470e_Electronic_inserts") + apply_patch(patches_dir / "mpeg4aac-darwin.patch", mpeg4_dir) + apply_patch(patches_dir / "mpeg4aac-ar-fix.patch", mpeg4_dir) + apply_patch(patches_dir / "mpeg4aac-sed-fix.patch", mpeg4_dir) + + print() + print("=== All dependencies downloaded successfully! ===") + print("You can now run: meson setup builddir") + + +if __name__ == "__main__": + main() diff --git a/build/patches/mpeg4aac-ar-fix.patch b/build/patches/mpeg4aac-ar-fix.patch new file mode 100644 index 00000000..b565f712 --- /dev/null +++ b/build/patches/mpeg4aac-ar-fix.patch @@ -0,0 +1,22 @@ +--- a/general/makefile.rules 2025-12-11 13:45:37 ++++ b/general/makefile.rules 2025-12-11 13:46:41 +@@ -159,9 +159,10 @@ + # compose library + $(DIRTARGET) : $(PLTDIRTAG) + $(DIRTARGET) : $(DIROBJS) ++ @-mkdir -p $(dir $(DIRTARGET)) + @echo "***** composing library $@ ..." + @-rm -f $(DIRTARGET) +- $(VERBOSECHAR)ar r $(DIRTARGET) $^ ++ $(VERBOSECHAR)ar r $(DIRTARGET) $(DIROBJS) + # $(VERBOSECHAR)ar rv $(DIRTARGET) $(DIROBJS) + $(VERBOSECHAR)ranlib $(DIRTARGET) + else +@@ -170,6 +171,7 @@ + $(DIRTARGET)$(EXE_SUFFIX) : $(PLTDIRTAG) + $(DIRTARGET)$(EXE_SUFFIX) : $(DIROBJS) $(COMLIBS_file) $(MODULELIBS_file) $(FORCE_LINKING) + @echo "***** linking $@ ..." ++ @-mkdir -p $(dir $@) + $(VERBOSECHAR)$(LINK) $(LDFLAGS) $(DIROBJS) $(LIBPATH) $(LIBS) -o $@ + @echo "OLDLNK = " $(LNK) > $(DIRTARGET)$(LNK_SUFFIX) + diff --git a/build/patches/mpeg4aac-darwin.patch b/build/patches/mpeg4aac-darwin.patch new file mode 100644 index 00000000..5f009ce3 --- /dev/null +++ b/build/patches/mpeg4aac-darwin.patch @@ -0,0 +1,46 @@ +--- a/general/makefile.platform ++++ b/general/makefile.platform +@@ -101,8 +101,10 @@ else + TMP=$(TMPDIR)/$(shell pwd)/../ + endif + +-GETMODULEDIR = $(shell cd $(1) && cat CVS/Repository CVS/Tag 2> /dev/null | sed -e's@.*/@@;N;s@[[:cntrl:]]@ @g') +-GETTARGETDIR = $(call GETMODULEDIR,$(1))/$(SYSTEM_NAME)$(BUSWIDTH) $(2) $(MAKE_CC) O$(OPTIM_LEV)$(if $(subst 0,,$(DEBUG)),d)$(if $(subst 0,,$(GPROF)),p) ++# GETMODULEDIR returns empty when CVS/Repository doesn't exist (e.g., downloaded from ISO) ++# which causes incorrect paths with double slashes. Use $(or ...) to provide fallback 'default'. ++GETMODULEDIR = $(or $(shell cd $(1) && cat CVS/Repository CVS/Tag 2> /dev/null | sed -e's@.*/@@;N;s@[[:cntrl:]]@ @g'),default) ++GETTARGETDIR = $(call GETMODULEDIR,$(1))/$(SYSTEM_NAME)$(BUSWIDTH) $(2) $(MAKE_CC) O$(OPTIM_LEV)$(if $(subst 0,,$(DEBUG)),d)$(if $(subst 0,,$(GPROF)),p) + MODULEDIR := $(call GETMODULEDIR,.) + TARGETBINDIR:= $(call GETTARGETDIR,.,$(ADDONDIR) $(ADDONBINDIR)) + TARGETLIBDIR:= $(call GETTARGETDIR,.,$(ADDONDIR) $(ADDONLIBDIR)) +@@ -240,6 +242,11 @@ ifeq "$(SYSTEM_NAME)" "OS2" + EXE_SUFFIX = .exe + override CFLAGS += -ansi -pedantic -Wall + else ++ifeq "$(SYSTEM_NAME)" "Darwin" ++ DCC = gcc ++ CC = gcc ++ LINK = gcc ++else + SYSTEM_NAME = unknown + TARGETTMPDIR := ../tmp/ $(SYSTEM_NAME) $(ADDONDIR) + DCC = $(CC) +@@ -251,6 +258,7 @@ endif + endif + endif + endif ++endif + + EMPTY:= + CHARSPACE:=$(EMPTY) $(EMPTY) +@@ -368,4 +376,8 @@ endif + ifeq "$(SYSTEM_NAME)" "Linux" + PLTDIR = linux + RMDIR := rmdir -p ++endif ++ifeq "$(SYSTEM_NAME)" "Darwin" ++PLTDIR = darwin ++RMDIR := rmdir -p + endif + + endif # ifneq "$(MAKELEVEL)" "0" diff --git a/build/patches/mpeg4aac-sed-fix.patch b/build/patches/mpeg4aac-sed-fix.patch new file mode 100644 index 00000000..48f6e48b --- /dev/null +++ b/build/patches/mpeg4aac-sed-fix.patch @@ -0,0 +1,11 @@ +--- a/general/makefile.rules 2025-12-11 14:20:18 ++++ b/general/makefile.rules 2025-12-11 14:20:31 +@@ -120,7 +120,7 @@ + ##compile a COMLIBS library + $(COMLIBS_file): .FORCE + @$(EXTERNALLIBCMDLINE) $(@F) $(COMLIBS_$(@F)_OPTIONS) | tee $(DIRTARGET)_libcompile_$(@F).log; \ +- sed -e's@######## library okay: @@;ta;d;:a;s@/[^/]*$$@/@' $(DIRTARGET)_libcompile_$(@F).log > $(DIRTARGET).lib_$(@F).log; \ ++ sed -e 's@######## library okay: @@' -e 'ta' -e 'd' -e ':a' -e 's@/[^/]*$$@/@' $(DIRTARGET)_libcompile_$(@F).log > $(DIRTARGET).lib_$(@F).log; \ + rm -f $(DIRTARGET)_libcompile_$(@F).log + + $(CLOBBERLIBDEPS) $(CLEANLIBDEPS): .FORCE diff --git a/build/patches/mpeg4aac-windows-headers.patch b/build/patches/mpeg4aac-windows-headers.patch new file mode 100644 index 00000000..822a8ba0 --- /dev/null +++ b/build/patches/mpeg4aac-windows-headers.patch @@ -0,0 +1,19 @@ +--- a/audio/natural/mp4AudVm_Rewrite/src_frame/plotmtv_interf_dummy.c ++++ b/audio/natural/mp4AudVm_Rewrite/src_frame/plotmtv_interf_dummy.c +@@ -33,11 +33,11 @@ + #include + #include + #ifndef WIN32 + #include +-#endif +-#include /* variable artgument list */ +-#include +-#ifndef WIN32 + #include + #include + #endif ++#include /* variable artgument list */ ++#include + #include + #include + #include diff --git a/docker/Dockerfile b/docker/Dockerfile index 105052ab..d5dd922c 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -58,9 +58,9 @@ RUN apt-get update && apt-get install -y \ libva-dev \ libva-drm2 \ libva-x11-2 \ - vainfo \ - i965-va-driver \ + vainfo \ mesa-va-drivers \ + && (apt-get install -y i965-va-driver || true) \ && (apt-get install -y intel-media-va-driver-non-free || \ apt-get install -y intel-media-va-driver || true) \ && rm -rf /var/lib/apt/lists/* @@ -90,10 +90,9 @@ RUN if [ -n "${NVIDIA_DRIVER_VERSION}" ]; then \ rm -rf /var/lib/apt/lists/*; \ fi -# Intel QuickSync support via Media SDK and oneVPL -RUN apt-get update && apt-get install -y \ - libmfx1 \ - libmfx-tools \ +# Intel QuickSync support via Media SDK and oneVPL (x86_64 only) +RUN apt-get update \ + && (apt-get install -y libmfx1 libmfx-tools || true) \ && (apt-get install -y libmfx-gen1.2 || true) \ && (apt-get install -y libvpl-dev libvpl2 || true) \ && rm -rf /var/lib/apt/lists/* @@ -204,9 +203,29 @@ RUN if [ "${FFMPEG_INSTALL_METHOD}" = "source" ]; then \ libavformat-dev \ libavutil-dev \ libswscale-dev \ + libaom-dev \ + libaom3 \ && rm -rf /var/lib/apt/lists/*; \ fi +# Install AV1 reference decoder (libaom) +RUN apt-get update && apt-get install -y --no-install-recommends \ + git \ + cmake \ + build-essential \ + && mkdir /tmp/aom-tools \ + && cd /tmp/aom-tools \ + && git clone --depth 1 https://aomedia.googlesource.com/aom \ + && mkdir -p aom/build \ + && cd aom/build \ + && cmake -DCMAKE_INSTALL_PREFIX=/usr/local -DENABLE_TESTS=OFF -DENABLE_DOCS=OFF -DENABLE_EXAMPLES=ON .. \ + && make -j$(nproc) \ + && make install \ + && cd / && rm -rf /tmp/aom-tools \ + && apt-get remove -y git cmake build-essential \ + && apt-get autoremove -y \ + && rm -rf /var/lib/apt/lists/* + # GStreamer installation (2 methods: system, source) # Method "source": Build GStreamer from source (needed for new versions on old distros) # Note: gst-libav is disabled when building from source to avoid FFmpeg API incompatibilities diff --git a/meson.build b/meson.build new file mode 100644 index 00000000..e608096c --- /dev/null +++ b/meson.build @@ -0,0 +1,400 @@ +# Fluster - testing framework for decoders conformance +# Copyright (C) 2025, Fluendo, S.A. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License +# as published by the Free Software Foundation, either version 3 +# of the License, or (at your option) any later version. + +project('fluster', 'c', 'cpp', + version: '0.6.0', + license: 'LGPL-3.0-or-later', + meson_version: '>= 0.63.0', + default_options: [ + 'c_std=c99', + 'cpp_std=c++14', + ], +) + +python = import('python').find_installation('python3') +cmake = import('cmake') +fs = import('fs') +cc = meson.get_compiler('c') + +# Directories +contrib_dir = meson.current_source_dir() / 'contrib' +decoders_dir = meson.current_source_dir() / 'decoders' +check_dir = meson.current_source_dir() / 'check' +tests_dir = meson.current_source_dir() / 'tests' +build_dir = meson.current_source_dir() / 'build' + +# Platform detection +is_windows = host_machine.system() == 'windows' +is_linux = host_machine.system() == 'linux' +is_darwin = host_machine.system() == 'darwin' + +# Set macOS deployment target to avoid linker warnings +if is_darwin + add_project_arguments('-mmacosx-version-min=15.0', language: ['c', 'cpp']) + add_project_link_arguments('-mmacosx-version-min=15.0', language: ['c', 'cpp']) +endif + +# Check for required ISO reference software dependencies +# These must be downloaded first using build/download_deps.py +build_mpeg2_aac = get_option('mpeg2_aac_decoder') +build_mpeg4_aac = get_option('mpeg4_aac_decoder') +build_mpeg4_aac_er = get_option('mpeg4_aac_er_decoder') +build_mpeg2_video = get_option('mpeg2_video_decoder') + +missing_deps = [] + +# Check MPEG-2 dependencies (needed for MPEG-2 AAC and MPEG-2 video) +if build_mpeg2_aac or build_mpeg2_video + if not fs.is_dir(contrib_dir / 'mpeg2aac') + missing_deps += ['contrib/mpeg2aac (MPEG-2 AAC decoder)'] + endif + if not fs.is_dir(contrib_dir / 'video') + missing_deps += ['contrib/video (MPEG-2 video decoder)'] + endif +endif + +# Check MPEG-4 dependencies (needed for MPEG-4 AAC decoders) +if build_mpeg4_aac or build_mpeg4_aac_er + if not fs.is_dir(contrib_dir / 'C050470e_Electronic_inserts') + missing_deps += ['contrib/C050470e_Electronic_inserts (MPEG-4 AAC decoder)'] + endif +endif + +# Check libtsp dependency (needed for all AAC decoders) +if build_mpeg2_aac or build_mpeg4_aac or build_mpeg4_aac_er + if not fs.is_dir(contrib_dir / 'libtsp-v7r0') + missing_deps += ['contrib/libtsp-v7r0 (audio library)'] + endif +endif + +if missing_deps.length() > 0 + error_msg = '\n\nERROR: Required ISO reference software dependencies are missing:\n' + foreach dep : missing_deps + error_msg += ' - ' + dep + '\n' + endforeach + error_msg += '\nPlease run the download script first:\n' + error_msg += ' python3 build/download_deps.py\n' + error_msg += '\nThis will download all required ISO reference software.\n' + error(error_msg) +endif + +# Install Python dependencies +run_target('install-deps', + command: [python, '-m', 'pip', 'install', '-r', meson.current_source_dir() / 'requirements-dev.txt'], +) + +# Run Python unit tests +test('functional-tests', + python, + args: ['-m', 'unittest', 'discover', '-v', '-s', tests_dir, '-p', 'test_*.py'], + workdir: meson.current_source_dir(), + timeout: 300, +) + +# Build options for reference decoders (disabled by default) +build_h264_decoder = get_option('h264_decoder') +build_h265_decoder = get_option('h265_decoder') +build_h266_decoder = get_option('h266_decoder') +build_h266_vvdec = get_option('h266_vvdec') + +# Automatically enable isobmff if any AAC decoder is enabled +build_isobmff = build_mpeg2_aac or build_mpeg4_aac or build_mpeg4_aac_er + +# H.264 Reference Decoder (JM) +jm_ldecod_tgt = disabler() +if build_h264_decoder + jm_opts = cmake.subproject_options() + cmake_c_flags = '' + # GCC/Clang-specific warning flags (not supported by MSVC) + if cc.get_id() != 'msvc' + cmake_c_flags = '-Wno-stringop-truncation -Wno-stringop-overflow' + endif + if is_darwin + cmake_c_flags += ' -mmacosx-version-min=15.0' + endif + jm_opts.add_cmake_defines({ + 'CMAKE_BUILD_TYPE': 'Release', + 'CMAKE_C_FLAGS': cmake_c_flags, + }) + jm_subproject = cmake.subproject('jm', options: jm_opts, required: false) + if jm_subproject.found() + jm_ldecod_tgt = jm_subproject.target('ldecod') + else + warning('H.264 reference decoder (JM) subproject not found') + endif +endif + +# H.265 Reference Decoder (HM) +hm_decoder_tgt = disabler() +if build_h265_decoder + hm_subproject = subproject('hm', required: false) + if hm_subproject.found() + hm_decoder_tgt = hm_subproject.get_variable('TAppDecoder') + else + warning('H.265 reference decoder (HM) subproject not found') + endif +endif + +# H.266 Reference Decoder (VTM) +vtm_decoder_tgt = disabler() +if build_h266_decoder + # Use native meson subproject (meson.build provided in packagefiles/vvcsoftware_vtm/) + vtm_subproject = subproject('vvcsoftware_vtm', required: false) + if vtm_subproject.found() + vtm_decoder_tgt = vtm_subproject.get_variable('DecoderApp') + else + warning('H.266 reference decoder (VTM) subproject not found') + endif +endif + +# H.266 VVdeC Decoder +vvdec_decoder_tgt = disabler() +if build_h266_vvdec + # Use native meson subproject (meson.build provided in packagefiles/vvdec/) + vvdec_subproject = subproject('vvdec', required: false) + if vvdec_subproject.found() + vvdec_decoder_tgt = vvdec_subproject.get_variable('vvdecapp') + else + warning('H.266 VVdeC decoder subproject not found') + endif +endif + +# isobmff library (required for AAC decoders) +isobmff_lib = disabler() +if build_isobmff + isobmff_opts = cmake.subproject_options() + isobmff_cmake_defines = {'CMAKE_BUILD_TYPE': 'Release'} + if is_darwin + isobmff_cmake_defines += { + 'CMAKE_C_FLAGS': '-mmacosx-version-min=15.0', + 'CMAKE_CXX_FLAGS': '-mmacosx-version-min=15.0', + } + endif + isobmff_opts.add_cmake_defines(isobmff_cmake_defines) + isobmff_subproject = cmake.subproject('isobmff', options: isobmff_opts, required: false) + if isobmff_subproject.found() + isobmff_lib = isobmff_subproject.target('libisomediafile') + else + warning('isobmff subproject not found') + endif +endif + +# MPEG-2 Video Reference Decoder +mpeg2decode_tgt = disabler() +if build_mpeg2_video + # Check if the mpeg2video subproject directory exists (symlinked from contrib/video) + mpeg2video_dir = meson.current_source_dir() / 'subprojects' / 'mpeg2video' + if fs.is_dir(mpeg2video_dir) or fs.is_symlink(mpeg2video_dir) + mpeg2video_subproject = subproject('mpeg2video', required: false) + if mpeg2video_subproject.found() + mpeg2decode_tgt = mpeg2video_subproject.get_variable('mpeg2decode') + else + warning('MPEG-2 video decoder subproject configuration failed') + endif + else + error('MPEG-2 video decoder: subprojects/mpeg2video symlink not found. Run: python3 build/download_deps.py') + endif +endif + +# libtsp library (required for AAC decoders) +libtsp_lib = disabler() +libtsp_inc = '' +if build_mpeg2_aac or build_mpeg4_aac or build_mpeg4_aac_er + libtsp_subproject = subproject('libtsp', required: false) + if libtsp_subproject.found() + libtsp_lib = libtsp_subproject.get_variable('libtsp') + # Get the library output path for use in shell scripts + libtsp_lib_path = libtsp_lib.full_path() + # Get include directory + libtsp_inc = meson.current_source_dir() / 'subprojects' / 'libtsp-v7r0' / 'include' + else + warning('libtsp subproject not found') + endif +endif + +# MPEG-2 AAC Reference Decoder +aacdec_mc_tgt = disabler() +if build_mpeg2_aac + # Check if the mpeg2aac subproject directory exists (symlinked from contrib/mpeg2aac) + mpeg2aac_dir = meson.current_source_dir() / 'subprojects' / 'mpeg2aac' + if fs.is_dir(mpeg2aac_dir) or fs.is_symlink(mpeg2aac_dir) + mpeg2aac_subproject = subproject('mpeg2aac', required: false) + if mpeg2aac_subproject.found() + aacdec_mc_tgt = mpeg2aac_subproject.get_variable('aacdec_mc') + else + warning('MPEG-2 AAC decoder subproject configuration failed') + endif + else + error('MPEG-2 AAC decoder: subprojects/mpeg2aac symlink not found. Run: python3 build/download_deps.py') + endif +endif + +# Extract compiler flags from meson's C compiler configuration +# This ensures ISO decoders use the same architecture as the main build +c_args_list = get_option('c_args') +c_link_args_list = get_option('c_link_args') + +# Add macOS compat headers for ISO decoders +if host_machine.system() == 'darwin' + c_args_list += ['-I' + build_dir / 'compat' / 'macos'] +endif + +# Join the args into space-separated strings for the shell script +iso_cflags = ' '.join(c_args_list) +iso_ldflags = ' '.join(c_link_args_list) + +# Build list of MPEG-4 AAC decoders to build via shell script +# (MPEG-2 video and MPEG-2 AAC are now meson subprojects) +iso_decoders_list = [] +if build_mpeg4_aac + iso_decoders_list += ['mpeg4-aac'] +endif +if build_mpeg4_aac_er + iso_decoders_list += ['mpeg4-aac-er'] +endif + +iso_decoders_arg = ' '.join(iso_decoders_list) + +# ISO reference decoders build target (builds by default) +# Only build MPEG-4 AAC decoders via shell script (MPEG-2 AAC is now a meson subproject) +if iso_decoders_list.length() > 0 + # Add libtsp and isobmff libraries as dependencies if AAC decoders are enabled + iso_build_deps = [] + if build_mpeg2_aac or build_mpeg4_aac or build_mpeg4_aac_er + iso_build_deps += [libtsp_lib, isobmff_lib] + endif + + iso_decoders_target = custom_target('iso-reference-decoders', + output: 'iso-decoders.stamp', + input: iso_build_deps, + command: [ + python, + build_dir / 'build_iso_decoders.py', + meson.current_build_dir(), + iso_cflags, + iso_ldflags, + iso_decoders_arg, + '&&', + 'touch', + '@OUTPUT@', + ], + build_by_default: true, + console: true, + ) +endif + +# ============================================================================= +# Create symlinks for decoders in decoders/ directory to be usable by fluster +# ============================================================================= + +# Helper script to create symlink with absolute path +# Note: @INPUT@ is relative to build dir, so we construct absolute path +link_script = ''' +#!/bin/sh +builddir="$1" +src="$2" +dst="$3" +mkdir -p "$(dirname "$dst")" +rm -f "$dst" +ln -sf "$builddir/$src" "$dst" +''' + +# H.264 decoder symlink (ldecod) +if not is_disabler(jm_ldecod_tgt) + custom_target('link-ldecod', + output: 'ldecod.link', + input: jm_ldecod_tgt, + command: ['sh', '-c', link_script, '_', meson.current_build_dir(), '@INPUT@', decoders_dir / 'ldecod'], + build_by_default: true, + ) +endif + +# H.265 decoder symlink (TAppDecoder) +if not is_disabler(hm_decoder_tgt) + custom_target('link-TAppDecoder', + output: 'TAppDecoder.link', + input: hm_decoder_tgt, + command: ['sh', '-c', link_script, '_', meson.current_build_dir(), '@INPUT@', decoders_dir / 'TAppDecoder'], + build_by_default: true, + ) +endif + +# H.266 VTM decoder symlink (DecoderApp) +if not is_disabler(vtm_decoder_tgt) + custom_target('link-DecoderApp', + output: 'DecoderApp.link', + input: vtm_decoder_tgt, + command: ['sh', '-c', link_script, '_', meson.current_build_dir(), '@INPUT@', decoders_dir / 'DecoderApp'], + build_by_default: true, + ) +endif + +# H.266 VVdeC decoder symlink (vvdecapp) +if not is_disabler(vvdec_decoder_tgt) + custom_target('link-vvdecapp', + output: 'vvdecapp.link', + input: vvdec_decoder_tgt, + command: ['sh', '-c', link_script, '_', meson.current_build_dir(), '@INPUT@', decoders_dir / 'vvdecapp'], + build_by_default: true, + ) +endif + +# MPEG-2 video decoder symlink (mpeg2decode) +if not is_disabler(mpeg2decode_tgt) + custom_target('link-mpeg2decode', + output: 'mpeg2decode.link', + input: mpeg2decode_tgt, + command: ['sh', '-c', link_script, '_', meson.current_build_dir(), '@INPUT@', decoders_dir / 'mpeg2decode'], + build_by_default: true, + ) +endif + +# MPEG-2 AAC decoder symlink (aacdec_mc) +if not is_disabler(aacdec_mc_tgt) + custom_target('link-aacdec_mc', + output: 'aacdec_mc.link', + input: aacdec_mc_tgt, + command: ['sh', '-c', link_script, '_', meson.current_build_dir(), '@INPUT@', decoders_dir / 'aacdec_mc'], + build_by_default: true, + ) +endif + +run_target('clean-contrib', + command: ['rm', '-rf', contrib_dir], +) + +# Summary +summary({ + 'Python': python.full_path(), + 'C Compiler': cc.get_id(), + 'Platform': host_machine.system(), +}, section: 'Build Environment') + +summary({ + 'Check directory': check_dir, + 'Tests directory': tests_dir, + 'Contrib directory': contrib_dir, + 'Decoders directory': decoders_dir, +}, section: 'Directories') + +summary({ + 'H.264 decoder (JM)': build_h264_decoder, + 'H.265 decoder (HM)': build_h265_decoder, + 'H.266 decoder (VTM)': build_h266_decoder, + 'H.266 decoder (VVdeC)': build_h266_vvdec, + 'MPEG-2 video decoder': build_mpeg2_video, + 'MPEG-2 AAC decoder': build_mpeg2_aac, + 'isobmff library': build_isobmff, +}, section: 'Meson Subproject Decoders') + +summary({ + 'MPEG-4 AAC': build_mpeg4_aac, + 'MPEG-4 AAC-ER': build_mpeg4_aac_er, + 'CFLAGS': iso_cflags != '' ? iso_cflags : 'default', + 'LDFLAGS': iso_ldflags != '' ? iso_ldflags : 'default', +}, section: 'ISO Reference Decoders (MPEG-4 AAC only)') diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 00000000..8e14ace2 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,21 @@ +# Fluster build options + +# Reference decoder options (enabled by default) +option('h264_decoder', type: 'boolean', value: true, + description: 'Build H.264 reference decoder (JM)') +option('h265_decoder', type: 'boolean', value: true, + description: 'Build H.265 reference decoder (HM)') +option('h266_decoder', type: 'boolean', value: true, + description: 'Build H.266 reference decoder (VTM)') +option('mpeg2_video_decoder', type: 'boolean', value: true, + description: 'Build MPEG-2 video reference decoder') +option('mpeg2_aac_decoder', type: 'boolean', value: true, + description: 'Build MPEG-2 AAC reference decoder') +option('mpeg4_aac_decoder', type: 'boolean', value: true, + description: 'Build MPEG-4 AAC reference decoder') +option('mpeg4_aac_er_decoder', type: 'boolean', value: true, + description: 'Build MPEG-4 AAC Error Resilient reference decoder') + +# VVdeC decoder +option('h266_vvdec', type: 'boolean', value: true, + description: 'Build H.266 VVdeC decoder') \ No newline at end of file diff --git a/subprojects/hm.wrap b/subprojects/hm.wrap new file mode 100644 index 00000000..7d71abcb --- /dev/null +++ b/subprojects/hm.wrap @@ -0,0 +1,9 @@ +[wrap-git] +url = https://vcgit.hhi.fraunhofer.de/jct-vc/HM.git +revision = ae4c8d6d67572e929610a205eb574bd8dc00c043 +depth = 1 +clone-recursive = false +patch_directory = hm + +[provide] +program_names = TAppDecoder diff --git a/subprojects/isobmff.wrap b/subprojects/isobmff.wrap new file mode 100644 index 00000000..407684ad --- /dev/null +++ b/subprojects/isobmff.wrap @@ -0,0 +1,8 @@ +[wrap-git] +url = https://github.com/MPEGGroup/isobmff.git +revision = v0.2.0 +depth = 1 +clone-recursive = false + +[provide] +dependency_names = libisomediafile diff --git a/subprojects/jm.wrap b/subprojects/jm.wrap new file mode 100644 index 00000000..25c4fd8f --- /dev/null +++ b/subprojects/jm.wrap @@ -0,0 +1,9 @@ +[wrap-git] +url = https://vcgit.hhi.fraunhofer.de/jct-vc/JM.git +revision = 933098befc4b18f176e99db8f98c019c27ce9748 +depth = 1 +clone-recursive = false +diff_files = jm/0001-Fix-ARM64-build-disable-SSE-on-ARM-architectures.patch, jm/0002-Fix-MinGW-intptr_t-redefinition.patch, jm/0003-Fix-ws2_32-linking-for-MinGW.patch + +[provide] +program_names = ldecod diff --git a/subprojects/libtsp.wrap b/subprojects/libtsp.wrap new file mode 100644 index 00000000..dc0db210 --- /dev/null +++ b/subprojects/libtsp.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = libtsp-v7r0 +patch_directory = libtsp + +[provide] +libtsp = libtsp_dep diff --git a/subprojects/mpeg2aac.wrap b/subprojects/mpeg2aac.wrap new file mode 100644 index 00000000..162ff5ce --- /dev/null +++ b/subprojects/mpeg2aac.wrap @@ -0,0 +1,6 @@ +[wrap-file] +directory = mpeg2aac +patch_directory = mpeg2aac + +[provide] +mpeg2aac = mpeg2aac_dep diff --git a/subprojects/mpeg2video.wrap b/subprojects/mpeg2video.wrap new file mode 100644 index 00000000..6178b487 --- /dev/null +++ b/subprojects/mpeg2video.wrap @@ -0,0 +1,17 @@ +# MPEG-2 Video Reference Decoder (ISO/IEC 13818-5) +# +# This wrap file expects the MPEG-2 video sources to be available at +# subprojects/mpeg2video/ (symlinked or copied from contrib/video) +# +# To set up: +# 1. Run: ninja -C builddir download-mpeg2-deps +# 2. Create symlink: ln -sf ../contrib/video subprojects/mpeg2video +# +# Or let the build system handle it automatically via meson setup hooks. + +[wrap-file] +directory = mpeg2video +patch_directory = mpeg2video + +[provide] +program_names = mpeg2decode diff --git a/subprojects/packagefiles/hm/meson.build b/subprojects/packagefiles/hm/meson.build new file mode 100644 index 00000000..77388bd3 --- /dev/null +++ b/subprojects/packagefiles/hm/meson.build @@ -0,0 +1,130 @@ +# Native meson.build for HM (HEVC Test Model) H.265 reference decoder +# This replaces the auto-generated CMake conversion which has broken link_args + +project('HM', 'cpp', + version: '18.0', + default_options: ['cpp_std=gnu++11', 'warning_level=0'] +) + +# Common include directories +common_inc = include_directories( + 'source/Lib/TLibCommon', + 'source/Lib/TLibDecoder', + 'source/Lib/TLibEncoder', + 'source/Lib/Utilities', + 'source/Lib/libmd5', + 'source/Lib', + '.' +) + +# Common compiler args +# JVET_AK0194_DSC_SEI=0 disables OpenSSL dependency for digital signature verification +common_cpp_args = [ + '-DJVET_AK0194_DSC_SEI=0', + '-Wno-unknown-attributes', + '-Wno-deprecated-register', + '-Wno-pessimizing-move', + '-Wno-absolute-value', + '-Wno-unused-const-variable', +] + +# TLibCommon static library +TLibCommon_src = files( + 'source/Lib/TLibCommon/ContextModel.cpp', + 'source/Lib/TLibCommon/ContextModel3DBuffer.cpp', + 'source/Lib/TLibCommon/Debug.cpp', + 'source/Lib/TLibCommon/ProfileLevelTierFeatures.cpp', + 'source/Lib/TLibCommon/SEI.cpp', + 'source/Lib/TLibCommon/SEIDigitallySignedContent.cpp', + 'source/Lib/TLibCommon/SEIFilmGrainAnalyzer.cpp', + 'source/Lib/TLibCommon/SEIFilmGrainSynthesizer.cpp', + 'source/Lib/TLibCommon/TComBitStream.cpp', + 'source/Lib/TLibCommon/TComCABACTables.cpp', + 'source/Lib/TLibCommon/TComChromaFormat.cpp', + 'source/Lib/TLibCommon/TComDataCU.cpp', + 'source/Lib/TLibCommon/TComInterpolationFilter.cpp', + 'source/Lib/TLibCommon/TComLoopFilter.cpp', + 'source/Lib/TLibCommon/TComMotionInfo.cpp', + 'source/Lib/TLibCommon/TComPattern.cpp', + 'source/Lib/TLibCommon/TComPic.cpp', + 'source/Lib/TLibCommon/TComPicSym.cpp', + 'source/Lib/TLibCommon/TComPicYuv.cpp', + 'source/Lib/TLibCommon/TComPicYuvMD5.cpp', + 'source/Lib/TLibCommon/TComPrediction.cpp', + 'source/Lib/TLibCommon/TComRdCost.cpp', + 'source/Lib/TLibCommon/TComRdCostWeightPrediction.cpp', + 'source/Lib/TLibCommon/TComRom.cpp', + 'source/Lib/TLibCommon/TComSampleAdaptiveOffset.cpp', + 'source/Lib/TLibCommon/TComSlice.cpp', + 'source/Lib/TLibCommon/TComTU.cpp', + 'source/Lib/TLibCommon/TComTrQuant.cpp', + 'source/Lib/TLibCommon/TComWeightPrediction.cpp', + 'source/Lib/TLibCommon/TComYuv.cpp', + 'source/Lib/libmd5/libmd5.cpp', +) + +TLibCommon = static_library('TLibCommon', + TLibCommon_src, + include_directories: common_inc, + cpp_args: common_cpp_args, +) + +# TLibDecoder static library +TLibDecoder_src = files( + 'source/Lib/TLibDecoder/AnnexBread.cpp', + 'source/Lib/TLibDecoder/NALread.cpp', + 'source/Lib/TLibDecoder/SEIread.cpp', + 'source/Lib/TLibDecoder/SyntaxElementParser.cpp', + 'source/Lib/TLibDecoder/TDecBinCoderCABAC.cpp', + 'source/Lib/TLibDecoder/TDecCAVLC.cpp', + 'source/Lib/TLibDecoder/TDecConformance.cpp', + 'source/Lib/TLibDecoder/TDecCu.cpp', + 'source/Lib/TLibDecoder/TDecEntropy.cpp', + 'source/Lib/TLibDecoder/TDecGop.cpp', + 'source/Lib/TLibDecoder/TDecSbac.cpp', + 'source/Lib/TLibDecoder/TDecSlice.cpp', + 'source/Lib/TLibDecoder/TDecTop.cpp', +) + +TLibDecoder = static_library('TLibDecoder', + TLibDecoder_src, + include_directories: common_inc, + cpp_args: common_cpp_args, + link_with: TLibCommon, +) + +# Utilities static library +Utilities_src = files( + 'source/Lib/Utilities/TVideoIOYuv.cpp', + 'source/Lib/Utilities/program_options_lite.cpp', +) + +Utilities = static_library('Utilities', + Utilities_src, + include_directories: common_inc, + cpp_args: common_cpp_args, +) + +# TAppDecoder executable (H.265 decoder) +TAppDecoder_src = files( + 'source/App/TAppDecoder/TAppDecCfg.cpp', + 'source/App/TAppDecoder/TAppDecTop.cpp', + 'source/App/TAppDecoder/decmain.cpp', +) + +TAppDecoder_inc = include_directories( + 'source/App/TAppDecoder', + 'source/Lib/TLibCommon', + 'source/Lib/TLibDecoder', + 'source/Lib/Utilities', + 'source/Lib/libmd5', + 'source/Lib', + '.' +) + +TAppDecoder = executable('TAppDecoder', + TAppDecoder_src, + include_directories: TAppDecoder_inc, + cpp_args: common_cpp_args, + link_with: [TLibCommon, TLibDecoder, Utilities], +) diff --git a/subprojects/packagefiles/jm/0001-Fix-ARM64-build-disable-SSE-on-ARM-architectures.patch b/subprojects/packagefiles/jm/0001-Fix-ARM64-build-disable-SSE-on-ARM-architectures.patch new file mode 100644 index 00000000..8948c3d5 --- /dev/null +++ b/subprojects/packagefiles/jm/0001-Fix-ARM64-build-disable-SSE-on-ARM-architectures.patch @@ -0,0 +1,22 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Fluster +Date: Wed, 11 Dec 2025 00:00:00 +0000 +Subject: [PATCH] Fix ARM64 build: disable SSE on ARM architectures + +The -msse4.1 flag is only valid for x86/x86_64 architectures. +This patch conditionally applies it only on non-ARM systems. + +diff --git a/CMakeLists.txt b/CMakeLists.txt +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -96,8 +96,10 @@ bb_enable_warnings( msvc warnings-as-errors "/wd4996 /wd5105 /wd5103" ) + + # enable sse4.1 build for all source files for gcc and clang + if( UNIX OR MINGW ) +- add_compile_options( "-msse4.1" ) ++ if( NOT CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch64|ARM64" ) ++ add_compile_options( "-msse4.1" ) ++ endif() + endif() + + # enable parallel build for Visual Studio diff --git a/subprojects/packagefiles/jm/0002-Fix-MinGW-intptr_t-redefinition.patch b/subprojects/packagefiles/jm/0002-Fix-MinGW-intptr_t-redefinition.patch new file mode 100644 index 00000000..92ebbc7b --- /dev/null +++ b/subprojects/packagefiles/jm/0002-Fix-MinGW-intptr_t-redefinition.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Build System +Date: Mon, 16 Dec 2025 00:00:00 +0000 +Subject: [PATCH] Fix MinGW intptr_t redefinition error + +Fix intptr_t typedef conflict when building with MinGW on Windows. +The issue occurs because _MSC_VER is not defined with MinGW, causing +the condition (_MSC_VER < 1400) to evaluate to true, resulting in a +conflicting typedef with the one from MinGW headers. + +Only typedef intptr_t when actually using an old MSVC compiler. +--- + source/lib/lcommon/win32.h | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/source/lib/lcommon/win32.h b/source/lib/lcommon/win32.h +index 1234567..abcdefg 100644 +--- a/source/lib/lcommon/win32.h ++++ b/source/lib/lcommon/win32.h +@@ -30,9 +30,9 @@ + # include + # include + # include +-#if (_MSC_VER < 1400) ++#if defined(_MSC_VER) && (_MSC_VER < 1400) + typedef int intptr_t; +-#else ++#elif defined(_MSC_VER) + # include + #endif + #if defined(OPENMP) +-- +2.43.0 diff --git a/subprojects/packagefiles/jm/0003-Fix-ws2_32-linking-for-MinGW.patch b/subprojects/packagefiles/jm/0003-Fix-ws2_32-linking-for-MinGW.patch new file mode 100644 index 00000000..3babba30 --- /dev/null +++ b/subprojects/packagefiles/jm/0003-Fix-ws2_32-linking-for-MinGW.patch @@ -0,0 +1,27 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Build System +Date: Mon, 16 Dec 2025 00:00:00 +0000 +Subject: [PATCH] Fix ws2_32 linking for MinGW/UCRT64 on Windows + +Link ws2_32 library for all Windows builds, not just MSVC. +MinGW and UCRT64 also need this library for network functions +like ntohs and ntohl used in rtp.c. +--- + source/app/ldecod/CMakeLists.txt | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/source/app/ldecod/CMakeLists.txt b/source/app/ldecod/CMakeLists.txt +index 1234567..abcdefg 100644 +--- a/source/app/ldecod/CMakeLists.txt ++++ b/source/app/ldecod/CMakeLists.txt +@@ -47,7 +47,7 @@ if( CMAKE_COMPILER_IS_GNUCC AND BUILD_STATIC ) + target_compile_definitions( ${EXE_NAME} PUBLIC ENABLE_WPP_STATIC_LINK=1 ) + endif() + +-if(NOT MSVC) ++if(NOT WIN32) + target_link_libraries( ${EXE_NAME} m Threads::Threads ${ADDITIONAL_LIBS} ) + else() + target_link_libraries( ${EXE_NAME} WS2_32 Threads::Threads ${ADDITIONAL_LIBS} ) +-- +2.43.0 diff --git a/subprojects/packagefiles/libtsp/meson.build b/subprojects/packagefiles/libtsp/meson.build new file mode 100644 index 00000000..5fb36998 --- /dev/null +++ b/subprojects/packagefiles/libtsp/meson.build @@ -0,0 +1,366 @@ +project('libtsp', 'c', + version: '7.0', + default_options: [ + 'c_std=c99', + 'warning_level=0', + ], +) + +# Include directories +inc = include_directories('include') + +# Audio file I/O routines (AF module) +af_sources = files( + 'libtsp/AF/AFclose.c', + 'libtsp/AF/AFdReadData.c', + 'libtsp/AF/AFdWriteData.c', + 'libtsp/AF/AFfReadData.c', + 'libtsp/AF/AFfWriteData.c', + 'libtsp/AF/AFopenRead.c', + 'libtsp/AF/AFopenWrite.c', + 'libtsp/AF/AFopnRead.c', + 'libtsp/AF/AFopnWrite.c', + 'libtsp/AF/AFreadData.c', + 'libtsp/AF/AFsetFileType.c', + 'libtsp/AF/AFsetInfo.c', + 'libtsp/AF/AFsetNHpar.c', + 'libtsp/AF/AFsetSpeaker.c', + 'libtsp/AF/AFwriteData.c', + 'libtsp/AF/dataio/AFdRdAlaw.c', + 'libtsp/AF/dataio/AFdRdFx.c', + 'libtsp/AF/dataio/AFdRdIx.c', + 'libtsp/AF/dataio/AFdRdMulaw.c', + 'libtsp/AF/dataio/AFdRdTA.c', + 'libtsp/AF/dataio/AFdRdU1.c', + 'libtsp/AF/dataio/AFdWrAlaw.c', + 'libtsp/AF/dataio/AFdWrFx.c', + 'libtsp/AF/dataio/AFdWrIx.c', + 'libtsp/AF/dataio/AFdWrMulaw.c', + 'libtsp/AF/dataio/AFdWrTA.c', + 'libtsp/AF/dataio/AFdWrU1.c', + 'libtsp/AF/dataio/AFfRdAlaw.c', + 'libtsp/AF/dataio/AFfRdFx.c', + 'libtsp/AF/dataio/AFfRdIx.c', + 'libtsp/AF/dataio/AFfRdMulaw.c', + 'libtsp/AF/dataio/AFfRdTA.c', + 'libtsp/AF/dataio/AFfRdU1.c', + 'libtsp/AF/dataio/AFfWrAlaw.c', + 'libtsp/AF/dataio/AFfWrFx.c', + 'libtsp/AF/dataio/AFfWrIx.c', + 'libtsp/AF/dataio/AFfWrMulaw.c', + 'libtsp/AF/dataio/AFfWrTA.c', + 'libtsp/AF/dataio/AFfWrU1.c', + 'libtsp/AF/dataio/AFgetLine.c', + 'libtsp/AF/dataio/AFposition.c', + 'libtsp/AF/dataio/AFseek.c', + 'libtsp/AF/dataio/AFtell.c', + 'libtsp/AF/header/AFdecSpeaker.c', + 'libtsp/AF/header/AFfindType.c', + 'libtsp/AF/header/AFgetInfoRec.c', + 'libtsp/AF/header/AFoptions.c', + 'libtsp/AF/header/AFprAFpar.c', + 'libtsp/AF/header/AFpreSetWPar.c', + 'libtsp/AF/header/AFrdAIhead.c', + 'libtsp/AF/header/AFrdAUhead.c', + 'libtsp/AF/header/AFrdBLhead.c', + 'libtsp/AF/header/AFrdEShead.c', + 'libtsp/AF/header/AFrdINhead.c', + 'libtsp/AF/header/AFrdNShead.c', + 'libtsp/AF/header/AFrdSFhead.c', + 'libtsp/AF/header/AFrdSPhead.c', + 'libtsp/AF/header/AFrdSWhead.c', + 'libtsp/AF/header/AFrdTAhead.c', + 'libtsp/AF/header/AFrdTextAFsp.c', + 'libtsp/AF/header/AFrdWVhead.c', + 'libtsp/AF/header/AFreadHead.c', + 'libtsp/AF/header/AFsetNHread.c', + 'libtsp/AF/header/AFsetNHwrite.c', + 'libtsp/AF/header/AFsetRead.c', + 'libtsp/AF/header/AFsetWrite.c', + 'libtsp/AF/header/AFupdAIhead.c', + 'libtsp/AF/header/AFupdAUhead.c', + 'libtsp/AF/header/AFupdHead.c', + 'libtsp/AF/header/AFupdWVhead.c', + 'libtsp/AF/header/AFwrAIhead.c', + 'libtsp/AF/header/AFwrAUhead.c', + 'libtsp/AF/header/AFwriteHead.c', + 'libtsp/AF/header/AFwrWVhead.c', +) + +# Filter routines (FI module) +fi_sources = files( + 'libtsp/FI/FIdBiquad.c', + 'libtsp/FI/FIdConvol.c', + 'libtsp/FI/FIdConvSI.c', + 'libtsp/FI/FIdFiltAP.c', + 'libtsp/FI/FIdFiltIIR.c', + 'libtsp/FI/FIdKaiserLPF.c', + 'libtsp/FI/FIdReadFilt.c', + 'libtsp/FI/FIdWinHamm.c', + 'libtsp/FI/FIdWinKaiser.c', + 'libtsp/FI/FIfBiquad.c', + 'libtsp/FI/FIfConvol.c', + 'libtsp/FI/FIfConvSI.c', + 'libtsp/FI/FIfDeem.c', + 'libtsp/FI/FIfFiltAP.c', + 'libtsp/FI/FIfFiltIIR.c', + 'libtsp/FI/FIfKaiserLPF.c', + 'libtsp/FI/FIfPreem.c', + 'libtsp/FI/FIfReadFilt.c', + 'libtsp/FI/FIfWinHamm.c', + 'libtsp/FI/FIfWinHCos.c', + 'libtsp/FI/FIfWinKaiser.c', + 'libtsp/FI/FIfWinRCos.c', + 'libtsp/FI/FIgdelFIR.c', + 'libtsp/FI/FIgdelIIR.c', + 'libtsp/FI/nucleus/FIrCosF.c', + 'libtsp/FI/nucleus/FIxKaiser.c', +) + +# File list routines (FL module) +fl_sources = files( + 'libtsp/FL/FLbackup.c', + 'libtsp/FL/FLbaseName.c', + 'libtsp/FL/FLdate.c', + 'libtsp/FL/FLdefName.c', + 'libtsp/FL/FLdirName.c', + 'libtsp/FL/FLdReadData.c', + 'libtsp/FL/FLdWriteData.c', + 'libtsp/FL/FLexpHome.c', + 'libtsp/FL/FLextName.c', + 'libtsp/FL/FLfileDate.c', + 'libtsp/FL/FLfReadData.c', + 'libtsp/FL/FLfullName.c', + 'libtsp/FL/FLfWriteData.c', + 'libtsp/FL/FLgetLine.c', + 'libtsp/FL/FLgetRec.c', + 'libtsp/FL/FLhomeDir.c', + 'libtsp/FL/FLpathList.c', + 'libtsp/FL/FLpreName.c', + 'libtsp/FL/FLprompt.c', + 'libtsp/FL/FLreadLine.c', + 'libtsp/FL/nucleus/FLdReadTF.c', + 'libtsp/FL/nucleus/FLexist.c', + 'libtsp/FL/nucleus/FLfileSize.c', + 'libtsp/FL/nucleus/FLfReadTF.c', + 'libtsp/FL/nucleus/FLjoinNames.c', + 'libtsp/FL/nucleus/FLseekable.c', + 'libtsp/FL/nucleus/FLterm.c', +) + +# Function routines (FN module) +fn_sources = files( + 'libtsp/FN/FNbessI0.c', + 'libtsp/FN/FNevChebP.c', + 'libtsp/FN/FNgcd.c', + 'libtsp/FN/FNiLog2.c', + 'libtsp/FN/FNsinc.c', +) + +# Matrix algebra routines (MA module) +ma_sources = files( + 'libtsp/MA/MAdAllocMat.c', + 'libtsp/MA/MAdFreeMat.c', + 'libtsp/MA/MAdPrint.c', + 'libtsp/MA/MAfAllocMat.c', + 'libtsp/MA/MAfChSolve.c', + 'libtsp/MA/MAfFreeMat.c', + 'libtsp/MA/MAfPrint.c', + 'libtsp/MA/MAfSubMat.c', + 'libtsp/MA/MAfSyBilin.c', + 'libtsp/MA/MAfSyQuad.c', + 'libtsp/MA/MAfTpQuad.c', + 'libtsp/MA/MAfTpSolve.c', + 'libtsp/MA/MAiPrint.c', + 'libtsp/MA/MAlPrint.c', + 'libtsp/MA/nucleus/MAfChFactor.c', + 'libtsp/MA/nucleus/MAfLTSolve.c', + 'libtsp/MA/nucleus/MAfTTSolve.c', +) + +# Math support routines (MS module) +ms_sources = files( + 'libtsp/MS/MSdConvCof.c', + 'libtsp/MS/MSdDeconvCof.c', + 'libtsp/MS/MSdIntLin.c', + 'libtsp/MS/MSdIntMC.c', + 'libtsp/MS/MSdLocate.c', + 'libtsp/MS/MSdNint.c', + 'libtsp/MS/MSdPolyInt.c', + 'libtsp/MS/MSfConvCof.c', + 'libtsp/MS/MSfGaussRand.c', + 'libtsp/MS/MSfIntLin.c', + 'libtsp/MS/MSfIntMC.c', + 'libtsp/MS/MSfUnifRand.c', + 'libtsp/MS/MSiCeil.c', + 'libtsp/MS/MSiFloor.c', + 'libtsp/MS/MSiPower.c', + 'libtsp/MS/MSlCeil.c', + 'libtsp/MS/MSlFloor.c', + 'libtsp/MS/MSratio.c', + 'libtsp/MS/nucleus/MScoefMC.c', + 'libtsp/MS/nucleus/MSdSlopeMC.c', + 'libtsp/MS/nucleus/MSevalMC.c', + 'libtsp/MS/nucleus/MSfSlopeMC.c', +) + +# Signal processing routines (SP module) +sp_sources = files( + 'libtsp/SP/nucleus/SPdPreFFT.c', + 'libtsp/SP/nucleus/SPdTrMat2.c', + 'libtsp/SP/nucleus/SPfPreFFT.c', + 'libtsp/SP/nucleus/SPfTrMat2.c', + 'libtsp/SP/SPautoc.c', + 'libtsp/SP/SPcepXpc.c', + 'libtsp/SP/SPcorBWexp.c', + 'libtsp/SP/SPcorFilt.c', + 'libtsp/SP/SPcorFmse.c', + 'libtsp/SP/SPcorPmse.c', + 'libtsp/SP/SPcorXpc.c', + 'libtsp/SP/SPcovar.c', + 'libtsp/SP/SPcovCXpc.c', + 'libtsp/SP/SPcovFilt.c', + 'libtsp/SP/SPcovFmse.c', + 'libtsp/SP/SPcovLXpc.c', + 'libtsp/SP/SPcovMXpc.c', + 'libtsp/SP/SPcovPmse.c', + 'libtsp/SP/SPcovXpc.c', + 'libtsp/SP/SPdCFFT.c', + 'libtsp/SP/SPdQuantL.c', + 'libtsp/SP/SPdRFFT.c', + 'libtsp/SP/SPecXpc.c', + 'libtsp/SP/SPfCFFT.c', + 'libtsp/SP/SPfDCT.c', + 'libtsp/SP/SPfQuantL.c', + 'libtsp/SP/SPfQuantU.c', + 'libtsp/SP/SPfRFFT.c', + 'libtsp/SP/SPlpcISdist.c', + 'libtsp/SP/SPlpcLSdist.c', + 'libtsp/SP/SPlsfXpc.c', + 'libtsp/SP/SPpcBWexp.c', + 'libtsp/SP/SPpcXcep.c', + 'libtsp/SP/SPpcXcor.c', + 'libtsp/SP/SPpcXec.c', + 'libtsp/SP/SPpcXlsf.c', + 'libtsp/SP/SPpcXrc.c', + 'libtsp/SP/SPrcXpc.c', +) + +# String routines (ST module) +st_sources = files( + 'libtsp/ST/nucleus/STdec1val.c', + 'libtsp/ST/nucleus/STdecNval.c', + 'libtsp/ST/nucleus/STdecPair.c', + 'libtsp/ST/nucleus/STstrDots.c', + 'libtsp/ST/nucleus/STstrstrNM.c', + 'libtsp/ST/nucleus/STtrimIws.c', + 'libtsp/ST/nucleus/STtrimNMax.c', + 'libtsp/ST/STcatMax.c', + 'libtsp/ST/STcopyMax.c', + 'libtsp/ST/STcopyNMax.c', + 'libtsp/ST/STdec1double.c', + 'libtsp/ST/STdec1float.c', + 'libtsp/ST/STdec1int.c', + 'libtsp/ST/STdec1long.c', + 'libtsp/ST/STdecDfrac.c', + 'libtsp/ST/STdecIfrac.c', + 'libtsp/ST/STdecIrange.c', + 'libtsp/ST/STdecLrange.c', + 'libtsp/ST/STdecNdouble.c', + 'libtsp/ST/STdecNfloat.c', + 'libtsp/ST/STdecNint.c', + 'libtsp/ST/STdecNlong.c', + 'libtsp/ST/STfindToken.c', + 'libtsp/ST/STkeyMatch.c', + 'libtsp/ST/STkeyXpar.c', + 'libtsp/ST/STstrLC.c', + 'libtsp/ST/STtrim.c', + 'libtsp/ST/STunQuote.c', +) + +# Utility routines (UT module) +ut_sources = files( + 'libtsp/UT/nucleus/UTbyteCode.c', + 'libtsp/UT/nucleus/UTbyteOrder.c', + 'libtsp/UT/nucleus/UTcheckIEEE.c', + 'libtsp/UT/nucleus/UTctime.c', + 'libtsp/UT/nucleus/UTdecOption.c', + 'libtsp/UT/nucleus/UTdIEEE80.c', + 'libtsp/UT/nucleus/UTeIEEE80.c', + 'libtsp/UT/nucleus/UTgetHost.c', + 'libtsp/UT/nucleus/UTgetUser.c', + 'libtsp/UT/nucleus/UTswapCode.c', + 'libtsp/UT/UTdate.c', + 'libtsp/UT/UTerror.c', + 'libtsp/UT/UTfree.c', + 'libtsp/UT/UTgetOption.c', + 'libtsp/UT/UThalt.c', + 'libtsp/UT/UTmalloc.c', + 'libtsp/UT/UTrealloc.c', + 'libtsp/UT/UTsetProg.c', + 'libtsp/UT/UTsysMsg.c', + 'libtsp/UT/UTuserName.c', + 'libtsp/UT/UTwarn.c', +) + +# Vector routines (VR module) +vr_sources = files( + 'libtsp/VR/nucleus/VRswapBytes.c', + 'libtsp/VR/VRdAdd.c', + 'libtsp/VR/VRdCopy.c', + 'libtsp/VR/VRdCorSym.c', + 'libtsp/VR/VRdDotProd.c', + 'libtsp/VR/VRdLinInc.c', + 'libtsp/VR/VRdMult.c', + 'libtsp/VR/VRdPrint.c', + 'libtsp/VR/VRdRFFTMSq.c', + 'libtsp/VR/VRdScale.c', + 'libtsp/VR/VRdSet.c', + 'libtsp/VR/VRdShift.c', + 'libtsp/VR/VRdSymPart.c', + 'libtsp/VR/VRdZero.c', + 'libtsp/VR/VRfAdd.c', + 'libtsp/VR/VRfAmpldB.c', + 'libtsp/VR/VRfCopy.c', + 'libtsp/VR/VRfCorSym.c', + 'libtsp/VR/VRfDiff.c', + 'libtsp/VR/VRfDiffSq.c', + 'libtsp/VR/VRfDotProd.c', + 'libtsp/VR/VRfLog10.c', + 'libtsp/VR/VRfMax.c', + 'libtsp/VR/VRfMin.c', + 'libtsp/VR/VRfMult.c', + 'libtsp/VR/VRfPow10.c', + 'libtsp/VR/VRfPrint.c', + 'libtsp/VR/VRfRev.c', + 'libtsp/VR/VRfScale.c', + 'libtsp/VR/VRfSet.c', + 'libtsp/VR/VRfShift.c', + 'libtsp/VR/VRfSum.c', + 'libtsp/VR/VRfZero.c', + 'libtsp/VR/VRiPrint.c', + 'libtsp/VR/VRiZero.c', + 'libtsp/VR/VRlPrint.c', +) + +# Combine all sources +libtsp_sources = af_sources + fi_sources + fl_sources + fn_sources + ma_sources + ms_sources + sp_sources + st_sources + ut_sources + vr_sources + +# Find math library +m_dep = meson.get_compiler('c').find_library('m', required: false) + +# Build static library +libtsp = static_library('tsp', + libtsp_sources, + include_directories: inc, + dependencies: m_dep, + install: false, +) + +# Declare dependency +libtsp_dep = declare_dependency( + link_with: libtsp, + include_directories: inc, +) + +meson.override_dependency('libtsp', libtsp_dep) diff --git a/subprojects/packagefiles/mpeg2aac/meson.build b/subprojects/packagefiles/mpeg2aac/meson.build new file mode 100644 index 00000000..8f691926 --- /dev/null +++ b/subprojects/packagefiles/mpeg2aac/meson.build @@ -0,0 +1,122 @@ +# Native meson.build for MPEG-2 AAC Decoder (aacdec_mc) +# ISO/IEC 13818-7 Reference Software +# This replaces the original Makefile to integrate with the meson build system + +project('mpeg2aac', 'c', + version: '2.0', + default_options: [ + 'c_std=c99', + 'default_library=static', + 'buildtype=release', + 'warning_level=0', + ] +) + +cc = meson.get_compiler('c') +fs = import('fs') + +# Get libtsp dependency (required for audio output) +libtsp_dep = dependency('libtsp', required: true) + +# Common AAC decoder source files +mpeg2aac_common_sources = [ + 'aacDec/src/bitinput.c', + 'aacDec/src/config.c', + 'aacDec/src/coupling.c', + 'aacDec/src/diagnose.c', + 'aacDec/src/drc.c', + 'aacDec/src/huffdec1.c', + 'aacDec/src/huffdec2.c', + 'aacDec/src/huffdec3.c', + 'aacDec/src/huffinit.c', + 'aacDec/src/hufftables.c', + 'aacDec/src/intensity.c', + 'aacDec/src/intrins.c', + 'aacDec/src/monopred.c', + 'aacDec/src/stereo.c', + 'aacDec/src/tns.c', + # DOLBY imdct + 'aacDec/src/adifdec.c', + 'aacDec/src/block.c', + 'aacDec/src/dolby_adapt.c', + 'aacDec/src/transfo.c', + # SONY gain control + 'aacDec/src/gc_unpac.c', + 'aacDec/src/gc_compensate.c', + 'aacDec/src/gc_common.c', + 'aacDec/src/gc_pqf_common.c', + 'aacDec/src/gc_ipqf.c', + 'aacDec/src/gc.c', + 'aacDec/src/gc_mdct_common.c', + 'aacDec/src/gc_imdct.c', + # Coding Technologies SBR (Spectral Band Replication) + 'aacDec/src/ct_envcalc.c', + 'aacDec/src/ct_envdec.c', + 'aacDec/src/ct_envextr.c', + 'aacDec/src/ct_freqsca.c', + 'aacDec/src/ct_hfgen.c', + 'aacDec/src/ct_sbrbitb.c', + 'aacDec/src/ct_sbrcrc.c', + 'aacDec/src/ct_sbrdec.c', + 'aacDec/src/ct_sbrdecoder.c', + 'aacDec/src/ct_polyphase.c', + # Parametric Stereo + 'aacDec/src/ct_psdec.c', +] + +# Decoder main sources +mpeg2aac_decoder_sources = [ + 'aacDec/src/decoder.c', + 'aacDec/src/audioout.c', + 'aacDec/src/aiff_support.c', +] + +# Compiler definitions +mpeg2aac_c_args = [ + '-DNEW_ADTS', + '-DWRITE_NEW_ADTS', + '-DDRC', + '-DBIGDECODER', # Support up to 48 channels + '-DCT_SBR', # Enable SBR + '-DPARAMETRICSTEREO', # Enable Parametric Stereo +] + +# Platform-specific compatibility +if host_machine.system() == 'darwin' + # macOS needs compat headers for malloc.h + # Use local compat directory within the subproject + compat_include = include_directories('compat') +else + compat_include = [] +endif + +# Include directories +mpeg2aac_inc = include_directories('aacDec/src') + +# Build the AAC library +libisoaac = static_library('isoaac', + mpeg2aac_common_sources, + c_args: mpeg2aac_c_args, + include_directories: [mpeg2aac_inc, compat_include], + dependencies: [libtsp_dep], + install: false, +) + +# Build the decoder executable +aacdec_mc = executable('aacdec_mc', + mpeg2aac_decoder_sources, + c_args: mpeg2aac_c_args, + include_directories: [mpeg2aac_inc, compat_include], + link_with: [libisoaac], + dependencies: [libtsp_dep], + install: false, +) + +# Declare dependency for other subprojects +mpeg2aac_dep = declare_dependency( + link_with: [libisoaac], + include_directories: [mpeg2aac_inc], +) + +# Override the dependency so other subprojects can use it +meson.override_dependency('mpeg2aac', mpeg2aac_dep) diff --git a/subprojects/packagefiles/mpeg2video/meson.build b/subprojects/packagefiles/mpeg2video/meson.build new file mode 100644 index 00000000..cba25572 --- /dev/null +++ b/subprojects/packagefiles/mpeg2video/meson.build @@ -0,0 +1,67 @@ +# Native meson.build for MPEG-2 Video Decoder (mpeg2decode) +# ISO/IEC 13818-5 Reference Software +# This replaces the original Makefile to integrate with the meson build system +# +# This file should be copied to contrib/video/ before running meson + +project('mpeg2video', 'c', + version: '1.2', + default_options: [ + 'c_std=c99', + 'default_library=static', + 'buildtype=release', + 'warning_level=0', + ] +) + +cc = meson.get_compiler('c') + +# Source files for mpeg2decode +mpeg2decode_sources = [ + 'decoder/mpeg2dec.c', + 'decoder/getpic.c', + 'decoder/motion.c', + 'decoder/getvlc.c', + 'decoder/gethdr.c', + 'decoder/getblk.c', + 'decoder/getbits.c', + 'decoder/store.c', + 'decoder/recon.c', + 'decoder/spatscal.c', + 'decoder/idct.c', + 'decoder/idctref.c', + 'decoder/display.c', + 'decoder/systems.c', + 'decoder/subspic.c', + 'decoder/verify.c', +] + +# Compiler arguments +mpeg2_c_args = [ + '-DTRACE', + '-DVERBOSE', + '-DVERIFY', + # Disable X11 display - not needed for conformance testing + # '-DDISPLAY', +] + +# Suppress warnings for legacy code +if cc.get_id() == 'gcc' or cc.get_id() == 'clang' + mpeg2_c_args += [ + '-Wno-implicit-function-declaration', + '-Wno-implicit-int', + '-Wno-int-conversion', + '-Wno-incompatible-pointer-types', + ] +endif + +# Math library +m_dep = cc.find_library('m', required: false) + +# Build mpeg2decode executable +mpeg2decode = executable('mpeg2decode', + mpeg2decode_sources, + c_args: mpeg2_c_args, + dependencies: [m_dep], + install: false, +) diff --git a/subprojects/packagefiles/vvcsoftware_vtm/meson.build b/subprojects/packagefiles/vvcsoftware_vtm/meson.build new file mode 100644 index 00000000..d162d521 --- /dev/null +++ b/subprojects/packagefiles/vvcsoftware_vtm/meson.build @@ -0,0 +1,240 @@ +# Native meson.build for VTM (VVC Test Model) +# This replaces the CMake build system to fix linking issues +project('VTM', 'cpp', + version: '23.4', + default_options: [ + 'cpp_std=c++17', + 'default_library=static', + 'buildtype=release' + ] +) + +cpp = meson.get_compiler('cpp') + +# Common compiler arguments +# JVET_AJ0151_DSC_SEI=0 disables OpenSSL dependency for digital signature verification +vtm_cpp_args = ['-DNDEBUG', '-DJVET_AJ0151_DSC_SEI=0'] + +if cpp.get_id() == 'gcc' or cpp.get_id() == 'clang' + vtm_cpp_args += ['-Wall', '-Wno-sign-compare', '-Wno-unused-variable'] +endif + +# Check if we're on x86 architecture for SIMD support +host_cpu = host_machine.cpu_family() +is_x86 = host_cpu == 'x86' or host_cpu == 'x86_64' + +# CommonLib sources (discovered from source tree) +commonlib_base_sources = [ + 'source/Lib/CommonLib/AdaptiveLoopFilter.cpp', + 'source/Lib/CommonLib/AffineGradientSearch.cpp', + 'source/Lib/CommonLib/BitStream.cpp', + 'source/Lib/CommonLib/Buffer.cpp', + 'source/Lib/CommonLib/CacheModel.cpp', + 'source/Lib/CommonLib/ChromaFormat.cpp', + 'source/Lib/CommonLib/CodingStructure.cpp', + 'source/Lib/CommonLib/ConstraintInfo.cpp', + 'source/Lib/CommonLib/ContextModelling.cpp', + 'source/Lib/CommonLib/Contexts.cpp', + 'source/Lib/CommonLib/DeblockingFilter.cpp', + 'source/Lib/CommonLib/DepQuant.cpp', + 'source/Lib/CommonLib/dtrace.cpp', + 'source/Lib/CommonLib/dtrace_blockstatistics.cpp', + 'source/Lib/CommonLib/Hash.cpp', + 'source/Lib/CommonLib/HRD.cpp', + 'source/Lib/CommonLib/IbcHashMap.cpp', + 'source/Lib/CommonLib/InterpolationFilter.cpp', + 'source/Lib/CommonLib/InterPrediction.cpp', + 'source/Lib/CommonLib/IntraPrediction.cpp', + 'source/Lib/CommonLib/MatrixIntraPrediction.cpp', + 'source/Lib/CommonLib/MCTS.cpp', + 'source/Lib/CommonLib/Mv.cpp', + 'source/Lib/CommonLib/ParameterSetManager.cpp', + 'source/Lib/CommonLib/Picture.cpp', + 'source/Lib/CommonLib/PictureParameterSet.cpp', + 'source/Lib/CommonLib/PicYuvMD5.cpp', + 'source/Lib/CommonLib/ProfileTierLevel.cpp', + 'source/Lib/CommonLib/Quant.cpp', + 'source/Lib/CommonLib/QuantRDOQ.cpp', + 'source/Lib/CommonLib/RdCost.cpp', + 'source/Lib/CommonLib/RdCostWeightPrediction.cpp', + 'source/Lib/CommonLib/Reshape.cpp', + 'source/Lib/CommonLib/Rom.cpp', + 'source/Lib/CommonLib/RomLFNST.cpp', + 'source/Lib/CommonLib/RomTr.cpp', + 'source/Lib/CommonLib/SampleAdaptiveOffset.cpp', + 'source/Lib/CommonLib/SEI.cpp', + 'source/Lib/CommonLib/SEIColourTransform.cpp', + 'source/Lib/CommonLib/SEIDigitallySignedContent.cpp', + 'source/Lib/CommonLib/SEIFilmGrainSynthesizer.cpp', + 'source/Lib/CommonLib/SEINeuralNetworkPostFiltering.cpp', + 'source/Lib/CommonLib/SEIPackedRegionsInfoProcess.cpp', + 'source/Lib/CommonLib/SequenceParameterSet.cpp', + 'source/Lib/CommonLib/Slice.cpp', + 'source/Lib/CommonLib/TrQuant.cpp', + 'source/Lib/CommonLib/TrQuant_EMT.cpp', + 'source/Lib/CommonLib/Unit.cpp', + 'source/Lib/CommonLib/UnitPartitioner.cpp', + 'source/Lib/CommonLib/UnitTools.cpp', + 'source/Lib/CommonLib/VideoParameterSet.cpp', + 'source/Lib/CommonLib/WeightPrediction.cpp', +] + +# x86 base sources (always included on x86) +commonlib_x86_base_sources = [ + 'source/Lib/CommonLib/x86/CommonDefX86.cpp', + 'source/Lib/CommonLib/x86/InitX86.cpp', +] + +# libmd5 sources +libmd5_sources = [ + 'source/Lib/libmd5/libmd5.cpp', +] + +# DecoderLib sources +decoderlib_sources = [ + 'source/Lib/DecoderLib/AnnexBread.cpp', + 'source/Lib/DecoderLib/BinDecoder.cpp', + 'source/Lib/DecoderLib/CABACReader.cpp', + 'source/Lib/DecoderLib/DecCu.cpp', + 'source/Lib/DecoderLib/DecLib.cpp', + 'source/Lib/DecoderLib/DecSlice.cpp', + 'source/Lib/DecoderLib/NALread.cpp', + 'source/Lib/DecoderLib/SEIread.cpp', + 'source/Lib/DecoderLib/VLCReader.cpp', +] + +# Utilities sources +utilities_sources = [ + 'source/Lib/Utilities/program_options_lite.cpp', + 'source/Lib/Utilities/VideoIOYuv.cpp', +] + +# DecoderApp sources +decoderapp_sources = [ + 'source/App/DecoderApp/DecApp.cpp', + 'source/App/DecoderApp/DecAppCfg.cpp', + 'source/App/DecoderApp/decmain.cpp', +] + +# Include directories +vtm_includes = include_directories( + 'source/Lib', + 'source/Lib/CommonLib', + 'source/Lib/CommonLib/x86', + 'source/Lib/DecoderLib', + 'source/Lib/Utilities', + 'source/Lib/libmd5', +) + +# x86 SIMD sources (only on x86 architectures) +# Each SIMD level needs specific compiler flags and defines +if is_x86 + # SSE4.1 sources + commonlib_sse41_sources = [ + 'source/Lib/CommonLib/x86/sse41/AdaptiveLoopFilter_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/AffineGradientSearch_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/Buffer_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/InterpolationFilter_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/RdCost_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/TrQuantX86_sse41.cpp', + ] + + # SSE4.2 sources + commonlib_sse42_sources = [ + 'source/Lib/CommonLib/x86/sse42/IbcHashmap_sse42.cpp', + ] + + # AVX sources + commonlib_avx_sources = [ + 'source/Lib/CommonLib/x86/avx/AdaptiveLoopFilter_avx.cpp', + 'source/Lib/CommonLib/x86/avx/AffineGradientSearch_avx.cpp', + 'source/Lib/CommonLib/x86/avx/Buffer_avx.cpp', + 'source/Lib/CommonLib/x86/avx/InterpolationFilter_avx.cpp', + 'source/Lib/CommonLib/x86/avx/RdCost_avx.cpp', + 'source/Lib/CommonLib/x86/avx/TrQuantX86_avx.cpp', + ] + + # AVX2 sources + commonlib_avx2_sources = [ + 'source/Lib/CommonLib/x86/avx2/AdaptiveLoopFilter_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/AffineGradientSearch_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/Buffer_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/InterpolationFilter_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/RdCost_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/TrQuantX86_avx2.cpp', + ] + + # Compiler-specific SIMD flags + if cpp.get_id() == 'msvc' + sse41_args = vtm_cpp_args + ['-DUSE_SSE41'] + sse42_args = vtm_cpp_args + ['-DUSE_SSE42'] + avx_args = vtm_cpp_args + ['-DUSE_AVX', '/arch:AVX'] + avx2_args = vtm_cpp_args + ['-DUSE_AVX2', '/arch:AVX2'] + else + sse41_args = vtm_cpp_args + ['-DUSE_SSE41', '-msse4.1'] + sse42_args = vtm_cpp_args + ['-DUSE_SSE42', '-msse4.2'] + avx_args = vtm_cpp_args + ['-DUSE_AVX', '-mavx'] + avx2_args = vtm_cpp_args + ['-DUSE_AVX2', '-mavx2'] + endif + + # Build SIMD object libraries + CommonLib_sse41 = static_library('CommonLib_sse41', + commonlib_sse41_sources, + include_directories: vtm_includes, + cpp_args: sse41_args, + ) + + CommonLib_sse42 = static_library('CommonLib_sse42', + commonlib_sse42_sources, + include_directories: vtm_includes, + cpp_args: sse42_args, + ) + + CommonLib_avx = static_library('CommonLib_avx', + commonlib_avx_sources, + include_directories: vtm_includes, + cpp_args: avx_args, + ) + + CommonLib_avx2 = static_library('CommonLib_avx2', + commonlib_avx2_sources, + include_directories: vtm_includes, + cpp_args: avx2_args, + ) + + commonlib_sources = commonlib_base_sources + commonlib_x86_base_sources + libmd5_sources + simd_libs = [CommonLib_sse41, CommonLib_sse42, CommonLib_avx, CommonLib_avx2] +else + commonlib_sources = commonlib_base_sources + libmd5_sources + simd_libs = [] +endif + +# Build CommonLib +CommonLib = static_library('CommonLib', + commonlib_sources, + include_directories: vtm_includes, + cpp_args: vtm_cpp_args, +) + +# Build DecoderLib +DecoderLib = static_library('DecoderLib', + decoderlib_sources, + include_directories: vtm_includes, + cpp_args: vtm_cpp_args, +) + +# Build Utilities +Utilities = static_library('Utilities', + utilities_sources, + include_directories: vtm_includes, + cpp_args: vtm_cpp_args, +) + +# Build DecoderApp executable +DecoderApp = executable('DecoderApp', + decoderapp_sources, + include_directories: vtm_includes, + link_with: [CommonLib, DecoderLib, Utilities] + simd_libs, + cpp_args: vtm_cpp_args, + install: false, +) diff --git a/subprojects/packagefiles/vvdec/meson.build b/subprojects/packagefiles/vvdec/meson.build new file mode 100644 index 00000000..1b1a033c --- /dev/null +++ b/subprojects/packagefiles/vvdec/meson.build @@ -0,0 +1,260 @@ +# Native meson.build for vvdec (VVC Decoder) +# This replaces the CMake build system to fix linking issues +project('vvdec', 'cpp', + version: '3.2.0', + default_options: [ + 'cpp_std=c++14', + 'default_library=static', + 'buildtype=release' + ] +) + +cpp = meson.get_compiler('cpp') +threads_dep = dependency('threads') + +# Common compiler arguments +vvdec_cpp_args = ['-DNDEBUG', '-DVVDEC_SOURCE'] + +if cpp.get_id() == 'gcc' or cpp.get_id() == 'clang' + vvdec_cpp_args += ['-Wall', '-Wno-sign-compare', '-Wno-unused-variable', '-fvisibility=hidden'] + if cpp.get_id() == 'clang' + vvdec_cpp_args += ['-fno-lax-vector-conversions'] + endif +endif + +# Check host architecture +host_cpu = host_machine.cpu_family() +is_x86 = host_cpu == 'x86' or host_cpu == 'x86_64' +is_arm = host_cpu == 'aarch64' or host_cpu == 'arm' + +# Generate version.h and vvdec.h headers +# The code includes "vvdec/version.h" so we need to place headers in a vvdec/ subdir +# Meson doesn't allow subdirectories in configure_file or custom_target output, +# so we use a generator script that creates the directory structure + +python = find_program('python3', 'python') + +# Generator script to create headers in vvdec/ subdirectory +gen_headers = custom_target('gen_vvdec_headers', + input: ['source/Lib/vvdec/version.h.in', 'include/vvdec/vvdec.h.in'], + output: ['vvdec_headers_done'], + command: [python, '-c', ''' +import os +import sys + +build_dir = os.path.dirname(sys.argv[3]) +vvdec_dir = os.path.join(build_dir, "vvdec") +os.makedirs(vvdec_dir, exist_ok=True) + +# Generate version.h +with open(sys.argv[1]) as f: + content = f.read() +content = content.replace("${PROJECT_VERSION_MAJOR}", "3") +content = content.replace("${PROJECT_VERSION_MINOR}", "2") +content = content.replace("${PROJECT_VERSION_PATCH}", "0") +with open(os.path.join(vvdec_dir, "version.h"), "w") as f: + f.write(content) + +# Generate vvdec.h +with open(sys.argv[2]) as f: + content = f.read() +content = content.replace("@VVDEC_USE_UNSTABLE_API@", "0") +with open(os.path.join(vvdec_dir, "vvdec.h"), "w") as f: + f.write(content) + +# Touch the marker file +with open(sys.argv[3], "w") as f: + f.write("done") +''', '@INPUT0@', '@INPUT1@', '@OUTPUT@'], +) + +# Include directory for generated headers (builddir/subprojects/vvdec/) +# This allows #include "vvdec/version.h" to work +gen_inc = include_directories('.') + +# Include directories +vvdec_includes = include_directories( + 'include', + 'source/Lib', + 'source/Lib/CommonLib', + 'source/Lib/CommonLib/x86', + 'source/Lib/CommonLib/arm', + 'source/Lib/DecoderLib', + 'source/Lib/Utilities', + 'source/Lib/libmd5', + 'source/Lib/vvdec', + 'source/Lib/FilmGrain', + 'thirdparty', +) + +# CommonLib base sources +commonlib_sources = [ + 'source/Lib/CommonLib/AdaptiveLoopFilter.cpp', + 'source/Lib/CommonLib/BitStream.cpp', + 'source/Lib/CommonLib/Buffer.cpp', + 'source/Lib/CommonLib/ChromaFormat.cpp', + 'source/Lib/CommonLib/CodingStructure.cpp', + 'source/Lib/CommonLib/ContextModelling.cpp', + 'source/Lib/CommonLib/Contexts.cpp', + 'source/Lib/CommonLib/dtrace.cpp', + 'source/Lib/CommonLib/InterpolationFilter.cpp', + 'source/Lib/CommonLib/InterPrediction.cpp', + 'source/Lib/CommonLib/IntraPrediction.cpp', + 'source/Lib/CommonLib/LoopFilter.cpp', + 'source/Lib/CommonLib/MatrixIntraPrediction.cpp', + 'source/Lib/CommonLib/Mv.cpp', + 'source/Lib/CommonLib/ParameterSetManager.cpp', + 'source/Lib/CommonLib/PicListManager.cpp', + 'source/Lib/CommonLib/Picture.cpp', + 'source/Lib/CommonLib/PicYuvMD5.cpp', + 'source/Lib/CommonLib/Quant.cpp', + 'source/Lib/CommonLib/RdCost.cpp', + 'source/Lib/CommonLib/Reshape.cpp', + 'source/Lib/CommonLib/Rom.cpp', + 'source/Lib/CommonLib/RomLFNST.cpp', + 'source/Lib/CommonLib/RomTr.cpp', + 'source/Lib/CommonLib/SampleAdaptiveOffset.cpp', + 'source/Lib/CommonLib/SEI_internal.cpp', + 'source/Lib/CommonLib/Slice.cpp', + 'source/Lib/CommonLib/StatCounter.cpp', + 'source/Lib/CommonLib/TrQuant.cpp', + 'source/Lib/CommonLib/TrQuant_EMT.cpp', + 'source/Lib/CommonLib/Unit.cpp', + 'source/Lib/CommonLib/UnitPartitioner.cpp', + 'source/Lib/CommonLib/UnitTools.cpp', + 'source/Lib/CommonLib/WeightPrediction.cpp', +] + +# DecoderLib sources +decoderlib_sources = [ + 'source/Lib/DecoderLib/AnnexBread.cpp', + 'source/Lib/DecoderLib/BinDecoder.cpp', + 'source/Lib/DecoderLib/CABACReader.cpp', + 'source/Lib/DecoderLib/DecCu.cpp', + 'source/Lib/DecoderLib/DecLib.cpp', + 'source/Lib/DecoderLib/DecLibParser.cpp', + 'source/Lib/DecoderLib/DecLibRecon.cpp', + 'source/Lib/DecoderLib/DecSlice.cpp', + 'source/Lib/DecoderLib/HLSyntaxReader.cpp', + 'source/Lib/DecoderLib/NALread.cpp', + 'source/Lib/DecoderLib/SEIread.cpp', + 'source/Lib/DecoderLib/VLCReader.cpp', +] + +# Utilities sources +utilities_sources = [ + 'source/Lib/Utilities/ThreadPool.cpp', +] + +# vvdec API sources +vvdec_api_sources = [ + 'source/Lib/vvdec/vvdec.cpp', + 'source/Lib/vvdec/vvdecimpl.cpp', +] + +# FilmGrain base sources +filmgrain_sources = [ + 'source/Lib/FilmGrain/FilmGrain.cpp', + 'source/Lib/FilmGrain/FilmGrainImpl.cpp', +] + +# All base sources +all_sources = commonlib_sources + decoderlib_sources + utilities_sources + vvdec_api_sources + filmgrain_sources + +# ARM SIMD sources +if is_arm + arm_sources = [ + 'source/Lib/CommonLib/arm/CommonDefARM.cpp', + 'source/Lib/CommonLib/arm/InitARM.cpp', + 'source/Lib/CommonLib/arm/neon/AdaptiveLoopFilter_neon.cpp', + 'source/Lib/CommonLib/arm/neon/Buffer_neon.cpp', + 'source/Lib/CommonLib/arm/neon/InterpolationFilter_neon.cpp', + 'source/Lib/CommonLib/arm/neon/RdCost_neon.cpp', + ] + all_sources += arm_sources +endif + +# x86 SIMD sources (via SIMDE on ARM) +if is_x86 or is_arm + x86_sources = [ + 'source/Lib/CommonLib/x86/InitX86.cpp', + ] + + x86_sse41_sources = [ + 'source/Lib/CommonLib/x86/sse41/AdaptiveLoopFilter_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/Buffer_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/InterpolationFilter_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/InterPred_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/IntraPred_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/LoopFilter_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/Picture_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/Quant_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/RdCost_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/SampleAdaptiveOffset_sse41.cpp', + 'source/Lib/CommonLib/x86/sse41/Trafo_sse41.cpp', + 'source/Lib/FilmGrain/FilmGrainImpl_sse41.cpp', + ] + + x86_avx2_sources = [ + 'source/Lib/CommonLib/x86/avx2/AdaptiveLoopFilter_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/Buffer_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/InterpolationFilter_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/InterPred_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/IntraPred_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/LoopFilter_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/Picture_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/Quant_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/RdCost_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/SampleAdaptiveOffset_avx2.cpp', + 'source/Lib/CommonLib/x86/avx2/Trafo_avx2.cpp', + 'source/Lib/FilmGrain/FilmGrainImpl_avx2.cpp', + ] + + all_sources += x86_sources + + # SSE4.1 sources with USE_SSE41 define + sse41_lib = static_library('vvdec_sse41', + x86_sse41_sources, gen_headers, + include_directories: [vvdec_includes, gen_inc], + cpp_args: vvdec_cpp_args + ['-DUSE_SSE41'], + dependencies: threads_dep, + ) + + # AVX2 sources with USE_AVX2 define + avx2_lib = static_library('vvdec_avx2', + x86_avx2_sources, gen_headers, + include_directories: [vvdec_includes, gen_inc], + cpp_args: vvdec_cpp_args + ['-DUSE_AVX2'], + dependencies: threads_dep, + ) +endif + +# Build vvdec library +vvdec_lib = static_library('vvdec', + all_sources, gen_headers, + include_directories: [vvdec_includes, gen_inc], + cpp_args: vvdec_cpp_args, + dependencies: threads_dep, +) + +# Link all libraries together +if is_x86 or is_arm + vvdec_link = [vvdec_lib, sse41_lib, avx2_lib] +else + vvdec_link = [vvdec_lib] +endif + +# DecoderApp sources +vvdecapp_sources = [ + 'source/App/vvdecapp/vvdecapp.cpp', +] + +# Build vvdecapp executable +vvdecapp = executable('vvdecapp', + vvdecapp_sources, gen_headers, + include_directories: [vvdec_includes, gen_inc, include_directories('source/Lib/libmd5')], + link_with: vvdec_link, + cpp_args: vvdec_cpp_args, + dependencies: threads_dep, + install: false, +) diff --git a/subprojects/vvcsoftware_vtm.wrap b/subprojects/vvcsoftware_vtm.wrap new file mode 100644 index 00000000..5759624e --- /dev/null +++ b/subprojects/vvcsoftware_vtm.wrap @@ -0,0 +1,9 @@ +[wrap-git] +url = https://vcgit.hhi.fraunhofer.de/jvet/VVCSoftware_VTM.git +revision = 83abdf6d4bf45bf8d5f3dd30e8a8b9ee8eefb409 +depth = 1 +clone-recursive = false +patch_directory = vvcsoftware_vtm + +[provide] +program_names = DecoderApp diff --git a/subprojects/vvdec.wrap b/subprojects/vvdec.wrap new file mode 100644 index 00000000..6134eb0b --- /dev/null +++ b/subprojects/vvdec.wrap @@ -0,0 +1,9 @@ +[wrap-git] +url = https://github.com/fraunhoferhhi/vvdec.git +revision = dba55d0f93a10e608f6b7cc7a129cf62b172f1b5 +depth = 1 +clone-recursive = false +patch_directory = vvdec + +[provide] +program_names = vvdecapp